GitLab 默认使用 Merge commit 策略(即 git merge --no-ff),这是一个设计选择。我们来看看背后的原因:
什么是 Merge Commit
sql
# 使用 Merge commit(--no-ff)
* a1b2c3d Merge branch 'feature' into main ← 这就是 merge commit
|\
| * d4e5f6a feature commit 2
| * b7c8d9e feature commit 1
|/
* 1a2b3c4 main 的上一个提交
# 不使用 Merge commit(fast-forward)
* d4e5f6a feature commit 2
* b7c8d9e feature commit 1
* 1a2b3c4 main 的上一个提交
为什么 GitLab 默认创建 Merge Commit
1. 保留分支历史
Merge commit 记录了"这些提交来自一个 feature 分支"这个事实:
sql
Merge branch 'feature/login' into 'main'
See merge request !1234
没有它,你无法从 Git 历史中看出哪些 commits 属于同一个功能。
2. 关联 MR 信息
Merge commit message 包含:
-
分支名称
-
MR 编号(
!1234) -
MR 标题
这使得从 Git 历史直接追溯到 GitLab MR 页面成为可能。
3. 方便回滚整个功能
sql
# 有 merge commit,一条命令回滚整个功能
git revert -m 1 a1b2c3d
# 没有 merge commit,需要逐个回滚
git revert d4e5f6a
git revert b7c8d9e
4. 清晰的审批记录
Merge commit 的 Author 是执行合并的人,代表"谁批准了这次合并"。
三种合并策略对比
| 策略 | Git 命令 | 历史形态 | 适用场景 |
|---|---|---|---|
| Merge commit | git merge --no-ff |
保留分支结构 | 团队协作,需要追溯 |
| Fast-forward | git merge --ff |
线性,无合并点 | 简单的个人分支 |
| Rebase | git rebase + --ff |
线性,commits 重写 | 追求干净历史 |
| Squash | git merge --squash |
线性,压缩为一个 | 一个功能一个提交 |
GitLab 的配置
GitLab 允许在项目设置中修改默认策略:
Settings → Merge requests → Merge method
| 选项 | 效果 |
|---|---|
| Merge commit | 始终创建 merge commit(默认) |
| Merge commit with semi-linear history | 先 rebase 再 merge commit |
| Fast-forward merge | 仅允许 fast-forward,不创建 merge commit |
总结
GitLab 默认创建 Merge commit 是为了:
-
可追溯性:知道哪些提交属于哪个功能
-
关联性:commit 直接链接到 MR
-
可回滚性:一条命令撤销整个功能
-
审批记录:记录谁批准了合并
如果你的团队偏好线性历史,可以在项目设置中改为 Squash 或 Fast-forward 策略。