Show More
@@ -540,6 +540,9 b' class localrepository(repo.repository):' | |||
|
540 | 540 | continue |
|
541 | 541 | node, label = l.split(" ", 1) |
|
542 | 542 | label = encoding.tolocal(label.strip()) |
|
543 | if not node in self: | |
|
544 | raise ValueError('invalidating branch cache because node '+ | |
|
545 | '%s does not exist' % node) | |
|
543 | 546 | partial.setdefault(label, []).append(bin(node)) |
|
544 | 547 | except KeyboardInterrupt: |
|
545 | 548 | raise |
@@ -561,6 +564,10 b' class localrepository(repo.repository):' | |||
|
561 | 564 | pass |
|
562 | 565 | |
|
563 | 566 | def _updatebranchcache(self, partial, ctxgen): |
|
567 | """Given a branchhead cache, partial, that may have extra nodes or be | |
|
568 | missing heads, and a generator of nodes that are at least a superset of | |
|
569 | heads missing, this function updates partial to be correct. | |
|
570 | """ | |
|
564 | 571 | # collect new branch entries |
|
565 | 572 | newbranches = {} |
|
566 | 573 | for c in ctxgen: |
@@ -571,21 +578,42 b' class localrepository(repo.repository):' | |||
|
571 | 578 | for branch, newnodes in newbranches.iteritems(): |
|
572 | 579 | bheads = partial.setdefault(branch, []) |
|
573 | 580 | bheads.extend(newnodes) |
|
574 | if len(bheads) <= 1: | |
|
575 | continue | |
|
576 | bheads = sorted(bheads, key=lambda x: self[x].rev()) | |
|
577 | # starting from tip means fewer passes over reachable | |
|
578 | while newnodes: | |
|
579 | latest = newnodes.pop() | |
|
580 | if latest not in bheads: | |
|
581 | continue | |
|
582 | minbhnode = self[bheads[0]].node() | |
|
583 | reachable = self.changelog.reachable(latest, minbhnode) | |
|
584 | reachable.remove(latest) | |
|
585 |
|
|
|
586 | bheads = [b for b in bheads if b not in reachable] | |
|
581 | # Remove duplicates - nodes that are in newnodes and are already in | |
|
582 | # bheads. This can happen if you strip a node and its parent was | |
|
583 | # already a head (because they're on different branches). | |
|
584 | bheads = set(bheads) | |
|
585 | ||
|
586 | # Remove candidate heads that no longer are in the repo (e.g., as | |
|
587 | # the result of a strip that just happened). | |
|
588 | # avoid using 'bhead in self' here because that dives down into | |
|
589 | # branchcache code somewhat recrusively. | |
|
590 | bheads = [bhead for bhead in bheads \ | |
|
591 | if self.changelog.hasnode(bhead)] | |
|
592 | if len(bheads) > 1: | |
|
593 | bheads = sorted(bheads, key=lambda x: self[x].rev()) | |
|
594 | # starting from tip means fewer passes over reachable | |
|
595 | while newnodes: | |
|
596 | latest = newnodes.pop() | |
|
597 | if latest not in bheads: | |
|
598 | continue | |
|
599 | minbhnode = self[bheads[0]].node() | |
|
600 | reachable = self.changelog.reachable(latest, minbhnode) | |
|
601 | reachable.remove(latest) | |
|
602 | if reachable: | |
|
603 | bheads = [b for b in bheads if b not in reachable] | |
|
587 | 604 | partial[branch] = bheads |
|
588 | 605 | |
|
606 | # There may be branches that cease to exist when the last commit in the | |
|
607 | # branch was stripped. This code filters them out. Note that the | |
|
608 | # branch that ceased to exist may not be in newbranches because | |
|
609 | # newbranches is the set of candidate heads, which when you strip the | |
|
610 | # last commit in a branch will be the parent branch. | |
|
611 | for branch in partial.keys(): | |
|
612 | nodes = [head for head in partial[branch] \ | |
|
613 | if self.changelog.hasnode(head)] | |
|
614 | if len(nodes) < 1: | |
|
615 | del partial[branch] | |
|
616 | ||
|
589 | 617 | def lookup(self, key): |
|
590 | 618 | return self[key].node() |
|
591 | 619 | |
@@ -848,6 +876,9 b' class localrepository(repo.repository):' | |||
|
848 | 876 | else: |
|
849 | 877 | ui.status(_('working directory now based on ' |
|
850 | 878 | 'revision %d\n') % parents) |
|
879 | # TODO: if we know which new heads may result from this rollback, pass | |
|
880 | # them to destroy(), which will prevent the branchhead cache from being | |
|
881 | # invalidated. | |
|
851 | 882 | self.destroyed() |
|
852 | 883 | return 0 |
|
853 | 884 | |
@@ -1291,12 +1322,27 b' class localrepository(repo.repository):' | |||
|
1291 | 1322 | tr.release() |
|
1292 | 1323 | lock.release() |
|
1293 | 1324 | |
|
1294 | def destroyed(self): | |
|
1325 | def destroyed(self, newheadrevs=None): | |
|
1295 | 1326 | '''Inform the repository that nodes have been destroyed. |
|
1296 | 1327 | Intended for use by strip and rollback, so there's a common |
|
1297 |
place for anything that has to be done after destroying history. |
|
|
1298 | # XXX it might be nice if we could take the list of destroyed | |
|
1299 | # nodes, but I don't see an easy way for rollback() to do that | |
|
1328 | place for anything that has to be done after destroying history. | |
|
1329 | ||
|
1330 | If you know the branchheadcache was uptodate before nodes were removed | |
|
1331 | and you also know the set of candidate set of new heads that may have | |
|
1332 | resulted from the destruction, you can set newheadrevs. This will | |
|
1333 | enable the code to update the branchheads cache, rather than having | |
|
1334 | future code decide it's invalid and regenrating it. | |
|
1335 | ''' | |
|
1336 | if newheadrevs: | |
|
1337 | tiprev = len(self) - 1 | |
|
1338 | ctxgen = (self[rev] for rev in newheadrevs) | |
|
1339 | self._updatebranchcache(self._branchcache, ctxgen) | |
|
1340 | self._writebranchcache(self._branchcache, self.changelog.tip(), | |
|
1341 | tiprev) | |
|
1342 | else: | |
|
1343 | # No info to update the cache. If nodes were destroyed, the cache | |
|
1344 | # is stale and this will be caught the next time it is read. | |
|
1345 | pass | |
|
1300 | 1346 | |
|
1301 | 1347 | # Ensure the persistent tag cache is updated. Doing it now |
|
1302 | 1348 | # means that the tag cache only has to worry about destroyed |
@@ -56,6 +56,11 b' def _collectbrokencsets(repo, files, str' | |||
|
56 | 56 | return s |
|
57 | 57 | |
|
58 | 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 | 64 | cl = repo.changelog |
|
60 | 65 | # TODO handle undo of merge sets |
|
61 | 66 | if isinstance(nodelist, str): |
@@ -63,6 +68,14 b' def strip(ui, repo, nodelist, backup="al' | |||
|
63 | 68 | striplist = [cl.rev(node) for node in nodelist] |
|
64 | 69 | striprev = min(striplist) |
|
65 | 70 | |
|
71 | # Set of potential new heads resulting from the strip. The parents of any | |
|
72 | # node removed could be a new head because the node to be removed could have | |
|
73 | # been the only child of the parent. | |
|
74 | # Do a list->set->list conversion to remove duplicates. | |
|
75 | stringstriplist = [str(rev) for rev in striplist] | |
|
76 | newheadrevs = set(repo.revs("parents(%lr::) - %lr::", stringstriplist, | |
|
77 | stringstriplist)) | |
|
78 | ||
|
66 | 79 | keeppartialbundle = backup == 'strip' |
|
67 | 80 | |
|
68 | 81 | # Some revisions with rev > striprev may not be descendants of striprev. |
@@ -169,4 +182,4 b' def strip(ui, repo, nodelist, backup="al' | |||
|
169 | 182 | % chgrpfile) |
|
170 | 183 | raise |
|
171 | 184 | |
|
172 | repo.destroyed() | |
|
185 | repo.destroyed(newheadrevs) |
@@ -247,6 +247,7 b' Same thing, different code path:' | |||
|
247 | 247 | |
|
248 | 248 | $ echo b >> b |
|
249 | 249 | $ hg ci -m 'reopen branch' |
|
250 | created new head | |
|
250 | 251 | reopening closed branch head 4 |
|
251 | 252 | $ echo b >> b |
|
252 | 253 | $ hg ci --amend --close-branch |
@@ -36,7 +36,8 b' mq patch on an empty repo' | |||
|
36 | 36 | $ hg qrefresh -m 'patch 1' |
|
37 | 37 | $ show_branch_cache |
|
38 | 38 | tip: 0 |
|
39 | No branch cache | |
|
39 | d986d5caac23a7d44a46efc0ddaf5eb9665844cf 0 | |
|
40 | d986d5caac23a7d44a46efc0ddaf5eb9665844cf default | |
|
40 | 41 | |
|
41 | 42 | some regular revisions |
|
42 | 43 | |
@@ -75,8 +76,8 b' add some mq patches' | |||
|
75 | 76 | $ hg qrefresh -m 'patch 2' |
|
76 | 77 | $ show_branch_cache 1 |
|
77 | 78 | tip: 3 |
|
78 | c229711f16da3d7591f89b1b8d963b79bda22714 1 | |
|
79 | c229711f16da3d7591f89b1b8d963b79bda22714 bar | |
|
79 | 982611f6955f9c48d3365decea203217c945ef0d 2 | |
|
80 | 982611f6955f9c48d3365decea203217c945ef0d bar | |
|
80 | 81 | dc25e3827021582e979f600811852e36cbe57341 foo |
|
81 | 82 | branch foo: 3 |
|
82 | 83 | branch bar: 2 |
General Comments 0
You need to be logged in to leave comments.
Login now