bug-patch
[Top][All Lists]
Advanced

[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)




reply via email to

[Prev in Thread] Current Thread [Next in Thread]