workspace: Do not scan for .gitignore files if a .git directory is encountered along the way (#3135)

Partially fixes zed-industries/community#575

This PR will see one more fix to the case I've spotted while working on
this: namely, if a project has several nested repositories, e.g for a
structure:
/a
/a/.git/
/a/.gitignore
/a/b/
/a/b/.git/
/a/b/.gitignore

/b/ should not account for a's .gitignore at all - which is sort of
similar to the fix in commit #c416fbb, but for the paths in the project.

The release note is kinda bad, I'll try to reword it too.
- [ ] Improve release note.
- [x] Address the same bug for project files.

Release Notes:
- Fixed .gitignore files beyond the first .git directory being respected
by the worktree (zed-industries/community#575).
This commit is contained in:
Piotr Osiewicz 2023-10-17 18:56:03 +02:00 committed by GitHub
parent adabf0107f
commit 31241f48be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -2027,13 +2027,18 @@ impl LocalSnapshot {
fn ignore_stack_for_abs_path(&self, abs_path: &Path, is_dir: bool) -> Arc<IgnoreStack> { fn ignore_stack_for_abs_path(&self, abs_path: &Path, is_dir: bool) -> Arc<IgnoreStack> {
let mut new_ignores = Vec::new(); let mut new_ignores = Vec::new();
for ancestor in abs_path.ancestors().skip(1) { for (index, ancestor) in abs_path.ancestors().enumerate() {
if index > 0 {
if let Some((ignore, _)) = self.ignores_by_parent_abs_path.get(ancestor) { if let Some((ignore, _)) = self.ignores_by_parent_abs_path.get(ancestor) {
new_ignores.push((ancestor, Some(ignore.clone()))); new_ignores.push((ancestor, Some(ignore.clone())));
} else { } else {
new_ignores.push((ancestor, None)); new_ignores.push((ancestor, None));
} }
} }
if ancestor.join(&*DOT_GIT).is_dir() {
break;
}
}
let mut ignore_stack = IgnoreStack::none(); let mut ignore_stack = IgnoreStack::none();
for (parent_abs_path, ignore) in new_ignores.into_iter().rev() { for (parent_abs_path, ignore) in new_ignores.into_iter().rev() {
@ -2048,7 +2053,6 @@ impl LocalSnapshot {
if ignore_stack.is_abs_path_ignored(abs_path, is_dir) { if ignore_stack.is_abs_path_ignored(abs_path, is_dir) {
ignore_stack = IgnoreStack::all(); ignore_stack = IgnoreStack::all();
} }
ignore_stack ignore_stack
} }
@ -3064,8 +3068,10 @@ impl BackgroundScanner {
// Populate ignores above the root. // Populate ignores above the root.
let root_abs_path = self.state.lock().snapshot.abs_path.clone(); let root_abs_path = self.state.lock().snapshot.abs_path.clone();
for ancestor in root_abs_path.ancestors().skip(1) { for (index, ancestor) in root_abs_path.ancestors().enumerate() {
if let Ok(ignore) = build_gitignore(&ancestor.join(&*GITIGNORE), self.fs.as_ref()).await if index != 0 {
if let Ok(ignore) =
build_gitignore(&ancestor.join(&*GITIGNORE), self.fs.as_ref()).await
{ {
self.state self.state
.lock() .lock()
@ -3074,6 +3080,11 @@ impl BackgroundScanner {
.insert(ancestor.into(), (ignore.into(), false)); .insert(ancestor.into(), (ignore.into(), false));
} }
} }
if ancestor.join(&*DOT_GIT).is_dir() {
// Reached root of git repository.
break;
}
}
let (scan_job_tx, scan_job_rx) = channel::unbounded(); let (scan_job_tx, scan_job_rx) = channel::unbounded();
{ {