前言
前文说到 Git 撤销操作实践之 Reset Revert Rebase 中提到 rebase 在修改 commit 日志的用法,但是对于 git rebase 来说只是冰山一角。rebase 的功能以及复杂程度也完全没有体现出来。所以今天就来深入了解 rebase 的用法。
说到 git rebase 就不得不提到 git merge,这两个命令都有合并分支的功能,下面看一下在合并分支上最大的区别:
git merge尽可能的保持原始的提交、合并记录,并不在乎分叉的节点,操作简单。git rebase让多个人在同一个分支开发的提交节点形成一条线,而不是多条线,操作较复杂。
Rebase
举个例子
首先我线模拟我们最常用的 merge 操作对应的 git graph,如下图:
ps:vscode 插件为 Git Graph
如果是三个需求同时开发就会出现图上的三个分叉点,其实这么看还是可以接受的,那么下面的这中图呢?
想必无论是哪个开发 面对这种 git 提交的历史都是头疼的,根本没有review 代码的欲望。对于查看历史需求也是个噩梦。
那么如何避免提交历史出现类似的噩梦呢?
答案就是今天的主角 rebase。
如何操作
Rebase 的原理是首先找到这两个分支的最近共同祖先,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件,然后将当前分支指向目标基底,最后以此将之前另存为临时文件的修改按照顺序合并。
合并代码的本质操作依旧是 git merge,只是在合并之前拉齐开发分支与被合并分支 git rebase master feature。
# 1. 当前开发分支与 master 对齐
$ git rebase master feature
Current branch feature is up to date.
# 这条命令等价于: # git checkout boxfilter; git rebase main
# 如果发生冲突,手动解决后需要执行 git rebase --continue
# 2. 切换分支到 master
git checkout master
# 3. 执行合并
git merge feature
# 或者使用 git merge --squash feature 可以合并多次 commit
# 如果有冲突 解决完冲突 继续
git rebase --continue
需要注意的是 git pull 默认使用的是 merge 的方式将远程分支与本地本地合并;可以使用 git pull --rebase 使用 rebase 的方式拉取代码。
git pull==git fetch + git mergegit pull --rebase==git fetch+git rebase teamone/master
结果对比
如下图可以很明显的看出用了 rebase 后的区别。提交日志从多分支变成了单分支,日志也清晰明了。
总结
关于 merge 与 rebase 的使用网络上也是众说纷纭。反正是各有千秋,所以观点基本上很难统一。
我的观点是如果项目迭代的较慢、开发人员较少,merge 保留所有的开发合并记录没有问题。一旦一个项目参与人员越来越多,并行开发功能也越来越多那么 rebase 在尽可能保留提交历史的前提下,才是最适合开发人的。