Git如何在分支中间压缩(commits squash)提交记录

49

我希望在分支的中间将几个提交合并在一起,而不修改之前和之后的提交记录。

我有:

A -- B -- C -- D -- E -- F -- G
|                             |
master                        dev
origin/master

我想把那个压缩进去

A -- H -- E -- F -- G
|                   |
master              dev
origin/master

其中H等同于B -- C -- D。 我想能够指定H的提交信息。 A是最后一个已推送的提交,因此在不搞乱服务器的情况下可以重写之后的所有提交。这个想法是在我快进master之前清理历史记录。

我应该如何做到这一点?

PS:请注意,在我的情况下,我实际上有更多的提交要压缩在中间,但如果我可以用3个提交做到这一点,我就应该能够用更多的提交做到这一点。

PPS:此外,如果可能的话,我希望EFG保持不变(主要涉及提交日期)。


当提交“C”是合并分支时,是否有简单的解决方案? - Navid_pdp11
1个回答

76

您可以执行交互式 rebase 并手动选择要压缩的提交记录。 这将重写您的 dev 分支历史记录,但由于您尚未推送这些提交记录,因此除了在您自己的计算机上可能发生的情况外,不应该会有任何负面影响。

从以下内容开始:

git checkout dev
git rebase -i HEAD~6

这将会弹出一个窗口,其中将显示以下7个提交的列表,从您的dev分支的HEAD向后退了6步:

pick 07c5abd message for commit A
pick dl398cn message for commit B
pick 93nmcdu message for commit C
pick lst28e4 message for commit D
pick 398nmol message for commit E
pick 9kml38d message for commit F
pick 02jmdmp message for commit G

展示的第一个提交(上面的A)是最老的,而最后一个则是最近的。默认情况下,每个提交选项都是pick。如果现在完成rebase,那么您只会保留每个提交,这实际上就是一个no-op操作。但是,由于您想压缩某些中间提交,因此请编辑并将列表更改为如下内容:

pick 07c5abd message for commit A
pick dl398cn new commit message for "H" goes here
squash 93nmcdu message for commit C
squash lst28e4 message for commit D
pick 398nmol message for commit E
pick 9kml38d message for commit F
pick 02jmdmp message for commit G

注意上面发生的事情。通过输入 squash 命令,您告诉Git将该提交合并到其上面的提交中,这是在它之前立即出现的提交之前的提交。因此,这意味着将提交D向后压缩到提交C中,然后将C压缩到B中,让您只有一个提交记录:BCD。其他提交保持不变。

保存文件(在Windows上使用Git Bash键入: wq ),重定基完成。请注意,可能会像预期的那样遇到合并冲突,但解决它们没有什么特别之处,您可以像进行常规重定基或合并一样继续。

如果在重定基后检查分支,您会注意到EFG提交现在具有新的哈希、日期等信息。这是因为这些提交已被新提交所取代。原因是您重写了历史记录,因此提交记录通常不能与以前完全相同。


3
非常感谢,运行得很顺利!我没想到会这么简单。不过,有没有一种方法可以在不重写最后三个提交记录的情况下完成相同的操作?我注意到Git创建了3个新的提交记录(提交日期为当前日期)。 - deadbeef
1
@deadbeef 如果你仔细思考一下你的问题,你会意识到为什么答案必须是否定的。由于你重写了在 EFG 提交之前发生的事情,这三个提交本身已经被重写并且实际上是_新的_提交。 - Tim Biegeleisen
我思考了一段时间,意识到这可能是不可能的 :-). 然而,我发现 git rebase --committer-date-is-author-date 可以基本实现我的需求(保留原始提交日期)。 - deadbeef
1
另外,正如我所提到的,我有很多超过3个提交需要压缩,因此我使用了git rebase -i <commit_sha>而不是你提到的那种方法,这比计算所有这些提交要容易得多。 - deadbeef
1
@deadbeef 我不知道有关保留提交者日期选项的事情,但是提交的哈希值确实已经改变了。它们是全新的有效提交。你很明智地没有对任何已发布的提交进行这样的操作。 - Tim Biegeleisen
2
在谷歌上找到了这个方法。我在第一次变基时尝试了它,但没有成功。然而,之后我运行了它,并且它改变了所有在commit_sha之后的提交记录。所以在我的情况下,执行git rebase --committer-date-is-author-date sha_of_H就达到了我想要的效果。 - deadbeef

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接