@@ -135,6 +135,7 @@ pub trait Fs: Send + Sync {
Arc<dyn Watcher>,
);
+ fn home_dir(&self) -> Option<PathBuf>;
fn open_repo(&self, abs_dot_git: &Path) -> Option<Arc<dyn GitRepository>>;
fn is_fake(&self) -> bool;
async fn is_case_sensitive(&self) -> Result<bool>;
@@ -813,6 +814,10 @@ impl Fs for RealFs {
temp_dir.close()?;
case_sensitive
}
+
+ fn home_dir(&self) -> Option<PathBuf> {
+ Some(paths::home_dir().clone())
+ }
}
#[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
@@ -846,6 +851,7 @@ struct FakeFsState {
metadata_call_count: usize,
read_dir_call_count: usize,
moves: std::collections::HashMap<u64, PathBuf>,
+ home_dir: Option<PathBuf>,
}
#[cfg(any(test, feature = "test-support"))]
@@ -1031,6 +1037,7 @@ impl FakeFs {
read_dir_call_count: 0,
metadata_call_count: 0,
moves: Default::default(),
+ home_dir: None,
}),
});
@@ -1524,6 +1531,10 @@ impl FakeFs {
fn simulate_random_delay(&self) -> impl futures::Future<Output = ()> {
self.executor.simulate_random_delay()
}
+
+ pub fn set_home_dir(&self, home_dir: PathBuf) {
+ self.state.lock().home_dir = Some(home_dir);
+ }
}
#[cfg(any(test, feature = "test-support"))]
@@ -2079,6 +2090,10 @@ impl Fs for FakeFs {
fn as_fake(&self) -> Arc<FakeFs> {
self.this.upgrade().unwrap()
}
+
+ fn home_dir(&self) -> Option<PathBuf> {
+ self.state.lock().home_dir.clone()
+ }
}
fn chunks(rope: &Rope, line_ending: LineEnding) -> impl Iterator<Item = &str> {
@@ -4292,7 +4292,11 @@ impl BackgroundScanner {
let mut containing_git_repository = None;
for (index, ancestor) in root_abs_path.as_path().ancestors().enumerate() {
if index != 0 {
- if let Ok(ignore) =
+ if Some(ancestor) == self.fs.home_dir().as_deref() {
+ // Unless $HOME is itself the worktree root, don't consider it as a
+ // containing git repository---expensive and likely unwanted.
+ break;
+ } else if let Ok(ignore) =
build_gitignore(&ancestor.join(*GITIGNORE), self.fs.as_ref()).await
{
self.state
@@ -2241,6 +2241,73 @@ async fn test_rename_work_directory(cx: &mut TestAppContext) {
});
}
+#[gpui::test]
+async fn test_home_dir_as_git_repository(cx: &mut TestAppContext) {
+ init_test(cx);
+ cx.executor().allow_parking();
+ let fs = FakeFs::new(cx.background_executor.clone());
+ fs.insert_tree(
+ "/root",
+ json!({
+ "home": {
+ ".git": {},
+ "project": {
+ "a.txt": "A"
+ },
+ },
+ }),
+ )
+ .await;
+ fs.set_home_dir(Path::new(path!("/root/home")).to_owned());
+
+ let tree = Worktree::local(
+ Path::new(path!("/root/home/project")),
+ true,
+ fs.clone(),
+ Default::default(),
+ &mut cx.to_async(),
+ )
+ .await
+ .unwrap();
+
+ cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
+ .await;
+ tree.flush_fs_events(cx).await;
+
+ tree.read_with(cx, |tree, _cx| {
+ let tree = tree.as_local().unwrap();
+
+ let repo = tree.repository_for_path(path!("a.txt").as_ref());
+ assert!(repo.is_none());
+ });
+
+ let home_tree = Worktree::local(
+ Path::new(path!("/root/home")),
+ true,
+ fs.clone(),
+ Default::default(),
+ &mut cx.to_async(),
+ )
+ .await
+ .unwrap();
+
+ cx.read(|cx| home_tree.read(cx).as_local().unwrap().scan_complete())
+ .await;
+ home_tree.flush_fs_events(cx).await;
+
+ home_tree.read_with(cx, |home_tree, _cx| {
+ let home_tree = home_tree.as_local().unwrap();
+
+ let repo = home_tree.repository_for_path(path!("project/a.txt").as_ref());
+ assert_eq!(
+ repo.map(|repo| &repo.work_directory),
+ Some(&WorkDirectory::InProject {
+ relative_path: Path::new("").into()
+ })
+ );
+ })
+}
+
#[gpui::test]
async fn test_git_repository_for_path(cx: &mut TestAppContext) {
init_test(cx);