在一个旧提交中,添加了一个大文件。在几次提交后,它已被删除,但是它仍保留在历史记录中,因此我尝试通过以下命令从历史记录中删除该文件:
git filter-branch -f --index-filter "git rm -rf --cached --ignore-unmatch src/main/resources/embed/linux/mongodb-linux-x86_64-3.2.0.tgz" --pru-tag-name-filter cat -- --all
此命令的结果如下:
Rewrite 9e96a248322ba6e85efde1e41498db0d41c1ee79 (3026/5151) (13917 seconds passed, remaining 9773 predicted) rm 'src/main/resources/embed/lib-linux-x86_64-3.2.0.tgz'
Rewrite 070cbe84ad8e1bc8f1ccec5294b600218d714e30 (4123/5151) (18963 seconds passed, remaining 4728 predicted) rm 'src/main/resources/embed/lib-linux-x86_64-3.2.0.tgz'
Rewrite 1f5604b332d6d48169fa398b60fc5ac42124d63d (5151/5151) (24005 seconds passed, remaining 0 predicted)
Ref 'refs/heads/master' was rewritten
Ref 'refs/remotes/origin/master' was rewritten
....
据我从输出中了解到,该文件已从提交9e96a248322ba6e85efde1e41498db0d41c1ee79
中删除,因此我进行了以下检查:
git checkout 9e96a248322ba6e85efde1e41498db0d41c1ee79
ls src/main/resources/embed/linux/
结果为mongodb-linux-x86_64-3.2.0.tgz
。因此该文件仍存在于历史记录中。我做错了什么?如何依法删除它?
答案 0 :(得分:3)
据我从输出中了解,该文件已从提交9e96a248322ba6e85efde1e41498db0d41c1ee79中删除
git filter-branch
删除了文件,并创建了新的提交。新提交的哈希值不同,因为其内容不同。在运行git gc
之前,带有哈希9e96a248322ba6e85efde1e41498db0d41c1ee79的原始提交仍然存在。请注意,如果您运行git log | grep 9e96a
,该哈希将不会出现,因为相应的提交不再在您的历史记录中。
要更详细地了解这一点,建议您阅读有关如何创建提交的内容。 This blog article很好地解释了这一点。 this chapter in Pro Git详细介绍了git的内部构造以及如何创建提交。
答案 1 :(得分:1)
代码学徒的答案基本上是正确的,但需要详细说明:
不可能修改提交。 filter-branch
(或任何历史记录重写机制)的作用是创建新的提交,这些提交与现有的提交“就像”,但需要您进行更改。 (例如,您的新提交中没有较大的文件,但否则它们看起来像您的旧提交)
这有两个重要的后果。
首先,在重写分支的历史记录之后,拥有该分支副本的其他任何人都需要执行一些恢复步骤。您可以在git rebase
文档中了解这些内容(在“从上游资源恢复中”下)。如果他们执行错误的操作来恢复,它将撤消历史记录的重写(将大文件放回历史记录中),因此在重写历史记录时您需要所有人的配合。因此,有时重写历史记录是不切实际的。对于大型重写(尤其是那些影响复杂历史记录,多个分支等的重写),通常最好安排一个过渡,每个人都丢弃其现有克隆,然后从重写的repo中重新克隆。
(这是一个细微的差别,当您重写历史记录时,依赖提交ID的任何工具或文档也都被破坏了。)
第二,这意味着进行重写不会立即从存储库中删除旧提交。这既很重要,既可以尝试从二进制膨胀中恢复空间,也可以尝试清理回购历史记录中的敏感信息泄漏。 (在后一种情况下,几乎总是有必要将信息视为已泄露。)
运行git gc
可能是解决方案的一部分,但这还不够。这是因为在您重写之后,您的存储库仍然具有对旧提交的引用,因此gc
不会将它们视为垃圾。至少,您需要清除reflog。可能还有其他问题。
有很多方法可以做到这一点,但是通常我只是通过从重写的仓库中创建一个新的克隆来回避这个问题。该克隆不应该费心复制旧的/已删除的历史记录。 (要明确-我不认为有任何书面要求说这样的克隆不能复制已失效的历史记录,但是根据我的经验-至少在使用标准git实现时-它不会然后,您可以销毁原始存储库,并从经过完全消毒的克隆中重新创建它。