git rebase使用详解
本篇博客的视频教程首发于 Youtube:科技小飞哥,加入 电报粉丝群 获得最新视频更新和问题解答。
背景
在你看这篇文章之前,我假设你已经至少会git
的一些基本指令,能进行简单的git repo的操作。比如:pull, add, commit, merge, push 等几个基础命令至少会用。而我们刚开始接触git的时候,会这些简单的指令能满足基本的git代码的开发与提交。
但是当你把git作为一个常用的工具之后,还是需要了解一些相对进阶的常用指令。而这篇文章我们来讲讲进阶命令git rebase
。
理解Rebase命令
git rebase 命令的文档描述是:
Reapply commits on top of another base tip
从字面上理解是在另一个基端之上重新应用提交
,这个定义听起来有点抽象,换个角度可以理解为将分支的基础从一个提交改成另一个提交,使其看起来就像是从另一个提交中创建了分支一样
。
下面我来详细讲解一下git rebase
命令最常用的两个用法,让大家更深入的理解 在另一个基端之上重新应用提交 的概念。
Rebase常用的两个使用场景是:
- 合并commit记录
- 合并分支(重写提交历史)
一、合并commit记录
有时候开发一个 feature
的时候,在自己的 feature 分支有过多次修改记录,多的时候有好几十次。每次都进行了一些小的修改。这么多commit看起来很不舒服,而且如果合并到master,导入了过多的commit,导致充满了很多无用的commit记录,如果有一天线上出现问题需要回滚代码,大量的commit记录会让你爆炸。
我这里实际的演示,我在我的开发分支 feature1 开发了一个功能,有多条commit 记录,我想要合并成一条,然后提交MR到master(main)。
Note: github 叫 Pull Request, gitlab 叫 Merge Request,只是叫法不一样。
这个时候就需要用到git rebase
了。这个命令并不难,对于git命令的新手来说不熟悉的情况下可能不太敢使用,你可以在用之前先备份你的分支,避免操作失误又不会还原。
1. 合并最近的三条提交记录
执行:
git rebase -i HEAD~3
或者
git rebase -i commit_id
这里的commit_id是你要合并的第一条commit的前一条。可以通过 git log
查看 commmit id。
会自动进入vi编辑模式。
这里可以看到我们有三次提交记录:
pick 3ae8e31 fix 1
pick c2828fb fix 2
pick 6077ab1 fix 3
# Rebase c0933b9..6077ab1 onto c0933b9 (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
这里有一些Commands
,每个有不同的作用,上面都有详细的解释。
我们暂时只需要关注两个,一个是 p(pick), 一个是 s(squash)。
- p, 保留该commit
- s, 将该commit和前一个commit合并
把第一个commit使用 p,后面的所有commit都使用 s。
2、把除第一条commit外都改成squash
pick 3ae8e31 fix 1
s c2828fb fix 2
s 6077ab1 fix 3
像以上这样,把除了第一条提交之外的所有提交的 pick 改成 s(squash)。 然后使用 :wq 退出编辑。
3、修改commit信息(可选)
如果你觉得第一条的commit不太好,想改成一个比较可读性的commit记录,可以直接修改。
这里我把
fix 1
直接编辑 修改为
feature 1 development
然后 :wq 退出。
4、 git log查看commit记录。
这个时候会发现git log里面关于你的feature只有一条commit记录了,就是rebase成功了。
5、git push -f
最后一步就是执行 git push -f 强制push到远端。一定要加 -f 或者 –force。不然无法push成功。因为你当前的本地分支已经回到了之前的提交点。
这个时候刷新一下你的MR的页面。就会发现:
你的commit已经合并了。这个时候你在Merge到master分支,就只有这一条commit记录了。是不是非常干净了。
注意:
- 如果你的分支里面有来自其他分支的
Merge Request
,比如你的开发周期比较久,在你开发的几次提交中间,不停的git merge master
,导致你的分支里面有了master最新的修改。也就是MR
的记录,慎用rebase
,这个时候我一般会用git reset
。只有当你的分支里面全部是你的commit记录的时候,用git rebase
。
二、合并分支
rebase的第二大作用就是合并分支了。
rebase
通常用于重写提交历史。下面的使用场景在大多数 Git 工作流中是十分常见的:
- 我们从
master
分支拉取了一条feature1
分支在本地进行功能开发 - 远程的
master
分支在之后又合并了一些新的提交 - 我们想在
feature1
分支集成master
的最新更改
下面用具体的例子来描述
1、我们先从 master 分支切出一个 feature1 分支,进行开发:
git:(master) git checkout -b feature1
2、这个时候你的同事可能开发了 feature2 并合并到了 master,此时master 已经领先于你的 feature1 分支了。
3、之后我们需要同步 master 的改动。
最常用的做法就是,在你的feature1
分支执行:
git merge master
使用过git命令的人都了解这个命令。 合并之后查看一下log。执行:
git log
就会发现多了一些 merge 的commit信息。如果你的feature的开发周期很长,经常需要定期merge master,就会发现多了很多的 commit 信息。想要保持一份干净的 commit, 这个时候 git rebase 就派上用场了。
4、使用 git rebase master 代替 git merge master
在你自己的feature1
分支上执行:
git rebase master
这里 git rebase 的原理是什么呢?
- git 会把 feature1 分支里面的每个 commit 取消掉;
- 把上面的操作临时保存成 patch 文件,存在 .git/rebase 目录下;
- 把 feature1 分支更新到最新的 master 分支;
- 把上面保存的 patch 文件应用到 feature1 分支上;
从 commit 记录我们可以看出来,feature1 分支是基于 feature2 合并后的 master,就像把一个并行的流程变成一个串行的流程。就没有了 merge 的 commit 记录,看起来会清晰多了。
Note:
在 rebase 的过程中,也许会出现冲突 conflict。在这种情况,git 会停止 rebase 并会让你去解决冲突。在解决完冲突后,用 git add 命令去更新这些内容。
git rebase --continue
在任何时候,我们都可以用 –abort 参数来终止 rebase 的行动,并且分支会回到 rebase 开始前的状态。
git rebase —abort
总结:
- 当我们在一个过时的分支上面开发时,执行
git rebase
来同步master
分支的最新改动 - 相比较
merge
来说会减少分支合并的记录
注意:
- 不要在公共分支使用
rebase
,rebase会改变commit历史,其他依赖此分支的人可能会丢失记录。
总结
通过 rebase 策略执行 git pull Git 在最近的某个版本起,直接运行 git pull 会有如下提示消息:
warning: 不建议在没有为偏离分支指定合并策略时执行 pull 操作。 您可以在执行下一次 pull 操作之前执行下面一条命令来抑制本消息:
git config pull.rebase false # 合并(缺省策略)
git config pull.rebase true # 变基
git config pull.ff only # 仅快进
原来 git pull 时也可以通过 rebase 来进行合并,这是因为 git pull 实际上等于 git fetch + git merge ,我们可以修改git配置直接使用 git rebase 替换 git merge来合并 fetch 取得的变更,作用同样是避免额外的 merge 提交以保持线性的提交历史。
具体的使用方式有多种:
- 每次执行 pull 命令时添加特定选项:
git pull --rebase
。 - 为当前仓库设定配置项:
git config pull.rebase true
,在 git config 后添加 –global 选项可以使该配置项对所有仓库生效。
结论
git-rebase 存在的价值是:对一个分支做「变基」操作。
- 当我们某一个分支有过多的 commit 记录需要整合,执行 rebase 来合并提交。
- 当我们在一个过时的分支上面开发的时候,执行 rebase 以此同步 master 分支最新变动;
- 假如我们要启动一个放置了很久的并行工作,现在有时间来继续这件事情,很显然这个分支已经落后了。这时候需要在最新的基准上面开始工作,所以 rebase 是最合适的选择。
<全文完>