关于 resolve-conflicts
面向编码 Agent 的 Git 合并冲突处理技能,先制定方案并获批,再执行合并与验证;尽可能保留两个分支的更改意图。
主要功能
- 01编辑前制定冲突解决计划
- 02获批并询问不明确之处
- 03尽可能合并双方更改
- 04从源文件重新生成生成文件
- 05为删除-修改冲突创建备份
- 06验证冲突解决并运行测试
适用场景
- 01处理多种文件类型的冲突
- 02备份并分析删除-修改文件
- 03合并测试、导入项和配置
- 04提交前检查冲突是否解决
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ tailcallhq/ forgecode --skill resolve-conflicts安装后在 Claude Code 中输入/resolve-conflicts确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/patterns.mdsample-plan.mdscripts/handle-deleted-modified.shvalidate-conflicts.sh详细介绍
Git 冲突解决
通过智能合并两个分支的更改来解决 Git 合并冲突,同时保留双方更改的意图。本技能采用先规划的方法:评估冲突、制定详细的解决计划、获得批准,然后执行。
核心原则
- 先规划,再执行:始终制定结构化的解决计划,并在进行更改前获得用户批准
- 优先保留双方更改:默认保留双方的更改,除非它们直接矛盾
- 合并,而不是择一:尤其是导入项、测试和配置
- 重新生成生成文件:绝不手动合并生成文件;始终从源文件重新生成
- 解决前先备份:对于删除-修改冲突,先创建备份
- 通过测试进行验证:解决冲突后始终运行测试
- 说明所有解决方式:对于解决的每个冲突,用一行说明所采用的解决策略
- 有疑问时询问:如果无法从差异中明确正确的解决方式,请向用户列出选项并询问其选择
工作流
步骤 1:评估冲突情况
运行初始检查以了解冲突范围:
git status
识别并分类所有冲突文件:
- 常规文件冲突(双方均已修改)
- 删除-修改冲突(一方删除,一方修改)
- 生成文件冲突(锁文件、构建产物、生成代码)
- 测试文件冲突
- 导入项/配置冲突
- 二进制文件冲突
对于每个冲突文件,收集以下信息:
- 文件类型和用途
- 冲突性质(内容、删除、类型变更)
- 更改范围(更改的行数、受影响的部分)
- 文件是生成的还是手动编写的
步骤 2:制定合并冲突解决计划
根据评估结果,在解决任何冲突之前制定结构化计划。按以下 Markdown 格式展示计划:
## Merge Resolution Plan
### Conflict Summary
- **Total conflicted files**: [N]
- **Deleted-modified conflicts**: [N]
- **Generated files**: [N]
- **Regular conflicts**: [N]
### Resolution Strategy by File
#### 1. [File Path]
**Conflict Type**: [deleted-modified / generated / imports / tests / code logic / config / struct / binary]
**Strategy**: [Brief description of resolution approach]
**Rationale**: [Why this strategy is appropriate]
**Risk**: [Low/Medium/High] - [Brief risk description]
**Action Items**:
- [ ] [Specific action 1]
- [ ] [Specific action 2]
#### 2. [File Path]
...
### Execution Order
1. **Phase 1: Deleted-Modified Files** - Handle deletions and backups first
2. **Phase 2: Generated Files** - Regenerate from source
3. **Phase 3: Low-Risk Merges** - Imports, tests, documentation
4. **Phase 4: High-Risk Merges** - Code logic, configuration, structs
5. **Phase 5: Validation** - Compile, test, verify
### Questions/Decisions Needed
- [ ] **[File/Decision]**: [Question for user] (Options: 1, 2, 3)
### Validation Steps
- [ ] Run conflict validation script
- [ ] Compile project
- [ ] Run test suite
- [ ] Manual verification of high-risk changes
向用户展示此计划,并在继续解决前等待批准。如果有任何需要用户提供意见的未明确冲突,请将其列在“需要回答的问题/决定”部分。
完整计划示例请参见 references/sample-plan.md。
步骤 3:处理删除-修改文件
仅在计划获批后执行此阶段。
如果存在已删除但已修改的文件(状态:DU、UD、DD、UA、AU):
.forge/skills/resolve-conflicts/scripts/handle-deleted-modified.sh
此脚本将:
- 为已修改的内容创建带时间戳的备份
- 分析可能的迁移目标
- 为每个文件生成分析报告
- 自动解决删除状态
查看备份目录和分析文件,了解应在何处应用更改。
步骤 4:执行解决计划
按照计划中定义的执行顺序操作。 对每个冲突文件,根据计划应用相应的解决模式。对于解决的每个冲突,用一行说明如何解决。
完成计划中的每项操作后,将其标记为已完成,并向用户报告进度。
解决方式不明确时
如果仅凭差异无法确定正确的解决方式(这类情况应已列在计划的“需要回答的问题/决定”部分):
- 向用户展示冲突,并附上双方冲突的代码
- 列出带编号的选项(选项 1、选项 2 等)
- 清楚说明每个选项及其作用
- 请用户选择一个选项编号或提供更多信息
- 记住用户的选择,并将类似的推理应用于后续相关冲突
交互示例:
I found a conflict in src/main.rs where both branches modify the `calculate_price` function:
<<<<<<< HEAD (Current Branch)
fn calculate_price(item: &Item) -> f64 {
item.base_price * (1.0 + item.tax_rate)
}
=======
fn calculate_price(item: &Item) -> f64 {
item.base_price + item.tax_amount
}
>>>>>>> feature-branch (Incoming Branch)
I'm not sure which calculation is correct. Please select an option:
**Option 1**: Keep current branch (multiplies base_price by tax_rate)
**Option 2**: Keep incoming branch (adds tax_amount to base_price)
**Option 3**: Keep both approaches with a new parameter
**Option 4**: Provide more context to help me decide
Please respond with "Option 1", "Option 2", "Option 3", or "Option 4", or provide additional information.
用户回复后,应用其决定,并将类似逻辑用于相关冲突。
解决模式
对于每个冲突文件,应用相应的解决模式:
导入/依赖项
目标:合并两个分支中的所有唯一导入项。
一句话说明:“合并导入项:整合两个分支中的唯一导入项、移除重复项,并按模块分组。”
阅读 references/patterns.md 中的“导入冲突”部分,查看详细示例。
快速处理方法:
- 提取两侧的所有导入项
- 移除重复项
- 按模块/包分组
- 遵循特定语言的风格(按字母顺序排列、区分标准库/外部库/内部模块)
测试
目标:纳入两个分支中的所有测试用例和测试数据。
一句话说明:“合并测试:纳入两个分支中的所有测试用例、合并测试固件,并在必要时重命名以避免冲突。”
阅读 references/patterns.md 中的“测试冲突”部分,查看详细示例。
快速处理方法:
- 保留所有测试函数,除非它们测试的内容完全相同
- 合并测试固件和设置函数
- 整合两侧的断言
- 如果测试名称冲突,但测试的是不同的行为,则重命名以明确区分
生成文件
目标:重新生成所有生成文件,以纳入两个分支中的更改。
一句话说明:“解决生成文件冲突:从源文件重新生成文件,以纳入两个分支中的更改。”
识别方法:满足以下条件的文件属于生成文件:
- 由构建工具、编译器或代码生成器生成
- 有对应的源文件或配置来定义它
- 包含表明其为自动生成文件的头部信息/注释
- 在
.gitattributes中被列为生成文件 - 常见示例:锁定文件、protobuf 输出文件、GraphQL 架构文件、编译后的资源、自动生成的文档
处理方法:
-
确定生成源:确认生成该文件的命令或工具
-
暂时选择任一版本(选择哪个都无关紧要):
git checkout --ours <generated-file> # or --theirs -
从源文件重新生成:运行相应的生成命令:
# Package manager lock files cargo update # for Cargo.lock npm install # for package-lock.json yarn install # for yarn.lock bundle install # for Gemfile.lock poetry lock --no-update # for poetry.lock # Code generation protoc ... # for protobuf files graphql-codegen # for GraphQL generated code make generate # for Makefile-based generation npm run generate # for npm script-based generation # Build artifacts npm run build # for compiled/bundled assets cargo build # for Rust build artifacts -
暂存重新生成的文件:
git add <generated-file>
不确定文件是否为生成文件时:检查文件头部是否有自动生成标记,或者询问用户应重新生成该文件还是手动合并。
配置文件
目标:合并两个分支中的配置值。
一句话说明:“合并配置:纳入两个分支中的所有键,并为冲突选择合适的值。”
阅读 references/patterns.md 中的“配置文件冲突”部分,查看详细示例。
快速处理方法:
- 纳入两侧的所有键
- 对于冲突的值,根据以下因素选择:
- 更新/更近期的值
- 更安全/更保守的值
- 生产环境要求
- 在提交消息中说明选择依据
不明确时:询问用户应优先采用哪个配置值(当前值还是传入值)
代码逻辑
目标:理解两项更改的意图,并尽可能将它们结合起来。
一句话说明:“解决代码逻辑冲突:分析更改意图;如果更改涉及不同方面,则合并;如果更改相互冲突,则选择一种方案。”
阅读 references/patterns.md 中的“代码逻辑冲突”部分,查看详细示例。
快速处理方法:
- 分析每个分支要实现的目标
- 如果更改涉及不同方面,则合并两者
- 如果更改相互冲突(关注点相同,但方案不同):
- 查看提交消息/PR,了解背景
- 选择符合需求的方案
- 如果不明确,则测试两种方案
- 说明决定的依据
不明确时:向用户介绍两种方案,并说明各自的作用
Struct/类型定义
目标:包含两个分支中的所有字段。
一句话说明:“合并 struct,包含两个分支中的所有字段,并为任何冲突的字段定义选择合适的类型。”
快速处理方法:
- 合并所有字段
- 如果字段类型冲突,分析哪种类型更合适
- 修复更新 struct 后出现的所有编译错误
- 更新测试以使用新字段
不确定时:如果字段类型冲突,询问用户哪种类型定义才是正确的
第 5 步:验证解决结果
完成计划中的所有解决阶段后,验证所有冲突均已解决:
.forge/skills/resolve-conflicts/scripts/validate-conflicts.sh
此脚本会检查:
- 剩余的冲突标记(<<<<<<<、=======、>>>>>>>)
git status中尚未合并的路径- 已删除-已修改冲突
- 合并状态文件
第 6 步:编译和测试
按照计划中的验证步骤进行构建和测试,确保解决结果正确:
# For Rust projects
cargo test
# For other projects, use appropriate test command
# npm test
# pytest
# etc.
如果测试失败:
- 检查失败情况——问题来自合并后的代码还是冲突解决?
- 检查两个分支的测试是否各自单独通过
- 修复合并更改之间的集成问题
- 重新运行测试,直到全部通过
第 7 步:完成
解决所有冲突且测试通过后,检查已完成的计划并提交:
# Review the changes
git diff --cached
# Commit with descriptive message that references the plan
git commit -m "Resolve merge conflicts: [describe key decisions]
Executed merge resolution plan:
- [Phase 1 summary]
- [Phase 2 summary]
- [Phase 3+ summaries]
Key decisions:
- Merged imports from both branches
- Combined test cases
- Regenerated lock files
- [other significant decisions from plan]
Co-Authored-By: ForgeCode <[email protected]>"
决策跟踪
当你让用户在多个选项中做出选择时,记录其决定,并在后续冲突中采用类似的推理方式:
场景示例:
- 第一个冲突:用户选择选项 1(优先采用当前分支的验证逻辑)
- 第二个类似的冲突:采用相同的推理方式(优先采用当前分支的验证方法)
- 提及:“保留当前分支的方法来解决(与您之前的选择一致)”
关键原则:
- 在同一冲突解决会话中记住用户的偏好
- 对类似冲突采用一致的处理模式
- 说明处理的一致性:“沿用之前相同的处理模式……”
- 如果新冲突与之前的冲突有明显差异,则再次询问
常见模式参考
如需详细的解决模式,请阅读:
references/patterns.md- 所有冲突类型的综合示例
快速查找模式:
- 导入项:合并所有不重复的导入项,并按模块分组
- 测试:保留所有测试(重复项除外),合并测试夹具
- 生成文件:选择任一版本,并从源文件重新生成
- 配置:合并所有键,发生冲突时选择更新或更安全的值
- 代码:分析意图;如果改动互不冲突则合并,否则选择其一
- Struct:包含两个分支中的所有字段
- 文档:合并所有文档章节
特殊场景
冲突中的二进制文件
二进制文件无法合并。选择其中一个版本:
git checkout --ours path/to/binary # keep our version
# or
git checkout --theirs path/to/binary # keep their version
大规模重命名/重构冲突
如果一个分支重命名或重构了许多文件,而另一个分支修改了这些文件:
- 接受重命名/重构(结构性更改)
- 将修改应用到新结构中
- 使用
handle-deleted-modified.sh中的备份来指导应用修改
子模块冲突
# Check submodule status
git submodule status
# Update to the correct commit
cd path/to/submodule
git checkout <desired-commit>
cd ../..
git add path/to/submodule
故障排除
“双方都新增”冲突(AA)
两个分支新增了同名但内容不同的文件:
- 检查两个版本
- 如果用途相同,则合并内容
- 如果用途不同,则重命名其中一个
仅空白字符冲突
如果冲突仅涉及空白字符差异:
git merge -Xignore-space-change <branch>
持续存在的冲突标记
如果验证显示仍有冲突标记,但你认为已经解决:
- 搜索准确的标记字符串:
git grep -n "<<<<<<< HEAD" - 某些标记可能位于字符串或注释中——也要解决这些标记
- 检查是否存在隐藏字符或编码问题
解决后测试失败
- 单独测试每个分支,确认测试通过
- 失败很可能是合并后的更改相互作用所致
- 调试相互作用问题,而不是单独的更改
- 更新代码,使两项更改能够协同工作
快速参考卡
| 冲突类型 | 策略 | 一句话说明模板 |
|---|---|---|
| 导入项 | 全部合并、去重,并按模块分组 | “合并两条分支中的唯一导入项,并按模块分组” |
| 测试 | 全部保留,合并测试固件 | “纳入两条分支中的所有测试用例,并合并测试固件” |
| 生成的文件 | 根据源文件重新生成 | “根据源文件重新生成 [file],以纳入两条分支中的更改” |
| 配置 | 合并键,选择较新的值 | “合并所有配置键,并为 [key] 选择 [current/incoming] 值” |
| 代码逻辑 | 分析意图,若关注点互不冲突则合并 | “合并两项更改,因为它们处理的是不同的关注点”或“出于 [reason],选择 [current/incoming] 方案” |
| 结构体 | 纳入所有字段 | “在结构体定义中纳入两条分支中的所有字段” |
| 文档 | 合并所有章节 | “合并两条分支中的文档内容” |
| 已删除-已修改 | 备份、分析,并应用到新位置 | “文件移动或重命名后,将修改应用到新位置” |
| 二进制文件 | 选择一个版本 | “保留 [current/incoming] 版本的二进制文件” |
请记住:
- 始终为每项冲突解决方案提供一句话说明
- 不确定时,向用户提供带编号的选项
- 跟踪用户的决定,并将其一致地应用于类似冲突
- 目标是在创建协调一致的合并结果时,保留两条分支的意图和功能