Remco Smits cd7f1a0fb1 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.
2026-06-29 05:05:26 +00:00
2026-04-30 11:10:14 +00:00
2026-06-05 23:12:31 +00:00
2026-05-27 18:17:59 +00:00
2026-01-22 23:57:26 +05:30
WIP
2023-12-14 09:25:14 -07:00
2026-04-29 10:27:47 +00:00
2025-02-04 09:02:59 -05:00
2025-10-27 13:27:59 -04:00
2026-06-27 15:06:29 +00:00
2025-10-17 18:58:14 +00:00
2026-03-17 16:34:35 +00:00
2026-04-29 10:27:47 +00:00

Zed

Zed CI

Welcome to Zed, a high-performance, multiplayer code editor from the creators of Atom and Tree-sitter.


Installation

On macOS, Linux, and Windows you can download Zed directly or install Zed via your local package manager (macOS/Linux/Windows).

Other platforms are not yet available:

Developing Zed

Contributing

See CONTRIBUTING.md for ways you can contribute to Zed.

Also... we're hiring! Check out our jobs page for open roles.

Licensing

Zed source code is licensed primarily under GPL-3.0-or-later, with Apache-2.0 components where marked.

License information for third party dependencies must be correctly provided for CI to pass.

We use cargo-about to automatically comply with open source licenses. If CI is failing, check the following:

  • Is it showing a no license specified error for a crate you've created? If so, add publish = false under [package] in your crate's Cargo.toml.
  • Is the error failed to satisfy license requirements for a dependency? If so, first determine what license the project has and whether this system is sufficient to comply with this license's requirements. If you're unsure, ask a lawyer. Once you've verified that this system is acceptable add the license's SPDX identifier to the accepted array in script/licenses/zed-licenses.toml.
  • Is cargo-about unable to find the license for a dependency? If so, add a clarification field at the end of script/licenses/zed-licenses.toml, as specified in the cargo-about book.

Sponsorship

Zed is developed by Zed Industries, Inc., a for-profit company.

If you’d like to financially support the project, you can do so via GitHub Sponsors. Sponsorships go directly to Zed Industries and are used as general company revenue. There are no perks or entitlements associated with sponsorship.

S
Description
No description provided
Readme
411 MiB
0 Stars 1 Watchers 0 Forks
Languages
Rust 94.9%
JSON-with-Comments 2.7%
Python 0.8%
Inno Setup 0.3%
Tree-sitter Query 0.3%
Other 0.5%