Merge branch 'ph/rebase-i-redo'
authorJunio C Hamano <gitster@pobox.com>
Tue, 19 May 2015 20:17:56 +0000 (13:17 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 19 May 2015 20:17:56 +0000 (13:17 -0700)
"git rebase -i" moved the "current" command from "todo" to "done" a
bit too prematurely, losing a step when a "pick" did not even start.

* ph/rebase-i-redo:
rebase -i: redo tasks that die during cherry-pick

1  2 
git-rebase--interactive.sh
t/t3404-rebase-interactive.sh
index 08e5d86fe5b5eda37f2ab44c3cce6dabb42c54e1,00080572529ae4c7e0c86c0aa2ba7cb83146dd2a..bab0dccc04d85215223c30597659f23cf8edff32
@@@ -132,6 -132,16 +132,16 @@@ mark_action_done () 
        fi
  }
  
+ # Put the last action marked done at the beginning of the todo list
+ # again. If there has not been an action marked done yet, leave the list of
+ # items on the todo list unchanged.
+ reschedule_last_action () {
+       tail -n 1 "$done" | cat - "$todo" >"$todo".new
+       sed -e \$d <"$done" >"$done".new
+       mv -f "$todo".new "$todo"
+       mv -f "$done".new "$done"
+ }
  append_todo_help () {
        git stripspace --comment-lines >>"$todo" <<\EOF
  
@@@ -252,6 -262,12 +262,12 @@@ pick_one () 
        output eval git cherry-pick \
                        ${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} \
                        "$strategy_args" $empty_args $ff "$@"
+       # If cherry-pick dies it leaves the to-be-picked commit unrecorded. Reschedule
+       # previous task so this commit is not lost.
+       ret=$?
+       case "$ret" in [01]) ;; *) reschedule_last_action ;; esac
+       return $ret
  }
  
  pick_one_preserving_merges () {
@@@ -642,9 -658,9 +658,9 @@@ do_next () 
                git notes copy --for-rewrite=rebase < "$rewritten_list" ||
                true # we don't care if this copying failed
        } &&
 -      if test -x "$GIT_DIR"/hooks/post-rewrite &&
 -              test -s "$rewritten_list"; then
 -              "$GIT_DIR"/hooks/post-rewrite rebase < "$rewritten_list"
 +      hook="$(git rev-parse --git-path hooks/post-rewrite)"
 +      if test -x "$hook" && test -s "$rewritten_list"; then
 +              "$hook" rebase < "$rewritten_list"
                true # we don't care if this hook failed
        fi &&
        warn "Successfully rebased and updated $head_name."
index eed76cca55ce655cb51c793f21cd5ebbd363ba85,96be93c62443e681eb685e6b2b4e254b041916cf..ac429a0bbbbeb95f96336aa203a5d9726ed6eb1d
@@@ -950,7 -950,7 +950,7 @@@ test_expect_success 'rebase --edit-tod
        set_fake_editor &&
        FAKE_LINES="edit 1 2 3" git rebase -i HEAD~3 &&
        FAKE_LINES="2 1" git rebase --edit-todo &&
 -      git rebase --continue
 +      git rebase --continue &&
        test M = $(git cat-file commit HEAD^ | sed -ne \$p) &&
        test L = $(git cat-file commit HEAD | sed -ne \$p)
  '
@@@ -1007,7 -1007,7 +1007,7 @@@ test_expect_success 'rebase -i with --s
  '
  
  test_expect_success 'rebase -i error on commits with \ in message' '
 -      current_head=$(git rev-parse HEAD)
 +      current_head=$(git rev-parse HEAD) &&
        test_when_finished "git rebase --abort; git reset --hard $current_head; rm -f error" &&
        test_commit TO-REMOVE will-conflict old-content &&
        test_commit "\temp" will-conflict new-content dummy &&
@@@ -1055,4 -1055,51 +1055,51 @@@ test_expect_success 'todo count' 
        grep "^# Rebase ..* onto ..* ([0-9]" actual
  '
  
+ test_expect_success 'rebase -i commits that overwrite untracked files (pick)' '
+       git checkout --force branch2 &&
+       git clean -f &&
+       set_fake_editor &&
+       FAKE_LINES="edit 1 2" git rebase -i A &&
+       test_cmp_rev HEAD F &&
+       test_path_is_missing file6 &&
+       >file6 &&
+       test_must_fail git rebase --continue &&
+       test_cmp_rev HEAD F &&
+       rm file6 &&
+       git rebase --continue &&
+       test_cmp_rev HEAD I
+ '
+ test_expect_success 'rebase -i commits that overwrite untracked files (squash)' '
+       git checkout --force branch2 &&
+       git clean -f &&
+       git tag original-branch2 &&
+       set_fake_editor &&
+       FAKE_LINES="edit 1 squash 2" git rebase -i A &&
+       test_cmp_rev HEAD F &&
+       test_path_is_missing file6 &&
+       >file6 &&
+       test_must_fail git rebase --continue &&
+       test_cmp_rev HEAD F &&
+       rm file6 &&
+       git rebase --continue &&
+       test $(git cat-file commit HEAD | sed -ne \$p) = I &&
+       git reset --hard original-branch2
+ '
+ test_expect_success 'rebase -i commits that overwrite untracked files (no ff)' '
+       git checkout --force branch2 &&
+       git clean -f &&
+       set_fake_editor &&
+       FAKE_LINES="edit 1 2" git rebase -i --no-ff A &&
+       test $(git cat-file commit HEAD | sed -ne \$p) = F &&
+       test_path_is_missing file6 &&
+       >file6 &&
+       test_must_fail git rebase --continue &&
+       test $(git cat-file commit HEAD | sed -ne \$p) = F &&
+       rm file6 &&
+       git rebase --continue &&
+       test $(git cat-file commit HEAD | sed -ne \$p) = I
+ '
  test_done