git-变基(rebase)的原理和最佳实践

前言

在 Git 中整合来自不同分支的修改主要有两种方法:merge 以及 rebase

其中merge是一个三方(分支master最新快照,分支dev最新快照,分支master和dev的共同祖先快照)合并的方式来整合修改,并且整合之后会生成新的提交快照。

merge之前的三方(c4c5及共同祖先c2):
在这里插入图片描述
merge之后产生新的提交快照(c6
在这里插入图片描述
merge之后,iss53分支的c3c5提交快照消失了。

为了避免提交快照因为合并而移除的问题,发明了rebase方法来整合不同分支的修改。

更多merge的用法请参考分支的新建与合并

变基的原理

假设日常开发中出现了如下图所示的场景:分支experiment和分支master分别在共同祖先C2上生成了提交快照C4C3
在这里插入图片描述

首先找到这两个分支(即当前分支 experiment、变基操作的目标基底分支master) 的最近共同祖先 C2,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件, 然后将当前分支指向目标基底 C3, 最后以此将之前另存为临时文件的修改依序应用。

在这里插入图片描述
此时,只需要在目标基底分支master上和合并rebase过的experiment分支即可。

$ git checkout master
$ git merge experiment

这样,两个分支的提交快照都保留了下来,效果如下:
在这里插入图片描述

更复杂的变基

在对两个分支进行变基时,所生成的“重放”并不一定要在目标分支(下文的server分支)上应用,你也可以指定另外的一个分支(下文的master分支)进行应用。 你创建了一个主题分支server,为服务端添加了一些功能,提交了C3C4。 然后从C3上创建了主题分支client,为客户端添加了一些功能,提交了C8C9。 最后,你回到server分支,又提交了C10

整个项目的提交状态如下:
在这里插入图片描述
master分支和server分支的共同祖先是C2server分支和client分支的共同祖先的C3

假设你希望将client中的修改合并到主分支并发布,但暂时并不想合并server中的修改, 因为它们还需要经过更全面的测试。这时,你就可以使用 git rebase 命令的 --onto 选项, 选中在client分支里但不在server分支里的修改(即C8C9,也就是serverclient共同祖先C3之后的修改),将它们在master分支上重放:

git rebase --onto master server client

--onto参数指定的分支是最后要变基的基底分支,这里是master,而server用于确定client分支要基于的共同祖先C3之后的提交快照。

以上命令的意思是:“取出client分支,找出它从server分支分歧之后的补丁, 然后把这些补丁在master分支上重放一遍,让 client 看起来像直接基于master修改一样”。这理解起来有一点复杂,不过效果非常酷。

使用--onto参数,client分支需要重播的提交是C3之后的提交,而不是C2之后的提交。这样,用于确定共同祖先的分支(server)和最终要变基的基底分支(master)是独立的。

最终rebase后的效果如下:

在这里插入图片描述
同样,此时要在目标基底分支master合并client分支来整合C8C9提交:

$ git checkout master
$ git merge client

在这里插入图片描述
接下来你决定将server分支中的修改也整合进来。 使用 git rebase <basebranch> <topicbranch> 命令可以直接将主题分支 (即本例中的server)变基到目标分支(即master)上。 这样做能省去你先切换到server分支,再对其执行变基命令的多个步骤。

$ git rebase master server

在这里插入图片描述
然后就可以快进合并主分支master了:

$ git checkout master
$ git merge server

在这里插入图片描述
至此,clientserver分支中的修改都已经整合到主分支里了, 你可以删除这两个分支,最终提交历史会变成上图中的样子:

$ git branch -d client
$ git branch -d server

使用变基的原则

如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。

简单的说就是只在自己的分支变基,然后在公共分支上合并变基后的提交记录。

本地变基后推送到远程

在本地分支变基(可能要解决冲突)后,本地分支和远程分支会变得不一样,特别是有冲突的时候,推送上去会提示要merge还是rebase。如果远程的分支只有自己修改,可以使用git push --force让本地分支直接覆盖远程分支,使远程分支最新。如果远程分支可能有其他人修改,最好使用git push --force-with-lease,这个命令在检测到远程分支修改时,不会强制覆盖。此时需要先fetch远程分支,然后整合分支修改,然后再使用git push --force-with-lease推送代码。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值