前言
看完本篇文章,你将能用自己的语言解释
什么是 git 中的 Fast-Forward?
正文
当前的工作状态是这样的:
- 我的
master
分支指向了提交B
。 - 我的
dev_jjq
分支是从master
的某个更早的提交(比如A
)创建出来的。
所以现在的提交历史图看起来是一条直线:
css
A---B (master, HEAD)
\
(dev_jjq 还指在 A)
现在,我在 dev_jjq
分支上辛勤工作,完成了一个新功能,并做了一次提交 C
。历史图就变成了:
scss
A---B (master)
\
C (dev_jjq)
关键的时刻来了 :我准备把在 dev_jjq
上开发的新功能合并回 master
主分支。
- 我首先切换回
master
分支:git checkout master
- 然后执行合并命令:
git merge dev_jjq
这时,Git 会进行判断。它发现 master
当前的指向 B
,直接就是 dev_jjq
的祖先。这意味着 dev_jjq
的提交历史完全包含了 master
自分支点以后的所有历史,没有任何分歧。
在这种情况下,Git 就会执行一次 fast-forward(快进) 合并。
快进合并的结果是: Git 不会创建任何新的提交,它只是简单地将 master
分支的指针直接向前移动 ,指向 dev_jjq
所指的同一个提交 C
。
合并后的历史图依然是一条干净直线,就像所有工作都是在 master
分支上顺序完成的一样:
css
A---B---C (master, dev_jjq)
对我来说,这有什么感觉?
- 优点:历史非常清晰和线性,没有多余的合并提交,看起来很整洁。
- 缺点:在历史中丢失了"曾经存在过一个功能分支"的信息。对于简单的修复或短期分支,这很好;但对于重要的功能分支,我有时会希望保留分支信息。
如果我不想用 fast-forward 模式呢? 我可以在合并时使用 --no-ff
(no fast-forward) 选项: git merge --no-ff dev_jjq
这样,即使满足快进条件,Git 也会强制创建一个新的合并提交,历史图会变成这样:
scss
A---B-----------M (master)
\ /
C--- (dev_jjq)
这样就能在历史中清晰地看到一次合并事件和一个功能分支的存活周期,对我管理项目历史更有帮助。
最后
【问】那么什么是 git 中的 Fast-Forward 呢?
【答】如果你想将本地的 dev_jjq 分支合并到 master 分支:
bash
# 切换到主分支
git checkout master
# 合并功能分支
git merge dev_jjq
这时,如果 dev_jjq 是 master 的直接后继,Git 就会采用 Fast-Forward 模式,将 master 指针直接向前移动到 dev_jjq 所指的提交,不会创建新的合并提交。