git worktree list will feel as natural as
git branch.
Open a terminal in any git repository โ your current project is perfect.
We'll create a worktree for a new branch called
experiment/lesson-0001.
# From the root of your repo:
git worktree add ../my-project-lesson-0001 -b experiment/lesson-0001
That's it. You now have a second working tree. Let's break down what just happened.
The command
git worktree add <path> -b <branch> does three
things simultaneously:
experiment/lesson-0001) at the same commit as your current
HEAD
.git/worktrees/ so git knows it exists
If the branch already exists, omit -b:
git worktree add ../path/to/worktree existing-branch
Let's examine the result piece by piece. Run each command and compare what you see to the explanation below.
git worktree list
You'll see output like:
/Users/mark/dev/my-project abc1234 [main]
/Users/mark/dev/my-project-lesson-0001 abc1234 [experiment/lesson-0001]
Each line shows: path, commit hash,
branch name (in brackets). The first line is your
main worktree โ the original one. The second is your new
linked worktree. Both are at the same commit because
-b branched from HEAD.
git worktree list is your dashboard. Run it
whenever you need to orient yourself. It answers "what worktrees exist,
where are they, and what branch is each on?" in one line. Make it a habit.
# In your MAIN worktree:
ls -la .git
# Output: a directory full of subdirectories (objects/, refs/, etc.)
# In the NEW worktree:
ls -la ../my-project-lesson-0001/.git
# Output: a single FILE, not a directory
cat ../my-project-lesson-0001/.git
# Output: gitdir: /Users/mark/dev/my-project/.git/worktrees/my-project-lesson-0001
This is the secret handshake from Lesson 0000 made concrete. The linked
worktree's .git is a pointer file, not a
directory. It tells git: "your real metadata lives over there, in the main
repo's .git/worktrees/."
ls -la .git/worktrees/my-project-lesson-0001/
# Output: HEAD ORIG_HEAD commondir gitdir index logs/
This directory is the linked worktree's private git state. Let's look at each file:
| File | What it holds |
|---|---|
HEAD |
Which branch/commit is checked out in this worktree |
ORIG_HEAD |
The previous HEAD (used by git reset, merge conflict
recovery)
|
index |
The staging area โ what's currently staged in this worktree |
commondir |
Path back to the main .git/ directory (one level up from
worktrees/)
|
gitdir |
Path to this metadata directory (self-referential) |
logs/ |
HEAD reflog for this worktree (separate from the main worktree's reflog) |
git reflog in a linked worktree only shows that worktree's
history, not the whole repo's.
The mental model says the object database and refs are shared. Let's verify.
# In the MAIN worktree:
echo "hello from main" >> shared-test.txt
git add shared-test.txt
git commit -m "add shared-test from main worktree"
# Now switch to the LINKED worktree:
cd ../my-project-lesson-0001
git log --oneline -3
# You'll see the new commit immediately โ no fetch needed.
# The branch you created also appears everywhere:
git branch --list 'experiment/*'
# Shows experiment/lesson-0001 in both worktrees.
No git fetch. No git pull. The commit is visible
immediately because all worktrees share the same
.git/objects/ and .git/refs/.
# In the LINKED worktree:
echo "staged in linked worktree" >> isolation-test.txt
git add isolation-test.txt
git status
# Shows isolation-test.txt as staged
# In the MAIN worktree:
cd ../my-project
git status
# Shows nothing about isolation-test.txt โ it's invisible here.
The staging area (index) is per-worktree. Untracked files are also per-worktree โ each worktree has its own set of files on disk. This is the isolation you need for parallel work.
When you're done with a worktree, clean it up properly:
# The safe way โ refuses if there's uncommitted work:
git worktree remove ../my-project-lesson-0001
# Force removal (discards uncommitted changes):
git worktree remove --force ../my-project-lesson-0001
# Verify it's gone:
git worktree list
rm -rf.
If you manually delete the directory, git still has metadata in
.git/worktrees/ โ and git worktree list will
show a "prunable" entry. Use git worktree prune to clean
those up, or better yet, always use git worktree remove.
| Command | What it does |
|---|---|
git worktree add <path> <branch> |
Create a worktree at path with
branch checked out
|
git worktree add -b <new-branch> <path>
|
Create a worktree AND a new branch simultaneously |
git worktree add --detach <path> <commit>
|
Create a worktree in detached HEAD at a specific commit |
git worktree list |
Show all worktrees with path, commit, and branch |
git worktree list --porcelain |
Machine-readable format (useful for scripts) |
git worktree remove <path> |
Safely remove a worktree (refuses if dirty) |
git worktree remove --force <path> |
Remove a worktree even if it has uncommitted changes |
git worktree prune |
Clean up metadata for worktrees whose directories were deleted |
You run git commit in a linked worktree. Does the
commit appear in git log in the main worktree?
Think about it, then click to reveal.
.git/objects/ database and the branch ref is updated
in the shared .git/refs/. All worktrees see the new
commit instantly.
You run git add in a linked worktree. Does
git status in the main worktree show the staged file?
Think about it, then click to reveal.
.git/worktrees/<name>/index. Each worktree has
its own staging area.
You run git branch -D experiment/lesson-0001 in the
main worktree while the linked worktree still has that branch
checked out. What happens?
Think about it, then click to reveal.
git worktree remove), which also handles the branch cleanup.
git worktree add <path> -b <branch> creates a
new branch and a new working tree in one command.
git worktree list is your dashboard โ use it to orient
yourself across multiple worktrees.
.git is a
file that points to
.git/worktrees/<name>/ in the main repo.
git worktree remove, never
rm -rf.
Primary source:
git-worktree โ COMMANDS section. The add, list, remove, and
prune subcommands are documented here with all flags.
Ask questions: If the isolation model isn't clear, ask your agent-teacher to walk through a specific scenario โ e.g., "What happens if I rebase in worktree A while worktree B has the old version of the branch checked out?"