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>
This commit is contained in:
parent
f2b25dd81f
commit
e0af48e496
@ -4,7 +4,7 @@
|
||||
#include "xdiff-interface.h"
|
||||
|
||||
static const char merge_file_usage[] =
|
||||
"git merge-file [-p | --stdout] [-q | --quiet] [-L name1 [-L orig [-L name2]]] file1 orig_file file2";
|
||||
"git merge-file [-p | --stdout] [--diff3] [-q | --quiet] [-L name1 [-L orig [-L name2]]] file1 orig_file file2";
|
||||
|
||||
int cmd_merge_file(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
@ -13,6 +13,8 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
|
||||
mmbuffer_t result = {NULL, 0};
|
||||
xpparam_t xpp = {XDF_NEED_MINIMAL};
|
||||
int ret = 0, i = 0, to_stdout = 0;
|
||||
int merge_level = XDL_MERGE_ZEALOUS_ALNUM;
|
||||
int merge_style = 0;
|
||||
|
||||
while (argc > 4) {
|
||||
if (!strcmp(argv[1], "-L") && i < 3) {
|
||||
@ -25,6 +27,10 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
|
||||
else if (!strcmp(argv[1], "-q") ||
|
||||
!strcmp(argv[1], "--quiet"))
|
||||
freopen("/dev/null", "w", stderr);
|
||||
else if (!strcmp(argv[1], "--diff3")) {
|
||||
merge_style = XDL_MERGE_DIFF3;
|
||||
merge_level = XDL_MERGE_EAGER;
|
||||
}
|
||||
else
|
||||
usage(merge_file_usage);
|
||||
argc--;
|
||||
@ -46,7 +52,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
|
||||
ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],
|
||||
&xpp, XDL_MERGE_ZEALOUS_ALNUM, &result);
|
||||
&xpp, merge_level | merge_style, &result);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
free(mmfs[i].ptr);
|
||||
|
@ -161,4 +161,41 @@ test_expect_success 'ZEALOUS_ALNUM' '
|
||||
|
||||
'
|
||||
|
||||
cat >expect <<\EOF
|
||||
Dominus regit me,
|
||||
<<<<<<< new8.txt
|
||||
et nihil mihi deerit;
|
||||
|
||||
|
||||
|
||||
|
||||
In loco pascuae ibi me collocavit;
|
||||
super aquam refectionis educavit me.
|
||||
|||||||
|
||||
et nihil mihi deerit.
|
||||
In loco pascuae ibi me collocavit,
|
||||
super aquam refectionis educavit me;
|
||||
=======
|
||||
et nihil mihi deerit,
|
||||
|
||||
|
||||
|
||||
|
||||
In loco pascuae ibi me collocavit --
|
||||
super aquam refectionis educavit me,
|
||||
>>>>>>> new9.txt
|
||||
animam meam convertit,
|
||||
deduxit me super semitas jusitiae,
|
||||
propter nomen suum.
|
||||
Nam et si ambulavero in medio umbrae mortis,
|
||||
non timebo mala, quoniam TU mecum es:
|
||||
virga tua et baculus tuus ipsa me consolata sunt.
|
||||
EOF
|
||||
|
||||
test_expect_success '"diff3 -m" style output' '
|
||||
test_must_fail git merge-file -p --diff3 \
|
||||
new8.txt new5.txt new9.txt >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
@ -50,10 +50,16 @@ extern "C" {
|
||||
#define XDL_BDOP_CPY 2
|
||||
#define XDL_BDOP_INSB 3
|
||||
|
||||
/* merge simplification levels */
|
||||
#define XDL_MERGE_MINIMAL 0
|
||||
#define XDL_MERGE_EAGER 1
|
||||
#define XDL_MERGE_ZEALOUS 2
|
||||
#define XDL_MERGE_ZEALOUS_ALNUM 3
|
||||
#define XDL_MERGE_LEVEL_MASK 0x0f
|
||||
|
||||
/* merge output styles */
|
||||
#define XDL_MERGE_DIFF3 0x8000
|
||||
#define XDL_MERGE_STYLE_MASK 0x8000
|
||||
|
||||
typedef struct s_mmfile {
|
||||
char *ptr;
|
||||
|
103
xdiff/xmerge.c
103
xdiff/xmerge.c
@ -30,17 +30,32 @@ typedef struct s_xdmerge {
|
||||
* 2 = no conflict, take second.
|
||||
*/
|
||||
int mode;
|
||||
/*
|
||||
* These point at the respective postimages. E.g. <i1,chg1> is
|
||||
* how side #1 wants to change the common ancestor; if there is no
|
||||
* overlap, lines before i1 in the postimage of side #1 appear
|
||||
* in the merge result as a region touched by neither side.
|
||||
*/
|
||||
long i1, i2;
|
||||
long chg1, chg2;
|
||||
/*
|
||||
* These point at the preimage; of course there is just one
|
||||
* preimage, that is from the shared common ancestor.
|
||||
*/
|
||||
long i0;
|
||||
long chg0;
|
||||
} xdmerge_t;
|
||||
|
||||
static int xdl_append_merge(xdmerge_t **merge, int mode,
|
||||
long i1, long chg1, long i2, long chg2)
|
||||
long i0, long chg0,
|
||||
long i1, long chg1,
|
||||
long i2, long chg2)
|
||||
{
|
||||
xdmerge_t *m = *merge;
|
||||
if (m && (i1 <= m->i1 + m->chg1 || i2 <= m->i2 + m->chg2)) {
|
||||
if (mode != m->mode)
|
||||
m->mode = 0;
|
||||
m->chg0 = i0 + chg0 - m->i0;
|
||||
m->chg1 = i1 + chg1 - m->i1;
|
||||
m->chg2 = i2 + chg2 - m->i2;
|
||||
} else {
|
||||
@ -49,6 +64,8 @@ static int xdl_append_merge(xdmerge_t **merge, int mode,
|
||||
return -1;
|
||||
m->next = NULL;
|
||||
m->mode = mode;
|
||||
m->i0 = i0;
|
||||
m->chg0 = chg0;
|
||||
m->i1 = i1;
|
||||
m->chg1 = chg1;
|
||||
m->i2 = i2;
|
||||
@ -91,11 +108,13 @@ static int xdl_merge_cmp_lines(xdfenv_t *xe1, int i1, xdfenv_t *xe2, int i2,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
|
||||
static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add_nl, char *dest)
|
||||
{
|
||||
xrecord_t **recs = xe->xdf2.recs + i;
|
||||
xrecord_t **recs;
|
||||
int size = 0;
|
||||
|
||||
recs = (use_orig ? xe->xdf1.recs : xe->xdf2.recs) + i;
|
||||
|
||||
if (count < 1)
|
||||
return 0;
|
||||
|
||||
@ -113,9 +132,19 @@ static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
|
||||
return size;
|
||||
}
|
||||
|
||||
static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
|
||||
{
|
||||
return xdl_recs_copy_0(0, xe, i, count, add_nl, dest);
|
||||
}
|
||||
|
||||
static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
|
||||
{
|
||||
return xdl_recs_copy_0(1, xe, i, count, add_nl, dest);
|
||||
}
|
||||
|
||||
static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
|
||||
xdfenv_t *xe2, const char *name2,
|
||||
int size, int i,
|
||||
int size, int i, int style,
|
||||
xdmerge_t *m, char *dest)
|
||||
{
|
||||
const int marker_size = 7;
|
||||
@ -143,6 +172,20 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
|
||||
/* Postimage from side #1 */
|
||||
size += xdl_recs_copy(xe1, m->i1, m->chg1, 1,
|
||||
dest ? dest + size : NULL);
|
||||
|
||||
if (style == XDL_MERGE_DIFF3) {
|
||||
/* Shared preimage */
|
||||
if (!dest) {
|
||||
size += marker_size + 1;
|
||||
} else {
|
||||
for (j = 0; j < marker_size; j++)
|
||||
dest[size++] = '|';
|
||||
dest[size++] = '\n';
|
||||
}
|
||||
size += xdl_orig_copy(xe1, m->i0, m->chg0, 1,
|
||||
dest ? dest + size : NULL);
|
||||
}
|
||||
|
||||
if (!dest) {
|
||||
size += marker_size + 1;
|
||||
} else {
|
||||
@ -170,14 +213,15 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
|
||||
}
|
||||
|
||||
static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
|
||||
xdfenv_t *xe2, const char *name2, xdmerge_t *m, char *dest)
|
||||
xdfenv_t *xe2, const char *name2,
|
||||
xdmerge_t *m, char *dest, int style)
|
||||
{
|
||||
int size, i;
|
||||
|
||||
for (size = i = 0; m; m = m->next) {
|
||||
if (m->mode == 0)
|
||||
size = fill_conflict_hunk(xe1, name1, xe2, name2,
|
||||
size, i, m, dest);
|
||||
size, i, style, m, dest);
|
||||
else if (m->mode == 1)
|
||||
size += xdl_recs_copy(xe1, i, m->i1 + m->chg1 - i, 0,
|
||||
dest ? dest + size : NULL);
|
||||
@ -342,9 +386,11 @@ static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m,
|
||||
*/
|
||||
static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
|
||||
xdfenv_t *xe2, xdchange_t *xscr2, const char *name2,
|
||||
int level, xpparam_t const *xpp, mmbuffer_t *result) {
|
||||
int flags, xpparam_t const *xpp, mmbuffer_t *result) {
|
||||
xdmerge_t *changes, *c;
|
||||
int i1, i2, chg1, chg2;
|
||||
int i0, i1, i2, chg0, chg1, chg2;
|
||||
int level = flags & XDL_MERGE_LEVEL_MASK;
|
||||
int style = flags & XDL_MERGE_STYLE_MASK;
|
||||
|
||||
c = changes = NULL;
|
||||
|
||||
@ -352,11 +398,14 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
|
||||
if (!changes)
|
||||
changes = c;
|
||||
if (xscr1->i1 + xscr1->chg1 < xscr2->i1) {
|
||||
i0 = xscr1->i1;
|
||||
i1 = xscr1->i2;
|
||||
i2 = xscr2->i2 - xscr2->i1 + xscr1->i1;
|
||||
chg0 = xscr1->chg1;
|
||||
chg1 = xscr1->chg2;
|
||||
chg2 = xscr1->chg1;
|
||||
if (xdl_append_merge(&c, 1, i1, chg1, i2, chg2)) {
|
||||
if (xdl_append_merge(&c, 1,
|
||||
i0, chg0, i1, chg1, i2, chg2)) {
|
||||
xdl_cleanup_merge(changes);
|
||||
return -1;
|
||||
}
|
||||
@ -364,11 +413,14 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
|
||||
continue;
|
||||
}
|
||||
if (xscr2->i1 + xscr2->chg1 < xscr1->i1) {
|
||||
i0 = xscr2->i1;
|
||||
i1 = xscr1->i2 - xscr1->i1 + xscr2->i1;
|
||||
i2 = xscr2->i2;
|
||||
chg0 = xscr2->chg1;
|
||||
chg1 = xscr2->chg1;
|
||||
chg2 = xscr2->chg2;
|
||||
if (xdl_append_merge(&c, 2, i1, chg1, i2, chg2)) {
|
||||
if (xdl_append_merge(&c, 2,
|
||||
i0, chg0, i1, chg1, i2, chg2)) {
|
||||
xdl_cleanup_merge(changes);
|
||||
return -1;
|
||||
}
|
||||
@ -385,19 +437,26 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
|
||||
int off = xscr1->i1 - xscr2->i1;
|
||||
int ffo = off + xscr1->chg1 - xscr2->chg1;
|
||||
|
||||
i0 = xscr1->i1;
|
||||
i1 = xscr1->i2;
|
||||
i2 = xscr2->i2;
|
||||
if (off > 0)
|
||||
if (off > 0) {
|
||||
i0 -= off;
|
||||
i1 -= off;
|
||||
}
|
||||
else
|
||||
i2 += off;
|
||||
chg0 = xscr1->i1 + xscr1->chg1 - i0;
|
||||
chg1 = xscr1->i2 + xscr1->chg2 - i1;
|
||||
chg2 = xscr2->i2 + xscr2->chg2 - i2;
|
||||
if (ffo > 0)
|
||||
chg2 += ffo;
|
||||
else
|
||||
else {
|
||||
chg0 -= ffo;
|
||||
chg1 -= ffo;
|
||||
if (xdl_append_merge(&c, 0, i1, chg1, i2, chg2)) {
|
||||
}
|
||||
if (xdl_append_merge(&c, 0,
|
||||
i0, chg0, i1, chg1, i2, chg2)) {
|
||||
xdl_cleanup_merge(changes);
|
||||
return -1;
|
||||
}
|
||||
@ -414,11 +473,14 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
|
||||
while (xscr1) {
|
||||
if (!changes)
|
||||
changes = c;
|
||||
i0 = xscr1->i1;
|
||||
i1 = xscr1->i2;
|
||||
i2 = xscr1->i1 + xe2->xdf2.nrec - xe2->xdf1.nrec;
|
||||
chg0 = xscr1->chg1;
|
||||
chg1 = xscr1->chg2;
|
||||
chg2 = xscr1->chg1;
|
||||
if (xdl_append_merge(&c, 1, i1, chg1, i2, chg2)) {
|
||||
if (xdl_append_merge(&c, 1,
|
||||
i0, chg0, i1, chg1, i2, chg2)) {
|
||||
xdl_cleanup_merge(changes);
|
||||
return -1;
|
||||
}
|
||||
@ -427,11 +489,14 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
|
||||
while (xscr2) {
|
||||
if (!changes)
|
||||
changes = c;
|
||||
i0 = xscr2->i1;
|
||||
i1 = xscr2->i1 + xe1->xdf2.nrec - xe1->xdf1.nrec;
|
||||
i2 = xscr2->i2;
|
||||
chg0 = xscr2->chg1;
|
||||
chg1 = xscr2->chg1;
|
||||
chg2 = xscr2->chg2;
|
||||
if (xdl_append_merge(&c, 2, i1, chg1, i2, chg2)) {
|
||||
if (xdl_append_merge(&c, 2,
|
||||
i0, chg0, i1, chg1, i2, chg2)) {
|
||||
xdl_cleanup_merge(changes);
|
||||
return -1;
|
||||
}
|
||||
@ -449,7 +514,7 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
|
||||
/* output */
|
||||
if (result) {
|
||||
int size = xdl_fill_merge_buffer(xe1, name1, xe2, name2,
|
||||
changes, NULL);
|
||||
changes, NULL, style);
|
||||
result->ptr = xdl_malloc(size);
|
||||
if (!result->ptr) {
|
||||
xdl_cleanup_merge(changes);
|
||||
@ -457,14 +522,14 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
|
||||
}
|
||||
result->size = size;
|
||||
xdl_fill_merge_buffer(xe1, name1, xe2, name2, changes,
|
||||
result->ptr);
|
||||
result->ptr, style);
|
||||
}
|
||||
return xdl_cleanup_merge(changes);
|
||||
}
|
||||
|
||||
int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
|
||||
mmfile_t *mf2, const char *name2,
|
||||
xpparam_t const *xpp, int level, mmbuffer_t *result) {
|
||||
xpparam_t const *xpp, int flags, mmbuffer_t *result) {
|
||||
xdchange_t *xscr1, *xscr2;
|
||||
xdfenv_t xe1, xe2;
|
||||
int status;
|
||||
@ -501,7 +566,7 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
|
||||
} else {
|
||||
status = xdl_do_merge(&xe1, xscr1, name1,
|
||||
&xe2, xscr2, name2,
|
||||
level, xpp, result);
|
||||
flags, xpp, result);
|
||||
}
|
||||
xdl_free_script(xscr1);
|
||||
xdl_free_script(xscr2);
|
||||
|
Loading…
Reference in New Issue
Block a user