diff --git a/mercurial/branchmap.py b/mercurial/branchmap.py --- a/mercurial/branchmap.py +++ b/mercurial/branchmap.py @@ -884,8 +884,7 @@ class BranchCacheV3(_LocalBranchCache): elif self.tiprev == cl.tiprev(): return cl.headrevs() else: - # XXX passing tiprev as ceiling of cl.headrevs could be faster - heads = cl.headrevs(cl.revs(stop=self.tiprev)) + heads = cl.headrevs(stop_rev=self.tiprev + 1) return heads def _write_header(self, fp) -> None: diff --git a/mercurial/repoview.py b/mercurial/repoview.py --- a/mercurial/repoview.py +++ b/mercurial/repoview.py @@ -310,9 +310,14 @@ class filteredchangelogmixin: # no Rust fast path implemented yet, so just loop in Python return [self.node(r) for r in self.headrevs()] - def headrevs(self, revs=None): + def headrevs(self, revs=None, stop_rev=None): if revs is None: - return self.index.headrevs(self.filteredrevs) + filtered = self.filteredrevs + if stop_rev is not None and stop_rev < len(self.index): + filtered = set(self.filteredrevs) + filtered.update(range(stop_rev, len(self.index))) + return self.index.headrevs(filtered) + assert stop_rev is None revs = self._checknofilteredinrevs(revs) return super(filteredchangelogmixin, self).headrevs(revs) diff --git a/mercurial/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -2380,9 +2380,15 @@ class revlog: assert heads return (orderedout, roots, heads) - def headrevs(self, revs=None): + def headrevs(self, revs=None, stop_rev=None): if revs is None: - return self.index.headrevs() + excluded = None + if stop_rev is not None and stop_rev < len(self.index): + # We should let the native code handle it, but that a + # simple enough first step. + excluded = range(stop_rev, len(self.index)) + return self.index.headrevs(excluded) + assert stop_rev is None if rustdagop is not None and self.index.rust_ext_compat: return rustdagop.headrevs(self.index, revs) return dagop.headrevs(revs, self._uncheckedparentrevs)