--- a/hgext3rd/evolve/rewind.py Sat Jun 16 23:32:22 2018 +0200
+++ b/hgext3rd/evolve/rewind.py Sun Jun 17 00:15:18 2018 +0200
@@ -1,10 +1,12 @@
from __future__ import absolute_import
+import collections
import hashlib
from mercurial import (
error,
obsolete,
+ obsutil,
scmutil,
)
@@ -24,10 +26,19 @@
@eh.command(
'^rewind',
[('', 'to', [], _("rewind to these revision")),
+ ('', 'as-divergence', None, _("preserve current latest successors")),
],
_(''))
def rewind(ui, repo, **opts):
"""rewind stacks of changeset to a previous content
+
+ This command can be used to restore stacks of changesets to an obsolete
+ state, creating identical identical copies.
+
+ The latest successors the obsolete changesets will be superseed by these
+ new copies. This behavior can be disabled using `--as-divergence`, the
+ current latest successors won't be affected and content-divergence will
+ appears between them and the restored version of the obsolete changesets.
"""
unfi = repo.unfiltered()
@@ -36,11 +47,35 @@
rewinded = scmutil.revrange(repo, opts.get('to'))
+ successorsmap = collections.defaultdict(set)
+ rewindmap = {}
+ sscache = {}
with repo.wlock(), repo.lock():
+ if not opts['as_divergence']:
+ for rev in rewinded:
+ ctx = unfi[rev]
+ ssets = obsutil.successorssets(repo, ctx.node(), sscache)
+ if 1 < len(ssets):
+ msg = _('rewind confused by divergence on %s') % ctx
+ hint = _('solve divergence first or use "--as-divergence"')
+ raise error.Abort(msg, hint=hint)
+ if ssets and ssets[0]:
+ for succ in ssets[0]:
+ successorsmap[succ].add(ctx.node())
+
# Check that we can rewind these changesets
with repo.transaction('rewind'):
for rev in rewinded:
- _revive_revision(unfi, rev)
+ ctx = unfi[rev]
+ rewindmap[ctx.node()] = _revive_revision(unfi, rev)
+
+ relationships = []
+ cl = unfi.changelog
+ for (source, dest) in sorted(successorsmap.items()):
+ newdest = [rewindmap[d] for d in sorted(dest, key=cl.rev)]
+ rel = (unfi[source], tuple(unfi[d] for d in newdest))
+ relationships.append(rel)
+ obsolete.createmarkers(unfi, relationships, operation='rewind')
repo.ui.status(_('rewinded to %d changesets\n') % len(rewinded))
def _revive_revision(unfi, rev):