[PATCH STABLE] graft: support grafting across renames (issue4028)

Gábor Stefanik gabor.stefanik at nng.com
Mon Jul 25 14:16:32 EDT 2016


# HG changeset patch
# User Gábor Stefanik <gabor.stefanik at nng.com>
# Date 1469470573 -7200
#      Mon Jul 25 20:16:13 2016 +0200
# Branch stable
# Node ID 395d3fa2ac89fad199c99cc137bf801502292325
# Parent  9c2cc107547fd701a7604349632f2f590366f17c
graft: support grafting across renames (issue4028)

Graft performs a merge with a false common ancestor, which must be taken into
account when tracking renames. Compute the real common ancestor in this case,
and track renames between the real and false common ancestors in reverse.

diff --git a/mercurial/copies.py b/mercurial/copies.py
--- a/mercurial/copies.py
+++ b/mercurial/copies.py
@@ -327,13 +327,22 @@
         return {}, {}, {}, {}
     repo.ui.debug("  searching for copies back to rev %d\n" % limit)
 
+    # graft gives us a false common ancestor, we need to find a real one
+    true_ca = ca
+    if not (ca.descendant(c1) and ca.descendant(c2)):
+        true_ca = c1.ancestor(c2)
+    
     m1 = c1.manifest()
     m2 = c2.manifest()
-    ma = ca.manifest()
+    ma = true_ca.manifest()
 
-    copy1, copy2, = {}, {}
+    copy1, copy2 = {}, {}
+    copy1a, copy2a = {}, {}
+    copy1b, copy2b = {}, {}
     movewithdir1, movewithdir2 = {}, {}
     fullcopy1, fullcopy2 = {}, {}
+    fullcopy1a, fullcopy2a = {}, {}
+    fullcopy1b, fullcopy2b = {}, {}
     diverge = {}
 
     # find interesting file sets from manifests
@@ -343,10 +352,18 @@
     bothnew = sorted(addedinm1 & addedinm2)
 
     for f in u1:
-        checkcopies(c1, f, m1, m2, ca, limit, diverge, copy1, fullcopy1)
+        checkcopies(c1, f, m1, m2, ca, limit, diverge, copy1a, fullcopy1a)
+        checkcopies(c1, f, m1, m2, true_ca, limit, diverge, copy1b, fullcopy1b)
+        copy1 = dict((set(copy1a.items()) & set(copy1b.items())) |
+            (set([(y, x) for (x, y) in copy1a.items()])-
+             set([(y, x) for (x, y) in copy1b.items()])))
 
     for f in u2:
-        checkcopies(c2, f, m2, m1, ca, limit, diverge, copy2, fullcopy2)
+        checkcopies(c2, f, m2, m1, ca, limit, diverge, copy2a, fullcopy2a)
+        checkcopies(c2, f, m2, m1, true_ca, limit, diverge, copy2b, fullcopy2b)
+        copy2 = dict((set(copy2a.items()) & set(copy2b.items())) |
+            (set([(y, x) for (x, y) in copy2a.items()])-
+             set([(y, x) for (x, y) in copy2b.items()])))
 
     copy = dict(copy1.items() + copy2.items())
     movewithdir = dict(movewithdir1.items() + movewithdir2.items())
@@ -373,6 +390,8 @@
     for f in bothnew:
         checkcopies(c1, f, m1, m2, ca, limit, bothdiverge, _copy, _fullcopy)
         checkcopies(c2, f, m2, m1, ca, limit, bothdiverge, _copy, _fullcopy)
+        checkcopies(c1, f, m1, m2, true_ca, limit, bothdiverge, _copy, _fullcopy)
+        checkcopies(c2, f, m2, m1, true_ca, limit, bothdiverge, _copy, _fullcopy)
     for of, fl in bothdiverge.items():
         if len(fl) == 2 and fl[0] == fl[1]:
             copy[fl[0]] = of # not actually divergent, just matching renames


More information about the Mercurial-devel mailing list