首页 > 解决方案 > 如何从 git 存储库中完全删除文件的特​​定版本?

问题描述

我正在从事几个游戏开发项目,这些项目同时涉及对代码和大型二进制文件的大量更改。为简单起见,假设我有一个 git 存储库,其中包含 2 个文件(一个文本文件和一个大型二进制 blob),它们都在多个提交中更新:

commit dddd: "Release day is finally here!" <tag: v1.0>
   changed hello.md
   changed image.png (lfs) <==== keeper!

commit cccc: "Ok, that's a bit better."
   changed hello.md
   changed image.png (lfs)

commit bbbb: "Updated my project."
   changed hello.md
   changed image.png (lfs)

commit aaaa: "Initial commit!" 
   added hello.md
   added image.png (lfs) <==== keeper!

每次提交我都对我的两个文件进行了某种更改。

但是,回想起来,我已经决定要删除一些 lfs 文件以减小存储库的整体大小,并且只有一半的版本image.png不同,值得保留。(请记住,它并不总是像不提交中间版本那么简单,因为我们并不总是事后才知道“关键”版本是什么。)

那么,我可以完全删除image.png包含在我的存储库中bbbbcccc从我的存储库中删除的版本以减少它的整体存储空间吗?如何?我一直在研究git gcgit filter-repo但我一直无法实现我想做的事情。我在正确的轨道上吗?是否有任何其他策略可以用来优化我的存储库的大小或以其他方式缓解这种情况?

标签: gitgithubgitlabgit-lfsgit-filter-repo

解决方案


感谢您提出有趣的问题!我终于过来戳了一下 Git。这将是我的(未经测试的)想法如何处理这个问题。我使用git.git存储库进行实验。它不包含 LFS 数据,但希望它能让您朝着正确的方向开始 :)

git rev-list --oneline --objects --in-commit-order HEAD -- path/to/file

输出提交、树和 blob 的列表;例如:

cf1b7869f0 Commit message here
b299d53c5f9a2a8be72f819e26f49421ed6c45bc 
52c10caf3523b877ef7fa77f7af3c64de3055b4f path/to/file

结合grep,这使您可以提取相关文件的所有 blob id(哈希):

git rev-list --oneline --objects --in-commit-order HEAD -- path/to/file \
  | grep 'path/to/file$'

现在,您必须确定要保留/删除哪些 blob。也许一些聪明sed的魔法可以帮助你,或者提供正确的提交范围到rev-list. 因此,与其HEAD列出所有可访问的提交,不如只做v1..v3或类似的事情(--since并且--until可能也有帮助)。在最坏的情况下,您必须手动执行此操作。

现在,请确保备份您的存储库!(不能强调这一点)。最好在单独的目录中创建一个新的克隆。

git-filter-repo似乎带有一个基于内容的过滤器,它提供了--strip-blobs-with-ids选项。

将要删除的所有 blob id(即标识文件的特定版本的哈希)逐行存储到文本文件中。然后将此文件提供给filter-repo. 如果是这样,手册中的状态是什么,你应该只留下你想要保留的 blob。

下一步,您可能希望从 LFS 本身中删除文件,而不仅仅是提交中的引用:如何删除 git-lfs 跟踪的文件并释放存储配额?

我希望这会有所帮助。让我知道它是如何 - 以及是否 - 它成功了。


推荐阅读