git: Avoid unnecessary git repo rescans when unrelated git files change - #59318
Merged
cole-miller merged 6 commits intoJun 16, 2026
Merged
Conversation
lgeiger
commented
Jun 14, 2026
| pub const LOGS_REFS_HEADS_DIR: &str = "logs/refs/heads"; | ||
| pub const LOGS_REFS_REMOTES_DIR: &str = "logs/refs/remotes"; | ||
| pub const COMMIT_MESSAGE: &str = "COMMIT_EDITMSG"; | ||
| pub const INDEX_LOCK: &str = "index.lock"; |
Contributor
Author
There was a problem hiding this comment.
We now ignore all *.lock files
lgeiger
commented
Jun 15, 2026
Comment on lines
+27
to
+29
| pub const REBASE_MERGE_DIR: &str = "rebase-merge"; | ||
| pub const REBASE_APPLY_DIR: &str = "rebase-apply"; | ||
| pub const SEQUENCER_DIR: &str = "sequencer"; |
Contributor
Author
There was a problem hiding this comment.
These specific ignores have been found by Gemini, but I think that's correct since git only writes intermediate state to these files
they are allowed branch suffixes
Contributor
Author
|
As a followup PR we could further improve this by only triggering the relevant rescans in |
This was referenced Jun 18, 2026
Closed
Collaborator
|
Great job @lgeiger |
This was referenced Jul 8, 2026
jolutz
pushed a commit
to jolutz/zed
that referenced
this pull request
Aug 8, 2026
…ge (zed-industries#59318) # Objective Zed triggers many git rescans whenever an outside git command modifies files inside `.git` dir. This becomes especially problematic when working on large repos or doing remote development on machines with slow filesystems. ## Solution Events for object writes, hook files, lock files, and the reflogs of HEAD/branches/remote-tracking branches carry no git changes that Zed cares about beyond what the ref or events already cover. So changes to these files shouldn't trigger a full git rescan. ## Testing I extended the existing unittests to add the additionally ignored directories and lock files. I also manually verified the changes by viewing the zed git debug logs that get generated when running `git gc` on a freshly gc'ed repo. Previously Zed triggered **7 worktree updates**, with these changes it was reduced to **a single worktree update** which is due to `.git/packed-refs` which we can't ignore. **main:** ``` 2026-06-13T13:56:52+01:00 DEBUG [project::git_store] received worktree update for repositories: [UpdatedGitRepository { work_directory_id: ProjectEntryId(0), old_work_directory_abs_path: Some("/Users/lgeiger/code/zed"), new_work_directory_abs_path: Some("/Users/lgeiger/code/zed"), dot_git_abs_path: Some("/Users/lgeiger/code/zed/.git"), repository_dir_abs_path: Some("/Users/lgeiger/code/zed/.git"), common_dir_abs_path: Some("/Users/lgeiger/code/zed/.git") }] 2026-06-13T13:56:52+01:00 DEBUG [project::git_store] local worktree repos changed 2026-06-13T13:56:52+01:00 DEBUG [project::git_store] run scheduled git status scan 2026-06-13T13:56:52+01:00 DEBUG [project::git_store] starting compute snapshot 2026-06-13T13:56:52+01:00 DEBUG [project::git_store] fetched branches, head commit, worktrees 2026-06-13T13:56:52+01:00 DEBUG [project::git_store] fetched remotes 2026-06-13T13:56:52+01:00 DEBUG [git::repository] Checking for git status in [""] 2026-06-13T13:56:52+01:00 DEBUG [project::git_store] fetched statuses, diff stats, stash entries 2026-06-13T13:56:52+01:00 DEBUG [project::git_store] load merge details 2026-06-13T13:56:52+01:00 DEBUG [project::git_store] new merge details: MergeDetails { merge_heads_by_conflicted_path: {}, message: None } 2026-06-13T13:56:53+01:00 DEBUG [project::git_store] received worktree update for repositories: [UpdatedGitRepository { work_directory_id: ProjectEntryId(0), old_work_directory_abs_path: Some("/Users/lgeiger/code/zed"), new_work_directory_abs_path: Some("/Users/lgeiger/code/zed"), dot_git_abs_path: Some("/Users/lgeiger/code/zed/.git"), repository_dir_abs_path: Some("/Users/lgeiger/code/zed/.git"), common_dir_abs_path: Some("/Users/lgeiger/code/zed/.git") }] 2026-06-13T13:56:53+01:00 DEBUG [project::git_store] local worktree repos changed 2026-06-13T13:56:53+01:00 DEBUG [project::git_store] run scheduled git status scan 2026-06-13T13:56:53+01:00 DEBUG [project::git_store] starting compute snapshot 2026-06-13T13:56:53+01:00 DEBUG [project::git_store] fetched branches, head commit, worktrees 2026-06-13T13:56:53+01:00 DEBUG [project::git_store] fetched remotes 2026-06-13T13:56:53+01:00 DEBUG [git::repository] Checking for git status in [""] 2026-06-13T13:56:53+01:00 DEBUG [project::git_store] fetched statuses, diff stats, stash entries 2026-06-13T13:56:53+01:00 DEBUG [project::git_store] load merge details 2026-06-13T13:56:53+01:00 DEBUG [project::git_store] new merge details: MergeDetails { merge_heads_by_conflicted_path: {}, message: None } 2026-06-13T13:56:54+01:00 DEBUG [project::git_store] received worktree update for repositories: [UpdatedGitRepository { work_directory_id: ProjectEntryId(0), old_work_directory_abs_path: Some("/Users/lgeiger/code/zed"), new_work_directory_abs_path: Some("/Users/lgeiger/code/zed"), dot_git_abs_path: Some("/Users/lgeiger/code/zed/.git"), repository_dir_abs_path: Some("/Users/lgeiger/code/zed/.git"), common_dir_abs_path: Some("/Users/lgeiger/code/zed/.git") }] 2026-06-13T13:56:54+01:00 DEBUG [project::git_store] local worktree repos changed 2026-06-13T13:56:54+01:00 DEBUG [project::git_store] run scheduled git status scan 2026-06-13T13:56:54+01:00 DEBUG [project::git_store] starting compute snapshot 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] fetched branches, head commit, worktrees 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] fetched remotes 2026-06-13T13:56:55+01:00 DEBUG [git::repository] Checking for git status in [""] 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] fetched statuses, diff stats, stash entries 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] load merge details 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] new merge details: MergeDetails { merge_heads_by_conflicted_path: {}, message: None } 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] received worktree update for repositories: [UpdatedGitRepository { work_directory_id: ProjectEntryId(0), old_work_directory_abs_path: Some("/Users/lgeiger/code/zed"), new_work_directory_abs_path: Some("/Users/lgeiger/code/zed"), dot_git_abs_path: Some("/Users/lgeiger/code/zed/.git"), repository_dir_abs_path: Some("/Users/lgeiger/code/zed/.git"), common_dir_abs_path: Some("/Users/lgeiger/code/zed/.git") }] 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] local worktree repos changed 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] run scheduled git status scan 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] starting compute snapshot 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] fetched branches, head commit, worktrees 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] fetched remotes 2026-06-13T13:56:55+01:00 DEBUG [git::repository] Checking for git status in [""] 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] fetched statuses, diff stats, stash entries 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] load merge details 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] new merge details: MergeDetails { merge_heads_by_conflicted_path: {}, message: None } 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] received worktree update for repositories: [UpdatedGitRepository { work_directory_id: ProjectEntryId(0), old_work_directory_abs_path: Some("/Users/lgeiger/code/zed"), new_work_directory_abs_path: Some("/Users/lgeiger/code/zed"), dot_git_abs_path: Some("/Users/lgeiger/code/zed/.git"), repository_dir_abs_path: Some("/Users/lgeiger/code/zed/.git"), common_dir_abs_path: Some("/Users/lgeiger/code/zed/.git") }] 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] local worktree repos changed 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] run scheduled git status scan 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] starting compute snapshot 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] fetched branches, head commit, worktrees 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] fetched remotes 2026-06-13T13:56:55+01:00 DEBUG [git::repository] Checking for git status in [""] 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] fetched statuses, diff stats, stash entries 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] load merge details 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] new merge details: MergeDetails { merge_heads_by_conflicted_path: {}, message: None } 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] received worktree update for repositories: [UpdatedGitRepository { work_directory_id: ProjectEntryId(0), old_work_directory_abs_path: Some("/Users/lgeiger/code/zed"), new_work_directory_abs_path: Some("/Users/lgeiger/code/zed"), dot_git_abs_path: Some("/Users/lgeiger/code/zed/.git"), repository_dir_abs_path: Some("/Users/lgeiger/code/zed/.git"), common_dir_abs_path: Some("/Users/lgeiger/code/zed/.git") }] 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] local worktree repos changed 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] run scheduled git status scan 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] starting compute snapshot 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] fetched branches, head commit, worktrees 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] fetched remotes 2026-06-13T13:56:55+01:00 DEBUG [git::repository] Checking for git status in [""] 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] fetched statuses, diff stats, stash entries 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] load merge details 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] new merge details: MergeDetails { merge_heads_by_conflicted_path: {}, message: None } 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] received worktree update for repositories: [UpdatedGitRepository { work_directory_id: ProjectEntryId(0), old_work_directory_abs_path: Some("/Users/lgeiger/code/zed"), new_work_directory_abs_path: Some("/Users/lgeiger/code/zed"), dot_git_abs_path: Some("/Users/lgeiger/code/zed/.git"), repository_dir_abs_path: Some("/Users/lgeiger/code/zed/.git"), common_dir_abs_path: Some("/Users/lgeiger/code/zed/.git") }] 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] local worktree repos changed 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] run scheduled git status scan 2026-06-13T13:56:55+01:00 DEBUG [project::git_store] starting compute snapshot 2026-06-13T13:56:56+01:00 DEBUG [project::git_store] fetched branches, head commit, worktrees 2026-06-13T13:56:56+01:00 DEBUG [project::git_store] fetched remotes 2026-06-13T13:56:56+01:00 DEBUG [git::repository] Checking for git status in [""] 2026-06-13T13:56:56+01:00 DEBUG [project::git_store] fetched statuses, diff stats, stash entries 2026-06-13T13:56:56+01:00 DEBUG [project::git_store] load merge details 2026-06-13T13:56:56+01:00 DEBUG [project::git_store] new merge details: MergeDetails { merge_heads_by_conflicted_path: {}, message: None } ``` **This PR:** ``` 2026-06-15T01:19:51+01:00 DEBUG [project::git_store] received worktree update for repositories: [UpdatedGitRepository { work_directory_id: ProjectEntryId(0), old_work_directory_abs_path: Some("/Users/lgeiger/code/zed"), new_work_directory_abs_path: Some("/Users/lgeiger/code/zed"), dot_git_abs_path: Some("/Users/lgeiger/code/zed/.git"), repository_dir_abs_path: Some("/Users/lgeiger/code/zed/.git"), common_dir_abs_path: Some("/Users/lgeiger/code/zed/.git") }] 2026-06-15T01:19:51+01:00 DEBUG [project::git_store] local worktree repos changed 2026-06-15T01:19:51+01:00 DEBUG [project::git_store] run scheduled git status scan 2026-06-15T01:19:51+01:00 DEBUG [project::git_store] starting compute snapshot 2026-06-15T01:19:51+01:00 DEBUG [project::git_store] fetched branches, head commit, worktrees 2026-06-15T01:19:51+01:00 DEBUG [project::git_store] fetched remotes 2026-06-15T01:19:51+01:00 DEBUG [git::repository] Checking for git status in [""] 2026-06-15T01:19:51+01:00 DEBUG [project::git_store] fetched statuses, diff stats, stash entries 2026-06-15T01:19:51+01:00 DEBUG [project::git_store] load merge details 2026-06-15T01:19:51+01:00 DEBUG [project::git_store] new merge details: MergeDetails { merge_heads_by_conflicted_path: {}, message: None }``` ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Release Notes: - Reduced number of git operations when repository state changes outside of zed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Objective
Zed triggers many git rescans whenever an outside git command modifies files inside
.gitdir. This becomes especially problematic when working on large repos or doing remote development on machines with slow filesystems.Solution
Events for object writes, hook files, lock files, and the reflogs of HEAD/branches/remote-tracking branches carry no git changes that Zed cares about beyond what the ref or events already cover. So changes to these files shouldn't trigger a full git rescan.
Testing
I extended the existing unittests to add the additionally ignored directories and lock files.
I also manually verified the changes by viewing the zed git debug logs that get generated when running
git gcon a freshly gc'ed repo. Previously Zed triggered 7 worktree updates, with these changes it was reduced to a single worktree update which is due to.git/packed-refswhich we can't ignore.main:
This PR:
Self-Review Checklist:
Release Notes: