在大屏或电脑上体验更佳——动画和操作区域更宽敞。
输入

快进合并

当前检出分支是待合入分支的祖先时,Git 可以快进合并:不用组合快照,也不创建合并提交,只将当前分支引用移到已有提交。

算法先证明祖先关系,再写引用。成功后改变的是目标分支,不是源分支或提交图。动画沿真实父链接验证,引用面板显示移动的名称,验证条从轨迹统计引用写入和提交对象数量。

图上的条件

假设 main 在 A,feature 在 C:

A ← B ← C
↑       ↑
main    feature

提交指向父,因此从 C 向后走 C、B、A。找到 main 的当前末端 A,就证明 main 可达的全部历史已属于 feature 的历史。条件为:

is_ancestor(current_tip, source_tip)

成立后只需:

refs/heads/main: A → C

feature 仍在 C,A、B、C 的 ID、父、树都不变,也没有第四个提交。git merge 是整合操作的名称,是否需要新提交由图和所选策略决定,合并不总等于创建合并提交。

快进合并逐步演示

默认用空提交建立本地仓库:

git commit --allow-empty -m "base"
git branch feature
git switch feature
git commit --allow-empty -m "feature-1"
git commit --allow-empty -m "feature-2"
git switch main
git merge --ff-only feature

固定空树让文件变化不干扰引用机制,ID 是可重复的 Git 格式对象 ID,而非显示标签。

  1. 首次提交写入根对象,再把尚未诞生的 main 指向它。
  2. 创建 feature,在同一根上新增引用,不复制对象,也不切换 HEAD。
  3. 切到 feature 后,两次空提交各自写入子对象,只推进 feature;main 留在根。
  4. 切回 main 只改变符号 HEAD,两分支末端都不移动。
  5. merge 解析 main 当前末端与 feature 源末端。
  6. 祖先游标从源末端出发,每个节拍沿一条父边,最终到达旧 main。
  7. 证明完成后,将 main 移到源末端,feature 保持不动。
  8. 检查对象数量未变:本次合并写一个已有引用,写零个提交对象。

不能先移动引用再检查祖先,否则可能丢掉当前分支的独立历史入口,必须先分类再写入。

边界情况

  • 当前落后于源: 当前末端在源的祖先链中,目标引用前进到源末端,写入一次。
  • 两引用相同: 已是最新,无需移动,引用写入零次。虽双向祖先关系都成立,引擎先处理等值,连遍历也不需要。
  • 源落后于当前: 本课模型从源找不到当前后,再从当前末端往回找(真实 Git 一次算出合并基点,两个结论都从它读出);若源在当前祖先中,当前已包含全部源历史,同样报告已是最新,写入零次。

--ff-only 何时拒绝

双方从共同基点各自提交:

    M ← main
   /
A
   \
    F ← feature

从 F 找不到 M,从 M 也找不到 F,两者都不是对方祖先,历史已分叉。git merge --ff-only feature 失败,main、feature、对象都不变。普通合并可协调快照后创建双父提交,属于下一课;ff-only 的用途就是让意外分叉显式失败。

源分支的角色

源分支只提供待整合提交,成功快进仅更新当前检出的目标分支。默认合并后 main、feature 恰好值相同,却仍是独立引用;以后在哪个分支提交,只推进哪个。两名称没有永久绑定。

本课 HEAD 始终是符号引用,它命名目标分支。源分支则来自 git merge --ff-only 的参数。

常见错误

  • “快进把源提交复制进当前分支。” 没有分支私有副本可复制,只是移动末端,让同一历史从两个名称可达。
  • “每次合并都创建提交。” 快进直接复用源末端,合并策略和图形决定是否需要新对象。
  • “源分支也移动。” 默认成功轨迹只有一次当前引用写入,源引用写入为零。
  • “有共同祖先就能快进。” 分叉分支也有共同祖先,必须有一个末端在另一个末端的祖先链中;真正向前移动还需当前是源祖先。
  • “已是最新表示两末端相同。” 当前领先于源、已包含它时也会如此报告。
  • “工作文件相同证明可以快进。” 快进资格来自提交图。真实 Git 还检查索引和工作区覆盖安全,但内容相同不能证明祖先关系。

可尝试的预设

准备合并停在命令前,让 main 落后于 feature,可手动选择 feature 合并。同末端展示零遍历零写入;源落后展示模型改从当前末端往回找;已分叉展示共同基点为何不够;缺失分支展示不修改图的错误路径。快进成功后再提交一次,还能验证两个同值引用依然独立。

可视化最多三分支、七提交、二十条命令,这是布局限制,不是 Git 限制。

模型范围

本课只有干净的本地仓库、附着 HEAD、单父提交,所有提交复用固定空树。省略工作区、索引、检出冲突、未跟踪文件、合并提交、内容协调、重命名检测、远程、上游配置、标签、reflog、钩子、签名、子模块、替换引用、并发引用更新和垃圾回收。

真实 Git 用锁文件保护引用更新,也会检查本地修改是否被覆盖,这些不在当前图模型中。这里的规则是:当前末端为源末端祖先时可快进,其图效果是目标引用指向已有提交。

基础概念可回看分支与 HEAD、提交快照课程。命令与祖先关系见 git merge、git merge-base --is-ancestor、gitglossary。