Github中pull request的三种合并方式
熟悉Github的同学都知道,Github的项目发起分支的合并请求时,会有三种合并方式可供选择:
- Merge pull request(
Create a merge commit,创建合并提交)。 - Squash and merge(压缩合并)。
- Rebase and merge(变基合并)。
那你知道这三种合并方式的区别?本文将详细讲解这部分的知识。
1. 案例说明
为了更详细的描述他们之间的区别,这里举个实际的项目案例进行说明。假设有个测试项目Project,有main和feature两个分支,两个分支的操作如下:
Commit操作
main分支: A — B — C
feature分支(从B分叉): D — E — F
合并之前的Commit历史
main分支
A -> B -> C
feature分支
A -> B -> D -> E -> F
2. Merge pull request
2.1. 工作方式
git checkout main
git merge feature-branch
- 创建一个新的"合并提交"(merge commit)
- 保留分支的所有原始提交记录
- 在历史中清晰显示分支的合并点
2.2. 适用场景
- 团队协作开发
- 需要保留完整历史记录
- 开源项目通常使用这种方式
2.3. 示例结果
2.3.1. log graph
git log --graph
* commit c21e30adc80f7871e054ef5cabbacf2c6dbefc94 (HEAD -> main, origin/main)
|\ Merge: 26ed2ce 5589288
| | Author: Spencer.Luo <spencer.luo@foxmail.com>
| | Date: Wed Jan 7 09:57:39 2026 +0800
| |
| | Merge pull request #1 from spencer-luo/feature
| |
| | Add D E F
| |
| * commit 5589288c90accff11053b7b5a15d1417fc02dec3 (origin/feature, feature)
| | Author: Spencer <spencer.luo@foxmail.com>
| | Date: Wed Jan 7 09:44:58 2026 +0800
| |
| | F
| |
| * commit 8898199e1a81947e7afa70381a26c3cee149cc51
| | Author: Spencer <spencer.luo@foxmail.com>
| | Date: Wed Jan 7 09:44:25 2026 +0800
| |
| | E
| |
| * commit 2b5a7d5c9fee60d02643e222c132629cfd16b6c1
| | Author: Spencer <spencer.luo@foxmail.com>
| | Date: Wed Jan 7 09:44:10 2026 +0800
| |
| | D
| |
* | commit 26ed2ce92acca37a71d0482c05611d546a2f307a
|/ Author: Spencer <spencer.luo@foxmail.com>
| Date: Wed Jan 7 09:45:39 2026 +0800
|
| C
|
* commit 44acdc392398020909d91ce6e088dd08ba3d19d1
| Author: Spencer <spencer.luo@foxmail.com>
| Date: Wed Jan 7 09:43:10 2026 +0800
|
| B
|
* commit e8e92d1233f00f28f880722b004cb9f39d6f0d0f
Author: Spencer <spencer.luo@foxmail.com>
Date:
2.3.2. Github页面的Commits记录
Github(main分支)页面点击Commits按钮看到的提交记录,是按照commit的提交时间进行排序的。
A -> B -> D -> E -> F -> C -> "Merge pull request"
3. Squash and merge
3.1. 工作方式
- 将分支上的多个提交压缩成一个提交
- 将这个单一提交合并到主分支
- 删除分支的原始提交历史
3.2. 优点
- 保持主线历史简洁干净
- 每个功能对应一个清晰的提交
- 便于代码审查和回滚
3.3. 缺点
- 丢失详细的开发过程记录
- 无法查看功能的逐步实现
3.4. 示例结果
3.4.1. log graph
git log --graph
* commit 6aafda5fac27e2e76fca0d206396ab588097e45c (HEAD -> main, origin/main)
| Author: Spencer.Luo <spencer.luo@foxmail.com>
| Date: Wed Jan 7 10:42:33 2026 +0800
|
| Add D E F (#1)
|
| * D
|
| * E
|
| * F
|
* commit d9e84ca4abe8e352161dcabaadc01e97cb478d5f
| Author: Spencer <spencer.luo@foxmail.com>
| Date: Wed Jan 7 10:37:20 2026 +0800
|
| C
|
* commit f6912d95b74e80c7e1c338f05ade56cb4dce5c6e
| Author: Spencer <spencer.luo@foxmail.com>
| Date: Wed Jan 7 10:35:22 2026 +0800
|
| B
|
* commit 3d579e78044687012e15f6e061f363ec6a846eb8
Author: Spencer <spencer.luo@foxmail.com>
Date: Wed Jan 7 10:35:05 2026 +0800
A
3.4.2. Github页面的Commits记录
Github(main分支)页面点击Commits按钮看到的提交记录,feature分支的三次commit被合并成了一次。
A -> B -> C -> "Add D E F"
4. Rebase and merge
4.1. 工作方式
git checkout feature-branch
git rebase main
git checkout main
git merge feature-branch
- 将分支的提交"重新播放"在主分支的最新提交之后
- 创建线性的历史(没有合并提交)
4.2. 优点
- 历史记录是线性的、干净的
- 易于跟踪提交顺序
4.3. 缺点
- 重写了提交历史(新的提交哈希)
- 可能对协作有影响(如果分支已被共享)
4.4. 示例结果
4.4.1. log graph
git log --graph
* commit 371c7bb78ca9a40c73b266c6cc52afc8441febd6 (HEAD -> main, origin/main)
| Author: Spencer <spencer.luo@foxmail.com>
| Date: Wed Jan 7 11:00:47 2026 +0800
|
| F
|
* commit b49fd102bf6dfa07cda6346da8d788848221ee4a
| Author: Spencer <spencer.luo@foxmail.com>
| Date: Wed Jan 7 10:59:51 2026 +0800
|
| E
|
* commit a5bcc12a3ff3c046b328f86c52af59ea6efe9a1e
| Author: Spencer <spencer.luo@foxmail.com>
| Date: Wed Jan 7 10:59:39 2026 +0800
|
| D
|
* commit 59866f85e44b79da38a618cc01b1a96d090be1b6
| Author: Spencer <spencer.luo@foxmail.com>
| Date: Wed Jan 7 11:00:16 2026 +0800
|
| C
|
* commit 11b7caec95f88461ac3fc20104a374de9595bec6
| Author: Spencer <spencer.luo@foxmail.com>
| Date: Wed Jan 7 10:58:00 2026 +0800
|
| B
|
* commit f40d659c1a25c78c6a45e9f82e69cce0395f5e44
Author: Spencer <spencer.luo@foxmail.com>
Date: Wed Jan 7 10:57:49 2026 +0800
A
4.4.2. Github页面的Commits记录
Github(main分支)页面点击Commits按钮看到的提交记录,是按照commit的提交时间进行排序的。
A -> B -> C -> D -> E -> F
5. 对比总结
5.1. 特点说明
| 特性 | Create a merge commit | Squash and merge | Rebase and merge |
|---|---|---|---|
| 历史记录 | 保留完整分支历史 | 压缩为单个提交 | 线性历史 |
| 提交哈希 | 保留原哈希 | 新哈希 | 新哈希(rebase后) |
| 合并提交 | 有 | 有 | 无 |
| 历史清晰度 | 显示分支结构 | 非常简洁 | 完全线性 |
| 适合场景 | 团队协作、开源项目 | 功能开发、保持整洁 | 个人开发、维护线性历史 |
5.2. 对比示意图
原始结构:
D — E — F (feature)
/
A — B — C (main)
合并后:
1. Create merge commit:
A — B — C — G
|\
D E F (保留原结构)
2. Squash and merge:
A — B — C — G(压缩的D+E+F)
3. Rebase and merge:
A — B — C — D' — E' — F' (线性)
5.3. 实际Git命令对应关系
# 1. Create merge commit (保留历史)
git checkout main
git merge --no-ff feature # 创建合并提交
# 2. Squash and merge (压缩)
git checkout main
git merge --squash feature # 压缩成一个提交
git commit -m "Feature X"
# 3. Rebase and merge (变基)
git checkout feature
git rebase main # 变基到main
git checkout main
git merge feature # 快速前进合并