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

[PATCH v2 5/5] checkout: fix interaction between --conflict and --merge

From
PGPhillip Wood via GitGitGadget <gitgitgadget@gmail.com>
Date
Mar 14, 2024, 17:05 UTC
Message-ID
<b771b29e45abd1992e46c174dcaebe20ca8a41f9.1710435907.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.1684.v2.git.1710435907.gitgitgadget@gmail.com>
From: Phillip Wood <phillip.wood@dunelm.org.uk>

When using "git checkout" to recreate merge conflicts or merge uncommitted changes when switching branch "--conflict" sensibly implies "--merge". Unfortunately the way this is implemented means that "git checkout --conflict=diff3 --no-merge" implies "--merge" violating the usual last-one-wins rule. Fix this by only overriding the value of opts->merge if "--conflicts" comes after "--no-merge" or "-[-no]-merge" is not given on the command line.

The behavior of "git checkout --merge --no-conflict" is unchanged and will still merge on the basis that the "-[-no]-conflict" options are primarily intended to affect the conflict style and so "--no-conflict" should cancel a previous "--conflict" but not override "--merge".

Of the four new tests the second one tests the behavior change introduced by this commit, the other three check that this commit does not regress the existing behavior.

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
---
 builtin/checkout.c | 10 +++++---
 t/t7201-co.sh      | 60 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 3 deletions(-)
diff --git a/builtin/checkout.c b/builtin/checkout.c
index d6ab3b1d665..b8ce1904897 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -100,7 +100,7 @@ struct checkout_opts {
 	struct tree *source_tree;
 };
 
-#define CHECKOUT_OPTS_INIT { .conflict_style = -1 }
+#define CHECKOUT_OPTS_INIT { .conflict_style = -1, .merge = -1 }
 
 struct branch_info {
 	char *name; /* The short name used */
@@ -1635,6 +1635,9 @@ static int parse_opt_conflict(const struct option *o, const char *arg, int unset
 	opts->conflict_style = parse_conflict_style_name(arg);
 	if (opts->conflict_style < 0)
 		return error(_("unknown conflict style '%s'"), arg);
+	/* --conflict overrides a previous --no-merge */
+	if (!opts->merge)
+		opts->merge = -1;
 
 	return 0;
 }
@@ -1742,8 +1745,9 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
 			opts->show_progress = isatty(2);
 	}
 
