# worktree: Avoid dropping git repositories during watcher rescans \(\#59976\) · gitcafe/zed

[View on GitCafe](https://git.cafe/gitcafe/zed/commit/cd7f1a0fb18dd6f2474fbb84c6d6a19cce72ec76)

Repository: [gitcafe/zed](https://git.cafe/gitcafe/zed)

Visibility: public

Requested revision: cd7f1a0fb18dd6f2474fbb84c6d6a19cce72ec76

Requested commit: cd7f1a0fb18dd6f2474fbb84c6d6a19cce72ec76

Commit: cd7f1a0fb18dd6f2474fbb84c6d6a19cce72ec76

Tree: d02e3703db9f87506cc78fc44dd404bedb3ee225

Author: Remco Smits

Committer: GitHub

## Message

````
worktree: Avoid dropping git repositories during watcher rescans (#59976)

Related to #59610.

# Objective

When the filesystem watcher loses sync (common on macOS under heavy
churn, e.g. a dev build constantly rewriting `target/` and `.git/`), it
forces a recursive rescan of the worktree root. That rescan removes the
whole subtree from the snapshot before re-scanning it, and
`remove_path_from_snapshot` was unconditionally pruning the worktree's
git repositories along with it.

Because the scanner publishes intermediate snapshots while it works, a
snapshot could be published in the window after the repository was
pruned but before `.git` was re-scanned. The `GitStore` would see the
repository as removed, tear it down, and then re-create it with a fresh
`RepositoryId` once it reappeared — churning the id on every watcher
overflow and spamming `RepositoryUpdated` events to all consumers (git
panel, git graph, blame, etc.).

Here some debug logs, 
**See** that the **repoId** inside the git graph event is different and
is **8** now, even though I only have one repository and didn't do any
git related updates.

```
2026-06-26T18:38:44+02:00 WARN  [fs::fs_watcher] filesystem watcher lost sync for Native; scheduling rescans for 11 registrations
2026-06-26T18:38:44+02:00 WARN  [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN  [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN  [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN  [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN  [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN  [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN  [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN  [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN  [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN  [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN  [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 INFO  [git::repository] opening git repository at "/Users/remcosmits/Documents/code/zed/.git" using git binary "/opt/homebrew/bin/git"
2026-06-26T18:38:44+02:00 ERROR [crates/git_ui/src/git_panel.rs:3892] oneshot canceled
2026-06-26T18:38:44+02:00 ERROR [crates/git_ui/src/git_panel.rs:3892] oneshot canceled
2026-06-26T18:38:44+02:00 ERROR [crates/git_ui/src/git_panel.rs:3892] oneshot canceled
2026-06-26T18:38:44+02:00 ERROR [crates/git_ui/src/git_panel.rs:3892] oneshot canceled
2026-06-26T18:38:44+02:00 ERROR [crates/zed/src/main.rs:1991] Is a directory (os error 21)
2026-06-26T18:38:44+02:00 INFO  [project::prettier_store] Prettier config file ".prettierrc" changed, reloading prettier instances for worktree 1
2026-06-26T18:38:45+02:00 INFO  [project::prettier_store] Prettier config file ".prettierrc" changed, reloading prettier instances for worktree 1
2026-06-26T18:38:45+02:00 INFO  [git::repository] opening git repository at "/Users/remcosmits/Documents/code/zed/.git" using git binary "/opt/homebrew/bin/git"
2026-06-26T18:38:45+02:00 ERROR [crates/git_ui/src/git_panel.rs:3892] oneshot canceled
2026-06-26T18:38:45+02:00 ERROR [crates/git_ui/src/git_panel.rs:3892] oneshot canceled


[crates/git_ui/src/git_graph.rs:1468:21] &this.repo_id = RepositoryId(
    1,
)
[crates/git_ui/src/git_graph.rs:1468:21] "other repo id" = "other repo id"
[crates/git_ui/src/git_graph.rs:1468:21] &updated_repo_id = RepositoryId(
    8,
)
[crates/git_ui/src/git_graph.rs:1468:21] &this.repo_id = RepositoryId(
    1,
)
[crates/git_ui/src/git_graph.rs:1468:21] "other repo id" = "other repo id"
[crates/git_ui/src/git_graph.rs:1468:21] &updated_repo_id = RepositoryId(
    8,
)
[crates/git_ui/src/git_graph.rs:1468:21] &this.repo_id = RepositoryId(
    1,
)
[crates/git_ui/src/git_graph.rs:1468:21] "other repo id" = "other repo id"
[crates/git_ui/src/git_graph.rs:1468:21] &updated_repo_id = RepositoryId(
    8,
)
[crates/git_ui/src/git_graph.rs:1468:21] &this.repo_id = RepositoryId(
    1,
)
```

## Solution

This change makes `remove_path_from_snapshot` prune git repositories
only when the path was genuinely removed (`metadata == Ok(None)`), not
during a recursive refresh where the subtree is about to be re-scanned.
Stale repositories are still reaped authoritatively against the
filesystem in `update_git_repositories`.

## Testing

It seems to be that I'm the only that can reproduce this issue
@Anthony-Eid tried reproducing this but couldn't.
**Note**: that I dindn't write a regression test since this is a async
timing issue that I couldn't figure out to write a test for.

Steps how I can reproduce this:
1. Run `cargo run`
2. Open `Zed` as only project
3. Open the git graph
4. Open a rust file e.g. `git_graph.rs`
5. CTRL-C inside the terminal to kill Zed
6. Run `cargo run` see that you have git graph open and a rust file,
note that cargo check is doing it's thing.
7. See within a few seconds that Zed's UI flickers (especially the
project panel & nav bar with the selected repo & branch)

## 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)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase

**Note**: This PR only fixes that we don't send as many git store
events, so this results in not having to update the nav bar where the
selected repo & branch on every event (that is duplicated in a way).
Result of that we now also fixed a rare case that the git graph commit
entries where gone, this was because we incremented the **repoId** and
the graph couldn't find the repo anymore with the id that it has stored
on the gitGraph struct itself.

**Before** 

See that the nav bar with selected repo & branch flickers and the git
graph commits are empty.


https://github.com/user-attachments/assets/0957be7f-e732-4fd0-a950-29c496b6407d

See that the git panel entries flicker and we have an temporary empty
panel.


https://github.com/user-attachments/assets/3b70e45c-c720-4009-aefa-696986d731b4

**After** 

See that the nav bar with selected repo & branch does not flicker
anymore and that the git graph keeps showing the commits.


https://github.com/user-attachments/assets/6e8a74f6-4a8e-4b28-ad30-574c2f33c6d9

See that the git panel does not show an empy state and does not flicker
anymore.


https://github.com/user-attachments/assets/1df7aacf-b337-4b81-b195-e67d8554d9da

---

cc @Anthony-Eid Since we where debugging this yesterday.

Release Notes:

- Fixed git repositories being repeatedly torn down and re-created when
the filesystem watcher forced a rescan, which caused redundant git
status refreshes and UI churn.
````

## Parents

- [b40aa65d9ede445f2159c3088e0a0240c9efb18a](https://git.cafe/gitcafe/zed/commit/b40aa65d9ede445f2159c3088e0a0240c9efb18a?format=markdown)

[Source at this commit](https://git.cafe/gitcafe/zed/tree/cd7f1a0fb18dd6f2474fbb84c6d6a19cce72ec76?format=markdown)
