push: prevent moving phases outside of the pushed subset stable
authorPierre-Yves David <pierre-yves.david@ens-lyon.org>
Fri, 20 Jan 2012 21:21:13 +0100
branchstable
changeset 15956 5653f2d166ea
parent 15955 5a14f48d6b9a
child 15957 12a1c9e92d66
push: prevent moving phases outside of the pushed subset
mercurial/localrepo.py
tests/test-hook.t
tests/test-phases-exchange.t
--- a/mercurial/localrepo.py	Fri Jan 20 19:41:18 2012 +0100
+++ b/mercurial/localrepo.py	Fri Jan 20 21:21:13 2012 +0100
@@ -1554,21 +1554,29 @@
                 clend = len(self.changelog)
                 added = [self.changelog.node(r) for r in xrange(clstart, clend)]
 
+            # compute target subset
+            if heads is None:
+                # We pulled every thing possible
+                # sync on everything common
+                subset = common + added
+            else:
+                # We pulled a specific subset
+                # sync on this subset
+                subset = heads
 
             # Get remote phases data from remote
             remotephases = remote.listkeys('phases')
             publishing = bool(remotephases.get('publishing', False))
             if remotephases and not publishing:
                 # remote is new and unpublishing
-                subset = common + added
                 pheads, _dr = phases.analyzeremotephases(self, subset,
                                                          remotephases)
                 phases.advanceboundary(self, phases.public, pheads)
-                phases.advanceboundary(self, phases.draft, common + added)
+                phases.advanceboundary(self, phases.draft, subset)
             else:
                 # Remote is old or publishing all common changesets
                 # should be seen as public
-                phases.advanceboundary(self, phases.public, common + added)
+                phases.advanceboundary(self, phases.public, subset)
         finally:
             lock.release()
 
@@ -1652,11 +1660,35 @@
                         # we return an integer indicating remote head count change
                         ret = remote.addchangegroup(cg, 'push', self.url())
 
-                cheads = outgoing.commonheads[:]
                 if ret:
-                    # push succeed, synchonize common + pushed
-                    # this is a no-op if there was nothing to push
-                    cheads += outgoing.missingheads
+                    # push succeed, synchonize target of the push
+                    cheads = outgoing.missingheads
+                elif revs is None:
+                    # All out push fails. synchronize all common
+                    cheads = outgoing.commonheads
+                else:
+                    # I want cheads = heads(::missingheads and ::commonheads)
+                    # (missingheads is revs with secret changeset filtered out)
+                    #
+                    # This can be expressed as:
+                    #     cheads = ( (missingheads and ::commonheads)
+                    #              + (commonheads and ::missingheads))"
+                    #              )
+                    #
+                    # while trying to push we already computed the following:
+                    #     common = (::commonheads)
+                    #     missing = ((commonheads::missingheads) - commonheads)
+                    #
+                    # We can pick:
+                    # * missingheads part of comon (::commonheads)
+                    common = set(outgoing.common)
+                    cheads = [n for node in revs if n in common]
+                    # and 
+                    # * commonheads parents on missing
+                    rvset = repo.revset('%ln and parents(roots(%ln))',
+                                        outgoing.commonheads,
+                                        outgoing.missing)
+                    cheads.extend(c.node() for c in rvset)
                 # even when we don't push, exchanging phase data is useful
                 remotephases = remote.listkeys('phases')
                 if not remotephases: # old server or public only repo
--- a/tests/test-hook.t	Fri Jan 20 19:41:18 2012 +0100
+++ b/tests/test-hook.t	Fri Jan 20 21:21:13 2012 +0100
@@ -179,7 +179,6 @@
   pushing to ../a
   searching for changes
   no changes found
-  pushkey hook: HG_KEY=07f3376c1e655977439df2a814e3cc14b27abac2 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1 
   exporting bookmark foo
   pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1 
   $ cd ../a
@@ -193,7 +192,7 @@
   pulling from ../a
   listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'} 
   no changes found
-  listkeys hook: HG_NAMESPACE=phases HG_VALUES={'539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10': '1', 'publishing': 'True'} 
+  listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'} 
   listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'} 
   importing bookmark bar
   $ cd ../a
@@ -207,7 +206,7 @@
   pushing to ../a
   searching for changes
   no changes found
-  listkeys hook: HG_NAMESPACE=phases HG_VALUES={'539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10': '1', 'publishing': 'True'} 
+  listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'} 
   listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'} 
   listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'} 
   exporting bookmark baz
