mercurial/scmutil.py
changeset 34368 f61f5af5ed31
parent 34350 255c761a52db
parent 33686 2f427b57bf90
child 34457 7757cc48b766
--- a/mercurial/scmutil.py	Fri Sep 22 22:45:02 2017 +0900
+++ b/mercurial/scmutil.py	Sat Sep 30 07:52:48 2017 -0700
@@ -594,41 +594,59 @@
     def __contains__(self, node):
         return self._revcontains(self._torev(node))
 
-def cleanupnodes(repo, mapping, operation):
+def cleanupnodes(repo, replacements, operation, moves=None):
     """do common cleanups when old nodes are replaced by new nodes
 
     That includes writing obsmarkers or stripping nodes, and moving bookmarks.
     (we might also want to move working directory parent in the future)
 
-    mapping is {oldnode: [newnode]} or a iterable of nodes if they do not have
-    replacements. operation is a string, like "rebase".
+    By default, bookmark moves are calculated automatically from 'replacements',
+    but 'moves' can be used to override that. Also, 'moves' may include
+    additional bookmark moves that should not have associated obsmarkers.
+
+    replacements is {oldnode: [newnode]} or a iterable of nodes if they do not
+    have replacements. operation is a string, like "rebase".
     """
-    if not util.safehasattr(mapping, 'items'):
-        mapping = {n: () for n in mapping}
+    if not replacements and not moves:
+        return
+
+    # translate mapping's other forms
+    if not util.safehasattr(replacements, 'items'):
+        replacements = {n: () for n in replacements}
+
+    # Calculate bookmark movements
+    if moves is None:
+        moves = {}
+    # Unfiltered repo is needed since nodes in replacements might be hidden.
+    unfi = repo.unfiltered()
+    for oldnode, newnodes in replacements.items():
+        if oldnode in moves:
+            continue
+        if len(newnodes) > 1:
+            # usually a split, take the one with biggest rev number
+            newnode = next(unfi.set('max(%ln)', newnodes)).node()
+        elif len(newnodes) == 0:
+            # move bookmark backwards
+            roots = list(unfi.set('max((::%n) - %ln)', oldnode,
+                                  list(replacements)))
+            if roots:
+                newnode = roots[0].node()
+            else:
+                newnode = nullid
+        else:
+            newnode = newnodes[0]
+        moves[oldnode] = newnode
 
     with repo.transaction('cleanup') as tr:
         # Move bookmarks
         bmarks = repo._bookmarks
         bmarkchanges = []
-        allnewnodes = [n for ns in mapping.values() for n in ns]
-        for oldnode, newnodes in mapping.items():
+        allnewnodes = [n for ns in replacements.values() for n in ns]
+        for oldnode, newnode in moves.items():
             oldbmarks = repo.nodebookmarks(oldnode)
             if not oldbmarks:
                 continue
             from . import bookmarks # avoid import cycle
-            if len(newnodes) > 1:
-                # usually a split, take the one with biggest rev number
-                newnode = next(repo.set('max(%ln)', newnodes)).node()
-            elif len(newnodes) == 0:
-                # move bookmark backwards
-                roots = list(repo.set('max((::%n) - %ln)', oldnode,
-                                      list(mapping)))
-                if roots:
-                    newnode = roots[0].node()
-                else:
-                    newnode = nullid
-            else:
-                newnode = newnodes[0]
             repo.ui.debug('moving bookmarks %r from %s to %s\n' %
                           (oldbmarks, hex(oldnode), hex(newnode)))
             # Delete divergent bookmarks being parents of related newnodes
@@ -651,18 +669,19 @@
             # Also sort the node in topology order, that might be useful for
             # some obsstore logic.
             # NOTE: the filtering and sorting might belong to createmarkers.
-            # Unfiltered repo is needed since nodes in mapping might be hidden.
-            unfi = repo.unfiltered()
             isobs = unfi.obsstore.successors.__contains__
             torev = unfi.changelog.rev
             sortfunc = lambda ns: torev(ns[0])
             rels = [(unfi[n], tuple(unfi[m] for m in s))
-                    for n, s in sorted(mapping.items(), key=sortfunc)
+                    for n, s in sorted(replacements.items(), key=sortfunc)
                     if s or not isobs(n)]
-            obsolete.createmarkers(repo, rels, operation=operation)
+            if rels:
+                obsolete.createmarkers(repo, rels, operation=operation)
         else:
             from . import repair # avoid import cycle
-            repair.delayedstrip(repo.ui, repo, list(mapping), operation)
+            tostrip = list(replacements)
+            if tostrip:
+                repair.delayedstrip(repo.ui, repo, tostrip, operation)
 
 def addremove(repo, matcher, prefix, opts=None, dry_run=None, similarity=None):
     if opts is None: