diff mercurial/bookmarks.py @ 17551:a7b3fdaf768d

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.
author Pierre-Yves David <pierre-yves.david@logilab.fr>
date Sun, 26 Aug 2012 01:28:22 +0200
parents fc530080013b
children b83c18204c36
line wrap: on
line diff
--- 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