[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[bug-patch] [PATCH] 'diff3 -m' style merge conflicts
From: |
Bert Wesarg |
Subject: |
[bug-patch] [PATCH] 'diff3 -m' style merge conflicts |
Date: |
Wed, 25 Nov 2009 01:05:57 +0100 |
Add support to emit merge conflicts like the 'GNU diff3' tool. This has also
found its way into 'git' which have a good documentation how it looks like.
See the HOW CONFLICTS ARE PRESENTED section the help of 'git merge'[1].
To get the same result as 'diff3 -m' I have to removed the common prefix/suffix
operation when in diff3 mode. See the commit message in [2] for an explanation
of this.
Also, I think the test in line 170 of tests/merge shows a wrong behavior of
'patch --merge'. I have added the output of 'diff3 -m' into the file as an
reference.
[1] http://repo.or.cz/w/git.git/blob/HEAD:/Documentation/git-merge.txt
[2] http://repo.or.cz/w/git.git/commit/83133740d9c81ce4c98cb53b85c8d5b190944f81
Signed-off-by: Bert Wesarg <address@hidden>
---
Makefile.in | 1 +
src/common.h | 5 +-
src/merge.c | 32 ++++-
src/patch.c | 14 ++-
tests/merge | 9 ++
tests/merge-diff3 | 401 +++++++++++++++++++++++++++++++++++++++++++++++++++++
tests/test-lib.sh | 10 ++
7 files changed, 464 insertions(+), 8 deletions(-)
diff --git a/Makefile.in b/Makefile.in
index 2c5fb95..24d6321 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -201,6 +201,7 @@ TESTS = \
tests/inname \
tests/line-numbers \
tests/merge \
+ tests/merge-diff3 \
tests/munged-context-format \
tests/need-filename \
tests/no-newline-triggers-assert \
diff --git a/src/common.h b/src/common.h
index b9684de..5a2c3ac 100644
--- a/src/common.h
+++ b/src/common.h
@@ -283,7 +283,8 @@ bool copy_till (struct outstate *, LINENUM);
bool similar (char const *, size_t, char const *, size_t);
#ifdef ENABLE_MERGE
-bool merge_hunk (int hunk, struct outstate *, LINENUM where, bool *);
+bool merge_hunk (int hunk, struct outstate *, LINENUM where, bool *,
+ bool diff3_conflict);
#else
-# define merge_hunk(hunk, outstate, where, somefailed) false
+# define merge_hunk(hunk, outstate, where, somefailed, diff3_conflict) false
#endif
diff --git a/src/merge.c b/src/merge.c
index 2994786..842321e 100644
--- a/src/merge.c
+++ b/src/merge.c
@@ -197,7 +197,7 @@ merge_result (bool *first_result, int hunk, char const
*what, LINENUM from,
bool
merge_hunk (int hunk, struct outstate *outstate, LINENUM where,
- bool *somefailed)
+ bool *somefailed, bool diff3_conflict)
{
bool applies_cleanly;
bool first_result = true;
@@ -206,8 +206,10 @@ merge_hunk (int hunk, struct outstate *outstate, LINENUM
where,
LINENUM firstold = pch_ptrn_lines ();
LINENUM new = firstold + 1;
LINENUM firstnew = pch_end ();
+ LINENUM firstnew_safed;
LINENUM in;
LINENUM firstin;
+ LINENUM firstin_safed;
char *oldin;
LINENUM matched;
LINENUM lastwhere;
@@ -421,6 +423,8 @@ merge_hunk (int hunk, struct outstate *outstate, LINENUM
where,
|| (oldin[old] == '=' && oldin[in] == '^')));
/* Output common prefix lines. */
+ firstin_safed = firstin;
+ firstnew_safed = firstnew;
for (lastwhere = where;
firstin < in && firstnew < new
&& context_matches_file (firstnew, lastwhere);
@@ -429,7 +433,7 @@ merge_hunk (int hunk, struct outstate *outstate, LINENUM
where,
if (firstin == in && firstnew == new)
merge_result (&first_result, hunk, "already applied",
where, lastwhere - 1);
- if (where != lastwhere)
+ if (!diff3_conflict && where != lastwhere)
{
where = lastwhere;
if (! copy_till (outstate, where - 1))
@@ -441,10 +445,18 @@ merge_hunk (int hunk, struct outstate *outstate, LINENUM
where,
LINENUM common_suffix;
LINENUM lines;
- /* Remember common suffix lines. */
+ /* We have definitive a conflict, so revert any common prefix
+ operations, which does not make sense in diff3 mode. */
+ if (diff3_conflict)
+ {
+ firstin = firstin_safed;
+ firstnew = firstnew_safed;
+ }
+
+ /* Remember common suffix lines. But not in diff3 mode. */
for (common_suffix = 0,
lastwhere = where + (in - firstin);
- firstin < in && firstnew < new
+ !diff3_conflict && firstin < in && firstnew < new
&& context_matches_file (new - 1, lastwhere - 1);
in--, new--, lastwhere--, common_suffix++)
continue;
@@ -462,6 +474,18 @@ merge_hunk (int hunk, struct outstate *outstate, LINENUM
where,
if (! copy_till (outstate, where - 1))
return false;
}
+
+ if (diff3_conflict)
+ {
+ fputs (outstate->after_newline + "\n|||||||\n", fp);
+ outstate->after_newline = true;
+ while (firstold < old)
+ {
+ outstate->after_newline = pch_write_line (firstold, fp);
+ firstold++;
+ }
+ }
+
fputs (outstate->after_newline + "\n=======\n", fp);
outstate->after_newline = true;
while (firstnew < new)
diff --git a/src/patch.c b/src/patch.c
index c935592..996b5f9 100644
--- a/src/patch.c
+++ b/src/patch.c
@@ -58,6 +58,7 @@ static void abort_hunk_unified (bool, bool);
#ifdef ENABLE_MERGE
static bool merge;
+static bool diff3_conflict;
#else
# define merge false
#endif
@@ -288,7 +289,7 @@ main (int argc, char **argv)
newwhere = (where ? where : pch_first()) + out_offset;
if (skip_rest_of_patch
|| (merge && ! merge_hunk (hunk, &outstate, where,
- &somefailed))
+ &somefailed, diff3_conflict))
|| (! merge
&& ((where == 1 && pch_says_nonexistent (reverse) == 2
&& instat.st_size)
@@ -572,6 +573,9 @@ static struct option const longopts[] =
{"posix", no_argument, NULL, CHAR_MAX + 7},
{"quoting-style", required_argument, NULL, CHAR_MAX + 8},
{"reject-format", required_argument, NULL, CHAR_MAX + 9},
+#ifdef ENABLE_MERGE
+ {"diff3-conflict", no_argument, NULL, CHAR_MAX + 10},
+#endif
{NULL, no_argument, NULL, 0}
};
@@ -601,6 +605,7 @@ static char const *const option_help[] =
" -D NAME --ifdef=NAME Make merged if-then-else output using NAME.",
#ifdef ENABLE_MERGE
" -m --merge Merge using conflict markers instead of creating reject
files.",
+" --diff3-conflict Output the common base in case of merge conflict.",
#endif
" -E --remove-empty-files Remove output files that are empty after
patching.",
"",
@@ -737,7 +742,7 @@ get_some_switches (void)
break;
#ifdef ENABLE_MERGE
case 'm':
- merge = true;
+ merge = true;
break;
#endif
case 'n':
@@ -841,6 +846,11 @@ get_some_switches (void)
else
usage (stderr, 2);
break;
+#ifdef ENABLE_MERGE
+ case CHAR_MAX + 10:
+ diff3_conflict = true;
+ break;
+#endif
default:
usage (stderr, 2);
}
diff --git a/tests/merge b/tests/merge
index 80d9383..ef383d2 100644
--- a/tests/merge
+++ b/tests/merge
@@ -177,6 +177,15 @@ c
Status: 1
EOF
+# the previous test differs with the output from diff3 -m
+cat >/dev/null <<EOF
+<<<<<<<
+c
+=======
+b
+>>>>>>>
+EOF
+
check 'x 4 2ca 3cb -- 2ca 3cc' <<EOF
Hunk #1 NOT MERGED at 3-7.
1
diff --git a/tests/merge-diff3 b/tests/merge-diff3
new file mode 100644
index 0000000..8e2518d
--- /dev/null
+++ b/tests/merge-diff3
@@ -0,0 +1,401 @@
+# Copyright (C) 2009 Free Software Foundation, Inc.
+#
+# Copying and distribution of this file, with or without modification,
+# in any medium, are permitted without royalty provided the copyright
+# notice and this notice are preserved.
+
+# Test the --reject-format=FORMAT option
+
+. $srcdir/test-lib.sh
+
+require_cat
+require_diff
+#require_diff3
+use_local_patch
+use_tmpdir
+
+# ==============================================================
+
+if ! patch --merge --diff3-conflict </dev/null 2>/dev/null ; then
+ echo "Merge support DISABLED; skipping this test"
+ exit
+fi
+
+# ==============================================================
+
+x() {
+ body=`seq 1 $1`
+ shift
+ echo "$body" > a
+ sed=
+ while test $# -gt 0 -a "$1" != -- ; do
+ sed="$sed -e $1"
+ shift
+ done
+ echo "$body" | sed$sed -e b > b
+ shift
+ sed=
+ while test $# -gt 0 ; do
+ sed="$sed -e $1"
+ shift
+ done
+ echo "$body" | sed$sed -e b > c
+ output=`diff -u a b | patch $ARGS -f --merge --diff3-conflict c`
+ status=$?
+ echo "$output" | sed -e '/^\(\|patching file c\)$/d'
+ cat c
+ test $status == 0 || echo "Status: $status"
+}
+
+unset ARGS
+
+# ==============================================================
+
+check 'x 3' <<EOF
+1
+2
+3
+EOF
+
+check 'x 3 2d' <<EOF
+1
+3
+EOF
+
+check 'x 2 2ib' <<EOF
+1
+b
+2
+EOF
+
+check 'x 3 2ib -- 3ic' <<EOF
+Hunk #1 merged at 2.
+1
+b
+2
+c
+3
+EOF
+
+# ==============================================================
+
+check 'x 3 2c2b -- 2c2c' <<EOF
+Hunk #1 NOT MERGED at 2-6.
+1
+<<<<<<<
+2c
+|||||||
+2
+=======
+2b
+>>>>>>>
+3
+Status: 1
+EOF
+
+check 'x 3 2d -- 2d' <<EOF
+Hunk #1 already applied at 2.
+1
+3
+EOF
+
+check 'x 2 2ibc -- 2ibc' <<EOF
+Hunk #1 already applied at 2.
+1
+bc
+2
+EOF
+
+check 'x 4 2aa 2aa -- 2aa 2aa' <<EOF
+Hunk #1 already applied at 3-4.
+1
+2
+a
+a
+3
+4
+EOF
+
+# ==============================================================
+
+check 'x 4 2d -- 3d' <<EOF
+Hunk #1 NOT MERGED at 2-6.
+1
+<<<<<<<
+2
+|||||||
+2
+3
+=======
+3
+>>>>>>>
+4
+Status: 1
+EOF
+
+check 'x 4 3d -- 2d' <<EOF
+Hunk #1 NOT MERGED at 2-6.
+1
+<<<<<<<
+3
+|||||||
+2
+3
+=======
+2
+>>>>>>>
+4
+Status: 1
+EOF
+
+# ==============================================================
+
+check 'x 3 3ib -- 2d' <<EOF
+Hunk #1 NOT MERGED at 2-6.
+1
+<<<<<<<
+|||||||
+2
+=======
+2
+b
+>>>>>>>
+3
+Status: 1
+EOF
+
+check 'x 3 2d -- 3ib' <<EOF
+Hunk #1 NOT MERGED at 2-6.
+1
+<<<<<<<
+2
+b
+|||||||
+2
+=======
+>>>>>>>
+3
+Status: 1
+EOF
+
+# ==============================================================
+
+check 'x 1 1cb -- 1cc' <<EOF
+Hunk #1 NOT MERGED at 1-4.
+<<<<<<<
+|||||||
+1
+=======
+b
+>>>>>>>
+c
+Status: 1
+EOF
+
+# the previous test differs with the output from diff3 -m
+cat >/dev/null <<EOF
+<<<<<<<
+c
+|||||||
+1
+=======
+b
+>>>>>>>
+EOF
+
+check 'x 4 2ca 3cb -- 2ca 3cc' <<EOF
+Hunk #1 NOT MERGED at 2-8.
+1
+<<<<<<<
+a
+c
+|||||||
+2
+3
+=======
+a
+b
+>>>>>>>
+4
+Status: 1
+EOF
+
+check 'x 6 3c3b 4c4b -- 3c3c 4c4c' <<EOF
+Hunk #1 NOT MERGED at 3-9.
+1
+2
+<<<<<<<
+3c
+4c
+|||||||
+3
+4
+=======
+3b
+4b
+>>>>>>>
+5
+6
+Status: 1
+EOF
+
+check 'x 4 2cb 3ca -- 2cc 3ca' <<EOF
+Hunk #1 NOT MERGED at 2-8.
+1
+<<<<<<<
+c
+a
+|||||||
+2
+3
+=======
+b
+a
+>>>>>>>
+4
+Status: 1
+EOF
+
+check 'x 3 2ib 3ib -- 2ic' <<EOF
+Hunk #1 NOT MERGED at 2-6, merged at 8.
+1
+<<<<<<<
+c
+|||||||
+=======
+b
+>>>>>>>
+2
+b
+3
+Status: 1
+EOF
+
+check 'x 3 2ib 3ib 3ib -- 2ic' <<EOF
+Hunk #1 NOT MERGED at 2-6, merged at 8-9.
+1
+<<<<<<<
+c
+|||||||
+=======
+b
+>>>>>>>
+2
+b
+b
+3
+Status: 1
+EOF
+
+check 'x 9 4ca 5cb 6ca -- 4ca 5cc 6ca' <<EOF
+Hunk #1 NOT MERGED at 4-12.
+1
+2
+3
+<<<<<<<
+a
+c
+a
+|||||||
+4
+5
+6
+=======
+a
+b
+a
+>>>>>>>
+7
+8
+9
+Status: 1
+EOF
+
+check 'x 3 2ib 3ib -- 1i0' <<EOF
+0
+1
+b
+2
+b
+3
+EOF
+
+check 'x 4 2ib 4ib -- 1i0 3ic' <<EOF
+Hunk #1 merged at 3,7.
+0
+1
+b
+2
+c
+3
+b
+4
+EOF
+
+# ==============================================================
+
+check 'x 5 2,4d -- 3c3c' <<EOF
+Hunk #1 NOT MERGED at 2-7.
+1
+<<<<<<<
+2
+3c
+4
+|||||||
+2
+3
+4
+=======
+>>>>>>>
+5
+Status: 1
+EOF
+
+check 'x 5 3c3c -- 2,4d' <<EOF
+Hunk #1 NOT MERGED at 2-7.
+1
+<<<<<<<
+|||||||
+2
+3
+4
+=======
+2
+3c
+4
+>>>>>>>
+5
+Status: 1
+EOF
+
+# ==============================================================
+
+check 'x 3 1,2d -- 2ic' <<EOF
+Hunk #1 NOT MERGED at 1-6.
+<<<<<<<
+1
+c
+2
+|||||||
+1
+2
+=======
+>>>>>>>
+3
+Status: 1
+EOF
+
+check 'x 3 2ic -- 1,2d' <<EOF
+Hunk #1 NOT MERGED at 1-6.
+<<<<<<<
+|||||||
+1
+2
+=======
+1
+c
+2
+>>>>>>>
+3
+Status: 1
+EOF
diff --git a/tests/test-lib.sh b/tests/test-lib.sh
index bc46412..0f1aa0d 100644
--- a/tests/test-lib.sh
+++ b/tests/test-lib.sh
@@ -22,6 +22,16 @@ require_diff() {
esac
}
+#require_diff3() {
+# case "`diff3 --version 2> /dev/null`" in
+# *GNU*)
+# ;;
+# *)
+# echo "This test requires GNU diff3" >&2
+# exit 2
+# esac
+#}
+
have_ed() {
type ed >/dev/null 2>/dev/null
}
--
tg: (f01f282..) bw/diff3 (depends on: master)
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [bug-patch] [PATCH] 'diff3 -m' style merge conflicts,
Bert Wesarg <=