diff3: Add support for -m
diff3 in -m mode generates a complete file with changes bracketed with conflict markers. This adds support for diff3 to generate version control style three way merge output. The output format was inferred from looking at the gnu diff3 output on a selection of test files as a specification of what diff3 -m should output is not available. It is likely there are cases where the -m output differs from other tools and I am happy to update diff3 to address these. Discussed with: pstef, kevans Sponsored by: Klara, Inc.
This commit is contained in:
parent
f45f90c5d6
commit
034dd2d54f
@ -38,7 +38,7 @@
|
|||||||
.Nd 3-way differential file comparison
|
.Nd 3-way differential file comparison
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm diff3
|
.Nm diff3
|
||||||
.Op Fl 3AaEeiTXx
|
.Op Fl 3AaEeimTXx
|
||||||
.Op Fl Fl diff-program Ar program
|
.Op Fl Fl diff-program Ar program
|
||||||
.Op Fl Fl strip-trailing-cr
|
.Op Fl Fl strip-trailing-cr
|
||||||
.Op Fl L | Fl Fl label Ar label1
|
.Op Fl L | Fl Fl label Ar label1
|
||||||
@ -117,6 +117,8 @@ Defines labels to print instead of file names
|
|||||||
.Ar file2
|
.Ar file2
|
||||||
and
|
and
|
||||||
.Ar file3 .
|
.Ar file3 .
|
||||||
|
.It Fl m, Fl Fl merge
|
||||||
|
Merge output instead of generating ed script.
|
||||||
.It Fl T, Fl Fl initial-tab
|
.It Fl T, Fl Fl initial-tab
|
||||||
In the normal listing,
|
In the normal listing,
|
||||||
use a tab instead of two spaces
|
use a tab instead of two spaces
|
||||||
|
@ -153,6 +153,7 @@ static void prange(struct range *, bool);
|
|||||||
static void repos(int);
|
static void repos(int);
|
||||||
static void edscript(int) __dead2;
|
static void edscript(int) __dead2;
|
||||||
static void Ascript(int) __dead2;
|
static void Ascript(int) __dead2;
|
||||||
|
static void mergescript(int) __dead2;
|
||||||
static void increase(void);
|
static void increase(void);
|
||||||
static void usage(void) __dead2;
|
static void usage(void) __dead2;
|
||||||
static void printrange(FILE *, struct range *);
|
static void printrange(FILE *, struct range *);
|
||||||
@ -389,7 +390,9 @@ merge(int m1, int m2)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Aflag)
|
if (mflag)
|
||||||
|
mergescript(j);
|
||||||
|
else if (Aflag)
|
||||||
Ascript(j);
|
Ascript(j);
|
||||||
else if (eflag)
|
else if (eflag)
|
||||||
edscript(j);
|
edscript(j);
|
||||||
@ -687,6 +690,86 @@ Ascript(int n)
|
|||||||
exit(overlapcnt > 0);
|
exit(overlapcnt > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output the merged file directly (don't generate an ed script). When
|
||||||
|
* regurgitating diffs we need to walk forward through the file and print any
|
||||||
|
* inbetween lines.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
mergescript(int i)
|
||||||
|
{
|
||||||
|
struct range r;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
r.from = 1;
|
||||||
|
r.to = 1;
|
||||||
|
|
||||||
|
for (n = 1; n < i+1; n++) {
|
||||||
|
/* print any lines leading up to here */
|
||||||
|
r.to = de[n].old.from;
|
||||||
|
printrange(fp[0], &r);
|
||||||
|
|
||||||
|
if (de[n].type == DIFF_TYPE2) {
|
||||||
|
printf("%s %s\n", oldmark, f2mark);
|
||||||
|
printrange(fp[1], &de[n].old);
|
||||||
|
printf("=======\n");
|
||||||
|
printrange(fp[2], &de[n].new);
|
||||||
|
printf("%s %s\n", newmark, f3mark);
|
||||||
|
} else if (de[n].type == DIFF_TYPE3) {
|
||||||
|
if (!oflag || !overlap[n]) {
|
||||||
|
printrange(fp[2], &de[n].new);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
printf("%s %s\n", oldmark, f1mark);
|
||||||
|
printrange(fp[0], &de[n].old);
|
||||||
|
|
||||||
|
printf("%s %s\n", orgmark, f2mark);
|
||||||
|
if (de[n].old.from == de[n].old.to) {
|
||||||
|
struct range or;
|
||||||
|
or.from = de[n].old.from -1;
|
||||||
|
or.to = de[n].new.to;
|
||||||
|
printrange(fp[1], &or);
|
||||||
|
} else
|
||||||
|
printrange(fp[1], &de[n].old);
|
||||||
|
|
||||||
|
printf("=======\n");
|
||||||
|
|
||||||
|
printrange(fp[2], &de[n].new);
|
||||||
|
printf("%s %s\n", newmark, f3mark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (de[n].old.from == de[n].old.to)
|
||||||
|
r.from = de[n].new.to;
|
||||||
|
else
|
||||||
|
r.from = de[n].old.to;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Print from the final range to the end of 'myfile'. Any deletions or
|
||||||
|
* additions to this file should have been handled by now.
|
||||||
|
*
|
||||||
|
* If the ranges are the same we need to rewind a line.
|
||||||
|
* If the new range is 0 length (from == to), we need to use the old
|
||||||
|
* range.
|
||||||
|
*/
|
||||||
|
if ((de[n-1].old.from == de[n-1].new.from) &&
|
||||||
|
(de[n-1].old.to == de[n-1].new.to))
|
||||||
|
r.from--;
|
||||||
|
else if (de[n-1].new.from == de[n-1].new.to)
|
||||||
|
r.from = de[n-1].old.from;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the range is a 3 way merge then we need to skip a line in the
|
||||||
|
* trailing output.
|
||||||
|
*/
|
||||||
|
if (de[n-1].type == DIFF_TYPE3)
|
||||||
|
r.from++;
|
||||||
|
|
||||||
|
r.to = INT_MAX;
|
||||||
|
printrange(fp[0], &r);
|
||||||
|
exit(overlapcnt > 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
increase(void)
|
increase(void)
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,7 @@ ${PACKAGE}FILES+= \
|
|||||||
8.out \
|
8.out \
|
||||||
9.out \
|
9.out \
|
||||||
long-ed.out \
|
long-ed.out \
|
||||||
long-A.out
|
long-A.out \
|
||||||
|
long-merge.out \
|
||||||
|
|
||||||
.include <bsd.test.mk>
|
.include <bsd.test.mk>
|
||||||
|
@ -4,6 +4,7 @@ atf_test_case diff3
|
|||||||
atf_test_case diff3_lesssimple
|
atf_test_case diff3_lesssimple
|
||||||
atf_test_case diff3_ed
|
atf_test_case diff3_ed
|
||||||
atf_test_case diff3_A
|
atf_test_case diff3_A
|
||||||
|
atf_test_case diff3_merge
|
||||||
|
|
||||||
diff3_body()
|
diff3_body()
|
||||||
{
|
{
|
||||||
@ -56,10 +57,22 @@ diff3_A_body()
|
|||||||
diff3 -A -L long-m.txt -L long-o.txt -L long-y.txt $(atf_get_srcdir)/long-m.txt $(atf_get_srcdir)/long-o.txt $(atf_get_srcdir)/long-y.txt
|
diff3 -A -L long-m.txt -L long-o.txt -L long-y.txt $(atf_get_srcdir)/long-m.txt $(atf_get_srcdir)/long-o.txt $(atf_get_srcdir)/long-y.txt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
diff3_merge_body()
|
||||||
|
{
|
||||||
|
atf_check -s exit:1 -o file:$(atf_get_srcdir)/9.out \
|
||||||
|
diff3 -m -L 1 -L 2 -L 3 $(atf_get_srcdir)/1.txt $(atf_get_srcdir)/2.txt $(atf_get_srcdir)/3.txt
|
||||||
|
atf_check -s exit:1 -o file:$(atf_get_srcdir)/tao-merge.out \
|
||||||
|
diff3 -m -L lao.txt -L tzu.txt -L tao.txt $(atf_get_srcdir)/lao.txt $(atf_get_srcdir)/tzu.txt $(atf_get_srcdir)/tao.txt
|
||||||
|
atf_check -s exit:1 -o file:$(atf_get_srcdir)/long-merge.out \
|
||||||
|
diff3 -m -L long-m.txt -L long-o.txt -L long-y.txt $(atf_get_srcdir)/long-m.txt $(atf_get_srcdir)/long-o.txt $(atf_get_srcdir)/long-y.txt
|
||||||
|
}
|
||||||
|
|
||||||
atf_init_test_cases()
|
atf_init_test_cases()
|
||||||
{
|
{
|
||||||
atf_add_test_case diff3
|
atf_add_test_case diff3
|
||||||
# atf_add_test_case diff3_lesssimple
|
# atf_add_test_case diff3_lesssimple
|
||||||
atf_add_test_case diff3_ed
|
atf_add_test_case diff3_ed
|
||||||
atf_add_test_case diff3_A
|
atf_add_test_case diff3_A
|
||||||
|
atf_add_test_case diff3_merge
|
||||||
}
|
}
|
||||||
|
35
usr.bin/diff3/tests/long-merge.out
Normal file
35
usr.bin/diff3/tests/long-merge.out
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
This is a long file
|
||||||
|
These lines are the same in all three files
|
||||||
|
These lines are the same in all three files
|
||||||
|
This line is different in mine, not better
|
||||||
|
These lines are the same in all three files
|
||||||
|
These lines are the same in all three files
|
||||||
|
These lines are the same in all three files
|
||||||
|
This line is different in yours, much butter
|
||||||
|
These lines are the same in all three files
|
||||||
|
These lines are the same in all three files
|
||||||
|
<<<<<<< long-o.txt
|
||||||
|
This line is different in yours and mine, but the same
|
||||||
|
=======
|
||||||
|
This line is different in yours and mine, the same is in both
|
||||||
|
>>>>>>> long-y.txt
|
||||||
|
These lines are the same in all three files
|
||||||
|
These lines are the same in all three files
|
||||||
|
These lines are the same in all three files
|
||||||
|
These lines are the same in all three files
|
||||||
|
<<<<<<< long-m.txt
|
||||||
|
This line is different in yours and mine, best change in mine
|
||||||
|
||||||| long-o.txt
|
||||||
|
This line is different in yours and mine, but the different in each
|
||||||
|
=======
|
||||||
|
This line is different in yours and mine, but the best in yours
|
||||||
|
>>>>>>> long-y.txt
|
||||||
|
These lines are the same in all three files
|
||||||
|
These lines are the same in all three files
|
||||||
|
These lines are the same in all three files
|
||||||
|
These lines are the same in all three files
|
||||||
|
These lines are the same in all three files
|
||||||
|
These lines are the same in all three files
|
||||||
|
These lines are the same in all three files
|
||||||
|
These lines are the same in all three files
|
||||||
|
These lines are the same in all three files
|
Loading…
Reference in New Issue
Block a user