From: Phillip Wood <phillip.wood@xxxxxxxxxxxxx> 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.wood@xxxxxxxxxxxxx> --- 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