跳到主要内容

合并(清理)提交历史

下面是一个 git log 示例,一共有两个分支:main 和 squash-multi-commit。

其中 squash-multi-commit 是基于 main 分支(794d76af444cbadd7b5e553a4d3aadf2512bafd6)叉出来,之后又推送了 4 个 commit:

我觉得 squash-multi-commit 分支的 commit message 写的是一塌糊涂,不够清晰。为了让 commit 信息更友好,我现在想重新修正(合并/清理)这些提交历史(比如将某些琐碎的提交“压缩/合并”成 1 个提交),该怎么解决呢?这里就需要用到 git rebase -i 了。

从基准分支开始修正提交历史

以上面的 log 为例,当前分支只有一个基准分支: main(commit=794d76af444cbadd7b5e553a4d3aadf2512bafd6)。

如果我想从该基准分支开始修正提交历史,就可以使用下面命令:

git rebase -i main

因为当前分支只有 4 次提交记录,所以实际会修正 4 次提交历史。

修正最近 N 次提交历史

另一种是修正最近 N 次提交,这种方式就比较友好,适合少量 commit 的合并操作。以 log 为例,该新分支只有 4 次提交,我想要修正最近 4 次提交:

git rebase -i HEAD~4
信息

因为新分支只有 4 次提交,所以 -i HEAD~4-i main 是等效的。

实操

现在开始实践,我需要将第一次提交合并给第二次,将第三次提交合并给第四次:

执行 rebase 命令,之后会进入一个编辑窗口,只需要将第二次、第四次提交的 pick 修改为 squash 即可:

squash 解释

squash 的作用将前一次 pick 或 squash 合并过来。比如有如下几个 commit:

pick commit_1
pick commit_2
pick commit_3
pick commit_4
pick commit_5

如果我修改为:

pick commit_1
pick commit_2
squash commit_3
squash commit_4
pick commit_5

就表示将 commit_2 合并给 commit_3,commit_3 继续合并给 commit_4。

保存并关闭编辑器。Git 会再次弹出一个编辑器,让你为前一步合并的操作创建新的提交信息。因为做了两次合并,所以会依次弹出两次,下面是第一次合并弹窗:

重写第一次合并的 commit message,之后保存即可。

接着会进入第二次合并弹窗,一样重写 commit message:

保存之后再看一下 log:

这样就实现了 commit 合并/清理,之后需要强制推送到远程:

git push origin squash-multi-commit --force-with-lease
# 或(不推荐)
git push origin squash-multi-commit --force
合并任意 commit

前面已经做 squash 的作用做了说明:squash 会将前面的 pick 和 squash 全部合并过来。并不是说只能按照顺序合并,所以你可以修正 git log 中的任意部分 commit,比如修正前三次合并,保留最后一次合并:

保存之后重写 commit message:

再看下 git log:

最后执行强制提交即可:

git push origin squash-multi-commit --force-with-lease

现在就可以放飞自我了,随意写一下 commit 即可,反正之后能重新修正~

JetBrains IDE

如果直接使用图形化 IDE,操作起来就简单很多。以 RustRover 为例,只需要按顺序选中要合并的 commit,右键菜单选择 Squash Commits... 即可:

在弹窗中重写 commit message:

看下 log:

最后执行下强制推送就好了