You open the Codex PR and the diff looks fine, but git log is wrong: the last three commits you made are gone, replaced by a single “WIP” commit you never wrote. Or Codex pushed --force after rebasing onto an older base, and a teammate’s commit disappeared. Or the agent amended a commit that was already on main, breaking everyone’s local clone.
Codex agents pattern-match on whatever git instructions they find — your README, an old CONTRIBUTING.md, a stack-overflow snippet pasted in a comment. If any of those say “always squash with git commit --amend” or “rebase onto main before pushing,” the agent will do it, even on shared branches.
The fix is two layers: explicit “never rewrite history” rules the agent reads, and git server protections that reject force-pushes regardless.
Common causes
1. Old README or CONTRIBUTING.md still recommends git commit --amend
Years ago you wrote “squash fixups with git commit --amend --no-edit before pushing.” The doc is still there. Codex reads it, follows it, amends commits that have already been pushed.
How to spot it: grep -ri 'amend\|rebase -i\|force-push' README.md CONTRIBUTING.md docs/. If the agent’s transcript quotes those lines, that is the source.
2. Agent rebased onto main to “resolve conflicts”
Codex saw a merge conflict and decided rebase was tidier. After rebasing it --force pushed. Anyone with the old branch checked out now has divergent history.
How to spot it: Look in the transcript for git rebase, git push --force, or git push -f. Compare the branch’s reflog before and after.
3. Agent amended to “fix a typo in the previous commit”
The model treated commits as drafts. It noticed it forgot to add a file, ran git add forgotten.ts && git commit --amend --no-edit, then --force. The original commit’s SHA is gone — any review comment referencing it now 404s.
How to spot it: Compare git reflog entries. If you see commit (amend) after push, this is it.
4. Squash-on-push default in the agent’s wrapper
Some Codex harnesses default to “squash all task commits into one before pushing.” If you wanted the intermediate commits for review, they are now gone.
How to spot it: PR has exactly one commit even though the transcript shows many distinct edits. Check your Codex/agent harness config for squash_commits: true.
5. Agent ran a destructive cleanup script
You have a scripts/cleanup.sh that does git reset --hard origin/main. Agent ran it thinking it would clean state, wiping uncommitted work and any local commits.
How to spot it: Transcript contains git reset --hard, git clean -fdx, or a call to a project script that does so.
Shortest path to fix
Step 1: Add an explicit AGENTS.md rule
Put this near the top of AGENTS.md:
## Git rules (mandatory)
- Never run `git commit --amend` for any reason.
- Never run `git rebase`, `git rebase -i`, or `git reset --hard`.
- Never run `git push --force` or `git push -f` or `git push --force-with-lease`.
- Always create new commits on top of the current branch tip.
- If a merge conflict appears, stop and report it — do not rewrite history to avoid it.
- To "fix" a previous commit, write a new commit. Use `git revert` for undoing.
Codex follows the first matching rule it sees. Keeping these near the top of the file gives them priority over older READMEs.
Step 2: Audit existing docs for stale advice
Find and update every mention of history rewriting:
grep -rn -E 'commit --amend|rebase -i|push --force|reset --hard' \
README.md CONTRIBUTING.md docs/ .github/
Either delete the lines or add a “DO NOT” prefix with a pointer to AGENTS.md. Old positive advice is worse than no advice for an agent.
Step 3: Protect the branch on GitHub
In repo Settings → Branches, for main and any shared release branch:
- Require pull request before merging
- Require status checks to pass
- Restrict who can push (no one — only via PR)
- Block force pushes
- Block deletions
This is the safety net. Even if Codex tries to force-push, the server says no.
Also consider protecting codex/* and agent/* branch patterns — those are the ones Codex pushes to. If two parallel tasks land on the same branch, force-pushing wipes one.
Step 4: Pre-receive or pre-push hook in setup.sh
Some agent sandboxes let you install client-side hooks. In .codex/setup.sh:
mkdir -p .git/hooks
cat > .git/hooks/pre-push <<'EOF'
#!/usr/bin/env bash
# Block force-push and amend-after-push from the agent sandbox
while read local_ref local_sha remote_ref remote_sha; do
if [[ "$remote_sha" != "0000000000000000000000000000000000000000" ]]; then
if ! git merge-base --is-ancestor "$remote_sha" "$local_sha"; then
echo "ERROR: non-fast-forward push blocked. Do not rewrite history."
exit 1
fi
fi
done
EOF
chmod +x .git/hooks/pre-push
This refuses any non-fast-forward push at the sandbox layer, before it ever reaches GitHub.
Step 5: Review git log before clicking merge
In your PR review checklist:
- [ ] `git log --oneline origin/main..HEAD` shows the commits I expect
- [ ] No `(amend)` entries in `git reflog` for this branch
- [ ] No commits from people other than the agent on this branch
- [ ] Force-push count on the PR is 0 (GitHub shows "force-pushed" in timeline)
Two seconds per PR, catches every variant.
Prevention
- Keep
AGENTS.md“no history rewrite” rules at the top of the file - Sweep README/CONTRIBUTING for outdated git advice every quarter
- Branch protect
mainplus everycodex/*andagent/*pattern - Install a pre-push hook in
.codex/setup.shthat blocks non-fast-forward - Review
git logand the GitHub timeline before merging agent PRs - Use
git revertfor undoing, never--amendorreset --hard
Related
- Codex cannot finish patch
- Codex patch conflicts existing code
- Codex cannot resolve merge conflict
- Codex PR too large
- Codex runs tests but skips failures
- Codex misses project conventions
Tags: #Codex #agent #Troubleshooting #git