作者同系列博客参考链接:
Git基础入门六:标签管理(git tag)
Git基础入门五:分支管理
Git基础入门四:版本回退(撤销修改)
Git基础入门三:创建版本库和添加修改文件基本命令
Git基础入门二:工作区和暂存区
Git基础入门一:起源与安装
1、rebase概念:
rebase翻译过来的意思是变基,将你的当前分支重新设置开始点。
rebase会把你当前分支的 commit 放到公共分支的最后面,所以叫变基。就好像你从公共分支又重新拉出来这个分支一样。
举例:如果你从 master 拉了个feature分支出来,然后你提交了几个 commit,这个时候刚好有人把他开发的东西合并到 master 了,这个时候 master 就比你拉分支的时候多了几个 commit,如果这个时候你 rebase master 的话,就会把你当前的几个 commit,放到那个人 commit 的后面。
rebase操作的特点:把分叉的提交历史“整理”成一条直线,看上去更直观。缺点是本地的分叉提交已经被修改过了。
操作方法思路:你可以提取在旁支
中引入的补丁和修改,然后在 主分支
的基础上应用一次。
目的:rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比。
2、Rebase和merge区别:
操作前:
Merge后:
Rebase后:
$ git checkout experiment
$ git rebase master
或者:
$ git rebase master experiment
使用 git rebase [basebranch] [topicbranch]
命令可以直接将特性分支(即本例中的 experiment
)变基到目标分支(即 master
)上。这样做能省去你先切换到 experiment
分支,再对其执行变基命令的多个步骤。
此时还需做下快速合并分支,使得experiment和master指针到最新版本:
$ git checkout master
$ git merge experiment
请注意:无论是通过变基,还是通过三方合并,整合的最终结果所指向的快照始终是一样的,只不过提交历史不同罢了。 变基是将一系列提交按照原有次序依次应用到另一分支上,而合并是把最终结果合在一起。
3、切片rebase:--onto选项: 截取特性分支上的另一个特性分支,然后变基到其他分支
原场景:
诉求:只想把client的改动而不是server分支的改动合并到master中
$ git rebase --onto master server client
以上命令的意思是:“取出 client
分支,找出处于 client
分支和 server
分支的共同祖先之后的修改,然后把它们在 master
分支上重放一遍”。
然后再从client快速合并到master中:
$ git checkout master
$ git merge client
接下来你决定将 server
分支中的修改也整合进master,server
中的代码被“续”到了 master
后面。
$ git rebase master server
然后就可以快进合并主分支 master 了:
$ git checkout master
$ git merge server
至此,client
和 server
分支中的修改都已经整合到主分支里了,你可以删除这两个分支,最终提交历史会变成图 最终的提交历史 中的样子:
$ git branch -d client
$ git branch -d server
4、变基的风险:不要对在你的仓库外有副本的分支执行变基。
变基操作的实质是丢弃一些现有的提交,然后相应地新建一些内容一样但实际上不同的提交。 如果你已经将提交推送至某个仓库,而其他人也已经从该仓库拉取提交并进行了后续工作,此时,如果你用 git rebase
命令重新整理了提交并再次推送,你的同伴因此将不得不再次将他们手头的工作与你的提交进行整合,如果接下来你还要拉取并整合他们修改过的提交,事情就会变得一团糟。
5、在一个被变基然后强制推送的分支上再次执行变基
如果团队中的某人强制推送并覆盖了一些你所基于的提交,你需要做的就是检查你做了哪些修改,以及他们覆盖了哪些修改。
实际上,Git 除了对整个提交计算 SHA-1 校验和以外,也对本次提交所引入的修改计算了校验和—— 即 “patch-id”。
如果你拉取被覆盖过的更新并将你手头的工作基于此进行变基的话,一般情况下 Git 都能成功分辨出哪些是你的修改,并把它们应用到新分支上。
举个例子,如果遇到前面提到的 有人推送了经过变基的提交,并丢弃了你的本地开发所基于的一些提交 那种情境,如果我们不是执行合并,而是执行 git rebase teamone/master,
Git 将会:
- 检查哪些提交是我们的分支上独有的(C2,C3,C4,C6,C7)
- 检查其中哪些提交不是合并操作的结果(C2,C3,C4)
- 检查哪些提交在对方覆盖更新时并没有被纳入目标分支(只有 C2 和 C3,因为 C4 其实就是 C4')
- 把查到的这些提交应用在 teamone/master 上面
(1)原场景:
(2)Git pull方式会变成下图所示情况:
此时如果你执行 git log
命令,你会发现有两个提交的作者、日期、日志居然是一样的,这会令人感到混乱。 此外,如果你将这一堆又推送到服务器上,你实际上是将那些已经被变基抛弃的提交又找了回来,这会令人感到更加混乱。 很明显对方并不想在提交历史中看到 C4
和 C6
,因为之前就是他把这两个提交通过变基丢弃的。
(3)用变基解决变基: git rebase teamone/master
上图变为:
要想上述方案有效,还需要对方在变基时确保 C4' 和 C4 是几乎一样的。 否则变基操作将无法识别,并新建另一个类似 C4 的补丁(而这个补丁很可能无法整洁的整合入历史,因为补丁中的修改已经存在于某个地方了)。
在本例中另一种简单的方法是使用 git pull --rebase 命令而不是直接 git pull。 又或者你可以自己手动完成这个过程,先 git fetch,再 git rebase teamone/master。
如果你习惯使用 git pull ,同时又希望默认使用选项 --rebase,你可以执行这条语句 git config --global pull.rebase true 来更改 pull.rebase 的默认配置。
只要你把变基命令当作是在推送前清理提交使之整洁的工具,并且只在从未推送至共用仓库的提交上执行变基命令,就不会有事。 假如在那些已经被推送至共用仓库的提交上执行变基命令,并因此丢弃了一些别人的开发所基于的提交,那你就有大麻烦了,你的同事也会因此鄙视你。如果你或你的同事在某些情形下决意要这么做,请一定要通知每个人执行 git pull --rebase 命令,这样尽管不能避免伤痛,但能有所缓解。
到底合并还是变基好?总的原则是,只对尚未推送或分享给别人的本地修改执行变基操作清理历史,从不对已推送至别处的提交执行变基操作,这样,你才能享受到两种方式带来的便利。
作者同系列博客参考链接:
Git基础入门六:标签管理(git tag)标签管理(git tag)
Git基础入门五:分支管理
Git基础入门四:版本回退(撤销修改)
Git基础入门三:创建版本库和添加修改文件基本命令
Git基础入门二:工作区和暂存区
Git基础入门一:起源与安装