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

时间:2010-01-29 19:27:38

标签: git version-control git-rewrite-history

(解决,见问题正文的底部)
现在寻找这个,我现在拥有的是:

几乎相同的方法,但它们都将对象留在包文件中...坚持。
我尝试了什么:

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 - 最终删除这些对象

8 个答案:

答案 0 :(得分:64)

我无法确定无法访问您的存储库数据,但我相信在运行git filter-branch之前,可能还有一个或多个打包的引用仍引用旧提交。这可以解释为什么git fsck --full --unreachable不会将大blob称为无法访问的对象,即使你已经使你的reflog过期并删除了原始(未压缩的)refs。

以下是我要做的事情(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 :(得分:14)

我建议使用BFG Repo-Cleaner,这是git-filter-branch的一种更简单,更快的替代方案,专门用于重写Git历史记录中的文件。它让你的生活更轻松的一种方式是它实际上默认处理所有引用(所有标签,分支,refs / remotes / origin / master之类的东西等),但它也是{{3更快。

您应该在这里仔细按照以下步骤操作:10-50x - 但核心位是这样的:下载http://rtyley.github.com/bfg-repo-cleaner/#usage(需要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的作者。

答案 2 :(得分: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

答案 3 :(得分:5)

我试图摆脱历史上的一个大文件,而上述答案在某种程度上有效。关键是:如果你有标签,它们就不起作用。如果可以从标记访问包含大文件的提交,那么您需要调整filter-branches命令:

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

答案 4 :(得分:2)

请参阅:How do I remove sensitive files from git’s history

如果文件在转速中不存在,则上述操作将失败。在这种情况下,' - ignore-unmatch'开关将修复它:

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

然后,将所有松散的物品从废物箱中取出:

git gc --prune='0 days ago'

答案 5 :(得分:1)

git gc之后,由于does not remove all loose objects,您有多种原因可以获得仍然很大的git仓库大小。

我在“reduce the git repository size

中详述了这些原因

但是,在你的情况下测试的一个技巧是clone your "cleaned" Git repo并查看克隆是否具有合适的大小。

(''clean“repo'是您应用filter-branch,然后gcprune

的应用

答案 6 :(得分:1)

这应该由Git Extras中的git obliterate命令(https://github.com/visionmedia/git-extras)涵盖。

git obliterate <filename>

答案 7 :(得分:0)

我遇到了同样的问题,我在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