mercurial/bookmarks.py
changeset 37896 04ceb267271a
parent 37895 82a153e6dc4a
child 38539 2f7104984857
--- a/mercurial/bookmarks.py	Sat May 05 11:44:43 2018 +0900
+++ b/mercurial/bookmarks.py	Sat May 05 11:42:42 2018 +0900
@@ -60,6 +60,7 @@
     def __init__(self, repo):
         self._repo = repo
         self._refmap = refmap = {}  # refspec: node
+        self._nodemap = nodemap = {}  # node: sorted([refspec, ...])
         self._clean = True
         self._aclean = True
         nm = repo.changelog.nodemap
@@ -76,6 +77,14 @@
                         if node in nm:
                             refspec = encoding.tolocal(refspec)
                             refmap[refspec] = node
+                            nrefs = nodemap.get(node)
+                            if nrefs is None:
+                                nodemap[node] = [refspec]
+                            else:
+                                nrefs.append(refspec)
+                                if nrefs[-2] > refspec:
+                                    # bookmarks weren't sorted before 4.5
+                                    nrefs.sort()
                     except (TypeError, ValueError):
                         # TypeError:
                         # - bin(...)
@@ -118,6 +127,7 @@
         return self._refmap.keys()
 
     # TODO: maybe rename to allnodes()? but nodes would have to be deduplicated
+    # could be self._nodemap.keys()
     def values(self):
         return self._refmap.values()
 
@@ -132,19 +142,29 @@
 
     def _set(self, mark, node):
         self._clean = False
+        if mark in self._refmap:
+            self._del(mark)
         self._refmap[mark] = node
+        nrefs = self._nodemap.get(node)
+        if nrefs is None:
+            self._nodemap[node] = [mark]
+        else:
+            nrefs.append(mark)
+            nrefs.sort()
 
     def _del(self, mark):
         self._clean = False
-        del self._refmap[mark]
+        node = self._refmap.pop(mark)
+        nrefs = self._nodemap[node]
+        if len(nrefs) == 1:
+            assert nrefs[0] == mark
+            del self._nodemap[node]
+        else:
+            nrefs.remove(mark)
 
     def names(self, node):
         """Return a sorted list of bookmarks pointing to the specified node"""
-        marks = []
-        for m, n in self._refmap.iteritems():
-            if n == node:
-                marks.append(m)
-        return sorted(marks)
+        return self._nodemap.get(node, [])
 
     def changectx(self, mark):
         node = self._refmap[mark]