Fix adding new git repos to a project (#24471)

Conrad Irwin created

Release Notes:

- N/A

Change summary

crates/git_ui/src/git_panel.rs  |  6 +++++-
crates/util/src/paths.rs        |  2 +-
crates/worktree/src/worktree.rs | 18 +++++++++++++++---
3 files changed, 21 insertions(+), 5 deletions(-)

Detailed changes

crates/git_ui/src/git_panel.rs 🔗

@@ -1243,7 +1243,11 @@ impl GitPanel {
             .child(
                 v_flex()
                     .gap_3()
-                    .child("No changes to commit")
+                    .child(if self.active_repository.is_some() {
+                        "No changes to commit"
+                    } else {
+                        "No Git repositories"
+                    })
                     .text_ui_sm(cx)
                     .mx_auto()
                     .text_color(Color::Placeholder.color(cx)),

crates/util/src/paths.rs 🔗

@@ -105,7 +105,7 @@ impl<T: AsRef<Path>> PathExt for T {
 /// leverages Rust's type system to ensure that all paths entering Zed are always "sanitized" by removing the `\\\\?\\` prefix.
 /// On non-Windows operating systems, this struct is effectively a no-op.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct SanitizedPath(Arc<Path>);
+pub struct SanitizedPath(pub Arc<Path>);
 
 impl SanitizedPath {
     pub fn starts_with(&self, prefix: &SanitizedPath) -> bool {

crates/worktree/src/worktree.rs 🔗

@@ -2817,6 +2817,7 @@ impl Snapshot {
 
     pub fn entry_for_path(&self, path: impl AsRef<Path>) -> Option<&Entry> {
         let path = path.as_ref();
+        debug_assert!(path.is_relative());
         self.traverse_from_path(true, true, true, path)
             .entry()
             .and_then(|entry| {
@@ -4384,6 +4385,13 @@ impl BackgroundScanner {
                         dot_git_abs_paths.push(dot_git_abs_path);
                     }
                 }
+                if abs_path.0.file_name() == Some(*GITIGNORE) {
+                    for (_, repo) in snapshot.git_repositories.iter().filter(|(_, repo)| repo.directory_contains(&abs_path.0)) {
+                        if !dot_git_abs_paths.iter().any(|dot_git_abs_path| dot_git_abs_path == repo.dot_git_dir_abs_path.as_ref()) {
+                            dot_git_abs_paths.push(repo.dot_git_dir_abs_path.to_path_buf());
+                        }
+                    }
+                }
 
                 let relative_path: Arc<Path> =
                     if let Ok(path) = abs_path.strip_prefix(&root_canonical_path) {
@@ -5169,8 +5177,12 @@ impl BackgroundScanner {
 
                 let local_repository = match existing_repository_entry {
                     None => {
+                        let Ok(relative) = dot_git_dir.strip_prefix(state.snapshot.abs_path())
+                        else {
+                            return;
+                        };
                         match state.insert_git_repository(
-                            dot_git_dir.into(),
+                            relative.into(),
                             self.fs.as_ref(),
                             self.watcher.as_ref(),
                         ) {
@@ -5299,8 +5311,8 @@ impl BackgroundScanner {
         let Some(mut repository) =
             snapshot.repository(job.local_repository.work_directory.path_key())
         else {
-            log::error!("Got an UpdateGitStatusesJob for a repository that isn't in the snapshot");
-            debug_assert!(false);
+            // happens when a folder is deleted
+            log::debug!("Got an UpdateGitStatusesJob for a repository that isn't in the snapshot");
             return;
         };