rewrite revert command. fix issues 93, 123, 147.

new version does these things:

- saves backup copies of modified files (issue 147)

- prints output like other commands, and errors when files not found
  (issue 123)

- marks files added/removed (issue 93)
This commit is contained in:
Vadim Gelfer 2006-03-31 10:37:25 -08:00
parent 8afffd9943
commit cd9a2c218d
10 changed files with 165 additions and 33 deletions

View File

@ -43,16 +43,17 @@ def matchpats(repo, pats=[], opts={}, head=''):
return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
opts.get('exclude'), head)
def makewalk(repo, pats, opts, node=None, head=''):
def makewalk(repo, pats, opts, node=None, head='', badmatch=None):
files, matchfn, anypats = matchpats(repo, pats, opts, head)
exact = dict(zip(files, files))
def walk():
for src, fn in repo.walk(node=node, files=files, match=matchfn):
for src, fn in repo.walk(node=node, files=files, match=matchfn,
badmatch=None):
yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
return files, matchfn, walk()
def walk(repo, pats, opts, node=None, head=''):
files, matchfn, results = makewalk(repo, pats, opts, node, head)
def walk(repo, pats, opts, node=None, head='', badmatch=None):
files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
for r in results:
yield r
@ -2003,7 +2004,7 @@ def merge(ui, repo, node=None, **opts):
performed before any further updates are allowed.
"""
return update(ui, repo, node=node, merge=True, **opts)
def outgoing(ui, repo, dest="default-push", **opts):
"""show changesets not found in destination
@ -2088,7 +2089,7 @@ def postincoming(ui, repo, modheads, optupdate):
ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
else:
ui.status(_("(run 'hg update' to get a working copy)\n"))
def pull(ui, repo, source="default", **opts):
"""pull changes from the specified source
@ -2286,6 +2287,10 @@ def revert(ui, repo, *pats, **opts):
to the named files or directories. This restores the contents of
the affected files to an unmodified state.
Modified files have backup copies saved before revert. To disable
backups, use --no-backup. To change the name of backup files, use
--backup to give a format string.
Using the -r option, it reverts the given files or directories to
their state as of an earlier revision. This can be helpful to "roll
back" some or all of a change that should not have been committed.
@ -2300,15 +2305,92 @@ def revert(ui, repo, *pats, **opts):
If no arguments are given, all files in the repository are reverted.
"""
node = opts['rev'] and repo.lookup(opts['rev']) or \
repo.dirstate.parents()[0]
parent = repo.dirstate.parents()[0]
node = opts['rev'] and repo.lookup(opts['rev']) or parent
mf = repo.manifest.read(repo.changelog.read(node)[0])
files, choose, anypats = matchpats(repo, pats, opts)
modified, added, removed, deleted, unknown = repo.changes(match=choose)
repo.forget(added)
repo.undelete(removed)
def backup(name, exact):
bakname = make_filename(repo, repo.changelog,
opts['backup_name'] or '%p.orig',
node=parent, pathname=name)
if os.path.exists(name):
# if backup already exists and is same as backup we want
# to make, do nothing
if os.path.exists(bakname):
if repo.wread(name) == repo.wread(bakname):
return
raise util.Abort(_('cannot save current version of %s - '
'%s exists and differs') %
(name, bakname))
ui.status(('saving current version of %s as %s\n') %
(name, bakname))
shutil.copyfile(name, bakname)
shutil.copymode(name, bakname)
return repo.update(node, False, True, choose, False)
wlock = repo.wlock()
entries = []
names = {}
for src, abs, rel, exact in walk(repo, pats, opts, badmatch=mf.has_key):
names[abs] = True
entries.append((abs, rel, exact))
changes = repo.changes(match=names.has_key, wlock=wlock)
modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
revert = ([], _('reverting %s\n'))
add = ([], _('adding %s\n'))
remove = ([], _('removing %s\n'))
forget = ([], _('forgetting %s\n'))
undelete = ([], _('undeleting %s\n'))
update = {}
disptable = (
# dispatch table:
# file state
# action if in target manifest
# action if not in target manifest
# make backup if in target manifest
# make backup if not in target manifest
(modified, revert, remove, True, True),
(added, revert, forget, True, True),
(removed, undelete, None, False, False),
(deleted, revert, remove, False, False),
(unknown, add, None, True, False),
)
for abs, rel, exact in entries:
def handle(xlist, dobackup):
xlist[0].append(abs)
if dobackup and not opts['no_backup']:
backup(rel, exact)
if ui.verbose or not exact:
ui.status(xlist[1] % rel)
for table, hitlist, misslist, backuphit, backupmiss in disptable:
if abs not in table: continue
# file has changed in dirstate
if abs in mf:
handle(hitlist, backuphit)
elif misslist is not None:
handle(misslist, backupmiss)
else:
if exact: ui.warn(_('file not managed: %s\n' % rel))
break
else:
# file has not changed in dirstate
if node == parent:
if exact: ui.warn(_('no changes needed to %s\n' % rel))
continue
if abs not in mf:
remove[0].append(abs)
update[abs] = True
repo.dirstate.forget(forget[0])
r = repo.update(node, False, True, update.has_key, False, wlock=wlock)
repo.dirstate.update(add[0], 'a')
repo.dirstate.update(undelete[0], 'n')
repo.dirstate.update(remove[0], 'r')
return r
def root(ui, repo):
"""print the root (top) of the current working dir
@ -2929,8 +3011,10 @@ table = {
"^revert":
(revert,
[('r', 'rev', '', _('revision to revert to')),
('I', 'include', [], _('include names matching the given patterns')),
('X', 'exclude', [], _('exclude names matching the given patterns'))],
('', 'backup-name', '', _('save backup with formatted name')),
('', 'no-backup', None, _('do not save backup copies of files')),
('I', 'include', [], _('include names matching given patterns')),
('X', 'exclude', [], _('exclude names matching given patterns'))],
_('hg revert [-r REV] [NAME]...')),
"root": (root, [], _('hg root')),
"^serve":

View File

@ -483,7 +483,7 @@ class localrepository(object):
self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2)
return n
def walk(self, node=None, files=[], match=util.always):
def walk(self, node=None, files=[], match=util.always, badmatch=None):
if node:
fdict = dict.fromkeys(files)
for fn in self.manifest.read(self.changelog.read(node)[0]):
@ -491,8 +491,12 @@ class localrepository(object):
if match(fn):
yield 'm', fn
for fn in fdict:
self.ui.warn(_('%s: No such file in rev %s\n') % (
util.pathto(self.getcwd(), fn), short(node)))
if badmatch and badmatch(fn):
if match(fn):
yield 'b', fn
else:
self.ui.warn(_('%s: No such file in rev %s\n') % (
util.pathto(self.getcwd(), fn), short(node)))
else:
for src, fn in self.dirstate.walk(files, match):
yield src, fn

View File

@ -2,16 +2,24 @@
A b
R a
reverting...
saving current version of b as b.bak
forgetting b
undeleting a
%%% should show b unknown and a back to normal
? b
? b.bak
merging a
%%% should show foo-b
foo-b
%%% should show a removed and b added
A b
R a
? b.bak
reverting...
forgetting b
undeleting a
%%% should show b unknown and a marked modified (merged)
? b
? b.bak
%%% should show foo-b
foo-b

View File

@ -3,10 +3,18 @@
016807e6fdaf tip
eb43f19ff115
eb43f19ff115+
saving current version of file1 as file1.bak
reverting file1
? file1.bak
eb43f19ff115
? file1.bak
016807e6fdaf tip
merging file1
? file1.bak
016807e6fdaf tip
? file1.bak
016807e6fdaf tip
? file1.bak
016807e6fdaf tip
? file1.bak
016807e6fdaf tip

View File

@ -16,7 +16,7 @@ hg update -C 0
hg id
echo "changed file1" >> file1
hg id
hg revert
hg revert --no-backup
hg diff
hg status
hg id
@ -31,11 +31,11 @@ hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" -e "s/\(<<<<<<<\) .*/\1/" \
-e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" -e "s/\(>>>>>>>\) .*/\1/"
hg status
hg id
hg revert
hg revert --no-backup
hg diff
hg status
hg id
hg revert -r tip
hg revert -r tip --no-backup
hg diff
hg status
hg id

View File

@ -3,6 +3,7 @@
f248da0d4c3e tip
9eca13a34789
9eca13a34789+
reverting file1
9eca13a34789
f248da0d4c3e tip
merge: warning: conflicts during merge
@ -21,6 +22,7 @@ diff -r f248da0d4c3e file1
+>>>>>>>
M file1
f248da0d4c3e+ tip
reverting file1
f248da0d4c3e tip
f248da0d4c3e tip
f248da0d4c3e tip

View File

@ -3,8 +3,9 @@
hg init
echo 123 > a
echo 123 > c
hg add a c
hg commit -m "first" -d "1000000 0" a c
echo 123 > e
hg add a c e
hg commit -m "first" -d "1000000 0" a c e
echo 123 > b
echo %% should show b unknown
hg status
@ -18,15 +19,25 @@ hg rm a
echo %% should show a removed, b added and c modified
hg status
hg revert a
echo %% should show b added and c modified
echo %% should show b added, copy saved, and c modified
hg status
hg revert b
echo %% should show b unknown and c modified
echo %% should show b unknown, b.bak unknown, and c modified
hg status
hg revert c
echo %% should show b unknown
hg revert --no-backup c
echo %% should show unknown: b b.bak
hg status
echo %% should show a b and c
echo %% should show a b b.bak c e
ls
echo %% should save backup to e.0
echo z > e
hg revert --backup='%p.%R'
echo %% should say no changes needed
hg revert a
echo %% should say file not managed
echo q > q
hg revert q
echo %% should say file not found
hg revert notfound
true

View File

@ -1,7 +1,7 @@
%% Should show unknown
? unknown
%% Should show unknown and b removed
! b
R b
? unknown
%% Should show a and unknown
a

View File

@ -10,15 +10,29 @@ A b
M c
A b
R a
%% should show b added and c modified
%% should show b added, copy saved, and c modified
M c
A b
%% should show b unknown and c modified
saving current version of b as b.bak
%% should show b unknown, b.bak unknown, and c modified
M c
? b
%% should show b unknown
? b.bak
%% should show unknown: b b.bak
? b
%% should show a b and c
? b.bak
%% should show a b b.bak c e
a
b
b.bak
c
e
%% should save backup to e.0
saving current version of e as e.0
reverting e
%% should say no changes needed
no changes needed to a
%% should say file not managed
file not managed: q
%% should say file not found
notfound: No such file or directory

View File

@ -21,6 +21,7 @@ failed
use of 'hg tag NAME [REV]' is deprecated, please use 'hg tag [-r REV] NAME' instead
abort: use only one form to specify the revision
failed
saving current version of .hgtags as .hgtags.bak
use of 'hg tag NAME [REV]' is deprecated, please use 'hg tag [-r REV] NAME' instead
0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah
0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah0