从git存储库中删除文件(历史记录)


77

(已解决,请参阅问题正文的底部。)
很长时间以来,我一直在寻找以下内容:

几乎相同的方法,但是它们都将对象保留在打包文件中...卡住了。
我试过的

git filter-branch --index-filter 'git rm --cached --ignore-unmatch file_name'
rm -Rf .git/refs/original
rm -Rf .git/logs/
git gc

包中仍然有文件,这就是我所知道的:

git verify-pack -v .git/objects/pack/pack-3f8c0...bb.idx | sort -k 3 -n | tail -3

还有这个:

git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch file_name" HEAD
rm -rf .git/refs/original/ && git reflog expire --all &&  git gc --aggressive --prune

相同...

尝试过git clone技巧,它删除了一些文件(〜3000个),但最大的文件仍然存在...

我的存储库中有一些较大的旧文件,大约200M,我真的不希望它们在那里...而且我也不想将存储库重置为0 :(

解决方案:这是摆脱文件的最短方法:

  1. 检查.git / packed-refs-我的问题是我在refs/remotes/origin/master远程存储库中有一行,请将其删除,否则git不会删除那些文件
  2. (可选) git verify-pack -v .git/objects/pack/#{pack-name}.idx | sort -k 3 -n | tail -5 -检查最大的文件
  3. (可选) git rev-list --objects --all | grep a0d770a97ff0fac0be1d777b32cc67fe69eb9a98 -检查哪些文件
  4. git filter-branch --index-filter 'git rm --cached --ignore-unmatch file_names' -从所有版本中删除文件
  5. rm -rf .git/refs/original/ -删除git的备份
  6. git reflog expire --all --expire='0 days' -使所有松散的物体失效
  7. git fsck --full --unreachable -检查是否有松散的物体
  8. git repack -A -d -重新包装
  9. git prune -最终删除那些对象


zneak-我的问题在标题中。gbacon-尝试过这些,文件仍然保留在打包文件中……
Boris Churzin 2010年

如果您查看重复文章中引用的文章,它显示了在删除有问题的文件之后如何压缩对象存储。
凯尔·巴特

1
这是一个救命稻草。提示:始终向.gitignore添加潜在的巨大* .log文件。此后从800mb的存储库转到6mb。
JackCA 2010年

1
第2步和第3步合为一体 for i in `git verify-pack -v .git/objects/pack/#{pack-name}.idx | sort -k 3 -n | tail -5` ; do git rev-list --objects --all | grep $(echo $i | sed 's/ .*//g') ; done
geermc4

Answers:


64

我不能肯定地说不能访问您的存储库数据,但是我相信可能有一个或多个打包的ref仍然引用您运行前的旧提交git filter-branch。这可以解释为什么git fsck --full --unreachable即使您的reflog已过期并删除了原始(未打包的)ref,也不会将大blob称为不可访问的对象。

这是我会怎么做(后git filter-branchgit gc已经完成):

1)确保原始裁判不见了:

rm -rf .git/refs/original

2)使所有reflog条目过期:

git reflog expire --all --expire='0 days'

3)检查旧包装的裁判

这可能很棘手,具体取决于您有多少个打包的引用。我不知道可以自动执行此操作的任何Git命令,因此我认为您必须手动执行此操作。备份.git/packed-refs。现在编辑.git/packed-refs。检查是否有旧的裁判(尤其是查看是否包装了的任何裁判.git/refs/original)。如果发现不需要的旧物件,请将其删除(删除该引用的行)。

完成清理packed-refs文件后,请查看是否git fsck注意到无法访问的对象:

git fsck --full --unreachable

如果可行,git fsck现在报告您的大Blob无法访问,则可以继续执行下一步。

4)重新打包打包的档案

git repack -A -d

这将确保无法到达的对象被解压并保持解压。

5)修剪松散(无法到达)的物体

git prune

那应该做到的。Git确实应该有更好的方法来管理打包的引用。也许有一个我不知道的更好的方法。在没有更好的方法的情况下,手动编辑packed-refs文件可能是唯一的方法。


1
是的!我爱你 !问题出在packed-refs文件中,从我将其备份到某些服务器上时就出现了refs / remotes / origin / master。(使用完整解决方案更新问题正文)
Boris Churzin'2

15

我建议使用BFG Repo-Cleaner,这是一种更简单,更快速的替代方法,git-filter-branch专门用于重写Git历史记录中的文件。一种使您的生活更轻松的方法是,它实际上默认情况下处理所有引用(所有标记,分支,诸如refs / remotes / origin / master之类的东西),但它的速度也快10到50倍。

您应该在此处仔细执行以下步骤:http : //rtyley.github.com/bfg-repo-cleaner/#usage-但核心部分是这样:下载BFG的jar(需要Java 6或更高版本)并运行此命令:

