git_graph: Add some design adjustments (#53803)

Danilo Leal created

Closes https://github.com/zed-industries/zed/issues/53524

- Improve overall colors
- Fix chip truncation
- Better highlight which branch is currently checked out

| Truncation | Checked out branch |
|--------|--------|
| <img width="2774" height="2158" alt="Screenshot 2026-04-13 at 9 
40@2x"
src="https://github.com/user-attachments/assets/176cbe72-a757-4b83-b8c1-9fcbda16a5a8"
/> | <img width="2774" height="2158" alt="Screenshot 2026-04-13 at 9 
41@2x"
src="https://github.com/user-attachments/assets/cf4a3863-9dae-4891-b93a-443e4d7ca5a2"
/> |

Release Notes:

- Git Graph: Improved visibility of the currently checked out branch and
fixed branch name truncation.

Change summary

crates/git_graph/src/git_graph.rs | 72 +++++++++++++++++++++++++-------
crates/ui/src/components/chip.rs  | 35 +++++++++++++++
2 files changed, 90 insertions(+), 17 deletions(-)

Detailed changes

crates/git_graph/src/git_graph.rs 🔗

@@ -1184,11 +1184,33 @@ impl GitGraph {
         git_store.repositories().get(&self.repo_id).cloned()
     }
 
-    fn render_chip(&self, name: &SharedString, accent_color: gpui::Hsla) -> impl IntoElement {
+    /// Checks whether a ref name from git's `%D` decoration
+    ///  format refers to the currently checked-out branch.
+    fn is_head_ref(ref_name: &str, head_branch_name: &Option<SharedString>) -> bool {
+        head_branch_name.as_ref().is_some_and(|head| {
+            ref_name == head.as_ref() || ref_name.strip_prefix("HEAD -> ") == Some(head.as_ref())
+        })
+    }
+
+    fn render_chip(
+        &self,
+        name: &SharedString,
+        accent_color: gpui::Hsla,
+        is_head: bool,
+    ) -> impl IntoElement {
         Chip::new(name.clone())
             .label_size(LabelSize::Small)
-            .bg_color(accent_color.opacity(0.1))
-            .border_color(accent_color.opacity(0.5))
+            .truncate()
+            .map(|chip| {
+                if is_head {
+                    chip.icon(IconName::Check)
+                        .bg_color(accent_color.opacity(0.25))
+                        .border_color(accent_color.opacity(0.5))
+                } else {
+                    chip.bg_color(accent_color.opacity(0.08))
+                        .border_color(accent_color.opacity(0.25))
+                }
+            })
     }
 
     fn render_table_rows(
@@ -1199,6 +1221,14 @@ impl GitGraph {
     ) -> Vec<Vec<AnyElement>> {
         let repository = self.get_repository(cx);
 
+        let head_branch_name: Option<SharedString> = repository.as_ref().and_then(|repo| {
+            repo.read(cx)
+                .snapshot()
+                .branch
+                .as_ref()
+                .map(|branch| SharedString::from(branch.name().to_string()))
+        });
+
         let row_height = self.row_height;
 
         // We fetch data outside the visible viewport to avoid loading entries when
@@ -1311,13 +1341,13 @@ impl GitGraph {
                                 .gap_2()
                                 .overflow_hidden()
                                 .children((!commit.data.ref_names.is_empty()).then(|| {
-                                    h_flex().gap_1().children(
-                                        commit
-                                            .data
-                                            .ref_names
-                                            .iter()
-                                            .map(|name| self.render_chip(name, accent_color)),
-                                    )
+                                    h_flex().gap_1().children(commit.data.ref_names.iter().map(
+                                        |name| {
+                                            let is_head =
+                                                Self::is_head_ref(name.as_ref(), &head_branch_name);
+                                            self.render_chip(name, accent_color, is_head)
+                                        },
+                                    ))
                                 }))
                                 .child(subject_label),
                         )
@@ -1652,7 +1682,7 @@ impl GitGraph {
                     .px_1p5()
                     .gap_1()
                     .border_1()
-                    .border_color(color.border)
+                    .border_color(color.border_variant)
                     .rounded_md()
                     .bg(color.toolbar_background)
                     .on_action(cx.listener(Self::confirm_search))
@@ -1784,6 +1814,13 @@ impl GitGraph {
         let full_sha: SharedString = commit_entry.data.sha.to_string().into();
         let ref_names = commit_entry.data.ref_names.clone();
 
+        let head_branch_name: Option<SharedString> = repository
+            .read(cx)
+            .snapshot()
+            .branch
+            .as_ref()
+            .map(|branch| SharedString::from(branch.name().to_string()));
+
         let accent_colors = cx.theme().accents();
         let accent_color = accent_colors
             .0
@@ -1855,7 +1892,7 @@ impl GitGraph {
         v_flex()
             .min_w(px(300.))
             .h_full()
-            .bg(cx.theme().colors().surface_background)
+            .bg(cx.theme().colors().editor_background)
             .flex_basis(DefiniteLength::Fraction(
                 self.commit_details_split_state.read(cx).right_ratio(),
             ))
@@ -1898,9 +1935,10 @@ impl GitGraph {
                     )
                     .children((!ref_names.is_empty()).then(|| {
                         h_flex().gap_1().flex_wrap().justify_center().children(
-                            ref_names
-                                .iter()
-                                .map(|name| self.render_chip(name, accent_color)),
+                            ref_names.iter().map(|name| {
+                                let is_head = Self::is_head_ref(name.as_ref(), &head_branch_name);
+                                self.render_chip(name, accent_color, is_head)
+                            }),
                         )
                     }))
                     .child(
@@ -2059,6 +2097,8 @@ impl GitGraph {
                     .child(
                         h_flex()
                             .gap_1()
+                            .w_full()
+                            .justify_between()
                             .child(
                                 Label::new(format!("{} Changed Files", changed_files_count))
                                     .size(LabelSize::Small)
@@ -2110,7 +2150,7 @@ impl GitGraph {
                 h_flex().p_1p5().w_full().child(
                     Button::new("view-commit", "View Commit")
                         .full_width()
-                        .style(ButtonStyle::Outlined)
+                        .style(ButtonStyle::OutlinedGhost)
                         .on_click(cx.listener(|this, _, window, cx| {
                             this.open_selected_commit_view(window, cx);
                         })),

crates/ui/src/components/chip.rs 🔗

@@ -15,9 +15,12 @@ pub struct Chip {
     label: SharedString,
     label_color: Color,
     label_size: LabelSize,
+    icon: Option<IconName>,
+    icon_color: Color,
     bg_color: Option<Hsla>,
     border_color: Option<Hsla>,
     height: Option<Pixels>,
+    truncate: bool,
     tooltip: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyView + 'static>>,
 }
 
@@ -28,9 +31,12 @@ impl Chip {
             label: label.into(),
             label_color: Color::Default,
             label_size: LabelSize::XSmall,
+            icon: None,
+            icon_color: Color::Default,
             bg_color: None,
             border_color: None,
             height: None,
+            truncate: false,
             tooltip: None,
         }
     }
@@ -47,6 +53,18 @@ impl Chip {
         self
     }
 
+    /// Sets an icon to display before the label.
+    pub fn icon(mut self, icon: IconName) -> Self {
+        self.icon = Some(icon);
+        self
+    }
+
+    /// Sets the color of the icon.
+    pub fn icon_color(mut self, color: Color) -> Self {
+        self.icon_color = color;
+        self
+    }
+
     /// Sets a custom background color for the callout content.
     pub fn bg_color(mut self, color: Hsla) -> Self {
         self.bg_color = Some(color);
@@ -65,6 +83,12 @@ impl Chip {
         self
     }
 
+    /// Allows the chip to shrink and truncate its label when space is limited.
+    pub fn truncate(mut self) -> Self {
+        self.truncate = true;
+        self
+    }
+
     pub fn tooltip(mut self, tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static) -> Self {
         self.tooltip = Some(Box::new(tooltip));
         self
@@ -81,13 +105,22 @@ impl RenderOnce for Chip {
 
         h_flex()
             .when_some(self.height, |this, h| this.h(h))
-            .flex_none()
+            .when(self.truncate, |this| this.min_w_0())
+            .when(!self.truncate, |this| this.flex_none())
+            .gap_0p5()
             .px_1()
             .border_1()
             .rounded_sm()
             .border_color(border_color)
             .bg(bg_color)
             .overflow_hidden()
+            .when_some(self.icon, |this, icon| {
+                this.child(
+                    Icon::new(icon)
+                        .size(IconSize::XSmall)
+                        .color(self.icon_color),
+                )
+            })
             .child(
                 Label::new(self.label.clone())
                     .size(self.label_size)