Adjust worktree name display in agent panel and git picker (#53351)

This PR adjust the name of the worktree within the agent panel: we
display `main` if you're in the main worktree and then the worktree name
when in a linked one. Additionally, I also took the opportunity to fix
something that confused me in the general worktree picker: for the list
item that represented the main worktree, we were using the current
checked out branch name for that item's name. I think that's a bit
incorrect, given the _name_ of that worktree isn't the name of the
branch you have active at that moment. For now, I'm using simply `main`
as the worktree name. Lastly, also added a little blue check icon in the
worktree _and branch_ picker to highlight which worktree/branch is
currently active.

| main worktree | linked worktree | main worktree in picker |
|--------|--------|--------|
| <img width="802" height="338" alt="Screenshot 2026-04-07 at 10  32
2@2x"
src="https://github.com/user-attachments/assets/aad993e6-adc3-4c8d-b01a-abb2597182e7"
/> | <img width="804" height="332" alt="Screenshot 2026-04-07 at 10 
32@2x"
src="https://github.com/user-attachments/assets/e59c5b86-8cee-476c-ab7b-32ae87249c1a"
/> | <img width="804" height="856" alt="Screenshot 2026-04-07 at 10 
36@2x"
src="https://github.com/user-attachments/assets/282d89a8-570e-4e62-b703-853bed9b21ff"
/> |

Release Notes:

- Git: Fixed display of the main worktree name in the worktree picker.
This commit is contained in:
Danilo Leal 2026-04-07 23:21:17 -03:00 committed by GitHub
parent a5aea73474
commit 30e7e8b550
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 71 additions and 15 deletions

View file

@ -62,7 +62,7 @@ use gpui::{
use language::LanguageRegistry;
use language_model::LanguageModelRegistry;
use project::project_settings::ProjectSettings;
use project::{Project, ProjectPath, Worktree};
use project::{Project, ProjectPath, Worktree, linked_worktree_short_name};
use prompt_store::{PromptStore, UserPromptId};
use rules_library::{RulesLibrary, open_rules_library};
use settings::TerminalDockPosition;
@ -641,6 +641,18 @@ impl StartThreadIn {
}
}
if let Some(name) = linked_worktree_short_name(
repo.original_repo_abs_path.as_ref(),
repo.work_directory_abs_path.as_ref(),
) {
if visible_paths
.iter()
.any(|p| p.as_path() == repo.work_directory_abs_path.as_ref())
{
return Some(SharedString::from(format!("({})", name)));
}
}
if visible_paths
.iter()
.any(|p| p.as_path() == work_dir.as_ref())

View file

@ -885,12 +885,16 @@ impl PickerDelegate for BranchListDelegate {
})
.unwrap_or_else(|| (None, None, None));
let is_head_branch = entry.as_branch().is_some_and(|branch| branch.is_head);
let entry_icon = match entry {
Entry::NewUrl { .. } | Entry::NewBranch { .. } | Entry::NewRemoteName { .. } => {
IconName::Plus
}
Entry::Branch { branch, .. } => {
if branch.is_remote() {
if is_head_branch {
IconName::Check
} else if branch.is_remote() {
IconName::Screen
} else {
IconName::GitBranchAlt
@ -975,7 +979,11 @@ impl PickerDelegate for BranchListDelegate {
.flex_grow()
.child(
Icon::new(entry_icon)
.color(Color::Muted)
.color(if is_head_branch {
Color::Accent
} else {
Color::Muted
})
.size(IconSize::Small),
)
.child(

View file

@ -19,13 +19,15 @@ use remote_connection::{RemoteConnectionModal, connect};
use settings::Settings;
use std::{path::PathBuf, sync::Arc};
use ui::{HighlightedLabel, KeyBinding, ListItem, ListItemSpacing, Tooltip, prelude::*};
use util::{ResultExt, debug_panic};
use util::{ResultExt, debug_panic, paths::PathExt};
use workspace::{
ModalView, MultiWorkspace, OpenMode, Workspace, notifications::DetachAndPromptErr,
};
use crate::git_panel::show_error_toast;
const MAIN_WORKTREE_DISPLAY_NAME: &str = "main";
actions!(
git,
[
@ -273,6 +275,7 @@ pub struct WorktreeListDelegate {
focus_handle: FocusHandle,
default_branch: Option<SharedString>,
forbidden_deletion_path: Option<PathBuf>,
current_worktree_path: Option<PathBuf>,
}
impl WorktreeListDelegate {
@ -282,6 +285,10 @@ impl WorktreeListDelegate {
_window: &mut Window,
cx: &mut Context<WorktreeList>,
) -> Self {
let current_worktree_path = repo
.as_ref()
.map(|r| r.read(cx).work_directory_abs_path.to_path_buf());
Self {
matches: vec![],
all_worktrees: None,
@ -293,6 +300,7 @@ impl WorktreeListDelegate {
focus_handle: cx.focus_handle(),
default_branch: None,
forbidden_deletion_path: None,
current_worktree_path,
}
}
@ -699,7 +707,14 @@ impl PickerDelegate for WorktreeListDelegate {
let candidates = all_worktrees
.iter()
.enumerate()
.map(|(ix, worktree)| StringMatchCandidate::new(ix, worktree.display_name()))
.map(|(ix, worktree)| {
let name = if worktree.is_main {
MAIN_WORKTREE_DISPLAY_NAME
} else {
worktree.display_name()
};
StringMatchCandidate::new(ix, name)
})
.collect::<Vec<StringMatchCandidate>>();
fuzzy::match_strings(
&candidates,
@ -722,9 +737,14 @@ impl PickerDelegate for WorktreeListDelegate {
picker
.update(cx, |picker, _| {
if !query.is_empty()
&& !matches
.first()
.is_some_and(|entry| entry.worktree.display_name() == query)
&& !matches.first().is_some_and(|entry| {
let name = if entry.worktree.is_main {
MAIN_WORKTREE_DISPLAY_NAME
} else {
entry.worktree.display_name()
};
name == query
})
{
let query = query.replace(' ', "-");
matches.push(WorktreeEntry {
@ -777,7 +797,7 @@ impl PickerDelegate for WorktreeListDelegate {
cx: &mut Context<Picker<Self>>,
) -> Option<Self::ListItem> {
let entry = &self.matches.get(ix)?;
let path = entry.worktree.path.to_string_lossy().to_string();
let path = entry.worktree.path.compact().to_string_lossy().to_string();
let sha = entry
.worktree
.sha
@ -800,17 +820,21 @@ impl PickerDelegate for WorktreeListDelegate {
),
)
} else {
let branch = entry.worktree.display_name();
let branch_first_line = branch.lines().next().unwrap_or(branch);
let display_name = if entry.worktree.is_main {
MAIN_WORKTREE_DISPLAY_NAME
} else {
entry.worktree.display_name()
};
let first_line = display_name.lines().next().unwrap_or(display_name);
let positions: Vec<_> = entry
.positions
.iter()
.copied()
.filter(|&pos| pos < branch_first_line.len())
.filter(|&pos| pos < first_line.len())
.collect();
(
HighlightedLabel::new(branch_first_line.to_owned(), positions)
HighlightedLabel::new(first_line.to_owned(), positions)
.truncate()
.into_any_element(),
path,
@ -832,8 +856,16 @@ impl PickerDelegate for WorktreeListDelegate {
}))
};
let is_current = !entry.is_new
&& self
.current_worktree_path
.as_ref()
.is_some_and(|current| *current == entry.worktree.path);
let entry_icon = if entry.is_new {
IconName::Plus
} else if is_current {
IconName::Check
} else {
IconName::GitWorktree
};
@ -849,7 +881,11 @@ impl PickerDelegate for WorktreeListDelegate {
.gap_2p5()
.child(
Icon::new(entry_icon)
.color(Color::Muted)
.color(if is_current {
Color::Accent
} else {
Color::Muted
})
.size(IconSize::Small),
)
.child(v_flex().w_full().child(branch_name).map(|this| {
@ -879,7 +915,7 @@ impl PickerDelegate for WorktreeListDelegate {
)
.child(
Label::new(sublabel)
.truncate()
.truncate_start()
.color(Color::Muted)
.size(LabelSize::Small)
.flex_1(),