跳转到内容

分支的合并

在 Git 中,将一个分支的更改整合到另一个分支,最常用的方法就是 git merge。根据分支历史的结构不同,Git 会自动选择不同的合并策略。

本章将深入讲解两种最基础且最常见的合并机制:Fast-forward (快进)3-way Merge (三方合并)

当你想把 feature 分支合并到 main 分支时,如果 main 分支在 feature 分支创建之后没有发生过任何更改(即 feature 的提交历史是 main 的直接延续),Git 就会执行 Fast-forward 合并。

在这种情况下,Git 不需要创建一个新的 “Merge Commit”。它只需要简单地将 main 分支的指针向前移动feature 分支的位置即可。

合并前: main 指向 C2,feature 基于 C2 继续前进了 C3, C4。

gitGraph
commit id: "C1"
commit id: "C2"
branch feature
checkout feature
commit id: "C3"
commit id: "C4"
checkout main

执行 Fast-forward 合并后: main 直接“快进”到了 C4。

gitGraph
commit id: "C1"
commit id: "C2"
branch feature
checkout feature
commit id: "C3"
commit id: "C4"
checkout main
merge feature
Terminal window
# 1. 切换到接收更改的分支 (例如 main)
git checkout main
# 2. 合并 feature 分支
git merge feature

CLI 输出示例:

Terminal window
Updating 3a1b2c..8d9e0f
Fast-forward
file1.txt | 2 ++
1 file changed, 2 insertions(+)

如果自 feature 分支创建以来,main 分支也产生了新的提交,那么两者的历史就发生了分叉 (Diverged)。此时,Git 无法简单地移动指针,因为 main 的最新提交并不在 feature 的历史路径上。

在这种情况下,Git 必须执行 3-way Merge (三方合并)

Git 会使用三个提交快照来进行合并计算:

  1. Current Commit: 当前分支的末端(例如 main 的最新提交)。
  2. Target Commit: 试图合并进来的分支末端(例如 feature 的最新提交)。
  3. Common Ancestor: 两个分支分叉处的共同祖先提交。

Git 会对比这三者,自动将差异整合,并创建一个新的 Merge Commit(合并提交)。这个提交比较特殊,它有两个父节点

合并前: 历史分叉了。main 前进了 C3,feature 前进了 C4。共同祖先是 C2。

gitGraph
commit id: "C1"
commit id: "C2"
branch feature
checkout feature
commit id: "C4"
checkout main
commit id: "C3"

执行 3-way Merge 后: 生成了新的合并提交 C5。

gitGraph
commit id: "C1"
commit id: "C2"
branch feature
checkout feature
commit id: "C4"
checkout main
commit id: "C3"
merge feature id: "C5"

命令与 Fast-forward 完全一样,Git 会自动检测并切换策略。

Terminal window
git checkout main
git merge feature

CLI 输出示例: 此时 Git 通常会弹出一个默认编辑器让你输入合并提交的信息(默认是 Merge branch 'feature')。

Terminal window
Merge made by the 'ort' strategy.
file_in_feature.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 file_in_feature.txt

有时候,即使满足 Fast-forward 的条件,我们也希望保留“这里曾经有过一个特性分支”的历史记录。这时可以使用 --no-ff 参数强制生成一个 Merge Commit。

Terminal window
git merge --no-ff feature

这在团队协作中很有用,因为它可以让历史记录更清晰地展示功能的开发周期。

特性Fast-forward (快进)3-way Merge (三方合并)
触发条件当前分支(接收方)是被合并分支的祖先(即历史没有分叉)分支历史分叉
是否生成新提交 (仅移动指针) (生成 Merge Commit)
历史形态线性,看不出分支痕迹网状,清晰展示合并点
父节点数量N/A (只是指针移动)两个父节点

下一章,我们将讨论当 Git 无法自动完成三方合并时会发生什么——即合并冲突的处理。