git merge 的 --no-ff 参数有什么作用

--no-ff 禁止快进合并:即使可以直接快进,也创建合并提交;若目标历史已被包含,则不额外创建。作用是保留"这里曾经合并过一个功能分支"的历史痕迹,让分支拓扑清晰可见,回滚整组改动更容易。

最佳实践
Git 分支协作与合并示意

默认情况下,如果目标分支没有新提交,merge 会"快进"(fast-forward)——分支指针直接前移,不产生合并提交,历史上看不出这里曾有一条功能分支。 --no-ff 在需要合并新历史时生成合并提交,把"这次合并"作为可见节点;若已经 up-to-date 则不生成提交。

图解

默认快进(--ff):
main: A---B---C---D    (D 原属于 feature,看不出分支存在过)

--no-ff:
main: A---B-----------M  (M 是合并提交,"Merge branch 'feature-x'")
            \         /
feature-x:     C---D

为什么团队喜欢 --no-ff

  1. 特性边界清晰:git log --first-parent main 沿第一父提交查看历史,会同时包含主线普通提交;是否每个合并点对应一个特性/PR 取决于团队流程;
  2. 回滚整组改动容易:git revert -m 1 <合并提交> 相对第一父提交撤销该合并带来的树变化,但保留合并祖先关系;以后再合并同一历史不会自动恢复被撤销内容;
  3. 配合分支删除:分支删了,拓扑仍在;分支名本身不是提交身份,只有提交信息等可能留下名称。

配置默认行为

git config --global merge.ff false     # 本机所有合并默认 --no-ff
# 只对特定分支(如 main)
git config branch.main.mergeoptions "--no-ff"

常见问题(FAQ)

Q:--no-ff 和 squash merge 怎么选?

--no-ff 保留功能分支的每个提交+合并节点(历史详尽);git merge --squash 把合并结果放入索引和工作区,需要再执行 commit,且不记录第二父提交。要细节选前者,要简洁选后者。

Q:Git Flow 必须用 --no-ff 吗?

Git Flow 的分支模型依赖合并提交来标记特性边界,所以是它的惯例配置。GitHub Flow 下按团队喜好。

Q:--ff-only 又是什么?

相反方向:只允许快进,不能快进就报错。用于"我不想产生合并提交"的线性历史策略,常与 rebase 工作流搭配。

参考资料

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台