合并选项
一次普通的合并只需要按一个按钮,多数时候故事到此为止。这一页是写给其余那些时候的:每次合并都会打架的锁文件、被某人重新缩进过的文件、路径对不上的 vendored 项目。这三种情况 git 多年前就备好了开关;它们只是埋在一份没人会在冲突当下打开的手册页里。
右键点击一个分支 → 带选项合并…——侧边栏的分支行和远程行以及图中彩色的引用徽章都有,它们共用同一个菜单块——或者 ⌘K → 带选项合并。

命令会随着你的选择实时打印出来。它在那里是为了让你对照手册核验——也是为了下一次可以直接在终端里运行,不再需要这个对话框。
当某个变更块冲突时
| 选择 | 参数 | 含义 |
|---|---|---|
| 停下来问我 | — | 默认。由你来解决 |
| 保留本分支这一侧 | -X ours |
打架的变更块解析为当前已检出的内容 |
| 采用传入的一侧 | -X theirs |
打架的变更块解析为并入进来的那个分支 |
-X ours 不是 -s ours。 这里的开关只决定真正打架的那些变更块;另一个分支的其余改动照常合并。名为 ours 的那个策略——Gitcito 不提供——会整棵树照搬你这边,把另一侧全部丢掉,产生一个声称包含了它其实并不包含的工作的合并提交。这个区别是 git 合并中最常被误解的一件事。
它不能决定一切。 修改/删除冲突——一侧编辑了文件,另一侧删掉了它——不是内容层面的变更块,-X 会把它留给你。这是对的:「优先用我们的」没有哪个版本能回答一个被删除的文件是否应该回来。
空白字符
| 选择 | 参数 |
|---|---|
| 忽略已有空白字符的改动 | -X ignore-space-change |
| 完全忽略空白字符 | -X ignore-space-at-eol、-X ignore-all-space |
它存在的理由是这样一种情况:一个分支重新缩进了某个文件(或者某个格式化工具干的),另一个分支编辑了同样那些行。git 看到同一行上有两处编辑,于是停下。把空白字符忽略掉之后,重新缩进就不再是一处需要权衡的改动,真正的编辑就顺利合并进来了。
结果会在被触及的那些行上保留另一侧的空白字符,所以事后跑一遍格式化工具不是个坏主意。
记录什么
| 选择 | 参数 | 你会得到 |
|---|---|---|
| 可以快进时就快进 | — | 只有历史分叉了才产生合并提交 |
| 总是生成合并提交 | --no-ff |
即使能快进也生成合并提交,于是这个分支在图里永远可见 |
| 只允许快进,否则拒绝 | --ff-only |
如果需要真正的合并,就什么也不做。作为检查很有用 |
| 压缩 | --squash |
改动已暂存,不记录合并,提交信息由你来写 |
| 合并但不提交 | --no-commit |
合并已暂存并处于进行中,于是你可以先检查或修补它 |
压缩和 --no-commit 不是一回事。 压缩会忘掉曾经发生过合并这件事:git 不记录第二个父提交,下一次这个分支看起来仍然是未合并的。--no-commit 则是一次进行中的合并,它只是在等你——MERGE_HEAD 已经设好,提交一下就正常收尾。
--ff-only 不会悄悄失败。 如果需要一个合并提交,git 会拒绝,什么都不会动——这正是它作为脚本化合并前的一道理智检查的价值所在。
策略
| 策略 | 适用于 |
|---|---|
默认(ort) |
一切。git 现代的三方合并 |
subtree |
两侧位于不同路径——一个被 vendored 到本项目某个子目录里的项目 |
resolve |
老的三方合并。在交叉(criss-cross)历史上 ort 放弃时,它偶尔能成功 |
-s subtree 是值得记住的那一个。合并一个位于 vendor/parser/ 的项目的更新,否则会被读成「每个文件都被删除、每个文件都被新增」;subtree 策略会先把路径的位移算出来。完整工作流见子树。
为什么会冲突
在冲突解决器里有一个为什么会冲突按钮。它会对你眼前这个文件运行 git log --merge,并按两侧分别列出自分支分岔以来动过它的提交。

冲突标记说的是什么在打架。这里说的是谁改的、什么时候改的、为什么改——而这通常才是真正决定该如何解决的那个问题,也是你在选边之前应该先去问问某个人的理由。
如果它什么都没显示,说明两侧都没有提交过对这个确切文件的改动:冲突来自更上层的一次重命名或目录移动。
值得知道的限制
- 选项只作用于这一次合并。 它们不会被记住,也不会改变普通的合并到当前分支入口或拖放菜单。
- 撤销照常有效:带选项运行的合并会记录同样的撤销条目,它会重置到
ORIG_HEAD。 - 章鱼合并(一次并入两个以上的分支)这里不提供。
- 提交菜单里按引用列出的「把 X 合并进 Y」入口仍然是普通合并。想要选项时,请用引用徽章本身。
-X会悄无声息地做决定。 没有任何标记指出哪些变更块是被自动解决的,所以在一次重要的合并之后,请去读一遍差异,而不是相信「没有冲突」这件事。