Git Worktree Deep Dive: Parallel Branches, One Repository, Zero Headache

Git Worktree Deep Dive: Parallel Branches, One Repository, Zero Headache
Photo by Wolfgang Hasselmann / Unsplash

When people say “Git lets you have multiple branches,” they usually mean logically multiple branches inside one working directory. In real life, though, your working directory can only reflect one branch (one commit) at a time. That limitation is why developers constantly juggle git stash, temporary commits, or messy context switches.

git worktree solves this in a clean, first-class way: it lets you check out multiple branches at the same time, each in its own folder, while sharing the same underlying repository data. If you frequently multitask—hotfixes, review changes, long-running features—worktrees can make your workflow calmer and faster.

Below is an in-depth explanation of how it works, when it helps, where it bites, and how to use it effectively.


1) The mental model: Branch vs Worktree

Branch

A branch is just a name (a reference) pointing to a commit. It is not a folder. It does not “contain files” by itself. Your working directory materializes one commit at a time.

  • Branch = pointer to a commit (refs/heads/my-branch)
  • Working directory = the files you see on disk right now (checked out from one commit)

Worktree

A worktree is an additional working directory attached to the same repository. Each worktree can have its own branch checked out, simultaneously.

  • Worktree = extra checkout folder + metadata linking it to the repo
  • Multiple worktrees share the same .git object database (efficient)

Key idea: With worktrees, you stop treating “one folder = one branch.” Instead you get “one repo = many folders, each on its own branch.”


2) Why Git worktree exists (the pain it removes)

Common pain without worktrees:

  • You’re midway in a feature branch and suddenly need a hotfix on main.
  • You either:
    • stash changes (sometimes painful/unsafe if changes are half-baked),
    • create a “WIP commit” you later rewrite,
    • or keep switching branches and recompiling dependencies repeatedly.

With worktrees:

  • Keep feature work open in one folder.
  • Create a separate folder for hotfix branch.
  • Switch contexts by switching folders, not branches.

This is especially powerful when your project has:

  • expensive builds,
  • heavy dependency installs,
  • long-running test servers,
  • or multiple “states” you want live at once.

3) How Git worktree actually works (under the hood, but practical)

Your main checkout has a .git directory (or a .git file pointing somewhere). With worktrees:

  • There is still one “main” Git directory that stores objects, refs, etc.
  • Each additional worktree gets:
    • a working directory with files
    • a small .git file pointing to metadata stored under the main repo in something like:
      • .git/worktrees/<name>/

Git uses that metadata to ensure safety:

  • A branch is typically “locked” to a worktree while checked out there, preventing you from accidentally checking it out elsewhere and corrupting state.

4) Core commands you should know

Create a new worktree

Create a new worktree folder for an existing branch:

git worktree add ../my-hotfix hotfix/urgent-fix
  • ../my-hotfix = path where the new working directory will be created
  • hotfix/urgent-fix = branch to check out there

If the branch doesn’t exist yet, create it:

git worktree add -b hotfix/urgent-fix ../my-hotfix origin/main
  • -b creates the branch
  • origin/main is the starting point

List worktrees

git worktree list

This shows:

  • path of each worktree
  • which branch/commit it is on
  • and whether it’s “locked” or detached

Remove a worktree

Safest method:

git worktree remove ../my-hotfix

If the folder was deleted manually, clean up metadata:

git worktree prune

Lock / unlock (prevent pruning)

If you keep a worktree around for a long time:

git worktree lock ../my-hotfix
git worktree unlock ../my-hotfix

5) The biggest difference in day-to-day workflow

Without worktrees

  • One folder
  • constant branch switching
  • repeated install/build cycles
  • risk of stashing or half-commits

With worktrees

  • One folder per context
  • feature branch stays “warm”
  • hotfix branch gets isolated
  • you can run two dev servers at once, each from different worktrees

This is why many people say worktrees feel like “Git branches, but real.”


6) Worktrees vs cloning the repo twice

You can clone the same repo into two folders, but worktrees are better in most cases:

Why worktrees are better

  • Disk efficient: objects are shared
  • Faster: no second clone fetch
  • Safer: branch checkout conflicts are managed
  • Cleaner: one repo identity, many working directories

