Show worktree name next to branch in branches list

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:
Ruud Kamphuis 2026-03-04 13:45:05 +01:00
parent 4c7323b255
commit 6ad56d5852
No known key found for this signature in database
12 changed files with 55 additions and 31 deletions

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)

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) {

View file

@ -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"),
)
},
})

View file

@ -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)

View file

@ -37,7 +37,7 @@ var AddFromBranchDetached = NewIntegrationTest(NewIntegrationTestArgs{
IsFocused().
Lines(
Contains("(no branch)").IsSelected(),
Contains("mybranch (worktree)"),
Contains("mybranch (worktree repo)"),
)
t.Views().Status().

View file

@ -50,7 +50,7 @@ var AddFromCommit = NewIntegrationTest(NewIntegrationTestArgs{
IsFocused().
Lines(
Contains("newbranch").IsSelected(),
Contains("mybranch (worktree)"),
Contains("mybranch (worktree repo)"),
)
},
})

View file

@ -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

View file

@ -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)"),
)
},
})

View file

@ -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).

View file

@ -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(),
)
},
})

View file

@ -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"))

View file

@ -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).