D728: rebase: move working parent movement logic to scmutil.cleanupnodes
quark (Jun Wu)
phabricator at mercurial-scm.org
Mon Sep 18 20:21:04 UTC 2017
quark created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.
REVISION SUMMARY
Moving working parent is a common requirement that could be shared in other
places. This patch makes it possible.
REPOSITORY
rHG Mercurial
REVISION DETAIL
https://phab.mercurial-scm.org/D728
AFFECTED FILES
hgext/rebase.py
mercurial/scmutil.py
tests/test-rebase-conflicts.t
CHANGE DETAILS
diff --git a/tests/test-rebase-conflicts.t b/tests/test-rebase-conflicts.t
--- a/tests/test-rebase-conflicts.t
+++ b/tests/test-rebase-conflicts.t
@@ -283,7 +283,6 @@
updating the branch cache
rebased as 2a7f09cac94c
rebase merging completed
- update back to initial working directory parent
resolving manifests
branchmerge: False, force: False, partial: False
ancestor: 2a7f09cac94c, local: 2a7f09cac94c+, remote: d79e2059b5c0
diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py
--- a/mercurial/scmutil.py
+++ b/mercurial/scmutil.py
@@ -579,11 +579,11 @@
def __contains__(self, node):
return self._revcontains(self._torev(node))
-def cleanupnodes(repo, mapping, operation):
+def cleanupnodes(repo, mapping, operation, workingparent=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)
+ That includes writing obsmarkers or stripping nodes, moving bookmarks, and
+ optionally moving working parent.
mapping is {oldnode: {'new': [newnode], 'move': newnode}}, where 'new'
decide obsolete markers, and 'move' decide bookmark move, which could be
@@ -596,6 +596,11 @@
- {oldnode: [newnode]}, equal to {oldnode: {'new': [newnode]}}
- {oldnode}, equal to {oldnode: []}
+
+ If workingparent is not None, it's the desired node that needs to update
+ to. The node may be adjusted using the bookmark movement logic. Uncommitted
+ changes will be discarded, the caller is responsible for checking the
+ cleanness of working copy.
"""
if not mapping:
return
@@ -606,13 +611,17 @@
elif all('new' not in v and 'move' not in v for v in mapping.values()):
mapping = {n: {'new': newnodes} for n, newnodes in mapping.items()}
+ bmarkwp = '' # an invalid bookmark name to indicate working parent
+
with repo.transaction('cleanup') as tr:
# Move bookmarks
bmarks = repo._bookmarks
bmarkchanges = []
allnewnodes = [n for v in mapping.values() for n in v.get('new', ())]
for oldnode, value in mapping.items():
oldbmarks = repo.nodebookmarks(oldnode)
+ if workingparent is not None and oldnode == workingparent:
+ oldbmarks = oldbmarks + [bmarkwp]
if not oldbmarks:
continue
newnode = value.get('move')
@@ -641,13 +650,22 @@
allnewnodes, newnode, oldnode)
deletenodes = _containsnode(repo, deleterevs)
for name in oldbmarks:
+ if name is bmarkwp: # working parent adjustment
+ workingparent = newnode
+ continue
bmarkchanges.append((name, newnode))
for b in bookmarks.divergent2delete(repo, deletenodes, name):
bmarkchanges.append((b, None))
if bmarkchanges:
bmarks.applychanges(repo, tr, bmarkchanges)
+ # Working parent movement
+ if workingparent and [workingparent] != [r.node()
+ for r in repo[None].parents()]:
+ from . import hg # avoid import cycle
+ hg.updaterepo(repo, workingparent, False)
+
# Obsolete or strip nodes
if obsolete.isenabled(repo, obsolete.createmarkersopt):
# If a node is already obsoleted, and we want to obsolete it
diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -34,7 +34,6 @@
dirstateguard,
error,
extensions,
- hg,
lock,
merge as mergemod,
mergeutil,
@@ -533,22 +532,12 @@
if 'qtip' in repo.tags():
updatemq(repo, self.state, self.skipped, **opts)
- # restore original working directory
- # (we do this before stripping)
- newwd = self.state.get(self.originalwd, self.originalwd)
- if newwd < 0:
- # original directory is a parent of rebase set root or ignored
- newwd = self.originalwd
- if newwd not in [c.rev() for c in repo[None].parents()]:
- ui.note(_("update back to initial working directory parent\n"))
- hg.updaterepo(repo, newwd, False)
-
collapsedas = None
if not self.keepf:
if self.collapsef:
collapsedas = newnode
clearrebased(ui, repo, self.destmap, self.state, self.skipped,
- collapsedas, self.keepf)
+ collapsedas, self.keepf, self.originalwd)
clearstatus(repo)
clearcollapsemsg(repo)
@@ -1513,14 +1502,16 @@
return originalwd, destmap, state
def clearrebased(ui, repo, destmap, state, skipped, collapsedas=None,
- keepf=False):
+ keepf=False, originalwd=None):
"""dispose of rebased revision at the end of the rebase
If `collapsedas` is not None, the rebase was a collapse whose result if the
`collapsedas` node.
If `keepf` is not True, the rebase has --keep set and no nodes should be
removed (but bookmarks still need to be moved).
+
+ If `originalwd` is not None, working parent will be moved.
"""
tonode = repo.changelog.node
mapping = {}
@@ -1535,7 +1526,9 @@
succs = (newnode,)
value['new'] = succs
mapping[tonode(rev)] = value
- scmutil.cleanupnodes(repo, mapping, 'rebase')
+ if originalwd is not None:
+ originalwd = repo[originalwd].node()
+ scmutil.cleanupnodes(repo, mapping, 'rebase', workingparent=originalwd)
def pullrebase(orig, ui, repo, *args, **opts):
'Call rebase after pull if the latter has been invoked with --rebase'
To: quark, #hg-reviewers
Cc: mercurial-devel
More information about the Mercurial-devel
mailing list