$ java -jar bfg.jar  --delete-files file_name  my-repo.git

任何命名的文件file_name(不在您的最新提交中)将被从存储库的历史记录中完全删除。然后,您可以git gc用来清除无效数据:

$ git gc --prune=now --aggressive

BFG通常比使用起来简单得多git-filter-branch-这些选项是针对以下两个常见用例量身定制的:

  • 删除疯狂的大文件
  • 删除密码,凭据和其他私人数据

完全公开:我是BFG Repo-Cleaner的作者。


推送后是否还会从远程存储库中清除私有数据?
Thomas Lauria

@ThomasLauria是的,将相同的已清理引用在推送时推送到远程存储库-rtyley.github.io/bfg-repo-cleaner/#usage上的说明应将其覆盖。如果您可以控制远程仓库,也可以在推送以确保可以立即从中删除死对象后,对其执行“ git gc --prune = now --aggressive”。
罗伯托·泰利

@RobertoTyley这可能会导致两个提交在历史记录中彼此之后出现并且具有相同的树(如果其中一个提交仅添加了已删除的文件)。您是否知道从提交历史记录中删除此类提交的简便方法,因为它们似乎是人为的?
user44400 '18

@RobertoTyley我认为这涉及另一个问题。我描述的情况仅涉及一个存储库。但这git filter-branch --prune-empty似乎是我的问题的解决方案(尽管使用其他工具,但请让我知道BFG Repo-Cleaner是否可以做到这一点)。
user44400 '18

6

我发现这对于删除整个文件夹很有帮助,因为上述内容并没有真正帮助我:https : //help.github.com/articles/remove-sensitive-data

我用了:

git filter-branch -f --force \
--index-filter 'git rm -rf --cached --ignore-unmatch folder/sub-folder' \
--prune-empty --tag-name-filter cat -- --all

rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now

5

我试图摆脱历史上的一个大文件,上面的答案一直有效。关键是:如果您有标签,它们将不起作用。如果包含一个大文件的提交可以从一个标签到达,那么您就需要调整filter-branches命令:

git filter-branch --tag-name-filter cat \
--index-filter 'git rm --cached --ignore-unmatch huge_file_name' -- \
--all --tags

2

请参阅:如何从git的历史记录中删除敏感文件

如果文件在版本中不存在,则以上操作将失败。在这种情况下,'-ignore-unmatch'开关将解决此问题:

git filter-branch -f --index-filter 'git rm --cached --ignore-unmatch <filename>' HEAD

然后,要使所有松散的物体脱离记忆库,请执行以下操作:

git gc --prune='0 days ago'

是的,尝试了这个,但文件包中仍然有文件,并且大小没有太大变化……
Boris Churzin 2010年

我刚刚制作了一个git沙箱并尝试了它。这里也不行。让我们看看我能弄清楚什么。
韦恩·康拉德

答案中的一个?:)与我发布的内容相同,它仍然将文件保留在包中……尝试使用git沙箱,执行git gc以便将文件打包,然后运行此文件……
Boris Churzin 2010年

哦,松散的物体?看上面。我倾向于让它们在两周内被垃圾收集(gc的默认设置);杀死所有松散的物体就像清空垃圾桶一样-我失去了找回不小心删除的任何东西的机会。
韦恩·康拉德

:)也尝试过此方法...删除了一些文件,但是最大的文件仍然存在...
Boris Churzin 2010年

2

由于git repo大小过大,您有各种原因git gc,因为它不能删除所有松散的对象

我在“减小git存储库大小”中详细说明了这些原因

但是,要测试这种情况的一个技巧是克隆“清理过的” Git存储库,看看克隆是否具有适当的大小。

(““清理过的”仓库”是您确实应用了 filter-branch,然后是gcprune


是的,已经对其进行了测试,现在又对其进行了测试,它使存储库减少了2k :),文件仍然存在...
Boris Churzin 2010年

奇怪的是git count-objects -v -> count: 0, size: 0, in-pack: 10021, packs: 1, size-pack: 244547, prune-packable: 0, garbage: 0git clone test1 test2 -> Checking out files: 100% (8509/8509), done
鲍里斯·库尔钦


0

我遇到了同样的问题,我在github上找到了一个很棒的教程,该教程逐步解释了如何清除意外提交的文件。

以下是纸杯蛋糕建议的程序概述。

如果您有一个file_to_remove要从历史记录中删除的文件:

cd path_to_parent_dir

git filter-branch --force --index-filter \
  'git rm --cached --ignore-unmatch file_to_remove' \
  --prune-empty --tag-name-filter cat -- --all

1
强烈建议不要在Stack Overflow上使用仅链接的答案,因为如果将来链接断开,答案将变得毫无用处。请考虑汇总答案中链接中包含的相关信息。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.