From 95446195aff0b9b00dcb5e8ce0af4a3869e26da9 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 3 Mar 2025 17:04:46 +0200 Subject: [PATCH] Skip .git/lfs FS events (#25927) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes https://github.com/zed-industries/zed/issues/25865 Closes https://github.com/zed-industries/zed/pull/25915 In the issue, Zed had caused `.git/lfs/tmp/466102258`-like files to appear in the directory, which lead to background FS event listener to handle this as an update, incrementing snapshot's `scan_id`, which lead to git status rescan, which caused another increment to `status_scan_id` — incrementing either of the IDs causes the related repo data to be considered "changed: https://github.com/zed-industries/zed/blob/41b45eaba798a56e596857fa497c862050788bc7/crates/worktree/src/worktree.rs#L1590-L1605 hence propagating events to the other parts of the system (e.g. git blame, which was also active in the issue's case) ``` [2025-03-01T20:01:08+01:00 DEBUG worktree] ignoring event ".git/lfs/tmp/466102258" within unloaded directory [2025-03-01T20:01:08+01:00 DEBUG worktree] received fs events [] [2025-03-01T20:01:08+01:00 DEBUG worktree] reloading repositories: ["/Users/alex/dev/monorepo/.git"] [2025-03-01T20:01:08+01:00 DEBUG editor::git::blame] Status of git repositories updated. Regenerating blame data... [2025-03-01T20:01:08+01:00 DEBUG editor::git::blame] Status of git repositories updated. Regenerating blame data... [2025-03-01T20:01:08+01:00 DEBUG editor::git::blame] Status of git repositories updated. Regenerating blame data... ``` Due to repo update events sent, another `.git/lfs/tmp/` entry is created, things start over... The PR fixes this by ignoring any `.git/lfs/` directory-related FS events, as needed for the current git status update heuristics. https://github.com/zed-industries/zed/pull/25915 tried to follow further and `scan_id` and `status_scan_id` but we do not store all git state in memory, e.g. head https://github.com/zed-industries/zed/blob/e0060b92cc862c4d926652e1a01f0991ccb3a805/crates/editor/src/editor_tests.rs#L13686 as [tests](https://github.com/zed-industries/zed/actions/runs/13631960559/job/38101504549?pr=25915) show. Release Notes: - Improved `.git` scan heuristics --- crates/git/src/git.rs | 1 + crates/worktree/src/worktree.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/git/src/git.rs b/crates/git/src/git.rs index d26409a007c0b83925c997adbe76cf2a91303426..97735bd174dfd9b88b1d8c742fad06296fb7ea2e 100644 --- a/crates/git/src/git.rs +++ b/crates/git/src/git.rs @@ -26,6 +26,7 @@ pub static DOT_GIT: LazyLock<&'static OsStr> = LazyLock::new(|| OsStr::new(".git pub static GITIGNORE: LazyLock<&'static OsStr> = LazyLock::new(|| OsStr::new(".gitignore")); pub static FSMONITOR_DAEMON: LazyLock<&'static OsStr> = LazyLock::new(|| OsStr::new("fsmonitor--daemon")); +pub static LFS_DIR: LazyLock<&'static OsStr> = LazyLock::new(|| OsStr::new("lfs")); pub static COMMIT_MESSAGE: LazyLock<&'static OsStr> = LazyLock::new(|| OsStr::new("COMMIT_EDITMSG")); pub static INDEX_LOCK: LazyLock<&'static OsStr> = LazyLock::new(|| OsStr::new("index.lock")); diff --git a/crates/worktree/src/worktree.rs b/crates/worktree/src/worktree.rs index d3614cfb649e414437d1a770e481978550c7bef2..67a6727a736b4778acbac454400a5ec70b04e3b3 100644 --- a/crates/worktree/src/worktree.rs +++ b/crates/worktree/src/worktree.rs @@ -25,6 +25,7 @@ use git::{ FileStatus, GitSummary, StatusCode, TrackedStatus, UnmergedStatus, UnmergedStatusCode, }, GitHostingProviderRegistry, COMMIT_MESSAGE, DOT_GIT, FSMONITOR_DAEMON, GITIGNORE, INDEX_LOCK, + LFS_DIR, }; use gpui::{ App, AppContext as _, AsyncApp, BackgroundExecutor, Context, Entity, EventEmitter, Task, @@ -4513,7 +4514,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 = HashSet::from_iter([*COMMIT_MESSAGE, *INDEX_LOCK]); - let skipped_dirs_in_dot_git = [*FSMONITOR_DAEMON]; + let skipped_dirs_in_dot_git = [*FSMONITOR_DAEMON, *LFS_DIR]; let mut relative_paths = Vec::with_capacity(abs_paths.len()); let mut dot_git_abs_paths = Vec::new();