diff --git a/hgext/amend.py b/hgext/amend.py --- a/hgext/amend.py +++ b/hgext/amend.py @@ -16,7 +16,12 @@ from mercurial import ( cmdutil, commands, + error, + obsolete, registrar, + rewriteutil, + scmutil, + state as statemod, ) # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for @@ -48,6 +53,12 @@ ), (b's', b'secret', None, _(b'use the secret phase for committing')), (b'n', b'note', b'', _(b'store a note on the amend')), + ( + b'r', + b'rev', + b'', + _(b'amend into the specified revision (EXPERIMENTAL)'), + ), ] + cmdutil.walkopts + cmdutil.commitopts @@ -67,8 +78,69 @@ """ cmdutil.check_note_size(opts) - with repo.wlock(), repo.lock(): - if not opts.get('logfile'): - opts['message'] = opts.get('message') or repo[b'.'].description() - opts['amend'] = True - return commands._docommit(ui, repo, *pats, **opts) + if opts.get('rev'): + return _amend_rev(ui, repo, *pats, **opts) + else: + with repo.wlock(), repo.lock(): + if not opts.get('logfile'): + opts['message'] = ( + opts.get('message') or repo[b'.'].description() + ) + opts['amend'] = True + return commands._docommit(ui, repo, *pats, **opts) + + +def _amend_rev(ui, repo, *pats, **opts): + # TODO: Add support for most of these + cmdutil.check_incompatible_arguments( + opts, + 'rev', + [ + 'addremove', + 'edit', + 'interactive', + 'close_branch', + 'secret', + 'note', + 'include', + 'exclude', + 'message', + 'logfile', + 'date', + 'user', + 'currentdate', + 'currentuser', + ], + ) + + if not obsolete.isenabled(repo, obsolete.createmarkersopt): + raise error.StateError(_(b'--rev requires evolution')) + + with repo.wlock(), repo.lock(), repo.transaction(b'amend'): + cmdutil.checkunfinished(repo) + target_ctx = scmutil.revsingle(repo, opts['rev']) + to_rewrite = repo.revs(b'%d::.', target_ctx.rev()) + rewriteutil.precheck(repo, to_rewrite, b'amend') + state = statemod.cmdstate(repo, b'amend-state') + ret = commands._docommit( + ui, repo, message=b'temporary commit for "amend --rev"' + ) + if ret: + return ret + temp_ctx = repo[b'tip'] + state.save(1, {b"tmp_node": temp_ctx.node()}) + + +def _abort_amend_rev(ui, repo): + state = statemod.cmdstate(repo, b'amend-state') + state.delete() + + +def extsetup(ui): + statemod.addunfinished( + b'amend', + fname=b'amend-state', + allowcommit=False, + continueflag=False, + abortfunc=_abort_amend_rev, + ) diff --git a/tests/test-amend-rev.t b/tests/test-amend-rev.t new file mode 100644 --- /dev/null +++ b/tests/test-amend-rev.t @@ -0,0 +1,50 @@ + + $ cat << EOF >> $HGRCPATH + > [extensions] + > amend= + > debugdrawdag=$TESTDIR/drawdag.py + > [experimental] + > evolution.createmarkers=True + > EOF + +Some simple setup + + $ hg init repo1 + $ cd repo1 + $ echo a > a + $ hg ci -Aqm A + $ echo b > b + $ hg ci -Aqm B + +Fails if the working copy is clean + + $ hg amend -r '.^' + nothing changed + [1] + +Fails if evolution is not enabled + + $ echo a2 > a + $ hg amend -r '.^' --config experimental.evolution.createmarkers=False + abort: --rev requires evolution + [20] + + $ hg amend -r '.^' + $ hg log -G -T '{rev} {desc}' + @ 2 temporary commit for "amend --rev" + | + o 1 B + | + o 0 A + + $ hg cat -r '.^' a + a (known-bad-output !) + a2 (missing-correct-output !) + $ hg st -v + # The repository is in an unfinished *amend* state. (known-bad-output !) + (known-bad-output !) + # To continue: hg amend --continue (known-bad-output !) + # To abort: hg amend --abort (known-bad-output !) + (known-bad-output !) + $ hg abort + $ hg st -v