worktree: Do not scan for .gitignore files beyond project root. (#8189)

Piotr Osiewicz created

This has been fixed and reported before (and got lost in gpui1->gpui2
transition);
https://github.com/zed-industries/zed/issues/5749#issuecomment-1959217319

Release Notes:

- Fixed .gitignore files beyond the first .git directory being respected
by the worktree (zed-industries/zed#5749).

Change summary

crates/project/src/worktree.rs | 38 +++++++++++++++++++++++------------
1 file changed, 25 insertions(+), 13 deletions(-)

Detailed changes

crates/project/src/worktree.rs 🔗

@@ -2252,11 +2252,16 @@ impl LocalSnapshot {
 
     fn ignore_stack_for_abs_path(&self, abs_path: &Path, is_dir: bool) -> Arc<IgnoreStack> {
         let mut new_ignores = Vec::new();
-        for ancestor in abs_path.ancestors().skip(1) {
-            if let Some((ignore, _)) = self.ignores_by_parent_abs_path.get(ancestor) {
-                new_ignores.push((ancestor, Some(ignore.clone())));
-            } else {
-                new_ignores.push((ancestor, None));
+        for (index, ancestor) in abs_path.ancestors().enumerate() {
+            if index > 0 {
+                if let Some((ignore, _)) = self.ignores_by_parent_abs_path.get(ancestor) {
+                    new_ignores.push((ancestor, Some(ignore.clone())));
+                } else {
+                    new_ignores.push((ancestor, None));
+                }
+            }
+            if ancestor.join(&*DOT_GIT).is_dir() {
+                break;
             }
         }
 
@@ -3319,14 +3324,21 @@ impl BackgroundScanner {
 
         // Populate ignores above the root.
         let root_abs_path = self.state.lock().snapshot.abs_path.clone();
-        for ancestor in root_abs_path.ancestors().skip(1) {
-            if let Ok(ignore) = build_gitignore(&ancestor.join(&*GITIGNORE), self.fs.as_ref()).await
-            {
-                self.state
-                    .lock()
-                    .snapshot
-                    .ignores_by_parent_abs_path
-                    .insert(ancestor.into(), (ignore.into(), false));
+        for (index, ancestor) in root_abs_path.ancestors().enumerate() {
+            if index != 0 {
+                if let Ok(ignore) =
+                    build_gitignore(&ancestor.join(&*GITIGNORE), self.fs.as_ref()).await
+                {
+                    self.state
+                        .lock()
+                        .snapshot
+                        .ignores_by_parent_abs_path
+                        .insert(ancestor.into(), (ignore.into(), false));
+                }
+            }
+            if ancestor.join(&*DOT_GIT).is_dir() {
+                // Reached root of git repository.
+                break;
             }
         }