Mercurial > hg
comparison mercurial/commands.py @ 38453: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 |
comparison
equal
deleted
inserted
replaced
38452:afb7e15392b9 | 38453:5cdfc20bfd5f |
---|---|
47 patch, | 47 patch, |
48 phases, | 48 phases, |
49 pycompat, | 49 pycompat, |
50 rcutil, | 50 rcutil, |
51 registrar, | 51 registrar, |
52 repair, | |
52 revsetlang, | 53 revsetlang, |
53 rewriteutil, | 54 rewriteutil, |
54 scmutil, | 55 scmutil, |
55 server, | 56 server, |
56 state as statemod, | 57 state as statemod, |
2105 @command( | 2106 @command( |
2106 'graft', | 2107 'graft', |
2107 [('r', 'rev', [], _('revisions to graft'), _('REV')), | 2108 [('r', 'rev', [], _('revisions to graft'), _('REV')), |
2108 ('c', 'continue', False, _('resume interrupted graft')), | 2109 ('c', 'continue', False, _('resume interrupted graft')), |
2109 ('', 'stop', False, _('stop interrupted graft')), | 2110 ('', 'stop', False, _('stop interrupted graft')), |
2111 ('', 'abort', False, _('abort interrupted graft')), | |
2110 ('e', 'edit', False, _('invoke editor on commit messages')), | 2112 ('e', 'edit', False, _('invoke editor on commit messages')), |
2111 ('', 'log', None, _('append graft info to log message')), | 2113 ('', 'log', None, _('append graft info to log message')), |
2112 ('f', 'force', False, _('force graft')), | 2114 ('f', 'force', False, _('force graft')), |
2113 ('D', 'currentdate', False, | 2115 ('D', 'currentdate', False, |
2114 _('record the current date as commit date')), | 2116 _('record the current date as commit date')), |
2202 | 2204 |
2203 if opts.get('stop'): | 2205 if opts.get('stop'): |
2204 if opts.get('continue'): | 2206 if opts.get('continue'): |
2205 raise error.Abort(_("cannot use '--continue' and " | 2207 raise error.Abort(_("cannot use '--continue' and " |
2206 "'--stop' together")) | 2208 "'--stop' together")) |
2209 if opts.get('abort'): | |
2210 raise error.Abort(_("cannot use '--abort' and '--stop' together")) | |
2211 | |
2207 if any((opts.get('edit'), opts.get('log'), opts.get('user'), | 2212 if any((opts.get('edit'), opts.get('log'), opts.get('user'), |
2208 opts.get('date'), opts.get('currentdate'), | 2213 opts.get('date'), opts.get('currentdate'), |
2209 opts.get('currentuser'), opts.get('rev'))): | 2214 opts.get('currentuser'), opts.get('rev'))): |
2210 raise error.Abort(_("cannot specify any other flag with '--stop'")) | 2215 raise error.Abort(_("cannot specify any other flag with '--stop'")) |
2211 return _stopgraft(ui, repo, graftstate) | 2216 return _stopgraft(ui, repo, graftstate) |
2217 elif opts.get('abort'): | |
2218 if opts.get('continue'): | |
2219 raise error.Abort(_("cannot use '--continue' and " | |
2220 "'--abort' together")) | |
2221 if any((opts.get('edit'), opts.get('log'), opts.get('user'), | |
2222 opts.get('date'), opts.get('currentdate'), | |
2223 opts.get('currentuser'), opts.get('rev'))): | |
2224 raise error.Abort(_("cannot specify any other flag with '--abort'")) | |
2225 | |
2226 return _abortgraft(ui, repo, graftstate) | |
2212 elif opts.get('continue'): | 2227 elif opts.get('continue'): |
2213 cont = True | 2228 cont = True |
2214 if revs: | 2229 if revs: |
2215 raise error.Abort(_("can't specify --continue and revisions")) | 2230 raise error.Abort(_("can't specify --continue and revisions")) |
2216 # read in unfinished revisions | 2231 # read in unfinished revisions |
2371 | 2386 |
2372 # remove state when we complete successfully | 2387 # remove state when we complete successfully |
2373 if not opts.get('dry_run'): | 2388 if not opts.get('dry_run'): |
2374 graftstate.delete() | 2389 graftstate.delete() |
2375 | 2390 |
2391 return 0 | |
2392 | |
2393 def _abortgraft(ui, repo, graftstate): | |
2394 """abort the interrupted graft and rollbacks to the state before interrupted | |
2395 graft""" | |
2396 if not graftstate.exists(): | |
2397 raise error.Abort(_("no interrupted graft to abort")) | |
2398 statedata = _readgraftstate(repo, graftstate) | |
2399 newnodes = statedata.get('newnodes') | |
2400 if newnodes is None: | |
2401 # and old graft state which does not have all the data required to abort | |
2402 # the graft | |
2403 raise error.Abort(_("cannot abort using an old graftstate")) | |
2404 | |
2405 # changeset from which graft operation was started | |
2406 startctx = None | |
2407 if len(newnodes) > 0: | |
2408 startctx = repo[newnodes[0]].p1() | |
2409 else: | |
2410 startctx = repo['.'] | |
2411 # whether to strip or not | |
2412 cleanup = False | |
2413 if newnodes: | |
2414 newnodes = [repo[r].rev() for r in newnodes] | |
2415 cleanup = True | |
2416 # checking that none of the newnodes turned public or is public | |
2417 immutable = [c for c in newnodes if not repo[c].mutable()] | |
2418 if immutable: | |
2419 repo.ui.warn(_("cannot clean up public changesets %s\n") | |
2420 % ', '.join(bytes(repo[r]) for r in immutable), | |
2421 hint=_("see 'hg help phases' for details")) | |
2422 cleanup = False | |
2423 | |
2424 # checking that no new nodes are created on top of grafted revs | |
2425 desc = set(repo.changelog.descendants(newnodes)) | |
2426 if desc - set(newnodes): | |
2427 repo.ui.warn(_("new changesets detected on destination " | |
2428 "branch, can't strip\n")) | |
2429 cleanup = False | |
2430 | |
2431 if cleanup: | |
2432 with repo.wlock(), repo.lock(): | |
2433 hg.updaterepo(repo, startctx.node(), True) | |
2434 # stripping the new nodes created | |
2435 strippoints = [c.node() for c in repo.set("roots(%ld)", | |
2436 newnodes)] | |
2437 repair.strip(repo.ui, repo, strippoints, backup=False) | |
2438 | |
2439 if not cleanup: | |
2440 # we don't update to the startnode if we can't strip | |
2441 startctx = repo['.'] | |
2442 hg.updaterepo(repo, startctx.node(), True) | |
2443 | |
2444 ui.status(_("graft aborted\n")) | |
2445 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12]) | |
2446 graftstate.delete() | |
2376 return 0 | 2447 return 0 |
2377 | 2448 |
2378 def _readgraftstate(repo, graftstate): | 2449 def _readgraftstate(repo, graftstate): |
2379 """read the graft state file and return a dict of the data stored in it""" | 2450 """read the graft state file and return a dict of the data stored in it""" |
2380 try: | 2451 try: |