BLACK LABELAcademy
← Our Failures

A second agent (or a self-coder running 'git checkout .') silently reverts your uncommitted work

intermediate6 min read · updated 2026-06-20

Market & numbers — every figure sourced

uncommitted_work_recoverable_via_git0 percentest: git design: tracked-but-uncommitted edits live only in the working tree and index; 'git checkout .' / 'git restore .' overwrite them with no object written to the database, so reflog/fsck cannot recover them (per git-checkout & git-restore docs)
commit_time_to_make_work_durable10 secondsest: wall-clock estimate for 'git add -A && git commit -m wip' on a small change set; the point is it is trivially fast relative to the cost of losing the work

A second agent (or a self-coder running 'git checkout .') silently reverts your uncommitted work

You spend an hour with an agent fixing a real bug. The edits look right on disk. Then they're just... gone. The file is back to its last-committed state, no error, no diff, no trace. Nothing crashed. Something quietly reset the working tree out from under you.

This is one of the most demoralizing failure modes in agent-driven and multi-process development, because the work never existed anywhere durable. We've eaten this exact loss more than once, and it always comes from the same two sources.

What we tried

We ran more than one thing against the same repo at the same time:

Both felt safe in the moment. Worktrees are supposed to isolate work. And an auto-loop resetting to clean before it starts seems hygienic. The assumption in both cases was: "my uncommitted edits are mine; another process can't touch them."

What broke

The killer detail: uncommitted edits are not stored in git's object database. Tracked-but-uncommitted changes live only in your working tree and index. When any process runs `git checkout .` or `git restore .`, git overwrites those files with their last-committed content and writes nothing to the object store. There is no dangling commit, no blob to fish out — so reflog and fsck cannot bring it back 0. That's the whole horror of it: it's not "hard to recover," it's unrecoverable by git.

The two paths to that reset:

The unifying root cause: work that isn't committed has no owner git will defend. Worktree isolation protects committed branch state, not your dirty working tree against a sibling process that runs a reset.

The fix

Commit fast, and disarm anything that resets the tree. Two moves:

1. Make work durable the instant it's worth keeping

A WIP commit takes about 10 seconds and converts "ephemeral edits a reset can erase" into "an object in the database that survives any later checkout/reset and is recoverable via reflog."

```bash

git add -A && git commit -m "wip: <what you just did>"

```

Don't wait for "done." Commit the moment the work would hurt to lose. You can always `git commit --amend` or squash later. A commit is the only thing a sibling process can't silently revert — and even if a branch gets rewound, the commit stays reachable through `git reflog` (git-reflog docs).

If you're not ready to commit, at least stash — `git stash` saves dirty state as real commit objects (git-stash docs), so a later `git checkout .` in the tree can't touch it.

2. Disarm the wiper

Find the self-coder / auto-improve / watcher process and either stop it or remove its reset step before you start hand-editing in that repo.

```bash

find scheduled resetters (macOS launchd example)

launchctl list | grep -i improve

launchctl unload ~/Library/LaunchAgents/com.<yourorg>.improve.plist

grep the loop's source for the destructive commands

grep -rn "checkout \.\|reset --hard\|restore \." path/to/loop/

```

The non-negotiable rule for any automated loop: it must never run `git checkout .` / `git reset --hard` / `git restore .` on a tree a human or another agent might be editing. If a loop needs a clean state, it should do its work in its own dedicated worktree or a throwaway clone, never the shared one.

3. Keep multi-agent work on separate branches in separate worktrees

If you genuinely want two agents in parallel, give each its own worktree on its own branch and let them integrate by merging commits — not by sharing a dirty working tree:

```bash

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

```

Then neither one's reset can reach the other's files, and integration happens through committed history.

Apply it

Sources

© 2026 Black Label · Education, not financial or legal advice. Every number is sourced or labeled an estimate. Subscribe for $30/month