mirror of
https://github.com/zed-industries/zed.git
synced 2026-05-31 19:05:00 +07:00
Fix the filtering of index.lock + COMMIT_MESSAGE FS events to work in linked worktrees (#57763)
Zed reloads a lot of data about a git repository any time any file changes inside of the `.git` directory, with the exception of a few known paths that we know do not warrant a reload, such as `index.lock` and `COMMIT_MESSAGE`. Previously, we ignored FS events for those files, but we used a specific path that only worked for the main worktree. This caused a lot of unnecessary reloads when using linked worktrees. Now we ignore those files in a general way, by their filename, so that the optimization applies to linked worktrees as well. @cole-miller Noticed this bug. Release Notes: - Fixed unnecessary reloading of Git state that could occur when editing in linked worktrees.
This commit is contained in:
parent
53ed11b2af
commit
4129fc87d8
8 changed files with 93 additions and 8 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
mod fake_git_repo_tests;
|
||||
|
||||
use std::{
|
||||
collections::BTreeSet,
|
||||
ffi::OsString,
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
mod fake_git_repo;
|
||||
mod fs;
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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/<name>/`. 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<Cell<usize>> = 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,
|
||||
Loading…
Reference in a new issue