Git代码合并之使用 rebase
整理提交历史
Git 中整合来自不同分支的修改有两种方式:git merge
和 git rebase
。本文主要介绍 rebase
的3种使用场景:
- 场景1: 使用
rebase
合并分支--整合分叉的提交历史 -
使用
交互式的 rebase
- 场景2: 压缩提交历史
- 场景3: 修改多个提交信息
1 使用 rebase 合并分支
1.1 场景描述
我们在 feature
分支开发完新的功能后,通常会通过 merge
操作将代码合并到 master
分支,这样会产生一条分叉。这时可以通过变基使得提交历史更加整洁,看上去就像是串行的一样,提交历史是一条直线没有分叉。
1.2 操作命令
首先在自己的 feature
分支里进行开发,当开发完成时你需要先将你的代码变基到 master
上,然后再向 master
分支提交修改。 这样的话,该项目的维护者就不再需要进行整合工作,只需要快进合并便可。具体操作如下:
# 1 变基到 master
git checkout feature
git rebase master
# 2 回到 master 分支,进行一次快进合并。
git checkout master
git merge feature
1.3 原理图解
假设在你的项目上 master
分支的提交为 C0、C1、C2、C3
,基于 master
的 C2
节点拉出了一个 feature
分支,并产生了新的提交C4
,如下图:
整个变基操作的过程如下图所示,首先找到这两个分支(即当前分支 feature
、变基操作的目标基底分支 master
) 的最近共同祖先 C2
,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件, 然后将当前分支(feature
)指向目标基底 C3
, 最后以此将之前另存为临时文件的修改依序应用,此时 feature
指向 C4'
,如下图:
最后回到 master
分支,进行一次快进合并,完成后 feature
和 master
分支均指向 C4'
,如下图:
至此合并分支操作完成,master
的提交历史是一条干净的、没有分叉的直线。
2 使用 交互式的 rebase
通过给 git rebase
增加 -i
选项来交互式地运行变基。 一般被用于将 feature
分支并入 master
分支之前,清理混乱的提交历史。
2.1 压缩提交历史
2.1.1 场景描述
觉得 commit
太小太散,将多个 commit
压缩成一个单独的提交。
2.1.2 操作命令
假设将 feature
分支当前最近的3个提交变为一个提交,操作如下:
# 1.执行交互式 rebase
git rebase -i HEAD~3
# 或使用如下命令
git rebase -i dbcc8dd # dbcc8dd 为与 HEAD~3 对应的 commitid
# 2.进入编辑器,将16.md-2、16.md-3 的 pick 改为 squash,代表想要把它们跟上一个 commit(16.md-1)合并
pick fe08362 feat: update 16.md-1
squash 72a7fae feat: update 16.md-2
squash f606aec feat: update 16.md-3
# 3.第2步保存并退出编辑器后看到如下画面
feat: add file 16.md # 删除原本的 commit message, 改为自己想要的提交信息
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Wed Aug 3 20:00:18 2022 +0800
#
# interactive rebase in progress; onto dbcc8dd
# Last commands done (3 commands done):
# squash 72a7fae feat: update 16.md-2
# squash f606aec feat: update 16.md-3
# No commands remaining.
# You are currently rebasing branch 'master' on 'dbcc8dd'.
# 4.操作完成,验证结果
git log
注意上述第2步中的反序显示。 交互式变基给你一个它将会运行的脚本。 它将会从你在命令行中指定的提交(HEAD~3
)开始,从上到下的依次重演每一个提交引入的修改。 它将最旧的而不是最新的列在上面,因为那会是第一个将要重演的。
2.2 修改多个提交信息
2.2.1 场景描述
修改在提交历史中的提交信息。
2.2.2 操作命令
例如要修改 feature
分支最近三次的提交中的任意一个提交信息。
# 1.执行交互式 rebase
git rebase -i HEAD~3
# 2.进入编辑器,将要被修改信息的提交由 pick 改为 reword,代表要修改16.md-1的提交信息
reword fe08362 feat: update 16.md-1
pick 72a7fae feat: update 16.md-2
pick f606aec feat: update 16.md-3
# 3.第2步保存并退出编辑器后看到如下画面
修改后的提交信息feat: update 16.md-1 # 删除原本的 commit message, 改为自己想要的提交信息
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Thu Aug 18 16:34:55 2022 +0800
#
# interactive rebase in progress; onto dbcc8dd
#...
# 4.操作完成,验证修改结果
git log
2.3 其它的一些操作
除了2.1、2.2的使用场景外,交互式的 rebase
还可以 调整commit顺序、删除 commit 等,操作过程与2.1、2.2大同小异,具体可参考如下指令:
# 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')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
3 注意事项
使用 rebase 得遵守一条准则:
如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。
换句话说,因为 rebase
会变更历史记录,所以最好是在 push
之前就做好 rebase
,不然就是确保要这个 branch
只有你自己在修改,否则你也 rebase
、他也 rebase
,最后只会把历史记录搞得一团糟。
4 参考资料
- Git 官方文档
- 送 PR 前,使用 Git rebase 來整理你的 commit 吧!
GIT宝典
网页查找不方便?想查看更多相关文章?微信扫码进入--👉GIT宝典--,一键查找,解锁最及时的Git解决方案~