分支的合并
在 Git 中,将一个分支的更改整合到另一个分支,最常用的方法就是 git merge。根据分支历史的结构不同,Git 会自动选择不同的合并策略。
本章将深入讲解两种最基础且最常见的合并机制:Fast-forward (快进) 和 3-way Merge (三方合并)。
1. 快进合并 (Fast-forward)
Section titled “1. 快进合并 (Fast-forward)”什么是 Fast-forward?
Section titled “什么是 Fast-forward?”当你想把 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# 1. 切换到接收更改的分支 (例如 main)git checkout main
# 2. 合并 feature 分支git merge featureCLI 输出示例:
Updating 3a1b2c..8d9e0fFast-forward file1.txt | 2 ++ 1 file changed, 2 insertions(+)2. 三方合并 (3-way Merge)
Section titled “2. 三方合并 (3-way Merge)”什么是 3-way Merge?
Section titled “什么是 3-way Merge?”如果自 feature 分支创建以来,main 分支也产生了新的提交,那么两者的历史就发生了分叉 (Diverged)。此时,Git 无法简单地移动指针,因为 main 的最新提交并不在 feature 的历史路径上。
在这种情况下,Git 必须执行 3-way Merge (三方合并)。
为什么要叫 “3-way”?
Section titled “为什么要叫 “3-way”?”Git 会使用三个提交快照来进行合并计算:
- Current Commit: 当前分支的末端(例如
main的最新提交)。 - Target Commit: 试图合并进来的分支末端(例如
feature的最新提交)。 - 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 会自动检测并切换策略。
git checkout maingit merge featureCLI 输出示例:
此时 Git 通常会弹出一个默认编辑器让你输入合并提交的信息(默认是 Merge branch 'feature')。
Merge made by the 'ort' strategy. file_in_feature.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 file_in_feature.txt3. 强制创建合并提交
Section titled “3. 强制创建合并提交”有时候,即使满足 Fast-forward 的条件,我们也希望保留“这里曾经有过一个特性分支”的历史记录。这时可以使用 --no-ff 参数强制生成一个 Merge Commit。
git merge --no-ff feature这在团队协作中很有用,因为它可以让历史记录更清晰地展示功能的开发周期。
| 特性 | Fast-forward (快进) | 3-way Merge (三方合并) |
|---|---|---|
| 触发条件 | 当前分支(接收方)是被合并分支的祖先(即历史没有分叉) | 分支历史分叉 |
| 是否生成新提交 | 否 (仅移动指针) | 是 (生成 Merge Commit) |
| 历史形态 | 线性,看不出分支痕迹 | 网状,清晰展示合并点 |
| 父节点数量 | N/A (只是指针移动) | 两个父节点 |
下一章,我们将讨论当 Git 无法自动完成三方合并时会发生什么——即合并冲突的处理。