@matheusbsbs / matheus-bagliano / commits / 6bdcd0d2fc
Fork 0

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 <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michael Haggerty committed Jan 14, 2010 at 06:54 UTC 6bdcd0d2fcca7c3985a078c8d343a863136fb675
2 files changed +63 -39
git-rebase--interactive.sh
+27 -39
@@ -408,6 +408,21 @@ peek_next_command () {
408 sed -n -e "/^#/d" -e "/^$/d" -e "s/ .*//p" -e "q" < "$TODO"
409 }
410
411 +# A squash/fixup has failed. Prepare the long version of the squash
412 +# commit message, then die_with_patch. This code path requires the
413 +# user to edit the combined commit message for all commits that have
414 +# been squashed/fixedup so far. So also erase the old squash
415 +# messages, effectively causing the combined commit to be used as the
416 +# new basis for any further squash/fixups. Args: sha1 rest
417 +die_failed_squash() {
418 + mv "$SQUASH_MSG" "$MSG" || exit
419 + rm -f "$FIXUP_MSG"
420 + cp "$MSG" "$GIT_DIR"/MERGE_MSG || exit
421 + warn
422 + warn "Could not apply $1... $2"
423 + die_with_patch $1 ""
424 +}
425 +
426 do_next () {
427 rm -f "$MSG" "$AUTHOR_SCRIPT" "$AMEND" || exit
428 read command sha1 rest < "$TODO"
@@ -465,58 +480,31 @@ do_next () {
480
481 mark_action_done
482 update_squash_messages $squash_style $sha1
468 - failed=f
483 author_script=$(get_author_ident_from_commit HEAD)
484 echo "$author_script" > "$AUTHOR_SCRIPT"
485 eval "$author_script"
486 output git reset --soft HEAD^
473 - pick_one -n $sha1 || failed=t
487 + pick_one -n $sha1 || die_failed_squash $sha1 "$rest"
488 case "$(peek_next_command)" in
489 squash|s|fixup|f)
490 # This is an intermediate commit; its message will only be
491 # used in case of trouble. So use the long version:
478 - if test $failed = f
479 - then
480 - do_with_author output git commit --no-verify -F "$SQUASH_MSG" ||
481 - failed=t
482 - fi
483 - if test $failed = t
484 - then
485 - cp "$SQUASH_MSG" "$MSG" || exit
486 - # After any kind of hiccup, prevent committing without
487 - # opening the commit message editor:
488 - rm -f "$FIXUP_MSG"
489 - cp "$MSG" "$GIT_DIR"/MERGE_MSG || exit
490 - warn
491 - warn "Could not apply $sha1... $rest"
492 - die_with_patch $sha1 ""
493 - fi
492 + do_with_author output git commit --no-verify -F "$SQUASH_MSG" ||
493 + die_failed_squash $sha1 "$rest"
494 ;;
495 *)
496 # This is the final command of this squash/fixup group
497 - if test $failed = f
497 + if test -f "$FIXUP_MSG"
498 then
499 - if test -f "$FIXUP_MSG"
500 - then
501 - do_with_author git commit --no-verify -F "$FIXUP_MSG" ||
502 - failed=t
503 - else
504 - cp "$SQUASH_MSG" "$GIT_DIR"/SQUASH_MSG || exit
505 - rm -f "$GIT_DIR"/MERGE_MSG
506 - do_with_author git commit --no-verify -e ||
507 - failed=t
508 - fi
509 - fi
510 - rm -f "$FIXUP_MSG"
511 - if test $failed = t
512 - then
513 - mv "$SQUASH_MSG" "$MSG" || exit
514 - cp "$MSG" "$GIT_DIR"/MERGE_MSG || exit
515 - warn
516 - warn "Could not apply $sha1... $rest"
517 - die_with_patch $sha1 ""
499 + do_with_author git commit --no-verify -F "$FIXUP_MSG" ||
500 + die_failed_squash $sha1 "$rest"
501 + else
502 + cp "$SQUASH_MSG" "$GIT_DIR"/SQUASH_MSG || exit
503 + rm -f "$GIT_DIR"/MERGE_MSG
504 + do_with_author git commit --no-verify -e ||
505 + die_failed_squash $sha1 "$rest"
506 fi
519 - rm -f "$SQUASH_MSG"
507 + rm -f "$SQUASH_MSG" "$FIXUP_MSG"
508 ;;
509 esac
510 ;;
t/t3404-rebase-interactive.sh
+36
@@ -264,6 +264,42 @@ test_expect_success 'multi-fixup does not fire up editor' '
264 git branch -D multi-fixup
265 '
266
267 +test_expect_success 'commit message used after conflict' '
268 + git checkout -b conflict-fixup conflict-branch &&
269 + base=$(git rev-parse HEAD~4) &&
270 + (
271 + FAKE_LINES="1 fixup 3 fixup 4" &&
272 + export FAKE_LINES &&
273 + test_must_fail git rebase -i $base
274 + ) &&
275 + echo three > conflict &&
276 + git add conflict &&
277 + FAKE_COMMIT_AMEND="ONCE" EXPECT_HEADER_COUNT=2 \
278 + git rebase --continue &&
279 + test $base = $(git rev-parse HEAD^) &&
280 + test 1 = $(git show | grep ONCE | wc -l) &&
281 + git checkout to-be-rebased &&
282 + git branch -D conflict-fixup
283 +'
284 +
285 +test_expect_success 'commit message retained after conflict' '
286 + git checkout -b conflict-squash conflict-branch &&
287 + base=$(git rev-parse HEAD~4) &&
288 + (
289 + FAKE_LINES="1 fixup 3 squash 4" &&
290 + export FAKE_LINES &&
291 + test_must_fail git rebase -i $base
292 + ) &&
293 + echo three > conflict &&
294 + git add conflict &&
295 + FAKE_COMMIT_AMEND="TWICE" EXPECT_HEADER_COUNT=2 \
296 + git rebase --continue &&
297 + test $base = $(git rev-parse HEAD^) &&
298 + test 2 = $(git show | grep TWICE | wc -l) &&
299 + git checkout to-be-rebased &&
300 + git branch -D conflict-squash
301 +'
302 +
303 cat > expect-squash-fixup << EOF
304 B
305