When separate clones are still useful

  • You need different Git configs/remotes/credentials per copy
  • You want totally separate .git metadata (rare)
  • You want isolation across different Git versions/environments

7) Important gotchas (things people discover late)

1) Branches can be “in use”

If branch feature/x is checked out in a worktree, Git may prevent you from checking it out elsewhere.

This is a feature: it prevents two worktrees from writing to the same branch state.

2) Each worktree is a full working directory

Meaning:

  • running npm install in one worktree does not automatically apply to another
  • build artifacts are separate per folder

This is usually good (isolation), but it can surprise people who expected shared node_modules.

Tip: If you want shared dependencies, use tooling like:

  • pnpm store, bun cache, cargo cache, etc.
    But avoid symlinking node_modules across worktrees unless you really understand the tradeoffs.

3) Different worktrees can conflict on ports

If you run two dev servers:

  • one will fail because port 3000 is taken
    Use different ports per worktree (or .env.local per folder).

4) Hooks and tooling

Git hooks are usually stored in the main repo’s .git/hooks. However, your tools might reference relative paths assuming one working directory. Be mindful if scripts assume “repo root is current directory.”


8) Detached HEAD worktrees (and why you might want them)

A worktree can be created at a specific commit without attaching it to a branch (detached HEAD). Useful for:

  • checking out a tagged release for a quick test
  • reproducing a historical build
  • bisecting without disturbing your active branches

Example:

git worktree add ../release-test v1.2.3

If v1.2.3 is a tag, you’ll likely be in detached HEAD state.


9) Practical patterns that work extremely well

Pattern A: Hotfix without interrupting feature

  • Worktree 1: feature/big-refactor
  • Worktree 2: hotfix/payment-timeout

You fix, test, merge hotfix, and your feature worktree never moved.

Pattern B: Code review / PR checkout

Create a worktree just to review a PR branch:

git fetch origin pull/123/head:pr-123
git worktree add ../pr-123 pr-123

Now you can run it locally without messing your main workspace.

Pattern C: Release branch stability

Keep a long-lived worktree for release/1.8 to cherry-pick fixes while continuing normal work elsewhere.

Pattern D: Matrix testing

Have worktrees for:

  • main
  • feature/x
  • experiment/y
    Run tests in parallel, compare results quickly.

10) Recommendations and best practices

  • Put worktrees in a predictable structure, e.g.:
    • ~/code/myrepo/ (main)
    • ~/code/myrepo-wt/hotfix-xyz/
    • ~/code/myrepo-wt/pr-123/
  • Name branches/worktrees consistently:
    • branch: hotfix/xyz, feature/abc
    • folder: wt-hotfix-xyz, wt-feature-abc
  • Regularly prune stale metadata:
    • git worktree prune
  • Prefer worktrees over stash for long-lived context switching.
    • Stash is fine for tiny interruptions.
    • Worktrees are best for “I need to work on this for 1–3 hours.”

11) When you should NOT use worktrees

Worktrees are not always the best hammer:

  • You are extremely space constrained (multiple node_modules can be large)
  • Your project setup assumes only one working directory (some older tooling)
  • You rarely context-switch and stashing is enough

Even then, worktrees remain useful for:

  • PR reviews
  • quick hotfixes
  • testing old tags

12) A simple “starter workflow” you can adopt today

  1. Keep your main folder on your primary branch:
cd ~/code/myrepo
git switch main
  1. Start a feature in a separate worktree:
git worktree add -b feature/new-dashboard ../wt-new-dashboard main
  1. Emergency hotfix arrives:
git worktree add -b hotfix/login-timeout ../wt-hotfix-login main
  1. When done:
git worktree remove ../wt-hotfix-login

This becomes addictive—in a good way.


Other considerations you might be missing

  • CI parity: Having two worktrees lets you quickly reproduce “works on main, fails on branch” issues side-by-side.
  • Faster debugging: You can run a debugger against one worktree while editing another.
  • Safer experiments: Experimental branches stay isolated; no accidental merges or resets in your “real” workspace.
  • Better mental clarity: You associate a physical folder with a task. Less “what branch am I on?” fatigue.

Support Us

Share to Friends