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

[PATCH 18/18] rebase -i: Retain user-edited commit messages after squash/fixup conflicts

From
Michael Haggerty <mhagger@alum.mit.edu>
Date
Jan 14, 2010, 05:54 UTC
Message-ID
<41c3e65ab43be6b2f98f3c162e34c160c059bb5c.1263447038.git.mhagger@alum.mit.edu>
In-Reply-To
<cover.1263447037.git.mhagger@alum.mit.edu>

When a squash/fixup fails due to a conflict, the user is required to edit the commit message. Previously, if further squash/fixup commands followed the conflicting squash/fixup, this user-edited message was discarded and a new automatically-generated commit message was suggested.

Change the handling of conflicts within squash/fixup command series: Whenever the user is required to intervene, consider the resulting commit to be a new basis for the following squash/fixups and use its commit message in later suggested combined commit messages.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
 git-rebase--interactive.sh    |   66 +++++++++++++++++------------------------
 t/t3404-rebase-interactive.sh |   36 ++++++++++++++++++++++
 2 files changed, 63 insertions(+), 39 deletions(-)
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index c9390cd..e551906 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -410,6 +410,21 @@ peek_next_command () {
 	sed -n -e "/^#/d" -e "/^$/d" -e "s/ .*//p" -e "q" < "$TODO"
 }
 
