Merge branch 'cw/rebase-i-root'
authorJunio C Hamano <gitster@pobox.com>
Wed, 25 Jul 2012 22:46:59 +0000 (15:46 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 25 Jul 2012 22:46:59 +0000 (15:46 -0700)
Finishing touches to the "rebase -i --root" (new feature for
1.7.12).

* cw/rebase-i-root:
rebase -i: handle fixup of root commit correctly

1  2 
git-rebase--interactive.sh
t/t3404-rebase-interactive.sh
index bef7bc0444bab7b7e511c6e29417ce6db44b77ef,45addba1b0ddd1ab0521e6034bcc2497951d66fe..0d2056f027cbd6811faee3c45088a11b24d86102
@@@ -9,7 -9,9 +9,7 @@@
  #
  # The original idea comes from Eric W. Biederman, in
  # http://article.gmane.org/gmane.comp.version-control.git/22407
 -
 -. git-sh-setup
 -
 +#
  # The file containing rebase commands, comments, and empty lines.
  # This file is created by "git rebase -i" then edited by the user.  As
  # the lines are processed, they are removed from the front of this
@@@ -493,25 -495,28 +493,28 @@@ do_next () 
                author_script_content=$(get_author_ident_from_commit HEAD)
                echo "$author_script_content" > "$author_script"
                eval "$author_script_content"
-               output git reset --soft HEAD^
-               pick_one -n $sha1 || die_failed_squash $sha1 "$rest"
+               if ! pick_one -n $sha1
+               then
+                       git rev-parse --verify HEAD >"$amend"
+                       die_failed_squash $sha1 "$rest"
+               fi
                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:
-                       do_with_author output git commit --no-verify -F "$squash_msg" ||
+                       do_with_author output git commit --amend --no-verify -F "$squash_msg" ||
                                die_failed_squash $sha1 "$rest"
                        ;;
                *)
                        # This is the final command of this squash/fixup group
                        if test -f "$fixup_msg"
                        then
-                               do_with_author git commit --no-verify -F "$fixup_msg" ||
+                               do_with_author git commit --amend --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 ||
+                               do_with_author git commit --amend --no-verify -F "$GIT_DIR"/SQUASH_MSG -e ||
                                        die_failed_squash $sha1 "$rest"
                        fi
                        rm -f "$squash_msg" "$fixup_msg"
@@@ -702,27 -707,6 +705,27 @@@ rearrange_squash () 
        rm -f "$1.sq" "$1.rearranged"
  }
  
 +# Add commands after a pick or after a squash/fixup serie
 +# in the todo list.
 +add_exec_commands () {
 +      {
 +              first=t
 +              while read -r insn rest
 +              do
 +                      case $insn in
 +                      pick)
 +                              test -n "$first" ||
 +                              printf "%s" "$cmd"
 +                              ;;
 +                      esac
 +                      printf "%s %s\n" "$insn" "$rest"
 +                      first=
 +              done
 +              printf "%s" "$cmd"
 +      } <"$1" >"$1.new" &&
 +      mv "$1.new" "$1"
 +}
 +
  case "$action" in
  continue)
        # do we have anything to commit?
@@@ -748,7 -732,6 +751,6 @@@ In both case, once you're done, continu
                fi
                . "$author_script" ||
                        die "Error trying to find the author identity to amend commit"
-               current_head=
                if test -f "$amend"
                then
                        current_head=$(git rev-parse --verify HEAD)
                        die "\
  You have uncommitted changes in your working tree. Please, commit them
  first and then run 'git rebase --continue' again."
-                       git reset --soft HEAD^ ||
-                       die "Cannot rewind the HEAD"
+                       do_with_author git commit --amend --no-verify -F "$msg" -e ||
+                               die "Could not commit staged changes."
+               else
+                       do_with_author git commit --no-verify -F "$msg" -e ||
+                               die "Could not commit staged changes."
                fi
-               do_with_author git commit --no-verify -F "$msg" -e || {
-                       test -n "$current_head" && git reset --soft $current_head
-                       die "Could not commit staged changes."
-               }
        fi
  
        record_in_rewritten "$(cat "$state_dir"/stopped-sha)"
@@@ -896,8 -878,6 +897,8 @@@ f
  
  test -s "$todo" || echo noop >> "$todo"
  test -n "$autosquash" && rearrange_squash "$todo"
 +test -n "$cmd" && add_exec_commands "$todo"
 +
  cat >> "$todo" << EOF
  
  # Rebase $shortrevisions onto $shortonto
