From 572d1b5920104b06b3297e3861454f14738bf71b Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 5 Aug 2023 12:06:37 +0200 Subject: [PATCH] Add "Show divergence from upstream" entry to Upstream menu in branches panel --- pkg/commands/models/branch.go | 18 ++++++++ pkg/gui/context/sub_commits_context.go | 45 ++++++++++++++++++- pkg/gui/controllers/branches_controller.go | 22 +++++++++ pkg/gui/controllers/helpers/refresh_helper.go | 11 ++--- .../controllers/helpers/sub_commits_helper.go | 22 +++++---- .../switch_to_sub_commits_controller.go | 1 + pkg/gui/presentation/commits.go | 6 ++- pkg/i18n/english.go | 8 ++++ 8 files changed, 116 insertions(+), 17 deletions(-) diff --git a/pkg/commands/models/branch.go b/pkg/commands/models/branch.go index b4dcc0a79..5fc887f87 100644 --- a/pkg/commands/models/branch.go +++ b/pkg/commands/models/branch.go @@ -1,5 +1,7 @@ package models +import "fmt" + // Branch : A git branch // duplicating this for now type Branch struct { @@ -43,6 +45,22 @@ func (b *Branch) ParentRefName() string { return b.RefName() + "^" } +func (b *Branch) FullUpstreamRefName() string { + if b.UpstreamRemote == "" || b.UpstreamBranch == "" { + return "" + } + + return fmt.Sprintf("refs/remotes/%s/%s", b.UpstreamRemote, b.UpstreamBranch) +} + +func (b *Branch) ShortUpstreamRefName() string { + if b.UpstreamRemote == "" || b.UpstreamBranch == "" { + return "" + } + + return fmt.Sprintf("%s/%s", b.UpstreamRemote, b.UpstreamBranch) +} + func (b *Branch) ID() string { return b.RefName() } diff --git a/pkg/gui/context/sub_commits_context.go b/pkg/gui/context/sub_commits_context.go index b9b3a91b0..7bf34d190 100644 --- a/pkg/gui/context/sub_commits_context.go +++ b/pkg/gui/context/sub_commits_context.go @@ -1,12 +1,14 @@ package context import ( + "fmt" "time" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/samber/lo" ) type SubCommitsContext struct { @@ -71,12 +73,41 @@ func NewSubCommitsContext( selectedCommitSha, startIdx, endIdx, - shouldShowGraph(c), + // Don't show the graph in the left/right view; we'd like to, but + // it's too complicated: + shouldShowGraph(c) && viewModel.GetRefToShowDivergenceFrom() == "", git_commands.NewNullBisectInfo(), false, ) } + getNonModelItems := func() []*NonModelItem { + result := []*NonModelItem{} + if viewModel.GetRefToShowDivergenceFrom() != "" { + _, upstreamIdx, found := lo.FindIndexOf( + c.Model().SubCommits, func(c *models.Commit) bool { return c.Divergence == models.DivergenceRight }) + if !found { + upstreamIdx = 0 + } + result = append(result, &NonModelItem{ + Index: upstreamIdx, + Content: fmt.Sprintf("--- %s ---", c.Tr.DivergenceSectionHeaderRemote), + }) + + _, localIdx, found := lo.FindIndexOf( + c.Model().SubCommits, func(c *models.Commit) bool { return c.Divergence == models.DivergenceLeft }) + if !found { + localIdx = len(c.Model().SubCommits) + } + result = append(result, &NonModelItem{ + Index: localIdx, + Content: fmt.Sprintf("--- %s ---", c.Tr.DivergenceSectionHeaderLocal), + }) + } + + return result + } + ctx := &SubCommitsContext{ c: c, SubCommitsViewModel: viewModel, @@ -94,6 +125,7 @@ func NewSubCommitsContext( ListRenderer: ListRenderer{ list: viewModel, getDisplayStrings: getDisplayStrings, + getNonModelItems: getNonModelItems, }, c: c, refreshViewportOnChange: true, @@ -110,7 +142,8 @@ func NewSubCommitsContext( type SubCommitsViewModel struct { // name of the ref that the sub-commits are shown for - ref types.Ref + ref types.Ref + refToShowDivergenceFrom string *ListViewModel[*models.Commit] limitCommits bool @@ -125,6 +158,14 @@ func (self *SubCommitsViewModel) GetRef() types.Ref { return self.ref } +func (self *SubCommitsViewModel) SetRefToShowDivergenceFrom(ref string) { + self.refToShowDivergenceFrom = ref +} + +func (self *SubCommitsViewModel) GetRefToShowDivergenceFrom() string { + return self.refToShowDivergenceFrom +} + func (self *SubCommitsViewModel) SetShowBranchHeads(value bool) { self.showBranchHeads = value } diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go index 84d9e838e..67174439c 100644 --- a/pkg/gui/controllers/branches_controller.go +++ b/pkg/gui/controllers/branches_controller.go @@ -9,6 +9,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -141,6 +142,27 @@ func (self *BranchesController) setUpstream(selectedBranch *models.Branch) error return self.c.Menu(types.CreateMenuOptions{ Title: self.c.Tr.Actions.SetUnsetUpstream, Items: []*types.MenuItem{ + { + LabelColumns: []string{self.c.Tr.ViewDivergenceFromUpstream}, + OnPress: func() error { + branch := self.context().GetSelected() + if branch == nil { + return nil + } + + if !branch.RemoteBranchStoredLocally() { + return self.c.ErrorMsg(self.c.Tr.DivergenceNoUpstream) + } + return self.c.Helpers().SubCommits.ViewSubCommits(helpers.ViewSubCommitsOpts{ + Ref: branch, + TitleRef: fmt.Sprintf("%s <-> %s", branch.RefName(), branch.ShortUpstreamRefName()), + RefToShowDivergenceFrom: branch.FullUpstreamRefName(), + Context: self.context(), + ShowBranchHeads: false, + }) + }, + Key: 'v', + }, { LabelColumns: []string{self.c.Tr.UnsetUpstream}, OnPress: func() error { diff --git a/pkg/gui/controllers/helpers/refresh_helper.go b/pkg/gui/controllers/helpers/refresh_helper.go index 0fe8884c1..578089af1 100644 --- a/pkg/gui/controllers/helpers/refresh_helper.go +++ b/pkg/gui/controllers/helpers/refresh_helper.go @@ -334,11 +334,12 @@ func (self *RefreshHelper) refreshSubCommitsWithLimit() error { commits, err := self.c.Git().Loaders.CommitLoader.GetCommits( git_commands.GetCommitsOptions{ - Limit: self.c.Contexts().SubCommits.GetLimitCommits(), - FilterPath: self.c.Modes().Filtering.GetPath(), - IncludeRebaseCommits: false, - RefName: self.c.Contexts().SubCommits.GetRef().FullRefName(), - RefForPushedStatus: self.c.Contexts().SubCommits.GetRef().FullRefName(), + Limit: self.c.Contexts().SubCommits.GetLimitCommits(), + FilterPath: self.c.Modes().Filtering.GetPath(), + IncludeRebaseCommits: false, + RefName: self.c.Contexts().SubCommits.GetRef().FullRefName(), + RefToShowDivergenceFrom: self.c.Contexts().SubCommits.GetRefToShowDivergenceFrom(), + RefForPushedStatus: self.c.Contexts().SubCommits.GetRef().FullRefName(), }, ) if err != nil { diff --git a/pkg/gui/controllers/helpers/sub_commits_helper.go b/pkg/gui/controllers/helpers/sub_commits_helper.go index 412c23f0d..74c50fd14 100644 --- a/pkg/gui/controllers/helpers/sub_commits_helper.go +++ b/pkg/gui/controllers/helpers/sub_commits_helper.go @@ -27,19 +27,22 @@ func NewSubCommitsHelper( } type ViewSubCommitsOpts struct { - Ref types.Ref - Context types.Context - ShowBranchHeads bool + Ref types.Ref + RefToShowDivergenceFrom string + TitleRef string + Context types.Context + ShowBranchHeads bool } func (self *SubCommitsHelper) ViewSubCommits(opts ViewSubCommitsOpts) error { commits, err := self.c.Git().Loaders.CommitLoader.GetCommits( git_commands.GetCommitsOptions{ - Limit: true, - FilterPath: self.c.Modes().Filtering.GetPath(), - IncludeRebaseCommits: false, - RefName: opts.Ref.FullRefName(), - RefForPushedStatus: opts.Ref.FullRefName(), + Limit: true, + FilterPath: self.c.Modes().Filtering.GetPath(), + IncludeRebaseCommits: false, + RefName: opts.Ref.FullRefName(), + RefForPushedStatus: opts.Ref.FullRefName(), + RefToShowDivergenceFrom: opts.RefToShowDivergenceFrom, }, ) if err != nil { @@ -53,8 +56,9 @@ func (self *SubCommitsHelper) ViewSubCommits(opts ViewSubCommitsOpts) error { subCommitsContext.SetSelectedLineIdx(0) subCommitsContext.SetParentContext(opts.Context) subCommitsContext.SetWindowName(opts.Context.GetWindowName()) - subCommitsContext.SetTitleRef(utils.TruncateWithEllipsis(opts.Ref.RefName(), 50)) + subCommitsContext.SetTitleRef(utils.TruncateWithEllipsis(opts.TitleRef, 50)) subCommitsContext.SetRef(opts.Ref) + subCommitsContext.SetRefToShowDivergenceFrom(opts.RefToShowDivergenceFrom) subCommitsContext.SetLimitCommits(true) subCommitsContext.SetShowBranchHeads(opts.ShowBranchHeads) subCommitsContext.ClearSearchString() diff --git a/pkg/gui/controllers/switch_to_sub_commits_controller.go b/pkg/gui/controllers/switch_to_sub_commits_controller.go index 71ed5747c..3109f559e 100644 --- a/pkg/gui/controllers/switch_to_sub_commits_controller.go +++ b/pkg/gui/controllers/switch_to_sub_commits_controller.go @@ -54,6 +54,7 @@ func (self *SwitchToSubCommitsController) viewCommits() error { return self.c.Helpers().SubCommits.ViewSubCommits(helpers.ViewSubCommitsOpts{ Ref: ref, + TitleRef: ref.RefName(), Context: self.context, ShowBranchHeads: self.context.ShowBranchHeadsInSubCommits(), }) diff --git a/pkg/gui/presentation/commits.go b/pkg/gui/presentation/commits.go index 6ae04f95a..b4297f6ed 100644 --- a/pkg/gui/presentation/commits.go +++ b/pkg/gui/presentation/commits.go @@ -359,7 +359,9 @@ func displayCommit( } cols := make([]string, 0, 7) - if icons.IsIconEnabled() { + if commit.Divergence != models.DivergenceNone { + cols = append(cols, shaColor.Sprint(lo.Ternary(commit.Divergence == models.DivergenceLeft, "↑", "↓"))) + } else if icons.IsIconEnabled() { cols = append(cols, shaColor.Sprint(icons.IconForCommit(commit))) } cols = append(cols, shaColor.Sprint(commit.ShortSha())) @@ -430,6 +432,8 @@ func getShaColor( shaColor = theme.DiffTerminalColor } else if cherryPickedCommitShaSet.Includes(commit.Sha) { shaColor = theme.CherryPickedCommitTextStyle + } else if commit.Divergence == models.DivergenceRight && commit.Status != models.StatusMerged { + shaColor = style.FgBlue } return shaColor diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 93909cbdc..3dbe405ff 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -348,6 +348,10 @@ type TranslationSet struct { SetAsUpstream string SetUpstream string UnsetUpstream string + ViewDivergenceFromUpstream string + DivergenceNoUpstream string + DivergenceSectionHeaderLocal string + DivergenceSectionHeaderRemote string SetUpstreamTitle string SetUpstreamMessage string EditRemote string @@ -1128,6 +1132,10 @@ func EnglishTranslationSet() TranslationSet { SetAsUpstream: "Set as upstream of checked-out branch", SetUpstream: "Set upstream of selected branch", UnsetUpstream: "Unset upstream of selected branch", + ViewDivergenceFromUpstream: "View divergence from upstream", + DivergenceNoUpstream: "Cannot show divergence of a branch that has no (locally tracked) upstream", + DivergenceSectionHeaderLocal: "Local", + DivergenceSectionHeaderRemote: "Remote", SetUpstreamTitle: "Set upstream branch", SetUpstreamMessage: "Are you sure you want to set the upstream branch of '{{.checkedOut}}' to '{{.selected}}'", EditRemote: "Edit remote",