comparison mercurial/repair.py @ 17013:c8eda7bbdcab

strip: incrementally update the branchheads cache after a strip This function augments strip to incrementally update the branchheads cache rather than recompute it from scratch. This speeds up the performance of strip and rebase on repos with long history. The performance optimization only happens if the revisions stripped are all on the same branch and the parents of the stripped revisions are also on that same branch. This adds a few test cases, particularly one that reproduces the extra heads that mpm observed.
author Joshua Redstone <joshua.redstone@fb.com>
date Fri, 18 May 2012 12:45:47 -0700
parents 1093ad1e8903
children ec7b9bec19c9
comparison
equal deleted inserted replaced
17012:ea97744c4801 17013:c8eda7bbdcab
54 collectone(repo.file(fname)) 54 collectone(repo.file(fname))
55 55
56 return s 56 return s
57 57
58 def strip(ui, repo, nodelist, backup="all", topic='backup'): 58 def strip(ui, repo, nodelist, backup="all", topic='backup'):
59 # It simplifies the logic around updating the branchheads cache if we only
60 # have to consider the effect of the stripped revisions and not revisions
61 # missing because the cache is out-of-date.
62 repo.updatebranchcache()
63
59 cl = repo.changelog 64 cl = repo.changelog
60 # TODO handle undo of merge sets 65 # TODO handle undo of merge sets
61 if isinstance(nodelist, str): 66 if isinstance(nodelist, str):
62 nodelist = [nodelist] 67 nodelist = [nodelist]
63 striplist = [cl.rev(node) for node in nodelist] 68 striplist = [cl.rev(node) for node in nodelist]
64 striprev = min(striplist) 69 striprev = min(striplist)
70
71 # Generate set of branches who will have nodes stripped.
72 striprevs = repo.revs("%ld::", striplist)
73 stripbranches = set([repo[rev].branch() for rev in striprevs])
74
75 # Set of potential new heads resulting from the strip. The parents of any
76 # node removed could be a new head because the node to be removed could have
77 # been the only child of the parent.
78 newheadrevs = repo.revs("parents(%ld::) - %ld::", striprevs, striprevs)
79 newheadnodes = set([cl.node(rev) for rev in newheadrevs])
80 newheadbranches = set([repo[rev].branch() for rev in newheadrevs])
65 81
66 keeppartialbundle = backup == 'strip' 82 keeppartialbundle = backup == 'strip'
67 83
68 # Some revisions with rev > striprev may not be descendants of striprev. 84 # Some revisions with rev > striprev may not be descendants of striprev.
69 # We have to find these revisions and put them in a bundle, so that 85 # We have to find these revisions and put them in a bundle, so that
167 elif saveheads: 183 elif saveheads:
168 ui.warn(_("strip failed, partial bundle stored in '%s'\n") 184 ui.warn(_("strip failed, partial bundle stored in '%s'\n")
169 % chgrpfile) 185 % chgrpfile)
170 raise 186 raise
171 187
172 repo.destroyed() 188 if len(stripbranches) == 1 and len(newheadbranches) == 1 \
189 and stripbranches == newheadbranches:
190 repo.destroyed(newheadnodes)
191 else:
192 # Multiple branches involved in strip. Will allow branchcache to become
193 # invalid and later on rebuilt from scratch
194 repo.destroyed()
195