Git不支持git merge -s直接调用自定义脚本,因-s仅识别内置策略(如recursive、ours);自定义逻辑须通过配置merge.driver并结合.gitattributes绑定文件类型实现。

Git 本身不支持直接用 git merge -s 指定任意脚本作为合并策略;所谓“自定义合并策略”必须通过 git config 配置 merge.<name>.driver</name>,再配合 .gitattributes 绑定文件类型,才能生效。 直接在命令行用 -s custom 会报错:fatal: Invalid strategy 'custom' —— 因为 Git 只认内置策略名(如 recursive、ours),不认你随便起的名字。
为什么 git merge -s 不能直接调用你的 Python 脚本
Git 的 -s(或 --strategy)参数只接受内建策略标识符,比如 recursive、resolve、ours。它不负责加载外部程序,也不解析路径或命令行参数。你写的 custom_merge.py 属于“合并驱动(merge driver)”,和“合并策略(merge strategy)”是两个不同层级的概念:
-
strategy决定“怎么找共同祖先、要不要递归、冲突时是否尝试自动选一边” -
driver决定“当某个具体文件发生冲突时,用什么命令去生成合并后的内容”
所以,想让 Git 在遇到 config.json 冲突时自动跑你的 Python 脚本,不能靠 git merge -s myscript,而要走 driver 路线。
如何正确配置并启用自定义合并驱动
分三步:写脚本 → 注册 driver → 绑定文件类型。每步都容易漏掉关键细节:
- 脚本必须能从
stdin读取 Git 提供的冲突内容(含<<<<<< HEAD等标记),输出无冲突的纯文本到stdout;不能交互、不能依赖当前工作目录(Git 调用时 pwd 是仓库根) - 注册 driver 时,
git config必须加--local(推荐)或--global,且命令中%A、%O、%B这三个占位符顺序不能错:git config --local merge.jsondriver.driver 'python3 /path/to/custom_merge.py %O %A %B' - 绑定文件类型必须用
.gitattributes(不能只靠git config),内容形如:config.json merge=jsondriver;该文件需提交进仓库,否则其他协作者无法复现行为
示例(假设脚本已存为 ~/bin/json-merge.py):
git config --local merge.jsondriver.name "JSON-aware merge" git config --local merge.jsondriver.driver 'python3 ~/bin/json-merge.py %O %A %B' echo "config.json merge=jsondriver" >> .gitattributes git add .gitattributes
git merge -X 和自定义 driver 的关系与误用点
-Xours 或 -Xtheirs 是给 recursive 策略用的“冲突解决提示”,只影响 Git 内置的文本行级合并逻辑,对自定义 driver 完全无效 —— driver 脚本自己决定怎么处理冲突,Git 不会再干预。
- 如果你同时用了
git merge -Xours和config.json merge=jsondriver,Git 会忽略-Xours,只执行你的脚本 - 反过来,如果忘了在
.gitattributes中声明merge=xxx,哪怕 driver 已注册,Git 也不会调用它,仍走默认文本合并 -
-X参数也不能用于ours/theirs策略本身(即git merge -s ours不接受-X),这点常被混淆
真正需要“自定义合并”的典型场景
不是所有冲突都值得写 driver。多数情况手动解决更快。只有满足以下全部条件时,才值得投入:
- 文件格式结构清晰(如 JSON/YAML/INI)、语义明确(键名唯一、无顺序依赖)
- 冲突高频发生且模式固定(例如多个 PR 同时改不同 key 的
package.json) - 团队已约定该类文件禁止手动编辑冲突块(避免误删他人字段)
- 脚本能做到“无损合并”:不丢 key、不破坏缩进、不引入语法错误
一旦跨出这个范围(比如合并 Python 类定义),自定义 driver 很可能比人工还不可靠 —— 因为 Git 传给它的只是带冲突标记的纯文本,没有 AST 解析能力。这时候与其硬写脚本,不如用 git checkout --ours 或 --theirs 快速保留一方,再人工补漏。


















