merge: pull manifest checks and updates into separate functions
authorMatt Mackall <mpm@selenic.com>
Sun, 17 Sep 2006 16:47:33 -0500
changeset 3107 3bd05ad67f45
parent 3106 4ec28446fca8
child 3108 67874ebbb7dd
merge: pull manifest checks and updates into separate functions
mercurial/merge.py
--- a/mercurial/merge.py	Sun Sep 17 16:13:34 2006 -0500
+++ b/mercurial/merge.py	Sun Sep 17 16:47:33 2006 -0500
@@ -52,13 +52,67 @@
     os.unlink(c)
     return r
 
-def manifestmerge(ui, m1, m2, ma, overwrite, backwards):
+def checkunknown(repo, m2, status):
+    """
+    check for collisions between unknown files and files in m2
+    """
+    modified, added, removed, deleted, unknown = status[:5]
+    for f in unknown:
+        if f in m2:
+            if repo.file(f).cmp(m2[f], repo.wread(f)):
+                raise util.Abort(_("'%s' already exists in the working"
+                                   " dir and differs from remote") % f)
+
+def workingmanifest(repo, man, status):
+    """
+    Update manifest to correspond to the working directory
+    """
+
+    modified, added, removed, deleted, unknown = status[:5]
+    for i,l in (("a", added), ("m", modified), ("u", unknown)):
+        for f in l:
+            man[f] = man.get(f, nullid) + i
+            man.set(f, util.is_exec(repo.wjoin(f), man.execf(f)))
+
+    for f in deleted + removed:
+        del man[f]
+
+    return man
+
+def forgetremoved(m2, status):
+    """
+    Forget removed files
+
+    If we're jumping between revisions (as opposed to merging), and if
+    neither the working directory nor the target rev has the file,
+    then we need to remove it from the dirstate, to prevent the
+    dirstate from listing the file when it is no longer in the
+    manifest.
+    """
+
+    modified, added, removed, deleted, unknown = status[:5]
+    action = []
+
+    for f in deleted + removed:
+        if f not in m2:
+            action.append((f, "f"))
+
+    return action
+
+def manifestmerge(ui, m1, m2, ma, overwrite, backwards, partial):
     """
     Merge manifest m1 with m2 using ancestor ma and generate merge action list
     """
 
     action = []
 
+    # Filter manifests
+    if partial:
+        for f in m1.keys():
+            if not partial(f): del m1[f]
+        for f in m2.keys():
+            if not partial(f): del m2[f]
+
     # Compare manifests
     for f, n in m1.iteritems():
         if f in m2:
@@ -176,7 +230,8 @@
         raise util.Abort(_("update spans branches, use 'hg merge' "
                            "or 'hg update -C' to lose changes"))
 
-    modified, added, removed, deleted, unknown = repo.status()[:5]
+    status = repo.status()
+    modified, added, removed, deleted, unknown = status[:5]
     if branchmerge and not forcemerge:
         if modified or added or removed:
             raise util.Abort(_("outstanding uncommitted changes"))
@@ -185,13 +240,6 @@
     m2 = repo.changectx(p2).manifest().copy()
     ma = repo.changectx(pa).manifest()
 
-    if not force:
-        for f in unknown:
-            if f in m2:
-                if repo.file(f).cmp(m2[f], repo.wread(f)):
-                    raise util.Abort(_("'%s' already exists in the working"
-                                       " dir and differs from remote") % f)
-
     # resolve the manifest to determine which files
     # we care about merging
     repo.ui.note(_("resolving manifests\n"))
@@ -201,31 +249,13 @@
                   (short(p1), short(p2), short(pa)))
 
     action = []
-
-    # update m1 from working dir
-    for i,l in (("a", added), ("m", modified), ("u", unknown)):
-        for f in l:
-            m1[f] = m1.get(f, nullid) + i
-            m1.set(f, util.is_exec(repo.wjoin(f), m1.execf(f)))
-
-    for f in deleted + removed:
-        del m1[f]
+    m1 = workingmanifest(repo, m1, status)
 
-        # If we're jumping between revisions (as opposed to merging),
-        # and if neither the working directory nor the target rev has
-        # the file, then we need to remove it from the dirstate, to
-        # prevent the dirstate from listing the file when it is no
-        # longer in the manifest.
-        if linear_path and f not in m2:
-            action.append((f, "f"))
-
-    if partial:
-        for f in m1.keys():
-            if not partial(f): del m1[f]
-        for f in m2.keys():
-            if not partial(f): del m2[f]
-
-    action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards)
+    if not force:
+        checkunknown(repo, m2, status)
+    if linear_path:
+        action += forgetremoved(m2, status)
+    action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards, partial)
     del m1, m2, ma
 
     ### apply phase