[PATCH 6 of 6 phases] phases: do not exchange secret changesets

pierre-yves.david at logilab.fr pierre-yves.david at logilab.fr
Mon Dec 19 04:46:52 CST 2011


# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at logilab.fr>
# Date 1324291511 -3600
# Node ID 9d62a0e54cdb861635fe29db437a8a5a5e8e0180
# Parent  3ae9a35bb323deaf364174340e93d392c2f7c4fd
phases: do not exchange secret changesets

Any secret changesets will be exclude from pull and push. Phase data are
properly synchronized on pull and push if a changeset is seen as secret locally
but is non-secret remote side.

The case of a changeset that exist as secret on the remote side but are
non-secret locally is not covered by this changeset. The situation is much
trickier as we do not know the changeset exist remotely (and therefore don't
push any data about it).

diff --git a/mercurial/discovery.py b/mercurial/discovery.py
--- a/mercurial/discovery.py
+++ b/mercurial/discovery.py
@@ -83,16 +83,32 @@ def prepush(repo, remote, force, revs, n
     common, revs = findcommonoutgoing(repo, remote, onlyheads=revs,
                                       commoninc=commoninc, force=force)
     _common, inc, remoteheads = commoninc
 
     cl = repo.changelog
-    outg = cl.findmissing(common, revs)
+    alloutg = cl.findmissing(common, revs)
+    outg = []
+    secret = []
+    for o in alloutg:
+        if repo[o].phase() >= 2:
+            secret.append(o)
+        else:
+            outg.append(o)
 
     if not outg:
-        repo.ui.status(_("no changes found\n"))
+        if secret:
+            repo.ui.status(_("no changes to push but %i secret changesets\n")
+                           % len(secret))
+        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.
             # To be a remote head after push, node must be either:
             # - unknown locally
diff --git a/mercurial/setdiscovery.py b/mercurial/setdiscovery.py
--- a/mercurial/setdiscovery.py
+++ b/mercurial/setdiscovery.py
@@ -7,10 +7,11 @@
 # GNU General Public License version 2 or any later version.
 
 from node import nullid
 from i18n import _
 import random, collections, util, dagutil
+import phases
 
 def _updatesample(dag, nodes, sample, always, quicksamplesize=0):
     # if nodes is empty we scan the entire graph
     if nodes:
         heads = dag.headsetofconnecteds(nodes)
@@ -97,11 +98,11 @@ def findcommonheads(ui, local, remote,
     roundtrips += 1
     ownheads = dag.heads()
     sample = ownheads
     if remote.local():
         # stopgap until we have a proper localpeer that supports batch()
-        srvheadhashes = remote.heads()
+        srvheadhashes = phases.visibleheads(remote)
         yesno = remote.known(dag.externalizeall(sample))
     elif remote.capable('batch'):
         batch = remote.batch()
         srvheadhashesref = batch.heads()
         yesnoref = batch.known(dag.externalizeall(sample))
diff --git a/mercurial/wireproto.py b/mercurial/wireproto.py
--- a/mercurial/wireproto.py
+++ b/mercurial/wireproto.py
@@ -8,10 +8,11 @@
 import urllib, tempfile, os, sys
 from i18n import _
 from node import bin, hex
 import changegroup as changegroupmod
 import repo, error, encoding, util, store
+import phases
 
 # abstract batching support
 
 class future(object):
     '''placeholder for a value to be set later'''
@@ -447,11 +448,11 @@ def getbundle(repo, proto, others):
         opts[k] = decodelist(v)
     cg = repo.getbundle('serve', **opts)
     return streamres(proto.groupchunks(cg))
 
 def heads(repo, proto):
-    h = repo.heads()
+    h = phases.visibleheads(repo)
     return encodelist(h) + "\n"
 
 def hello(repo, proto):
     '''the hello command returns a set of lines describing various
     interesting things about the server, in an RFC822-like format.
diff --git a/tests/test-phases-exchange.t b/tests/test-phases-exchange.t
--- a/tests/test-phases-exchange.t
+++ b/tests/test-phases-exchange.t
@@ -5,11 +5,11 @@
   $ alias hgph='hg log --template "{rev} {phase} {desc} - {node|short}\n"'
 
   $ mkcommit() {
   >    echo "$1" > "$1"
   >    hg add "$1"
-  >    hg ci -m "$1"
+  >    hg ci -m "$1" $2
   > }
 
   $ hg init alpha
   $ cd alpha
   $ mkcommit a-A
@@ -476,10 +476,11 @@ Pushing to Publish=False (common changes
   0 0 a-A - 054250a37db4
 
 
 Pushing to Publish=True (common changeset from publish=False)
 
+(in mu)
   $ hg push ../alpha
   pushing to ../alpha
   searching for changes
   no changes found
   $ hgph
@@ -504,5 +505,64 @@ Pushing to Publish=True (common changese
   3 0 a-D - b555f63b6063
   2 0 a-C - 54acac6f23ab
   1 0 a-B - 548a3d25dbf0
   0 0 a-A - 054250a37db4
 
+
+Discovery locally secret changeset on a remote repository:
+
+- should make it non-secret
+
+  $ cd ../alpha
+  $ mkcommit A-secret --secret
+  $ hgph
+  11 2 A-secret - 435b5d83910c
+  10 0 a-H - 967b449fbc94
+  9 1 a-G - 3e27b6f1eee1
+  8 0 a-F - b740e3e5c05d
+  7 0 a-E - e9f537e46dea
+  6 0 n-B - 145e75495359
+  5 0 n-A - d6bcb4f74035
+  4 0 b-A - f54f1bb90ff3
+  3 0 a-D - b555f63b6063
+  2 0 a-C - 54acac6f23ab
+  1 0 a-B - 548a3d25dbf0
+  0 0 a-A - 054250a37db4
+  $ hg bundle --base 'parents(.)' -r . ../secret-bundle.hg
+  1 changesets found
+  $ hg -R ../mu unbundle ../secret-bundle.hg
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  (run 'hg update' to get a working copy)
+  $ hgph -R ../mu
+  10 1 A-secret - 435b5d83910c
+  9 0 a-H - 967b449fbc94
+  8 0 a-F - b740e3e5c05d
+  7 0 a-E - e9f537e46dea
+  6 0 n-B - 145e75495359
+  5 0 n-A - d6bcb4f74035
+  4 0 a-D - b555f63b6063
+  3 0 a-C - 54acac6f23ab
+  2 0 b-A - f54f1bb90ff3
+  1 0 a-B - 548a3d25dbf0
+  0 0 a-A - 054250a37db4
+  $ hg pull ../mu
+  pulling from ../mu
+  searching for changes
+  no changes found
+  $ hgph
+  11 1 A-secret - 435b5d83910c
+  10 0 a-H - 967b449fbc94
+  9 1 a-G - 3e27b6f1eee1
+  8 0 a-F - b740e3e5c05d
+  7 0 a-E - e9f537e46dea
+  6 0 n-B - 145e75495359
+  5 0 n-A - d6bcb4f74035
+  4 0 b-A - f54f1bb90ff3
+  3 0 a-D - b555f63b6063
+  2 0 a-C - 54acac6f23ab
+  1 0 a-B - 548a3d25dbf0
+  0 0 a-A - 054250a37db4
+
+
diff --git a/tests/test-phases.t b/tests/test-phases.t
--- a/tests/test-phases.t
+++ b/tests/test-phases.t
@@ -84,5 +84,51 @@ Even on merge
   3 1 D
   2 1 C
   1 0 B
   0 0 A
 
+Test secret changeset are not pushed
+
+  $ hg init ../push-dest
+  $ hg push ../push-dest -f # force because we push multiple heads
+  pushing to ../push-dest
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 5 changesets with 5 changes to 5 files (+1 heads)
+  $ hglog
+  7 2 merge B' and E
+  6 0 B'
+  5 2 H
+  4 2 E
+  3 0 D
+  2 0 C
+  1 0 B
+  0 0 A
+  $ cd ../push-dest
+  $ hglog
+  4 0 B'
+  3 0 D
+  2 0 C
+  1 0 B
+  0 0 A
+  $ cd ..
+
+Test secret changeset are not pull
+
+  $ hg init pull-dest
+  $ cd pull-dest
+  $ hg pull ../initialrepo
+  pulling from ../initialrepo
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 5 changesets with 5 changes to 5 files (+1 heads)
+  (run 'hg heads' to see heads, 'hg merge' to merge)
+  $ hglog
+  4 0 B'
+  3 0 D
+  2 0 C
+  1 0 B
+  0 0 A


More information about the Mercurial-devel mailing list