From: Michael Haggerty Date: Thu, 14 Jan 2010 05:54:57 +0000 (+0100) Subject: rebase -i: Retain user-edited commit messages after squash/fixup conflicts X-Git-Tag: v1.7.0-rc0~68^2 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=6bdcd0d2fcca7c3985a078c8d343a863136fb675;p=git.git rebase -i: Retain user-edited commit messages after squash/fixup conflicts When a squash/fixup fails due to a conflict, the user is required to edit the commit message. Previously, if further squash/fixup commands followed the conflicting squash/fixup, this user-edited message was discarded and a new automatically-generated commit message was suggested. Change the handling of conflicts within squash/fixup command series: Whenever the user is required to intervene, consider the resulting commit to be a new basis for the following squash/fixups and use its commit message in later suggested combined commit messages. Signed-off-by: Michael Haggerty Signed-off-by: Junio C Hamano --- diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 1569a7ad9..b835a2975 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -408,6 +408,21 @@ peek_next_command () { sed -n -e "/^#/d" -e "/^$/d" -e "s/ .*//p" -e "q" < "$TODO" } +# A squash/fixup has failed. Prepare the long version of the squash +# commit message, then die_with_patch. This code path requires the +# user to edit the combined commit message for all commits that have +# been squashed/fixedup so far. So also erase the old squash +# messages, effectively causing the combined commit to be used as the +# new basis for any further squash/fixups. Args: sha1 rest +die_failed_squash() { + mv "$SQUASH_MSG" "$MSG" || exit + rm -f "$FIXUP_MSG" + cp "$MSG" "$GIT_DIR"/MERGE_MSG || exit + warn + warn "Could not apply $1... $2" + die_with_patch $1 "" +} + do_next () { rm -f "$MSG" "$AUTHOR_SCRIPT" "$AMEND" || exit read command sha1 rest < "$TODO" @@ -465,58 +480,31 @@ do_next () { mark_action_done update_squash_messages $squash_style $sha1 - failed=f author_script=$(get_author_ident_from_commit HEAD) echo "$author_script" > "$AUTHOR_SCRIPT" eval "$author_script" output git reset --soft HEAD^ - pick_one -n $sha1 || failed=t + pick_one -n $sha1 || die_failed_squash $sha1 "$rest" case "$(peek_next_command)" in squash|s|fixup|f) # This is an intermediate commit; its message will only be # used in case of trouble. So use the long version: - if test $failed = f - then - do_with_author output git commit --no-verify -F "$SQUASH_MSG" || - failed=t - fi - if test $failed = t - then - cp "$SQUASH_MSG" "$MSG" || exit - # After any kind of hiccup, prevent committing without - # opening the commit message editor: - rm -f "$FIXUP_MSG" - cp "$MSG" "$GIT_DIR"/MERGE_MSG || exit - warn - warn "Could not apply $sha1... $rest" - die_with_patch $sha1 "" - fi + do_with_author output git commit --no-verify -F "$SQUASH_MSG" || + die_failed_squash $sha1 "$rest" ;; *) # This is the final command of this squash/fixup group - if test $failed = f + if test -f "$FIXUP_MSG" then - if test -f "$FIXUP_MSG" - then - do_with_author git commit --no-verify -F "$FIXUP_MSG" || - failed=t - else - cp "$SQUASH_MSG" "$GIT_DIR"/SQUASH_MSG || exit - rm -f "$GIT_DIR"/MERGE_MSG - do_with_author git commit --no-verify -e || - failed=t - fi - fi - rm -f "$FIXUP_MSG" - if test $failed = t - then - mv "$SQUASH_MSG" "$MSG" || exit - cp "$MSG" "$GIT_DIR"/MERGE_MSG || exit - warn - warn "Could not apply $sha1... $rest" - die_with_patch $sha1 "" + do_with_author git commit --no-verify -F "$FIXUP_MSG" || + die_failed_squash $sha1 "$rest" + else + cp "$SQUASH_MSG" "$GIT_DIR"/SQUASH_MSG || exit + rm -f "$GIT_DIR"/MERGE_MSG + do_with_author git commit --no-verify -e || + die_failed_squash $sha1 "$rest" fi - rm -f "$SQUASH_MSG" + rm -f "$SQUASH_MSG" "$FIXUP_MSG" ;; esac ;; diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index a119ce0d3..4e3513709 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -264,6 +264,42 @@ test_expect_success 'multi-fixup does not fire up editor' ' git branch -D multi-fixup ' +test_expect_success 'commit message used after conflict' ' + git checkout -b conflict-fixup conflict-branch && + base=$(git rev-parse HEAD~4) && + ( + FAKE_LINES="1 fixup 3 fixup 4" && + export FAKE_LINES && + test_must_fail git rebase -i $base + ) && + echo three > conflict && + git add conflict && + FAKE_COMMIT_AMEND="ONCE" EXPECT_HEADER_COUNT=2 \ + git rebase --continue && + test $base = $(git rev-parse HEAD^) && + test 1 = $(git show | grep ONCE | wc -l) && + git checkout to-be-rebased && + git branch -D conflict-fixup +' + +test_expect_success 'commit message retained after conflict' ' + git checkout -b conflict-squash conflict-branch && + base=$(git rev-parse HEAD~4) && + ( + FAKE_LINES="1 fixup 3 squash 4" && + export FAKE_LINES && + test_must_fail git rebase -i $base + ) && + echo three > conflict && + git add conflict && + FAKE_COMMIT_AMEND="TWICE" EXPECT_HEADER_COUNT=2 \ + git rebase --continue && + test $base = $(git rev-parse HEAD^) && + test 2 = $(git show | grep TWICE | wc -l) && + git checkout to-be-rebased && + git branch -D conflict-squash +' + cat > expect-squash-fixup << EOF B