用AI解决Git合并冲突,要同时提供共同祖先、两边代码和各自的修改目的,再检查合并结果是否保住两项规则。只删除冲突标记,或直接“接受当前修改”,可能得到语法正确却丢失业务意图的代码。
例如,一条分支把默认重试次数从1改为3,另一条分支让调用者传入的0真正表示“不重试”。正确结果应同时满足“缺省为3”和“显式0生效”。下面在一个独立练习仓库里制造这次冲突,完成比较、修正和本地验证。

先确认现在进行的是哪一种合并操作
先看git status,确认仓库、当前分支和操作状态。本文只演示从main执行普通git merge default-three的情形:当前一侧是main,传入一侧是default-three。不要把这个对应关系机械套到rebase。
确认上下文后,可以让墨刀AI客户端比较本地冲突材料。将共同祖先、两边内容和规则说明放在授权项目目录里,先让它解释冲突与提出合并建议;具体文件修改、测试和Git后续操作仍需按当前仓库状态进行。
VS Code的冲突说明特别区分不同操作下的Current与Incoming。团队使用的编辑器即使提供“接受某一侧”按钮,也不能仅凭标签判断哪一边应留下,更不能把另一款工具的按钮当成墨刀的操作入口。
在新练习仓库中制造一个真实冲突
准备Git和Node.js,在新的空目录中操作,不要把下面的初始化命令放进现有项目。该练习只在本地创建提交,没有远程仓库。实际运行环境为Git 2.53.0.windows.1与Node.js v24.19.0。
新建一个尚不存在的merge-retry-practice目录,进入后初始化仓库。下面的作者信息只供这个练习仓库使用:
mkdir merge-retry-practice
cd merge-retry-practice
git init -b main
git config user.name "Article Example"
git config user.email "example@example.invalid"
将下面内容保存为retry.mjs,使用UTF-8和LF换行:
export function retryLimit(options = {}) {
return options.retries || 1;
}
提交共同起点,然后创建调整默认值的分支:
git add retry.mjs
git commit -m "base retry rule"
git switch -c default-three
在该分支把返回语句改为return options.retries || 3;,保存并提交,再回到main:
git add retry.mjs
git commit -m "default retries to three"
git switch main
main仍是共同起点。在main把返回语句改为return options.retries ?? 1;,保存后执行:
git add retry.mjs
git commit -m "preserve explicit zero"
git merge default-three
git status
这时Git会报告retry.mjs内容冲突,文件中出现类似下面的标记。合并停在冲突状态是本练习的预期结果:
export function retryLimit(options = {}) {
<<<<<<< HEAD
return options.retries ?? 1;
=======
return options.retries || 3;
>>>>>>> default-three
}
把共同祖先补齐,AI才能看见两边改了什么
冲突文件直接呈现的是两侧内容。还没有执行git add retry.mjs时,可以用下面命令读取索引中的共同祖先和两侧版本:
git show :1:retry.mjs
git show :2:retry.mjs
git show :3:retry.mjs
在这次普通merge中,1是共同祖先,2是当前main,3是传入的default-three。Git的合并手册说明了冲突时这些索引阶段的作用。解决并暂存文件后,阶段内容会变化,因此应在暂存前保留需要比较的材料。
| 版本 | 返回语句 | 相对共同祖先的目的 |
|---|---|---|
| 共同祖先 | options.retries || 1 | 默认1,但显式0也会被替换为1 |
| 当前main | options.retries ?? 1 | 用空值判断保留显式0 |
| 传入default-three | options.retries || 3 | 将默认值提高到3 |
这里的两个目的能够同时成立。如果一边要求默认3、另一边明确要求默认5,就不是简单拼合运算符的问题,应先确认哪个业务约定有效。
交给AI的任务可以明确到文件和样本:
当前操作是从main执行普通 git merge default-three,不是rebase。
共同祖先:return options.retries || 1;
main目的:允许显式传入0,当前代码为 return options.retries ?? 1;
default-three目的:默认重试次数改为3,代码为 return options.retries || 3;
请先说明两侧分别改变什么,再给出同时保留两项规则的retry.mjs。
函数签名仍为 retryLimit(options = {})。
检查未传参数、传入retries:0、传入retries:5三种情况。
只提出该文件的合并建议,不自动提交、推送或处理其他冲突文件。
如果两项要求不能同时成立,指出冲突,不替我选择业务优先级。

把共同祖先、两侧意图与合并建议放在一起,便于逐项检查保留了哪些规则。
接受任意一侧,都会丢掉一项规则
正确的合并文件应保留空值合并运算符??,并使用新默认值3。将retry.mjs整体改成下面的内容,删除冲突标记:
export function retryLimit(options = {}) {
return options.retries ?? 3;
}
| 处理方式 | 未传参数 | 显式传0 | 显式传5 |
|---|---|---|---|
| 只保留main:?? 1 | 1,丢失新默认值 | 0 | 5 |
| 只保留default-three:|| 3 | 3 | 3,丢失不重试语义 | 5 |
| 合并两项规则:?? 3 | 3 | 0 | 5 |
“接受双方”也不一定解决问题。如果只是顺序留下两条return,第二条可能永远不会执行。能否保留双方意图,要看最终行为,不看文件里是否还能找到两边的文字。
先跑两侧规则,再完成本地合并
在仓库根目录新建verify.mjs,把约定写成三个独立断言:
import assert from 'node:assert/strict';
import { retryLimit } from './retry.mjs';
assert.equal(retryLimit(), 3);
assert.equal(retryLimit({ retries: 0 }), 0);
assert.equal(retryLimit({ retries: 5 }), 5);
console.log('通过:未传参数=3;显式0=0;显式5=5');
先执行检查,不要急着暂存:
node verify.mjs
git diff --check
git diff
本地练习中,正确的?? 3通过了三个断言;把文件分别替换成“只保留main”和“只保留default-three”的独立副本后,两份副本均失败,分别暴露默认值1和显式0变3的问题。
git diff --check用于发现冲突标记、空白等问题,不能判断默认次数是否正确。真实项目还需运行相关回归测试;缺少测试时,先从双方已经确认的规则补充能识别错误的断言。
确认只有预期改动后,在这个练习仓库中完成合并:
git add retry.mjs verify.mjs
git diff --cached
git commit --no-edit
git status
练习最终得到本地合并提交,工作区干净,没有推送远程。团队仓库还应按原有评审流程检查合并差异;代码评审可以继续关注此次合并是否遗漏调用方和关联规则。
想取消时,按当前操作状态处理
如果还处于这次merge冲突中,决定放弃本次合并,可先保存想保留的手工解决内容,再执行git merge --abort。本练习也实际演算了取消:回到main的?? 1版本,工作区恢复干净;随后重新制造冲突并完成上述合并。
不要把这个结果理解为任何仓库都能无损恢复。Git官方手册提醒,合并前已有未提交改动时,取消可能无法完整重建原状态。因此,团队项目开始合并前应先处理好现有修改;若当前正在rebase,或已经完成合并提交,应根据对应状态采取措施,不能照搬本节命令。
锁文件、自动生成文件、文件删除与修改相撞,以及二进制文件,也不适合让AI直接按文本拼接。先确认源文件、生成方式或保留规则,再选择处理路径。AI最有帮助的位置,是把双方意图和需要验证的条件讲明白,让最终合并有据可查。