Mercurial > public > mercurial-scm > hg-stable
diff mercurial/commands.py @ 38458:5cdfc20bfd5f
graft: introduce --abort flag to abort interrupted graft
This patch introduces a new --abort flag to `hg graft` command which aborts an
interrupted graft and rollbacks to the state before graft.
The behavior when some of grafted changeset get's published while interrupted
graft or we have new descendants on grafted changesets is same as that of rebase
which is warn the user, don't strip and abort the abort the graft.
Tests are added for the new flag.
.. feature::
`hg graft` now has a `--abort` flag which aborts the interrupted graft and
rollbacks to state before the graft.
Differential Revision: https://phab.mercurial-scm.org/D3754
author | Pulkit Goyal <7895pulkit@gmail.com> |
---|---|
date | Fri, 25 May 2018 18:16:38 +0530 |
parents | afb7e15392b9 |
children | 854c2ccc800e |
line wrap: on
line diff
--- a/mercurial/commands.py Fri Jun 15 02:46:34 2018 +0530 +++ b/mercurial/commands.py Fri May 25 18:16:38 2018 +0530 @@ -49,6 +49,7 @@ pycompat, rcutil, registrar, + repair, revsetlang, rewriteutil, scmutil, @@ -2107,6 +2108,7 @@ [('r', 'rev', [], _('revisions to graft'), _('REV')), ('c', 'continue', False, _('resume interrupted graft')), ('', 'stop', False, _('stop interrupted graft')), + ('', 'abort', False, _('abort interrupted graft')), ('e', 'edit', False, _('invoke editor on commit messages')), ('', 'log', None, _('append graft info to log message')), ('f', 'force', False, _('force graft')), @@ -2204,11 +2206,24 @@ if opts.get('continue'): raise error.Abort(_("cannot use '--continue' and " "'--stop' together")) + if opts.get('abort'): + raise error.Abort(_("cannot use '--abort' and '--stop' together")) + if any((opts.get('edit'), opts.get('log'), opts.get('user'), opts.get('date'), opts.get('currentdate'), opts.get('currentuser'), opts.get('rev'))): raise error.Abort(_("cannot specify any other flag with '--stop'")) return _stopgraft(ui, repo, graftstate) + elif opts.get('abort'): + if opts.get('continue'): + raise error.Abort(_("cannot use '--continue' and " + "'--abort' together")) + if any((opts.get('edit'), opts.get('log'), opts.get('user'), + opts.get('date'), opts.get('currentdate'), + opts.get('currentuser'), opts.get('rev'))): + raise error.Abort(_("cannot specify any other flag with '--abort'")) + + return _abortgraft(ui, repo, graftstate) elif opts.get('continue'): cont = True if revs: @@ -2375,6 +2390,62 @@ return 0 +def _abortgraft(ui, repo, graftstate): + """abort the interrupted graft and rollbacks to the state before interrupted + graft""" + if not graftstate.exists(): + raise error.Abort(_("no interrupted graft to abort")) + statedata = _readgraftstate(repo, graftstate) + newnodes = statedata.get('newnodes') + if newnodes is None: + # and old graft state which does not have all the data required to abort + # the graft + raise error.Abort(_("cannot abort using an old graftstate")) + + # changeset from which graft operation was started + startctx = None + if len(newnodes) > 0: + startctx = repo[newnodes[0]].p1() + else: + startctx = repo['.'] + # whether to strip or not + cleanup = False + if newnodes: + newnodes = [repo[r].rev() for r in newnodes] + cleanup = True + # checking that none of the newnodes turned public or is public + immutable = [c for c in newnodes if not repo[c].mutable()] + if immutable: + repo.ui.warn(_("cannot clean up public changesets %s\n") + % ', '.join(bytes(repo[r]) for r in immutable), + hint=_("see 'hg help phases' for details")) + cleanup = False + + # checking that no new nodes are created on top of grafted revs + desc = set(repo.changelog.descendants(newnodes)) + if desc - set(newnodes): + repo.ui.warn(_("new changesets detected on destination " + "branch, can't strip\n")) + cleanup = False + + if cleanup: + with repo.wlock(), repo.lock(): + hg.updaterepo(repo, startctx.node(), True) + # stripping the new nodes created + strippoints = [c.node() for c in repo.set("roots(%ld)", + newnodes)] + repair.strip(repo.ui, repo, strippoints, backup=False) + + if not cleanup: + # we don't update to the startnode if we can't strip + startctx = repo['.'] + hg.updaterepo(repo, startctx.node(), True) + + ui.status(_("graft aborted\n")) + ui.status(_("working directory is now at %s\n") % startctx.hex()[:12]) + graftstate.delete() + return 0 + def _readgraftstate(repo, graftstate): """read the graft state file and return a dict of the data stored in it""" try: