diff --git a/crates/worktree/src/worktree.rs b/crates/worktree/src/worktree.rs index 437dbcd451795ff0fdb88ed00b0d9e2e6c4be158..d848271976da0d66b70f4d96b52ebb5acc4f23c9 100644 --- a/crates/worktree/src/worktree.rs +++ b/crates/worktree/src/worktree.rs @@ -2665,10 +2665,21 @@ impl Snapshot { /// Get the repository whose work directory contains the given path. pub fn repository_for_path(&self, path: &Path) -> Option<&RepositoryEntry> { - self.repositories - .iter() - .filter(|repo| repo.work_directory.directory_contains(path)) - .last() + let mut cursor = self.repositories.cursor::(&()); + let mut repository = None; + + // Git repositories may contain other git repositories. As a side effect of + // lexicographic sorting by path, deeper repositories will be after higher repositories + // So, let's loop through every matching repository until we can't find any more to find + // the deepest repository that could contain this path. + while cursor.seek_forward(&PathTarget::Contains(path), Bias::Left, &()) + && cursor.item().is_some() + { + repository = cursor.item(); + cursor.next(&()); + } + + repository } /// Given an ordered iterator of entries, returns an iterator of those entries, @@ -5954,6 +5965,7 @@ impl<'a> Iterator for Traversal<'a> { enum PathTarget<'a> { Path(&'a Path), Successor(&'a Path), + Contains(&'a Path), } impl<'a> PathTarget<'a> { @@ -5967,6 +5979,13 @@ impl<'a> PathTarget<'a> { Ordering::Equal } } + PathTarget::Contains(path) => { + if path.starts_with(other) { + Ordering::Equal + } else { + Ordering::Greater + } + } } } }