From 153b05ace763b3364018b84da5871688da4fb10e Mon Sep 17 00:00:00 2001 From: Durham Goode Date: Fri, 19 Sep 2014 18:43:53 -0700 Subject: [PATCH] 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. --- mercurial/cmdutil.py | 59 +++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py index ce27344fb9..96e4d49000 100644 --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -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])