diff -r eeba4eaf0716 -r 5fc2ae1c631b mercurial/revlog.py --- a/mercurial/revlog.py Mon Nov 11 16:40:02 2013 -0800 +++ b/mercurial/revlog.py Mon Nov 11 16:42:49 2013 -0800 @@ -1285,6 +1285,46 @@ return content + def getstrippoint(self, minlink): + """find the minimum rev that must be stripped to strip the linkrev + + Returns a tuple containing the minimum rev and a set of all revs that + have linkrevs that will be broken by this strip. + """ + brokenrevs = set() + strippoint = len(self) + + heads = {} + futurelargelinkrevs = set() + for head in self.headrevs(): + headlinkrev = self.linkrev(head) + heads[head] = headlinkrev + if headlinkrev >= minlink: + futurelargelinkrevs.add(headlinkrev) + + # This algorithm involves walking down the rev graph, starting at the + # heads. Since the revs are topologically sorted according to linkrev, + # once all head linkrevs are below the minlink, we know there are + # no more revs that could have a linkrev greater than minlink. + # So we can stop walking. + while futurelargelinkrevs: + strippoint -= 1 + linkrev = heads.pop(strippoint) + + if linkrev < minlink: + brokenrevs.add(strippoint) + else: + futurelargelinkrevs.remove(linkrev) + + for p in self.parentrevs(strippoint): + if p != nullrev: + plinkrev = self.linkrev(p) + heads[p] = plinkrev + if plinkrev >= minlink: + futurelargelinkrevs.add(plinkrev) + + return strippoint, brokenrevs + def strip(self, minlink, transaction): """truncate the revlog on the first revision with a linkrev >= minlink @@ -1302,10 +1342,8 @@ if len(self) == 0: return - for rev in self: - if self.index[rev][4] >= minlink: - break - else: + rev, _ = self.getstrippoint(minlink) + if rev == len(self): return # first truncate the files on disk