git rebase与git merge
前言
世界上对待任何事物都会有至少2种看法,好的或坏的或好坏折中等。
规范或许就是你眼中的最折中的方案。
而git rebase与git merge,对应的2种看法:
有一种观点认为,仓库的提交历史即是 记录实际发生过什么。 它是针对历史的文档,本身就有价值,不能乱改。 从这个角度看来,改变提交历史是一种亵渎,你使用_谎言_掩盖了实际发生过的事情。 如果由合并产生的提交历史是一团糟怎么办? 既然事实就是如此,那么这些痕迹就应该被保留下来,让后人能够查阅。
另一种观点则正好相反,他们认为提交历史是 项目过程中发生的事。 没人会出版一本书的第一版草稿,软件维护手册也是需要反复修订才能方便使用。 持这一观点的人会使用 rebase 及 filter-branch 等工具来编写故事,怎么方便后来的读者就怎么写。
就像使用reset
和revert
一样,并不是极端的认为谁谁就一定不能用。此时,脑子是个好东西。
git rebase
我也称之为“变基”,通俗点说就是将修改的提交从一个“同源基础”移植变换到另一个新的“同源基础”上。
变基的2种使用场景
假设我们的git分支为
* master
name_a
- 1.简单的分支变基操作
假设我们对分支做了如下操作:
接着做变基操作
# 当前分支
* name_a
master
git rebase master name_a
git checkout master
git merge name_a
结果如图所示
可以发现,在做变基之后,name_a分支和master分支在同源祖先c0后的提交一模一样了
变基的流程是:
- 找到同源祖先c0
- 对比name_a分支与祖先的修改c2,提取暂存到缓存区
- 将c2分支变基指向c1
变基有冲突时,git会提示你先resolve掉,接着git add/rm file
,然后git rebase --continue
First, rewinding head to replay your work on top of it...
Applying: 修改name_a
Using index info to reconstruct a base tree...
M 02.js
.git/rebase-apply/patch:9: trailing whitespace.
222
warning: 1 line adds whitespace errors.
Falling back to patching base and 3-way merge...
Auto-merging 02.js
CONFLICT (content): Merge conflict in 02.js
error: Failed to merge in the changes.
Patch failed at 0001 修改name_a
The copy of the patch that failed is found in: .git/rebase-apply/patch
master上查看log
name_a上查看log
可以看到分支name_a上和master上的commit记录是一样的。
疑问?
网上的资料说
一个提交仅仅包括很少的属性,比如作者,日期,变动和谁是它的父提交。如果改变其中任何一个信息,就必须创建一个全新的提交。当然,新的提交也会拥有一个新的 hash ID 。
此时c2与c2*虽然为相同的修改,但是由于目标基底不一致了,所以应该为不同的提交。但是我查看commit_id后发现是一样的。作何理解?
- 2.多分支的变基操作
此时我们需要新增一个分支name_b
,分支即为
* master
name_a
name_b
修改过程:
- 我们从master上做了c1修改并提交
- 同时拉了一个新分支name_a,并做了c2修改
- 在c2的基础上新拉一个分支name_b
- name_a继续做修改c3
- name_b做了c4,c5修改
突然有一天,需要先发布c4, c5修改。像极了你在功能分支develop
上新拉分支写新需求的场景有没有?
此时,我们可以使用
git rebase --onto master name_a name_b
git checkout master
git merge name_b
--onto
的过程解释为:找到name_b分支,再找到它与name_a分支同源祖先c2之后的修改,即c4,c5,将他们变基到master上,得到的结果如下图:
分支name_b上查看log
接着可能又有一天分支name_a的修改可以发布了,需要合并到master,接着我们再使用简单的变基即可
master上查看log
查看--graph
会发现是一条线,很清晰
rebase的适用场景
1 .只适合本地提交记录的清理,不能将已push的记录再做rebase。
例如,你提交了c1,c2并push到了仓库,别人也pull你的c1, c2到本地进行了开发并push了c3,c4,此时如果你回滚掉c2,再做rebase,那将使得你自己得整合冲突,并且提交记录里会出现一模一样的2条。如下图中的c7,c8,就是一模一样的2条提交记录
2 .当自己本地分支rebase后,在master上准备push前,一定要先git pull --rebase
,因为很有可能别人已经push过了,git pull --rebase
可以认为是2步:
- git fetch到缓存区一个分支
- 在master上git rebase 这个分支
那么你的提交永远变基在最前面。
以上部分参考
- 3.6 Git 分支 - 变基
- Rebase 代替合并 此文中有部分观点与上一篇冲突,但能帮助理解