从 git 存储库中删除文件(历史记录)
Posted
技术标签:
【中文标题】从 git 存储库中删除文件(历史记录)【英文标题】:Remove file from git repository (history) 【发布时间】:2011-01-10 23:56:11 【问题描述】:(已解决,见问题正文底部) 找这个找了很久,到现在有的是:
http://dound.com/2009/04/git-forever-remove-files-or-folders-from-history/ 和 http://progit.org/book/ch9-7.html几乎相同的方法,但它们都将对象留在包文件中......卡住了。 我尝试了什么:
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 :(
解决方案: 这是删除文件的最短方法:
-
检查 .git/packed-refs - 我的问题是我有一个远程存储库的
refs/remotes/origin/master
行,删除它,否则 git 不会删除这些文件
(可选) git verify-pack -v .git/objects/pack/#pack-name.idx | sort -k 3 -n | tail -5
- 检查最大的文件
(可选) git rev-list --objects --all | grep a0d770a97ff0fac0be1d777b32cc67fe69eb9a98
- 检查这些文件是什么
git filter-branch --index-filter 'git rm --cached --ignore-unmatch file_names'
- 从所有修订中删除文件
rm -rf .git/refs/original/
- 删除 git 的备份
git reflog expire --all --expire='0 days'
- 使所有松散的对象失效
git fsck --full --unreachable
- 检查是否有松散的物体
git repack -A -d
- 重新包装
git prune
- 最终移除这些对象
【问题讨论】:
可能重复:***.com/questions/2100907/…***.com/questions/872565/… zneak - 我的问题在标题中。 gbacon - 尝试了这些,文件仍然保留在包文件中...... 如果您查看重复中引用的文章,它会显示如何在删除有问题的文件后压缩您的对象存储。 这是救命稻草。心理提示:始终将潜在的巨大 *.log 文件添加到 .gitignore。在此之后从 800mb 的 repo 变成了 6mb。 第二步和第三步合二为一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
【参考方案1】:
见:How do I remove sensitive files from git’s history
如果文件在 rev 中不存在,上述操作将失败。在这种情况下,'--ignore-unmatch' 开关将修复它:
git filter-branch -f --index-filter 'git rm --cached --ignore-unmatch <filename>' HEAD
然后,将所有松散的对象从存储库中取出:
git gc --prune='0 days ago'
【讨论】:
是的,这个试过了,包里的文件还在,大小也没有太大变化…… 我刚做了一个git沙箱,试了一下。这里也不好。让我们看看我能弄清楚什么。 答案中的那个? :) 和我发布的一样,它仍然将文件留在包中......尝试一个 git 沙箱,执行 git gc 以便它会打包文件,然后运行它...... 哦,松散的物体?往上看。我倾向于让它们在两周内被垃圾收集(gc 的默认值);杀死所有个松散的对象就像清空垃圾箱——我失去了找回我不小心删除的任何东西的机会。 :) 也试过这个...删除了一些文件,但最大的仍然存在...【参考方案2】:git gc
之后仍然很大的 git repo 大小有多种原因,因为它是does not remove all loose objects。
我在“reduce the git repository size”中详细说明了这些原因
但在您的情况下测试的一个技巧是 clone your "cleaned" Git repo 并查看克隆是否具有适当的大小。
('"cleaned" repo' 是你应用filter-branch
,然后是gc
和prune
)
【讨论】:
是的,已经测试过了,现在再次测试,它减少了 2k 的存储库:) 并且文件仍然存在...... 奇怪的是git count-objects -v -> count: 0, size: 0, in-pack: 10021, packs: 1, size-pack: 244547, prune-packable: 0, garbage: 0
但是:git clone test1 test2 -> Checking out files: 100% (8509/8509), done
【参考方案3】:
如果不能访问您的存储库数据,我不能肯定地说,但我相信在您运行 git filter-branch
之前,可能有一个或多个打包的引用仍在引用旧提交。这可以解释为什么 git fsck --full --unreachable
不会将大 blob 称为无法访问的对象,即使您已过期 reflog 并删除了原始(未打包的)refs。
这是我要做的(在完成git filter-branch
和git gc
之后):
1) 确保原始 refs 已消失:
rm -rf .git/refs/original
2) 使所有 reflog 条目过期:
git reflog expire --all --expire='0 days'
3) 检查旧打包的 refs
这可能会很棘手,具体取决于您拥有多少打包的 ref。我不知道任何可以自动执行此操作的 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
文件可能是唯一的方法。
【讨论】:
耶!!!我爱你 !问题出在打包的引用文件中,有 refs/remotes/origin/master 从我在某个服务器上备份它的时候开始......一旦我删除它,它就开始消失了......谢谢! (用完整的解决方案更新问题主体)【参考方案4】:我试图摆脱历史上的一个大文件,上面的答案在一定程度上是有效的。关键是:如果你有标签,它们就不起作用。如果可以从标签访问包含大文件的提交,那么您需要调整 filter-branches 命令:
git filter-branch --tag-name-filter cat \
--index-filter 'git rm --cached --ignore-unmatch huge_file_name' -- \
--all --tags
【讨论】:
【参考方案5】:我遇到了同样的问题,我在 github 上找到了一个很棒的 tutorial,它逐步解释了如何删除您意外提交的文件。
这里是 Cupcake 建议的程序的一个小总结。
如果您有一个名为 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
【讨论】:
在 Stack Overflow 上非常不鼓励仅链接的答案,因为如果将来链接断开,那么答案将变得毫无用处。请考虑在您的答案中总结链接中包含的相关信息。【参考方案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
【讨论】:
【参考方案7】:这应该包含在 Git Extras (https://github.com/visionmedia/git-extras) 中的 git obliterate
命令中。
git obliterate <filename>
【讨论】:
【参考方案8】:我建议使用BFG Repo-Cleaner,它是git-filter-branch
的更简单、更快速的替代方案,专为重写 Git 历史文件而设计。它使您的生活在这里变得更轻松的一种方法是它实际上默认处理 all 引用(所有标签、分支、像 refs/remotes/origin/master 之类的东西),但它也是 10-50x更快。
您应该在这里仔细按照以下步骤操作:http://rtyley.github.com/bfg-repo-cleaner/#usage - 但核心位是这样的:下载BFG's 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 的作者。
【讨论】:
推送后这是否还会清除远程仓库中的私有数据? @ThomasLauria 是的,相同的清理后的 ref 在推送时被推送到远程仓库 - rtyley.github.io/bfg-repo-cleaner/#usage 的说明应该涵盖它。如果您可以控制远程仓库,您还可以在推送后对其运行“git gc --prune=now --aggressive”,以确保死对象也立即从中删除。 @RobertoTyley 这可能导致两个提交在历史记录中相继出现并且具有相同的树(如果其中一个提交只添加了已删除的文件)。您是否知道一种从提交历史记录中删除此类提交的简单方法,因为它们似乎是人为的? @RobertoTyley 我认为这涉及另一个问题。在我描述的情况下,只涉及一个存储库。但是git filter-branch --prune-empty
似乎是我的问题的解决方案(虽然使用其他工具,请让我知道 BFG Repo-Cleaner 是否可以这样做)。以上是关于从 git 存储库中删除文件(历史记录)的主要内容,如果未能解决你的问题,请参考以下文章