mercurial/copies.py
changeset 30195 88626de195f8
parent 30194 8c69c52ced98
child 30196 d738cda70894
--- a/mercurial/copies.py	Thu Oct 13 02:03:49 2016 +0200
+++ b/mercurial/copies.py	Thu Oct 13 02:03:54 2016 +0200
@@ -374,10 +374,10 @@
     bothnew = sorted(addedinm1 & addedinm2)
 
     for f in u1u:
-        _checkcopies(c1, f, m1, m2, base, limit, data1)
+        _checkcopies(c1, f, m1, m2, base, tca, limit, data1)
 
     for f in u2u:
-        _checkcopies(c2, f, m2, m1, base, limit, data2)
+        _checkcopies(c2, f, m2, m1, base, tca, limit, data2)
 
     copy = dict(data1['copy'].items() + data2['copy'].items())
     fullcopy = dict(data1['fullcopy'].items() + data2['fullcopy'].items())
@@ -405,8 +405,8 @@
                 'diverge': bothdiverge,
                }
     for f in bothnew:
-        _checkcopies(c1, f, m1, m2, base, limit, bothdata)
-        _checkcopies(c2, f, m2, m1, base, limit, bothdata)
+        _checkcopies(c1, f, m1, m2, base, tca, limit, bothdata)
+        _checkcopies(c2, f, m2, m1, base, tca, limit, bothdata)
     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
@@ -521,7 +521,7 @@
     except StopIteration:
         return False
 
-def _checkcopies(ctx, f, m1, m2, base, limit, data):
+def _checkcopies(ctx, f, m1, m2, base, tca, limit, data):
     """
     check possible copies of f from m1 to m2
 
@@ -530,6 +530,7 @@
     m1 = the source manifest
     m2 = the destination manifest
     base = the changectx used as a merge base
+    tca = topological common ancestor for graft-like scenarios
     limit = the rev number to not search beyond
     data = dictionary of dictionary to store copy data. (see mergecopies)
 
@@ -540,6 +541,17 @@
     """
 
     mb = base.manifest()
+    # Might be true if this call is about finding backward renames,
+    # This happens in the case of grafts because the DAG is then rotated.
+    # If the file exists in both the base and the source, we are not looking
+    # for a rename on the source side, but on the part of the DAG that is
+    # traversed backwards.
+    #
+    # In the case there is both backward and forward renames (before and after
+    # the base) this is more complicated as we must detect a divergence. This
+    # is currently broken and hopefully some later code update will make that
+    # work (we use 'backwards = False' in that case)
+    backwards = base != tca and f in mb
     getfctx = _makegetfctx(ctx)
 
     of = None
@@ -554,7 +566,11 @@
             continue
         seen.add(of)
 
-        data['fullcopy'][f] = of # remember for dir rename detection
+        # remember for dir rename detection
+        if backwards:
+            data['fullcopy'][of] = f # grafting backwards through renames
+        else:
+            data['fullcopy'][f] = of
         if of not in m2:
             continue # no match, keep looking
         if m2[of] == mb.get(of):
@@ -562,9 +578,11 @@
         c2 = getfctx(of, m2[of])
         # c2 might be a plain new file on added on destination side that is
         # unrelated to the droids we are looking for.
-        cr = _related(oc, c2, base.rev())
+        cr = _related(oc, c2, tca.rev())
         if cr and (of == f or of == c2.path()): # non-divergent
-            if of in mb:
+            if backwards:
+                data['copy'][of] = f
+            elif of in mb:
                 data['copy'][f] = of
             return