--- a/mercurial/scmutil.py Sun Jun 25 10:38:45 2017 -0700
+++ b/mercurial/scmutil.py Sun Jun 25 13:31:56 2017 -0700
@@ -16,6 +16,8 @@
from .i18n import _
from .node import (
+ hex,
+ nullid,
wdirid,
wdirrev,
)
@@ -24,6 +26,7 @@
encoding,
error,
match as matchmod,
+ obsolete,
pathutil,
phases,
pycompat,
@@ -561,6 +564,68 @@
return fullorigpath + ".orig"
+def cleanupnodes(repo, mapping, operation):
+ """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".
+ """
+ if not util.safehasattr(mapping, 'items'):
+ mapping = {n: () for n in mapping}
+
+ with repo.transaction('cleanup') as tr:
+ # Move bookmarks
+ bmarks = repo._bookmarks
+ bmarkchanged = False
+ for oldnode, newnodes in mapping.items():
+ oldbmarks = repo.nodebookmarks(oldnode)
+ if not oldbmarks:
+ continue
+ bmarkchanged = True
+ if len(newnodes) > 1:
+ heads = list(repo.set('heads(%ln)', newnodes))
+ if len(heads) != 1:
+ raise error.ProgrammingError(
+ 'cannot figure out bookmark movement')
+ newnode = heads[0].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)))
+ for name in oldbmarks:
+ bmarks[name] = newnode
+ if bmarkchanged:
+ bmarks.recordchange(tr)
+
+ # Obsolete or strip nodes
+ if obsolete.isenabled(repo, obsolete.createmarkersopt):
+ # If a node is already obsoleted, and we want to obsolete it
+ # without a successor, skip that obssolete request since it's
+ # unnecessary. That's the "if s or not isobs(n)" check below.
+ # Also sort the node in topology order, that might be useful for
+ # some obsstore logic.
+ # NOTE: the filtering and sorting might belong to createmarkers.
+ isobs = repo.obsstore.successors.__contains__
+ sortfunc = lambda ns: repo.changelog.rev(ns[0])
+ rels = [(repo[n], (repo[m] for m in s))
+ for n, s in sorted(mapping.items(), key=sortfunc)
+ if s or not isobs(n)]
+ obsolete.createmarkers(repo, rels, operation=operation)
+ else:
+ from . import repair # avoid import cycle
+ repair.delayedstrip(repo.ui, repo, list(mapping), operation)
+
def addremove(repo, matcher, prefix, opts=None, dry_run=None, similarity=None):
if opts is None:
opts = {}