[PATCH 1 of 6] checkheads: extract branchmap preprocessing

pierre-yves.david at logilab.fr pierre-yves.david at logilab.fr
Tue Jul 17 16:49:32 UTC 2012


# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at logilab.fr>
# Date 1342542109 -7200
# Node ID fbe4b7d68ae1f6aa14e4750c85103380eded8414
# Parent  1506bc9c67424d8252dc1525e2acc028d2aa1541
checkheads: extract branchmap preprocessing

The checkheads function is far too complicated. This extract help to explicite
what part of the preprocessing are reused by the actual check.

This the first step toward a wider refactoring.

diff --git a/mercurial/discovery.py b/mercurial/discovery.py
--- a/mercurial/discovery.py
+++ b/mercurial/discovery.py
@@ -147,81 +147,100 @@ def findcommonoutgoing(repo, other, only
         commonheads = set(og.commonheads)
         og.missingheads = [h for h in og.missingheads if h not in commonheads]
 
     return og
 
+def _branchmapsummary(repo, remote, outgoing):
+    """compute a summary of branch and heads status before and after push
+
+    - oldmap:      {'branch': [heads]} mapping for remote
+    - newmap:      {'branch': [heads]} mapping for local
+    - unsynced:    set of branch that have unsynced remote changes
+    - branches:    set of all common branch pushed
+    - newbranches: list of plain new pushed branch
+    """
+    cl = repo.changelog
+
+    # A. Create set of branches involved in the push.
+    branches = set(repo[n].branch() for n in outgoing.missing)
+    remotemap = remote.branchmap()
+    newbranches = branches - set(remotemap)
+    branches.difference_update(newbranches)
+
+    # B. Construct the initial oldmap and newmap dicts.
+    # They contain information about the remote heads before and
+    # after the push, respectively.
+    # Heads not found locally are not included in either dict,
+    # since they won't be affected by the push.
+    # unsynced contains all branches with incoming changesets.
+    oldmap = {}
+    newmap = {}
+    unsynced = set()
+    for branch in branches:
+        remotebrheads = remotemap[branch]
+
+        prunedbrheads = [h for h in remotebrheads if h in cl.nodemap]
+        oldmap[branch] = prunedbrheads
+        newmap[branch] = list(prunedbrheads)
+        if len(remotebrheads) > len(prunedbrheads):
+            unsynced.add(branch)
+
+    # C. Update newmap with outgoing changes.
+    # This will possibly add new heads and remove existing ones.
+    ctxgen = (repo[n] for n in outgoing.missing)
+    repo._updatebranchcache(newmap, ctxgen)
+    return oldmap, newmap, unsynced, branches, newbranches
+
+def _oldbranchmapsummary(repo, remoteheads, outgoing, inc=False):
+    """Compute branchmapsummary for repo without branchmap support"""
+
+    cl = repo.changelog
+    # 1-4b. old servers: Check for new topological heads.
+    # Construct {old,new}map with branch = None (topological branch).
+    # (code based on _updatebranchcache)
+    oldheads = set(h for h in remoteheads if h in cl.nodemap)
+    # all nodes in outgoing.missing are children of either:
+    # - an element of oldheads
+    # - another element of outgoing.missing
+    # - nullrev
+    # This explains why the new head are very simple to compute.
+    r = repo.set('heads(%ln + %ln)', oldheads, outgoing.missing)
+    branches = set([None])
+    newmap = {None: list(c.node() for c in r)}
+    oldmap = {None: oldheads}
+    unsynced = inc and branches or set()
+    return oldmap, newmap, unsynced, branches, set()
+
 def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False):
     """Check that a push won't add any outgoing head
 
     raise Abort error and display ui message as needed.
     """
+    # Check for each named branch if we're creating new remote heads.
+    # To be a remote head after push, node must be either:
+    # - unknown locally
+    # - a local outgoing head descended from update
+    # - a remote head that's known locally and not
+    #   ancestral to an outgoing head
     if remoteheads == [nullid]:
         # remote is empty, nothing to check.
         return
 
-    cl = repo.changelog
     if remote.capable('branchmap'):
-        # Check for each named branch if we're creating new remote heads.
-        # To be a remote head after push, node must be either:
-        # - unknown locally
-        # - a local outgoing head descended from update
-        # - a remote head that's known locally and not
-        #   ancestral to an outgoing head
+        bms = _branchmapsummary(repo, remote, outgoing)
+    else:
+        bms = _oldbranchmapsummary(repo, remoteheads, outgoing, inc)
+    oldmap, newmap, unsynced, branches, newbranches = bms
+    # 1. Check for new branches on the remote.
+    if newbranches and not newbranch:  # new branch requires --new-branch
+        branchnames = ', '.join(sorted(newbranches))
+        raise util.Abort(_("push creates new remote branches: %s!")
+                           % branchnames,
+                         hint=_("use 'hg push --new-branch' to create"
+                                " new remote branches"))
 
-        # 1. Create set of branches involved in the push.
-        branches = set(repo[n].branch() for n in outgoing.missing)
-
-        # 2. Check for new branches on the remote.
-        remotemap = remote.branchmap()
-        newbranches = branches - set(remotemap)
-        if newbranches and not newbranch: # new branch requires --new-branch
-            branchnames = ', '.join(sorted(newbranches))
-            raise util.Abort(_("push creates new remote branches: %s!")
-                               % branchnames,
-                             hint=_("use 'hg push --new-branch' to create"
-                                    " new remote branches"))
-        branches.difference_update(newbranches)
-
-        # 3. Construct the initial oldmap and newmap dicts.
-        # They contain information about the remote heads before and
-        # after the push, respectively.
-        # Heads not found locally are not included in either dict,
-        # since they won't be affected by the push.
-        # unsynced contains all branches with incoming changesets.
-        oldmap = {}
-        newmap = {}
-        unsynced = set()
-        for branch in branches:
-            remotebrheads = remotemap[branch]
-            prunedbrheads = [h for h in remotebrheads if h in cl.nodemap]
-            oldmap[branch] = prunedbrheads
-            newmap[branch] = list(prunedbrheads)
-            if len(remotebrheads) > len(prunedbrheads):
-                unsynced.add(branch)
-
-        # 4. Update newmap with outgoing changes.
-        # This will possibly add new heads and remove existing ones.
-        ctxgen = (repo[n] for n in outgoing.missing)
-        repo._updatebranchcache(newmap, ctxgen)
-
-    else:
-        # 1-4b. old servers: Check for new topological heads.
-        # Construct {old,new}map with branch = None (topological branch).
-        # (code based on _updatebranchcache)
-        oldheads = set(h for h in remoteheads if h in cl.nodemap)
-        # all nodes in outgoing.missing are children of either:
-        # - an element of oldheads
-        # - another element of outgoing.missing
-        # - nullrev
-        # This explains why the new head are very simple to compute.
-        r = repo.set('heads(%ln + %ln)', oldheads, outgoing.missing)
-        branches = set([None])
-        newmap = {None: list(c.node() for c in r)}
-        oldmap = {None: oldheads}
-        unsynced = inc and branches or set()
-
-    # 5. Check for new heads.
+    # 2. Check for new heads.
     # If there are more heads after the push than before, a suitable
     # error message, depending on unsynced status, is displayed.
     error = None
     localbookmarks = repo._bookmarks
 


More information about the Mercurial-devel mailing list