Run two automated agents against the same working directory and one will quietly commit the other’s half-finished files. The fix is one working tree per line of work, not more discipline.
git add -A in one stages every untracked file in the directory – including the other worker’s in-progress files – and the next commit carries them onto the wrong branch. The fix is a git worktree: git worktree add gives each parallel line of work its own directory, HEAD, and index while sharing the repository’s object store. One worktree per agent, branch, or task, and neither can touch the other’s tree.Table of Contents
What actually goes wrong when two workers share one checkout
We hit this running two automated agents in parallel against one repository checkout. Each was editing different files for different branches. One agent finished a change and ran the ordinary git add -A && git commit – and its commit silently included the other agent’s untracked, work-in-progress files, on a branch those files did not belong to. It happened twice before we understood it. Nothing was lost, but the result was files on the wrong branch, a confusing pull request, and a manual untangle.
A shared checkout does not merge two workers politely; the first to stage sweeps up whatever the second left lying around.
The trigger is mundane: broad staging. git add -A, git add ., and git commit -a do not stage “your” files – they stage every changed and untracked path in the working tree. In a directory only one worker touches, that is exactly what you want. With two workers, it is a trap.
Why one working tree cannot safely hold two lines of work
A git repository separates two things people usually conflate: the object store (the history, under .git/) and the working tree (the checked-out files you edit). A normal git clone gives you one working tree bound to one HEAD – the “current branch” – and one index, the staging area a commit is built from.
That single HEAD and single index are the problem. Two workers in one tree share them. If one runs git checkout other-branch, the tracked files change under the other worker’s feet. If one stages broadly, it stages the other’s files too. There is no per-worker view; the working tree is one global mutable surface, and git has no idea two independent tasks are using it.
One checkout is one HEAD and one index – a single global surface that two tasks cannot safely share.
The fix: a worktree per parallel line of work
Git’s built-in answer is git worktree. It attaches additional working trees to the same repository, each in its own directory, each with its own HEAD and index, all sharing the one object store underneath:
# from the main checkout, create an isolated tree for a task, on a new branch
git worktree add ../wt-featureA -b featureA origin/main
git worktree add ../wt-featureB -b featureB origin/main
Code language: Bash (bash)
Now each agent works in its own directory. A git add -A in wt-featureA can only ever see wt-featureA‘s files; a git checkout there moves only that tree’s HEAD. The two lines of work are physically incapable of capturing or overwriting each other, because they no longer share a tree or an index – only immutable history. Branch each worktree off origin/main so it starts from the current base rather than whatever the shared checkout happened to have checked out.
One HEAD, one index. Two workers share both; add -A stages everyone's.
A separate directory per task, each branched off origin/main.
Own dir, HEAD, index; one shared object store. No capture. Clean removal.
Git refuses the same branch in two worktrees at once — that alone blocks the double-checkout that corrupts a shared tree.
A worktree, not a second clone – and why it is cheaper
You could give each worker its own full git clone, and it would also isolate them. A worktree is better on three counts. It shares the object store, so a second tree costs kilobytes of metadata, not a full copy of history. It stays one repository, so branches, tags, and fetches are shared – no juggling several remotes or re-fetching the same objects. And it is disposable: git worktree remove <path> cleans a tree up in one command, and git worktree list shows every tree and the branch it holds.
A worktree shares history and costs almost nothing; a clone duplicates everything and drifts.
The one rule git enforces for you: the same branch cannot be checked out in two worktrees at once. That is a feature – it stops the exact double-checkout that corrupts a shared tree.
The discipline that makes it stick
Tooling helps, but the habit is the real fix. Three rules cover it:
- One worktree per parallel line of work. Before an agent (or a second person) starts editing, give it its own tree off
origin/main. Never let two independent tasks share the main checkout. - Never broad-stage a shared checkout. In any directory more than one worker might touch,
git add -Aandgit commit -aare unsafe – stage explicit paths instead. - Guard it, but keep the escape hatch open. A pre-commit or wrapper check can block a state-mutating git command (commit, checkout, merge) while another process is active in the same tree. Critically, it must exempt
git worktree add– creating a new tree never moves the shared HEAD, so it is the safe way out of the conflict, not into it. A guard that blocks the escape hatch traps you in the shared tree.
This matters far beyond AI agents: two engineers sharing a checkout over SSH, a CI job and a human on the same runner, or a script and a shell in one directory hit the identical collision. It is the same family of shared-resource surprise as a database’s connection limit that is not its concurrency limit – and the mirror image of a resource you should share, like a Playwright browser cache that belongs shared, not per project. The test is always whether the shared thing is immutable history (safe) or a mutable surface (not).
How to verify and clean up
Confirm the isolation and tidy up with three commands:
git worktree list # every tree + the branch each holds
git worktree remove ../wt-featureA # delete a finished tree (add --force if dirty)
git worktree prune # drop admin records for trees deleted by hand
Code language: Bash (bash)
If you ever see a task’s files appear in another branch’s diff, that is the shared-checkout smell – check git worktree list and make sure each line of work actually has its own tree.
The short version
A single git checkout has one HEAD and one index, so two lines of work running in it share both – and a broad git add -A in one commits the other’s untracked files onto the wrong branch. Give each parallel agent, branch, or task its own git worktree, branched off origin/main: separate directory, separate HEAD, separate index, shared object store. Never broad-stage a shared checkout, and if you add a guard, exempt git worktree add so the escape hatch stays open. Clones work too but cost far more; the worktree is git’s built-in, near-free isolation.
Frequently Asked Questions
What is a git worktree?
A git worktree is an additional working directory attached to the same repository, with its own checked-out branch (HEAD) and its own staging index, sharing the repository’s object store. git worktree add <path> -b <branch> creates one. It lets you have several branches checked out at once, each isolated, without cloning the repository again.
Why did my commit include files I did not create?
Because a broad git add -A / git add . / git commit -a stages every untracked file in the working tree, not just the ones you touched. If another process or person left files in the same checkout, they get staged and committed too. In a shared working tree this is how one worker captures another’s in-progress files onto the wrong branch.
Is a git worktree better than cloning the repository again?
Usually, yes, when the goal is isolating parallel work on one machine. A worktree shares the object store (a second tree costs almost nothing), keeps a single set of branches and remotes, and is removed in one command. A second clone duplicates all history and gives you a separate repository to keep in sync. Clone when you need a genuinely separate copy; worktree when you need isolated trees of the same repository.
Can two worktrees check out the same branch?
No, and deliberately so. Git refuses to check out one branch in two worktrees simultaneously, which prevents the double-checkout that corrupts a shared tree. Give each worktree its own branch (-b newbranch), typically created off origin/main.
How do I remove a git worktree safely?
Run git worktree remove <path> (add --force if the tree has uncommitted changes you intend to discard). If you deleted the directory by hand, run git worktree prune to clear the stale bookkeeping. git worktree list shows every tree currently attached so you can see what is safe to remove.