mirror of
https://github.com/facebook/sapling.git
synced 2024-10-07 07:17:55 +03:00
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:
parent
8afffd9943
commit
cd9a2c218d
@ -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":
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,7 +1,7 @@
|
||||
%% Should show unknown
|
||||
? unknown
|
||||
%% Should show unknown and b removed
|
||||
! b
|
||||
R b
|
||||
? unknown
|
||||
%% Should show a and unknown
|
||||
a
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user