mercurial/merge.py
branchstable
changeset 19105 c60a7f5a741f
parent 19095 5cc71484ee9c
child 19157 113681bbef9e
--- a/mercurial/merge.py	Tue Apr 30 05:01:32 2013 +0900
+++ b/mercurial/merge.py	Tue Apr 30 05:01:32 2013 +0900
@@ -110,54 +110,6 @@
         raise util.Abort(_("untracked files in working directory differ "
                            "from files in requested revision"))
 
-def _remains(f, m, ma, workingctx=False):
-    """check whether specified file remains after merge.
-
-    It is assumed that specified file is not contained in the manifest
-    of the other context.
-    """
-    if f in ma:
-        n = m[f]
-        if n != ma[f]:
-            return True # because it is changed locally
-            # even though it doesn't remain, if "remote deleted" is
-            # chosen in manifestmerge()
-        elif workingctx and n[20:] == "a":
-            return True # because it is added locally (linear merge specific)
-        else:
-            return False # because it is removed remotely
-    else:
-        return True # because it is added locally
-
-def _checkcollision(mctx, extractxs):
-    "check for case folding collisions in the destination context"
-    folded = {}
-    for fn in mctx:
-        fold = util.normcase(fn)
-        if fold in folded:
-            raise util.Abort(_("case-folding collision between %s and %s")
-                             % (fn, folded[fold]))
-        folded[fold] = fn
-
-    if extractxs:
-        wctx, actx = extractxs
-        # class to delay looking up copy mapping
-        class pathcopies(object):
-            @util.propertycache
-            def map(self):
-                # {dst@mctx: src@wctx} copy mapping
-                return copies.pathcopies(wctx, mctx)
-        pc = pathcopies()
-
-        for fn in wctx:
-            fold = util.normcase(fn)
-            mfn = folded.get(fold, None)
-            if (mfn and mfn != fn and pc.map.get(mfn) != fn and
-                _remains(fn, wctx.manifest(), actx.manifest(), True) and
-                _remains(mfn, mctx.manifest(), actx.manifest())):
-                raise util.Abort(_("case-folding collision between %s and %s")
-                                 % (mfn, fn))
-
 def _forgetremoved(wctx, mctx, branchmerge):
     """
     Forget removed files
@@ -186,6 +138,62 @@
 
     return actions
 
+def _checkcollision(repo, wmf, actions, prompts):
+    # build provisional merged manifest up
+    pmmf = set(wmf)
+
+    def addop(f, args):
+        pmmf.add(f)
+    def removeop(f, args):
+        pmmf.discard(f)
+    def nop(f, args):
+        pass
+
+    def renameop(f, args):
+        f2, fd, flags = args
+        if f:
+            pmmf.discard(f)
+        pmmf.add(fd)
+    def mergeop(f, args):
+        f2, fd, move = args
+        if move:
+            pmmf.discard(f)
+        pmmf.add(fd)
+
+    opmap = {
+        "a": addop,
+        "d": renameop,
+        "dr": nop,
+        "e": nop,
+        "f": addop, # untracked file should be kept in working directory
+        "g": addop,
+        "m": mergeop,
+        "r": removeop,
+        "rd": nop,
+    }
+    for f, m, args, msg in actions:
+        op = opmap.get(m)
+        assert op, m
+        op(f, args)
+
+    opmap = {
+        "cd": addop,
+        "dc": addop,
+    }
+    for f, m in prompts:
+        op = opmap.get(m)
+        assert op, m
+        op(f, None)
+
+    # check case-folding collision in provisional merged manifest
+    foldmap = {}
+    for f in sorted(pmmf):
+        fold = util.normcase(f)
+        if fold in foldmap:
+            raise util.Abort(_("case-folding collision between %s and %s")
+                             % (f, foldmap[fold]))
+        foldmap[fold] = f
+
 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
                   acceptremote=False):
     """
@@ -342,6 +350,14 @@
         raise util.Abort(_("untracked files in working directory differ "
                            "from files in requested revision"))
 
+    if not util.checkcase(repo.path):
+        # check collision between files only in p2 for clean update
+        if (not branchmerge and
+            (force or not wctx.dirty(missing=True, branch=False))):
+            _checkcollision(repo, m2, [], [])
+        else:
+            _checkcollision(repo, m1, actions, prompts)
+
     for f, m in sorted(prompts):
         if m == "cd":
             if acceptremote:
@@ -541,14 +557,6 @@
                      acceptremote=False):
     "Calculate the actions needed to merge mctx into tctx"
     actions = []
-    folding = not util.checkcase(repo.path)
-    if folding:
-        # collision check is not needed for clean update
-        if (not branchmerge and
-            (force or not tctx.dirty(missing=True, branch=False))):
-            _checkcollision(mctx, None)
-        else:
-            _checkcollision(mctx, (tctx, ancestor))
     actions += manifestmerge(repo, tctx, mctx,
                              ancestor,
                              branchmerge, force,