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.
git worktree add -b feature/x ../app-xis the form you want 90 percent of the time.- An existing branch cannot be checked out twice. That is the first error everyone hits.
--detachis the read-only look at a commit or tag.- A remote branch needs a local one:
-b name ../dir origin/namesets 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.
# 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.
| Flag | Does | Use it when |
|---|---|---|
-b <branch> | Create the branch and check it out | Almost always |
-B <branch> | Same, but reset the branch if it exists | Recycling a scratch branch |
-d, --detach | Detached HEAD; no branch involved | Reading a tag or bisecting |
-f, --force | Override the safety refusals | A registered-but-missing path |
--track, --no-track | Force upstream tracking on or off | Only valid with -b or -B |
--guess-remote | Match the directory name against remote branches | Checking out a colleague branch by name |
--no-checkout | Register it but leave it empty | Configuring sparse-checkout first |
--orphan | New worktree on a new unborn branch | A clean-slate branch, git 2.42 and newer |
--lock | Mark it so prune leaves it alone | Removable or network storage |
--reason <text> | Why it is locked; requires --lock | So future-you knows |
--relative-paths | Link with relative rather than absolute paths | Repos that move, git 2.48 and newer |
-q, --quiet | Suppress the progress lines | Scripts |
Where to put them
Siblings of the repository. This is the convention, and the reasons are practical rather than aesthetic.
~/code/
app/ <- main worktree, on main
app-auth/ <- feature/auth
app-search/ <- feature/search
app-review/ <- review/pr-42
$ 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.
| Message | Cause | Fix |
|---|---|---|
'x' is already used by worktree at '...' | That branch is checked out in another worktree | Use -b for a new branch, or --detach |
<path> already exists | The directory is there | Pick another path, or delete the directory |
invalid reference: <ref> | The start point does not exist locally | git fetch, then use origin/<name> |
missing but already registered worktree | You deleted the directory by hand | git worktree prune, or add -f |
missing but locked worktree | Deleted by hand and it was locked | git worktree unlock then prune |
cannot lock ref 'refs/heads/x' | A branch x/something already exists | Rename one of them; git refs are directories |
not a git repository | You ran it outside a repository | cd 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.
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"
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.
#!/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.
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.