index 8078db6856ba4428e9d6b13f5e02076da7963b09,ef2d6313792ccb3c7d42c222bf681f6a054b6db8..3f75d328de8ee08e0d27b3eb589d9c247182d435
@@@ -755,123 -755,6 +755,123 @@@ test_expect_success 'rebase-i history w
        test_cmp expect actual
  '
  
 +
 +test_expect_success 'prepare for rebase -i --exec' '
 +      git checkout master &&
 +      git checkout -b execute &&
 +      test_commit one_exec main.txt one_exec &&
 +      test_commit two_exec main.txt two_exec &&
 +      test_commit three_exec main.txt three_exec
 +'
 +
 +
 +test_expect_success 'running "git rebase -i --exec git show HEAD"' '
 +      git rebase -i --exec "git show HEAD" HEAD~2 >actual &&
 +      (
 +              FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
 +              export FAKE_LINES &&
 +              git rebase -i HEAD~2 >expect
 +      ) &&
 +      sed -e "1,9d" expect >expected &&
 +      test_cmp expected actual
 +'
 +
 +
 +test_expect_success 'running "git rebase --exec git show HEAD -i"' '
 +      git reset --hard execute &&
 +      git rebase --exec "git show HEAD" -i HEAD~2 >actual &&
 +      (
 +              FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
 +              export FAKE_LINES &&
 +              git rebase -i HEAD~2 >expect
 +      ) &&
 +      sed -e "1,9d" expect >expected &&
 +      test_cmp expected actual
 +'
 +
 +
 +test_expect_success 'running "git rebase -ix git show HEAD"' '
 +      git reset --hard execute &&
 +      git rebase -ix "git show HEAD" HEAD~2 >actual &&
 +      (
 +              FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
 +              export FAKE_LINES &&
 +              git rebase -i HEAD~2 >expect
 +      ) &&
 +      sed -e "1,9d" expect >expected &&
 +      test_cmp expected actual
 +'
 +
 +
 +test_expect_success 'rebase -ix with several <CMD>' '
 +      git reset --hard execute &&
 +      git rebase -ix "git show HEAD; pwd" HEAD~2 >actual &&
 +      (
 +              FAKE_LINES="1 exec_git_show_HEAD;_pwd 2 exec_git_show_HEAD;_pwd" &&
 +              export FAKE_LINES &&
 +              git rebase -i HEAD~2 >expect
 +      ) &&
 +      sed -e "1,9d" expect >expected &&
 +      test_cmp expected actual
 +'
 +
 +
 +test_expect_success 'rebase -ix with several instances of --exec' '
 +      git reset --hard execute &&
 +      git rebase -i --exec "git show HEAD" --exec "pwd" HEAD~2 >actual &&
 +      (
 +              FAKE_LINES="1 exec_git_show_HEAD exec_pwd 2
 +                              exec_git_show_HEAD exec_pwd" &&
 +              export FAKE_LINES &&
 +              git rebase -i HEAD~2 >expect
 +      ) &&
 +      sed -e "1,11d" expect >expected &&
 +      test_cmp expected actual
 +'
 +
 +
 +test_expect_success 'rebase -ix with --autosquash' '
 +      git reset --hard execute &&
 +      git checkout -b autosquash &&
 +      echo second >second.txt &&
 +      git add second.txt &&
 +      git commit -m "fixup! two_exec" &&
 +      echo bis >bis.txt &&
 +      git add bis.txt &&
 +      git commit -m "fixup! two_exec" &&
 +      (
 +              git checkout -b autosquash_actual &&
 +              git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual
 +      ) &&
 +      git checkout autosquash &&
 +      (
 +              git checkout -b autosquash_expected &&
 +              FAKE_LINES="1 fixup 3 fixup 4 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
 +              export FAKE_LINES &&
 +              git rebase -i HEAD~4 >expect
 +      ) &&
 +      sed -e "1,13d" expect >expected &&
 +      test_cmp expected actual
 +'
 +
 +
 +test_expect_success 'rebase --exec without -i shows error message' '
 +      git reset --hard execute &&
 +      test_must_fail git rebase --exec "git show HEAD" HEAD~2 2>actual &&
 +      echo "--exec option must be used with --interactive option" >expected &&
 +      test_i18ncmp expected actual
 +'
 +
 +
 +test_expect_success 'rebase -i --exec without <CMD>' '
 +      git reset --hard execute &&
 +      test_must_fail git rebase -i --exec 2>tmp &&
 +      sed -e "1d" tmp >actual &&
 +      test_must_fail git rebase -h >expected &&
 +      test_cmp expected actual &&
 +      git checkout master
 +'
 +
  test_expect_success 'rebase -i --root re-order and drop commits' '
        git checkout E &&
        FAKE_LINES="3 1 2 5" git rebase -i --root &&
@@@ -903,4 -786,12 +903,12 @@@ test_expect_success 'rebase -i --root t
        git rebase --abort
  '
  
+ test_expect_success 'rebase -i --root fixup root commit' '
+       git checkout B &&
+       FAKE_LINES="1 fixup 2" git rebase -i --root &&
+       test A = $(git cat-file commit HEAD | sed -ne \$p) &&
+       test B = $(git show HEAD:file1) &&
+       test 0 = $(git cat-file commit HEAD | grep -c ^parent\ )
+ '
  test_done