← Back to blog AI & LLM

Claude Code and git worktrees: two sessions, one repo

Parallel Claude Code sessions only started to make sense to me once I stopped running them on the same checkout. Before that, for example, one session would be writing tests for a blog build while another was editing the CSS at the same time. But both were working on the same files. The first one would make a change and commit it, and the second one would carry on as if nothing had happened. Then, in the evening, instead of checking the results, I'd have to figure out which session each change actually came from. And it was completely unnecessary. Git has had a solution for this for years — worktrees: each session gets its own directory and its own branch, but they still work on the same repository. This way, the files don't overwrite each other, and both can commit independently of one another.

(Everything here runs locally on my machine. If I want to completely separate the task from the computer, I use a different approach — I describe it in the article about Claude Code in the cloud. And if you need a refresher on Git commands, I have a separate cheat sheet.)

How worktrees work

You can think of a Git worktree as another working directory connected to the same repository. It shares the history and remote with other worktrees, but its own working files and branch are separate. For details, see the Git documentation. One thing is essential for Claude Code: two sessions can run on a single repository, each in its own directory, and one cannot access the other's files.

When it pays off

For me, two things are decisive.

First: tasks must truly be able to be done independently of one another. One session can write tests while another works on CSS. One can refactor code while another updates the documentation. One can fix a bug while another prepares a new feature. But as soon as the second session needs the results from the first, it doesn't make sense. Instead of saving time, I'm just adding another branch of work that I have to keep track of.

Second: The number of sessions isn't limited by the machine, but by how many outputs I can keep up with. I can handle two sessions. With three, it's a mess: I just end up switching between contexts, rushing through reviews, and doing more harm than good. As a result, I just end up with a growing pile of half-read diffs that I have to go back to one by one.

Step by step

I'll start with one flag:

claude --worktree testy

Claude Code creates a worktree at .claude/worktrees/testy/, creates a branch named worktree-testy, and starts the session within that branch. In a second terminal, I can open another session with a different name in the same way, and both sessions then run concurrently. If I don't specify a name, Claude generates one on its own, something like dark-chocolate-cookie. The shortcut is -w.

I recommend setting the following right away:

  • .gitignore: Add .claude/worktrees/ to .gitignore. Otherwise, the contents of the worktrees will appear in git status of the main checkout.
  • Gitignored files like .env: a new worktree is a clean checkout, so they are not there. If you need them in individual worktrees, create .worktreeinclude in the root directory. The syntax works similarly to .gitignore, except that here you specify the files to be copied into each new worktree.
  • The existing branch: --worktree branches from the default branch by default. However, if I need to run Claude on a specific branch I'm currently working on, I'll create a worktree manually using git and run Claude from within it:
git worktree add ../oprava-formulare fix-formular
cd ../oprava-formulare
claude
  • Cleanup: After the interactive session is complete, Claude takes care of cleanup. If the worktree is empty, it deletes it automatically. If there is unfinished work left in it, it asks if I want to keep it. I can check the current status at any time via git worktree list and remove an unnecessary worktree using git worktree remove.

On Mac and Windows, the principle and set of commands are the same. On Windows, you'll just see paths with backslashes, such as .claude\worktrees\testy. And one thing that surprised me the first time I cleaned up: if there's an NTFS junction or a symlink inside the worktree pointing to a directory located elsewhere, deleting the worktree will only remove the link itself. The target directory remains in place. That's how it's supposed to work, so don't be surprised if the "folder is still there."

Traps and guardrails

  • Parallel sessions do not mean parallel subscriptions. They all draw from the same standard five-hour window and the same weekly limit. The more I run at the same time, the faster they use up the shared quota. This saves me time at the keyboard, not tokens. So running three large tasks in parallel when I'm nearing the end of the window doesn't really pay off for me — I'll easily end up with several sessions in progress at once, and when the window runs out, they'll all stop.
  • Every worktree starts as a new, clean checkout. That means no node_modules, no virtualenv, and no existing build cache. So I reinstall the dependencies for each new worktree. For a smaller project, this is a minor issue, but with a large monorepo, the cost of maintaining additional parallel environments can add up enough that I have to think carefully about the number of worktrees I use. .worktreeinclude helps with smaller configuration files, but of course, it won't install dependencies for me.
  • The new worktree doesn't see my work in progress locally. I ran into this when I first used it: the session told me the file didn't exist. Well, of course — it wasn't in its checkout yet. If I want the new session to be based on my current work, I have to commit the changes first. And to ensure the worktree is created from the commit I'm currently working on (including changes I haven't pushed yet), rather than from the default branch on the remote, I set worktree.baseRef to "head" in my settings.
  • Non-interactive runs via -p behave differently. If I run claude -p --worktree ..., the final interactive cleanup does not occur, and the created worktree remains active. Therefore, from time to time, I go to git worktree list and remove unnecessary items using git worktree remove. If Git reports that the worktree is locked, I first run git worktree unlock.

Conclusion

For me, worktrees are one of the easiest ways to get usable parallel work out of Claude Code. I don't need any additional infrastructure or complicated setup — all it takes is one flag, and each session has its own separate working files and branch.

Rules that have worked well for me: I only run tasks in parallel that aren't dependent on one another; I limit the number of concurrent sessions based on how many results I can thoroughly check; I use .claude/worktrees/ in .gitignore; and I use .worktreeinclude to transfer the necessary local configurations to new worktrees. Most importantly, I keep in mind that all sessions draw from the same subscription limit — the more there are, the faster I burn through tokens.

If a task doesn't require my computer at all — if it's small, clearly defined, and easy to set up — I prefer to send it straight to a cloud session. There, I don't have to worry about isolation or cleanup afterward, because I get a fresh sandbox every time. I mainly use worktrees when I want to keep my work locally and maintain continuous control over it.

Let's work together

What can I help you with?

Got a project, an idea, or just a question? Write, call, send carrier pigeons... Happy to talk it through. No strings attached. Ready?

Let's get started!