[PATCH] Add support for 'union' merge strategy

Erik Huelsmann ehuels at gmail.com
Fri Jun 26 19:24:53 UTC 2015


As discussed on IRC, I'm submitting my first mercurial patch: to support
the 'union' merge strategy, where both sides of a conflict are included in
the result and not marking the file as conflicted.

Please tell me how to proceed. Thanks for your comments and help!

Regards,

Erik.

# HG changeset patch
# User erik <erik at hucs.nl>
# Date 1435346089 -7200
#      Fri Jun 26 21:14:49 2015 +0200
# Node ID d35c0f4e71ed16627a2c95539121bfda2b253157
# Parent  ff5172c830022b64cc5bd1bae36b2276e9dc6e5d
internal merge tool: add support for 'union' merge strategy.

One use-case for this merge strategy is the Changelog file being changed
on multiple branches and conflicting when being merged back to the main
branch.

diff -r ff5172c83002 -r d35c0f4e71ed mercurial/filemerge.py
--- a/mercurial/filemerge.py Wed Jun 24 13:41:27 2015 -0500
+++ b/mercurial/filemerge.py Fri Jun 26 21:14:49 2015 +0200
@@ -212,10 +212,7 @@
             util.copyfile(back, a) # restore from backup and try again
     return 1 # continue merging

- at internaltool('merge', True,
-              _("merging %s incomplete! "
-                "(edit conflicts, then use 'hg resolve --mark')\n"))
-def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files,
labels=None):
+def __imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels,
mode):
     """
     Uses the internal non-interactive simple merge algorithm for merging
     files. It will fail if there are any conflicts and leave markers in
@@ -232,10 +229,38 @@

         ui = repo.ui

-        r = simplemerge.simplemerge(ui, a, b, c, label=labels)
+        r = simplemerge.simplemerge(ui, a, b, c, label=labels, mode=mode)
         return True, r
     return False, 0

+
+ at internaltool('merge', True,
+              _("merging %s incomplete! "
+                "(edit conflicts, then use 'hg resolve --mark')\n"))
+def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files,
labels=None):
+    """
+    Uses the internal non-interactive simple merge algorithm for merging
+    files. It will fail if there are any conflicts and leave markers in
+    the partially merged file. Markers will have two sections, one for
each side
+    of merge."""
+
+    return __imerge(repo, mynode, orig, fcd, fco, fca, toolconf,
+                    files, labels, 'merge')
+
+
+ at internaltool('union', True,
+              _("merging %s incomplete! "
+                "(edit conflicts, then use 'hg resolve --mark')\n"))
+def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files,
labels=None):
+    """
+    Uses the internal non-interactive union merge algorithm for merging
+    files. It will use both sides if there are any conflicts."""
+
+    return __imerge(repo, mynode, orig, fcd, fco, fca, toolconf,
+                    files, labels, 'union')
+
+
+
 @internaltool('merge3', True,
               _("merging %s incomplete! "
                 "(edit conflicts, then use 'hg resolve --mark')\n"))
diff -r ff5172c83002 -r d35c0f4e71ed mercurial/simplemerge.py
--- a/mercurial/simplemerge.py Wed Jun 24 13:41:27 2015 -0500
+++ b/mercurial/simplemerge.py Fri Jun 26 21:14:49 2015 +0200
@@ -92,9 +92,9 @@
                 newline = '\r\n'
             elif self.a[0].endswith('\r'):
                 newline = '\r'
-        if name_a:
+        if name_a and start_marker:
             start_marker = start_marker + ' ' + name_a
-        if name_b:
+        if name_b and end_marker:
             end_marker = end_marker + ' ' + name_b
         if name_base and base_marker:
             base_marker = base_marker + ' ' + name_base
@@ -112,17 +112,20 @@
                     yield self.b[i]
             elif what == 'conflict':
                 self.conflicts = True
-                yield start_marker + newline
+                if start_marker is not None:
+                    yield start_marker + newline
                 for i in range(t[3], t[4]):
                     yield self.a[i]
                 if base_marker is not None:
                     yield base_marker + newline
                     for i in range(t[1], t[2]):
                         yield self.base[i]
-                yield mid_marker + newline
+                if mid_marker is not None:
+                    yield mid_marker + newline
                 for i in range(t[5], t[6]):
                     yield self.b[i]
-                yield end_marker + newline
+                if end_marker is not None:
+                    yield end_marker + newline
             else:
                 raise ValueError(what)

@@ -345,18 +348,24 @@
                 raise util.Abort(msg)
         return text

-    name_a = local
-    name_b = other
-    name_base = None
-    labels = opts.get('label', [])
-    if len(labels) > 0:
-        name_a = labels[0]
-    if len(labels) > 1:
-        name_b = labels[1]
-    if len(labels) > 2:
-        name_base = labels[2]
-    if len(labels) > 3:
-        raise util.Abort(_("can only specify three labels."))
+    mode = opts.get('mode', '')
+    if mode == 'union':
+        name_a = None
+        name_b = None
+        name_base = None
+    else:
+        name_a = local
+        name_b = other
+        name_base = None
+        labels = opts.get('label', [])
+        if len(labels) > 0:
+            name_a = labels[0]
+        if len(labels) > 1:
+            name_b = labels[1]
+        if len(labels) > 2:
+            name_base = labels[2]
+        if len(labels) > 3:
+            raise util.Abort(_("can only specify three labels."))

     try:
         localtext = readfile(local)
@@ -374,7 +383,11 @@

     m3 = Merge3Text(basetext, localtext, othertext)
     extrakwargs = {}
-    if name_base is not None:
+    if mode == 'union':
+        extrakwargs['start_marker'] = None
+        extrakwargs['end_marker'] = None
+        extrakwargs['mid_marker'] = None
+    elif name_base is not None:
         extrakwargs['base_marker'] = '|||||||'
         extrakwargs['name_base'] = name_base
     for line in m3.merge_lines(name_a=name_a, name_b=name_b,
**extrakwargs):
@@ -383,7 +396,7 @@
     if not opts.get('print'):
         out.close()

-    if m3.conflicts:
+    if m3.conflicts and not mode == 'union':
         if not opts.get('quiet'):
             ui.warn(_("warning: conflicts during merge.\n"))
         return 1


-- 
Bye,

Erik.

http://efficito.com -- Hosted accounting and ERP.
Robust and Flexible. No vendor lock-in.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://selenic.com/pipermail/mercurial-devel/attachments/20150626/d6a81e9d/attachment.html>


More information about the Mercurial-devel mailing list