Commit c7f769ea authored by Vadim Gelfer's avatar Vadim Gelfer
Browse files

add backout command.

command undoes effect of an earlier commit, commits new changeset
as result.
parent 1e82f2337498
......@@ -19,6 +19,11 @@ class UnknownCommand(Exception):
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 @@ def archive(ui, repo, dest, **opts):
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 @@ def import_(ui, repo, patch1, *patches, **opts):
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 @@ table = {
('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,
......
#!/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
# 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
......@@ -42,6 +42,7 @@ list of commands (use "hg help -v" to show aliases and global options):
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 @@ list of commands (use "hg help -v" to show aliases and global options):
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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment