The Quiet Risk of a Shared Worktree
A commit should answer a simple question: what changed, and why?
That question gets much harder when several pieces of work pass through the same checkout.
It does not take a dramatic mistake. One task leaves a useful-but-uncommitted edit behind. Another task needs to change the same file. A hurried git add stages the whole file, the test suite passes, and a perfectly plausible commit now contains two unrelated decisions.
Nothing is obviously broken. That is what makes it dangerous.
The File Is Not the Unit of Work
Git stages files, but work is usually smaller than a file.
A workflow configuration can contain a reliability tweak from one investigation and an unrelated branching rule from another. A documentation page can hold a factual correction beside a paragraph still being drafted. When those changes share a working tree, git add path/to/file quietly says: “all of this belongs together.” Often it does not.
The resulting commit has costs that do not show up in a green test run:
- Review becomes ambiguous. A reviewer cannot tell which lines support the stated purpose.
- Reverts become unsafe. Undoing one change might undo another task’s legitimate work.
- History becomes misleading. Future readers inherit a false story about why a line exists.
- Ownership blurs. The person or process handling the next task has to rediscover which edits are intentional.
This is not just a neatness problem. It is a concurrency problem: separate pieces of work are mutating shared state without a clear transaction boundary.
Why “I’ll Be Careful” Is Not a Control
The usual response is attention: inspect git status, remember what was already there, stage only the right hunk, reread the diff. All of those are good habits. None is a strong boundary.
Attention is especially fragile when work is interrupted, delegated, or resumed later. The context that made a change obvious at 10:00 may be gone by 14:00. An autonomous loop has the same problem in a different shape: it can preserve logs, but it does not automatically preserve the exact intent behind every unstaged line.
A safe process should not depend on perfect recall.
The practical guardrail is to give each bounded task its own worktree and branch. Isolation turns “remember which lines are mine” into a property of the filesystem:
git fetch origin
git worktree add -b fix/clear-scope ../clear-scope origin/main
cd ../clear-scope
Now the checkout begins at a known commit, and every uncommitted change has one source: the task currently being done.
That does not make the code correct. It makes the change set inspectable.
A Worktree Is a Transaction Boundary
Thinking of a worktree as a folder is accurate but incomplete. It is also a lightweight transaction boundary.
Inside it, a task gets:
- A known starting point — usually the current upstream base.
- A dedicated branch — so incomplete work is not confused with someone else’s progress.
- A local diff — a compact, reviewable statement of intent.
- A clean exit — commit and push the verified change, or discard the worktree without disturbing other tasks.
This is helpful for people working in parallel, but it is also helpful for one person switching contexts. “Parallel” can mean two developers. It can also mean a bug fix, a documentation update, and an interrupted experiment all competing for the same attention across a day.
The important part is not the command. It is the rule: one task should have one explicit change boundary.
The Diff Is Still the Final Authority
Isolation reduces the chance of accidental inclusion; it does not eliminate it. A fresh branch can still contain the wrong edit. A generated file can still change unexpectedly. A test can still pass for the wrong reason.
Before committing, I want two pieces of evidence:
git diff --check
git diff --cached
The first catches basic whitespace errors. The second asks the more important question: does the staged patch tell the same story as the commit message?
Then comes focused verification. For a content change, that may be a production build. For a behavioral change, it should be the smallest relevant test suite plus any necessary typecheck or lint command. “The repository builds” is useful evidence, but it is not a substitute for reading the actual diff.
Only after those checks should a commit be created:
git add path/to/intended-file
git diff --cached
git commit -m "docs: explain isolated worktree boundaries"
git push -u origin HEAD
The path-specific git add is deliberate. When a file genuinely contains two independent changes, use git add -p or split the work before committing. A clean commit is not one that happens to pass CI; it is one that can be understood, reviewed, and safely reversed.
A Small Checklist for Small Changes
For bounded work, the whole protocol can be short:
- Start from an updated upstream reference.
- Create a dedicated worktree and branch.
- Make only the change in scope.
- Inspect
git statusand the staged diff. - Run the smallest verification that exercises the change.
- Commit one coherent intention and push it.
- Remove the worktree after the branch or pull request has a clear home.
The overhead is a few commands. The payoff is avoiding the most expensive kind of mistake: a commit that looks fine today but cannot be safely interpreted tomorrow.
The Point Is Honest History
Version control is not merely a delivery pipe. It is the record future collaborators use to understand a system. When commits preserve a clear boundary between tasks, that record stays useful: reviewers can reason about it, maintainers can revert it, and the next person can build on it without archaeology.
Shared worktrees are convenient. They are also shared mutable state. Treating them casually turns context switching into hidden coupling.
A separate worktree is a small act of restraint. It says that the change should be able to stand on its own — not just compile, but explain itself.