changeset 4403:249e2603324c

Merge with crew-stable
author Matt Mackall <mpm@selenic.com>
date Thu, 03 May 2007 17:26:21 -0500
parents 84cd52b48f94 (diff) d1dd16256114 (current diff)
children 47371e1c1db4 8369672060b5
files
diffstat 1 files changed, 45 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -102,6 +102,27 @@ def findcopies(repo, m1, m2, ma, limit):
     Find moves and copies between m1 and m2 back to limit linkrev
     """
 
+    def nonoverlap(d1, d2, d3):
+        "Return list of elements in d1 not in d2 or d3"
+        l = [d for d in d1 if d not in d3 and d not in d2]
+        l.sort()
+        return l
+
+    def dirname(f):
+        s = f.rfind("/")
+        if s == -1:
+            return ""
+        return f[:s]
+
+    def dirs(files):
+        d = {}
+        for f in files:
+            f = dirname(f)
+            while f not in d:
+                d[f] = True
+                f = dirname(f)
+        return d
+
     def findold(fctx):
         "find files that path was copied from, back to linkrev limit"
         old = {}
@@ -124,33 +145,25 @@ def findcopies(repo, m1, m2, ma, limit):
         old.sort()
         return old
 
-    def nonoverlap(d1, d2, d3):
-        "Return list of elements in d1 not in d2 or d3"
-        l = [d for d in d1 if d not in d3 and d not in d2]
-        l.sort()
-        return l
+    copy = {}
+    fullcopy = {}
 
     def checkcopies(c, man):
         '''check possible copies for filectx c'''
         for of in findold(c):
-            if of not in man:
+            if of not in man: # original file not in other manifest?
                 continue
             c2 = ctx(of, man[of])
             ca = c.ancestor(c2)
-            if not ca: # unrelated
+            if not ca: # unrelated?
                 continue
+            # named changed on only one side?
             if ca.path() == c.path() or ca.path() == c2.path():
-                fullcopy[c.path()] = of
-                if c == ca and c2 == ca: # no merge needed, ignore copy
+                fullcopy[c.path()] = of # remember for dir rename detection
+                if c == c2: # no merge needed, ignore copy
                     continue
                 copy[c.path()] = of
 
-    def dirs(files):
-        d = {}
-        for f in files:
-            d[os.path.dirname(f)] = True
-        return d
-
     if not repo.ui.configbool("merge", "followcopies", True):
         return {}
 
@@ -159,8 +172,6 @@ def findcopies(repo, m1, m2, ma, limit):
         return {}
 
     dcopies = repo.dirstate.copies()
-    copy = {}
-    fullcopy = {}
     u1 = nonoverlap(m1, m2, ma)
     u2 = nonoverlap(m2, m1, ma)
     ctx = util.cachefunc(lambda f, n: repo.filectx(f, fileid=n[:20]))
@@ -179,28 +190,41 @@ def findcopies(repo, m1, m2, ma, limit):
     invalid = {}
     dirmove = {}
 
+    # examine each file copy for a potential directory move, which is
+    # when all the files in a directory are moved to a new directory
     for dst, src in fullcopy.items():
-        dsrc, ddst = os.path.dirname(src), os.path.dirname(dst)
+        dsrc, ddst = dirname(src), dirname(dst)
         if dsrc in invalid:
+            # already seen to be uninteresting
             continue
-        elif (dsrc in d1 and ddst in d1) or (dsrc in d2 and ddst in d2):
+        elif dsrc in d1 and ddst in d1:
+            # directory wasn't entirely moved locally
+            invalid[dsrc] = True
+        elif dsrc in d2 and ddst in d2:
+            # directory wasn't entirely moved remotely
             invalid[dsrc] = True
         elif dsrc in dirmove and dirmove[dsrc] != ddst:
+            # files from the same directory moved to two different places
             invalid[dsrc] = True
-            del dirmove[dsrc]
         else:
+            # looks good so far
             dirmove[dsrc + "/"] = ddst + "/"
 
+    for i in invalid:
+        if i in dirmove:
+            del dirmove[i]
+
     del d1, d2, invalid
 
     if not dirmove:
         return copy
 
-    # check unaccounted nonoverlapping files
+    # check unaccounted nonoverlapping files against directory moves
     for f in u1 + u2:
         if f not in fullcopy:
             for d in dirmove:
                 if f.startswith(d):
+                    # new file added in a directory that was moved, move it
                     copy[f] = dirmove[d] + f[len(d):]
                     break