1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-08-06 22:33:07 +02:00

Draw divergence from base branch right-aligned in branches view (#4785)

- **PR Description**

I didn't enable the `showDivergenceFromBaseBranch` config by default yet
(even though I find it very useful) because I'm worried that people
might find the display too noisy. Drawing the divergence information
right-aligned helps reduce that noise a little bit.
This commit is contained in:
Stefan Haller
2025-07-30 14:26:00 +02:00
committed by GitHub
6 changed files with 53 additions and 44 deletions

View File

@ -57,12 +57,13 @@ func getBranchDisplayStrings(
checkedOutByWorkTree := git_commands.CheckedOutByOtherWorktree(b, worktrees) checkedOutByWorkTree := git_commands.CheckedOutByOtherWorktree(b, worktrees)
showCommitHash := fullDescription || userConfig.Gui.ShowBranchCommitHash showCommitHash := fullDescription || userConfig.Gui.ShowBranchCommitHash
branchStatus := BranchStatus(b, itemOperation, tr, now, userConfig) branchStatus := BranchStatus(b, itemOperation, tr, now, userConfig)
divergence := divergenceStr(b, itemOperation, tr, userConfig)
worktreeIcon := lo.Ternary(icons.IsIconEnabled(), icons.LINKED_WORKTREE_ICON, fmt.Sprintf("(%s)", tr.LcWorktree)) worktreeIcon := lo.Ternary(icons.IsIconEnabled(), icons.LINKED_WORKTREE_ICON, fmt.Sprintf("(%s)", tr.LcWorktree))
// Recency is always three characters, plus one for the space // Recency is always three characters, plus one for the space
availableWidth := viewWidth - 4 availableWidth := viewWidth - 4
if len(branchStatus) > 0 { if len(divergence) > 0 {
availableWidth -= utils.StringWidth(utils.Decolorise(branchStatus)) + 1 availableWidth -= utils.StringWidth(divergence) + 1
} }
if icons.IsIconEnabled() { if icons.IsIconEnabled() {
availableWidth -= 2 // one for the icon, one for the space availableWidth -= 2 // one for the icon, one for the space
@ -73,6 +74,11 @@ func getBranchDisplayStrings(
if checkedOutByWorkTree { if checkedOutByWorkTree {
availableWidth -= utils.StringWidth(worktreeIcon) + 1 availableWidth -= utils.StringWidth(worktreeIcon) + 1
} }
paddingNeededForDivergence := availableWidth
if len(branchStatus) > 0 {
availableWidth -= utils.StringWidth(utils.Decolorise(branchStatus)) + 1
}
displayName := b.Name displayName := b.Name
if b.DisplayName != "" { if b.DisplayName != "" {
@ -114,6 +120,13 @@ func getBranchDisplayStrings(
res = append(res, utils.ShortHash(b.CommitHash)) res = append(res, utils.ShortHash(b.CommitHash))
} }
if divergence != "" {
paddingNeededForDivergence -= utils.StringWidth(utils.Decolorise(coloredName)) - 1
if paddingNeededForDivergence > 0 {
coloredName += strings.Repeat(" ", paddingNeededForDivergence)
coloredName += style.FgCyan.Sprint(divergence)
}
}
res = append(res, coloredName) res = append(res, coloredName)
if fullDescription { if fullDescription {
@ -185,16 +198,23 @@ func BranchStatus(
} }
} }
if userConfig.Gui.ShowDivergenceFromBaseBranch != "none" { return result
}
func divergenceStr(
branch *models.Branch,
itemOperation types.ItemOperation,
tr *i18n.TranslationSet,
userConfig *config.UserConfig,
) string {
result := ""
if ItemOperationToString(itemOperation, tr) == "" && userConfig.Gui.ShowDivergenceFromBaseBranch != "none" {
behind := branch.BehindBaseBranch.Load() behind := branch.BehindBaseBranch.Load()
if behind != 0 { if behind != 0 {
if result != "" {
result += " "
}
if userConfig.Gui.ShowDivergenceFromBaseBranch == "arrowAndNumber" { if userConfig.Gui.ShowDivergenceFromBaseBranch == "arrowAndNumber" {
result += style.FgCyan.Sprintf("↓%d", behind) result += fmt.Sprintf("↓%d", behind)
} else { } else {
result += style.FgCyan.Sprintf("↓") result += "↓"
} }
} }
} }

View File

@ -113,7 +113,7 @@ func Test_getBranchDisplayStrings(t *testing.T) {
}, },
itemOperation: types.ItemOperationNone, itemOperation: types.ItemOperationNone,
fullDescription: false, fullDescription: false,
viewWidth: 100, viewWidth: 20,
useIcons: false, useIcons: false,
checkedOutByWorktree: false, checkedOutByWorktree: false,
showDivergenceCfg: "onlyArrow", showDivergenceCfg: "onlyArrow",
@ -130,7 +130,7 @@ func Test_getBranchDisplayStrings(t *testing.T) {
}, },
itemOperation: types.ItemOperationNone, itemOperation: types.ItemOperationNone,
fullDescription: false, fullDescription: false,
viewWidth: 100, viewWidth: 22,
useIcons: false, useIcons: false,
checkedOutByWorktree: false, checkedOutByWorktree: false,
showDivergenceCfg: "arrowAndNumber", showDivergenceCfg: "arrowAndNumber",
@ -147,7 +147,7 @@ func Test_getBranchDisplayStrings(t *testing.T) {
}, },
itemOperation: types.ItemOperationNone, itemOperation: types.ItemOperationNone,
fullDescription: false, fullDescription: false,
viewWidth: 100, viewWidth: 26,
useIcons: false, useIcons: false,
checkedOutByWorktree: false, checkedOutByWorktree: false,
showDivergenceCfg: "arrowAndNumber", showDivergenceCfg: "arrowAndNumber",
@ -240,6 +240,23 @@ func Test_getBranchDisplayStrings(t *testing.T) {
showDivergenceCfg: "none", showDivergenceCfg: "none",
expected: []string{"1m", "branch_… ✓"}, expected: []string{"1m", "branch_… ✓"},
}, },
{
branch: &models.Branch{
Name: "branch_name",
Recency: "1m",
UpstreamRemote: "origin",
AheadForPull: "3",
BehindForPull: "5",
BehindBaseBranch: makeAtomic(4),
},
itemOperation: types.ItemOperationNone,
fullDescription: false,
viewWidth: 21,
useIcons: false,
checkedOutByWorktree: false,
showDivergenceCfg: "arrowAndNumber",
expected: []string{"1m", "branch_n… ↓5↑3 ↓4"},
},
{ {
branch: &models.Branch{ branch: &models.Branch{
Name: "branch_name", Name: "branch_name",

View File

@ -32,7 +32,7 @@ var RebaseOntoBaseBranch = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Branches(). t.Views().Branches().
Focus(). Focus().
Lines( Lines(
Contains("feature ↓1").IsSelected(), MatchesRegexp(`feature\s+↓1`).IsSelected(),
Contains("master"), Contains("master"),
). ).
Press(keys.Branches.RebaseBranch) Press(keys.Branches.RebaseBranch)

View File

@ -25,7 +25,7 @@ var ShowDivergenceFromBaseBranch = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Branches(). t.Views().Branches().
Focus(). Focus().
Lines( Lines(
Contains("feature ↓1").IsSelected(), MatchesRegexp(`feature\s+↓1`).IsSelected(),
Contains("master"), Contains("master"),
). ).
Press(keys.Branches.SetUpstream) Press(keys.Branches.SetUpstream)

View File

@ -1,27 +0,0 @@
package status
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var ShowDivergenceFromBaseBranch = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Show divergence from base branch in the status panel",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Gui.ShowDivergenceFromBaseBranch = "arrowAndNumber"
},
SetupRepo: func(shell *Shell) {
shell.CreateNCommits(2)
shell.CloneIntoRemote("origin")
shell.NewBranch("feature")
shell.HardReset("HEAD^")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.GlobalPress(keys.Universal.NextBlock)
t.Views().Status().
Content(Equals("↓1 repo → feature"))
},
})

View File

@ -373,7 +373,6 @@ var tests = []*components.IntegrationTest{
status.ClickWorkingTreeStateToOpenRebaseOptionsMenu, status.ClickWorkingTreeStateToOpenRebaseOptionsMenu,
status.LogCmd, status.LogCmd,
status.LogCmdStatusPanelAllBranchesLog, status.LogCmdStatusPanelAllBranchesLog,
status.ShowDivergenceFromBaseBranch,
submodule.Add, submodule.Add,
submodule.Enter, submodule.Enter,
submodule.EnterNested, submodule.EnterNested,