Skip to main content

Worktree Commands and Configuration

Most people learn git worktree add and stop. That’s enough for one worktree. It isn’t enough when agents are creating and deleting them for you. This lesson is the reference shelf: the commands, the configuration that changes behavior across all of them, and the layouts worth choosing between. For the failure modes, see Worktrees in Practice.

Commands

The full git worktree command set is small:

  • add: Creates a worktree.
  • list --porcelain -z: Lists worktrees in a stable, machine-readable format. Each field line, such as worktree, HEAD, or branch, ends in a NUL byte. An empty field separates worktree records, producing a double NUL at each record boundary. Group fields until that empty field; a single NUL is not a complete-worktree delimiter. Use this framing in scripts instead of the human-readable output.
  • lock and unlock: Protect a worktree from being pruned or removed.
  • move: Relocates a worktree. Don’t move the folder yourself.
  • remove: Deletes a worktree.
  • prune: Cleans up records for worktrees whose folders no longer exist.
  • repair: Fixes the links between a repository and its worktrees after something moved.

A few add flags earn their keep:

  • -b with an explicit base: Creates a new branch from a starting point you name, instead of whatever HEAD happens to be.
  • --detach: Checks out a commit without a branch.
  • --no-checkout: Creates the worktree without populating files, so you can set up sparse checkout before anything lands.
  • --orphan (Git 2.42+): Starts a branch with no history.
  • --lock --reason: Locks the worktree at creation and records why.
  • --no-track: Doesn’t set up upstream tracking for the new branch.

Configuration

  • Shared configuration: git config --local changes every worktree, because the repository’s configuration file is shared.
  • Per-worktree configuration: First enable extensions.worktreeConfig in the common configuration. Then move any existing core.worktree and core.bare values that belong to the main worktree into its config.worktree, and remove them from the common file. Perform the move in the main worktree and verify both files before using linked worktrees. As the Git configuration reference explains, git config --worktree acts like --local while the extension is disabled, so moving keys first just writes them back to the shared file. Older versions of Git refuse repositories that have this extension.
  • Relative paths (Git 2.48+): Let you move a repository and its worktrees together, and work inside containers. The cost is that older Git versions and some graphical clients can’t open the repository.
  • Other keys worth knowing: gc.worktreePruneExpire (how long Git waits before pruning stale worktree records; the default is three months), worktree.guessRemote (guess a matching remote branch when creating a worktree), and includeIf "worktree:" (Git 2.56), which applies configuration only to worktrees whose path matches a pattern.

Layouts

  • Siblings (../app-feature): The simplest option. Each worktree is a folder next to the main checkout.
  • Nested and gitignored (.worktrees/, .claude/worktrees/): Self-contained, but some IDEs and indexers trip over it.
  • A bare hub (.bare plus one folder per branch): A bare repository holds the Git data, and every branch is a worktree. You have to fix the fetch refspec (the rule that says which remote branches to download), or you get no origin/* branches.
  • Tool-managed: Let the tool clean them up, not rm.

Advanced techniques

  • Detached worktrees: For frozen reviews and side-by-side regression checks.
  • Bisect in its own worktree: Bisect refs are private to each worktree, so the hunt doesn’t disturb your main checkout. In bisect run, exit code 127 means “command not found,” but it counts as bad. Exit 125 tells bisect to skip.
  • Sparse worktrees: Use --no-checkout, then sparse-checkout set, then an explicit checkout HEAD. You get a worktree with only the folders you named.
  • refs/worktree/*: For private checkpoints that don’t clutter the branch list.
  • A post-checkout hook that bootstraps new worktrees: This is a Git hook, a script Git runs at set points, not a Claude Code hook. When worktree add creates one, the hook’s old-HEAD argument is all zeros, which is how you tell “new worktree” from “ordinary checkout.”
  • Conflict tooling: git merge-tree --write-tree predicts conflicts before you merge. rerere reuses conflict resolutions you’ve already made. range-diff shows what a rebase actually changed.

Pick a layout once, let the tool or one script create every worktree, and never move a folder by hand.

Last modified on .