你让 Codex 继续做一个长 branch。它开了头就停:“merge conflict in src/api/handler.ts”。更糟的版本:它把还带 <<<<<<< HEAD 标记的文件 commit 进去。再糟一点:它整段挑了错的那边,把上周 merge 进 main 的新逻辑直接丢了。
Codex 不是被训练来当 merge conflict 专家的。Model 能读两边,但没有语义 context(每一边为什么存在),常常靠猜。可靠的修法是让 agent 别遇到 conflict:调用前先 rebase、或 setup.sh 自动 rebase、再写 AGENTS.md 规则 “撞 conflict 就停下来上报”,不许 “挑一边”。
常见原因
1. branch 太老,撞 conflict 不可避免
你的 feature/x 是上周二切的。main 之后又走了 40 个 commit。Codex 改任何东西都得撞。
如何判断:git log --oneline origin/main..HEAD 没几条;git log --oneline HEAD..origin/main 一大坨。Branch 落后太多。
2. agent 开工前没 rebase
Codex 的 setup.sh 只跑 npm install,没 git rebase origin/main。agent 在过期 tree 上动手,conflict 要到 apply_patch 才浮现。
如何判断:setup log 里没 rebase / pull。第一个 conflict 出现在 apply_patch 阶段。
3. Codex 把 conflict marker 一起 commit 了
Model 看到 <<<<<<< HEAD ... ======= ... >>>>>>> main,没认出它是控制 marker,当成普通文本留下。PR 现在真有 <<<<<<< 行。
如何判断:git diff origin/main..HEAD | grep -E '^\+(<<<<<<<|=======|>>>>>>>)' 有 match。build 也会挂。
4. agent 整段挑了一边
让它解决 conflict,Codex 每个冲突点都全选 ours 或 theirs,根本没读。它挑的标准是 diff 更小或编译错更少,不是哪边对。
如何判断:PR 把刚 merge 进 main 的功能掉了,或把本 branch 该加的工作丢了。和 git log 对照。
5. 用 merge 而不是 rebase,结果产生 merge of merges
Codex 跑了 git merge origin/main,撞 conflict、修了;后来 main 又有新 commit,又 git merge origin/main、又 conflict。history 变成 merge commit 的鼠窝,每个 merge 都带自己的 conflict。
如何判断:git log --oneline --graph 一堆 merge commit。history 难读。
最短修复路径
Step 1:调用 Codex 之前先 rebase
养成习惯,或写进 harness:
git fetch origin
git rebase origin/main
# 撞 conflict 就在自己 editor 里解,绝不在 Codex 里解
git push --force-with-lease
# 然后再 invoke Codex
agent 跑之前 tree 干净,能消除 90% 中途 conflict。
Step 2:setup.sh 里加 pre-rebase
如果 Codex harness 支持,.codex/setup.sh:
#!/usr/bin/env bash
set -euo pipefail
# branch 落后太多直接拒绝开工
git fetch origin main --quiet
behind=$(git rev-list --count HEAD..origin/main)
if [ "$behind" -gt 50 ]; then
echo "ERROR: branch 落后 main $behind 个 commit。调用 Codex 前先 rebase。"
exit 1
fi
# 尝试干净 rebase。撞 conflict 直接退出。
if ! git rebase origin/main; then
git rebase --abort
echo "ERROR: rebase 撞 conflict。手动解决后再 retry。"
exit 1
fi
npm ci
这样 agent 永远只在干净 tree 上跑。Conflict 上报给人。
Step 3:AGENTS.md “撞到就停” 规则
## Merge conflict 处理
只要看到 conflict marker(`<<<<<<<`、`=======`、`>>>>>>>`),或
`git status` 显示 "both modified":
1. 立刻停下。
2. 不要编辑文件去除 marker。
3. 没有人类明确指示,不要选 `ours` 或 `theirs`。
4. 跑 `git rebase --abort` 或 `git merge --abort` 恢复干净状态。
5. 在 PR 描述里写明冲突文件和对应 commit。
6. 把任务标记为 blocked。
绝不允许 commit 含有 `<<<<<<<`、`=======`、`>>>>>>>` 的文件。
agent 有明确退路,不需要猜了。
Step 4:pre-commit hook 拦 conflict marker
.codex/setup.sh:
mkdir -p .git/hooks
cat > .git/hooks/pre-commit <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
if git diff --cached -U0 | grep -E '^(\+|-)?\s*(<<<<<<<|=======|>>>>>>>)\s' >/dev/null; then
echo "ERROR: commit 里有 merge conflict marker。先解决再 commit。"
exit 1
fi
EOF
chmod +x .git/hooks/pre-commit
哪怕 agent 没听 AGENTS.md,hook 也会拦。
Step 5:大 agent 任务前一晚手动 rebase
多步 Codex plan(4-5 个 PR 串起来),头天晚上把 branch rebase 好。第二天 agent 走进干净 tree,省下几小时 conflict 排查。
# 前一天
git fetch origin
git checkout feature/x
git rebase origin/main
git push --force-with-lease
# 确认 rebase 后 CI 是绿的
# 然后第二天早上 schedule Codex run
配合 branch protection,让 force-with-lease 是仅允许的 force 模式。
Step 6:rebase 优先于 merge
AGENTS.md 里:
和 main 集成时总是用 `git rebase origin/main`,不要 `git merge origin/main`。
你自己不要主动 rebase——只在 `.codex/setup.sh` 任务开头跑一次。任务中途
main 又前进了,不要再 merge;停下来上报。
Rebase 保持线性 history。长任务里 merge 会产生 conflict 套 conflict。
预防
- 调用 Codex 前 rebase;setup.sh 里 branch 落后太多直接 bail
- AGENTS.md “撞到 conflict 停下,不准 commit marker、不准挑边” 规则
- pre-commit hook 拦含
<<<<<<</=======/>>>>>>>的 commit - rebase 优先于 merge;任务开头 rebase 一次,中途绝不 re-merge
- 长 Codex plan 前一晚 rebase,agent 走进干净 tree
- branch protection 保证 agent 撞 conflict 时不能 force-push 覆盖队友
相关
- Codex patch 和现有代码冲突
- Codex 没完成 patch
- Codex 改了 git history
- Codex 环境初始化失败
- Codex 一遇大 diff 就停
- Codex PR 太大
标签: #Codex #agent #排查 #conflicts