Skip to content

Git Worktrees for Parallel CI Builds & Hotfix Isolation

git worktree lets you check out multiple branches simultaneously in separate working directories, all sharing one .git database. A DevOps engineer juggling a release build, an emergency CVE hotfix, and a CI debug session no longer has to git stash dance between them.

Why a DevOps Engineer Needs This

  • Run a long production build on release/2.4 while you keep editing on main.
  • Reproduce a customer's reported bug by checking out their exact SHA in a sidecar worktree — without stashing, without cloning again.
  • Run parallel CI matrix jobs locally: one worktree per GOOS/ARCH combination, each with its own dist/ artifact.
  • Compare two branches side-by-side in your editor (or a diff tool) without constantly switching HEAD.
  • Hotfix flow: main keeps moving forward, hotfix/CVE-2024-9999 lives in a dedicated worktree, you cut the patch tag, merge, and remove it.

Core Concepts

Term Meaning
Main worktree Your normal repo dir; always on whatever branch you checked out
Linked worktree Additional checkout under <repo>/../<branch>-wt (or anywhere)
Shared .git All worktrees share the same object database and reflog
One branch A branch (or detached SHA) can only be checked out in one worktree at a time

Quick Start

# Add a worktree for a hotfix branch (creates branch if missing)
git worktree add ../hotfix-cve-2024-9999 -b hotfix/CVE-2024-9999 main

# Add a worktree pinned to a specific SHA (reproducible CI)
git worktree add ../ci-debug-9f3a1bc 9f3a1bc

# Add a worktree for an existing remote branch
git worktree add ../feature-flag feature/flag-rollout

# List all worktrees
git worktree list

# Remove a worktree when done
git worktree remove ../hotfix-cve-2024-9999
# If the branch is fully merged you can prune it too:
git branch -d hotfix/CVE-2024-9999
git worktree prune

Pattern 1: Parallel Matrix Build (Local CI)

When you need to verify a release across architectures without firing up full CI:

# 1. Bootstrap one worktree per target
for GOARCH in amd64 arm64; do
  git worktree add ../build-${GOARCH} release/2.4
done

# 2. In each, build & drop artifact in a known location
( cd ../build-amd64 && GOARCH=amd64 go build -o dist/app-amd64 ./cmd/app )
( cd ../build-arm64 && GOARCH=arm64 go build -o dist/app-arm64 ./cmd/app )

# 3. Clean up
git worktree remove ../build-amd64
git worktree remove ../build-arm64

Pattern 2: Hotfix Isolation

# main is dirty with WIP; you need a CVE patch *now*
git stash push -u -m "wip: half-finished refactor"
git worktree add ../hotfix ../main -b hotfix/CVE-2024-9999

cd ../hotfix
# ... edit, commit, tag, push ...
git tag -s v2.4.1 -m "CVE-2024-9999 patch"
git push origin hotfix/CVE-2024-9999 --follow-tags

# Back to main
cd -
git worktree remove ../hotfix
git stash pop

Pattern 3: Reproducing a Customer's Bug

A support ticket says: "Crashes on commit a1b2c3d with input X." You don't want to lose your in-progress feature work:

git worktree add ../repro-a1b2c3d a1b2c3d
cd ../repro-a1b2c3d
./run-with-customer-input.sh
# ... gdb, strace, bisect ...
cd -
# worktree stays put until you're finished investigating

Pattern 4: Detached Worktree for Bisecting CI

Combine with git bisect to find which commit broke a CI pipeline, without losing your current branch context:

git worktree add ../bisect-runner HEAD
cd ../bisect-runner
git bisect start
git bisect bad HEAD
git bisect good v2.3.0
# bisect will checkout candidates inside this worktree — your main
# checkout is untouched and keeps your editor state intact

Pitfalls

  • Same branch, two worktrees — disallowed. Git refuses; pick a different branch or a detached SHA.
  • Submodules in worktrees need git submodule update --init in each new worktree; they're not auto-shared.
  • git gc and git prune are global — they affect every worktree's reachable objects. Run git worktree prune afterwards to clean up stale worktree metadata.
  • Editor / IDE must be opened per-worktree; opening the same project in two JetBrains windows can confuse indexing.
  • Sparse-checkout is per-worktree; configure separately if you want different file sets per checkout.

Useful Aliases

# ~/.gitconfig
[alias]
    wt      = worktree
    wta     = worktree add
    wtl     = worktree list
    wtr     = worktree remove
    wtp     = worktree prune

Verification

git worktree list
# /home/devops/myapp                 abc1234 [main]
# /home/devops/build-amd64           def5678 [release/2.4]
# /home/devops/hotfix                9f3a1bc [hotfix/CVE-2024-9999]

ls -la ../build-amd64/.git           # points back to the main repo's .git/worktrees/

When Not to Use Worktrees

  • You only need to peek at one file from another branch → just use git show branch:path or git restore --source=branch -- path.
  • The other branch is on a different filesystem (e.g. NFS) with weird lock semantics — clone separately instead.
  • You're orchestrating dozens of builds in CI — a build matrix in your CI tool is the right answer; worktrees are for local parallelism.