+# A squash/fixup has failed.  Prepare the long version of the squash
+# commit message, then die_with_patch.  This code path requires the
+# user to edit the combined commit message for all commits that have
+# been squashed/fixedup so far.  So also erase the old squash
+# messages, effectively causing the combined commit to be used as the
+# new basis for any further squash/fixups.  Args: sha1 rest
+die_failed_squash() {
+	mv "$SQUASH_MSG" "$MSG" || exit
+	rm -f "$FIXUP_MSG"
+	cp "$MSG" "$GIT_DIR"/MERGE_MSG || exit
+	warn
+	warn "Could not apply $1... $2"
+	die_with_patch $1 ""
+}
+
 do_next () {
 	rm -f "$MSG" "$AUTHOR_SCRIPT" "$AMEND" || exit
 	read command sha1 rest < "$TODO"
@@ -467,58 +482,31 @@ do_next () {
 
 		mark_action_done
 		update_squash_messages $squash_style $sha1
-		failed=f
 		author_script=$(get_author_ident_from_commit HEAD)
 		echo "$author_script" > "$AUTHOR_SCRIPT"
 		eval "$author_script"
 		output git reset --soft HEAD^
-		pick_one -n $sha1 || failed=t
+		pick_one -n $sha1 || die_failed_squash $sha1 "$rest"
 		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:
-			if test $failed = f
-			then
-				do_with_author output git commit --no-verify -F "$SQUASH_MSG" ||
-					failed=t
-			fi
-			if test $failed = t
-			then
-				cp "$SQUASH_MSG" "$MSG" || exit
-				# After any kind of hiccup, prevent committing without
-				# opening the commit message editor:
-				rm -f "$FIXUP_MSG"
-				cp "$MSG" "$GIT_DIR"/MERGE_MSG || exit
-				warn
-				warn "Could not apply $sha1... $rest"
-				die_with_patch $sha1 ""
-			fi
+			do_with_author output git commit --no-verify -F "$SQUASH_MSG" ||
+				die_failed_squash $sha1 "$rest"
 			;;
 		*)
 			# This is the final command of this squash/fixup group
-			if test $failed = f
+			if test -f "$FIXUP_MSG"
 			then
-				if test -f "$FIXUP_MSG"
-				then
-					do_with_author git commit --no-verify -F "$FIXUP_MSG" ||
-						failed=t
-				else
-					cp "$SQUASH_MSG" "$GIT_DIR"/SQUASH_MSG || exit
-					rm -f "$GIT_DIR"/MERGE_MSG
-					do_with_author git commit --no-verify -e ||
-						failed=t
-				fi
-			fi
-			rm -f "$FIXUP_MSG"
-			if test $failed = t
-			then
-				mv "$SQUASH_MSG" "$MSG" || exit
-				cp "$MSG" "$GIT_DIR"/MERGE_MSG || exit
-				warn
-				warn "Could not apply $sha1... $rest"
-				die_with_patch $sha1 ""
+				do_with_author git commit --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 ||
+					die_failed_squash $sha1 "$rest"
 			fi
-			rm -f "$SQUASH_MSG"
+			rm -f "$SQUASH_MSG" "$FIXUP_MSG"
 			;;
 		esac
 		;;
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index a119ce0..4e35137 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -264,6 +264,42 @@ test_expect_success 'multi-fixup does not fire up editor' '
 	git branch -D multi-fixup
 '
 
+test_expect_success 'commit message used after conflict' '
+	git checkout -b conflict-fixup conflict-branch &&
+	base=$(git rev-parse HEAD~4) &&
+	(
+		FAKE_LINES="1 fixup 3 fixup 4" &&
+		export FAKE_LINES &&
+		test_must_fail git rebase -i $base
+	) &&
+	echo three > conflict &&
+	git add conflict &&
+	FAKE_COMMIT_AMEND="ONCE" EXPECT_HEADER_COUNT=2 \
+		git rebase --continue &&
+	test $base = $(git rev-parse HEAD^) &&
+	test 1 = $(git show | grep ONCE | wc -l) &&
+	git checkout to-be-rebased &&
+	git branch -D conflict-fixup
+'
+
+test_expect_success 'commit message retained after conflict' '
+	git checkout -b conflict-squash conflict-branch &&
+	base=$(git rev-parse HEAD~4) &&
+	(
+		FAKE_LINES="1 fixup 3 squash 4" &&
+		export FAKE_LINES &&
+		test_must_fail git rebase -i $base
+	) &&
+	echo three > conflict &&
+	git add conflict &&
+	FAKE_COMMIT_AMEND="TWICE" EXPECT_HEADER_COUNT=2 \
+		git rebase --continue &&
+	test $base = $(git rev-parse HEAD^) &&
+	test 2 = $(git show | grep TWICE | wc -l) &&
+	git checkout to-be-rebased &&
+	git branch -D conflict-squash
+'
+
 cat > expect-squash-fixup << EOF
 B
 
-- 
1.6.6
Previous: Michael HaggertyNext: Junio C Hamano
Message 32 of 34 in “rebase -i: For pure fixups, do not start log message editor”
  1. 00/18 rebase -i: For pure fixups, do not start log message editorMichael Haggerty, Jan 14, 2010
  2. 01/18 rebase -i: Make the condition for an "if" more transparentMichael Haggerty, Jan 14, 2010
  3. Eric BlakeJan 14, 2010
  4. Junio C HamanoJan 14, 2010
  5. Paolo BonziniJan 15, 2010
  6. Johannes SchindelinJan 25, 2010
  7. Michael HaggertyJan 26, 2010
  8. Johannes SchindelinJan 26, 2010
  9. 02/18 rebase -i: Remove dead codeMichael Haggerty, Jan 14, 2010
  10. 03/18 rebase -i: Inline expressionMichael Haggerty, Jan 14, 2010
  11. 04/18 rebase -i: Use "test -n" instead of "test ! -z"Michael Haggerty, Jan 14, 2010
  12. 05/18 rebase -i: Use symbolic constant $MSG consistentlyMichael Haggerty, Jan 14, 2010
  13. 06/18 rebase -i: Document how temporary files are usedMichael Haggerty, Jan 14, 2010
  14. Greg PriceJan 25, 2010
  15. 07/18 rebase -i: Introduce a constant AUTHOR_SCRIPTMichael Haggerty, Jan 14, 2010
  16. 08/18 rebase -i: Introduce a constant AMENDMichael Haggerty, Jan 14, 2010
  17. 09/18 t3404: Test the commit count in commit messages generated by "rebase -i"Michael Haggerty, Jan 14, 2010
  18. Johannes SixtJan 14, 2010
  19. Michael HaggertyJan 14, 2010
  20. Johannes SixtJan 14, 2010
  21. 10/18 rebase -i: Improve consistency of commit count in generated commit messagesMichael Haggerty, Jan 14, 2010
  22. Johannes SixtJan 14, 2010
  23. Michael HaggertyJan 14, 2010
  24. 11/18 rebase -i: Simplify commit counting for generated commit messagesMichael Haggerty, Jan 14, 2010
  25. 12/18 rebase -i: Extract a function "commit_message"Michael Haggerty, Jan 14, 2010
  26. 13/18 rebase -i: Handle the author script all in one place in do_nextMichael Haggerty, Jan 14, 2010
  27. 14/18 rebase -i: Extract function do_with_authorMichael Haggerty, Jan 14, 2010
  28. 15/18 rebase -i: Change function make_squash_message into update_squash_messageMichael Haggerty, Jan 14, 2010
  29. Johannes SixtJan 14, 2010
  30. 16/18 rebase -i: For fixup commands without squashes, do not start editorMichael Haggerty, Jan 14, 2010
  31. 17/18 t3404: Set up more of the test repo in the "setup" stepMichael Haggerty, Jan 14, 2010
  32. 18/18 rebase -i: Retain user-edited commit messages after squash/fixup conflictsMichael Haggerty, Jan 14, 2010
  33. Junio C HamanoJan 14, 2010
  34. Johannes SchindelinJan 25, 2010

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.