git rebase实践,适合新手

2,025 阅读5分钟

网上有不少关于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]。

回车,进入下一交互界面:

这里只关注picksquash这两个命令,其余命令可参考其他文章了解。
p, pick: 保留该 commit
s, squash: 将该 commit 和 前面一个 commit 合并

上述交互界面中,输入i,进入INSERT编辑模式,修改下图的红框部分,我们将后两次commitpick改成squash,目的是将 3 次commit合并,好好对比下修改前后红框中的内容:

完成修改后按esc退出编辑,输入:wq保存退出,进入下一交互界面:

同样,进入编辑模式,修改红框中的commit message,这里我改成了完成A功能,如下图,保存退出。

git log查看下,3 次commit变成了 1 次commitcommit记录看上去清爽多了:

迫不及待的git push,却发现报错了:

wtf,执行git branch -a,原来我们进入了基于dev切出来的临时分支(no branch)

遇事不要慌,按以下步骤解决:

  1. 基于无名的临时分支创建dev-temp分支:git checkout -b dev-temp
  2. 切回dev分支:git checkout dev
  3. 执行git rebase dev-temp

再看一眼git log,ok,没问题:

执行git push,一切顺利,去github看下dev分支的提交记录:

多次commit合并了,是我想要的效果~
当然,也可以合并多次提交至另一分支,可自行学习git rebase --onto的用法

2. 合并其他分支

合并其他分支有git rebasegit merge两种方式,它们的区别以及适用场景可自行了解,本文只使用git rebase来实操一遍,先有个感性的认识。

接着上文,我们在dev分支开发A功能的同时,团队其他成员也在开发同一项目的B功能:增加d.jse.js文件,修改README.mdB功能完成后提交合并至master分支:

此时,dev分支的master的内容是落后于当前master分支内容的,因为dev分支的master的内容B功能合并之前的内容,少了B功能部分,这块好好体会一下。

如何合并包含新提交内容(B功能)的master分支呢?很简单,在当前dev分支执行git rebase master

以上就完成了合并,查看dev分支的项目代码:有了d.jse.js文件,README.md也变了,git log看下commit记录

发现个有趣的现象,B功能commitA功能commit之前,难道不应该在后吗?原来rebase内部会做以下处理:

  1. rebase内部会把dev分支里的commit取消掉;
  2. 把步骤 1 中取消的commit保存在.git/rebase目录下;
  3. dev分支更新到最新的master分支(这里好好体会下变基的意义);
  4. 把步骤 2 保存的commit应用到dev分支上。

但发生代码冲突的场景更加常见,如果开发A功能B功能时都修改了同一文件,例如你之前开发A功能时也改了README.md内容,那可能就产生冲突(conflict)了,如下图所示:

冲突的文件变紫了,遇事不要慌,按以下步骤解决就可以了:

  1. 先在IDE(我用的是VSCode)手动处理冲突,我选择了保留双方修改,并保存;
  2. 处理完冲突后执行git add .,注意:执行git add .后不需要再执行git commit
  3. 继续执行rebase命令:git rebase --continue,如果还有冲突,重复上面的步骤,直到完成分支合并,如下图;
  4. 记住,在 rebase过程中一旦处于懵逼状态,可随时终止当前rebase操作:git rebase --abort,想明白了重新再来。

结束

优秀的人,都在"刻意练习"。