[PATCH 3 of 3] merge: minimize conflicts when common base is not shown (issue4447)

Ryan McElroy rm at fb.com
Tue Feb 9 19:40:09 EST 2016


# HG changeset patch
# User Ryan McElroy <rmcelroy at fb.com>
# Date 1455064559 28800
#      Tue Feb 09 16:35:59 2016 -0800
# Node ID 2331e667b0ae2022dd39a28085fce65c6980535c
# Parent  51558e81358f58eb82c8a09d5cc3663e12619f7c
merge: minimize conflicts when common base is not shown (issue4447)

Previously, two changes that were nearly, but not quite, identical would result
in large merge conflict regions that looked very similar, and were thus very
confusing to users, and lead people used to other source control systems to
claim that "mercurial's merge algorithms suck". In the relatively common case
of a new file being introduced in two branches with very slight modifications,
the old behavior would show the entire file as a conflict, and it would be very
difficult for a user to determine what was going on.

In the past, mercurial attempted to solve this with a "very smart" algorithm
that would find all common lines, but this has significant problems as
described in 2ea6d906cf9b.

Instead, we use a "very dumb" algorithm introduced in the previous patch that
simply matches lines at the periphery of conflict regions. This minimizes most
conflict regions well, though there may still be some degenerate edge cases,
like small modification to the beginning and end of a large file.

diff --git a/mercurial/simplemerge.py b/mercurial/simplemerge.py
--- a/mercurial/simplemerge.py
+++ b/mercurial/simplemerge.py
@@ -92,7 +92,8 @@ class Merge3Text(object):
                     mid_marker='=======',
                     end_marker='>>>>>>>',
                     base_marker=None,
-                    localorother=None):
+                    localorother=None,
+                    minimize=False):
         """Return merge in cvs-like form.
         """
         self.conflicts = False
@@ -109,6 +110,8 @@ class Merge3Text(object):
         if name_base and base_marker:
             base_marker = base_marker + ' ' + name_base
         merge_regions = self.merge_regions()
+        if minimize:
+            merge_regions = self.minimize(merge_regions)
         for t in merge_regions:
             what = t[0]
             if what == 'unchanged':
