Symphony 仓库 Codex Pull 技能实战:基于合并(而非变基)的分支同步与冲突解决规范
【免费下载链接】symphonySymphony turns project work into isolated, autonomous implementation runs, allowing teams to manage work instead of supervising coding agents.项目地址: https://gitcode.com/gh_mirrors/symphony7/symphony
Symphony 参考实现的 Elixir 项目中,.codex/skills/目录沉淀了一套供 Codex 代理使用的“仓库本地技能”(repository-local skills),其中pull技能(又名 update-branch)规定了如何把origin/main以**合并(merge-based,而非 rebase)**方式并入当前特性分支,并系统化了冲突解决的判断流程与“何时必须停下来问用户”的边界。读完本篇,你可以完整掌握该技能的九步同步工作流、zdiff3 冲突上下文解读方法、生成文件与 import 冲突的分治策略,以及技能如何与push、commit等周边技能和 elixir/AGENTS.md 的验证门禁协同工作。
Pull 技能是什么:定位与适用场景
技能文件位于 .codex/skills/pull/SKILL.md,采用 YAML frontmatter 声明元信息,随后是自然语言形式的执行规范:
name: pull description: Pull latest origin/main into the current local branch and resolve merge conflicts (aka update-branch). Use when Codex needs to sync a feature branch with origin, perform a merge-based update (not rebase), and guide conflict resolution best practices.从description可以确认三点定位:
- 目标是把
origin/main合入当前本地特性分支,而不是让分支追随 main 做变基改写; - 触发时机是 Codex 需要同步特性分支与 origin 时(例如 PR 被 CI 要求更新,或 push 被拒后的修复动作);
- 附带职责是引导冲突解决的最佳实践,而不仅仅是执行
git merge。
该技能与同目录下的其他技能共同构成一个完整的开发闭环。elixir/README.md 将../.codex/描述为“repository-local Codex skills and setup helpers”,与 .codex/worktree_init.sh(负责在新 worktree 中执行mise trust与make setup的环境初始化脚本)共同支撑 Symphony 为每个 issue 创建隔离工作区的运行模式。
九步 update-branch 工作流
技能正文将同步流程拆成 9 个明确步骤,每一步都有具体的命令约束。以下按原文顺序完整梳理:
步骤 1–2:前置检查与 rerere 启用
- 确认工作区干净:合并前必须让
git status处于干净状态,否则先提交或暂存(stash)当前改动; - 启用 rerere(reuse recorded reverses,复用已记录的冲突解法):
git config rerere.enabled true git config rerere.autoupdate truererere 对长期维护的特性分支价值明显:同一处冲突在多次合并origin/main时可能出现,rerere 会记录此前的解法并在下次冲突时自动套用(autoupdate让解法自动进入暂存区),显著降低重复劳动。
步骤 3–4:确认远端与分支、抓取最新引用
- 确认
origin远端存在; - 确认当前分支就是要接收合并的分支(这一步直接对应后文“何时询问用户”中的一条规则:分支不是预期目标时不得继续);
- 执行
git fetch origin获取最新引用。
步骤 5:先同步远端的同名特性分支
这是整个工作流中最容易被忽略、也最能体现“merge-based”严谨性的一步:
git pull --ff-only origin $(git branch --show-current)技能文档明确解释了为什么要在合并origin/main之前先做这件事:远端的特性分支可能已有新提交(例如 GitHub 上产生的 auto-commit),先把它们以 fast-forward 方式拉到本地,可以避免后续合并时引入不必要的中间状态。--ff-only保证这一步只允许快进,一旦出现分叉会立即报错而不是悄悄产生合并提交。
步骤 6:以 zdiff3 风格合并 origin/main
git -c merge.conflictstyle=zdiff3 merge origin/main技能推荐使用zdiff3冲突风格,理由是其冲突标记包含三方信息(详见下文冲突解决部分),能提供更清晰的冲突上下文。
步骤 7:解决冲突并完成合并
若出现冲突,按冲突解决指南处理后:
git add <files> git commit # 或 git merge --continue(若合并处于暂停状态)步骤 8:按项目验证门禁跑检查
技能要求“Verify with project checks (follow repo policy inAGENTS.md)”。对应到本仓库,elixir/AGENTS.md 定义的主质量门禁是:
make all从 elixir/Makefile 可以看到all等价于ci目标,依次执行setup、build、fmt-check(格式检查)、lint、coverage(带覆盖率测试)、dialyzer(静态类型分析)。也就是说,一次合格的 pull 同步不只是“合并成功”,还必须通过这五道关卡。
步骤 9:总结本次合并
合并完成后需要输出摘要,明确:
- 最棘手的冲突/文件是什么、如何解决的;
- 是否存在假设或后续跟进项。
这一条是面向人类审查者的交付物,保证合并历史“清晰、可审查”(clear, reviewable)。
冲突解决指南:从“看差异”到“定语义”
技能文档用一整节篇幅给出冲突解决最佳实践(Conflict Resolution Guidance),可归纳为“观察 → 判意 → 最小修改 → 收尾验证”四个阶段。
观察阶段:三层差异信息
技能要求在动手编辑前先检查上下文,给出了具体的取证命令:
git status:列出所有冲突文件;git diff或git diff --merge:查看冲突块(hunks);- 利用 Git 的暂存区 stage 编号做文件级的意图对比:
git diff :1:path/to/file :2:path/to/file # base 与 ours 的差异 git diff :1:path/to/file :3:path/to/file # base 与 theirs 的差异:1:、:2:、:3:分别对应合并基线(base)、当前分支(ours)和对方分支(theirs)。两组 diff 合起来能还原出“双方各自从共同祖先改了什么”,是判断改动意图的关键依据。
开启merge.conflictstyle=zdiff3后,冲突标记为五段式:
<<<<<<< ours(当前分支改动) ||||||| base(共同祖先) ======= >>>>>>> theirs(对方分支改动)技能还特别提示:zdiff3 会裁掉冲突区域首尾的相同行,因此应聚焦中间真正不同的核心部分,不要被标记区域的整体篇幅干扰。
判意阶段:先定行为,再写代码
这是该技能最有方法论价值的部分。它要求在编辑前先回答三个问题:
- 双方各自想达成什么——是 bug 修复、重构、重命名,还是行为变更;
- 是否存在共同目标,以及哪一方是否覆盖了另一方(supersede);
- 先确定最终行为(decide the final behavior first),再按这个决定去构造代码。
并给出一条硬约束:除非冲突明确指向有意变更,否则优先保持不变量、API 契约与用户可见行为的稳定。文档还要求对复杂冲突主动搜索相关文件与定义,使解法与代码库其余部分保持一致。
最小修改阶段:意图保持的编辑纪律
- 编辑保持与分支目的(branch’s purpose)一致的行为,避免误删或无声的行为变更;
- 一次只解决一个文件,每完成一个逻辑批次就重新跑测试;
ours/theirs整体接受仅在“确定某一方应当完全获胜”时才允许使用。
特殊场景的分治策略
技能对两类高频难点场景给出了明确的处理次序:
生成文件(generated files):先解决非生成代码(手写源码与逻辑)的冲突,再运行产生该生成文件的 CLI/工具命令重新生成,最后暂存重新生成的产物——而不是手工去编辑生成物本身。这一策略对本仓库同样适用,例如 Elixir 侧的格式与类型检查产物应以mix format、mix dialyzer的输出为准。
import 冲突且意图不明时:先两边都保留,完成整个合并后再跑 lint/类型检查,由工具安全地清掉未使用或错误的 import。这避免了在合并过程中逐条判断 import 归属时引入误删。
收尾验证
全部冲突解决后,用下面一条命令确认没有残留冲突标记:
git diff --check最后一条原则是:拿不准时,记录假设并先征求确认,再最终确定合并。
何时必须询问用户:把不确定性压缩到最小
技能文档最后单独列出“当且仅当没有安全的、可回退的替代方案时才向用户求助”的原则,并要求优先做最佳努力决策、记录理由、继续推进(best-effort decision + documented rationale)。仅在以下五种情况停下来询问:
- 正确解法依赖产品意图或行为,且无法从代码、测试或邻近文档推断;
- 冲突跨越用户可见契约、API 表面或数据库迁移,选错会破坏外部使用者;
- 冲突需要在两个技术价值相当、互斥的设计之间二选一,且本地没有任何明确信号;
- 合并会引入数据丢失、schema 变更或不可逆副作用,且没有明显的安全默认值;
- 分支不是预期目标,或远端/分支名不存在且无法在本地确定。
其余情况一律继续合并,在备注中简要解释决策,并留下清晰、可审查的提交历史。这一节实际上定义了“自动代理做合并”与“人类监督”之间的责任边界:代理负责技术判断与留痕,人只介入意图层面无法从仓库证据推断的决策。
与周边技能的协同:pull 在 Symphony 工作流中的位置
pull 技能并非孤立存在,它与同目录技能形成了清晰的引用关系:
- push 技能的
Related Skills一节明确写着:当 push 被拒、出现 non-fast-forward、分支过期或存在合并冲突风险时,应运行pull技能来合并origin/main、解决冲突并重新验证。它甚至把错误归因做了切分——同步问题走 pull 技能;认证/权限/工作流限制则停止操作并原样上报错误,而不是改写 remote 或切换协议来绕过。pull 完成后再执行git push -u origin HEAD(仅当本地重写过历史时才允许--force-with-lease)。 - commit 技能负责在解决冲突后的提交环节生成规范的提交信息(Conventional Commits 类型前缀、72 字符换行、Summary/Rationale/Tests 三段式正文),保证 pull 工作流第 9 步“reviewable commit history”的要求落地。
- 工作区环境的准备则由 worktree_init.sh 承担:Symphony 按 elixir/WORKFLOW.md 的工作流为每个 issue 创建隔离工作区,脚本在其中检查
mise可用、执行mise trust和make setup,为后续在干净环境中执行 pull/merge 验证提供前提。
小结
.codex/skills/pull/SKILL.md的价值不在于“如何执行一次git merge”,而在于把一次可复现、可审查、可交接的分支同步封装成了明确契约:
- 前置纪律(干净工作区 + rerere + 先同步远端同名分支的
--ff-only拉取)保证合并起点正确; zdiff3+ 三方 stage diff(:1:/:2:/:3:)提供足够判断意图的差异信息;- “先定最终行为、再写代码”与“最小意图保持编辑”约束修改幅度;
- 生成文件“先源码后重生成”、import 冲突“先双保留后靠 lint 清理”等分治策略覆盖高频难点;
git diff --check收尾 + elixir/AGENTS.md 定义的make all门禁(格式、lint、覆盖率测试、dialyzer)保证合并后的质量回归被工具验证;- 五条“必须询问用户”清单把人类介入压缩到意图层面的真实不确定性上。
对维护 Symphony 类似“代理自主执行、人类管理工作”模式的仓库而言,这套 pull 技能(连同 push、commit 技能)本身就是一份可以直接移植的 Git 同步与冲突解决规范模板。
【免费下载链接】symphonySymphony turns project work into isolated, autonomous implementation runs, allowing teams to manage work instead of supervising coding agents.项目地址: https://gitcode.com/gh_mirrors/symphony7/symphony
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考