Unwait

Claude Code git worktrees, and what /rewind will not save you from

· 6 min read claude code git worktrees parallel sessions checkpoints workflow

Running several Claude Code sessions on one repo without them colliding, using worktrees. How isolation is actually enforced, the base-branch default that surprises people, why your hooks do not follow the worktree, and the four categories of change checkpoints silently cannot undo.

Two Claude Code sessions on one checkout is a bad time. They edit the same files, one overwrites the other's work, and the diff at the end belongs to nobody. Git worktrees are the fix: a separate working directory with its own files and branch, sharing the same repository history.

claude --worktree feature-auth

That creates .claude/worktrees/feature-auth/ at your repository root on a new branch called worktree-feature-auth, and starts Claude there. Run it again with a different name in another terminal and you have two sessions that cannot touch each other's files. Omit the name and you get a generated one like bright-running-fox.

First housekeeping item, before you forget: add .claude/worktrees/ to your .gitignore, or every worktree shows up as untracked files in your main checkout.

The default that surprises people

A new worktree branches from your repository's default branch on the remote, not from where you are standing. That is worktree.baseRef: "fresh", and it means your uncommitted work and unpushed commits are not in the worktree.

Often that is what you want, since a clean tree matching the remote is a good starting point for an independent task. When it is not, set it:

{
  "worktree": {
    "baseRef": "head"
  }
}

Now worktrees branch from your current local HEAD and carry your feature-branch state. There is no third option for naming a specific branch. To start from one, create the worktree with git yourself.

Worth knowing while you are here: --worktree also takes a pull request. Quote it so your shell does not read # as a comment.

claude --worktree "#1234"

That fetches the PR head from origin and lands you in .claude/worktrees/pr-1234.

A worktree is a fresh checkout, so your .env is gone

This is the first thing that breaks. A worktree contains tracked files only, so gitignored files your app needs are missing and nothing works until you notice.

Add a .worktreeinclude at your project root. It uses gitignore syntax, and only copies files that both match a pattern and are gitignored, so tracked files are never duplicated:

.env
.env.local
config/secrets.json

It applies to every worktree Claude Code creates with git, including subagent worktrees and the desktop app's parallel sessions. One syntax trap: a pattern starting with **/ does not reach into a directory that is gitignored as a whole unless the first name after the **/ appears in that directory's path. Write vendor/**/config.json rather than **/config.json.

You still need to install dependencies in the worktree. It is a fresh checkout, not a clone of your environment.

How isolation is actually enforced

This is better than "please do not edit those files." Claude Code applies four checks and blocks the tool call outright:

The same enforcement covers every subagent spawned from the session. If you want a subagent permanently isolated, put it in the frontmatter:

---
name: refactorer
description: Applies mechanical refactors across many files
isolation: worktree
---

Three things worktrees share with the main checkout

They are less isolated than they look, in ways that are mostly good:

Your hooks do not follow the worktree

If you run hooks, this one will cost you an afternoon. After Claude enters a worktree:

So a hook that lints "the project" will happily lint the wrong directory. Read cwd from the payload when the hook needs the worktree.

One more surprise for repositories using Git LFS with git lfs install --local: worktrees Claude Code creates contain pointer files instead of real content. This is deliberate. A filter driver is a shell command stored in the repository's own config, and anything that can write to the repository could have put it there, so Claude Code skips repo-local filter drivers when creating a worktree. Run git lfs pull inside the worktree.

Cleanup, which is mostly automatic

On exiting an interactive session, Claude checks the worktree for changed files, untracked files, and new commits. Clean unnamed worktrees are removed with their branch automatically. Anything with work in it prompts you to keep or remove, and removing deletes the work.

Two cases leave litter. -p runs have no exit prompt, so their worktrees stay, along with the lock Claude Code took at creation. And a periodic sweep removes subagent and background-session worktrees older than cleanupPeriodDays, but keeps any worktree that still holds work, any belonging to a live session, and any you created with git worktree add, which Claude Code recognizes by the absence of its own marker in the git metadata.

To clear one out by hand: git worktree remove, adding --force if it has changes, and git worktree unlock first if git refuses because of the lock.

What checkpoints cover, and the four things they do not

Worktrees stop sessions colliding. Checkpoints are the other half: undoing a session that went wrong inside one.

Claude Code snapshots your code before each prompt, keeps the 100 most recent per session, and saves them with the conversation so /rewind still works after a resume. Open it with /rewind, or Esc twice on an empty prompt. If there is text in the input, double Esc clears the text instead, which is the reason people think the shortcut does not work.

The menu offers restoring code, conversation, or both, plus two summarize options that compress part of the conversation to free context without touching files.

Now the part worth memorizing, because each of these fails silently:

  1. Bash commands are not tracked. rm, mv, cp run by Claude cannot be undone through rewind. Only edits made with the file editing tools are captured.
  2. Subagent edits are not restored. A subagent edits with the same tools, but its edits usually do not land in your session's checkpoints. The one exception is a foreground forked skill. Everything else, including a background /code-review --fix, needs git to revert.
  3. Symlinked and hard-linked paths are skipped. You get a Restored the code, but skipped N files warning and those files keep their current contents. Dotfile managers that symlink config into your project and pnpm's hard links both land here.
  4. External changes are not tracked, including edits from another concurrent session, which is exactly the situation worktrees exist to prevent.

Snapshots are also swept about 30 days after a session last wrote one. A rewind that far back can fail with No files were restored.

The setup worth copying

Put .claude/worktrees/ in .gitignore, write a .worktreeinclude with your env files, decide baseRef once, and start each independent task with claude --worktree <name>. Commit early inside the worktree rather than relying on checkpoints, because the four gaps above all have the same remedy and it is git.

The point of all this is not tidiness. It is that once sessions cannot collide, running three of them stops being reckless, and the parallel workflow becomes something you can actually sustain. The cost is that you are now waiting on three agents instead of one, which is its own problem, and the one we work on.

Unwait does this for you

A macOS menu bar app that watches your Claude Code and Codex sessions, shows a short card while they work, and puts a strip on screen the moment one finishes. Free for two weeks, no card and no sign up.

Try for free
← All posts