Git Worktree Tutorial - Hands-On Examples for Beginners

Who This Tutorial Is For

You know Git. You can commit, branch, merge. But git worktree is a blank in your knowledge and the man page didn't help.

This tutorial teaches by doing. You'll create a real repo, run real commands, and see real results. Every code block is copy-pasteable. By the end:

  • ✅ You'll have used all 9 git worktree subcommands
  • ✅ You'll understand why each exists
  • ✅ You'll know which situations warrant a worktree
  • ✅ You'll have a cleanup workflow you can reuse daily

Time required: ~20 minutes. Setup: Git 2.17+ (check with git --version).

Looking for the reference manual rather than a tutorial? See Git Worktree Complete Guide.


Part 1: The Setup

Let's create a throwaway repo so you can follow along without risking anything.

mkdir ~/worktree-tutorial && cd ~/worktree-tutorial
git init demo-repo
cd demo-repo

# A few commits on main
echo "# Demo Repo" > README.md
git add README.md && git commit -m "Initial commit"

echo "Version 1" > VERSION
git add VERSION && git commit -m "Add VERSION file"

# Create two branches we'll use later
git branch feat/login
git branch feat/payments

git log --oneline --all

You should see two commits on three branches (main, feat/login, feat/payments).


Part 2: Your First Worktree

# From inside demo-repo:
git worktree add ../demo-login feat/login

What just happened?

  1. Git created a new directory ../demo-login/
  2. Checked out feat/login in it
  3. Added metadata in .git/worktrees/demo-login/

Verify:

git worktree list
# /home/user/worktree-tutorial/demo-repo   abc123 [main]
# /home/user/worktree-tutorial/demo-login  abc123 [feat/login]

ls ../demo-login
# README.md  VERSION

Both directories contain the same files (same commit), but they're on different branches.

Exercise: Open both folders in your editor. Change a file in one — notice the other is unaffected.


Part 3: Making Changes in Parallel

Let's actually use the parallelism.

# In your main worktree (demo-repo), make a change:
cd ~/worktree-tutorial/demo-repo
echo "Main branch feature" >> README.md
git add README.md && git commit -m "Update README on main"

Now hop to the other worktree:

cd ~/worktree-tutorial/demo-login
cat README.md          # still the old version — different branch!
echo "Login feature" > LOGIN.md
git add LOGIN.md && git commit -m "Add LOGIN feature"

Back in the main:

cd ~/worktree-tutorial/demo-repo
ls                     # no LOGIN.md here
git branch             # you're on main, no LOGIN.md because that's on feat/login

Both branches advanced independently. Zero conflicts.


Part 4: Creating a Brand-New Branch With Worktree

The most common real-world pattern: new branch + new worktree in one command.

cd ~/worktree-tutorial/demo-repo
git worktree add -b feat/signup ../demo-signup main

This:

  1. Creates branch feat/signup starting from main
  2. Creates worktree ../demo-signup on that branch

Now you have four total worktrees:

git worktree list
# /home/user/worktree-tutorial/demo-repo     [main]
# /home/user/worktree-tutorial/demo-login    [feat/login]
# /home/user/worktree-tutorial/demo-signup   [feat/signup]

Tip: Make this your default for starting any new task. The older git checkout -b new-branch habit is a worktree opportunity in disguise.


Part 5: Trying to Check Out the Same Branch Twice

Git protects you from inconsistent states. Let's see it in action:

cd ~/worktree-tutorial/demo-repo
git worktree add ../demo-login-2 feat/login
# fatal: 'feat/login' is already checked out at '/home/user/worktree-tutorial/demo-login'

Lesson: A branch lives in one worktree at a time. If you want parallel work on the same branch, you need two different branches (perhaps diverging from the same start point).


Part 6: Listing Worktrees (Machine-Readable)

For scripts:

git worktree list --porcelain

Output:

worktree /home/user/worktree-tutorial/demo-repo
HEAD abc1234...
branch refs/heads/main

worktree /home/user/worktree-tutorial/demo-login
HEAD def5678...
branch refs/heads/feat/login

Easy to parse with awk or grep:

