当 repo 离线时,我需要对一个不必要的大存储库进行类似的重写。我采用的方法是使用 @james-foucar 和 @pfalcon 在 this answer 中介绍的 GIT_SEQUENCE_EDITOR 尝试自动“交互式”变基。
为了使其正常工作,我发现最好先从正在重写的历史记录部分中删除合并。对于我自己的情况,这是使用大量 git rebase --onto 完成的,这在 StackOverflow 上的其他问题中得到了充分介绍。
我创建了一个small script generate-similiar-commit-squashes.sh 来生成pick 和squash 命令,以便压缩连续的类似提交。我使用 author-date-and-shortlog 来匹配类似的提交,但你只需要 author (我的要点有一个关于如何使它只匹配作者的评论)。
$ generate-similiar-commit-squashes.sh > /tmp/git-rebase-todo-list
输出看起来像
...
pick aaff1c556004539a54a7a33ce2fb859af0c4238c foo@example.com-2015-01-01-Update-head.html
squash aa190ea2323ece42f1cd212041bf61b94d751d5c foo@example.com-2015-01-01-Update-head.html
pick aab8c98981a8d824d2bc0d5278d59bc1a22cc7b0 foo2@example.com-2015-01-28-Update-_config.yml
存储库也充满了具有相同样式的“更新 xyz”提交消息的自我恢复。当被压扁时,它们会导致空提交。
我正在合并的提交具有相同的提交消息。 git rebase -i 提供了一个修改后的提交消息,其中附加了所有压缩的提交消息,这将是重复的。为了解决这个问题,我使用了来自this answer 的一个小型perl 脚本来删除git rebase 提供的提交消息中的重复行。最好放在文件中,因为它会在 shell 变量中使用。
$ echo 'print if ! $x{$_}++' > /tmp/strip-seen-lines.pl
现在进入最后一步:
$ GIT_EDITOR='perl -i -n -f /tmp/strip-seen-lines.pl ' \
GIT_SEQUENCE_EDITOR='cat /tmp/git-rebase-todo-list >' \
git rebase --keep-empty -i $(git rev-list --max-parents=0 HEAD)
尽管使用了--keep-empty,git 在此过程中多次抱怨空提交。它会以不完整的git rebase 将我转储到控制台。要跳过空提交和恢复处理,需要以下两个命令(在我的情况下相当频繁)。
$ git reset HEAD^
$ GIT_EDITOR='perl -i -n -f /tmp/strip-seen-lines.pl ' git rebase --continue
尽管有--keep-empty,我还是在最终的 git 历史记录中发现了我的had no empty commits,所以上面的重置已将它们全部删除。我认为我的 git 版本 2.14.1 有问题。在一台蹩脚的笔记本电脑上处理大约 10000 个这样的提交只需要 10 多分钟。