Only fetch statuses for changed paths

Max Brunsfeld created

Change summary

crates/fs/src/repository.rs    | 14 +++++++++-----
crates/project/src/worktree.rs |  9 ++++++---
2 files changed, 15 insertions(+), 8 deletions(-)

Detailed changes

crates/fs/src/repository.rs 🔗

@@ -27,7 +27,7 @@ pub trait GitRepository: Send {
     fn reload_index(&self);
     fn load_index_text(&self, relative_file_path: &Path) -> Option<String>;
     fn branch_name(&self) -> Option<String>;
-    fn statuses(&self) -> TreeMap<RepoPath, GitFileStatus>;
+    fn statuses(&self, path_prefix: &Path) -> TreeMap<RepoPath, GitFileStatus>;
     fn status(&self, path: &RepoPath) -> Result<Option<GitFileStatus>>;
     fn branches(&self) -> Result<Vec<Branch>>;
     fn change_branch(&self, _: &str) -> Result<()>;
@@ -78,9 +78,11 @@ impl GitRepository for LibGitRepository {
         Some(branch.to_string())
     }
 
-    fn statuses(&self) -> TreeMap<RepoPath, GitFileStatus> {
+    fn statuses(&self, path_prefix: &Path) -> TreeMap<RepoPath, GitFileStatus> {
         let mut map = TreeMap::default();
-        if let Some(statuses) = self.statuses(None).log_err() {
+        let mut options = git2::StatusOptions::new();
+        options.pathspec(path_prefix);
+        if let Some(statuses) = self.statuses(Some(&mut options)).log_err() {
             for status in statuses
                 .iter()
                 .filter(|status| !status.status().contains(git2::Status::IGNORED))
@@ -201,11 +203,13 @@ impl GitRepository for FakeGitRepository {
         state.branch_name.clone()
     }
 
-    fn statuses(&self) -> TreeMap<RepoPath, GitFileStatus> {
+    fn statuses(&self, path_prefix: &Path) -> TreeMap<RepoPath, GitFileStatus> {
         let mut map = TreeMap::default();
         let state = self.state.lock();
         for (repo_path, status) in state.worktree_statuses.iter() {
-            map.insert(repo_path.to_owned(), status.to_owned());
+            if repo_path.0.starts_with(path_prefix) {
+                map.insert(repo_path.to_owned(), status.to_owned());
+            }
         }
         map
     }

crates/project/src/worktree.rs 🔗

@@ -2165,7 +2165,10 @@ impl BackgroundScannerState {
         let mut containing_repository = None;
         if !ignore_stack.is_all() {
             if let Some((workdir_path, repo)) = self.snapshot.local_repo_for_path(&path) {
-                containing_repository = Some((workdir_path, repo.repo_ptr.lock().statuses()));
+                if let Ok(repo_path) = path.strip_prefix(&workdir_path.0) {
+                    containing_repository =
+                        Some((workdir_path, repo.repo_ptr.lock().statuses(repo_path)));
+                }
             }
         }
         if !ancestor_inodes.contains(&entry.inode) {
@@ -2357,7 +2360,7 @@ impl BackgroundScannerState {
                         .repository_entries
                         .update(&work_dir, |entry| entry.branch = branch.map(Into::into));
 
-                    let statuses = repository.statuses();
+                    let statuses = repository.statuses(Path::new(""));
                     self.update_git_statuses(&work_dir, &statuses);
                 }
             }
@@ -2415,7 +2418,7 @@ impl BackgroundScannerState {
             },
         );
 
-        let statuses = repo_lock.statuses();
+        let statuses = repo_lock.statuses(Path::new(""));
         self.update_git_statuses(&work_directory, &statuses);
         drop(repo_lock);