Skip to content

Commit eac5a40

Browse files
committed
checkout --conflict=<style>: recreate merge in a non-default style
This new option does essentially the same thing as -m option when checking unmerged paths out of the index, but it uses the specified style instead of configured merge.conflictstyle. Setting "merge.conflictstyle" to "diff3" is usually less useful than using the default "merge" style, because the latter allows a conflict that results by both sides changing the same region in a very similar way to get simplified substancially by reducing the common lines. However, when one side removed a group of lines (perhaps a function was moved to some other file) while the other side modified it, the default "merge" style does not give any clue as to why the hunk is left conflicting. You would need the original to understand what is going on. The recommended use would be not to set merge.conflictstyle variable so that you would usually use the default "merge" style conflict, and when the result in a path in a particular merge is too hard to understand, use "git checkout --conflict=diff3 $path" to check it out with the original to review what is going on. Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 0cf8581 commit eac5a40

File tree

3 files changed

+72
-48
lines changed

3 files changed

+72
-48
lines changed

Documentation/git-checkout.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ SYNOPSIS
99
--------
1010
[verse]
1111
'git checkout' [-q] [-f] [[--track | --no-track] -b <new_branch> [-l]] [-m] [<branch>]
12-
'git checkout' [-f|--ours|--theirs|-m] [<tree-ish>] [--] <paths>...
12+
'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
1313

1414
DESCRIPTION
1515
-----------
@@ -84,6 +84,7 @@ entries; instead, unmerged entries are ignored.
8484
based sha1 expressions such as "<branchname>@\{yesterday}".
8585

8686
-m::
87+
--merge::
8788
When switching branches,
8889
if you have local modifications to one or more files that
8990
are different between the current branch and the branch to
@@ -101,6 +102,13 @@ should result in deletion of the path).
101102
When checking out paths from the index, this option lets you recreate
102103
the conflicted merge in the specified paths.
103104

105+
--conflict=<style>::
106+
The same as --merge option above, but changes the way the
107+
conflicting hunks are presented, overriding the
108+
merge.conflictstyle configuration variable. Possible values are
109+
"merge" (default) and "diff3" (in addition to what is shown by
110+
"merge" style, shows the original contents).
111+
104112
<new_branch>::
105113
Name for the new branch.
106114

builtin-checkout.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
580580
const char *arg;
581581
struct branch_info new;
582582
struct tree *source_tree = NULL;
583+
char *conflict_style = NULL;
583584
struct option options[] = {
584585
OPT__QUIET(&opts.quiet),
585586
OPT_STRING('b', NULL, &opts.new_branch, "new branch", "branch"),
@@ -591,7 +592,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
591592
OPT_SET_INT('3', "theirs", &opts.writeout_stage, "stage",
592593
3),
593594
OPT_BOOLEAN('f', NULL, &opts.force, "force"),
594-
OPT_BOOLEAN('m', NULL, &opts.merge, "merge"),
595+
OPT_BOOLEAN('m', "merge", &opts.merge, "merge"),
596+
OPT_STRING(0, "conflict", &conflict_style, "style",
597+
"conflict style (merge or diff3)"),
595598
OPT_END(),
596599
};
597600
int has_dash_dash;
@@ -606,6 +609,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
606609
argc = parse_options(argc, argv, options, checkout_usage,
607610
PARSE_OPT_KEEP_DASHDASH);
608611

612+
if (conflict_style) {
613+
opts.merge = 1; /* implied */
614+
git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
615+
}
616+
609617
if (!opts.new_branch && (opts.track != git_branch_track))
610618
die("git checkout: --track and --no-track require -b");
611619

t/t7201-co.sh

Lines changed: 54 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ test_expect_success \
337337
test refs/heads/delete-me = "$(git symbolic-ref HEAD)" &&
338338
test_must_fail git checkout --track -b track'
339339

340-
test_expect_success 'checkout an unmerged path should fail' '
340+
setup_conflicting_index () {
341341
rm -f .git/index &&
342342
O=$(echo original | git hash-object -w --stdin) &&
343343
A=$(echo ourside | git hash-object -w --stdin) &&
@@ -348,7 +348,11 @@ test_expect_success 'checkout an unmerged path should fail' '
348348
echo "100644 $A 2 file" &&
349349
echo "100644 $B 3 file" &&
350350
echo "100644 $A 0 filf"
351-
) | git update-index --index-info &&
351+
) | git update-index --index-info
352+
}
353+
354+
test_expect_success 'checkout an unmerged path should fail' '
355+
setup_conflicting_index &&
352356
echo "none of the above" >sample &&
353357
cat sample >fild &&
354358
cat sample >file &&
@@ -360,17 +364,7 @@ test_expect_success 'checkout an unmerged path should fail' '
360364
'
361365

