Skip to content

Commit ab43a54

Browse files
committed
Merge branch 'ad/merge-file-diff-algo' into next
"git merge-file" learned to take the "--diff-algorithm" option to use algorithm different from the default "myers" diff. * ad/merge-file-diff-algo: merge-file: add --diff-algorithm option
2 parents 9ac1707 + 4f7fd79 commit ab43a54

File tree

3 files changed

+157
-1
lines changed

3 files changed

+157
-1
lines changed

Documentation/git-merge-file.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ object store and the object ID of its blob is written to standard output.
9292
Instead of leaving conflicts in the file, resolve conflicts
9393
favouring our (or their or both) side of the lines.
9494

95+
--diff-algorithm={patience|minimal|histogram|myers}::
96+
Use a different diff algorithm while merging. The current default is "myers",
97+
but selecting more recent algorithm such as "histogram" can help
98+
avoid mismerges that occur due to unimportant matching lines
99+
(such as braces from distinct functions). See also
100+
linkgit:git-diff[1] `--diff-algorithm`.
95101

96102
EXAMPLES
97103
--------

builtin/merge-file.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "builtin.h"
22
#include "abspath.h"
3+
#include "diff.h"
34
#include "hex.h"
45
#include "object-name.h"
56
#include "object-store.h"
@@ -28,6 +29,30 @@ static int label_cb(const struct option *opt, const char *arg, int unset)
2829
return 0;
2930
}
3031

32+
static int set_diff_algorithm(xpparam_t *xpp,
33+
const char *alg)
34+
{
35+
long diff_algorithm = parse_algorithm_value(alg);
36+
if (diff_algorithm < 0)
37+
return -1;
38+
xpp->flags = (xpp->flags & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;
39+
return 0;
40+
}
41+
42+
static int diff_algorithm_cb(const struct option *opt,
43+
const char *arg, int unset)
44+
{
45+
xpparam_t *xpp = opt->value;
46+
47+
BUG_ON_OPT_NEG(unset);
48+
49+
if (set_diff_algorithm(xpp, arg))
50+
return error(_("option diff-algorithm accepts \"myers\", "
51+
"\"minimal\", \"patience\" and \"histogram\""));
52+
53+
return 0;
54+
}
55+
3156
int cmd_merge_file(int argc, const char **argv, const char *prefix)
3257
{
3358
const char *names[3] = { 0 };
@@ -48,6 +73,9 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
4873
XDL_MERGE_FAVOR_THEIRS),
4974
OPT_SET_INT(0, "union", &xmp.favor, N_("for conflicts, use a union version"),
5075
XDL_MERGE_FAVOR_UNION),
76+
OPT_CALLBACK_F(0, "diff-algorithm", &xmp.xpp, N_("<algorithm>"),
77+
N_("choose a diff algorithm"),
78+
PARSE_OPT_NONEG, diff_algorithm_cb),
5179
OPT_INTEGER(0, "marker-size", &xmp.marker_size,
5280
N_("for conflicts, use this marker size")),
5381
OPT__QUIET(&quiet, N_("do not warn about conflicts")),

t/t6403-merge-file.sh

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,67 @@ test_expect_success 'setup' '
5656
deduxit me super semitas jusitiae,
5757
EOF
5858
59-
printf "propter nomen suum." >>new4.txt
59+
printf "propter nomen suum." >>new4.txt &&
60+
61+
cat >base.c <<-\EOF &&
62+
int f(int x, int y)
63+
{
64+
if (x == 0)
65+
{
66+
return y;
67+
}
68+
return x;
69+
}
70+
71+
int g(size_t u)
72+
{
73+
while (u < 30)
74+
{
75+
u++;
76+
}
77+
return u;
78+
}
79+
EOF
80+
81+
cat >ours.c <<-\EOF &&
82+
int g(size_t u)
83+
{
84+
while (u < 30)
85+
{
86+
u++;
87+
}
88+
return u;
89+
}
90+
91+
int h(int x, int y, int z)
92+
{
93+
if (z == 0)
94+
{
95+
return x;
96+
}
97+
return y;
98+
}
99+
EOF
100+
101+
cat >theirs.c <<-\EOF
102+
int f(int x, int y)
103+
{
104+
if (x == 0)
105+
{
106+
return y;
107+
}
108+
return x;
109+
}
110+
111+
int g(size_t u)
112+
{
113+
while (u > 34)
114+
{
115+
u--;
116+
}
117+
return u;
118+
}
119+
EOF
60120
'
61121

62122
test_expect_success 'merge with no changes' '
@@ -447,4 +507,66 @@ test_expect_success '--object-id fails without repository' '
447507
grep "not a git repository" err
448508
'
449509

510+
test_expect_success 'merging C files with "myers" diff algorithm creates some spurious conflicts' '
511+
cat >expect.c <<-\EOF &&
512+
int g(size_t u)
513+
{
514+
while (u < 30)
515+
{
516+
u++;
517+
}
518+
return u;
519+
}
520+
521+
int h(int x, int y, int z)
522+
{
523+
<<<<<<< ours.c
524+
if (z == 0)
525+
||||||| base.c
526+
while (u < 30)
527+
=======
528+
while (u > 34)
529+
>>>>>>> theirs.c
530+
{
531+
<<<<<<< ours.c
532+
return x;
533+
||||||| base.c
534+
u++;
535+
=======
536+
u--;
537+
>>>>>>> theirs.c
538+
}
539+
return y;
540+
}
541+
EOF
542+
543+
test_must_fail git merge-file -p --diff3 --diff-algorithm myers ours.c base.c theirs.c >myers_output.c &&
544+
test_cmp expect.c myers_output.c
545+
'
546+
547+
test_expect_success 'merging C files with "histogram" diff algorithm avoids some spurious conflicts' '
548+
cat >expect.c <<-\EOF &&
549+
int g(size_t u)
550+
{
551+
while (u > 34)
552+
{
553+
u--;
554+
}
555+
return u;
556+
}
557+
558+
int h(int x, int y, int z)
559+
{
560+
if (z == 0)
561+
{
562+
return x;
563+
}
564+
return y;
565+
}
566+
EOF
567+
568+
git merge-file -p --diff3 --diff-algorithm histogram ours.c base.c theirs.c >histogram_output.c &&
569+
test_cmp expect.c histogram_output.c
570+
'
571+
450572
test_done

0 commit comments

Comments
 (0)