1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2026-06-20 01:19:23 +02:00

Show worktree name next to branch in branches list (#5340)

### PR Description

When a branch is checked out by another worktree, show the worktree name
in the label, e.g. "(worktree cosmos2)" instead of just "(worktree)", so
you can immediately see which worktree holds it.
This commit is contained in:
Stefan Haller
2026-03-09 11:58:28 +01:00
committed by GitHub
12 changed files with 55 additions and 31 deletions
+30 -6
View File
@@ -57,7 +57,6 @@ func getBranchDisplayStrings(
showCommitHash := fullDescription || userConfig.Gui.ShowBranchCommitHash
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))
// Recency is always three characters, plus one for the space
availableWidth := viewWidth - 4
@@ -72,17 +71,42 @@ func getBranchDisplayStrings(
}
paddingNeededForDivergence := availableWidth
if checkedOutByWorkTree {
availableWidth -= utils.StringWidth(worktreeIcon) + 1
displayName := b.Name
if b.DisplayName != "" {
displayName = b.DisplayName
}
if len(branchStatus) > 0 {
availableWidth -= utils.StringWidth(utils.Decolorise(branchStatus)) + 1
}
displayName := b.Name
if b.DisplayName != "" {
displayName = b.DisplayName
worktreeIcon := ""
if checkedOutByWorkTree {
if wt, ok := git_commands.WorktreeForBranch(b, worktrees); ok && wt.Name != b.Name {
if icons.IsIconEnabled() {
worktreeIcon = fmt.Sprintf("(%s %s)", icons.LINKED_WORKTREE_ICON, wt.Name)
} else {
worktreeIcon = fmt.Sprintf("(%s %s)", tr.LcWorktree, wt.Name)
}
// If the worktree name doesn't fit in the available width, omit it
remaining := availableWidth - utils.StringWidth(worktreeIcon) - 1
if remaining < utils.StringWidth(displayName) {
if icons.IsIconEnabled() {
worktreeIcon = icons.LINKED_WORKTREE_ICON
} else {
worktreeIcon = fmt.Sprintf("(%s)", tr.LcWorktree)
}
}
} else {
if icons.IsIconEnabled() {
worktreeIcon = icons.LINKED_WORKTREE_ICON
} else {
worktreeIcon = fmt.Sprintf("(%s)", tr.LcWorktree)
}
}
availableWidth -= utils.StringWidth(worktreeIcon) + 1
}
nameTextStyle := GetBranchTextStyle(b.Name)
+4 -4
View File
@@ -62,7 +62,7 @@ func Test_getBranchDisplayStrings(t *testing.T) {
useIcons: false,
checkedOutByWorktree: true,
showDivergenceCfg: "none",
expected: []string{"1m", "branch_name (worktree)"},
expected: []string{"1m", "branch_name (worktree other-worktree)"},
},
{
branch: &models.Branch{Name: "branch_name", Recency: "1m"},
@@ -72,7 +72,7 @@ func Test_getBranchDisplayStrings(t *testing.T) {
useIcons: true,
checkedOutByWorktree: true,
showDivergenceCfg: "none",
expected: []string{"1m", "󰘬", "branch_name 󰌹"},
expected: []string{"1m", "󰘬", "branch_name (󰌹 other-worktree)"},
},
{
branch: &models.Branch{
@@ -104,7 +104,7 @@ func Test_getBranchDisplayStrings(t *testing.T) {
useIcons: false,
checkedOutByWorktree: true,
showDivergenceCfg: "none",
expected: []string{"1m", "branch_name (worktree) ↓5↑3"},
expected: []string{"1m", "branch_name (worktree other-worktree) ↓5↑3"},
},
{
branch: &models.Branch{
@@ -347,7 +347,7 @@ func Test_getBranchDisplayStrings(t *testing.T) {
worktrees := []*models.Worktree{}
if s.checkedOutByWorktree {
worktrees = append(worktrees, &models.Worktree{Branch: s.branch.Name})
worktrees = append(worktrees, &models.Worktree{Branch: s.branch.Name, Name: "other-worktree"})
}
t.Run(fmt.Sprintf("getBranchDisplayStrings_%d", i), func(t *testing.T) {
@@ -38,7 +38,7 @@ var FetchAndAutoForwardBranchesAllBranchesCheckedOutInOtherWorktree = NewIntegra
Contains("checked-out").IsSelected(),
Contains("diverged ↓2↑1"),
Contains("feature ↓2").DoesNotContain("↑"),
Contains("master (worktree) ↓1").DoesNotContain("↑"),
Contains("master (worktree linked-worktree) ↓1").DoesNotContain("↑"),
)
t.Views().Files().
@@ -51,7 +51,7 @@ var FetchAndAutoForwardBranchesAllBranchesCheckedOutInOtherWorktree = NewIntegra
Contains("checked-out").IsSelected(),
Contains("diverged ↓2↑1"),
Contains("feature ✓"),
Contains("master (worktree) ↓1"),
Contains("master (worktree linked-worktree) ↓1"),
)
},
})
@@ -42,7 +42,7 @@ var AddFromBranch = NewIntegrationTest(NewIntegrationTestArgs{
IsFocused().
Lines(
Contains("newbranch").IsSelected(),
Contains("mybranch (worktree)"),
Contains("mybranch (worktree repo)"),
).
NavigateToLine(Contains("mybranch")).
Press(keys.Universal.Select).
@@ -54,7 +54,7 @@ var AddFromBranch = NewIntegrationTest(NewIntegrationTestArgs{
}).
Lines(
Contains("mybranch").IsSelected(),
Contains("newbranch (worktree)"),
Contains("newbranch (worktree linked-worktree)"),
).
// Confirm the files view is still showing in the files window
Press(keys.Universal.PrevBlock)
@@ -37,7 +37,7 @@ var AddFromBranchDetached = NewIntegrationTest(NewIntegrationTestArgs{
IsFocused().
Lines(
Contains("(no branch)").IsSelected(),
Contains("mybranch (worktree)"),
Contains("mybranch (worktree repo)"),
)
t.Views().Status().
@@ -50,7 +50,7 @@ var AddFromCommit = NewIntegrationTest(NewIntegrationTestArgs{
IsFocused().
Lines(
Contains("newbranch").IsSelected(),
Contains("mybranch (worktree)"),
Contains("mybranch (worktree repo)"),
)
},
})
@@ -30,7 +30,7 @@ var AssociateBranchBisect = NewIntegrationTest(NewIntegrationTestArgs{
Focus().
Lines(
Contains("mybranch").IsSelected(),
Contains("newbranch (worktree)"),
Contains("newbranch (worktree linked-worktree)"),
)
// start a bisect on the main worktree
@@ -70,7 +70,7 @@ var AssociateBranchBisect = NewIntegrationTest(NewIntegrationTestArgs{
}).
Lines(
Contains("newbranch").IsSelected(),
Contains("mybranch (worktree)"),
Contains("mybranch (worktree repo)"),
)
// switch back to main worktree
@@ -31,7 +31,7 @@ var AssociateBranchRebase = NewIntegrationTest(NewIntegrationTestArgs{
Focus().
Lines(
Contains("mybranch").IsSelected(),
Contains("newbranch (worktree)"),
Contains("newbranch (worktree linked-worktree)"),
)
// start a rebase on the main worktree
@@ -57,7 +57,7 @@ var AssociateBranchRebase = NewIntegrationTest(NewIntegrationTestArgs{
}).
Lines(
Contains("newbranch").IsSelected(),
Contains("mybranch (worktree)"),
Contains("mybranch (worktree repo)"),
)
// start a rebase on the linked worktree
@@ -83,7 +83,7 @@ var AssociateBranchRebase = NewIntegrationTest(NewIntegrationTestArgs{
Contains("(no branch").IsSelected(),
Contains("mybranch"),
// even though the linked worktree is rebasing, we still associate it with the branch
Contains("newbranch (worktree)"),
Contains("newbranch (worktree linked-worktree)"),
)
},
})
@@ -23,7 +23,7 @@ var DetachWorktreeFromBranch = NewIntegrationTest(NewIntegrationTestArgs{
Focus().
Lines(
Contains("mybranch").IsSelected(),
Contains("newbranch (worktree)"),
Contains("newbranch (worktree linked-worktree)"),
).
NavigateToLine(Contains("newbranch")).
Press(keys.Universal.Remove).
@@ -35,18 +35,18 @@ var FastForwardWorktreeBranch = NewIntegrationTest(NewIntegrationTestArgs{
Focus().
Lines(
Contains("mybranch").Contains("↓1").IsSelected(),
Contains("newbranch (worktree)").Contains("↓1"),
Contains("newbranch (worktree linked-worktree)").Contains("↓1"),
).
Press(keys.Branches.FastForward).
Lines(
Contains("mybranch").Contains("✓").IsSelected(),
Contains("newbranch (worktree)").Contains("↓1"),
Contains("newbranch (worktree linked-worktree)").Contains("↓1"),
).
NavigateToLine(Contains("newbranch (worktree)")).
NavigateToLine(Contains("newbranch (worktree linked-worktree)")).
Press(keys.Branches.FastForward).
Lines(
Contains("mybranch").Contains("✓"),
Contains("newbranch (worktree)").Contains("✓").IsSelected(),
Contains("newbranch (worktree linked-worktree)").Contains("✓").IsSelected(),
)
},
})
@@ -35,18 +35,18 @@ var FastForwardWorktreeBranchShouldNotPolluteCurrentWorktree = NewIntegrationTes
Focus().
Lines(
Contains("mybranch").Contains("↓1").IsSelected(),
Contains("newbranch (worktree)").Contains("↓1"),
Contains("newbranch (worktree linked-worktree)").Contains("↓1"),
).
Press(keys.Branches.FastForward).
Lines(
Contains("mybranch").Contains("✓").IsSelected(),
Contains("newbranch (worktree)").Contains("↓1"),
Contains("newbranch (worktree linked-worktree)").Contains("↓1"),
).
NavigateToLine(Contains("newbranch (worktree)")).
NavigateToLine(Contains("newbranch (worktree linked-worktree)")).
Press(keys.Branches.FastForward).
Lines(
Contains("mybranch").Contains("✓"),
Contains("newbranch (worktree)").Contains("✓").IsSelected(),
Contains("newbranch (worktree linked-worktree)").Contains("✓").IsSelected(),
).
NavigateToLine(Contains("mybranch"))
@@ -24,7 +24,7 @@ var RemoveWorktreeFromBranch = NewIntegrationTest(NewIntegrationTestArgs{
Focus().
Lines(
Contains("mybranch").IsSelected(),
Contains("newbranch (worktree)"),
Contains("newbranch (worktree linked-worktree)"),
).
NavigateToLine(Contains("newbranch")).
Press(keys.Universal.Remove).