从git历史记录中删除垃圾邮件

7
我“继承”了一个脏的Git存储库,其中包含大约5k个有效提交和约50k个垃圾邮件提交(这是曾经是可写入世界维基的编辑历史记录)。我们正在迁移格式,所以现在是重写历史的好时机。我不想完全丢失历史记录,但无论是按提交体积还是按原始内容体积,垃圾邮件都是压倒性的。旧的回滚到最后一个好的提交的整理技术留下了很多垃圾。
我可以使用git log -S 和一些正则表达式工作来找到大约80%的坏提交,没有太多麻烦。大部分垃圾邮件内容都很明显。问题是我不确定该如何处理我想要删除的大量提交列表。
请注意,我非常熟悉git并每小时使用git rebase(如果不是因为 git revise 已经承担了很多负载,那就会是每分钟),而且我知道如何手动完成此操作,但我需要自动化解决方案。通常我会使用git filter-branch,但我不确定使用哪个工具来检查当前差异。
我考虑编写一个脚本来操作rebase脚本,但我认为这会让我遇到错误的情况。我可能可以同时捕获和删除原始污损和回滚,但当我错过其中一个方程的一侧时会发生什么?当其中一个不干净的提交无法重新设置时,我希望成功而不是失败的其余可能匹配。
请注意,我不想根据我的匹配操作文件的内容或添加/删除文件,我想检查补丁的内容,并基于此决定选择还是丢弃。
最好使用哪个git工具?

1
“Spam commits”是什么意思?我猜“回滚到上一个好的提交”并不意味着分支被重置,而是在事后添加了还原提交,使得损坏的提交和重置成为线性历史中的单独提交。如果是这种情况,您可以尝试搜索具有相同树哈希值的提交,并忽略这些提交之间的所有历史记录。 - cmaster - reinstate monica
1
这个 Git 仓库是公开的吗?能够查看实际的历史记录可能有助于我们制定答案... - larsks
1
@cmaster 不幸的是,这些“还原”是通过手动从维基页面中删除垃圾并保存(因此产生新的提交)来完成的。结果类似于还原提交,但几乎从不相同。这些还原通常是手动完成的,而垃圾邮件则是自动发生的,因此会有10个小的垃圾邮件提交(例如每个提交添加10个链接),然后是一个大的回滚提交(删除100个链接)。 - Caleb
我想知道是否有任何答案能够帮助解决引发这个问题的难题。 - knittl
@knittl 不完全是这样。虽然时间已经过去了很久,但如果我的记忆没有出错,那么两个答案都没有真正解决我的问题,因为它们都对我的真正问题进行了概括:验证我的候选提交列表并在一个提交无法干净地应用时处理解决方案。我想我最终用一个脏脚本解决了这个问题,该脚本尝试在每一步后重新基于接下来的N个提交,并回溯尝试其他解决方案(不删除提交,删除更多提交)以找到不会导致后续重新基础错误的组合。我还记得这是一个长时间运行的操作,我必须看着它工作了一个星期或者更长时间。 - Caleb
显示剩余6条评论
2个回答

1
一种可能的方法是使用Git的嫁接文件或git replace。首先,确定所有“好”的提交,即非垃圾提交,还包括“清理/撤消”提交。例如,通过按提交者电子邮件或类似机制过滤您的历史记录(您提到了pickaxe/-S)。
一旦您获得了“好”提交的列表,使用paste命令进行简单转换,即可获取嫁接文件的内容,如下所示:
commit parent1 parent2 parent3...

假设你的好的提交记录如下(最新的提交在顶部):

b3fb1155cd5352da674d93ce4b0a1567674f6d27
b460ef0aea564e587e5866107c0fc52adf552ca1
9f803dd18c89e13f47170e1ace1d0abb992cfeee

然后您需要在graftsfile中添加以下内容:
b3fb1155cd5352da674d93ce4b0a1567674f6d27 b460ef0aea564e587e5866107c0fc52adf552ca1
b460ef0aea564e587e5866107c0fc52adf552ca1 9f803dd18c89e13f47170e1ace1d0abb992cfeee

这可以通过以下方式相对容易地获得:

sed 1d commits | paste commits - | sed '$d'

将此文件移动到.git/info/grafts,并使用git loggitk验证结果历史记录。 如果您对结果满意,请使用git filter-branch重写历史记录并保留您的接枝文件。 然后可以删除.git/info/grafts
请参阅https://dev59.com/ZW865IYBdhLWcg3wceNU#3811217以了解如何使用非弃用的替换机制。 在这种情况下,使用接枝文件更容易解释(它仍然适用于当前的Git版本,为什么不使用呢? :))

0
一个可能的解决方案,涉及到git rebase
你提到你能够确定要删除哪些提交,而rebase期望一个要挑选(或者删除)的提交列表。但是你不能简单地删除,因为那么你的“还原”提交也需要被删除(它们可能包含无关的更改?)。
考虑以下rebase脚本:
pick A normal edit
pick B spam
pick C spam
pick D spam
pick E spam
pick F revert spam
pick G normal edit

我猜你想要“删除”所有被认为是垃圾并进行回滚的更改。你可以通过以下rebase脚本实现:

pick A normal edit
fixup B spam
fixup C spam
fixup D spam
fixup E spam
fixup F revert spam
pick G normal edit

如果您有要“删除”的提交列表(包括“还原”提交),则应该能够通过sed或类似工具将所有匹配行替换为fixup而不是pick
如果您可以通过提交主题识别出错误提交,那么这将更加容易。

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