Git, CI/CD & GitOpsXXIII · WorktreesWorktrees
Creating and removing worktrees — git worktree add, -b, --detach, --force
What you'll learn
- Create a worktree pointing at an existing branch, a new branch, or a detached commit
- Use --force to recover from a "branch already checked out" conflict in a controlled way
- Remove a worktree cleanly or forcefully and understand the difference
- Map each flag (-b, --detach, --force) to the production scenario that justifies it
Prerequisites
Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x
The first lesson established that a worktree is a second working
tree attached to the same .git directory. This lesson covers the
mechanics: how to create one with the right initial state, and how
to remove one when it has done its job. The create command has
three flags that change behaviour (-b, —detach, —force); the
remove command has one flag that overrides safety. Each flag maps
to a specific production scenario.
The default create: add with an existing branch
The simplest create is git worktree add $PATH $BRANCH. It
creates a new working tree at $PATH, checks out $BRANCH in
it, and records the link under .git/worktrees/$BRANCH_BASENAME:
git worktree add ~/work/iac-hotfix hotfix/vpn-cert
# Preparing worktree (new branch 'hotfix/vpn-cert')
# HEAD is now at 7g8h9i0
The branch must already exist. If it does not, git worktree add
fails with fatal: invalid reference: hotfix/vpn-cert. The
working tree path must not be an existing non-empty directory. If
it is, the add fails with fatal: '$PATH' already exists. The
target branch must not be checked out in another worktree. If it
is, the add fails with fatal: 'hotfix/vpn-cert' is already checked out at '$OTHER_PATH'.
These three failure modes are intentional. Each one is a guard against a state the user almost certainly did not want: a branch that does not exist, a working tree path that would clobber an existing directory, or a branch that would be checked out twice.
Adding with a new branch: -b
The -b flag creates the branch at the same time as the
worktree, pointing at an optional start-point:
# New branch 'feature/iam-rotation' from origin/main, in a new worktree
git worktree add -b feature/iam-rotation ~/work/iac-feature-iam origin/main
# New branch 'hotfix/s3-bucket' from a specific commit (the rollback commit)
git worktree add -b hotfix/s3-bucket ~/work/iac-rollback a1b2c3d
The -b form is the worktree equivalent of git checkout -b.
The start-point defaults to HEAD if omitted; explicitly naming
it (origin/main, a tag, a commit) is the production discipline
because it makes the branch’s parent unambiguous. A common
incident is a worktree created against a local main that was
three days behind origin/main; the new branch points at the
wrong base and the PR diff includes unrelated changes.
Detached HEAD: —detach
The --detach flag creates the worktree in detached HEAD state —
no branch is checked out, only a commit. This is the worktree
equivalent of git checkout --detach:
# Detached HEAD at a specific commit (an old release tag's commit)
git worktree add --detach ~/work/iac-release-1.4 v1.4.0
# Detached HEAD at HEAD (a quick scratch worktree for inspection)
git worktree add --detach ~/work/iac-scratch
Detached-HEAD worktrees are useful for inspecting old states without creating a branch, for bisect sessions that need to jump between commits without leaving named refs behind, and for short-lived read-only checkouts of a release tag. The worktree keeps the commit reachable from its own HEAD; commits made on top of the detached HEAD are reachable only from that worktree’s reflog, and disappear when the worktree is removed without preserving them.
Forcing through a conflict: —force
The --force flag overrides two of the guards above: a
non-empty target directory and a branch already checked out
elsewhere. Each case is a different operational decision:
# Force-create into a non-empty directory that is known to be stale
git worktree add --force ~/work/iac-feature-iam feature/iam-rotation
# Force-create against a branch already checked out in another worktree
# (the OTHER worktree's index/HEAD will be left in an indeterminate state)
git worktree add --force ~/work/iac-feature-iam-copy feature/iam-rotation
The --force flag is appropriate in two cases: the target
directory is a stale leftover that the user has verified is safe
to overwrite, and the user is recovering from a corrupted
worktree metadata state that the normal add refuses. Neither
case is routine; both should be documented in the runbook when
they happen.
Removing a worktree: clean and forceful
The remove command has two forms:
# Clean remove — fails if the worktree has local changes or untracked files
git worktree remove ~/work/iac-hotfix
# Forceful remove — drops the worktree even if it has local changes
git worktree remove --force ~/work/iac-scratch
The clean form is the production default. It refuses to drop a
worktree that has uncommitted changes, untracked files that
match .gitignore-negation rules, or locks from a previous
git worktree lock (covered in lesson 06). The forceful form
drops the worktree regardless of state; any uncommitted changes
in it are lost.
# Inspect before removing
git worktree list
# /home/alice/work/iac a1b2c3d [main]
# /home/alice/work/iac-feature-iam d4e5f6a [feature/iam-rotation]
# /home/alice/work/iac-scratch 7g8h9i0 (detached HEAD)
# Clean remove of the scratch worktree
git worktree remove ~/work/iac-scratch
git worktree list
# /home/alice/work/iac a1b2c3d [main]
# /home/alice/work/iac-feature-iam d4e5f6a [feature/iam-rotation]
After git worktree remove, the directory is gone and the
.git/worktrees/$NAME metadata record is removed. The branch
itself is not deleted — git worktree remove does not touch
refs. Deleting the branch is a separate git branch -d (or
-D if the branch has not been merged).
Production discipline
- Default to the clean form.
git worktree addwithout--forceandgit worktree removewithout--force. The flags exist for the rare cases where the guards they bypass are wrong, not for routine use. - Name worktree paths off the parent directory. When the
main worktree is at
~/work/iac, name linked worktrees~/work/iac-feature-iam,~/work/iac-hotfix, etc. The sibling naming makesgit worktree listeasy to read and prevents accidental nesting. - Specify the start-point explicitly with
-b. Defaulting toHEADis a common source of “wrong-base” PRs. - Never
--forcea worktree onto an already-checked-out branch. The other worktree’s state is corrupted. If a branch needs to be in two places, use a clone. - Remove worktrees when the branch is merged. A worktree left checked out on a merged branch is a future “branch already checked out” error waiting to happen.
Cross-course references
- Git, CI/CD & GitOps - Part V (HEAD) lesson 03 covers the
detached-HEAD state that
--detachproduces; this lesson applies it to the worktree primitive. - Git, CI/CD & GitOps - Part IX (Merging) lesson 05 covers
aborting a merge, which is the same idea as
--forcefor recovery from a wedged state. - CI/CD Pipeline Patterns - Part III (CheckoutStrategies)
uses
git worktree addin CI runners; the--forceflag is rarely needed there but--detachis routine.
Quiz
Knowledge check · 4 questions
Q1. An engineer runs `git worktree add ~/work/iac-fix hotfix/vpn-cert` and gets the error `fatal: 'hotfix/vpn-cert' is already checked out at '/home/alice/work/iac-vpn'`. What is the safest next step?
Q2. `git worktree remove` deletes the branch the worktree was checked out on, in addition to removing the working tree directory and the .git/worktrees/$NAME metadata.
Q3. List the three flags that change the create semantics of `git worktree add`, and describe one production scenario that justifies each.
Q4. Pick the right `git worktree add` invocation for each of three production situations, and justify the choice.
An infrastructure team needs three worktrees off the same Terraform repository: (a) a new feature branch `feature/iam-rotation` based on `origin/main` for an in-progress refactor; (b) a read-only inspection of release `v1.4.0` to investigate a bug report; (c) a hotfix branch `hotfix/s3-bucket` based on the rollback commit `a1b2c3d` for an emergency fix.
Passing score: 75%. Answers are checked in this browser.