git worktree list --porcelain | awk '/^worktree / { print $2 }'

Part 7: Cleaning Up

cd ~/worktree-tutorial/demo-repo

# Remove a worktree (clean)
git worktree remove ../demo-signup

# Verify
git worktree list
# demo-signup is gone

# The branch still exists:
git branch
#   feat/login
#   feat/payments
#   feat/signup   <-- still here
# * main

# Delete the branch too (it's unmerged, so -D):
git branch -D feat/signup

What if there are uncommitted changes?

cd ../demo-login
echo "dirty work" >> LOGIN.md    # uncommitted
cd ../demo-repo
git worktree remove ../demo-login
# fatal: contains modified or untracked files, use --force to delete it

Two choices:

# A) Save the work:
cd ../demo-login && git add . && git commit -m "WIP" && cd -
git worktree remove ../demo-login

# B) Force and lose the work:
git worktree remove --force ../demo-login

Full cleanup guide: How to Remove a Git Worktree →


Part 8: Simulating a Dead Worktree

What if you (or a teammate) deletes a worktree folder directly?

# Create one:
git worktree add ../demo-oops feat/payments

# Simulate the mistake:
rm -rf ../demo-oops

# Git still thinks it's there:
git worktree list
# /home/user/worktree-tutorial/demo-repo     [main]
# /home/user/worktree-tutorial/demo-oops     (inaccessible)

# Clean it up:
git worktree prune -v
# Removing worktrees/demo-oops: gitdir file points to non-existent location

git worktree list
# demo-oops is gone

Part 9: The Complete Worktree Workflow

Putting it all together — the daily workflow:

# START OF DAY
cd ~/projects/myapp
git worktree list    # what am I working on?

# NEW TASK: spin up a worktree
git worktree add -b feat/new-thing ../myapp-new-thing origin/main
cd ../myapp-new-thing
# ... do work, commit, push ...

# EMERGENCY: hotfix in parallel
cd ~/projects/myapp
git worktree add -b hotfix/urgent ../myapp-hotfix origin/main
cd ../myapp-hotfix
# ... fix, commit, push, PR ...

# END OF DAY / WEEK: cleanup
cd ~/projects/myapp
git worktree list
# Go through each, decide keep / remove
git worktree remove ../myapp-finished-task
git branch -d feat/finished-task

Part 10: The ParallelCode Equivalent

Everything above, but through a UI:

  1. Open ParallelCode, pick your repo
  2. Click "+ New Task"
  3. Type the task name
  4. ParallelCode creates the worktree, switches to a new branch, and can even launch Claude Code / Cursor Agent inside it
  5. When done, click "Archive" — worktree removed, branch optionally deleted

You lose nothing from the raw Git workflow — all the same commands run under the hood. You gain a visual overview of all tasks across all repos, plus native integration with AI coding agents.

Download ParallelCode — Free →


Exercises (Optional)

Try these on your own:

  1. Multi-repo worktree: create a worktree for one repo while inside another. Does git worktree list show both? (Answer: no — list is per-repo.)
  2. Detached worktree: git worktree add --detach ../demo-at-first-commit abc1234 — inspect the code at the first commit, then remove.
  3. Worktree on a tag: create a tag with git tag v0.1, then git worktree add ../demo-v0.1 v0.1. What branch are you on? (None — it's detached on the tag's commit.)
  4. Rename a worktree: git worktree move ../demo-login ../demo-auth. What happens to the branch name?
  5. Locked worktree: git worktree lock ../demo-login --reason "test". Now try remove. Unlock and try again.

What You Learned

  • git worktree add in three forms (existing branch, new branch, detached)
  • git worktree list for inspection
  • git worktree remove for cleanup (clean and --force)
  • git worktree prune for recovering from rm -rf
  • git worktree move for renaming
  • git worktree lock / unlock for protection
  • ✅ The relationship between worktrees, branches, and the main repo

Where to Go Next


Once you've done this tutorial, you're ready for real parallel workflows.

ParallelCode turns everything you just learned into a one-click UI, with first-class support for Claude Code and Cursor Agent.

Download ParallelCode →

Related posts