bookmarks: introduce a repo._bookmarks.changectx(mark) method and use it
authorMartin von Zweigbergk <>
Fri, 06 Apr 2018 11:29:30 -0700
changeset 45252 81d35d5d35f92a0a95df9bdb3a9621111fe678dd
parent 45224 a0d71618074f3c90180b4e6615544ab20b2cdda4
child 45253 444ed53f93df02981f9a5d3984c08d87e171d3d9
push id782
push dateTue, 10 Apr 2018 03:41:24 +0000
bookmarks: introduce a repo._bookmarks.changectx(mark) method and use it Many places were doing repo[mark], which usually works, but it's slightly incorrect: if the bookmark has a name that matches a full hex nodeid of another node, then the context for the other node will be returned instead. Also, I'm about to remove support for repo[<namespace thing>] :) Differential Revision:
--- a/mercurial/
+++ b/mercurial/
@@ -114,16 +114,19 @@ class bmstore(dict):
     def _del(self, key):
         self._clean = False
         return dict.__delitem__(self, key)
     def update(self, *others):
         raise error.ProgrammingError("use 'bookmarks.applychanges' instead")
+    def changectx(self, mark):
+        return self._repo[self[mark]]
     def applychanges(self, repo, tr, changes):
         """Apply a list of changes to bookmarks
         bmchanges = tr.changes.get('bookmarks')
         for name, node in changes:
             old = self.get(name)
             if node is None:
@@ -207,18 +210,18 @@ class bmstore(dict):
         cur = self._repo['.'].node()
         if mark in self and not force:
             if target:
                 if self[mark] == target and target == cur:
                     # re-activating a bookmark
                     return []
                 rev = self._repo[target].rev()
                 anc = self._repo.changelog.ancestors([rev])
-                bmctx = self._repo[self[mark]]
-                divs = [self._repo[b].node() for b in self
+                bmctx = self.changectx(mark)
+                divs = [self[b] for b in self
                         if b.split('@', 1)[0] == mark.split('@', 1)[0]]
                 # allow resolving a single divergent bookmark even if moving
                 # the bookmark across branches when a revision is specified
                 # that contains a divergent bookmark
                 if bmctx.rev() not in anc and target in divs:
                     return divergent2delete(self._repo, [target], mark)
@@ -365,21 +368,21 @@ def update(repo, parents, node):
     marks = repo._bookmarks
     active =
     if not active:
         return False
     bmchanges = []
     if marks[active] in parents:
         new = repo[node]
-        divs = [repo[b] for b in marks
+        divs = [marks.changectx(b) for b in marks
                 if b.split('@', 1)[0] == active.split('@', 1)[0]]
         anc = repo.changelog.ancestors([new.rev()])
         deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
-        if validdest(repo, repo[marks[active]], new):
+        if validdest(repo, marks.changectx(active), new):
             bmchanges.append((active, new.node()))
     for bm in divergent2delete(repo, deletefrom, active):
         bmchanges.append((bm, None))
     if bmchanges:
         with repo.lock(), repo.transaction('bookmark') as tr:
             marks.applychanges(repo, tr, bmchanges)