-	if (opts->conflict_style >= 0)
-		opts->merge = 1; /* implied */
+	/* --conflicts implies --merge */
+	if (opts->merge == -1)
+		opts->merge = opts->conflict_style >= 0;
 
 	if (opts->force) {
 		opts->discard_changes = 1;
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index e1f85a91565..42352dc0dbe 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -631,6 +631,66 @@ test_expect_success 'checkout --conflict=diff3' '
 	test_cmp merged file
 '
 
+test_expect_success 'checkout --conflict=diff3 --no-conflict does not merge' '
+	setup_conflicting_index &&
+	echo "none of the above" >expect &&
+	cat expect >fild &&
+	cat expect >file &&
+	test_must_fail git checkout --conflict=diff3 --no-conflict -- fild file 2>err &&
+	test_cmp expect file &&
+	test_cmp expect fild &&
+	echo "error: path ${SQ}file${SQ} is unmerged" >expect &&
+	test_cmp expect err
+'
+
+test_expect_success 'checkout --conflict=diff3 --no-merge does not merge' '
+	setup_conflicting_index &&
+	echo "none of the above" >expect &&
+	cat expect >fild &&
+	cat expect >file &&
+	test_must_fail git checkout --conflict=diff3 --no-merge -- fild file 2>err &&
+	test_cmp expect file &&
+	test_cmp expect fild &&
+	echo "error: path ${SQ}file${SQ} is unmerged" >expect &&
+	test_cmp expect err
+'
+
+test_expect_success 'checkout --no-merge --conflict=diff3 does merge' '
+	setup_conflicting_index &&
+	echo "none of the above" >fild &&
+	echo "none of the above" >file &&
+	git checkout --no-merge --conflict=diff3 -- fild file &&
+	echo "ourside" >expect &&
+	test_cmp expect fild &&
+	cat >expect <<-\EOF &&
+	<<<<<<< ours
+	ourside
+	||||||| base
+	original
+	=======
+	theirside
+	>>>>>>> theirs
+	EOF
+	test_cmp expect file
+'
+
+test_expect_success 'checkout --merge --conflict=diff3 --no-conflict does merge' '
+	setup_conflicting_index &&
+	echo "none of the above" >fild &&
+	echo "none of the above" >file &&
+	git checkout --merge --conflict=diff3 --no-conflict -- fild file &&
+	echo "ourside" >expect &&
+	test_cmp expect fild &&
+	cat >expect <<-\EOF &&
+	<<<<<<< ours
+	ourside
+	=======
+	theirside
+	>>>>>>> theirs
+	EOF
+	test_cmp expect file
+'
+
 test_expect_success 'checkout with invalid conflict style' '
 	test_must_fail git checkout --conflict=bad 2>actual -- file &&
 	echo "error: unknown conflict style ${SQ}bad${SQ}" >expect &&
-- 
gitgitgadget
Previous: Junio C HamanoNext: Junio C Hamano
Message 27 of 29 in “checkout: cleanup --conflict=”
  1. 0/4 checkout: cleanup --conflict=Phillip Wood via GitGitGadget, Mar 8, 2024
  2. 1/4 xdiff-interface: refactor parsing of merge.conflictstylePhillip Wood via GitGitGadget, Mar 8, 2024
  3. 2/4 merge-ll: introduce LL_MERGE_OPTIONS_INITPhillip Wood via GitGitGadget, Mar 8, 2024
  4. 3/4 merge options: add a conflict style memberPhillip Wood via GitGitGadget, Mar 8, 2024
  5. Junio C HamanoMar 8, 2024
  6. phillip.wood123@gmail.comMar 8, 2024
  7. Junio C HamanoMar 8, 2024
  8. Elijah NewrenMar 9, 2024
  9. Junio C HamanoMar 9, 2024
  10. 4/4 checkout: cleanup --conflict=<style> parsingPhillip Wood via GitGitGadget, Mar 8, 2024
  11. Junio C HamanoMar 8, 2024
  12. phillip.wood123@gmail.comMar 8, 2024
  13. Junio C HamanoMar 8, 2024
  14. phillip.wood123@gmail.comMar 11, 2024
  15. Junio C HamanoMar 11, 2024
  16. Phillip WoodMar 12, 2024
  17. Junio C HamanoMar 8, 2024
  18. phillip.wood123@gmail.comMar 8, 2024
  19. 0/5 checkout: cleanup --conflict=Phillip Wood via GitGitGadget, Mar 14, 2024
  20. 1/5 xdiff-interface: refactor parsing of merge.conflictstylePhillip Wood via GitGitGadget, Mar 14, 2024
  21. Junio C HamanoMar 14, 2024
  22. 2/5 merge-ll: introduce LL_MERGE_OPTIONS_INITPhillip Wood via GitGitGadget, Mar 14, 2024
  23. 3/5 merge options: add a conflict style memberPhillip Wood via GitGitGadget, Mar 14, 2024
  24. Junio C HamanoMar 14, 2024
  25. 4/5 checkout: cleanup --conflict=<style> parsingPhillip Wood via GitGitGadget, Mar 14, 2024
  26. Junio C HamanoMar 14, 2024
  27. 5/5 checkout: fix interaction between --conflict and --mergePhillip Wood via GitGitGadget, Mar 14, 2024
  28. Junio C HamanoMar 14, 2024
  29. Phillip WoodMar 14, 2024

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.