最省事的是vs code:需配置git config --global merge.tool vscode和git config --global mergetool.vscode.cmd 'code --wait --merge "$local" "$remote" "$base" "$merged"',保存即写入$merged,退出即完成。

git mergetool 选哪个工具最省事
多数人卡在第一步:装了 meld/vscode/kdiff3,但 git mergetool 启动后报错或显示空白。根本原因不是工具没装好,而是 Git 没法把三方内容($LOCAL、$BASE、$REMOTE)正确传进去。
推荐顺序(按开箱即用程度降序):
-
vscode:需先运行code --install-extension ms-vsliveshare.vsliveshare(非必须),再执行git config --global merge.tool vscode和git config --global mergetool.vscode.cmd 'code --wait --merge "$LOCAL" "$REMOTE" "$BASE" "$MERGED"'。VS Code 会自动识别三路合并上下文,保存即写入$MERGED,退出即触发git add -
vimdiff:无需额外安装(macOS/Linux 自带 vi),配置简单:git config --global merge.tool vimdiff。但默认不显示$BASE,得加git config --global merge.conflictstyle diff3才能在冲突块里看到共同祖先行 -
meld:GUI 最直观,但 Linux 下常因 GTK 版本不兼容闪退;macOS 需用brew install --cask meld安装,且要确认mergetool.meld.path指向的是/opt/homebrew/bin/meld而非/usr/local/bin/meld
别碰 gvimdiff 或 tortoisemerge——前者依赖 GUI X11 环境(WSL/远程 SSH 基本不可用),后者只在 Windows + TortoiseGit 全套生态下才稳定。
为什么 git mergetool 要传 $BASE $LOCAL $REMOTE
这不是 Git 故意搞复杂,而是三方合并算法的硬性要求。Git 不是简单比对“当前文件”和“对方文件”,它必须知道:$BASE 是两个分支分叉前的共同版本,$LOCAL 是你当前分支的修改结果,$REMOTE 是你要合并进来的那个分支的修改结果。只有同时看到这三份内容,工具才能判断某段代码是“仅你改了”“仅对方改了”还是“双方都改了但改得不同”。
常见误解:
- 以为
$LOCAL就是 HEAD 分支的原始文件 → 错。$LOCAL是 Git 临时生成的副本,已包含你当前分支上所有未提交的脏修改(比如你刚git add过但还没commit的改动) - 以为关掉
diff3模式能简化界面 → 实际会让工具失去判断依据。例如两人都删了同一行,diff3下$BASE显示该行存在,$LOCAL/$REMOTE都为空,工具立刻知道该删;而merge模式下只显示两边都空,无法区分是“都删了”还是“都没动” - 手动改
$MERGED文件后不退出工具就关窗口 → Git 不会自动add,下次git status仍显示 Unmerged paths,且临时文件可能被清理,导致丢失你刚写的逻辑
自定义 mergetool 命令时最容易漏的 exit code 处理
当你用 git config mergetool.mytool.cmd 'my-merge-tool "$LOCAL" "$REMOTE" "$BASE" "$MERGED"' 定义自己的工具时,Git 默认假设:只要命令返回 0,就代表用户已解决冲突;非 0 则代表放弃。但很多 GUI 工具(如早期版 meld)成功保存后也返回 1,导致 git mergetool 误判为失败,反复弹窗。
必须同步设置:
-
git config mergetool.mytool.trustExitCode true:告诉 Git 相信工具自己的退出码 - 或者干脆绕过 exit code 判断:
git config mergetool.mytool.trustExitCode false,这时 Git 会在工具退出后问你 “Was the merge successful?”,手动敲y才继续
没设 trustExitCode 时,即使工具内部已写好 $MERGED,Git 仍会认为冲突未解决——这是线上排查时最隐蔽的坑。
rerere 为什么能让重复冲突自动消失
git config --global rerere.enabled true 开启后,Git 并不是记住了你最终选的代码,而是记录了冲突块的“指纹”(SHA-1 of the preimage)和你解决后的“输出块”。下次遇到完全相同的冲突内容(哪怕在不同文件、不同分支),Git 就直接把上次的解决方案填进 $MERGED,跳过人工干预。
关键限制:
- 只对 content conflict 生效,对 rename/delete/modify 类冲突无效
- 冲突块必须字节级一致——多一个空格、换一行,就匹配不上
- 记录存在本地
.git/rr-cache/下,不随git push同步,团队成员各自开启才各自受益
真正省时间的场景不是“每天合并一次”,而是“每周 rebase 一次长期 feature 分支”:第一次 rebase 解决 5 个冲突,之后每次 rebase,rerere 自动搞定其中 3 个,你只盯剩下的 2 个新冲突就行。











