Git进阶:熟悉rebase变基

本文最后更新于:3 个月前

rebase和常用的合并方式merge有什么区别?除了简单的合并之外,rebase命令还能实现哪些骚操作?使用rebase命令需要注意什么?

Git进阶:熟悉rebase变基

一、rebase简介

git-rebase - Reapply commits on top of another base tip(译:在其它基础分支的头部重新应用commit修改)

在git中,有两种合并分支的方式:mergerebase,下面通过两张图来快速了解两种方式的差异:

image-20231210155911684

1
2
git checkout master		# 切换到master分支
git merge experiment

image-20231210155931447

1
2
3
4
5
6
7
8
git rebase master experiment	
# 找出experiment分支在与master分支分歧(C2)之后的修改,在master分支上重放一遍
# 不管终端当前处在哪个分支上,执行完该命令后,都会定位到experiment分支上
# 但此时master并没有指向最新的commit,还需要切换到master分支上,然后使用merge快进

git checkout master
git merge expriment
git branch -d expriment # 合入之后,可以选择删除源分支,这是一个好习惯

image-20231210172900885

合并结果上来看:

  • rebase之后得到一条串行的commit链
  • merge之后得到一条并行的commit链

合并方式上来看:

  • rebase将「修改分支的所有commit节点」 有序地移动到 「目标分支的HEAD节点」 之后。相当于把所有修改行为,在合入分支上重新播放一遍!(记住:虽然节点的数量一致,修改的内容也一致,但C4与C4’并不是同一个节点),也相当于将expriment分支的祖先节点从 C2 变为 C3 ,即 base 发生改变,所以叫rebase
  • merge在「目标分支的HEAD节点」之后创建一个 「合并节点」,将「修改分支」和「目标分支」同时指向「合并节点」

至此,你会发现:虽然rebasemerge在合并方式、合并的形式上都不同,但最终实现的效果是相同的。别急,下面即将介绍一些rebase才特有的功能。

二、rebase用途

1. 跨域分支执行合并

这个标题可能有点抽象,看下面的两种图可能会更加清晰:

image-20231210170634869

image-20231210170707570

答案是使用 rebase --onto 命令:

1
git rebase --onto master server client

以上命令的意思是:“取出 client 分支,找出它从 server 分支分歧之后的补丁, 然后把这些补丁在 master 分支上重放一遍,让 client 看起来像直接基于 master 修改一样”

注意:此时master指针还停留在原地,需要将master指针进行快进

1
2
git checkout master
git merge client

2. 重写commit message

你可能会遇到过如下场景:在开发期间,先后提交了几条commit,例如:先后提交了“chore:初始化项目”“feat:添加Home组件”“feat:添加api接口逻辑”。但是突然有一刻,你觉得第一条commit message不是很妥当,于是想要修改它,但是却被新的两条commit阻隔,让你非常犹豫,是否要将三条commit reset然后全部重新commit一遍

此时,便可以使用git rebase -i-i表示interactive,交互式的)命令轻松实现,只修改指定的历史commit message

1
git rebase -i HEAD^3	#HEAD~3指定回溯的起点,从前3次commit开始回溯

下面给出一个示例:

(1)第一步,mock出多次commit记录

image-20231029110045291

(2)第二步,现在需要在不动HEAD^HEAD^2这两次commit的情况下,修改HEAD~3的commit message

1
git rebase -i HEAD~3

输入命令后,终端会打开一个编辑器,如下

image-20231029110431872

文首会按照commit的先后顺序,从上到下列出commit记录,此时将需要修改的commit,对应行首的pick改成edit(按下i键,进入编辑模式)

1
pick eaadd88 rebase测试1	# 改成 edit eaadd88 rebase测试1

然后(按下esc退出编辑模式),保存退出(输入:wq,并回车)

【扩展】如果在编辑该文件的过程中,失误导致了一些无法回撤的操作(eg:误删了一行),可以先:wq保存退出,然后输入git rebase --abort 终止rebase过程,然后再开启一个新的rebase

(3)第三步,终端会弹出提示。

image-20231029110900017
1
git commit --amend
image-20231029111016889

(键入i进入编辑,将第一行的commit message,按需求进行修改。按下esc键退出,输入:wq,并回车保存退出)

注意:如果此时(即没有输入git rebase --continue之前)再次输入git commit --amend,将再次进入同一个commit记录中,可以反复多次进行修改!

(4)第四步,进入下一步

1
git rebase --continue
image-20231029111536005

因为rebase过程只有一个edit需求,所以点击下一步直接完成rebase过程。此时给出成功提示!

image-20231029111808557

【扩展】

Q:如果要修改多条commit message怎么处理?
A:只需要将需要修改的commit记录前面的 pick 都改成 edit 即可!

3. 压缩历史commit

你可能遇到过这样的场景:

  • 开发完组件A,提交了一条commit,feat: 完成组件A开发
  • 接着又完成了组件B,又提交了一条commit,feat:完成组件B开发
  • 然后又开发完了组件C,再次提交了一条feat:完成组件C开发

提交完这些之后,你发现照这样的趋势下去,提交的commit条数可能会太多了,于是便想着把是否可以把这三条相似的commit合并压缩为一条,让提交更精简一点

答案是可以的,使用的正是rebase命令!

过程与上述「rebase重写commit message」基本相同,区别在于一条命令的差异(重写message用edit、压缩用squash

下面继续用一个示例进行演示

(1)第一步,mock出多条commit记录

image-20231029113608636

(2)第二步,输入git rebase -i HEAD~3

(3)第三步,修改命令,将需要压缩的commit记录,对应前面的pick改成squash

1
2
3
pick 5d21c3d rebase测试,第一次提交
squash e4358b8 rebase测试2
squash 735775e rebase 测试,第三次 commit

(4)第四步,保存退出之后,紧接着会弹出另外一个编辑器,让你编辑压缩的 message

image-20231029114030630
  • 可以选择保留每次的commit message,最终所有message会合并到一条message中

  • 可以删除不需要的message,只需要将对应的message删除即可

  • 可以对message重新编辑

image-20231029114347089

保存退出后,立即执行压缩,完成后弹出成功提示!

image-20231029114410734 image-20231029114540089

【扩展】

压缩提交还可以通过 git reset –soft 来完成!(Todo),参见:Git - 重置揭密 (git-scm.com)

1
2
git reset --soft HEAD~2
git commit

三、使用rebase的注意事项

​ 在普通的合并场景下,rebasemerge都能满足你的需求,区别点在于提交历史是更复杂(merge)还是更简洁(rebase),这是个主观和个性化的选择,没有对错之分,取决于你更倾向哪种!

​ 但是请记住:不要对已经存在于第二个人电脑上的分支执行 rebase 操作!退一步来说,不要对已经被推送到远程仓库的分支执行rebase操作(因为你不知道有没有第二个人拉取了这个分支)。因为rebase 实际上会删除掉一个现存的 commit 节点,然后再新建一个内容一模一样的 commit 节点,这会导致出现不一致的现象!

​ 只讲理论太抽象,下面通过一个例子来了解:

image-20231210164837133

image-20231210165136120

image-20231210165853715

image-20231210170136567

参考链接

对于git初学者,和希望对git有进一步了解的朋友,强烈推荐Git - Book (git-scm.com),理论体系完整、而且有中文版易于阅读


Git进阶:熟悉rebase变基
http://timegogo.top/2023/10/25/Git/Git进阶-熟悉rebase变基/
作者
丘智聪
发布于
2023年10月25日
更新于
2023年12月10日
许可协议