With Git worktrees, a Git repository can support multiple working trees. This allows you to check out more than one branch at a time.

Main Vs. Linked Worktrees

Git supports two kinds of worktrees:

  • Main worktree: Created when you run git clone <some_repo> or git init, as long as the repository is not a Bare Repository.
  • Linked worktree: Created by running git worktree add <worktree_path>.

A repository has one main worktree if it is not a bare repository, and zero or more linked worktrees.

Worktree Commands

Create Worktrees

Use git worktree add to create a new linked worktree:

git worktree add <worktree_path>

The <worktree_path> can point almost anywhere:

  • Another folder on the same computer
  • A mounted drive
  • A portable device

This command will either create a new branch (with the same name as <worktree_path>) or, if that branch already exists, check out the existing branch in the newly created worktree.

You can also explicitly specify the branch to check out in the new linked worktree:

git worktree add <worktree_path> <branch_name>

However, this works only if the following conditions are met:

  1. <branch_name> already exists.
  2. The branch is not currently checked out in another worktree.

Otherwise, Git will return an error.

List Worktrees

Run this from inside any worktree to see all worktrees connected to the same repository:

git worktree list

Use --porcelain when you want a more structured output. It prints each worktree attribute on its own line:

git worktree list --porcelain

Remove Worktrees

Use git worktree remove to delete a linked worktree and its files:

git worktree remove <worktree_path>

This removes the working tree folder, but it does not delete the branch that was created or checked out for that worktree.

Fiddling with Worktree Commands

We will use this dummy repo as a sandbox for testing worktree commands and observing how Git behaves.

The repository has two useful details for this walkthrough:

  • The default branch name is master.
  • The default branch, master, contains only a single README file.

Default Clone

Start with a normal clone:

git clone git@github.com:ishahroz/Hello-World.git

Move into the repository and list the files:

cd Hello-World
ls
 
# .git  README

Now list the worktrees:

git worktree list --porcelain
 
# worktree ~/Hello-World
# HEAD XXXXa60b01f91b31XXXXX5a4e4d4e80d8edXXXX
# branch refs/heads/master

The normal clone creates the main worktree, checked out on the master branch.

Now create a linked worktree:

git worktree add Hello-Test1

Because the path is Hello-Test1, Git creates:

  • A new folder named Hello-Test1
  • A new branch named Hello-Test1

Since we ran the command from inside the main repository, the new worktree is created inside the main repository folder:

ls
 
# .git  Hello-Test1  README

List the worktrees again:

git worktree list --porcelain
 
# worktree ~/Hello-World
# HEAD XXXXa60b01f91b31XXXXX5a4e4d4e80d8edXXXX
# branch refs/heads/master
 
# worktree ~/Hello-World/Hello-Test1
# HEAD XXXXa60b01f91b31XXXXX5a4e4d4e80d8edXXXX
# branch refs/heads/Hello-Test1

Move into the linked worktree and check its status:

cd Hello-Test1 && git status
 
# On branch Hello-Test1
# nothing to commit, working tree clean

The linked worktree is on the new Hello-Test1 branch that Git created for it.

Now go back to the main repository and check its status:

cd .. && git status
On branch master
Your branch is up to date with 'origin/master'.
 
Untracked files:
  (use "git add <file>..." to include in what will be committed)
	Hello-Test1/
 
nothing added to commit but untracked files present (use "git add" to track)

Notice two things:

  • The main worktree is still on master.
  • The Hello-Test1/ folder appears as untracked content because it was created inside the main repository.

For this reason, linked worktrees are usually easier to manage when they live outside the main repository folder.

Remove the linked worktree:

git worktree remove Hello-Test1

After removal, the folder is gone and only the main worktree remains:

ls
# .git  README
 
git worktree list --porcelain
 
# worktree ~/Hello-World
# HEAD XXXXa60b01f91b31XXXXX5a4e4d4e80d8edXXXX
# branch refs/heads/master

Now create the same linked worktree one level outside the main repository:

