# How Zed Manages File Worktrees and Git Operations Efficiently

> Discover how Zed efficiently manages file worktrees and Git operations through asynchronous parsing, centralized storage, and optimized UI rendering. Learn Zed's secrets here.

- Repository: [Zed Industries/zed](https://github.com/zed-industries/zed)
- Tags: internals
- Published: 2026-03-01

---

**Zed manages file worktrees and git operations efficiently by parsing Git's porcelain output asynchronously, maintaining a centralized WorktreeStore for lazy loading and deduplication, and separating visible worktrees from internal ones to minimize UI re-renders.**

Zed, the high-performance code editor from zed-industries, treats every open directory as a Git worktree to enable independent branch manipulation without leaving the main repository. To manage file worktrees and git operations efficiently across large projects, Zed implements a layered architecture that separates Git command execution from project-level state management and UI rendering.

## Architecture Overview

Zed organizes its worktree management into distinct layers, each with a specific responsibility:

| Layer | Responsibility | Key Source |
|------|----------------|------------|
| **Git interaction** | Executes Git commands (`git worktree list`, `git worktree add`, `git worktree remove`, `git worktree rename`) and parses their porcelain output. | [`crates/git/src/repository.rs`](https://github.com/zed-industries/zed/blob/main/crates/git/src/repository.rs) |
| **Worktree abstraction** | Represents a worktree with its path, branch name and current SHA. Provides helpers to resolve the worktree directory from the user-configurable `git.worktree_directory` setting. | [`crates/git/src/repository.rs`](https://github.com/zed-industries/zed/blob/main/crates/git/src/repository.rs) |
| **Project-level store** | Keeps a collection of all worktrees that belong to a Zed *Project*. Offers fast iteration over **visible** worktrees (those shown in the Project panel) and over **all** worktrees (including invisible single-file worktrees). Handles lazy loading, ordering, and retention policies. | [`crates/project/src/worktree_store.rs`](https://github.com/zed-industries/zed/blob/main/crates/project/src/worktree_store.rs) |
| **Trusted-worktree handling** | Determines which worktrees are allowed to perform privileged actions (e.g., executing tools). Trust can be granted per-directory, automatically propagating to sub-worktrees. | [`crates/project/src/trusted_worktrees.rs`](https://github.com/zed-industries/zed/blob/main/crates/project/src/trusted_worktrees.rs) |
| **UI integration** | The `Zed` core ([`crates/zed/src/zed.rs`](https://github.com/zed-industries/zed/blob/main/crates/zed/src/zed.rs)) reads the store's `visible_worktrees` iterator to populate the Project panel and to route file-system events. | [`crates/zed/src/zed.rs`](https://github.com/zed-industries/zed/blob/main/crates/zed/src/zed.rs) |

## Git Worktree Discovery

Zed discovers existing worktrees by running `git worktree list --porcelain` in a non-blocking background task. This approach avoids blocking the UI thread during repository scanning.

The implementation in [`crates/git/src/repository.rs`](https://github.com/zed-industries/zed/blob/main/crates/git/src/repository.rs) uses `--no-optional-locks` to prevent unnecessary lock acquisition:

```rust
fn worktrees(&self) -> BoxFuture<'_, Result<Vec<Worktree>>> {
    self.run_git(
        ["--no-optional-locks", "worktree", "list", "--porcelain"],
        // …
    )
    .map(|(stdout, stderr)| {
        if !stderr.is_empty() {
            anyhow::bail!("git worktree list failed: {stderr}");
        }
        Ok(parse_worktrees_from_str(&stdout))
    })
}

```

### Parsing the Porcelain Format

The parser processes Git's stable porcelain output to extract path, SHA, and branch information without invoking additional Git commands:

```rust
pub fn parse_worktrees_from_str<T: AsRef<str>>(raw_worktrees: T) -> Vec<Worktree> {
    let mut worktrees = Vec::new();
    let normalized = raw_worktrees.as_ref().replace("\r\n", "\n");
    let entries = normalized.split("\n\n");
    for entry in entries {
        let mut path = None;
        let mut sha = None;
        let mut ref_name = None;
        for line in entry.lines() {
            let line = line.trim();
            if line.is_empty() { continue; }
            if let Some(rest) = line.strip_prefix("worktree ") {
                path = Some(rest.to_string());
            } else if let Some(rest) = line.strip_prefix("HEAD ") {
                sha = Some(rest.to_string());
            } else if let Some(rest) = line.strip_prefix("branch ") {
                ref_name = Some(rest.to_string());
            }
        }
        if let (Some(path), Some(sha), Some(ref_name)) = (path, sha, ref_name) {
            worktrees.push(Worktree {
                path: PathBuf::from(path),
                ref_name: ref_name.into(),
                sha: sha.into(),
            })
        }
    }
    worktrees
}

```

This pure function minimizes allocations and avoids filesystem calls, making it safe to call frequently during project initialization.

## Worktree Path Resolution

Zed supports configurable worktree directories via the `git.worktree_directory` setting. The path resolution logic ensures absolute, safe paths that cannot escape the project directory:

```rust
/// Returns the absolute path for a specific branch's worktree.
pub fn worktree_path_for_branch(
    worktree_directory_setting: &str,
    working_directory: &Path,
    branch: &str,
) -> PathBuf {
    resolve_worktree_directory(working_directory, worktree_directory_setting).join(branch)
}

```

The `resolve_worktree_directory` function expands relative settings (e.g., `"../worktrees"`) into absolute paths anchored to the repository root, while `validate_worktree_directory` prevents directory traversal attacks.

## Project-Level Worktree Store

The `WorktreeStore` in [`crates/project/src/worktree_store.rs`](https://github.com/zed-industries/zed/blob/main/crates/project/src/worktree_store.rs) serves as the central authority for all worktrees within a Zed project. It maintains:

- **`worktrees: Vec<WorktreeHandle>`** – Handles to `Entity<Worktree>` instances
- **`retain_worktrees: bool`** – Retention policy (shared projects keep all worktrees alive)
- **`loading_worktrees: HashMap<AbsPath, Task<Result<Worktree>>>`** – In-flight creation tasks to prevent duplicate `git worktree add` calls

### Visible vs. All Worktrees

Zed distinguishes between worktrees displayed in the Project panel and internal worktrees used for single-file editing or background operations:

```rust
/// All worktrees, even those that do **not** appear in the UI.
pub fn worktrees(&self) -> impl '_ + DoubleEndedIterator<Item = Entity<Worktree>> {
    self.worktrees.iter().cloned()
}

/// Only the worktrees that appear in the Project panel.
pub fn visible_worktrees<'a>(&'a self) -> impl 'a + DoubleEndedIterator<Item = Entity<Worktree>> {
    self.worktrees()
        .filter(|wt| wt.read(cx).is_visible())
}

```

The `is_visible()` flag allows the UI to skip layout recomputation for hidden worktrees, significantly improving performance in large monorepos.

### Lazy Loading and Deduplication

When opening a new path, Zed checks the `loading_worktrees` cache to avoid spawning redundant Git processes:

```rust
if !self.loading_worktrees.contains_key(&abs_path) {
    let task = cx.spawn(async move { /* git worktree add */ });
    self.loading_worktrees.insert(abs_path.clone(), task.clone());
    task
} else {
    self.loading_worktrees.get(&abs_path).unwrap().clone()
}

```

Once the task completes, the entry is removed from the map, ensuring the cache only tracks in-flight operations.

## Trusted Worktrees

Security-sensitive operations like executing build tools are gated behind a trust model. The `TrustedWorktreesStore` in [`crates/project/src/trusted_worktrees.rs`](https://github.com/zed-industries/zed/blob/main/crates/project/src/trusted_worktrees.rs) maintains a set of trusted directories and automatically propagates trust to sub-worktrees:

```rust
// When a worktree is added:
if trusted_worktrees.is_trusted(&worktree_path) {
    worktree.set_trusted(true);
}

```

This design avoids repeated filesystem checks and provides a single source of truth for security decisions.

## UI Integration

The core UI component consumes worktrees through the `visible_worktrees` iterator, ensuring non-blocking access to already-loaded entities:

```rust
let worktree_ids = project.read(cx).visible_worktrees(cx).map(|wt| wt.read(cx).id()).collect::<Vec<_>>();

```

This pattern appears in [`crates/zed/src/zed.rs`](https://github.com/zed-industries/zed/blob/main/crates/zed/src/zed.rs) and ensures that heavy Git interactions happen in background tasks while the UI receives updates via `cx.update` only when necessary.

## Summary

- **Asynchronous Git operations** run in background tasks with `--no-optional-locks` to prevent UI blocking.
- **Porcelain parsing** extracts worktree metadata from `git worktree list` without spawning additional processes.
- **WorktreeStore** centralizes state, offering `visible_worktrees()` for UI efficiency and `worktrees()` for complete access.
- **Lazy loading** via `loading_worktrees` HashMap prevents duplicate `git worktree add` invocations.
- **Trust model** caches security decisions in `TrustedWorktreesStore` to avoid filesystem scans.

## Frequently Asked Questions

### How does Zed prevent the UI from freezing when scanning large Git repositories?

Zed executes all Git commands asynchronously in background tasks using `cx.background_spawn()`. The `worktrees()` method in [`crates/git/src/repository.rs`](https://github.com/zed-industries/zed/blob/main/crates/git/src/repository.rs) returns a `BoxFuture`, allowing the UI thread to continue while `git worktree list --porcelain` executes. Results are then pushed to the UI via `cx.update()` callbacks only when the data is ready.

### What is the difference between visible worktrees and all worktrees in Zed?

Visible worktrees are those displayed in the Project panel, accessible via `visible_worktrees()` in [`crates/project/src/worktree_store.rs`](https://github.com/zed-industries/zed/blob/main/crates/project/src/worktree_store.rs). All worktrees includes internal worktrees used for single-file editing or background operations, accessible via `worktrees()`. This separation allows Zed to skip layout recomputation for hidden worktrees, significantly improving performance in large monorepos.

### How does Zed ensure security when executing Git commands in worktrees?

Zed implements a trust model through `TrustedWorktreesStore` in [`crates/project/src/trusted_worktrees.rs`](https://github.com/zed-industries/zed/blob/main/crates/project/src/trusted_worktrees.rs). Security-sensitive operations are gated behind `is_trusted()` checks. Trust is granted per-directory and automatically propagates to sub-worktrees, avoiding repeated filesystem scans while maintaining a single source of truth for security decisions.

### Can I configure where Zed stores new Git worktrees?

Yes, through the `git.worktree_directory` setting. The `worktree_path_for_branch()` function in [`crates/git/src/repository.rs`](https://github.com/zed-industries/zed/blob/main/crates/git/src/repository.rs) resolves this setting relative to the repository root, ensuring absolute paths while preventing directory traversal attacks via `validate_worktree_directory()`.