diff --git a/pkg/commands/git_commands/bisect.go b/pkg/commands/git_commands/bisect.go index d3dff54d4..e554af117 100644 --- a/pkg/commands/git_commands/bisect.go +++ b/pkg/commands/git_commands/bisect.go @@ -3,6 +3,7 @@ package git_commands import ( "os" "path/filepath" + "strconv" "strings" ) @@ -192,3 +193,20 @@ func (self *BisectCommands) ReachableFromStart(bisectInfo *BisectInfo) bool { return err == nil } + +// Returns the number of commits that are reachable from logRef but not from +// the given commit. In a log of logRef, parents come after their children +// (unless the log uses git's default order and commit dates are skewed), so +// the commit is at most this many commits down from the top. +func (self *BisectCommands) CountCommitsAbove(hash string, logRef string) (int, error) { + cmdArgs := NewGitCmd("rev-list"). + Arg("--count", hash+".."+logRef). + ToArgv() + + output, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput() + if err != nil { + return 0, err + } + + return strconv.Atoi(strings.TrimSpace(output)) +} diff --git a/pkg/gui/controllers/helpers/refresh_helper.go b/pkg/gui/controllers/helpers/refresh_helper.go index c67e79f0c..aa1906a36 100644 --- a/pkg/gui/controllers/helpers/refresh_helper.go +++ b/pkg/gui/controllers/helpers/refresh_helper.go @@ -854,7 +854,7 @@ func (self *RefreshHelper) determineCheckedOutRef(env refreshEnv) models.Ref { func (self *RefreshHelper) refreshCommitsWithLimit(captured capturedCommitState, commitSelection types.CommitSelectionBehavior, env refreshEnv) error { checkedOutRef := self.determineCheckedOutRef(env) refName, bisectInfo := self.refForLog(env) - limit := lo.Ternary(captured.limitCommits, commitLimit, 0) + limit := self.commitLimitForLog(captured.limitCommits, refName, bisectInfo, env) commits, err := env.git.Loaders.CommitLoader.GetCommits( git_commands.GetCommitsOptions{ Limit: limit, @@ -1777,6 +1777,27 @@ func (self *RefreshHelper) refForLog(env refreshEnv) (string, *git_commands.Bise return bisectInfo.GetStartHash(), bisectInfo } +// commitLimitForLog returns the number of commits to load for the commits view, +// or 0 to load all of them. +func (self *RefreshHelper) commitLimitForLog(limitCommits bool, refName string, bisectInfo *git_commands.BisectInfo, env refreshEnv) int { + if !limitCommits { + return 0 + } + + if hash := bisectCommitToSelect(bisectInfo); hash != "" { + // Load the commit that the user needs to look at, and as many commits + // after it as we load from the top otherwise. This way we can select it + // without having to load all commits. + count, err := env.git.Bisect.CountCommitsAbove(hash, refName) + if err == nil { + return count + commitLimit + } + self.c.Log.Warnf("Failed to count the commits above the bisect commit to select: %v", err) + } + + return commitLimit +} + func (self *RefreshHelper) refreshView(context types.Context, env refreshEnv) { // refreshView is called from the worker goroutine that drives async // refreshes, so bounce to the UI thread before mutating view content. Guard diff --git a/pkg/integration/tests/bisect/select_current_commit_in_long_range.go b/pkg/integration/tests/bisect/select_current_commit_in_long_range.go index e3ad8aeba..09794c59f 100644 --- a/pkg/integration/tests/bisect/select_current_commit_in_long_range.go +++ b/pkg/integration/tests/bisect/select_current_commit_in_long_range.go @@ -23,9 +23,6 @@ var SelectCurrentCommitInLongRange = NewIntegrationTest(NewIntegrationTestArgs{ Run: func(t *TestDriver, keys config.KeybindingConfig) { t.Views().Commits(). Focus(). - /* EXPECTED: SelectedLine(Contains("<-- current")) - ACTUAL: */ - SelectedLine(Contains("commit 700")) }, })