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

Re: [BUG] git-rebase: reword squashes commits in case of merge-conflicts

From
Elijah Newren <newren@gmail.com>
Date
Jun 16, 2018, 16:08 UTC
Message-ID
<20180616160804.10914-1-newren@gmail.com>
In-Reply-To
<8e28202a-8646-53e8-8c22-389d61791c70@onlinehome.de>
On Mon, Jun 11, 2018 at 06:06:11PM +0200, ch wrote:
Show 6 quoted lines
> During a recent rebase operation on one of my repositories a number of commits
> unexpectedly ended up getting squashed into other commits. After some
> experiments it turned out that the 'reword' instruction seems to squash the
> referenced commit into the preceding commit if there's a merge-conflict.
> 
> Here's a small reproduction recipe to illustrate the behavior:

Indeed I can reproduce. It bisects back to when we switched to using the rebase-helper builtin, so this started with git-2.13.0. I can also slim down your reproduction testcase a bit; you don't need any additional commits after the reword, and the only reason to have commits before it is to induce a merge conflict by dropping them. The fact that there are lots of fixups floating around is not necessary.

Anyway, patch below.
-- >8 --
Subject: [PATCH] sequencer: do not squash 'reword' commits when we hit
 conflicts

Ever since commit 18633e1a22 ("rebase -i: use the rebase--helper builtin", 2017-02-09), when a commit marked as 'reword' in an interactive rebase has conflicts and fails to apply, when the rebase is resumed that commit will be squashed into its parent with its commit message taken.

The issue can be understood better by looking at commit 56dc3ab04b ("sequencer (rebase -i): implement the 'edit' command", 2017-01-02), which introduced error_with_patch() for the edit command. For the edit command, it needs to stop the rebase whether or not the patch applies cleanly. If the patch does apply cleanly, then when it resumes it knows it needs to amend all changes into the previous commit. If it does not apply cleanly, then the changes should not be amended. Thus, it passes !res (success of applying the 'edit' commit) to error_with_patch() for the to_amend flag.

The problematic line of code actually came from commit 04efc8b57c
("sequencer (rebase -i): implement the 'reword' command", 2017-01-02).
Note that to get to this point in the code:
  * !!res (i.e. patch application failed)
  * item->command < TODO_SQUASH
  * item->command != TODO_EDIT
  * !is_fixup(item->command) [i.e. not squash or fixup]
So that means this can only be a failed patch application that is either a
pick, revert, or reword.  For any of those cases we want a new commit, so
we should not set the to_amend flag.
Reported-by: ch <cr@onlinehome.de>
Signed-off-by: Elijah Newren <newren@gmail.com>
---
 sequencer.c              |  2 +-
 t/t3423-rebase-reword.sh | 44 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+), 1 deletion(-)
 create mode 100755 t/t3423-rebase-reword.sh
diff --git a/sequencer.c b/sequencer.c
index cca968043e..9e6d1ee368 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -3217,7 +3217,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
 			} else if (res && is_rebase_i(opts) && item->commit)
 				return res | error_with_patch(item->commit,
 					item->arg, item->arg_len, opts, res,
-					item->command == TODO_REWORD);
+					0);
 		} else if (item->command == TODO_EXEC) {
 			char *end_of_arg = (char *)(item->arg + item->arg_len);
 			int saved = *end_of_arg;
diff --git a/t/t3423-rebase-reword.sh b/t/t3423-rebase-reword.sh
new file mode 100755
index 0000000000..31c09efd22
--- /dev/null
+++ b/t/t3423-rebase-reword.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+test_description='git rebase interactive with rewording'
+
+. ./test-lib.sh
+
+. "$TEST_DIRECTORY"/lib-rebase.sh
+
+test_expect_success 'setup' '
+	test_commit master file-1 test &&
+
+	git checkout -b stuff &&
+
+	test_commit feature_a file-2 aaa &&
+	test_commit feature_b file-2 ddd
+'
+
+test_expect_success 'reword without issues functions as intended' '
+	git checkout stuff^0 &&
+
+	set_fake_editor &&
+	FAKE_LINES="pick 1 reword 2" FAKE_COMMIT_MESSAGE="feature_b_reworded" \
+		git rebase -i -v master &&
+
+	test "$(git log -1 --format=%B)" = "feature_b_reworded" &&
+	test $(git rev-list --count HEAD) = 3
+'
+
+test_expect_success 'reword comes after a conflict preserves commit' '
+	git checkout stuff^0 &&
+
+	set_fake_editor &&
+	test_must_fail env FAKE_LINES="reword 2" \
+		git rebase -i -v master &&
+
+	git checkout --theirs file-2 &&
+	git add file-2 &&
+	FAKE_COMMIT_MESSAGE="feature_b_reworded" git rebase --continue &&
+
+	test "$(git log -1 --format=%B)" = "feature_b_reworded" &&
+	test $(git rev-list --count HEAD) = 2
+'
+
+test_done
-- 
2.18.0.rc2.3.g7fc0d4cb57
Previous: chNext: Eric Sunshine
Message 4 of 19 in “[BUG] git-rebase: reword squashes commits in case of merge-conflicts”
  1. chJun 11, 2018
  2. Jeff KingJun 12, 2018
  3. chJun 15, 2018
  4. Elijah NewrenJun 16, 2018
  5. Eric SunshineJun 17, 2018
  6. sequencer: do not squash 'reword' commits when we hit conflictsElijah Newren, Jun 17, 2018
  7. Phillip WoodJun 17, 2018
  8. Johannes SchindelinJun 17, 2018
  9. Phillip WoodJun 18, 2018
  10. Junio C HamanoJun 18, 2018
  11. Johannes SchindelinJun 18, 2018
  12. Phillip WoodJun 19, 2018
  13. sequencer: do not squash 'reword' commits when we hit conflictsPhillip Wood, Jun 19, 2018
  14. Elijah NewrenJun 19, 2018
  15. Junio C HamanoJun 19, 2018
  16. t/lib-rebase.sh: support explicit 'pick' commands in 'fake_editor.sh'SZEDER Gábor, Aug 23, 2018
  17. Junio C HamanoAug 23, 2018
  18. Johannes SchindelinAug 23, 2018
  19. Johannes SchindelinJun 17, 2018

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.