git rebase指令
一、基本使用
-
github上新建一个项目
-
默认有master分支(注意:现在的Github默认创建的分支是main分支)
-
将项目clone到本地
模拟日常开发
A同学操作
-
执行git log
可以看出此时该项目仅有一次提交记录
-
新增文件,执行commit、push操作
-
刷新Github,发现A同学提交的记录
-
基于已有两次提交记录的本地master分支检出一个新分支dev,并将该分支推到远程仓库
-
查看远程仓库,多了一个dev分支
-
此时本地的git分支图类似如下(C1、C2表示提交的版本)
-
假设A同学基于dev分支开发功能,在本地新做了三次代码提交,git log 如下
-
此时的git分支图如下
B同学操作
如果此时在A同学准备进行第四次本地提交之前,另一个同学B向远程仓库推送了一个master分支的提交,即此时master实际的提交已经向前走了:
A同学操作
-
切换到master分支,获取master最新的B提交的代码
-
此时的分支图如下
-
A同学开发的dev分支是基于C2提交点切出来的,而这个时候master分支已经被更新了,如果A同学开发完毕,需要将其所作的功能合并到master分支 ,他可以有两种选择:
- git merge
- git rebase
方式一:git merge
切换到master分支,执行 git merge dev
命令,该命令的执行过程如下:
-
找出dev分支和master分支的最近共同祖先commit点,即C2
-
将dev最新一次commit(C5)和master最新一次commit(C6)合并后生成一个新的commit(C7),有冲突的话需要解决冲突
-
将以上两个分支dev和master上的所有提交点(从C2以后的)按照提交时间的先后顺序依次放到master分支上(也就是说所有提交的记录都会保留)
-
此时的分支图如下:
之后A同学继续在dev分支进行开发,master继续往前走,如果发生merge重复上述步骤。
这种方式的缺点:
由于merge会把所有分支的各种信息都会记录下来,如果项目分支较多且commit次数较多,就会出现如下情况,过于复杂:
方式二:git rebase
-
rebase之前需要将master的代码pull到最新
-
在dev分支,执行
git rebase master
命令,执行之后效果如下:可以发现并没有多出一次commit,而且dev后面几次提交的commit hash值已经变了,包括C3,C4,C5。
-
切换到master分支,执行
git rebase dev
,执行之后效果如下:发现采用rebase的方式进行分支合并,整个master分支并没有多出一个新的commit,原来dev分支上的那几次(C3,C4,C5)commit在rebase之后其hash值发生了变化,整个master分支的commit记录呈线性记录,如下图:
注意:原master的C6在dev的C3之前。
总结
-
git merge 操作合并分支会让两个分支的每一次提交都按照提交时间(并不是push时间)排序,并且会将两个分支的最新一次commit点进行合并成一个新的commit,最终的分支树呈现非整条线性直线的形式。
-
git rebase操作实际上是将当前执行rebase分支的所有基于原分支提交点之后的commit打散成一个一个的 patch(补丁),并重新生成一个新的commit hash值,再次基于原分支目前最新的commit点(所以需要将master拉取到最新)上进行提交,可以保持整个分支树的完美线性。
-
两种方式的对比图:
二、-i 参数合并commit
在日常开发中,代码变更比较频繁,有时候想让前几次提交的合并为一次提交(比如某一功能的多次提交只保留最后一次提交),这里可以使用git rebase -i 命令来完成。
格式:
git rebase -i [startpoint] [endpoint]
其中 -i 的意思是 –interactive,即弹出交互式的界面让用户编辑完成合并操作,[startpoint] [endpoint] 则指定了一个编辑区间,如果不指定 [endpoint],则该区间的终点默认是当前分支HEAD所指向的commit点(注意:该区间指定的是一个前开后闭的区间)
举例:
// 合并从当前head到15f745b(commit id)
git rebase -i 15f745b
// 合并最近的两次提交
git rebase -i HEAD~2
执行这个命令后会跳到一个vi编辑器:
将这个编辑器中想要压缩的commit的最前端修改为s,s 为 squash 的缩写,表示将这次提交压缩为最后一次提交。
输入 :wq
进行保存,会弹出如下界面:
输入 :wq
进行保存,然后输入 git push -f
与github端同步。
三、补充指令
git rebase --continue:继续rebase操作,比如rebase时发生冲突,解决完后 git add,再执行 git rebase --continue
就可以继续rebase操作了。
git rebase --abort:终止本次rebase操作。