git worktree add: every form of the command

One command with about eight useful shapes. Picking the right one takes thirty seconds and saves the ten minutes you would otherwise spend reading an error message and guessing.

By the Continuum team. We build a workbench that runs Claude Code, Codex, and their peers, so the model rates quoted here are the ones our own cost analytics ship with.

The short version

git worktree add <path> creates a working directory. Add -b <branch> to create a branch at the same time, which is the form you want almost always. Name an existing branch to check it out, use --detach for a read-only look at a commit, and pass a remote ref as the start point to get a local tracking branch. Omit everything and git names a new branch after the directory.

What you need to know
  • git worktree add -b feature/x ../app-x is the form you want 90 percent of the time.
  • An existing branch cannot be checked out twice. That is the first error everyone hits.
  • --detach is the read-only look at a commit or tag.
  • A remote branch needs a local one: -b name ../dir origin/name sets tracking automatically.
  • Omit the branch entirely and git creates one named after basename <path>.
  • Put worktrees beside the repository, never inside it.

Every form of the command

Run all of these from inside the repository. The path argument comes first in every form except the ones where a start point follows it.

The eight shapes worth memorising.
# 1. new branch, new worktree - the common case
git worktree add -b feature/auth ../app-auth

# 2. an existing local branch (must not be checked out elsewhere)
git worktree add ../app-hotfix hotfix/login

# 3. a remote branch: create a local branch that tracks it
git fetch origin
git worktree add -b review/pr-42 ../app-review origin/pr-42

# 4. read-only look at a commit, tag, or old release
git worktree add --detach ../app-v1 v1.0.0

# 5. new branch from a specific base rather than HEAD
git worktree add -b feature/x ../app-x origin/main

# 6. no branch named at all: git names one after the directory
git worktree add ../app-spike        # creates branch "app-spike"

# 7. reset a branch that already exists and check it out
git worktree add -B feature/x ../app-x origin/main

# 8. an empty worktree on a new unborn branch (git 2.42 and newer)
git worktree add --orphan -b docs-site ../app-docs

Form 3 deserves a note too. Naming a remote-tracking ref as the start point does not just copy the commit, it sets upstream tracking, so git push and git status behave the way you expect from the first command:

$ git worktree add -b feature/x2 ../app-x2 origin/feature/x
Preparing worktree (new branch 'feature/x2')
branch 'feature/x2' set up to track 'origin/feature/x'.
HEAD is now at f15eaad init

$ git -C ../app-x2 status -sb
## feature/x2...origin/feature/x

Every flag

Options documented for add in the git-worktree manual, checked August 2026.

FlagDoesUse it when
-b <branch>Create the branch and check it outAlmost always
-B <branch>Same, but reset the branch if it existsRecycling a scratch branch
-d, --detachDetached HEAD; no branch involvedReading a tag or bisecting
-f, --forceOverride the safety refusalsA registered-but-missing path
--track, --no-trackForce upstream tracking on or offOnly valid with -b or -B
--guess-remoteMatch the directory name against remote branchesChecking out a colleague branch by name
--no-checkoutRegister it but leave it emptyConfiguring sparse-checkout first
--orphanNew worktree on a new unborn branchA clean-slate branch, git 2.42 and newer
--lockMark it so prune leaves it aloneRemovable or network storage
--reason <text>Why it is locked; requires --lockSo future-you knows
--relative-pathsLink with relative rather than absolute pathsRepos that move, git 2.48 and newer
-q, --quietSuppress the progress linesScripts

Where to put them

Siblings of the repository. This is the convention, and the reasons are practical rather than aesthetic.

The layout that stays out of your way.
~/code/
  app/            <- main worktree, on main
  app-auth/       <- feature/auth
  app-search/     <- feature/search
  app-review/     <- review/pr-42
Verified on git 2.54: a nested worktree really does show up as untracked.
$ git worktree add -b inside .worktrees/inside
$ git status --short
?? .worktrees/

# If you must keep them contained, exclude the directory locally
$ echo '.worktrees/' >> .git/info/exclude   # not committed, not shared
$ git status --short
(nothing)

Every error, and the fix

These are the messages verbatim from git 2.54, August 2026. The first one accounts for most of the confusion.

Seven refusals, ranked by how often you will see them.

MessageCauseFix
'x' is already used by worktree at '...'That branch is checked out in another worktreeUse -b for a new branch, or --detach
<path> already existsThe directory is therePick another path, or delete the directory
invalid reference: <ref>The start point does not exist locallygit fetch, then use origin/<name>
missing but already registered worktreeYou deleted the directory by handgit worktree prune, or add -f
missing but locked worktreeDeleted by hand and it was lockedgit worktree unlock then prune
cannot lock ref 'refs/heads/x'A branch x/something already existsRename one of them; git refs are directories
not a git repositoryYou ran it outside a repositorycd into the repo first

