Mercurial > hg
changeset 2158:ec96c4518236
add backout command.
command undoes effect of an earlier commit, commits new changeset
as result.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Sat, 29 Apr 2006 20:56:46 -0700 |
parents | 1e82f2337498 |
children | 5c34b98ad6b1 |
files | mercurial/commands.py tests/test-backout tests/test-backout.out tests/test-help.out |
diffstat | 4 files changed, 127 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/commands.py Sat Apr 29 20:39:28 2006 -0700 +++ b/mercurial/commands.py Sat Apr 29 20:56:46 2006 -0700 @@ -19,6 +19,11 @@ class AmbiguousCommand(Exception): """Exception raised if command shortcut matches more than one command.""" +def bail_if_changed(repo): + modified, added, removed, deleted, unknown = repo.changes() + if modified or added or removed or deleted: + raise util.Abort(_("outstanding uncommitted changes")) + def filterfiles(filters, files): l = [x for x in files if x in filters] @@ -930,6 +935,44 @@ archival.archive(repo, dest, node, opts.get('type') or 'files', not opts['no_decode'], matchfn, prefix) +def backout(ui, repo, rev, **opts): + '''reverse effect of earlier changeset + + Commit the backed out changes as a new changeset. + + If you back out a changeset other than the tip, a new head is + created. The --merge option remembers the parent of the working + directory before starting the backout, then merges the new head + with it afterwards, to save you from doing this by hand. The + result of this merge is not committed, as for a normal merge.''' + + bail_if_changed(repo) + op1, op2 = repo.dirstate.parents() + if op2 != nullid: + raise util.Abort(_('outstanding uncommitted merge')) + node = repo.lookup(rev) + parent, p2 = repo.changelog.parents(node) + if parent == nullid: + raise util.Abort(_('cannot back out a change with no parents')) + if p2 != nullid: + raise util.Abort(_('cannot back out a merge')) + repo.update(node, force=True) + revert_opts = opts.copy() + revert_opts['rev'] = hex(parent) + revert(ui, repo, **revert_opts) + commit_opts = opts.copy() + commit_opts['addremove'] = False + if not commit_opts['message']: + commit_opts['message'] = _("Backed out changeset %s") % (hex(node)) + commit(ui, repo, **commit_opts) + def nice(node): + return '%d:%s' % (repo.changelog.rev(node), short(node)) + ui.status(_('changeset %s backs out changeset %s\n') % + (nice(repo.changelog.tip()), nice(node))) + if opts['merge'] and op1 != node: + ui.status(_('merging with changeset %s\n') % nice(op1)) + update(ui, repo, hex(op1), **opts) + def bundle(ui, repo, fname, dest="default-push", **opts): """create a changegroup file @@ -1797,9 +1840,7 @@ patches = (patch1,) + patches if not opts['force']: - modified, added, removed, deleted, unknown = repo.changes() - if modified or added or removed or deleted: - raise util.Abort(_("outstanding uncommitted changes")) + bail_if_changed(repo) d = opts["base"] strip = opts["strip"] @@ -2899,6 +2940,17 @@ ('I', 'include', [], _('include names matching the given patterns')), ('X', 'exclude', [], _('exclude names matching the given patterns'))], _('hg archive [OPTION]... DEST')), + 'backout': + (backout, + [('', 'message', '', _('use <text> as commit message')), + ('', 'merge', None, _('merge with old dirstate parent after backout')), + ('l', 'logfile', '', _('read commit message from <file>')), + ('d', 'date', '', _('record datecode as commit date')), + ('u', 'user', '', _('record user as committer')), + ('I', 'include', [], _('include names matching the given patterns')), + ('X', 'exclude', [], _('exclude names matching the given patterns'))], + _('hg backout [OPTION]... [FILE]...')), + "bundle": (bundle, [('f', 'force', None,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-backout Sat Apr 29 20:56:46 2006 -0700 @@ -0,0 +1,51 @@ +#!/bin/sh + +echo '# basic operation' +hg init basic +cd basic +echo a > a +hg commit -d '0 0' -A -m a +echo b >> a +hg commit -d '1 0' -m b + +hg backout -d '2 0' tip +cat a + +echo '# file that was removed is recreated' +cd .. +hg init remove +cd remove + +echo content > a +hg commit -d '0 0' -A -m a + +hg rm a +hg commit -d '1 0' -m b + +hg backout -d '2 0' --merge tip +cat a + +echo '# backout of backout is as if nothing happened' + +hg backout -d '3 0' --merge tip +cat a + +echo '# backout with merge' +cd .. +hg init merge +cd merge + +echo line 1 > a +hg commit -d '0 0' -A -m a + +echo line 2 >> a +hg commit -d '1 0' -m b + +echo line 3 >> a +hg commit -d '2 0' -m c + +hg backout --merge -d '3 0' 1 +hg commit -d '4 0' -m d +cat a + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-backout.out Sat Apr 29 20:56:46 2006 -0700 @@ -0,0 +1,19 @@ +# basic operation +adding a +changeset 2:b38a34ddfd9f backs out changeset 1:a820f4f40a57 +a +# file that was removed is recreated +adding a +adding a +changeset 2:44cd84c7349a backs out changeset 1:76862dcce372 +content +# backout of backout is as if nothing happened +removing a +changeset 3:0dd8a0ed5e99 backs out changeset 2:44cd84c7349a +cat: a: No such file or directory +# backout with merge +adding a +changeset 3:6c77ecc28460 backs out changeset 1:314f55b1bf23 +merging with changeset 2:b66ea5b77abb +merging a +line 1
--- a/tests/test-help.out Sat Apr 29 20:39:28 2006 -0700 +++ b/tests/test-help.out Sat Apr 29 20:56:46 2006 -0700 @@ -42,6 +42,7 @@ addremove add all new files, delete all missing files annotate show changeset information per file line archive create unversioned archive of a repository revision + backout reverse effect of earlier changeset bundle create a changegroup file cat output the latest or given revisions of files clone make a copy of an existing repository @@ -84,6 +85,7 @@ addremove add all new files, delete all missing files annotate show changeset information per file line archive create unversioned archive of a repository revision + backout reverse effect of earlier changeset bundle create a changegroup file cat output the latest or given revisions of files clone make a copy of an existing repository