likes
comments
collection
share

git rebase入坑指南(流程图+实验全解)

作者站长头像
站长
· 阅读数 2

在协同开发时,我们不可避免的需要代码整合,一般来说,merge是我们最先接触的代码整合方法。

但是我最近发现为什么有些人不喜欢用 merge而提倡用rebase了,因为在 merge 之后,commit 历史就会出现分叉,显得非常混乱。如下图:

git rebase入坑指南(流程图+实验全解)

这种分叉再汇合的结构总会让强迫症的我觉得很不舒服,不知道哪次改动在哪个commit记录中。

听说备受推崇的rebase能够解决这个问题,让commit历史成一条直线更加清晰。

但是,问题来了,我想解决的这个分叉虽然是我造成,但是他为什么会分叉呢?

一、merge为什么会产生分叉?

首先小明创建分支test,在master的基础上进行了一点小改动

git rebase入坑指南(流程图+实验全解)

与此同时,在小明想要将代码合并到master前,小刚将他的代码合并到了master。

git rebase入坑指南(流程图+实验全解)

此时,小明想要将代码合并到master中,发现merge request出现了冲突,于是就回到自己的分支通过merge master into xiaoming 在自己的分支上解决冲突。

git rebase入坑指南(流程图+实验全解) git rebase入坑指南(流程图+实验全解)

于是,分叉就出现了。此时紫色的分叉代表着xiaoming分支的改动,灰色的分支代表着master分支的改动。最后通过一个merger的commit进行合并。

无论有没有冲突,commit记录都会出现分叉。如果有冲突的话,最后的merge commit会显示冲突解决的过程;如果没有冲突的话,这里也会有一个无意义的merge commit。

xiaoming merge master后的分支如下:

root
同步
小明的提交
合并小刚的提交
merge-commit

也就是说,两个人同时对功能进行开发,如果进行代码整合,就不可避免地会造成commit 历史分叉。 两个人可能看起来还比较清晰,如果是一个大团队十几个人进行开发,那这个混乱程度想想就很绝望。

所以,我想让自己分支的commit历史变成成一条直线,是不是会更加清晰,更方便管理?

于是,我们就需要用到rebase了。

二、对rebase的理解

2.1 rebase的含义

相比较于merge(合并) 这种望文生义,通俗易懂的词语,rebase(变基) 貌似有点的过于生僻而难以理解了。

其实这个翻译还是比较准确的。rebase 的意思是,把你现在所在的 commit 以及它所在的 commit 串,以指定的⽬标分支最新提交为基础,依次重新提交⼀次。

官方的rebase解释如下: 当执行rebase操作时,git会从两个分支的共同祖先开始提取待变基分支上的修改,然后将待变基分支指向基分支的最新提交,最后将刚才提取的修改追加到基分支的最新提交的后面。

2.2 rebase操作流程

rebase xiaoming onto master中,待变基的分支是xiaoming,基分支是master。两个分支的共同祖先为 同步这个commit。执行这个命令的流程如下:

2.2.0. 原有xiaoming分支上的情况

root
同步
小明的提交

2.2.1. 提取xiaoming分支上的修改小明的提交

root
同步
小明的提交

2.2.2. xiaoming分支指向master分支上最新的提交合并小刚的提交

root
同步
合并小刚的提交
小明的提交

2.2.3. 将提取xiaoming分支出来的修改小明的提交,追加到master分支上最新的提交合并小刚的提交后面。

root
同步
合并小刚的提交
小明的提交

从上述rebase的流程图来看,就很容易就能发现为什么rebase不会产生分叉了。

2.3 rebase的缺陷

rebase后远程仓库和本地仓库会出现这样的情况。

  • git远程仓库中分支情况如下:
root
同步
小明的提交
  • 本地仓库分支情况如下:
root
同步
合并小刚的提交
小明的提交

这个时候你按照原有的习惯直接push是一定会报错的。因为git的push操作默认是假设远端的分支和你本地的分支可以进行fast-forward操作,换句话说就是这个push命令假设你的本地分支和远端分支的唯一区别是你本地有几个新的commit,而远端没有。

所以上面这种情况下是不能进行fast-forwad模式的合并操作的,所以当执行 git push origin xiaoming 命令时会报错。

此时没有其他人在这个分支上进行提交操作,那么可以直接进行强制推送 git push --force origin xiaoming ,–force可以直接理解为用你本地分支的状态去覆盖掉远端origin分支的状态,也就是执行过后,本地的分支什么样,远端分支就什么样

这里切记,一定要确保是在自己的分支上只有自己在开发,不能在主干分支上进行force操作,否则会直接覆盖掉别人已经提交的代码,会被打的。

如果这个分支有多人协同开发,最好不要用rebase避免 push --force, 如果一定要用rebase,那我更推荐另外一种更安全的命令  git push --force-with-lease origin xiaoming  使用该命令在强制覆盖前会进行一次检查如果其他人在该分支上有提交会有一个警告,此时可以避免覆盖代码的风险。

三、rebase实践

现在让我们回到最初的起点,reset xiaoming分支到未merge之前。同样的小明和小刚,同样的xiaoming和master,此时master上已经合并了小刚的提交。

xiaoming对master进行rebase,需要checkout xiaoming 然后 rebase xiaoming onto master

git rebase入坑指南(流程图+实验全解) git rebase入坑指南(流程图+实验全解)

需要注意的是rebase仍然需要进行冲突解决(选择merge):

git rebase入坑指南(流程图+实验全解)

rebase生成了新的commit

git rebase入坑指南(流程图+实验全解)

此时需要注意的点在于本地已经将远程的记录给更改了,一定要要push --force才能推送上去

git rebase入坑指南(流程图+实验全解)

push -force

关于git rebase的操作解决 push时被拒绝,整体流程_git push rebase-CSDN博客

git rebase后无法push远程分支的问题解决_git rebase master后git push-CSDN博客

git rebase入坑指南(流程图+实验全解) git rebase入坑指南(流程图+实验全解)

四、rebase与merge的争论

git pull --rebase的作用是什么,它与git pull有什么区别?-CSDN博客

Git 两个常用命令:Git Pull和Git Rebase|极客教程 (geek-docs.com)

总结:使用 rebase 来将远程的变更整合到本地仓库是一种更好的选择。(仅限自己的分支)

  • 用 merge 拉取远程变更的结果是,每次你想获取项目的最新进展时,都会有一个多余的 merge 提交。
  • 而使用 rebase 的结果更符合我们的本意:我想在其他人的已完成工作的基础上进行我的更改。

参考文章