git worktree add ../Hello-Test1
ls
# .git  README
 
git worktree list --porcelain
 
# worktree ~/Hello-World
# HEAD XXXXa60b01f91b31XXXXX5a4e4d4e80d8edXXXX
# branch refs/heads/master
 
# worktree ~/Hello-Test1
# HEAD XXXXa60b01f91b31XXXXX5a4e4d4e80d8edXXXX
# branch refs/heads/Hello-Test1

This time, the main repository stays clean because the linked worktree lives beside it, not inside it.

cd ../Hello-Test1 && git status
 
# On branch Hello-Test1
# nothing to commit, working tree clean
 
ls 
# .git  README

Inside the linked worktree, .git is not a metadata folder. It is a file that points back to the main repository’s Git metadata:

 cat .git
 
 # gitdir: ~/Hello-World/.git/worktrees/Hello-Test1

That reference is how Git connects this linked worktree back to the Hello-World repository.

You can still list all worktrees from inside the linked worktree:

git worktree list --porcelain
 
# worktree ~/Hello-World
# HEAD XXXXa60b01f91b31XXXXX5a4e4d4e80d8edXXXX
# branch refs/heads/master
 
# worktree ~/Hello-Test1
# HEAD XXXXa60b01f91b31XXXXX5a4e4d4e80d8edXXXX
# branch refs/heads/Hello-Test1

Create a new file called TestFile.md and commit it (don’t worry—we’ll come back later to why we created this file):

touch TestFile.md
 
git add . && git commit -m "Add TestFile.md"

Remove the linked worktree again, then check the main repository status:

git worktree remove Hello-Test1
 
cd ../Hello-World && git status
 
# On branch master
# Your branch is up to date with 'origin/master'.
 
# nothing to commit, working tree clean
 
 
git worktree list --porcelain
 
# worktree ~/Hello-World
# HEAD XXXXa60b01f91b31XXXXX5a4e4d4e80d8edXXXX
# branch refs/heads/master

Removing a linked worktree deletes the working tree files, but it does not delete the branch.

git branch
 
# master
# Hello-Test1

Let’s check out the Hello-Test1 branch again:

git checkout Hello-Test1
 
ls
# .git  README  TestFile.md

We can see that TestFile.md, which we committed earlier, is still present in the branch. The branch itself was not deleted.

This means we can still create a new working tree and check out the Hello-Test1 branch there, even if the previous working tree with the same name was removed.

Create a directory with the same name as the repository:

mkdir Hello-World && cd Hello-World

Clone the dummy repository as a Bare Repository:

git clone --bare git@github.com:ishahroz/Hello-World.git .git

This command downloads only the Git metadata and creates only the .git folder:

ls
 
# .git
 
ls .git
# config  description  HEAD  hooks  info  objects  packed-refs  refs

This .git directory is the same folder that Git creates when you perform a normal clone, except that no working files are checked out.

Let’s print the worktrees:

git worktree list --porcelain
 
# worktree ~/Hello-World
# bare

At this point, there is not a single linked worktree.

If we try to run git status or git checkout, Git will throw an error because these commands must be executed within a valid worktree:

git status
# fatal: this operation must be run in a work tree
 
git checkout master
# fatal: this operation must be run in a work tree

It is time to create a worktree with the path master and the master branch checked out:

git worktree add master

Let’s list the folder contents again. You can now see a new folder named master, which is a linked worktree:

ls
# .git  master

Let’s move to the master folder and run git status again:

cd master
 
git status
 
# On branch master
# nothing to commit, working tree clean

Since we are now inside a valid worktree, Git commands work as expected.

Let’s print the worktree list again:

cd .. && git worktree list --porcelain
 
# worktree ~/Hello-World
# bare
 
# worktree ~/Hello-World/master
# HEAD xxxxa60b01f91b314f5xxxxa4e4d4e80d8edxxxx
# branch refs/heads/master

We can now see the linked worktree associated with the master branch.

We can even remove the worktree and create it again later:

git worktree remove master
 
ls
# .git