Codex 遇到 merge conflict 就卡住或瞎选边:rebase 策略和 AGENTS.md 兜底

Codex 撞上 conflict marker 要么停下、要么挑错边、要么把 marker 直接写进文件。pre-rebase setup.sh + 显式 AGENTS.md 规则解决问题。

你让 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 每个冲突点都全选 ourstheirs,根本没读。它挑的标准是 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 #agent #排查 #conflicts