@@ -441,7 +444,10 @@ def simplemerge(ui, local, base, other, 
         out = sys.stdout
 
     m3 = Merge3Text(basetext, localtext, othertext)
-    extrakwargs = {"localorother": opts.get("localorother", None)}
+    extrakwargs = {
+            "localorother": opts.get("localorother", None),
+            'minimize': True,
+        }
     if mode == 'union':
         extrakwargs['start_marker'] = None
         extrakwargs['mid_marker'] = None
@@ -449,6 +455,7 @@ def simplemerge(ui, local, base, other, 
     elif name_base is not None:
         extrakwargs['base_marker'] = '|||||||'
         extrakwargs['name_base'] = name_base
+        extrakwargs['minimize'] = False
     for line in m3.merge_lines(name_a=name_a, name_b=name_b, **extrakwargs):
         out.write(line)
 
diff --git a/tests/test-conflict.t b/tests/test-conflict.t
--- a/tests/test-conflict.t
+++ b/tests/test-conflict.t
@@ -46,16 +46,13 @@
 
   $ cat a
   Small Mathematical Series.
-  <<<<<<< local: 618808747361 - test: branch2
   1
   2
   3
+  <<<<<<< local: 618808747361 - test: branch2
   6
   8
   =======
-  1
-  2
-  3
   4
   5
   >>>>>>> other: c0c68e4fe667  - test: branch1
@@ -79,16 +76,13 @@ Verify custom conflict markers
 
   $ cat a
   Small Mathematical Series.
-  <<<<<<< local: test 2
   1
   2
   3
+  <<<<<<< local: test 2
   6
   8
   =======
-  1
-  2
-  3
   4
   5
   >>>>>>> other: test 1
@@ -108,16 +102,13 @@ Verify line splitting of custom conflict
 
   $ cat a
   Small Mathematical Series.
-  <<<<<<< local: test 2
   1
   2
   3
+  <<<<<<< local: test 2
   6
   8
   =======
-  1
-  2
-  3
   4
   5
   >>>>>>> other: test 1
@@ -150,16 +141,13 @@ Verify line trimming of custom conflict 
 
   $ cat a
   Small Mathematical Series.
-  <<<<<<< local: 123456789012345678901234567890123456789012345678901234567890\xe3\x81\x82... (esc)
   1
   2
   3
+  <<<<<<< local: 123456789012345678901234567890123456789012345678901234567890\xe3\x81\x82... (esc)
   6
   8
   =======
-  1
-  2
-  3
   4
   5
   >>>>>>> other: branch1
@@ -179,16 +167,13 @@ Verify basic conflict markers
 
   $ cat a
   Small Mathematical Series.
-  <<<<<<< local
   1
   2
   3
+  <<<<<<< local
   6
   8
   =======
-  1
-  2
-  3
   4
   5
   >>>>>>> other
diff --git a/tests/test-contrib.t b/tests/test-contrib.t
--- a/tests/test-contrib.t
+++ b/tests/test-contrib.t
@@ -148,10 +148,8 @@ conflicts
   base
   <<<<<<< conflict-local
   not other
-  end
   =======
   other
-  end
   >>>>>>> conflict-other
   [1]
 
@@ -161,10 +159,8 @@ 1 label
   base
   <<<<<<< foo
   not other
-  end
   =======
   other
-  end
   >>>>>>> conflict-other
   [1]
 
@@ -174,10 +170,8 @@ 2 labels
   base
   <<<<<<< foo
   not other
-  end
   =======
   other
-  end
   >>>>>>> bar
   [1]
 
diff --git a/tests/test-rebase-conflicts.t b/tests/test-rebase-conflicts.t
--- a/tests/test-rebase-conflicts.t
+++ b/tests/test-rebase-conflicts.t
@@ -305,3 +305,55 @@ Check that the right ancestors is used w
   rebase completed
   updating the branch cache
   truncating cache/rbc-revs-v1 to 72
+
+Test minimization of merge conflicts
+  $ hg up -q null
+  $ echo a > a
+  $ hg add a
+  $ hg commit -q -m 'a'
+  $ echo b >> a
+  $ hg commit -q -m 'ab'
+  $ hg bookmark ab
+  $ hg up -q '.^'
+  $ echo b >> a
+  $ echo c >> a
+  $ hg commit -q -m 'abc'
+  $ hg rebase -s 7bc217434fc1 -d ab --keep
+  rebasing 13:7bc217434fc1 "abc" (tip)
+  merging a
+  warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
+  unresolved conflicts (see hg resolve, then hg rebase --continue)
+  [1]
+  $ hg diff
+  diff -r 328e4ab1f7cc a
+  --- a/a	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/a	Wed Feb 10 * +0000 (glob)
+  @@ -1,2 +1,6 @@
+   a
+   b
+  +<<<<<<< dest:   328e4ab1f7cc  ab - test: ab
+  +=======
+  +c
+  +>>>>>>> source: 7bc217434fc1 - test: abc
+  $ hg rebase --abort
+  rebase aborted
+  $ hg up -q -C 7bc217434fc1
+  $ hg rebase -s . -d ab --keep -t internal:merge3
+  rebasing 13:7bc217434fc1 "abc" (tip)
+  merging a
+  warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
+  unresolved conflicts (see hg resolve, then hg rebase --continue)
+  [1]
+  $ hg diff
+  diff -r 328e4ab1f7cc a
+  --- a/a	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/a	Wed Feb 10 * +0000 (glob)
+  @@ -1,2 +1,8 @@
+   a
+  +<<<<<<< dest:   328e4ab1f7cc  ab - test: ab
+   b
+  +||||||| base
+  +=======
+  +b
+  +c
+  +>>>>>>> source: 7bc217434fc1 - test: abc


More information about the Mercurial-devel mailing list