diff --git a/pkg/gui/context/commit_list_goto_bottom.go b/pkg/gui/context/commit_list_goto_bottom.go index 3d955f628..288d276d6 100644 --- a/pkg/gui/context/commit_list_goto_bottom.go +++ b/pkg/gui/context/commit_list_goto_bottom.go @@ -2,6 +2,7 @@ package context import ( "github.com/jesseduffield/generics/set" + "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/samber/lo" "github.com/stefanhaller/git-todo-parser/todo" @@ -18,9 +19,21 @@ import ( // - each branch of a stack, given by branchesBelow. Among the todos of a // rebase, update-ref todos separate the branches. // - the commits that aren't merged into a main branch yet +// +// During a bisect, it stops at the bottommost commit marked bad, at the commit +// to test, and at the topmost commit marked good instead. The commits list +// doesn't color the commits by whether they are merged during a bisect, so the +// beginnings of the sections would look like arbitrary commits. func indexForGotoBottomInCommits( - commits []*models.Commit, selectedIdx int, branchesBelow []*models.Branch, + commits []*models.Commit, + selectedIdx int, + branchesBelow []*models.Branch, + bisectInfo *git_commands.BisectInfo, ) int { + if bisectInfo.Started() { + return closestStopBelow(bisectStops(commits, bisectInfo), selectedIdx, len(commits)-1) + } + stops := []int{} if headIdx := models.HeadCommitIdx(commits); headIdx > 0 { @@ -51,6 +64,30 @@ func indexForGotoBottomInCommits( return closestStopBelow(stops, selectedIdx, len(commits)-1) } +func bisectStops(commits []*models.Commit, bisectInfo *git_commands.BisectInfo) []int { + hasStatus := func(status git_commands.BisectStatus) func(*models.Commit) bool { + return func(commit *models.Commit) bool { + commitStatus, ok := bisectInfo.Status(commit.Hash()) + return ok && commitStatus == status + } + } + isCommitToTest := func(commit *models.Commit) bool { + return bisectInfo.HasCommitToTest() && commit.Hash() == bisectInfo.GetCurrentHash() + } + + stops := []int{} + if _, idx, found := lo.FindLastIndexOf(commits, hasStatus(git_commands.BisectStatusNew)); found { + stops = append(stops, idx) + } + if _, idx, found := lo.FindIndexOf(commits, isCommitToTest); found { + stops = append(stops, idx) + } + if _, idx, found := lo.FindIndexOf(commits, hasStatus(git_commands.BisectStatusOld)); found { + stops = append(stops, idx) + } + return stops +} + // Returns the smallest of the given stops that is greater than the selected // index, or the last index if there is none func closestStopBelow(stops []int, selectedIdx int, lastIdx int) int { diff --git a/pkg/gui/context/commit_list_goto_bottom_test.go b/pkg/gui/context/commit_list_goto_bottom_test.go index bb942e480..36956b1e2 100644 --- a/pkg/gui/context/commit_list_goto_bottom_test.go +++ b/pkg/gui/context/commit_list_goto_bottom_test.go @@ -3,6 +3,7 @@ package context import ( "testing" + "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/utils" "github.com/stefanhaller/git-todo-parser/todo" @@ -185,7 +186,8 @@ func TestIndexForGotoBottomInCommits(t *testing.T) { for _, s := range scenarios { t.Run(s.testName, func(t *testing.T) { - assert.Equal(t, s.expected, indexForGotoBottomInCommits(s.commits, s.selectedIdx, s.branchesBelow)) + assert.Equal(t, s.expected, indexForGotoBottomInCommits( + s.commits, s.selectedIdx, s.branchesBelow, git_commands.NewNullBisectInfo())) }) } } diff --git a/pkg/gui/context/local_commits_context.go b/pkg/gui/context/local_commits_context.go index 23abc0239..6d63c1efd 100644 --- a/pkg/gui/context/local_commits_context.go +++ b/pkg/gui/context/local_commits_context.go @@ -525,5 +525,5 @@ func (self *LocalCommitsContext) IndexForGotoBottom() int { commits := self.GetCommits() branchesBelow := branchstack.BranchesBelow( commits, c.Model().Branches, c.Model().CheckedOutBranch, c.UserConfig().Git.MainBranches) - return indexForGotoBottomInCommits(commits, self.GetSelectedLineIdx(), branchesBelow) + return indexForGotoBottomInCommits(commits, self.GetSelectedLineIdx(), branchesBelow, c.Model().BisectInfo) } diff --git a/pkg/gui/context/sub_commits_context.go b/pkg/gui/context/sub_commits_context.go index 73adc4b89..edada3e52 100644 --- a/pkg/gui/context/sub_commits_context.go +++ b/pkg/gui/context/sub_commits_context.go @@ -276,5 +276,6 @@ func (self *SubCommitsContext) IndexForGotoBottom() int { branchesBelow = branchstack.BranchesBelow( commits, self.c.Model().Branches, self.GetRef().RefName(), self.c.UserConfig().Git.MainBranches) } - return indexForGotoBottomInCommits(commits, self.GetSelectedLineIdx(), branchesBelow) + return indexForGotoBottomInCommits( + commits, self.GetSelectedLineIdx(), branchesBelow, git_commands.NewNullBisectInfo()) } diff --git a/pkg/integration/tests/bisect/goto_bottom.go b/pkg/integration/tests/bisect/goto_bottom.go new file mode 100644 index 000000000..10f31be1a --- /dev/null +++ b/pkg/integration/tests/bisect/goto_bottom.go @@ -0,0 +1,47 @@ +package bisect + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var GotoBottom = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Go to the bottom of the commits list in steps, stopping only at the bad commit, the current commit, and the first good commit", + ExtraCmdArgs: []string{}, + Skip: false, + SetupRepo: func(shell *Shell) { + shell. + CreateNCommits(3). + NewBranch("mybranch"). + CreateNCommitsStartingAt(7, 4). + StartBisect("HEAD~1", "HEAD~8") + }, + SetupConfig: func(cfg *config.AppConfig) { + cfg.GetUserConfig().Git.Log.ShowGraph = "never" + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Commits(). + Focus(). + Lines( + Contains("CI commit-10"), + Contains("CI commit-09").Contains("<-- bad"), + Contains("CI commit-08"), + Contains("CI commit-07"), + Contains("CI commit-06"), + Contains("CI commit-05").Contains("<-- current").IsSelected(), + Contains("CI commit-04"), + Contains("CI commit-03"), + Contains("CI commit-02").Contains("<-- good"), + Contains("CI commit-01"), + ). + Press(keys.Universal.GotoTop). + Press(keys.Universal.GotoBottom). + SelectedLine(Contains("CI commit-09")). + Press(keys.Universal.GotoBottom). + SelectedLine(Contains("CI commit-05")). + Press(keys.Universal.GotoBottom). + SelectedLine(Contains("CI commit-02")). + Press(keys.Universal.GotoBottom). + SelectedLine(Contains("CI commit-01")) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index 0219fb43e..09ba2a464 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -39,6 +39,7 @@ var tests = []*components.IntegrationTest{ bisect.CheckOutBranchBeforeBisecting, bisect.ChooseTerms, bisect.FromOtherBranch, + bisect.GotoBottom, bisect.MarkCandidatesWhileTestingMergeBase, bisect.OfferResetWhenMergeBaseIsBad, bisect.SelectCurrentCommit,