diff mercurial/merge.py @ 18134:6c35b53cd28b

copies: separate moves via directory renames from explicit copies Currently the "copy" dict contains both explicit copies/moves made by a context and pending moves that need to happen because the other context moved the directory the file was in. For explicit copies, the dict stores a destination to source map, while for pending moves via directory renames, it stores a source to destination map. The merge code uses this fact in a non- obvious way to differentiate between these two cases. We make this explicit by storing these pending moves in a separate dict. The dict still has a source to destination map, but that is called out in the docstring.
author Siddharth Agarwal <sid0@fb.com>
date Wed, 26 Dec 2012 14:50:17 -0800
parents 551e2901192e
children 242d2f4ec01c
line wrap: on
line diff
--- a/mercurial/merge.py	Wed Dec 26 11:16:18 2012 -0600
+++ b/mercurial/merge.py	Wed Dec 26 14:50:17 2012 -0800
@@ -213,14 +213,15 @@
         repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m))
         action.append((f, m) + args)
 
-    action, copy = [], {}
+    action, copy, movewithdir = [], {}, {}
 
     if overwrite:
         pa = p1
     elif pa == p2: # backwards
         pa = p1.p1()
     elif pa and repo.ui.configbool("merge", "followcopies", True):
-        copy, diverge, renamedelete = copies.mergecopies(repo, p1, p2, pa)
+        ret = copies.mergecopies(repo, p1, p2, pa)
+        copy, movewithdir, diverge, renamedelete = ret
         for of, fl in diverge.iteritems():
             act("divergent renames", "dr", of, fl)
         for of, fl in renamedelete.iteritems():
@@ -233,6 +234,7 @@
 
     m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest()
     copied = set(copy.values())
+    copied.update(movewithdir.values())
 
     if '.hgsubstate' in m1:
         # check whether sub state is modified
@@ -259,14 +261,14 @@
                 act("versions differ", "m", f, f, f, rflags, False)
         elif f in copied: # files we'll deal with on m2 side
             pass
-        elif f in copy:
+        elif f in movewithdir: # directory rename
+            f2 = movewithdir[f]
+            act("remote renamed directory to " + f2, "d", f, None, f2,
+                m1.flags(f))
+        elif f in copy: # case 2 A,B/B/B or case 4,21 A/B/B
             f2 = copy[f]
-            if f2 not in m2: # directory rename
-                act("remote renamed directory to " + f2, "d",
-                    f, None, f2, m1.flags(f))
-            else: # case 2 A,B/B/B or case 4,21 A/B/B
-                act("local copied/moved to " + f2, "m",
-                    f, f2, f, fmerge(f, f2, f2), False)
+            act("local copied/moved to " + f2, "m", f, f2, f,
+                fmerge(f, f2, f2), False)
         elif f in ma: # clean, a different, no remote
             if n != ma[f]:
                 if repo.ui.promptchoice(
@@ -286,12 +288,13 @@
             continue
         if f in m1 or f in copied: # files already visited
             continue
-        if f in copy:
+        if f in movewithdir:
+            f2 = movewithdir[f]
+            act("local renamed directory to " + f2, "d", None, f, f2,
+                m2.flags(f))
+        elif f in copy:
             f2 = copy[f]
-            if f2 not in m1: # directory rename
-                act("local renamed directory to " + f2, "d",
-                    None, f, f2, m2.flags(f))
-            elif f2 in m2: # rename case 1, A/A,B/A
+            if f2 in m2: # rename case 1, A/A,B/A
                 act("remote copied to " + f, "m",
                     f2, f, f, fmerge(f2, f, f2), False)
             else: # case 3,20 A/B/A