revert: special case 'hg revert --all'

On large repos, hg revert --all can take over 13 seconds. This is mainly due to
it walking the tree three times: once to find the list of files in the
dirstate, once to find the list of files in the target, and once to compute the
status from the dirstate to the target.

This optimizes the hg revert --all case to only require the final status. This
speeds it up to 1.3 seconds or so (with hgwatchman enabled).

Further optimizations could be done for the -r NODE and pattern cases, but they
are significantly more complex.
This commit is contained in:
Durham Goode 2014-09-19 18:43:53 -07:00
parent 03d7086901
commit 153b05ace7

View File

@ -2480,34 +2480,43 @@ def revert(ui, repo, ctx, parents, *pats, **opts):
# walk dirstate to fill `names`
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 to fill `names`
def badfn(path, msg):
if path in names:
return
if path in ctx.substate:
return
path_ = path + '/'
for f in names:
if f.startswith(path_):
return
ui.warn("%s: %s\n" % (m.rel(path), msg))
m = scmutil.match(ctx, pats, opts)
m.bad = badfn
for abs in ctx.walk(m):
if abs not in names:
if not m.always() or node != parent:
m.bad = lambda x, y: False
for abs in repo.walk(m):
names[abs] = m.rel(abs), m.exact(abs)
# Find status of all file in `names`.
m = scmutil.matchfiles(repo, names)
# walk target manifest to fill `names`
def badfn(path, msg):
if path in names:
return
if path in ctx.substate:
return
path_ = path + '/'
for f in names:
if f.startswith(path_):
return
ui.warn("%s: %s\n" % (m.rel(path), msg))
m = scmutil.match(ctx, pats, opts)
m.bad = badfn
for abs in ctx.walk(m):
if abs not in names:
names[abs] = m.rel(abs), m.exact(abs)
# Find status of all file in `names`.
m = scmutil.matchfiles(repo, names)
changes = repo.status(node1=node, match=m,
unknown=True, ignored=True, clean=True)
else:
changes = repo.status(match=m)
for kind in changes:
for abs in kind:
names[abs] = m.rel(abs), m.exact(abs)
m = scmutil.matchfiles(repo, names)
changes = repo.status(node1=node, match=m,
unknown=True, ignored=True, clean=True)
modified = set(changes[0])
added = set(changes[1])
removed = set(changes[2])