这篇讲合并拉取请求时,创建合并提交、压缩合并和变基合并有什么差别。看完你可以在 设置 → 拉取请求 里只打开团队约定的那一种,合并时看清 main 上会多出什么样的提交,并按方式删掉已经合入的本地分支。
下文用示例仓库 xlliu/test-pr-example。克隆地址是 https://git.anguskit.com/xlliu/test-pr-example.git。这个仓库为了验收三种合入,把 允许合并提交、允许压缩合并、允许变基合并 都打开了,自动删除分支 是关的。新仓库的默认是前两个打开、变基合并关闭、自动删除分支关闭。已经合进去的记录里,#2 在 main 上留下了合并提交 Merge pull request #2 from feature/close-reopen。讲历史长什么样时,仍用一条有三个提交的源分支来画:提交 1、2、3 要合进已经有 A、B 的 main。
1. 三种方式合进去之后,main 长什么样
| 方式 | 合并后 main 上多了什么 |
作者与适用场景 |
|---|---|---|
| 创建合并提交 | 分支上的三个提交原样进入 main,外加一个合并提交(可快进时直接快进) |
原提交保留原作者,合并提交由系统创建;适合保留完整分支脉络 |
| 压缩合并 | 只多一个新提交,内容等于三个提交加起来的总改动 | 作者是拉取请求作者,提交者是点合并的人;适合把零碎提交压成一条 |
| 变基合并 | 三个提交被逐个接到 main 最新提交后面,生成新的提交哈希 |
每个提交保留原作者和原说明;适合每个提交都规整、追求线性历史 |
还有一种情况要知道:选 创建合并提交 时,如果从拉出分支到合并这段时间里,main 上没有任何新提交,AngusGit 会直接把 main 移到分支的最后一个提交,不再生成合并提交。结果和变基合并一样是一条直线。
2. 在仓库设置里决定允许哪几种
打开设置
进入仓库,切到 设置,在左侧选 拉取请求。这一操作需要仓库的管理权限。
选择允许的方式
三个开关分别是 允许合并提交(「在合并 pull request 时添加所有提交」)、允许压缩合并(「将所有提交合并为一个提交」)和 允许变基合并(「在基础分支上重新应用所有提交」)。新仓库默认打开前两个,关闭变基合并。团队约定只用一种时,只打开那一个,其他人合并时就不会选错。
决定合并后是否删除分支
同一页的 自动删除分支(「Pull request 合并后自动删除分支」)默认关闭。打开后,拉取请求合并成功时,AngusGit 会删除这条源分支。
保存
点 保存更改,提示 拉取请求设置已保存。

至少保留一种方式是打开的。三个都关掉时,设置照样能保存,但之后所有拉取请求都没法合并。
3. 合并时选择方式
拉取请求满足合并条件后,在 对话 页点 合并拉取请求。确认框的说明是「选择合并方式并确认合并操作」。
选方式
三个选项都会列出来:创建合并提交(「所有提交都会被添加到基础分支」)、压缩合并(「将所有提交压缩为一个提交」)、变基合并(「将提交变基到基础分支」)。仓库设置里没打开的方式是灰的,点不了。打开确认框时,默认选中按这个顺序排在最前、并且已允许的那一种。
检查提交信息
提交信息 会根据方式自动填好,可以修改:
- 创建合并提交:第一行是
Merge pull request #<编号> from <源分支>。xlliu/test-pr-example的 #2 合进去之后,main上的提交说明就是Merge pull request #2 from feature/close-reopen。 - 压缩合并:第一行是拉取请求的标题,下面是拉取请求的描述。这就是
main上那一个新提交的说明,值得认真改一下,写清这次改了什么。 - 变基合并:输入框是灰的,提示「变基合并不会生成合并提交信息」,因为每个提交都沿用原来的说明。
- 创建合并提交:第一行是
确认
点 确认合并。提示 拉取请求已合并 后,页面回到拉取请求列表,这一条的状态是 已合并。
确认框要等 合并拉取请求 可以点了才出现。现在打开的 xlliu/test-cicd-example #1 两条流水线都已成功,按钮仍然是灰的,卡上写的是「仍有评审未完成,需等待评审通过后才能合并」。按钮可以点开之后,确认框标题下的说明是「选择合并方式并确认合并操作」,三个选项是 创建合并提交、压缩合并、变基合并;仓库设置里没打开的那一项是灰的。

4. 合并之后,本地怎么收尾
先把本地的 main 更新到最新:
git switch main
git pull
然后删掉已经合并的本地分支。三种方式在这一步的表现不一样:
| 合入方式 | 删除命令 | 原因 |
|---|---|---|
| 创建合并提交 | git branch -d feature/close-reopen |
分支上的提交已经原样在 main 里,可直接安全删除。#2 就是这种合入 |
| 压缩合并 | git branch -D feature/close-reopen |
main 上是一个新提交,确认已合入后用 -D 强制删除 |
| 变基合并 | git branch -D feature/close-reopen |
main 上是新提交哈希,确认已合入后用 -D 强制删除 |
远端的源分支默认保留。没有打开 自动删除分支 时,到仓库的 分支 页签,在那一行点 删除分支,确认后提示 分支删除成功。
变基合并还会改写服务器上的源分支:合并完成后,源分支指向那三个新提交。如果合并之后还要在这条分支上继续开发,本地先执行 git fetch 和 git reset --hard origin/feature/close-reopen 和服务器对齐,再继续提交。reset --hard 会丢掉本地没推送的改动,执行前先确认。更简单的做法是从最新的 main 拉一条新分支。
5. 合并失败时
| 你看到的 | 原因 | 怎么处理 |
|---|---|---|
| 想用的方式在确认框里是灰的 | 仓库 设置 → 拉取请求 里没有打开这种方式 | 请仓库管理员打开对应开关,或者改用已允许的方式 |
| 仓库不允许使用变基合并(Rebase Merge)方式合并 | 在你打开确认框之后,管理员刚刚关掉了这种方式 | 刷新页面,重新选一种允许的方式 |
| 检测到合并冲突,请先解决冲突后再合并 | 分支和 main 改了同一处代码。变基合并逐个接提交时更容易遇到:总改动不冲突,中间某一个提交单独接上去也可能冲突 |
在本地把 main 合进分支、解决冲突后推送,再合并;或者改用压缩合并 |
选了创建合并提交,main 上却没有合并提交 |
拉出分支之后 main 没有新提交,AngusGit 直接快进了 |
这是正常结果,代码已经合入 |
合并后 git branch -d 删不掉本地分支 |
用的是压缩合并或变基合并,main 上的提交号和本地分支不同 |
确认已合入后用 git branch -D |
常见问题
合并之后能撤销吗?
页面上没有撤销合并的按钮。需要撤回时,在本地用 git revert 生成一个反向提交,推到新分支,再发起一条拉取请求合进 main。用 创建合并提交 合入的,可以执行 git revert -m 1 <合并提交号> 一次撤回整个分支;用 压缩合并 合入的,撤回那一个提交即可。
团队应该统一用一种方式吗?
建议统一。混用时,main 上一部分请求是一个提交,另一部分是一串提交,回头查历史和撤回时都要先分辨是哪种。在 设置 → 拉取请求 里只打开约定的那一种,最省事。
压缩合并之后,原来那几个提交还看得到吗?
看得到。打开这条已合并的拉取请求,提交 页签里仍然列着合并前的三个提交。只是 main 的历史里只有那一个压缩后的提交。
为什么默认不打开变基合并?
变基合并会改写服务器上的源分支,还要求分支上的每个提交单独接到 main 上都不冲突。团队确定要一条直线的历史、并且每个提交都写得规整时,再打开它。
小结
三种合并方式合进去的代码相同,区别只在 main 的历史:创建合并提交 留下全部提交加一个合并提交,压缩合并 压成一个新提交,变基合并 把每个提交接成一条直线。仓库管理员在 设置 → 拉取请求 里决定允许哪几种,团队最好约定一种。合并时检查 提交信息,压缩合并尤其要写清楚;合并之后更新本地 main,压缩或变基合入的本地分支用 git branch -D 删除。
结论: 在仓库 设置 → 拉取请求 只开启团队约定的合并方式(想一条请求对应一个提交选 压缩合并,想保留完整分支记录选 创建合并提交,想线性保留原提交选 变基合并),压缩或变基合入后本地分支用
git branch -D清理。