git merge 和 git rebase 的区别

1,201 阅读4分钟

git——Rebase 和 Merge

rebasingmerge 都是为了将一个分支的修改合并到另一个分支上,但是他们的实现方式不同。
比如说,假如我们有像下面这样的一些提交内容,merge 操作的结果像是合并了一个分支上的所有提交。而 rebase 操作将从 master 分支的最后一次提交开始添加 feature 分支中的所有更改。

  • 当你 rebase master 分支到 feature 分支,其实是将整个 feature 分支的起点移到了 master 分支的终点
  • Merging 获取到 feature 分支的内容并将它合并到 master 分支,最后只有 master 分支被改变了,feature 分支保持历史修改不变。
  • Merging 会添加一个新的 commit 到历史记录里

一个 commit 的流程看起来像是这样

从这里开始:

我们将在前一个版本的 master 分支切出来的 second_branch 分支上进行工作,second_branch 分支比 master 分支多一次提交记录,但是在我从 master 分支切出来重新创建分支之后,有人在 master 分支上进行了一次提交。 于是分支分叉了!

问题:在 second_branch 分支上需要 commit3 修改的内容(或者我的老大想让我的工作目录始终与 master 分支保持一致)

这里有两种可能的实现方法:

  • 使用 merge(或者偷懒的话可以使用 pull
  • 使用 rebase

提醒:我们在 second_branch 分支上进行工作之前我们执行了 git checkout second_branch 命令

git merge master 的结果

当分支分叉的时候,我们不能 fast-forward一篇关于fast-ward的好文档)合并的过程,因此 Git 创建了我们称之为合并提交的方法,以将 master 分支的所有修改应用于 second_branch。

这使 git 折线图产生了一个不好看的边缘线。

但是,它让所有提交都与合并之前保持一致,因为它们不会更改分支的历史记录。

注意:如果我们从 Git 提交树上删除了(使用 rebase -i 或者 reset)合并的提交记录(在我们的例子中是编号:63c6403),那么来自这个被合并分支的所有提交也将从分支中撤离。
这使的代码回滚变得非常容易,当您合并了一个分支的大量提交但它们不能满足需求且必须删除它们时:只需删除 merge commit 即可。

git rebase master 的结果

second_branch 分支的前一个 HEAD 指针(指向当前选定分支的最后一个提交的指针)指向的是 “Commit 2”,并且通过运行 git rebase,我希望它的 HEAD 指针与 master 分支相同,因此,分支首先是一模一样的,然后合并来自 second_branch 上面的提交。 这创造了一个非常好看且线性的树。
但是,树会发生变化,因为用于 Detached commit 这次提交( second_branch 分支)的基本哈希值由最开始是 3b36f32,在 rebasing 之后会改变为 a018520,这意味着如果有人正在使用 second_branch,他将很难检索到整个新的 second_branch,因为它的树已经完全改变了。 我承认这有点复杂,但实际上它正在将这个分支的旧的 “起点提交” 更改为 “新的” 起点。 如果您需要更好的表示方法,可以在 google 图片上查看 git rebase 的一些图形。

更直观的图形表示

rebase VS merge

什么时候使用 rebase,什么时候使用 merge

如果要同步修改的 feature 分支是和别人共同开发的分支,则不建议使用 rebase 操作,因为 rebase 会使仓库变得前后不一致。对于个人单独开发而言,rebase 操作会更有意义。

如果您想看到与合并操作发生之前完全相同的历史记录,那就用 merge 吧, merge 会保存历史记录,但 rebase 会重写它。

rebase 更好的简化了复杂的历史记录,您可以通过交互式 rebase 更改提交历史。您可以删除不需要的提交(git rebase --onto )、将两个或多个提交压缩到一个提交中或编辑提交消息。

rebase 将一次显示一个提交冲突,而 merge 将一次显示所有冲突。一次显示一个提交冲突会使冲突处理的更容易,更好,但是不要忘了当有很多冲突发生时 revert rebase 操作比 revert merge 操作要困难得多。

参考与扩展

git — Basic Rebase
git-difference-between-merge-and-rebase
git-for-each-ref
Rebase vs Merge Interactive Rebase