Decide the commit graph from the loaded list, not the filtering mode

Whether a graph can be drawn was read from the filtering mode, while the
graph itself is drawn over the commit list in the model. Those two only
agree once the list has been reloaded for the new mode, and a filtering
mode change reloads the list in the background, so in between we can be
asked to draw a graph over a list the graph makes no sense for.

That is not just cosmetic. Commits in a filtered list are almost never
each other's parents, so no pipe ever terminates: the pipe set grows by
one per row and every continuing pipe rescans it, which is cubic in the
length of the list. Escaping out of filtering mode with a filtered list
of 13000 commits — as you get once the 300 commit limit has been lifted,
which happens for good as soon as the selection passes COMMIT_THRESHOLD
— wedges the UI thread for around twenty minutes.

Record whether the list was loaded with a filter, right where the list
itself is stored, and decide from that. The graph now also stays up while
the pre-change list is still on display, rather than vanishing a moment
before the list it belongs to.
This commit is contained in:
Stefan Haller 2026-08-05 09:14:02 +02:00
parent 8996bd68b9
commit f8b7bab1ab
3 changed files with 9 additions and 1 deletions

View file

@ -324,7 +324,13 @@ func (self *LocalCommitsViewModel) GetCommits() []*models.Commit {
}
func shouldShowGraph(c *ContextCommon) bool {
if c.Modes().Filtering.Active() {
// Whether we can draw a graph is a property of the commit list we have
// loaded, not of the filtering mode: turning filtering on or off only
// reaches the screen when the reloaded list does, and until then the graph
// has to keep matching the list that is still on display. Drawing one for a
// filtered list is also ruinously slow, because none of the commits in it
// are connected to each other, so no pipe ever terminates.
if c.Model().CommitsWereFilteredAtLastRefresh {
return false
}

View file

@ -817,6 +817,7 @@ func (self *RefreshHelper) refreshCommitsWithLimit(captured capturedCommitState,
self.c.Model().BisectInfo = bisectInfo
self.c.Model().Commits = commits
self.c.Model().CommitsWereFilteredAtLastRefresh = captured.filterPath != "" || captured.filterAuthor != ""
self.RefreshAuthors(commits)
self.c.Model().WorkingTreeStateAtLastCommitRefresh = workingTreeState
if checkedOutRef != nil {

View file

@ -349,6 +349,7 @@ type Model struct {
BisectInfo *git_commands.BisectInfo
WorkingTreeStateAtLastCommitRefresh models.WorkingTreeState
CommitsWereFilteredAtLastRefresh bool
RemoteBranches []*models.RemoteBranch
Tags []*models.Tag