diff --git a/crates/project/src/git_repository.rs b/crates/project/src/git_repository.rs index d1df841fe71d4e55d55d37731b25167a428ce42b..73f7130e56da9fbcfc2f2210a70f90ecf1f87f46 100644 --- a/crates/project/src/git_repository.rs +++ b/crates/project/src/git_repository.rs @@ -56,7 +56,7 @@ impl GitRepository { self.last_scan_id = scan_id; } - pub fn with_repo(&mut self, f: Box) { + pub fn with_repo(&mut self, f: F) { let mut git2 = self.libgit_repository.lock(); f(&mut git2) } diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index ee54fdb394155afa2ffb2ade5dd4cb6fced269df..a9ebfd8612944b7f2315bf98b4d0719f0041be07 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -1311,9 +1311,7 @@ impl LocalSnapshot { self.git_repositories .iter() .rev() //git_repository is ordered lexicographically - .find(|repo| { - repo.is_path_managed_by(&self.abs_path.join(path)) - }) + .find(|repo| repo.is_path_managed_by(&self.abs_path.join(path))) .map(|repo| repo.clone()) } @@ -2548,13 +2546,16 @@ impl BackgroundScanner { } async fn update_git_repositories(&self) { - let mut snapshot = self.snapshot(); - let mut git_repositories = mem::take(&mut snapshot.git_repositories); - git_repositories.retain(|git_repository| { - let dot_git_path = git_repository.content_path().join(&*DOT_GIT); - snapshot.entry_for_path(dot_git_path).is_some() - }); - snapshot.git_repositories = git_repositories; + let mut snapshot = self.snapshot.lock(); + + let new_repos = snapshot + .git_repositories + .iter() + .cloned() + .filter(|repo| git2::Repository::open(repo.git_dir_path()).is_ok()) + .collect(); + + snapshot.git_repositories = new_repos; } async fn update_ignore_status(&self, job: UpdateIgnoreStatusJob, snapshot: &LocalSnapshot) { @@ -3179,30 +3180,59 @@ mod tests { .git_repository_for_file_path("dir1/src/b.txt".as_ref()) .unwrap(); - // Need to update the file system for anything involving git - // Goal: Make this test pass - // Up Next: Invalidating git repos! - assert_eq!(repo.content_path(), root.path().join("dir1").canonicalize().unwrap()); - assert_eq!(repo.git_dir_path(), root.path().join("dir1/.git").canonicalize().unwrap()); + assert_eq!( + repo.content_path(), + root.path().join("dir1").canonicalize().unwrap() + ); + assert_eq!( + repo.git_dir_path(), + root.path().join("dir1/.git").canonicalize().unwrap() + ); let repo = tree .git_repository_for_file_path("dir1/deps/dep1/src/a.txt".as_ref()) .unwrap(); - assert_eq!(repo.content_path(), root.path().join("dir1/deps/dep1").canonicalize().unwrap()); - assert_eq!(repo.git_dir_path(), root.path().join("dir1/deps/dep1/.git").canonicalize().unwrap()); + assert_eq!( + repo.content_path(), + root.path().join("dir1/deps/dep1").canonicalize().unwrap() + ); + assert_eq!( + repo.git_dir_path(), + root.path() + .join("dir1/deps/dep1/.git") + .canonicalize() + .unwrap() + ); let repo = tree .git_repository_for_git_data("dir1/.git/HEAD".as_ref()) .unwrap(); - assert_eq!(repo.content_path(), root.path().join("dir1").canonicalize().unwrap()); - assert_eq!(repo.git_dir_path(), root.path().join("dir1/.git").canonicalize().unwrap()); + assert_eq!( + repo.content_path(), + root.path().join("dir1").canonicalize().unwrap() + ); + assert_eq!( + repo.git_dir_path(), + root.path().join("dir1/.git").canonicalize().unwrap() + ); assert!(tree.does_git_repository_track_file_path(&repo, "dir1/src/b.txt".as_ref())); assert!(!tree .does_git_repository_track_file_path(&repo, "dir1/deps/dep1/src/a.txt".as_ref())); }); + + std::fs::remove_dir_all(root.path().join("dir1/.git")).unwrap(); + tree.flush_fs_events(cx).await; + + tree.read_with(cx, |tree, _cx| { + let tree = tree.as_local().unwrap(); + + assert!(tree + .git_repository_for_file_path("dir1/src/b.txt".as_ref()) + .is_none()); + }); } #[gpui::test]