Show base branches as bare names in labels

ShortBranchName previously turned "refs/remotes/origin/main" into
"origin/main", leaking the resolved-ref shape into UI labels that
the user thinks of as plain "main" — the name they put in their
mainBranches config. With the ambiguous-base label now potentially
listing several branches ("pick: origin/main, origin/13"), the noise
is even more pronounced. Strip the remote name along with the
"refs/remotes/" prefix so the short name matches what the user
configured.

Rename the helper to BaseBranchDisplayName to make the constraint
explicit at every call site: dropping the remote is a sensible
choice only for base-branch display, not for refs in general. All
current callers happen to be base-branch related, so the rename is
just a scope-tightening.

Existing integration test updated to expect the bare "master" form.
This commit is contained in:
Stefan Haller
2026-07-03 19:37:37 +02:00
parent cee2de60ba
commit 6e74cc0268
6 changed files with 35 additions and 13 deletions
+3 -3
View File
@@ -295,14 +295,14 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
if err != nil {
return err
}
baseBranchLabel := helpers.ShortBranchName(baseBranch)
baseBranchLabel := helpers.BaseBranchDisplayName(baseBranch)
switch {
case baseBranch == "":
baseBranchLabel = self.c.Tr.CouldNotDetermineBaseBranch
disabledReason = &types.DisabledReason{Text: self.c.Tr.CouldNotDetermineBaseBranch}
case baseAmbiguous:
shortNames := lo.Map(baseCandidates, func(ref string, _ int) string {
return helpers.ShortBranchName(ref)
return helpers.BaseBranchDisplayName(ref)
})
baseBranchLabel = utils.ResolvePlaceholderString(self.c.Tr.PickBaseBranchLabel,
map[string]string{"candidates": strings.Join(shortNames, ", ")},
@@ -323,7 +323,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
showDivergence := func(base string) error {
return self.c.Helpers().SubCommits.ViewSubCommits(helpers.ViewSubCommitsOpts{
Ref: branch,
TitleRef: fmt.Sprintf("%s <-> %s", branch.RefName(), helpers.ShortBranchName(base)),
TitleRef: fmt.Sprintf("%s <-> %s", branch.RefName(), helpers.BaseBranchDisplayName(base)),
RefToShowDivergenceFrom: base,
Context: self.context(),
ShowBranchHeads: false,
@@ -50,7 +50,7 @@ func (self *BaseBranchHelper) ShowPicker(
) error {
items := lo.Map(candidates, func(ref string, _ int) *types.MenuItem {
return &types.MenuItem{
Label: ShortBranchName(ref),
Label: BaseBranchDisplayName(ref),
OnPress: func() error { return onPicked(ref) },
}
})
+24 -2
View File
@@ -161,8 +161,30 @@ func (self *BranchesHelper) ConfirmLocalAndRemoteDelete(branches []*models.Branc
return nil
}
func ShortBranchName(fullBranchName string) string {
return strings.TrimPrefix(strings.TrimPrefix(fullBranchName, "refs/heads/"), "refs/remotes/")
// BaseBranchDisplayName returns the user-facing name of a configured main
// branch from its resolved full ref:
//
// refs/heads/main → main
// refs/remotes/origin/main → main
// refs/remotes/origin/feat/x → feat/x
//
// For remote-tracking refs the remote name is dropped along with the prefix:
// the user configured plain "main" in mainBranches and shouldn't have to see
// whether lazygit ultimately resolved it to a local or remote ref. The remote
// is only meaningful internally, so this function is intended specifically for
// base-branch display — don't use it where the local/remote distinction
// matters.
func BaseBranchDisplayName(fullBranchName string) string {
if name, ok := strings.CutPrefix(fullBranchName, "refs/heads/"); ok {
return name
}
if name, ok := strings.CutPrefix(fullBranchName, "refs/remotes/"); ok {
if _, withoutRemote, found := strings.Cut(name, "/"); found {
return withoutRemote
}
return name
}
return fullBranchName
}
func (self *BranchesHelper) checkedOutByOtherWorktree(branch *models.Branch) bool {
@@ -351,14 +351,14 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error {
if err != nil {
return err
}
baseBranchLabel := ShortBranchName(baseBranch)
baseBranchLabel := BaseBranchDisplayName(baseBranch)
switch {
case baseBranch == "":
baseBranchLabel = self.c.Tr.CouldNotDetermineBaseBranch
baseBranchDisabledReason = &types.DisabledReason{Text: self.c.Tr.CouldNotDetermineBaseBranch}
case baseAmbiguous:
shortNames := lo.Map(baseCandidates, func(ref string, _ int) string {
return ShortBranchName(ref)
return BaseBranchDisplayName(ref)
})
baseBranchLabel = utils.ResolvePlaceholderString(self.c.Tr.PickBaseBranchLabel,
map[string]string{"candidates": strings.Join(shortNames, ", ")},
+3 -3
View File
@@ -480,10 +480,10 @@ func (self *RefsHelper) MoveCommitsToNewBranch() error {
return nil
}
baseBranchLabel := ShortBranchName(baseBranchRef)
baseBranchLabel := BaseBranchDisplayName(baseBranchRef)
if baseAmbiguous {
shortNames := lo.Map(baseCandidates, func(ref string, _ int) string {
return ShortBranchName(ref)
return BaseBranchDisplayName(ref)
})
baseBranchLabel = utils.ResolvePlaceholderString(self.c.Tr.PickBaseBranchLabel,
map[string]string{"candidates": strings.Join(shortNames, ", ")},
@@ -503,7 +503,7 @@ func (self *RefsHelper) MoveCommitsToNewBranch() error {
Label: fmt.Sprintf(self.c.Tr.MoveCommitsToNewBranchFromBaseItem, baseBranchLabel),
OnPress: func() error {
moveOff := func(base string) error {
return withNewBranchNamePrompt(ShortBranchName(base), func(newBranchName string) error {
return withNewBranchNamePrompt(BaseBranchDisplayName(base), func(newBranchName string) error {
return self.moveCommitsToNewBranchOffOfMainBranch(newBranchName, base)
})
}
@@ -37,11 +37,11 @@ var MoveCommitsToNewBranchFromBaseBranch = NewIntegrationTest(NewIntegrationTest
t.ExpectPopup().Menu().
Title(Equals("Move commits to new branch")).
Select(Contains("New branch from base branch (origin/master)")).
Select(Contains("New branch from base branch (master)")).
Confirm()
t.ExpectPopup().Prompt().
Title(Equals("New branch name (branch is off of 'origin/master')")).
Title(Equals("New branch name (branch is off of 'master')")).
Type("new branch").
Confirm()