diff --git a/mercurial/phases.py b/mercurial/phases.py --- a/mercurial/phases.py +++ b/mercurial/phases.py @@ -323,6 +323,28 @@ self.filterunknown(repo) self.opener = repo.svfs + def hasnonpublicphases(self, repo): + """detect if there are revisions with non-public phase""" + repo = repo.unfiltered() + cl = repo.changelog + if len(cl) >= self._loadedrevslen: + self.invalidate() + self.loadphaserevs(repo) + return any(self.phaseroots[1:]) + + def nonpublicphaseroots(self, repo): + """returns the roots of all non-public phases + + The roots are not minimized, so if the secret revisions are + descendants of draft revisions, their roots will still be present. + """ + repo = repo.unfiltered() + cl = repo.changelog + if len(cl) >= self._loadedrevslen: + self.invalidate() + self.loadphaserevs(repo) + return set().union(*[roots for roots in self.phaseroots[1:] if roots]) + def getrevset(self, repo, phases, subset=None): """return a smartset for the given phases""" self.loadphaserevs(repo) # ensure phase's sets are loaded diff --git a/mercurial/repoview.py b/mercurial/repoview.py --- a/mercurial/repoview.py +++ b/mercurial/repoview.py @@ -129,7 +129,7 @@ def computemutable(repo, visibilityexceptions=None): assert not repo.changelog.filteredrevs # fast check to avoid revset call on huge repo - if any(repo._phasecache.phaseroots[1:]): + if repo._phasecache.hasnonpublicphases(repo): getphase = repo._phasecache.phase maymutable = filterrevs(repo, b'base') return frozenset(r for r in maymutable if getphase(repo, r)) @@ -154,9 +154,9 @@ assert not repo.changelog.filteredrevs cl = repo.changelog firstmutable = len(cl) - for roots in repo._phasecache.phaseroots[1:]: - if roots: - firstmutable = min(firstmutable, min(cl.rev(r) for r in roots)) + roots = repo._phasecache.nonpublicphaseroots(repo) + if roots: + firstmutable = min(firstmutable, min(cl.rev(r) for r in roots)) # protect from nullrev root firstmutable = max(0, firstmutable) return frozenset(pycompat.xrange(firstmutable, len(cl)))