The branch namespace collision

The sixth row is the one that looks like a git bug and is not. Refs are stored as a directory tree, so a branch called feat/one creates a directory named feat, and nothing can then be a file called feat.

$ git branch feat/one
$ git worktree add -b feat ../app-feat
Preparing worktree (new branch 'feat')
fatal: cannot lock ref 'refs/heads/feat': 'refs/heads/feat/one' exists; cannot create 'refs/heads/feat'

It bites hardest with agent workflows, because generated branch names drift between fix/login and plain fix. Pick one convention: always two segments, or never.

The mutually exclusive flags

$ git worktree add -b q --detach ../app-q
fatal: options '-b', '-B', and '--detach' cannot be used together

$ git worktree add --track ../app-t main
fatal: --[no-]track can only be used if a new branch is created

$ git worktree add --reason hi -b r ../app-r
fatal: the option '--reason' requires '--lock'

Making a new worktree actually runnable

A fresh worktree contains tracked files only, so your first command in it usually fails: no node_modules, no .env, no build output. Two ways to fix that once instead of every time.

01

Wrap add in a shell function

The version almost everyone writes eventually. Put it on your PATH as wt.

#!/usr/bin/env bash
# wt <branch-name> - create a worktree you can immediately run in
set -euo pipefail
name="$1"
dir="../$(basename "$PWD")-${name//\//-}"

git worktree add -b "$name" "$dir"

# gitignored files are not carried over; copy the ones you need
for f in .env .env.local; do
  if [ -f "$f" ]; then cp "$f" "$dir/"; fi
done

cd "$dir"
if   [ -f pnpm-lock.yaml ];    then pnpm install
elif [ -f package-lock.json ]; then npm ci
elif [ -f bun.lockb ];         then bun install
fi

echo "ready: $dir"
02

Or hook it, so every path is covered

Git runs the post-checkout hook on git worktree add too, unless you pass --no-checkout. Hooks are shared across worktrees, so one file in the main repository covers every worktree anyone creates, including ones created by a tool rather than by your function.

.git/hooks/post-checkout (chmod +x it)
#!/usr/bin/env bash
# Runs in the NEW worktree. Args: <old-head> <new-head> <branch-flag>
set -euo pipefail

# Only act on a fresh linked worktree, not on ordinary branch switches.
[ "$1" = "0000000000000000000000000000000000000000" ] || exit 0
[ "$(git rev-parse --git-dir)" != "$(git rev-parse --git-common-dir)" ] || exit 0

root="$(git rev-parse --git-common-dir)/.."
for f in .env .env.local; do
  if [ -f "$root/$f" ]; then cp "$root/$f" .; fi
done
if [ -f pnpm-lock.yaml ]; then pnpm install --silent; fi

The two guards matter. The null old-head narrows it to a fresh checkout, and the git-dir comparison narrows it to a linked worktree, because in the main worktree those two paths are identical.

03

Confirm it fired

$ git worktree add -b feature/auth ../app-auth
Preparing worktree (new branch 'feature/auth')
HEAD is now at f15eaad init
$ ls ../app-auth/.env
../app-auth/.env

Questions people ask

Run git worktree add -b <branch> <path> from inside your repository. That creates the branch and a new working directory in one step. Put the path beside the repository, not inside it.

git worktree add <path> <branch>, with no -b. It fails if the branch is checked out in another worktree, because git allows one branch in one working directory at a time.

Fetch first, then git worktree add -b <local-name> <path> origin/<remote-name>. Git creates the local branch and prints "set up to track", so push and status behave correctly straight away.

Git creates a branch named after the last path segment. git worktree add ../app-spike gives you a worktree on a new branch called app-spike. If worktree.guessRemote is on, git first looks for a uniquely matching remote branch.

Because it is checked out somewhere else. Run git worktree list to find where. Use -b for a new branch, or --detach if you only want to read the tree. On git 2.42 and older the same refusal read "already checked out at".

A branch called x/something already exists, so x is a directory in the ref store and cannot also be a branch. Rename one of the two. Pick a branch naming convention with a consistent number of segments and this stops happening.

As siblings of the repository directory. A worktree created inside the repo appears as an untracked directory in git status and gets indexed twice by editors, language servers and test runners.

Yes. Worktrees carry tracked files only, and node_modules and .env are gitignored. Automate it with a wrapper function or a post-checkout hook, which git runs on worktree add unless you pass --no-checkout.

Sources

Every figure above was read from these pages on August 2026. Vendors reprice without notice; if you find a stale number, tell us.

  1. git-worktree manual
  2. Pro Git book
  3. githooks: post-checkout
Try it

Worktrees,
without the script.

Continuum creates the worktree and branch per session and keeps them all visible in one sidebar.

free app · your subscriptions · local-first