[PATCH 4 of 4 phases] phases: make outgoing object and discovery aware of exclusion

Pierre-Yves David pierre-yves.david at ens-lyon.org
Tue Jan 10 17:31:23 CST 2012


# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at ens-lyon.org>
# Date 1326238066 -3600
# Node ID 477a3a40a35fb84f0d975de3545d10f70dd45a74
# Parent  7d93456f321f510481b62becaae977d171a54392
phases: make outgoing object and discovery aware of exclusion

The outgoing object gains an "excluded" members holding all changesets which
were excluded because there where secret.

The core discovery code now remove secret changeset from discovery by default.
This means that any command relying on discovery will exclude secret changeset.
Most notable one are outgoing and bundle. (But bundle with and explicit
``--base`` still allow to bundle outgoing changeset.

diff --git a/mercurial/discovery.py b/mercurial/discovery.py
--- a/mercurial/discovery.py
+++ b/mercurial/discovery.py
@@ -7,7 +7,7 @@
 
 from node import nullid, short
 from i18n import _
-import util, setdiscovery, treediscovery
+import util, setdiscovery, treediscovery, phases
 
 def findcommonincoming(repo, remote, heads=None, force=False):
     """Return a tuple (common, anyincoming, heads) used to identify the common
@@ -54,6 +54,7 @@
 
       missing is a list of all nodes present in local but not in remote.
       common is a list of all nodes shared between the two repos.
+      excluded is the list of missing changeset that shouldn't be sent remotely.
       missingheads is the list of heads of missing.
       commonheads is the list of heads of common.
 
@@ -66,6 +67,7 @@
         self._revlog = revlog
         self._common = None
         self._missing = None
+        self.excluded = []
 
     def _computecommonmissing(self):
         sets = self._revlog.findcommonmissing(self.commonheads,
@@ -94,8 +96,41 @@
 
     If commoninc is given, it must the the result of a prior call to
     findcommonincoming(repo, other, force) to avoid recomputing it here.'''
-    common, _any, _hds = commoninc or findcommonincoming(repo, other, force=force)
-    return outgoing(repo.changelog, common, onlyheads or repo.heads())
+    # declare an empty outgoing object to be filled later
+    og = outgoing(repo.changelog, None, None)
+
+    # get common set if not provided
+    if commoninc is None:
+        commoninc = findcommonincoming(repo, other, force=force)
+    og.commonheads, _any, _hds = commoninc
+
+    # compute outgoing
+    if not repo._phaseroots[phases.secret]:
+        og.missingheads = onlyheads or repo.heads()
+    elif onlyheads is None:
+        # use visible heads as it should be cached
+        og.missingheads = phases.visibleheads(repo)
+        og.excluded = [ctx.node() for ctx in repo.set('secret()')]
+    else:
+        # compute common, missing and exclude secret stuff
+        sets = repo.changelog.findcommonmissing(og.commonheads, onlyheads)
+        og._common, allmissing = sets
+        og._missing = missing = []
+        og._excluded = excluded = []
+        for node in allmissing:
+            if repo[node].phase() >= phases.secret:
+                excluded.append(node)
+            else:
+                missing.append(node)
+        if excluded:
+            # update missing heads
+            rset = repo.set('heads(%ln)', missing)
+            missingheads = [ctx.node() for ctx in rset]
+        else:
+            missingheads = onlyheads
+        og.missingheads = missingheads
+
+    return og
 
 def prepush(repo, remote, force, revs, newbranch):
     '''Analyze the local and remote repositories and determine which
@@ -121,29 +156,17 @@
     _common, inc, remoteheads = commoninc
 
     cl = repo.changelog
-    alloutg = outgoing.missing
+    outg = outgoing.missing
     common = outgoing.commonheads
-    outg = []
-    secret = []
-    for o in alloutg:
-        if repo[o].phase() >= 2:
-            secret.append(o)
-        else:
-            outg.append(o)
 
     if not outg:
-        if secret:
+        if outgoing.excluded:
             repo.ui.status(_("no changes to push but %i secret changesets\n")
-                           % len(secret))
+                           % len(outgoing.excluded))
         else:
             repo.ui.status(_("no changes found\n"))
         return None, 1, common
 
-    if secret:
-        # recompute target revs
-        revs = [ctx.node() for ctx in repo.set('heads(::(%ld))',
-                                               map(repo.changelog.rev, outg))]
-
     if not force and remoteheads != [nullid]:
         if remote.capable('branchmap'):
             # Check for each named branch if we're creating new remote heads.
@@ -241,7 +264,8 @@
         if unsynced:
             repo.ui.warn(_("note: unsynced remote changes!\n"))
 
-    if revs is None:
+    if revs is None and not outgoing.excluded:
+        # push everything,
         # use the fast path, no race possible on push
         cg = repo._changegroup(outg, 'push')
     else:
diff --git a/tests/test-check-code-hg.t b/tests/test-check-code-hg.t
--- a/tests/test-check-code-hg.t
+++ b/tests/test-check-code-hg.t
@@ -351,9 +351,6 @@
    >     If onlyheads is given, only nodes ancestral to nodes in onlyheads (inclusive)
    warning: line over 80 characters
   mercurial/discovery.py:0:
-   >     common, _any, _hds = commoninc or findcommonincoming(repo, other, force=force)
-   warning: line over 80 characters
-  mercurial/discovery.py:0:
    > def findcommonoutgoing(repo, other, onlyheads=None, force=False, commoninc=None):
    warning: line over 80 characters
   mercurial/dispatch.py:0:
diff --git a/tests/test-phases.t b/tests/test-phases.t
--- a/tests/test-phases.t
+++ b/tests/test-phases.t
@@ -95,6 +95,23 @@
   > [phases]
   > publish=False
   > EOF
+  $ hg outgoing ../push-dest --template='{rev} {phase} {desc|firstline}\n'
+  comparing with ../push-dest
+  searching for changes
+  0 public A
+  1 public B
+  2 draft C
+  3 draft D
+  6 draft B'
+  $ hg outgoing -r default ../push-dest --template='{rev} {phase} {desc|firstline}\n'
+  comparing with ../push-dest
+  searching for changes
+  0 public A
+  1 public B
+  2 draft C
+  3 draft D
+  6 draft B'
+
   $ hg push ../push-dest -f # force because we push multiple heads
   pushing to ../push-dest
   searching for changes
@@ -140,6 +157,13 @@
   0 0 A
   $ cd ..
 
+But secret can still be bundled explicitly
+
+  $ cd initialrepo
+  $ hg bundle --base '4^' -r 'children(4)' ../secret-bundle.hg
+  4 changesets found
+  $ cd ..
+
 Test revset
 
   $ cd initialrepo


More information about the Mercurial-devel mailing list