--- a/tests/test-phases-exchange.t	Fri Jan 20 19:41:18 2012 +0100
+++ b/tests/test-phases-exchange.t	Fri Jan 20 21:21:13 2012 +0100
@@ -238,10 +238,10 @@
   adding file changes
   added 1 changesets with 1 changes to 1 files
   (run 'hg update' to get a working copy)
-  $ hgph
+  $ hgph # f54f1bb90ff3 stay draft, not ancestor of -r
   o  4 public a-D - b555f63b6063
   |
-  | o  3 public b-A - f54f1bb90ff3
+  | o  3 draft b-A - f54f1bb90ff3
   | |
   o |  2 public a-C - 54acac6f23ab
   |/
@@ -262,7 +262,7 @@
   |
   | o  4 public a-D - b555f63b6063
   | |
-  o |  3 public b-A - f54f1bb90ff3
+  o |  3 draft b-A - f54f1bb90ff3
   | |
   | o  2 public a-C - 54acac6f23ab
   |/
@@ -288,7 +288,7 @@
   | |
   | o  3 public a-C - 54acac6f23ab
   | |
-  o |  2 public b-A - f54f1bb90ff3
+  o |  2 draft b-A - f54f1bb90ff3
   |/
   o  1 public a-B - 548a3d25dbf0
   |
@@ -497,20 +497,21 @@
   
 
   $ cd ../mu
-  $ hgph # d6bcb4f74035 and 145e75495359 changed because common is too smart
+  $ hgph # again f54f1bb90ff3, d6bcb4f74035 and 145e75495359 stay draft,
+  >      # not ancestor of -r
   o  8 draft a-F - b740e3e5c05d
   |
   o  7 draft a-E - e9f537e46dea
   |
-  | o  6 public n-B - 145e75495359
+  | o  6 draft n-B - 145e75495359
   | |
-  | o  5 public n-A - d6bcb4f74035
+  | o  5 draft n-A - d6bcb4f74035
   | |
   o |  4 public a-D - b555f63b6063
   | |
   o |  3 public a-C - 54acac6f23ab
   | |
-  | o  2 public b-A - f54f1bb90ff3
+  | o  2 draft b-A - f54f1bb90ff3
   |/
   o  1 public a-B - 548a3d25dbf0
   |
@@ -526,20 +527,21 @@
   adding manifests
   adding file changes
   added 2 changesets with 2 changes to 2 files
-  $ hgph # again d6bcb4f74035 and 145e75495359 changed because common is too smart
+  $ hgph # again f54f1bb90ff3, d6bcb4f74035 and 145e75495359 stay draft,
+  >      # not ancestor of -r
   o  8 public a-F - b740e3e5c05d
   |
   o  7 public a-E - e9f537e46dea
   |
-  | o  6 public n-B - 145e75495359
+  | o  6 draft n-B - 145e75495359
   | |
-  | o  5 public n-A - d6bcb4f74035
+  | o  5 draft n-A - d6bcb4f74035
   | |
   o |  4 public a-D - b555f63b6063
   | |
   o |  3 public a-C - 54acac6f23ab
   | |
-  | o  2 public b-A - f54f1bb90ff3
+  | o  2 draft b-A - f54f1bb90ff3
   |/
   o  1 public a-B - 548a3d25dbf0
   |
@@ -569,7 +571,7 @@
   o  0 public a-A - 054250a37db4
   
   $ cd ../alpha
-  $ hgph # e9f537e46dea and b740e3e5c05d should have been sync to 0
+  $ hgph
   @  10 draft a-H - 967b449fbc94
   |
   | o  9 draft a-G - 3e27b6f1eee1
@@ -627,14 +629,14 @@
   
   $ cd ../mu
   $ hgph # d6bcb4f74035 should have changed phase
-  >      # again d6bcb4f74035 and 145e75495359 changed because common was too smart
+  >      # 145e75495359 is still draft. not ancestor of -r
   o  9 draft a-H - 967b449fbc94
   |
   | o  8 public a-F - b740e3e5c05d
   | |
   | o  7 public a-E - e9f537e46dea
   | |
-  +---o  6 public n-B - 145e75495359
+  +---o  6 draft n-B - 145e75495359
   | |
   o |  5 public n-A - d6bcb4f74035
   | |