网上有不少关于
git rebase
的文章,图文并茂,讲解全面,但总体感觉理论偏多,入门实践较少,小白读起来会有些困难,本文将常用场景实操一遍,然后再结合其他文章反过来加深理解,这未尝不是一种好的学习方法。
常用的两种使用场景:
- 合并多次 commit 提交
- 合并其他分支代码
开始
github
上新建仓库:learn-rebase
,设置默认分支master
,或许你的默认分支是main
,基于master
分支新建开发分支:dev
,如图:
仓库中只有README.md
,内容如下:
1. 合并多次 commit 提交
为什么要合并多次
commit
?
答:开发一个功能时,由于太菜难免修修补补产生多次commit
,都是同一功能,提交太多commit
没必要,不利于追溯,看着一长串提交记录显得更菜。
例如,我们基于dev
分支开发A功能
,开发过程中共产生了 3 次commit
,每新建一个文件就commit
一次,如图:
此时,我想合并这 3 次commit
,在远程仓库上只体现 1 次commit
,怎么做呢?
执行以下命令来实现:
// git rebase -i [startpoint] [endpoint]
Mac:learn-rebase fanyanbo$ git rebase -i 5541c74775d37a587f233ed317511647900aba0d c0c5629757353fdc53d79232377b01f96e62121b
git rebase -i [startpoint] [endpoint]
-i
的含义是:弹出交互式的界面让用户编辑完成合并操作。
[startpoint]
指的是合并区间的起点;[endpoint]
指的是合并区间的终点,默认是当前分支HEAD
所指向的commit
。
注意:这里的区间是一个前开后闭的区间,(commit_id1,commit_id2]。
回车,进入下一交互界面:
这里只关注
pick
和squash
这两个命令,其余命令可参考其他文章了解。
p, pick: 保留该 commit
s, squash: 将该 commit 和 前面一个 commit 合并
上述交互界面中,输入i
,进入INSERT
编辑模式,修改下图的红框部分
,我们将后两次commit
的pick
改成squash
,目的是将 3 次commit
合并,好好对比下修改前后红框中的内容:
完成修改后按esc
退出编辑,输入:wq
保存退出,进入下一交互界面:
同样,进入编辑模式,修改红框中的commit message
,这里我改成了完成A功能
,如下图,保存退出。
git log
查看下,3 次commit
变成了 1 次commit
,commit
记录看上去清爽多了:
迫不及待的git push
,却发现报错了:
wtf
,执行git branch -a
,原来我们进入了基于dev
切出来的临时分支(no branch)
:
遇事不要慌,按以下步骤解决:
- 基于无名的临时分支创建
dev-temp
分支:git checkout -b dev-temp
- 切回
dev
分支:git checkout dev
- 执行
git rebase dev-temp
再看一眼git log
,ok,没问题:
执行git push
,一切顺利,去github
看下dev
分支的提交记录:
多次
commit
合并了,是我想要的效果~
当然,也可以合并多次提交至另一分支,可自行学习git rebase --onto
的用法
2. 合并其他分支
合并其他分支有
git rebase
和git merge
两种方式,它们的区别以及适用场景可自行了解,本文只使用git rebase
来实操一遍,先有个感性的认识。
接着上文,我们在dev
分支开发A功能
的同时,团队其他成员也在开发同一项目的B功能
:增加d.js
、e.js
文件,修改README.md
,B功能
完成后提交合并至master
分支:
此时,
dev
分支的master的内容
是落后于当前master分支内容
的,因为dev
分支的master的内容
是B功能
合并之前的内容,少了B功能
部分,这块好好体会一下。
如何合并包含新提交内容(B功能
)的master
分支呢?很简单,在当前dev分支
执行git rebase master
:
以上就完成了合并,查看dev
分支的项目代码:有了d.js
、e.js
文件,README.md
也变了,git log
看下commit
记录
发现个有趣的现象,
B功能
的commit
在A功能
的commit
之前,难道不应该在后吗?原来rebase
内部会做以下处理:
rebase
内部会把dev
分支里的commit
取消掉;- 把步骤 1 中取消的
commit
保存在.git/rebase
目录下;- 把
dev
分支更新到最新的master
分支(这里好好体会下变基的意义
);- 把步骤 2 保存的
commit
应用到dev
分支上。
但发生代码冲突的场景更加常见,如果开发A功能
和B功能
时都修改了同一文件,例如你之前开发A功能
时也改了README.md
内容,那可能就产生冲突(conflict
)了,如下图所示:
冲突的文件变紫了
,遇事不要慌,按以下步骤解决就可以了:
- 先在
IDE
(我用的是VSCode
)手动处理冲突,我选择了保留双方修改,并保存;- 处理完冲突后执行
git add .
,注意:执行git add .
后不需要再执行git commit
;- 继续执行
rebase
命令:git rebase --continue
,如果还有冲突,重复上面的步骤,直到完成分支合并,如下图;- 记住,在
rebase
过程中一旦处于懵逼状态,可随时终止当前rebase
操作:git rebase --abort
,想明白了重新再来。
结束
优秀的人,都在"刻意练习"。