rebase -i: handle fixup of root commit correctly

There is a bug with git rebase -i --root when a fixup or squash line is applied to the new root. We attempt to amend the commit onto which they apply with git reset --soft HEAD^ followed by a normal commit. Unlike a real commit --amend, this sequence will fail against a root commit as it has no parent. Fix rebase -i to use commit --amend for fixup and squash instead, and add a test for the case of a fixup of the root commit. Signed-off-by: Chris Webb <chris@arachsys.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Chris Webb committed Jul 24, 2012 at 13:17 UTC 2147f844ed13fa5052161d38f8cf7dca6f83c06e
2 files changed +21 -12
git-rebase--interactive.sh
+13 -12
@@ -495,25 +495,28 @@ do_next () {
495 author_script_content=$(get_author_ident_from_commit HEAD)
496 echo "$author_script_content" > "$author_script"
497 eval "$author_script_content"
498 - output git reset --soft HEAD^
499 - pick_one -n $sha1 || die_failed_squash $sha1 "$rest"
498 + if ! pick_one -n $sha1
499 + then
500 + git rev-parse --verify HEAD >"$amend"
501 + die_failed_squash $sha1 "$rest"
502 + fi
503 case "$(peek_next_command)" in
504 squash|s|fixup|f)
505 # This is an intermediate commit; its message will only be
506 # used in case of trouble. So use the long version:
504 - do_with_author output git commit --no-verify -F "$squash_msg" ||
507 + do_with_author output git commit --amend --no-verify -F "$squash_msg" ||
508 die_failed_squash $sha1 "$rest"
509 ;;
510 *)
511 # This is the final command of this squash/fixup group
512 if test -f "$fixup_msg"
513 then
511 - do_with_author git commit --no-verify -F "$fixup_msg" ||
514 + do_with_author git commit --amend --no-verify -F "$fixup_msg" ||
515 die_failed_squash $sha1 "$rest"
516 else
517 cp "$squash_msg" "$GIT_DIR"/SQUASH_MSG || exit
518 rm -f "$GIT_DIR"/MERGE_MSG
516 - do_with_author git commit --no-verify -e ||
519 + do_with_author git commit --amend --no-verify -F "$GIT_DIR"/SQUASH_MSG -e ||
520 die_failed_squash $sha1 "$rest"
521 fi
522 rm -f "$squash_msg" "$fixup_msg"
@@ -729,7 +732,6 @@ In both case, once you're done, continue with:
732 fi
733 . "$author_script" ||
734 die "Error trying to find the author identity to amend commit"
732 - current_head=
735 if test -f "$amend"
736 then
737 current_head=$(git rev-parse --verify HEAD)
@@ -737,13 +739,12 @@ In both case, once you're done, continue with:
739 die "\
740 You have uncommitted changes in your working tree. Please, commit them
741 first and then run 'git rebase --continue' again."
740 - git reset --soft HEAD^ ||
741 - die "Cannot rewind the HEAD"
742 + do_with_author git commit --amend --no-verify -F "$msg" -e ||
743 + die "Could not commit staged changes."
744 + else
745 + do_with_author git commit --no-verify -F "$msg" -e ||
746 + die "Could not commit staged changes."
747 fi
743 - do_with_author git commit --no-verify -F "$msg" -e || {
744 - test -n "$current_head" && git reset --soft $current_head
745 - die "Could not commit staged changes."
746 - }
748 fi
749
750 record_in_rewritten "$(cat "$state_dir"/stopped-sha)"
t/t3404-rebase-interactive.sh
+8
@@ -786,4 +786,12 @@ test_expect_success 'rebase -i --root temporary sentinel commit' '
786 git rebase --abort
787 '
788
789 +test_expect_success 'rebase -i --root fixup root commit' '
790 + git checkout B &&
791 + FAKE_LINES="1 fixup 2" git rebase -i --root &&
792 + test A = $(git cat-file commit HEAD | sed -ne \$p) &&
793 + test B = $(git show HEAD:file1) &&
794 + test 0 = $(git cat-file commit HEAD | grep -c ^parent\ )
795 +'
796 +
797 test_done