What Is the Role of the Repository Struct in Worktrunk's Git Core?

The Repository struct serves as the central abstraction in Worktrunk's Git core, encapsulating repository discovery, shared caching, and thread-safe coordination for all worktree operations.

Worktrunk is a Rust-based CLI tool designed for efficient Git worktree management. At the heart of its architecture lies the Repository struct, defined in src/git/repository/mod.rs, which provides a unified interface for discovering, caching, and coordinating access to Git repositories.

Central Representation and Discovery

The Repository struct acts as the canonical representation of a Git repository within Worktrunk's type system. It stores two critical path fields that distinguish between the entry point and the actual Git metadata location.

According to the source code at src/git/repository/mod.rs (lines 67-74), the struct definition includes:

pub struct Repository {
    discovery_path: PathBuf,
    git_common_dir: PathBuf,
    // ...
}

The discovery_path represents the path used to initially locate the repository, while the git_common_dir points to the actual .git directory (or the bare repository equivalent). This separation allows Worktrunk to handle complex repository layouts, including worktrees and alternate object databases, while maintaining a consistent reference to the repository's core metadata.

Shared State and Caching Architecture

Performance in Worktrunk relies on aggressive caching orchestrated through the Repository struct. Each instance maintains shared state via an Arc<RepoCache>, ensuring that expensive Git operations are executed only once per process.

As implemented in src/git/repository/mod.rs (lines 75-78), all repository-wide information—including default branch detection, configuration values, and branch inventories—is stored in this cache. When you clone a Repository value, you reuse the same cache rather than re-reading from disk.

Worktrunk implements three distinct caching layers:

  1. RepoCache (per-instance) – Shared via Arc across cloned Repository instances, storing repo-wide values like merge-base results and branch inventories to avoid duplicate Git commands during a single CLI invocation.

  2. Process-wide statics – Global LazyLock and OnceLock structures (such as WORKTREE_ROOTS, GIT_DIRS, and GIT_CONFIG_PRELOAD) that persist across all Repository objects created in the process, ensuring cold-path discovery costs are paid only once.

  3. On-disk sha_cache – JSON files under .git/wt/cache/ that persist expensive, repeatable results (like merge-tree outcomes) across process invocations.

The design guarantees cache immutability within a single command execution, eliminating race conditions during parallel worktree processing.

Thread-Safe Worktree Coordination

Concurrent modification of worktree metadata requires careful synchronization. The Repository struct attaches a global lock to each repository's common-git directory to serialize operations that modify the worktree registry.

As defined at src/git/repository/mod.rs (lines 85-88), the WORKTREE_REGISTRY_LOCKS mechanism ensures that adding or removing worktrees is serialized across all Repository instances pointing to the same underlying repository. This prevents corruption when multiple threads or processes manipulate worktree metadata simultaneously.

Factory Methods and Construction

Worktrunk centralizes Repository creation through two primary constructors that ensure consistent initialization of caches and locks.

Repository::current() (lines 16-20) provides a convenience wrapper that creates a Repository from the global base path (specified via the -C flag) or the current working directory:

let repo = Repository::current()?;

Repository::at(path) (lines 30-44) serves as the core constructor. This method resolves the Git common directory, installs the worktree registry lock, and optionally integrates pre-loaded configuration caches populated during the pre-warm phase:

let repo = Repository::at(PathBuf::from("/path/to/repo"))?;

Both methods ensure every Repository instance inherits the same cache layout and synchronization semantics.

Worktree-Specific Operations

While Repository handles repo-wide concerns, concrete worktree manipulation occurs through the WorkingTree type. The repository acts as an entry point for spawning per-worktree objects that inherit the shared cache.

As shown at src/git/repository/mod.rs (lines 49-57), you obtain a WorkingTree from a Repository instance:

let repo = Repository::current()?;
let wt = repo.current_worktree();  // Returns worktree-specific API

This architecture separates global queries (default branch, configuration) from worktree-local operations (file status, branch checkout), while both layers benefit from the same underlying cache.

Observation Mode and Temporary Object Stores

For read-only commands such as wt list, Worktrunk redirects Git's object writes to a temporary object database to prevent modifying the repository state. The Repository struct manages this through a temporary object store mechanism.

Implemented at src/git/repository/mod.rs (lines 84-99), this feature:

  1. Creates a temporary directory (temporary_object_store)
  2. Registers the path in observation_object_directories to prevent worktree logic from interpreting it as a real worktree
  3. Adjusts Git command environments via with_object_store_env

The temporary store persists as long as any cloned Repository carries the reference, ensuring automatic cleanup when the last clone drops.

Pre-warming for Cold-Path Optimization

To minimize latency during initial operations, Repository provides a prewarm() method that populates process-wide caches before any repository queries occur.

As implemented at src/git/repository/mod.rs (lines 160-188), Repository::prewarm() launches three background threads that:

  • Resolve the common-git directory via git rev-parse
  • Load the entire Git configuration via git config --list -z
  • Parse the user-level Worktrunk configuration from wt.toml

These results populate the process-wide static caches, allowing the first real Repository instantiation to retrieve them without spawning additional subprocesses.

Summary

  • The Repository struct centralizes Git repository discovery, storing both the discovery path and resolved .git directory location in src/git/repository/mod.rs.
  • It orchestrates a three-tier caching strategy—per-instance RepoCache, process-wide statics, and on-disk SHA caches—to minimize Git subprocess overhead.
  • Thread safety for worktree registry modifications is guaranteed through the WORKTREE_REGISTRY_LOCKS mechanism attached to each repository instance.
  • Factory methods Repository::current() and Repository::at() ensure consistent initialization of caches and locks across all code paths.
  • The struct provides the entry point for worktree-specific operations via the current_worktree() method, returning a WorkingTree object that shares the underlying cache.
  • Observation mode support allows read-only commands to operate safely using temporary object stores that automatically clean up when the Repository is dropped.

Frequently Asked Questions

What fields does the Repository struct contain?

The Repository struct contains discovery_path and git_common_dir fields of type PathBuf, along with shared cache and lock handles. The discovery path represents where the repository was found, while the git_common_dir points to the actual .git metadata directory, enabling support for worktrees and alternate object stores.

How does the Repository struct handle caching?

The struct uses an Arc<RepoCache> to share repository-wide data across cloned instances, combined with process-wide static caches (LazyLock and OnceLock globals) and persistent on-disk JSON caches under .git/wt/cache/. This three-layer approach ensures expensive Git operations execute only once per process or persist across invocations.

What is the difference between Repository and WorkingTree?

Repository represents the Git repository itself and handles repo-wide concerns like configuration, default branch detection, and the worktree registry. WorkingTree represents a specific worktree checkout and handles file-level operations. You obtain a WorkingTree by calling repo.current_worktree() on a Repository instance, inheriting the parent's shared cache.

How does Repository ensure thread safety?

Thread safety is achieved through the WORKTREE_REGISTRY_LOCKS global lock map, which assigns a unique lock to each repository's common-git directory. This ensures that operations modifying the worktree registry—such as adding or removing worktrees—are serialized across all Repository instances pointing to the same underlying repository, preventing metadata corruption during concurrent access.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →