实际开发中,我们通常会在独立的功能分支上进行开发,待功能完成后需要将其整合回主分支。这时就会面临一个选择:该使用 git merge 还是 git rebase 来合并分支?这两者有何区别呢?本文将通过一个模拟的团队协作场景,带你直观地理解它们的不同。
场景准备
首先,我们在一个代码托管平台(例如 GitHub)上新建一个名为 rebaseStudy 的仓库,默认会创建 master 分支。将项目克隆到本地后,准备工作就完成了。

同学A:在主分支提交
同学A首先在本地 master 分支上工作。执行 git log,可以看到仓库初始化的提交记录。
$ git log
commit 7d1bdd8a5c37cd574ad00b32cc88ebb7c7f87f16a (HEAD -> master, origin/master, origin/HEAD)
Author: shuyuan1992 <42328986+shuyuan1992@users.noreply.github.com>
Date: Sun Nov 11 10:07:07 2018 +0800
Initial commit
接着,同学A新增了一个 a.txt 文件并提交。再次查看提交记录,现在有两条了。

此时,将本地新的提交推送到远程仓库,就能在远程看到两次提交历史。

我们将这两次提交简称为 C1(Initial commit)和 C2(A first commit a.txt)。
同学B:创建开发分支
与此同时,同学B需要开发新功能。他从当前最新的 master 分支(即 C2 提交点)检出一个新的 dev 分支,并将其推送到远程。
$ git checkout -b dev
Switched to a new branch 'dev'
$ git push origin dev
...
* [new branch] dev -> dev

查看远程仓库,可以看到多出了一个 dev 分支。

此时的分支状态可以用下图表示:

然后,同学B在 dev 分支上专心开发,并完成了三次提交。查看 git log 如下:

我们将这三次提交简称为 C3、C4、C5。此时的分支图变为:

关键冲突场景
现实开发中常出现这种情况:当同学B正准备进行第四次提交时,同学A在 master 分支上又完成了一次新的提交(假设为 C6),并推送到了远程。此时,master 分支已经领先于 dev 分支创建时的基点(C2)。
分支状态更新为:

现在,同学B开发完毕,需要将 dev 分支的功能合并到 master 分支。他有两种主流选择:git merge 或 git rebase。
方案一:使用 git merge
操作:在 master 分支上执行 git merge dev。
合并过程:
- Git 会自动找到
master 和 dev 两个分支的最近共同祖先,即 C2。
- 将
dev 分支的最新提交 C5 和 master 分支的最新提交 C6 的内容进行合并,如果存在冲突则需要手动解决。这次合并会生成一个新的合并提交,我们称之为 C7。
- 最终,
master 分支会将 C2 之后 dev 和 master 的所有提交点(C3, C4, C5, C6)按照提交时间顺序合并到一起。
合并后的分支图示如下,可以看到历史记录出现了分叉和汇合,形成非线性的结构:

方案二:使用 git rebase
操作:首先切换到需要变基的分支,即 dev 分支,然后执行 git rebase master。
合并过程:
- Git 会将
dev 分支(从共同的祖先 C2 之后开始)的每一次提交(C3, C4, C5)暂时“保存”下来。
- 将
dev 分支的基点从 C2 更新为 master 分支的最新提交 C6。
- 再将刚才保存的提交依次应用到新的基点(C6)之上,形成新的提交 C3'、C4'、C5'。在这个过程中如果发生冲突,需要即时解决(解决后执行
git add . 和 git rebase --continue)。
完成 rebase 后,dev 分支的历史就变成了基于最新的 master。此时,只需要再切换到 master 分支执行一次快进合并 (git merge dev) 即可。
最终效果如下图所示,整个历史记录呈现为一条直线,非常清晰:

你会发现,采用 rebase 后,原来 dev 分支上的几次提交(C3,C4,C5)的哈希值(hash)发生了变化(变为C3‘, C4’, C5‘),但提交内容被保留了下来。master 分支没有产生额外的合并提交。
核心区别总结
| 操作 |
特点 |
历史记录 |
适用场景 |
git merge |
保留完整的提交历史,包括分支的合并点。会生成一个新的合并提交。 |
非线性,能清晰体现分支的合并时间和路线。 |
希望保留完整历史,特别是公共分支(如主分支)的合并;团队策略强调追溯每一次合并。 |
git rebase |
将当前分支的提交“移植”到目标分支的最新提交之后。重写了提交历史。 |
线性,仿佛所有工作都是在目标分支上依次进行的。 |
希望得到干净、线性的提交历史;在本地功能分支整理提交记录,然后再合并到主分支。 |
重要提示:rebase 操作会改变提交的哈希值,这意味着它重写了历史。因此,一个基本原则是:只对你本地、尚未推送至远程仓库的提交进行 rebase 操作。切勿对已经推送到远程、可能与其他人共享的分支执行 rebase,否则会给协作者带来巨大的同步困扰。
选择 merge 还是 rebase,往往取决于团队的工作流规范和偏好。merge 更安全、更完整地记录了项目演进;rebase 则能创造出更简洁、易于追溯的线性历史。理解两者的差异,有助于你更好地进行版本控制和协作开发。
如果你对 Git 的更多高级操作或团队协作DevOps实践感兴趣,欢迎在云栈社区与更多开发者交流探讨。