git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[RFC PATCH 2/5] rebase -i: improve --continue --autostage

From
PWPhillip Wood <phillip.wood@talktalk.net>
Date
Jul 26, 2017, 10:27 UTC
Message-ID
<20170726102720.15274-3-phillip.wood@talktalk.net>
In-Reply-To
<20170726102720.15274-1-phillip.wood@talktalk.net>
From: Phillip Wood <phillip.wood@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.wood@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
Previous: Phillip WoodNext: Junio C Hamano
Message 6 of 19 in “Add option to autostage changes when continuing a rebase”
  1. 0/5 Add option to autostage changes when continuing a rebasePhillip Wood, Jul 26, 2017
  2. 1/5 rebase --continue: add --autostage to stage unstaged changesPhillip Wood, Jul 26, 2017
  3. 3/5 Unify rebase amend message when HEAD has changedPhillip Wood, Jul 26, 2017
  4. 4/5 Add tests for rebase --continue --autostagePhillip Wood, Jul 26, 2017
  5. 5/5 Add rebase.continue.autostage config settingPhillip Wood, Jul 26, 2017
  6. 2/5 rebase -i: improve --continue --autostagePhillip Wood, Jul 26, 2017
  7. Junio C HamanoJul 26, 2017
  8. Junio C HamanoJul 26, 2017
  9. Junio C HamanoJul 26, 2017
  10. Phillip WoodJul 27, 2017
  11. Phillip WoodJul 27, 2017
  12. Junio C HamanoJul 27, 2017
  13. Phillip WoodAug 21, 2017
  14. Junio C HamanoAug 21, 2017
  15. Phillip WoodAug 22, 2017
  16. Junio C HamanoAug 22, 2017
  17. Phillip WoodAug 24, 2017
  18. Junio C HamanoAug 24, 2017
  19. Phillip WoodAug 25, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.