--- a/mercurial/commands.py Tue Mar 27 16:17:46 2012 -0500
+++ b/mercurial/commands.py Wed Mar 28 11:42:17 2012 +0200
@@ -4779,7 +4779,6 @@
hint=_('use "hg update" or see "hg help revert"'))
ctx = scmutil.revsingle(repo, opts.get('rev'))
- node = ctx.node()
if not pats and not opts.get('all'):
msg = _("no files or directories specified")
@@ -4788,6 +4787,7 @@
" or 'hg update -C .' to abort the merge")
raise util.Abort(msg, hint=hint)
dirty = util.any(repo.status())
+ node = ctx.node()
if node != parent:
if dirty:
hint = _("uncommitted changes, use --all to discard all"
@@ -4801,178 +4801,7 @@
hint = _("use --all to revert all files")
raise util.Abort(msg, hint=hint)
- mf = ctx.manifest()
- if node == parent:
- pmf = mf
- else:
- pmf = None
-
- # need all matching names in dirstate and manifest of target rev,
- # so have to walk both. do not print errors if files exist in one
- # but not other.
-
- names = {}
-
- wlock = repo.wlock()
- try:
- # walk dirstate.
-
- m = scmutil.match(repo[None], pats, opts)
- m.bad = lambda x, y: False
- for abs in repo.walk(m):
- names[abs] = m.rel(abs), m.exact(abs)
-
- # walk target manifest.
-
- def badfn(path, msg):
- if path in names:
- return
- if path in repo[node].substate:
- ui.warn("%s: %s\n" % (m.rel(path),
- 'reverting subrepos is unsupported'))
- return
- path_ = path + '/'
- for f in names:
- if f.startswith(path_):
- return
- ui.warn("%s: %s\n" % (m.rel(path), msg))
-
- m = scmutil.match(repo[node], pats, opts)
- m.bad = badfn
- for abs in repo[node].walk(m):
- if abs not in names:
- names[abs] = m.rel(abs), m.exact(abs)
-
- m = scmutil.matchfiles(repo, names)
- changes = repo.status(match=m)[:4]
- modified, added, removed, deleted = map(set, changes)
-
- # if f is a rename, also revert the source
- cwd = repo.getcwd()
- for f in added:
- src = repo.dirstate.copied(f)
- if src and src not in names and repo.dirstate[src] == 'r':
- removed.add(src)
- names[src] = (repo.pathto(src, cwd), True)
-
- def removeforget(abs):
- if repo.dirstate[abs] == 'a':
- return _('forgetting %s\n')
- return _('removing %s\n')
-
- revert = ([], _('reverting %s\n'))
- add = ([], _('adding %s\n'))
- remove = ([], removeforget)
- undelete = ([], _('undeleting %s\n'))
-
- 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, remove, True, False),
- (removed, undelete, None, False, False),
- (deleted, revert, remove, False, False),
- )
-
- for abs, (rel, exact) in sorted(names.items()):
- mfentry = mf.get(abs)
- target = repo.wjoin(abs)
- def handle(xlist, dobackup):
- xlist[0].append(abs)
- if (dobackup and not opts.get('no_backup') and
- os.path.lexists(target)):
- bakname = "%s.orig" % rel
- ui.note(_('saving current version of %s as %s\n') %
- (rel, bakname))
- if not opts.get('dry_run'):
- util.rename(target, bakname)
- if ui.verbose or not exact:
- msg = xlist[1]
- if not isinstance(msg, basestring):
- msg = msg(abs)
- ui.status(msg % rel)
- for table, hitlist, misslist, backuphit, backupmiss in disptable:
- if abs not in table:
- continue
- # file has changed in dirstate
- if mfentry:
- handle(hitlist, backuphit)
- elif misslist is not None:
- handle(misslist, backupmiss)
- break
- else:
- if abs not in repo.dirstate:
- if mfentry:
- handle(add, True)
- elif exact:
- ui.warn(_('file not managed: %s\n') % rel)
- continue
- # file has not changed in dirstate
- if node == parent:
- if exact:
- ui.warn(_('no changes needed to %s\n') % rel)
- continue
- if pmf is None:
- # only need parent manifest in this unlikely case,
- # so do not read by default
- pmf = repo[parent].manifest()
- if abs in pmf and mfentry:
- # if version of file is same in parent and target
- # manifests, do nothing
- if (pmf[abs] != mfentry or
- pmf.flags(abs) != mf.flags(abs)):
- handle(revert, False)
- else:
- handle(remove, False)
-
- if not opts.get('dry_run'):
- def checkout(f):
- fc = ctx[f]
- repo.wwrite(f, fc.data(), fc.flags())
-
- audit_path = scmutil.pathauditor(repo.root)
- for f in remove[0]:
- if repo.dirstate[f] == 'a':
- repo.dirstate.drop(f)
- continue
- audit_path(f)
- try:
- util.unlinkpath(repo.wjoin(f))
- except OSError:
- pass
- repo.dirstate.remove(f)
-
- normal = None
- if node == parent:
- # We're reverting to our parent. If possible, we'd like status
- # to report the file as clean. We have to use normallookup for
- # merges to avoid losing information about merged/dirty files.
- if p2 != nullid:
- normal = repo.dirstate.normallookup
- else:
- normal = repo.dirstate.normal
- for f in revert[0]:
- checkout(f)
- if normal:
- normal(f)
-
- for f in add[0]:
- checkout(f)
- repo.dirstate.add(f)
-
- normal = repo.dirstate.normallookup
- if node == parent and p2 == nullid:
- normal = repo.dirstate.normal
- for f in undelete[0]:
- checkout(f)
- normal(f)
-
- finally:
- wlock.release()
+ return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
@command('rollback', dryrunopts +
[('f', 'force', False, _('ignore safety measures'))])