bookmark: take successors into account when updating (issue3561)
authorPierre-Yves David <pierre-yves.david@logilab.fr>
Sun, 26 Aug 2012 01:28:22 +0200
changeset 17551 a7b3fdaf768d
parent 17550 fc530080013b
child 17552 453d790fe089
bookmark: take successors into account when updating (issue3561) When we rewrite a bookmarked changeset, we want to update the bookmark on its successors. But the successors are not descendants of its precursor (by definition). This changeset alters the bookmarks logic to update bookmark location if the newer location is a successor of the old one[1]. note: valid destinations are in fact any kind of successors of any kind of descendants (recursively.) This changeset requires the enabling of the obsolete feature in some bookmark tests.
mercurial/bookmarks.py
tests/test-bookmarks-pushpull.t
--- a/mercurial/bookmarks.py	Sun Aug 26 00:28:56 2012 +0200
+++ b/mercurial/bookmarks.py	Sun Aug 26 01:28:22 2012 +0200
@@ -7,7 +7,7 @@
 
 from mercurial.i18n import _
 from mercurial.node import hex
-from mercurial import encoding, error, util
+from mercurial import encoding, error, util, obsolete, phases
 import errno, os
 
 def valid(mark):
@@ -255,4 +255,30 @@
 
 def validdest(repo, old, new):
     """Is the new bookmark destination a valid update from the old one"""
-    return new in old.descendants()
+    if old == new:
+        # Old == new -> nothing to update.
+        validdests = ()
+    elif not old:
+        # old is nullrev, anything is valid.
+        # (new != nullrev has been excluded by the previous check)
+        validdests = (new,)
+    elif repo.obsstore:
+        # We only need this complicated logic if there is obsolescence
+        # XXX will probably deserve an optimised rset.
+
+        validdests = set([old])
+        plen = -1
+        # compute the whole set of successors or descendants
+        while len(validdests) != plen:
+            plen = len(validdests)
+            succs = set(c.node() for c in validdests)
+            for c in validdests:
+                if c.phase() > phases.public:
+                    # obsolescence marker does not apply to public changeset
+                    succs.update(obsolete.anysuccessors(repo.obsstore,
+                                                        c.node()))
+            validdests = set(repo.set('%ln::', succs))
+        validdests.remove(old)
+    else:
+        validdests = old.descendants()
+    return new in validdests
--- a/tests/test-bookmarks-pushpull.t	Sun Aug 26 00:28:56 2012 +0200
+++ b/tests/test-bookmarks-pushpull.t	Sun Aug 26 01:28:22 2012 +0200
@@ -1,5 +1,16 @@
   $ "$TESTDIR/hghave" serve || exit 80
 
+  $ cat << EOF >> $HGRCPATH
+  > [phases]
+  > publish=False
+  > [extensions]
+  > EOF
+  $ cat > obs.py << EOF
+  > import mercurial.obsolete
+  > mercurial.obsolete._enabled = True
+  > EOF
+  $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
+
 initialize
 
   $ hg init a
@@ -40,6 +51,7 @@
   bookmarks	
   phases	
   namespaces	
+  obsolete	
   $ hg debugpushkey ../a bookmarks
   Y	4e3505fd95835d721066b76e75dbb8cc554d7f77
   X	4e3505fd95835d721066b76e75dbb8cc554d7f77
@@ -198,6 +210,41 @@
      Y                         3:f6fc62dde3c0
      Z                         1:0d2164f0ce0d
 
+
+Unrelated marker does not alter the decision
+
+  $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+  $ hg push http://localhost:$HGPORT2/
+  pushing to http://localhost:$HGPORT2/
+  searching for changes
+  abort: push creates new remote head 4efff6d98829!
+  (did you forget to merge? use push -f to force)
+  [255]
+  $ hg -R ../a book
+   * X                         1:0d2164f0ce0d
+     Y                         3:f6fc62dde3c0
+     Z                         1:0d2164f0ce0d
+
+Update to a successor works
+
+  $ hg id --debug -r 3
+  f6fc62dde3c0771e29704af56ba4d8af77abcc2f
+  $ hg id --debug -r 4
+  4efff6d98829d9c824c621afd6e3f01865f5439f tip Y
+  $ hg debugobsolete f6fc62dde3c0771e29704af56ba4d8af77abcc2f 4efff6d98829d9c824c621afd6e3f01865f5439f
+  $ hg push http://localhost:$HGPORT2/
+  pushing to http://localhost:$HGPORT2/
+  searching for changes
+  remote: adding changesets
+  remote: adding manifests
+  remote: adding file changes
+  remote: added 1 changesets with 1 changes to 1 files (+1 heads)
+  updating bookmark Y
+  $ hg -R ../a book
+   * X                         1:0d2164f0ce0d
+     Y                         4:4efff6d98829
+     Z                         1:0d2164f0ce0d
+
 hgweb
 
   $ cat <<EOF > .hg/hgrc
@@ -214,6 +261,7 @@
   bookmarks	
   phases	
   namespaces	
+  obsolete	
   $ hg debugpushkey http://localhost:$HGPORT/ bookmarks
   Y	4efff6d98829d9c824c621afd6e3f01865f5439f
   foobar	9b140be1080824d768c5a4691a564088eede71f9
@@ -251,12 +299,12 @@
   adding changesets
   adding manifests
   adding file changes
-  added 5 changesets with 5 changes to 3 files (+3 heads)
+  added 4 changesets with 4 changes to 3 files (+2 heads)
   updating to branch default
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg -R cloned-bookmarks bookmarks
      X                         1:9b140be10808
-     Y                         4:4efff6d98829
+     Y                         3:4efff6d98829
      Z                         2:0d2164f0ce0d
      foo                       -1:000000000000
      foobar                    1:9b140be10808
@@ -270,7 +318,7 @@
   adding changesets
   adding manifests
   adding file changes
-  added 5 changesets with 5 changes to 3 files (+3 heads)
+  added 4 changesets with 4 changes to 3 files (+2 heads)
   updating to branch default
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ cd addmarks