@matheusbsbs / matheus-bagliano / commits / e0af48e496
Fork 0

xdiff-merge: optionally show conflicts in "diff3 -m" style

When showing conflicting merges, we traditionally followed RCS's merge output format. The output shows: <<<<<<< postimage from one side; ======= postimage of the other side; and >>>>>>> Some poeple find it easier to be able to understand what is going on when they can view the common ancestor's version, which is used by "diff3 -m", which shows: <<<<<<< postimage from one side; ||||||| shared preimage; ======= postimage of the other side; and >>>>>>> This is an initial step to bring that as an optional feature to git. Only "git merge-file" has been converted, with "--diff3" option. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Aug 28, 2008 at 01:10 UTC e0af48e49682ea3345f932f6b9e7fa7c5e5e611a
4 files changed +135 -21
builtin-merge-file.c
+8 -2
@@ -4,7 +4,7 @@
4 #include "xdiff-interface.h"
5
6 static const char merge_file_usage[] =
7 -"git merge-file [-p | --stdout] [-q | --quiet] [-L name1 [-L orig [-L name2]]] file1 orig_file file2";
7 +"git merge-file [-p | --stdout] [--diff3] [-q | --quiet] [-L name1 [-L orig [-L name2]]] file1 orig_file file2";
8
9 int cmd_merge_file(int argc, const char **argv, const char *prefix)
10 {
@@ -13,6 +13,8 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
13 mmbuffer_t result = {NULL, 0};
14 xpparam_t xpp = {XDF_NEED_MINIMAL};
15 int ret = 0, i = 0, to_stdout = 0;
16 + int merge_level = XDL_MERGE_ZEALOUS_ALNUM;
17 + int merge_style = 0;
18
19 while (argc > 4) {
20 if (!strcmp(argv[1], "-L") && i < 3) {
@@ -25,6 +27,10 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
27 else if (!strcmp(argv[1], "-q") ||
28 !strcmp(argv[1], "--quiet"))
29 freopen("/dev/null", "w", stderr);
30 + else if (!strcmp(argv[1], "--diff3")) {
31 + merge_style = XDL_MERGE_DIFF3;
32 + merge_level = XDL_MERGE_EAGER;
33 + }
34 else
35 usage(merge_file_usage);
36 argc--;
@@ -46,7 +52,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
52 }
53
54 ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],
49 - &xpp, XDL_MERGE_ZEALOUS_ALNUM, &result);
55 + &xpp, merge_level | merge_style, &result);
56
57 for (i = 0; i < 3; i++)
58 free(mmfs[i].ptr);
t/t6023-merge-file.sh
+37
@@ -161,4 +161,41 @@ test_expect_success 'ZEALOUS_ALNUM' '
161
162 '
163
164 +cat >expect <<\EOF
165 +Dominus regit me,
166 +<<<<<<< new8.txt
167 +et nihil mihi deerit;
168 +
169 +
170 +
171 +
172 +In loco pascuae ibi me collocavit;
173 +super aquam refectionis educavit me.
174 +|||||||
175 +et nihil mihi deerit.
176 +In loco pascuae ibi me collocavit,
177 +super aquam refectionis educavit me;
178 +=======
179 +et nihil mihi deerit,
180 +
181 +
182 +
183 +
184 +In loco pascuae ibi me collocavit --
185 +super aquam refectionis educavit me,
186 +>>>>>>> new9.txt
187 +animam meam convertit,
188 +deduxit me super semitas jusitiae,
189 +propter nomen suum.
190 +Nam et si ambulavero in medio umbrae mortis,
191 +non timebo mala, quoniam TU mecum es:
192 +virga tua et baculus tuus ipsa me consolata sunt.
193 +EOF
194 +
195 +test_expect_success '"diff3 -m" style output' '
196 + test_must_fail git merge-file -p --diff3 \
197 + new8.txt new5.txt new9.txt >actual &&
198 + test_cmp expect actual
199 +'
200 +
201 test_done
xdiff/xdiff.h
+6
@@ -50,10 +50,16 @@ extern "C" {
50 #define XDL_BDOP_CPY 2
51 #define XDL_BDOP_INSB 3
52
53 +/* merge simplification levels */
54 #define XDL_MERGE_MINIMAL 0
55 #define XDL_MERGE_EAGER 1
56 #define XDL_MERGE_ZEALOUS 2
57 #define XDL_MERGE_ZEALOUS_ALNUM 3
58 +#define XDL_MERGE_LEVEL_MASK 0x0f
59 +
60 +/* merge output styles */
61 +#define XDL_MERGE_DIFF3 0x8000
62 +#define XDL_MERGE_STYLE_MASK 0x8000
63
64 typedef struct s_mmfile {
65 char *ptr;
xdiff/xmerge.c
+84 -19
@@ -30,17 +30,32 @@ typedef struct s_xdmerge {
30 * 2 = no conflict, take second.
31 */
32 int mode;
33 + /*
34 + * These point at the respective postimages. E.g. <i1,chg1> is
35 + * how side #1 wants to change the common ancestor; if there is no
36 + * overlap, lines before i1 in the postimage of side #1 appear
37 + * in the merge result as a region touched by neither side.
38 + */
39 long i1, i2;
40 long chg1, chg2;
41 + /*
42 + * These point at the preimage; of course there is just one
43 + * preimage, that is from the shared common ancestor.
44 + */
45 + long i0;
46 + long chg0;
47 } xdmerge_t;
48
49 static int xdl_append_merge(xdmerge_t **merge, int mode,
38 - long i1, long chg1, long i2, long chg2)
50 + long i0, long chg0,
51 + long i1, long chg1,
52 + long i2, long chg2)
53 {
54 xdmerge_t *m = *merge;
55 if (m && (i1 <= m->i1 + m->chg1 || i2 <= m->i2 + m->chg2)) {
56 if (mode != m->mode)
57 m->mode = 0;
58 + m->chg0 = i0 + chg0 - m->i0;
59 m->chg1 = i1 + chg1 - m->i1;
60 m->chg2 = i2 + chg2 - m->i2;
61 } else {
@@ -49,6 +64,8 @@ static int xdl_append_merge(xdmerge_t **merge, int mode,
64 return -1;
65 m->next = NULL;
66 m->mode = mode;
67 + m->i0 = i0;
68 + m->chg0 = chg0;
69 m->i1 = i1;
70 m->chg1 = chg1;
71 m->i2 = i2;
@@ -91,11 +108,13 @@ static int xdl_merge_cmp_lines(xdfenv_t *xe1, int i1, xdfenv_t *xe2, int i2,
108 return 0;
109 }
110
94 -static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
111 +static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add_nl, char *dest)
112 {
96 - xrecord_t **recs = xe->xdf2.recs + i;
113 + xrecord_t **recs;
114 int size = 0;
115
116 + recs = (use_orig ? xe->xdf1.recs : xe->xdf2.recs) + i;
117 +
118 if (count < 1)
119 return 0;
120
@@ -113,9 +132,19 @@ static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
132 return size;
133 }
134
135 +static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
136 +{
137 + return xdl_recs_copy_0(0, xe, i, count, add_nl, dest);
138 +}
139 +
140 +static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
141 +{
142 + return xdl_recs_copy_0(1, xe, i, count, add_nl, dest);
143 +}
144 +
145 static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
146 xdfenv_t *xe2, const char *name2,
118 - int size, int i,
147 + int size, int i, int style,
148 xdmerge_t *m, char *dest)
149 {
150 const int marker_size = 7;
@@ -143,6 +172,20 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
172 /* Postimage from side #1 */
173 size += xdl_recs_copy(xe1, m->i1, m->chg1, 1,
174 dest ? dest + size : NULL);
175 +
176 + if (style == XDL_MERGE_DIFF3) {
177 + /* Shared preimage */
178 + if (!dest) {
179 + size += marker_size + 1;
180 + } else {
181 + for (j = 0; j < marker_size; j++)
182 + dest[size++] = '|';
183 + dest[size++] = '\n';
184 + }
185 + size += xdl_orig_copy(xe1, m->i0, m->chg0, 1,
186 + dest ? dest + size : NULL);
187 + }
188 +
189 if (!dest) {
190 size += marker_size + 1;
191 } else {
@@ -170,14 +213,15 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
213 }
214
215 static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
173 - xdfenv_t *xe2, const char *name2, xdmerge_t *m, char *dest)
216 + xdfenv_t *xe2, const char *name2,
217 + xdmerge_t *m, char *dest, int style)
218 {
219 int size, i;
220
221 for (size = i = 0; m; m = m->next) {
222 if (m->mode == 0)
223 size = fill_conflict_hunk(xe1, name1, xe2, name2,
180 - size, i, m, dest);
224 + size, i, style, m, dest);
225 else if (m->mode == 1)
226 size += xdl_recs_copy(xe1, i, m->i1 + m->chg1 - i, 0,
227 dest ? dest + size : NULL);
@@ -342,9 +386,11 @@ static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m,
386 */
387 static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
388 xdfenv_t *xe2, xdchange_t *xscr2, const char *name2,
345 - int level, xpparam_t const *xpp, mmbuffer_t *result) {
389 + int flags, xpparam_t const *xpp, mmbuffer_t *result) {
390 xdmerge_t *changes, *c;
347 - int i1, i2, chg1, chg2;
391 + int i0, i1, i2, chg0, chg1, chg2;
392 + int level = flags & XDL_MERGE_LEVEL_MASK;
393 + int style = flags & XDL_MERGE_STYLE_MASK;
394
395 c = changes = NULL;
396
@@ -352,11 +398,14 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
398 if (!changes)
399 changes = c;
400 if (xscr1->i1 + xscr1->chg1 < xscr2->i1) {
401 + i0 = xscr1->i1;
402 i1 = xscr1->i2;
403 i2 = xscr2->i2 - xscr2->i1 + xscr1->i1;
404 + chg0 = xscr1->chg1;
405 chg1 = xscr1->chg2;
406 chg2 = xscr1->chg1;
359 - if (xdl_append_merge(&c, 1, i1, chg1, i2, chg2)) {
407 + if (xdl_append_merge(&c, 1,
408 + i0, chg0, i1, chg1, i2, chg2)) {
409 xdl_cleanup_merge(changes);
410 return -1;
411 }
@@ -364,11 +413,14 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
413 continue;
414 }
415 if (xscr2->i1 + xscr2->chg1 < xscr1->i1) {
416 + i0 = xscr2->i1;
417 i1 = xscr1->i2 - xscr1->i1 + xscr2->i1;
418 i2 = xscr2->i2;
419 + chg0 = xscr2->chg1;
420 chg1 = xscr2->chg1;
421 chg2 = xscr2->chg2;
371 - if (xdl_append_merge(&c, 2, i1, chg1, i2, chg2)) {
422 + if (xdl_append_merge(&c, 2,
423 + i0, chg0, i1, chg1, i2, chg2)) {
424 xdl_cleanup_merge(changes);
425 return -1;
426 }
@@ -385,19 +437,26 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
437 int off = xscr1->i1 - xscr2->i1;
438 int ffo = off + xscr1->chg1 - xscr2->chg1;
439
440 + i0 = xscr1->i1;
441 i1 = xscr1->i2;
442 i2 = xscr2->i2;
390 - if (off > 0)
443 + if (off > 0) {
444 + i0 -= off;
445 i1 -= off;
446 + }
447 else
448 i2 += off;
449 + chg0 = xscr1->i1 + xscr1->chg1 - i0;
450 chg1 = xscr1->i2 + xscr1->chg2 - i1;
451 chg2 = xscr2->i2 + xscr2->chg2 - i2;
452 if (ffo > 0)
453 chg2 += ffo;
398 - else
454 + else {
455 + chg0 -= ffo;
456 chg1 -= ffo;
400 - if (xdl_append_merge(&c, 0, i1, chg1, i2, chg2)) {
457 + }
458 + if (xdl_append_merge(&c, 0,
459 + i0, chg0, i1, chg1, i2, chg2)) {
460 xdl_cleanup_merge(changes);
461 return -1;
462 }
@@ -414,11 +473,14 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
473 while (xscr1) {
474 if (!changes)
475 changes = c;
476 + i0 = xscr1->i1;
477 i1 = xscr1->i2;
478 i2 = xscr1->i1 + xe2->xdf2.nrec - xe2->xdf1.nrec;
479 + chg0 = xscr1->chg1;
480 chg1 = xscr1->chg2;
481 chg2 = xscr1->chg1;
421 - if (xdl_append_merge(&c, 1, i1, chg1, i2, chg2)) {
482 + if (xdl_append_merge(&c, 1,
483 + i0, chg0, i1, chg1, i2, chg2)) {
484 xdl_cleanup_merge(changes);
485 return -1;
486 }
@@ -427,11 +489,14 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
489 while (xscr2) {
490 if (!changes)
491 changes = c;
492 + i0 = xscr2->i1;
493 i1 = xscr2->i1 + xe1->xdf2.nrec - xe1->xdf1.nrec;
494 i2 = xscr2->i2;
495 + chg0 = xscr2->chg1;
496 chg1 = xscr2->chg1;
497 chg2 = xscr2->chg2;
434 - if (xdl_append_merge(&c, 2, i1, chg1, i2, chg2)) {
498 + if (xdl_append_merge(&c, 2,
499 + i0, chg0, i1, chg1, i2, chg2)) {
500 xdl_cleanup_merge(changes);
501 return -1;
502 }
@@ -449,7 +514,7 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
514 /* output */
515 if (result) {
516 int size = xdl_fill_merge_buffer(xe1, name1, xe2, name2,
452 - changes, NULL);
517 + changes, NULL, style);
518 result->ptr = xdl_malloc(size);
519 if (!result->ptr) {
520 xdl_cleanup_merge(changes);
@@ -457,14 +522,14 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
522 }
523 result->size = size;
524 xdl_fill_merge_buffer(xe1, name1, xe2, name2, changes,
460 - result->ptr);
525 + result->ptr, style);
526 }
527 return xdl_cleanup_merge(changes);
528 }
529
530 int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
531 mmfile_t *mf2, const char *name2,
467 - xpparam_t const *xpp, int level, mmbuffer_t *result) {
532 + xpparam_t const *xpp, int flags, mmbuffer_t *result) {
533 xdchange_t *xscr1, *xscr2;
534 xdfenv_t xe1, xe2;
535 int status;
@@ -501,7 +566,7 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
566 } else {
567 status = xdl_do_merge(&xe1, xscr1, name1,
568 &xe2, xscr2, name2,
504 - level, xpp, result);
569 + flags, xpp, result);
570 }
571 xdl_free_script(xscr1);
572 xdl_free_script(xscr2);