362366
test_expect_success 'checkout with an unmerged path can be ignored' '
363-
rm -f .git/index &&
364-
O=$(echo original | git hash-object -w --stdin) &&
365-
A=$(echo ourside | git hash-object -w --stdin) &&
366-
B=$(echo theirside | git hash-object -w --stdin) &&
367-
(
368-
echo "100644 $A 0 fild" &&
369-
echo "100644 $O 1 file" &&
370-
echo "100644 $A 2 file" &&
371-
echo "100644 $B 3 file" &&
372-
echo "100644 $A 0 filf"
373-
) | git update-index --index-info &&
367+
setup_conflicting_index &&
374368
echo "none of the above" >sample &&
375369
echo ourside >expect &&
376370
cat sample >fild &&
@@ -383,17 +377,7 @@ test_expect_success 'checkout with an unmerged path can be ignored' '
383377
'
384378

385379
test_expect_success 'checkout unmerged stage' '
386-
rm -f .git/index &&
387-
O=$(echo original | git hash-object -w --stdin) &&
388-
A=$(echo ourside | git hash-object -w --stdin) &&
389-
B=$(echo theirside | git hash-object -w --stdin) &&
390-
(
391-
echo "100644 $A 0 fild" &&
392-
echo "100644 $O 1 file" &&
393-
echo "100644 $A 2 file" &&
394-
echo "100644 $B 3 file" &&
395-
echo "100644 $A 0 filf"
396-
) | git update-index --index-info &&
380+
setup_conflicting_index &&
397381
echo "none of the above" >sample &&
398382
echo ourside >expect &&
399383
cat sample >fild &&
@@ -408,17 +392,7 @@ test_expect_success 'checkout unmerged stage' '
408392
'
409393

410394
test_expect_success 'checkout with --merge' '
411-
rm -f .git/index &&
412-
O=$(echo original | git hash-object -w --stdin) &&
413-
A=$(echo ourside | git hash-object -w --stdin) &&
414-
B=$(echo theirside | git hash-object -w --stdin) &&
415-
(
416-
echo "100644 $A 0 fild" &&
417-
echo "100644 $O 1 file" &&
418-
echo "100644 $A 2 file" &&
419-
echo "100644 $B 3 file" &&
420-
echo "100644 $A 0 filf"
421-
) | git update-index --index-info &&
395+
setup_conflicting_index &&
422396
echo "none of the above" >sample &&
423397
echo ourside >expect &&
424398
cat sample >fild &&
@@ -439,17 +413,7 @@ test_expect_success 'checkout with --merge' '
439413

440414
test_expect_success 'checkout with --merge, in diff3 -m style' '
441415
git config merge.conflictstyle diff3 &&
442-
rm -f .git/index &&
443-
O=$(echo original | git hash-object -w --stdin) &&
444-
A=$(echo ourside | git hash-object -w --stdin) &&
445-
B=$(echo theirside | git hash-object -w --stdin) &&
446-
(
447-
echo "100644 $A 0 fild" &&
448-
echo "100644 $O 1 file" &&
449-
echo "100644 $A 2 file" &&
450-
echo "100644 $B 3 file" &&
451-
echo "100644 $A 0 filf"
452-
) | git update-index --index-info &&
416+
setup_conflicting_index &&
453417
echo "none of the above" >sample &&
454418
echo ourside >expect &&
455419
cat sample >fild &&
@@ -470,4 +434,48 @@ test_expect_success 'checkout with --merge, in diff3 -m style' '
470434
test_cmp merged file
471435
'
472436

437+
test_expect_success 'checkout --conflict=merge, overriding config' '
438+
git config merge.conflictstyle diff3 &&
439+
setup_conflicting_index &&
440+
echo "none of the above" >sample &&
441+
echo ourside >expect &&
442+
cat sample >fild &&
443+
cat sample >file &&
444+
cat sample >filf &&
445+
git checkout --conflict=merge -- fild file filf &&
446+
(
447+
echo "<<<<<<< ours"
448+
echo ourside
449+
echo "======="
450+
echo theirside
451+
echo ">>>>>>> theirs"
452+
) >merged &&
453+
test_cmp expect fild &&
454+
test_cmp expect filf &&
455+
test_cmp merged file
456+
'
457+
458+
test_expect_success 'checkout --conflict=diff3' '
459+
git config --unset merge.conflictstyle
460+
setup_conflicting_index &&
461+
echo "none of the above" >sample &&
462+
echo ourside >expect &&
463+
cat sample >fild &&
464+
cat sample >file &&
465+
cat sample >filf &&
466+
git checkout --conflict=diff3 -- fild file filf &&
467+
(
468+
echo "<<<<<<< ours"
469+
echo ourside
470+
echo "|||||||"
471+
echo original
472+
echo "======="
473+
echo theirside
474+
echo ">>>>>>> theirs"
475+
) >merged &&
476+
test_cmp expect fild &&
477+
test_cmp expect filf &&
478+
test_cmp merged file
479+
'
480+
473481
test_done

0 commit comments

Comments
 (0)