合并冲突是 agent 在并行分支上工作时最常见的摩擦点之一。大多数冲突不是随机的——它们可以追溯到可预测的代码模式,可以通过结构、lint 规则和 PR 纪律来预防。
#为什么 Agent 会加剧冲突
人类开发者会本能地避免编辑相同的行。Agent 没有这种直觉。当两个 agent 会话在同一文件上工作时,它们倾向于:
- 向同一个不断增长的函数调用或配置对象追加内容
- 在同一个声明块中添加新变量
- 以不同方式修改同一个模板
结果是技术上简单但频繁到足以拖慢工作流的冲突。
#冲突易发的代码模式
#不断增长的函数调用参数
当函数调用积累了大量内联参数时,每个添加新参数的 PR 都会触及相同的行。
// 冲突易发:每个新变量都扩展这个块
const fullHtml = render(baseTemplate, {
title, lang, body, base, description, canonicalUrl,
pairCanonicalUrl, pairLang, ogLocale, noindex, jsonLd,
ogType, rssUrl, markdownUrl, siteName, siteTagline,
});
修复:提取一个辅助函数来组装对象,这样每个 PR 修改的是辅助函数而不是调用点。
const fullHtml = render(baseTemplate, {
title, lang, body, base,
...seoVars({ lang, title, description, canonicalUrl, ... }),
});
#按位置传参
参数过多的按位置传参函数比对象参数更糟糕,因为插入新参数会移动所有后续位置。
Lint 阈值:当函数超过 4-5 个参数时,重构为单个选项对象。
#共享常量块
当多个常量在单个块中声明时,任何添加新常量的 PR 都会触及相邻行。
修复:将常量分组到配置对象中。新属性在对象内部添加,减少行级冲突。
#仅追加文件
每次更改都是追加的文件(日志文件、变更记录、不断增长的数组)在两个分支同时追加时会冲突。
修复:使用条目独立的结构化格式(每个条目一个文件,或用清晰分隔符分隔的段落)。
#预防冲突的 Lint 规则
一些冲突易发模式可以通过静态分析捕获:
- 最大函数参数数:ESLint
max-params规则。设置阈值(如 4)并强制超过阈值时使用对象解构。 - 函数调用最大行长:长单行函数调用比多行更难合并。
- Import 排序:自动排序的 import 不会冲突,因为两个分支产生相同的顺序。
这些规则不提"冲突"——它们是标准的代码质量规则。但它们的副作用是直接减少合并冲突频率。
#PR 边界策略
最有效的冲突预防不在代码中——而在于如何拆分工作。
#文件重叠检查
在开始并行工作之前,列出每个 PR 将触及的文件。如果两个 PR 修改同一文件,声明依赖关系并定义合并顺序。
#纵向切片
按功能边界拆分工作,而不是按层。一个触及"所有模板"的 PR 会与任何其他模板 PR 冲突。一个"端到端添加 sitemap 生成"的 PR 触及更少的共享文件。
#最小化 diff
PR 改变的行越少,冲突的可能性越低。抵制在实现功能时顺便清理相邻代码的冲动。
#Agent 特定建议
#在任务中声明文件所有权
当向 agent 分配并行任务时,明确说明每个任务应该修改哪些文件。这防止两个 agent 独立决定"改进"同一文件。
#推送前 rebase,而不是冲突后
Agent 应该在推送前 rebase 到最新 main,而不是在报告冲突后才做。这在 diff 仍在上下文中时就能及早发现冲突。
#使用预工作检查清单
在创建分支之前,验证更改是可以用一句话描述的单一关注点。这是最简单也最有效的冲突预防措施。