Using Git Worktrees for Parallel Development: An Architecture Note
Learn how Git worktrees let you maintain multiple active working directories from one repository, with requirements, minimal design, trust boundaries, operational checks, failure modes, and when to reconsider the approach.
31 Aug 2025, 18:45 UTC

Problem
You need to work on a feature branch while an urgent hotfix must be prepared from the same local repository. Stashing changes or repeatedly cloning the repo adds overhead and risks losing work. You want independent working directories that share the same object store to avoid duplication.
Requirements
- Maintain multiple active contexts (e.g., feature and hotfix) without stashing.
- Avoid the disk and time cost of full clones.
- Keep a single source of truth for commits and objects.
- Allow each context to have its own HEAD, index, and working tree files.
Smallest Suitable Design
Git’s worktree feature satisfies these requirements. From an existing repository, run:
# From the repository root
mkdir -p /tmp/worktrees
cd /tmp/worktrees
# Create a worktree for the feature branch
git -C /path/to/repo worktree add feature-worktree feature
# Create a worktree for the hotfix branch
git -C /path/to/repo worktree add hotfix-worktree hotfix
Each worktree gets its own directory with a separate .git file that points back to the shared $GIT_DIR of the original repository. Internally:
- The shared object database (
.git/objects) and packed‑refs are used by all worktrees. - Each worktree has its own
HEADref, index, and working‑tree files. - Configuration is shared unless overridden with
-cor a worktree‑specific config file.
Trust and Data Boundaries
All worktrees share the same ref namespace and object store. Consequently:
- A destructive operation such as
git reset --hardorgit gc --prune=nowin one worktree can affect the reachability of objects used by another worktree. - Repository‑level settings (e.g.,
core.autocrlf,receive.denyNonFastForwards) apply to every linked worktree unless explicitly overridden. - The only per‑worktree isolation is the working tree files and the individual
HEADreference.
Operational Checks
- List active worktrees:
git worktree list. Verify each entry shows the correct branch and path. - Confirm the shared gitdir: from any worktree run
git rev-parse --git-dir; the output should be the original repository’s.gitdirectory. - Run integrity checks on the shared store periodically:
git fsck --full(run from the main repository). Look for dangling commits or corrupted objects. - Never edit the
.gitfile orHEADfile inside a worktree manually; let Git manage them. - Prune stale worktree entries after removing a directory:
git worktree pruneremoves lock files and administrative data.
Failure Modes
- Accidental directory deletion: Removing a worktree folder with
rm -rfleaves a lock file in$GIT_DIR/worktrees. Subsequentgit worktree addmay fail until the lock is cleared (git worktree pruneor manual removal). - Branch checkout conflict: Git prevents the same branch from being checked out in two worktrees simultaneously. Attempting to do so yields an error like "refusing to overwrite worktree file". Use
git worktree add -B new-branchto create a fresh branch if needed. - Garbage collection risk: Running
git gcorgit prunewhile another worktree holds uncommitted work can delete objects that are still referenced only by that worktree’s index, causing data loss. - Stale lock accumulation: Long‑lived worktrees that are abandoned without
git worktree removeleave lock files that accumulate over time.
Conditions That Would Change the Design
- Need for true isolation of refs (e.g., each team must have its own namespace). In that case, separate clones or a server‑side namespace (e.g., using
git clone --sharedwith separate refs) would be required. - CI pipelines that require ephemeral, disposable checkouts. Shallow clones (
git clone --depth 1) orgit worktree add --detachwith a temporary directory are lighter weight. - Extremely large monorepos where cloning the full object store is prohibitive. Sparse‑checkout (
git sparse-checkout init --cone) or partial clones (git clone --filter=blob:none) reduce data transfer, and worktrees can still be built on top of those. - Environments running Git older than 2.5, where linked worktrees are not available. The fallback is to maintain separate clones.
Practical Verification
To confirm that a worktree is correctly linked:
- Create a worktree:
git -C /path/to/repo worktree add /tmp/test-wt dev. - From the worktree, check the gitdir:
git -C /tmp/test-wt rev-parse --git-dirshould output something like/path/to/repo/.git. - List worktrees:
git worktree listshould show an entry for/tmp/test-wtwith thedevbranch. - Make a change in the worktree, commit it, and verify that the commit appears in the main repository’s log:
git -C /path/to/repo log --oneline -1. - Remove the worktree cleanly:
git worktree remove /tmp/test-wt. Afterwards,git worktree listno longer lists the path, andls $GIT_DIR/worktreesshows no leftover lock for that entry.
These steps provide confidence that the shared object store is intact and that the worktree mechanism is behaving as expected.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.