The Amend That Landed on Someone Else's Commit

I fixed a typo in a commit message with git commit --amend. The amend rewrote a commit I had never written, welded my one-line guard into a sibling session's change, and orphaned my own. HEAD is shared. --amend assumes it is not.

The Amend That Landed on Someone Else's Commit

You wrote one line. A guard: if (range.empty()) return;, the kind of fix you have made a thousand times. You committed it. Then you spotted a typo in the message and did what everyone does, git commit --amend, to tidy it before anyone saw.

The amend did not touch your commit. It touched someone else's. When you looked at the log, your guard was gone, and a commit you had never written, a sibling session's change to the shader cache, now carried your message with your one line welded inside it. You had not edited that commit. You had not seen it. Git did exactly what you asked. --amend means "rewrite the last commit," and the last commit was no longer yours.

Operating Conditions

Two background sessions on the same task. One repository. One working tree, one HEAD, one index. This is the default when you run a second agent in the same checkout, or open a second terminal, or let a harness spawn a sibling without isolating it. Nobody chose the shared state. It is just what you get when you do not go out of your way to avoid it.

Here is the part that makes it dangerous: nothing on your screen said another writer existed. One HEAD looks identical whether you are the only process moving it or one of three. There is no cursor for "someone else is also committing." You are working in a room you believe is empty, and the room is not empty.

Failure Modes

Two ways this bites. They look like different bugs. They are the same bug in different clothes: a command that assumes it owns state it actually shares.

The amend. git commit --amend does not mean "edit my commit." It means "replace whatever HEAD points at right now." HEAD is one mutable pointer, and it is shared. Between the moment you committed and the moment you amended, the sibling session committed its shader change. HEAD moved to theirs. Your amend rewrote theirs: your guard grafted onto their diff, under your message, your original commit left dangling with no ref pointing at it. git rebase is the same knife, longer blade. It rewrites a range of "your" history, and under a shared HEAD that range is not all yours.

The whole-file add. Now the index, same disease. You finished your change to MainWindow.cpp and ran git add MainWindow.cpp. That stages the file as it sits on disk. But the file on disk already carried a sibling's half-finished edits, because you share the working tree. Your commit, under your message, now contains their unfinished work. Their session comes back later to find its own file already committed, half-done, signed by you. git add <file> is last-write-wins on the index the same way --amend is last-write-wins on history.

Notice what caused neither of these: a bad model, a wrong answer, a hallucination. Both agents did their task correctly. The corruption happened in the plumbing between them, at the two pieces of state git lets more than one writer touch: the HEAD pointer and the index.

Root Cause

This is the first post's thesis with a specific weapon in its hand. The enemy is shared mutable state, and here it is exactly two things: HEAD and the index.

--amend, rebase, and git add <file> are all built on an assumption that was true for your entire career until about a year ago: that you are the only writer. One person, one checkout, one hand on the repo. Under that assumption "the last commit" is a stable noun and "the file on disk" is your file. Run a second agent in the same tree and the assumption quietly breaks, but the commands do not warn you, because from inside a single command there is no way to tell a shared pointer from a private one. The tool that assumes it owns HEAD is the tool that grafts your work onto a stranger's.

Proposed Fix

Rule one, the rule the rest of the series is footnotes to: one writer, one worktree, one branch. Never two writers on one HEAD.

Give each agent its own checkout. Git ships the tool:

git worktree add ../repo-agent-a -b agent-a
git worktree add ../repo-agent-b -b agent-b

Now agent A on agent-a and agent B on agent-b share the object store but nothing mutable. Different HEAD, different index, different files on disk. --amend is safe again because "the last commit" is once more a thing you alone own. There is no sibling write to land on because there is no shared pointer to land it on.

If you genuinely cannot isolate and must share one tree, two rules hold the line:

  • Never `--amend` or `rebase` under a shared HEAD. Amend only the commits you alone created, in a checkout only you write to. Everywhere else, add a new commit instead of rewriting the last one.
  • Commit by hunk, not by file. git add -p and stage only the change you wrote. Watch git status for an MM beside a file: staged changes plus newer unstaged changes usually means someone modified it after you staged. When you see that, do not add the whole file. Take your hunk and leave the rest.

System Status

Under a shared HEAD, "the last commit" is not a noun you own. It is a race, and --amend is you betting the pointer did not move while you were reading the message. Most of the time it did not, which is how the habit survives, and the one time it did you spend an afternoon reconstructing a commit from a reflog and a screenshot.

The fix is not to amend more carefully. It is to stop sharing the pointer. One writer, one worktree, one branch, and the sharpest commands in git go back to being safe, because they are finally telling the truth about who owns what.

What is the worst thing a shared HEAD has done to your history? Give me the command and what it rewrote. The mechanism is the part that transfers.

Further Reading

  • A Swarm Is a Distributed System, Not a Team (Part 1): why every one of these is a shared-write problem, not a smart-enough problem.
  • It Said Done, and Deleted the Branch (Part 3): the commit that is real but unreachable.
  • How I Run Three Agents Without Losing My Mind: the whole index card, worktrees included.

No comments yet