From: Phillip Wood <phillip.w...@dunelm.org.uk>

If HEAD has changed since the rebase stopped or rebase stopped due to
a failed exec then 'git rebase --continue --autostage' will autostage
changes that cannot be commited. Fix this by reordering some of the
checks so that 'git rebase --continue --autostage' never stages
changes unless they can be committed. Also reword some error
messages to account of --autostage and try and make them clearer.

Signed-off-by: Phillip Wood <phillip.w...@dunelm.org.uk>
---

This could do with some tests the check the correct error message is
given in each failure case. However I'm expecting to change the error
messages based on the feedback I get to this patch so I'll add the
tests once the messages are finalized. I've tried to give a bit more
explanation in the error messages as I found some of the previous
messages didn't explain why rebase couldn't continue. Splitting the
advice out means it is consistent between different code paths and
should make it easier to optionally disable it in future if anyone
wanted to add that. As for the formatting of the messages I wonder if
they would be better without so many empty lines (I find the current
messages a bit intimating as they seem so long). e.g.

If you wish to squash the unstaged changes into the last commit, run:
    git add -u
    git commit --amend \$gpg_sign_opt_quoted
If they are meant to go into a new commit, run:
    git add -u
    git commit \$gpg_sign_opt_quoted
In both cases, once you're done, continue with:
    git rebase --continue

Instead of

If you wish to squash the unstaged changes into the last commit, run:

  git add -u
  git commit --amend \$gpg_sign_opt_quoted

If they are meant to go into a new commit, run:

  git add -u
  git commit \$gpg_sign_opt_quoted

In both cases, once you're done, continue with:

  git rebase --continue


 git-rebase--interactive.sh    | 104 ++++++++++++++++++++++++++++++++----------
 t/t3404-rebase-interactive.sh |   2 +-
 2 files changed, 81 insertions(+), 25 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 
4c037a3f7a9e01406c4205bf8786a3da5060381f..8140c88839b4f3a86f53faaaa2ba4433ecc7f58b
 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -1056,6 +1056,42 @@ The possible behaviours are: ignore, warn, error.")"
        fi
 }
 
+unstaged_advice () {
+       gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote 
"$gpg_sign_opt")}
+       eval_gettext "\
+If you wish to squash the unstaged changes into the last commit, run:
+
+  git add -u
+  git commit --amend \$gpg_sign_opt_quoted
+
+If they are meant to go into a new commit, run:
+
+  git add -u
+  git commit \$gpg_sign_opt_quoted
+
+In both cases, once you're done, continue with:
+
+  git rebase --continue
+"
+}
+
+staged_advice () {
+       gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote 
"$gpg_sign_opt")}
+       eval_gettext "\
+If you wish to squash the staged changes into the last commit, run:
+
+  git commit --amend \$gpg_sign_opt_quoted
+
+If they are meant to go into a new commit, run:
+
+  git commit \$gpg_sign_opt_quoted
+
+In both cases, once you're done, continue with:
+
+  git rebase --continue
+"
+}
+
 # The whole contents of this file is run by dot-sourcing it from
 # inside a shell function.  It used to be that "return"s we see
 # below were not inside any function, and expected to return
@@ -1067,9 +1103,50 @@ The possible behaviours are: ignore, warn, error.")"
 # here, and immediately call it after defining it.
 git_rebase__interactive () {
 
+amend_head='' amend_ok=''
 case "$action" in
 continue)
-       check_unstaged
+       test -f "$amend" &&
+               amend_head=$(cat "$amend") &&
+               test $amend_head = $(git rev-parse HEAD) &&
+               amend_ok=1
+       git update-index --refresh --ignore-submodules >/dev/null
+       git diff-files --quiet --ignore-submodules
+       unstaged=$?
+       if ! test -f "$author_script"
+       then
+               if test $unstaged = 1
+               then
+                       die "$(gettext "Not expecting unstaged changes.")
+$(unstaged_advice)"
+               elif ! git diff-index --cached --quiet --ignore-submodules HEAD 
--
+               then
+                       die "$(gettext "Not expecting staged changes.")
+$(staged_advice)"
+               fi
+       fi
+       if test $unstaged = 1 && test $autostage = true
+       then
+               if test -n "$amend_head" && test -z "$amend_ok"
+               then
+                       die "$(gettext "\
+Unable to commit changes as HEAD has changed since git rebase stopped.")
+$(unstaged_advice)"
+               else
+                       check_autostage
+               fi
+       elif test $unstaged = 1
+       then
+               if test -n "$amend_head" && test -z "$amend_ok"
+               then
+                       die "$(gettext "\
+Unable to continue rebasing as there are unstaged changes and
+HEAD has changed since git rebase stopped.")
+$(unstaged_advice)"
+               else
+                       die "$(autostage_advice)"
+               fi
+       fi
        if test ! -d "$rewritten"
        then
                exec git rebase--helper ${force_rebase:+--no-ff} --continue
@@ -1083,31 +1160,11 @@ continue)
                rm "$GIT_DIR"/CHERRY_PICK_HEAD ||
                die "$(gettext "Could not remove CHERRY_PICK_HEAD")"
        else
-               if ! test -f "$author_script"
-               then
-                       gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse 
--sq-quote "$gpg_sign_opt")}
-                       die "$(eval_gettext "\
-You have staged changes in your working tree.
-If these changes are meant to be
-squashed into the previous commit, run:
-
-  git commit --amend \$gpg_sign_opt_quoted
-
-If they are meant to go into a new commit, run:
-
-  git commit \$gpg_sign_opt_quoted
-
-In both cases, once you're done, continue with:
-
-  git rebase --continue
-")"
-               fi
                . "$author_script" ||
                        die "$(gettext "Error trying to find the author 
identity to amend commit")"
-               if test -f "$amend"
+               if test -n "$amend_head"
                then
-                       current_head=$(git rev-parse --verify HEAD)
-                       test "$current_head" = $(cat "$amend") ||
+                       test -n "$amend_ok" ||
                        die "$(gettext "\
 You have uncommitted changes in your working tree. Please commit them
 first and then run 'git rebase --continue' again.")"
@@ -1126,7 +1183,6 @@ first and then run 'git rebase --continue' again.")"
                record_in_rewritten "$(cat "$state_dir"/stopped-sha)"
        fi
 
-       require_clean_work_tree "rebase"
        do_rest
        return 0
        ;;
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 
37821d245433f757fa13f0a3e27da0312bebb7db..3eed8a3bc5a8e9c3bae32e181d367d9a9c0aff80
 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -563,7 +563,7 @@ test_expect_success 'clean error after failed "exec"' '
        echo "edited again" > file7 &&
        git add file7 &&
        test_must_fail git rebase --continue 2>error &&
-       test_i18ngrep "you have staged changes in your working tree" error
+       test_i18ngrep "Not expecting staged changes" error
 '
 
 test_expect_success 'rebase a detached HEAD' '
-- 
2.13.3

Reply via email to