diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go index d7faa7811..b46802320 100644 --- a/pkg/gui/controllers/branches_controller.go +++ b/pkg/gui/controllers/branches_controller.go @@ -205,6 +205,40 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc }, } + var disabledReason *types.DisabledReason + baseBranch, err := self.c.Git().Loaders.BranchLoader.GetBaseBranch(selectedBranch, self.c.Model().MainBranches) + if err != nil { + return err + } + if baseBranch == "" { + baseBranch = self.c.Tr.CouldNotDetermineBaseBranch + disabledReason = &types.DisabledReason{Text: self.c.Tr.CouldNotDetermineBaseBranch} + } + shortBaseBranchName := helpers.ShortBranchName(baseBranch) + label := utils.ResolvePlaceholderString( + self.c.Tr.ViewDivergenceFromBaseBranch, + map[string]string{"baseBranch": shortBaseBranchName}, + ) + viewDivergenceFromBaseBranchItem := &types.MenuItem{ + LabelColumns: []string{label}, + Key: 'b', + OnPress: func() error { + branch := self.context().GetSelected() + if branch == nil { + return nil + } + + return self.c.Helpers().SubCommits.ViewSubCommits(helpers.ViewSubCommitsOpts{ + Ref: branch, + TitleRef: fmt.Sprintf("%s <-> %s", branch.RefName(), shortBaseBranchName), + RefToShowDivergenceFrom: baseBranch, + Context: self.context(), + ShowBranchHeads: false, + }) + }, + DisabledReason: disabledReason, + } + unsetUpstreamItem := &types.MenuItem{ LabelColumns: []string{self.c.Tr.UnsetUpstream}, OnPress: func() error { @@ -312,6 +346,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc options := []*types.MenuItem{ viewDivergenceItem, + viewDivergenceFromBaseBranchItem, unsetUpstreamItem, setUpstreamItem, upstreamResetItem, diff --git a/pkg/gui/controllers/helpers/branches_helper.go b/pkg/gui/controllers/helpers/branches_helper.go index d9d6dbd9a..c07d1d72b 100644 --- a/pkg/gui/controllers/helpers/branches_helper.go +++ b/pkg/gui/controllers/helpers/branches_helper.go @@ -1,6 +1,8 @@ package helpers import ( + "strings" + "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" @@ -44,3 +46,7 @@ func (self *BranchesHelper) ConfirmDeleteRemote(remoteName string, branchName st }, }) } + +func ShortBranchName(fullBranchName string) string { + return strings.TrimPrefix(strings.TrimPrefix(fullBranchName, "refs/heads/"), "refs/remotes/") +} diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index a9c8fcec5..a0f205508 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -468,6 +468,8 @@ type TranslationSet struct { SetUpstream string UnsetUpstream string ViewDivergenceFromUpstream string + ViewDivergenceFromBaseBranch string + CouldNotDetermineBaseBranch string DivergenceSectionHeaderLocal string DivergenceSectionHeaderRemote string ViewUpstreamResetOptions string @@ -1434,6 +1436,8 @@ func EnglishTranslationSet() TranslationSet { SetUpstream: "Set upstream of selected branch", UnsetUpstream: "Unset upstream of selected branch", ViewDivergenceFromUpstream: "View divergence from upstream", + ViewDivergenceFromBaseBranch: "View divergence from base branch ({{.baseBranch}})", + CouldNotDetermineBaseBranch: "Couldn't determine base branch", DivergenceSectionHeaderLocal: "Local", DivergenceSectionHeaderRemote: "Remote", ViewUpstreamResetOptions: "Reset checked-out branch onto {{.upstream}}", diff --git a/pkg/integration/tests/branch/show_divergence_from_base_branch.go b/pkg/integration/tests/branch/show_divergence_from_base_branch.go new file mode 100644 index 000000000..3efc0d76c --- /dev/null +++ b/pkg/integration/tests/branch/show_divergence_from_base_branch.go @@ -0,0 +1,47 @@ +package branch + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var ShowDivergenceFromBaseBranch = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Show divergence from base branch", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) { + config.UserConfig.Gui.ShowDivergenceFromBaseBranch = "arrowAndNumber" + }, + SetupRepo: func(shell *Shell) { + shell. + EmptyCommit("master 1"). + EmptyCommit("master 2"). + EmptyCommit("master 3"). + NewBranchFrom("feature", "master^"). + EmptyCommit("feature 1"). + EmptyCommit("feature 2") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Branches(). + Focus(). + Lines( + Contains("feature ↓1").IsSelected(), + Contains("master"), + ). + Press(keys.Branches.SetUpstream) + + t.ExpectPopup().Menu().Title(Contains("Upstream")). + Select(Contains("View divergence from base branch (master)")).Confirm() + + t.Views().SubCommits(). + IsFocused(). + Title(Contains("Commits (feature <-> master)")). + Lines( + DoesNotContainAnyOf("↓", "↑").Contains("--- Remote ---"), + Contains("↓").Contains("master 3"), + DoesNotContainAnyOf("↓", "↑").Contains("--- Local ---"), + Contains("↑").Contains("feature 2"), + Contains("↑").Contains("feature 1"), + ) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index 0ab0e4331..92aaedd23 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -56,6 +56,7 @@ var tests = []*components.IntegrationTest{ branch.Reset, branch.ResetToUpstream, branch.SetUpstream, + branch.ShowDivergenceFromBaseBranch, branch.ShowDivergenceFromUpstream, branch.SortLocalBranches, branch.SortRemoteBranches,