diff --git a/crates/fs/Cargo.toml b/crates/fs/Cargo.toml index bf47e0ee135..3e5f5dcad2f 100644 --- a/crates/fs/Cargo.toml +++ b/crates/fs/Cargo.toml @@ -15,7 +15,7 @@ test = false [[test]] name = "integration" required-features = ["test-support"] -path = "tests/integration/main.rs" +path = "tests/integration/fs_tests.rs" [dependencies] anyhow.workspace = true diff --git a/crates/fs/tests/integration/fake_git_repo.rs b/crates/fs/tests/integration/fake_git_repo_tests.rs similarity index 100% rename from crates/fs/tests/integration/fake_git_repo.rs rename to crates/fs/tests/integration/fake_git_repo_tests.rs diff --git a/crates/fs/tests/integration/fs.rs b/crates/fs/tests/integration/fs_tests.rs similarity index 99% rename from crates/fs/tests/integration/fs.rs rename to crates/fs/tests/integration/fs_tests.rs index b27e4113fd6..d86fadd46db 100644 --- a/crates/fs/tests/integration/fs.rs +++ b/crates/fs/tests/integration/fs_tests.rs @@ -1,3 +1,5 @@ +mod fake_git_repo_tests; + use std::{ collections::BTreeSet, ffi::OsString, diff --git a/crates/fs/tests/integration/main.rs b/crates/fs/tests/integration/main.rs deleted file mode 100644 index 7608563d7df..00000000000 --- a/crates/fs/tests/integration/main.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod fake_git_repo; -mod fs; diff --git a/crates/worktree/Cargo.toml b/crates/worktree/Cargo.toml index 5aac6f24173..9a95eec9697 100644 --- a/crates/worktree/Cargo.toml +++ b/crates/worktree/Cargo.toml @@ -13,7 +13,7 @@ test = false [[test]] name = "integration" required-features = ["test-support"] -path = "tests/integration/main.rs" +path = "tests/integration/worktree_tests.rs" [lints] workspace = true diff --git a/crates/worktree/src/worktree.rs b/crates/worktree/src/worktree.rs index 6b0f5a04ba0..ce2f34bc78d 100644 --- a/crates/worktree/src/worktree.rs +++ b/crates/worktree/src/worktree.rs @@ -4391,7 +4391,7 @@ impl BackgroundScanner { // // Certain directories may have FS changes, but do not lead to git data changes that Zed cares about. // Ignore these, to avoid Zed unnecessarily rescanning git metadata. - let skipped_files_in_dot_git = [COMMIT_MESSAGE, INDEX_LOCK]; + let skipped_file_names_in_dot_git = [COMMIT_MESSAGE, INDEX_LOCK]; let skipped_dirs_in_dot_git = [FSMONITOR_DAEMON, LFS_DIR]; let mut dot_git_abs_paths = Vec::new(); @@ -4421,8 +4421,10 @@ impl BackgroundScanner { } if let Some((dot_git_abs_path, path_in_git_dir)) = dot_git_paths { - let is_ignored = skipped_files_in_dot_git.iter().any(|skipped| { - OsStr::new(skipped) == path_in_git_dir.as_path().as_os_str() + let is_ignored = skipped_file_names_in_dot_git.iter().any(|skipped| { + path_in_git_dir + .file_name() + .is_some_and(|file_name| file_name == OsStr::new(skipped)) }) || skipped_dirs_in_dot_git .iter() .any(|skipped_git_subdir| path_in_git_dir.starts_with(skipped_git_subdir)); diff --git a/crates/worktree/tests/integration/worktree_settings.rs b/crates/worktree/tests/integration/worktree_settings_tests.rs similarity index 100% rename from crates/worktree/tests/integration/worktree_settings.rs rename to crates/worktree/tests/integration/worktree_settings_tests.rs diff --git a/crates/worktree/tests/integration/main.rs b/crates/worktree/tests/integration/worktree_tests.rs similarity index 98% rename from crates/worktree/tests/integration/main.rs rename to crates/worktree/tests/integration/worktree_tests.rs index f8e07ffa0b4..2ae248ad0e4 100644 --- a/crates/worktree/tests/integration/main.rs +++ b/crates/worktree/tests/integration/worktree_tests.rs @@ -1,4 +1,4 @@ -mod worktree_settings; +mod worktree_settings_tests; use anyhow::Result; use encoding_rs; @@ -3404,6 +3404,89 @@ async fn test_linked_worktree_git_file_event_does_not_panic( }); } +#[gpui::test] +async fn test_linked_worktree_index_lock_event_does_not_emit_git_repo_update( + executor: BackgroundExecutor, + cx: &mut TestAppContext, +) { + // Regression test: in a linked worktree, git operations like `git status` + // can touch the worktree-specific `index.lock` under the main repo's + // `.git/worktrees//`. We intend to ignore those events so they do not + // spuriously emit `UpdatedGitRepositories`. + init_test(cx); + + use git::repository::Worktree as GitWorktree; + + let fs = FakeFs::new(executor); + + fs.insert_tree( + path!("/main_repo"), + json!({ + ".git": {}, + "file.txt": "content", + }), + ) + .await; + fs.add_linked_worktree_for_repo( + Path::new(path!("/main_repo/.git")), + false, + GitWorktree { + path: PathBuf::from(path!("/linked_worktree")), + ref_name: Some("refs/heads/feature".into()), + sha: "abc123".into(), + is_main: false, + is_bare: false, + }, + ) + .await; + fs.write( + path!("/linked_worktree/file.txt").as_ref(), + "content".as_bytes(), + ) + .await + .unwrap(); + + let tree = Worktree::local( + path!("/linked_worktree").as_ref(), + true, + fs.clone(), + Arc::default(), + true, + WorktreeId::from_proto(0), + &mut cx.to_async(), + ) + .await + .unwrap(); + tree.update(cx, |tree, _| tree.as_local().unwrap().scan_complete()) + .await; + cx.run_until_parked(); + + let repo_update_count: Rc> = Rc::new(Cell::new(0)); + tree.update(cx, { + let repo_update_count = repo_update_count.clone(); + |_, cx| { + cx.subscribe(&cx.entity(), move |_, _, event, _| { + if matches!(event, Event::UpdatedGitRepositories(_)) { + repo_update_count.set(repo_update_count.get() + 1); + } + }) + .detach(); + } + }); + + fs.emit_fs_event( + path!("/main_repo/.git/worktrees/feature/index.lock"), + Some(PathEventKind::Changed), + ); + cx.run_until_parked(); + + assert_eq!( + repo_update_count.get(), + 0, + "linked-worktree index.lock events should not emit UpdatedGitRepositories" + ); +} + #[gpui::test] async fn test_linked_worktree_event_in_unregistered_common_git_dir_does_not_panic( executor: BackgroundExecutor,