Revert "git: Use worktree paths in the panel (#25950)" (#25995)

Cole Miller created

This reverts commit e7b3b8bf03f5f8693f8c330b98b656b16ab8f931.

Release Notes:

- N/A

Change summary

Cargo.lock                     |   1 
crates/git_ui/Cargo.toml       |   1 
crates/git_ui/src/git_panel.rs | 313 ++++++++++-------------------------
crates/zed/src/zed.rs          |   6 
4 files changed, 92 insertions(+), 229 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -5439,7 +5439,6 @@ dependencies = [
  "panel",
  "picker",
  "postage",
- "pretty_assertions",
  "project",
  "schemars",
  "serde",

crates/git_ui/Cargo.toml 🔗

@@ -61,7 +61,6 @@ ctor.workspace = true
 env_logger.workspace = true
 editor = { workspace = true, features = ["test-support"] }
 gpui = { workspace = true, features = ["test-support"] }
-pretty_assertions.workspace = true
 project = { workspace = true, features = ["test-support"] }
 settings = { workspace = true, features = ["test-support"] }
 unindent.workspace = true

crates/git_ui/src/git_panel.rs 🔗

@@ -18,14 +18,7 @@ use git::repository::{
 };
 use git::{repository::RepoPath, status::FileStatus, Commit, ToggleStaged};
 use git::{RestoreTrackedFiles, StageAll, TrashUntrackedFiles, UnstageAll};
-use gpui::{
-    actions, anchored, deferred, hsla, percentage, point, uniform_list, Action, Animation,
-    AnimationExt as _, AnyView, BoxShadow, ClickEvent, Corner, DismissEvent, Entity, EventEmitter,
-    FocusHandle, Focusable, KeyContext, ListHorizontalSizingBehavior, ListSizingBehavior,
-    Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, Point, PromptLevel,
-    ScrollStrategy, Stateful, Subscription, Task, Transformation, UniformListScrollHandle,
-    WeakEntity,
-};
+use gpui::*;
 use itertools::Itertools;
 use language::{Buffer, File};
 use menu::{Confirm, SecondaryConfirm, SelectFirst, SelectLast, SelectNext, SelectPrevious};
@@ -42,7 +35,6 @@ use settings::Settings as _;
 use smallvec::smallvec;
 use std::cell::RefCell;
 use std::future::Future;
-use std::path::Path;
 use std::rc::Rc;
 use std::{collections::HashSet, sync::Arc, time::Duration, usize};
 use strum::{IntoEnumIterator, VariantNames};
@@ -52,7 +44,6 @@ use ui::{
     Scrollbar, ScrollbarState, Tooltip,
 };
 use util::{maybe, post_inc, ResultExt, TryFutureExt};
-use workspace::AppState;
 
 use workspace::{
     dock::{DockPosition, Panel, PanelEvent},
@@ -72,12 +63,7 @@ actions!(
     ]
 );
 
-fn prompt<T>(
-    msg: &str,
-    detail: Option<&str>,
-    window: &mut Window,
-    cx: &mut App,
-) -> Task<anyhow::Result<T>>
+fn prompt<T>(msg: &str, detail: Option<&str>, window: &mut Window, cx: &mut App) -> Task<Result<T>>
 where
     T: IntoEnumIterator + VariantNames + 'static,
 {
@@ -179,7 +165,6 @@ impl GitListEntry {
 #[derive(Debug, PartialEq, Eq, Clone)]
 pub struct GitStatusEntry {
     pub(crate) repo_path: RepoPath,
-    pub(crate) worktree_path: Arc<Path>,
     pub(crate) status: FileStatus,
     pub(crate) is_staged: Option<bool>,
 }
@@ -277,94 +262,96 @@ pub(crate) fn commit_message_editor(
 
 impl GitPanel {
     pub fn new(
-        workspace: Entity<Workspace>,
-        project: Entity<Project>,
-        app_state: Arc<AppState>,
+        workspace: &mut Workspace,
         window: &mut Window,
-        cx: &mut Context<Self>,
-    ) -> Self {
-        let fs = app_state.fs.clone();
+        cx: &mut Context<Workspace>,
+    ) -> Entity<Self> {
+        let fs = workspace.app_state().fs.clone();
+        let project = workspace.project().clone();
         let git_store = project.read(cx).git_store().clone();
         let active_repository = project.read(cx).active_repository(cx);
-        let workspace = workspace.downgrade();
-
-        let focus_handle = cx.focus_handle();
-        cx.on_focus(&focus_handle, window, Self::focus_in).detach();
-        cx.on_focus_out(&focus_handle, window, |this, _, window, cx| {
-            this.hide_scrollbar(window, cx);
-        })
-        .detach();
+        let workspace = cx.entity().downgrade();
 
-        // just to let us render a placeholder editor.
-        // Once the active git repo is set, this buffer will be replaced.
-        let temporary_buffer = cx.new(|cx| Buffer::local("", cx));
-        let commit_editor = cx.new(|cx| {
-            commit_message_editor(temporary_buffer, None, project.clone(), true, window, cx)
-        });
-
-        commit_editor.update(cx, |editor, cx| {
-            editor.clear(window, cx);
-        });
+        cx.new(|cx| {
+            let focus_handle = cx.focus_handle();
+            cx.on_focus(&focus_handle, window, Self::focus_in).detach();
+            cx.on_focus_out(&focus_handle, window, |this, _, window, cx| {
+                this.hide_scrollbar(window, cx);
+            })
+            .detach();
 
-        let scroll_handle = UniformListScrollHandle::new();
+            // just to let us render a placeholder editor.
+            // Once the active git repo is set, this buffer will be replaced.
+            let temporary_buffer = cx.new(|cx| Buffer::local("", cx));
+            let commit_editor = cx.new(|cx| {
+                commit_message_editor(temporary_buffer, None, project.clone(), true, window, cx)
+            });
 
-        cx.subscribe_in(
-            &git_store,
-            window,
-            move |this, git_store, event, window, cx| match event {
-                GitEvent::FileSystemUpdated => {
-                    this.schedule_update(false, window, cx);
-                }
-                GitEvent::ActiveRepositoryChanged | GitEvent::GitStateUpdated => {
-                    this.active_repository = git_store.read(cx).active_repository();
-                    this.schedule_update(true, window, cx);
-                }
-            },
-        )
-        .detach();
+            commit_editor.update(cx, |editor, cx| {
+                editor.clear(window, cx);
+            });
 
-        let scrollbar_state =
-            ScrollbarState::new(scroll_handle.clone()).parent_entity(&cx.entity());
+            let scroll_handle = UniformListScrollHandle::new();
 
-        let repository_selector = cx.new(|cx| RepositorySelector::new(project.clone(), window, cx));
+            cx.subscribe_in(
+                &git_store,
+                window,
+                move |this, git_store, event, window, cx| match event {
+                    GitEvent::FileSystemUpdated => {
+                        this.schedule_update(false, window, cx);
+                    }
+                    GitEvent::ActiveRepositoryChanged | GitEvent::GitStateUpdated => {
+                        this.active_repository = git_store.read(cx).active_repository();
+                        this.schedule_update(true, window, cx);
+                    }
+                },
+            )
+            .detach();
 
-        let mut git_panel = Self {
-            pending_remote_operations: Default::default(),
-            remote_operation_id: 0,
-            active_repository,
-            commit_editor,
-            suggested_commit_message: None,
-            conflicted_count: 0,
-            conflicted_staged_count: 0,
-            current_modifiers: window.modifiers(),
-            add_coauthors: true,
-            entries: Vec::new(),
-            focus_handle: cx.focus_handle(),
-            fs,
-            hide_scrollbar_task: None,
-            new_count: 0,
-            new_staged_count: 0,
-            pending: Vec::new(),
-            pending_commit: None,
-            pending_serialization: Task::ready(None),
-            project,
-            repository_selector,
-            scroll_handle,
-            scrollbar_state,
-            selected_entry: None,
-            marked_entries: Vec::new(),
-            show_scrollbar: false,
-            tracked_count: 0,
-            tracked_staged_count: 0,
-            update_visible_entries_task: Task::ready(()),
-            width: Some(px(360.)),
-            context_menu: None,
-            workspace,
-            modal_open: false,
-        };
-        git_panel.schedule_update(false, window, cx);
-        git_panel.show_scrollbar = git_panel.should_show_scrollbar(cx);
-        git_panel
+            let scrollbar_state =
+                ScrollbarState::new(scroll_handle.clone()).parent_entity(&cx.entity());
+
+            let repository_selector =
+                cx.new(|cx| RepositorySelector::new(project.clone(), window, cx));
+
+            let mut git_panel = Self {
+                pending_remote_operations: Default::default(),
+                remote_operation_id: 0,
+                active_repository,
+                commit_editor,
+                suggested_commit_message: None,
+                conflicted_count: 0,
+                conflicted_staged_count: 0,
+                current_modifiers: window.modifiers(),
+                add_coauthors: true,
+                entries: Vec::new(),
+                focus_handle: cx.focus_handle(),
+                fs,
+                hide_scrollbar_task: None,
+                new_count: 0,
+                new_staged_count: 0,
+                pending: Vec::new(),
+                pending_commit: None,
+                pending_serialization: Task::ready(None),
+                project,
+                repository_selector,
+                scroll_handle,
+                scrollbar_state,
+                selected_entry: None,
+                marked_entries: Vec::new(),
+                show_scrollbar: false,
+                tracked_count: 0,
+                tracked_staged_count: 0,
+                update_visible_entries_task: Task::ready(()),
+                width: Some(px(360.)),
+                context_menu: None,
+                workspace,
+                modal_open: false,
+            };
+            git_panel.schedule_update(false, window, cx);
+            git_panel.show_scrollbar = git_panel.should_show_scrollbar(cx);
+            git_panel
+        })
     }
 
     pub fn entry_by_path(&self, path: &RepoPath) -> Option<usize> {
@@ -1489,7 +1476,7 @@ impl GitPanel {
         &mut self,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> impl Future<Output = anyhow::Result<Option<Remote>>> {
+    ) -> impl Future<Output = Result<Option<Remote>>> {
         let repo = self.active_repository.clone();
         let workspace = self.workspace.clone();
         let mut cx = window.to_async(cx);
@@ -1726,8 +1713,10 @@ impl GitPanel {
             return;
         };
 
+        // First pass - collect all paths
         let repo = repo.read(cx);
 
+        // Second pass - create entries with proper depth calculation
         for entry in repo.status() {
             let is_conflict = repo.has_conflict(&entry.repo_path);
             let is_new = entry.status.is_created();
@@ -1741,12 +1730,8 @@ impl GitPanel {
                 continue;
             }
 
-            let Some(worktree_path) = repo.repository_entry.unrelativize(&entry.repo_path) else {
-                continue;
-            };
             let entry = GitStatusEntry {
                 repo_path: entry.repo_path.clone(),
-                worktree_path,
                 status: entry.status,
                 is_staged,
             };
@@ -2394,7 +2379,7 @@ impl GitPanel {
         &self,
         sha: &str,
         cx: &mut Context<Self>,
-    ) -> Task<anyhow::Result<CommitDetails>> {
+    ) -> Task<Result<CommitDetails>> {
         let Some(repo) = self.active_repository.clone() else {
             return Task::ready(Err(anyhow::anyhow!("no active repo")));
         };
@@ -2479,12 +2464,12 @@ impl GitPanel {
         cx: &Context<Self>,
     ) -> AnyElement {
         let display_name = entry
-            .worktree_path
+            .repo_path
             .file_name()
             .map(|name| name.to_string_lossy().into_owned())
-            .unwrap_or_else(|| entry.worktree_path.to_string_lossy().into_owned());
+            .unwrap_or_else(|| entry.repo_path.to_string_lossy().into_owned());
 
-        let worktree_path = entry.worktree_path.clone();
+        let repo_path = entry.repo_path.clone();
         let selected = self.selected_entry == Some(ix);
         let marked = self.marked_entries.contains(&ix);
         let status_style = GitPanelSettings::get_global(cx).status_style;
@@ -2655,7 +2640,7 @@ impl GitPanel {
                 h_flex()
                     .items_center()
                     .overflow_hidden()
-                    .when_some(worktree_path.parent(), |this, parent| {
+                    .when_some(repo_path.parent(), |this, parent| {
                         let parent_str = parent.to_string_lossy();
                         if !parent_str.is_empty() {
                             this.child(
@@ -3703,119 +3688,3 @@ impl ComponentPreview for PanelRepoFooter {
             .into_any_element()
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use git::status::StatusCode;
-    use gpui::TestAppContext;
-    use project::{FakeFs, WorktreeSettings};
-    use serde_json::json;
-    use settings::SettingsStore;
-    use theme::LoadThemes;
-    use util::path;
-
-    use super::*;
-
-    fn init_test(cx: &mut gpui::TestAppContext) {
-        if std::env::var("RUST_LOG").is_ok() {
-            env_logger::try_init().ok();
-        }
-
-        cx.update(|cx| {
-            let settings_store = SettingsStore::test(cx);
-            cx.set_global(settings_store);
-            WorktreeSettings::register(cx);
-            workspace::init_settings(cx);
-            theme::init(LoadThemes::JustBase, cx);
-            language::init(cx);
-            editor::init(cx);
-            Project::init_settings(cx);
-            crate::init(cx);
-        });
-    }
-
-    #[gpui::test]
-    async fn test_entry_worktree_paths(cx: &mut TestAppContext) {
-        init_test(cx);
-        let fs = FakeFs::new(cx.background_executor.clone());
-        fs.insert_tree(
-            "/root",
-            json!({
-                "zed": {
-                    ".git": {},
-                    "crates": {
-                        "gpui": {
-                            "gpui.rs": "fn main() {}"
-                        },
-                        "util": {
-                            "util.rs": "fn do_it() {}"
-                        }
-                    }
-                },
-            }),
-        )
-        .await;
-
-        fs.set_status_for_repo_via_git_operation(
-            Path::new("/root/zed/.git"),
-            &[
-                (
-                    Path::new("crates/gpui/gpui.rs"),
-                    StatusCode::Modified.worktree(),
-                ),
-                (
-                    Path::new("crates/util/util.rs"),
-                    StatusCode::Modified.worktree(),
-                ),
-            ],
-        );
-
-        let project =
-            Project::test(fs.clone(), [path!("/root/zed/crates/gpui").as_ref()], cx).await;
-        let (workspace, cx) =
-            cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
-
-        cx.read(|cx| {
-            project
-                .read(cx)
-                .worktrees(cx)
-                .nth(0)
-                .unwrap()
-                .read(cx)
-                .as_local()
-                .unwrap()
-                .scan_complete()
-        })
-        .await;
-
-        cx.executor().run_until_parked();
-
-        let app_state = workspace.update(cx, |workspace, _| workspace.app_state().clone());
-        let panel = cx.new_window_entity(|window, cx| {
-            GitPanel::new(workspace, project, app_state, window, cx)
-        });
-
-        let handle = cx.update_window_entity(&panel, |panel, window, cx| {
-            panel.schedule_update(false, window, cx);
-            std::mem::replace(&mut panel.update_visible_entries_task, Task::ready(()))
-        });
-        cx.executor().advance_clock(2 * UPDATE_DEBOUNCE);
-        handle.await;
-
-        let entries = panel.update(cx, |panel, _| panel.entries.clone());
-        pretty_assertions::assert_eq!(
-            entries,
-            [
-                GitListEntry::Header(GitHeaderEntry {
-                    header: Section::Tracked
-                }),
-                GitListEntry::GitStatusEntry(GitStatusEntry {
-                    repo_path: "crates/gpui/gpui.rs".into(),
-                    worktree_path: Path::new("gpui.rs").into(),
-                    status: StatusCode::Modified.worktree(),
-                    is_staged: Some(false),
-                })
-            ],
-        )
-    }
-}

crates/zed/src/zed.rs 🔗

@@ -22,7 +22,6 @@ use editor::ProposedChangesEditorToolbar;
 use editor::{scroll::Autoscroll, Editor, MultiBuffer};
 use feature_flags::{FeatureFlagAppExt, FeatureFlagViewExt, GitUiFeatureFlag};
 use futures::{channel::mpsc, select_biased, StreamExt};
-use git_ui::git_panel::GitPanel;
 use git_ui::project_diff::ProjectDiffToolbar;
 use gpui::{
     actions, point, px, Action, App, AppContext as _, AsyncApp, Context, DismissEvent, Element,
@@ -430,10 +429,7 @@ fn initialize_panels(
             workspace.add_panel(chat_panel, window, cx);
             workspace.add_panel(notification_panel, window, cx);
             cx.when_flag_enabled::<GitUiFeatureFlag>(window, |workspace, window, cx| {
-                let entity = cx.entity();
-                let project = workspace.project().clone();
-                let app_state = workspace.app_state().clone();
-                let git_panel = cx.new(|cx| GitPanel::new(entity, project, app_state, window, cx));
+                let git_panel = git_ui::git_panel::GitPanel::new(workspace, window, cx);
                 workspace.add_panel(git_panel, window, cx);
             });
         })?;