删除由 git 创建的大型 .pack 文件

Posted

技术标签:

【中文标题】删除由 git 创建的大型 .pack 文件【英文标题】:Remove large .pack file created by git 【发布时间】:2012-06-18 11:59:19 【问题描述】:

我将大量文件检入到一个分支并合并,然后不得不删除它们,现在我留下了一个我不知道如何摆脱的大 .pack 文件。

我使用git rm -rf xxxxxx 删除了所有文件,还运行了--cached 选项。

谁能告诉我如何删除当前位于以下目录中的大型 .pack 文件:

.git/objects/pack/pack-xxxxxxxxxxxxxxxxx.pack

我是否只需要删除我仍然拥有但不再使用的分支?或者还有什么我需要运行的吗?

我不确定它有多大不同,但它显示了一个针对文件的挂锁。

谢谢


编辑

这里是我的 bash_history 的一些摘录,应该可以让我了解我是如何进入这种状态的(假设此时我正在处理一个名为“my-branch”的 git 分支,并且我有一个文件夹,其中包含更多文件夹/文件):

git add .
git commit -m "Adding my branch changes to master"
git checkout master
git merge my-branch
git rm -rf unwanted_folder/
rm -rf unwanted_folder/     (not sure why I ran this as well but I did)

我以为我也运行了以下内容,但它没有与其他人一起出现在 bash_history 中:

git rm -rf --cached unwanted_folder/

我还以为我运行了一些 git 命令(例如 git gc)来尝试整理包文件,但它们也没有出现在 .bash_history 文件中。

【问题讨论】:

您能说明一下您是如何删除它们的吗?如果它们仍在提交历史记录中,那么它们仍在您的包文件中。 嗨@loganfsmyth,我已经添加了 bash 历史脚本,希望能有所帮助。 【参考方案1】:

一个选项:

手动运行git gc 将多个包文件压缩成一个或几个包文件。 此操作是持久的(即大包文件将保留其压缩行为),因此使用 git gc --aggressive 定期压缩存储库可能是有益的

另一种选择是将代码和 .git 保存在某处,然后删除 .git 并使用此现有代码重新开始,创建一个新的 git 存储库 (git init)。

【讨论】:

嗨迈克尔,我尝试运行 git gc 并得到了几个包文件,但大的仍然是其中之一,我只想摆脱它,以便我可以更轻松地从外部备份文件夹(之前的 zip 文件是 1-2Mb,现在是 55Mb)。除非有人可以提出其他建议,否则我认为我可能必须创建一个新的 git。我认为这意味着我将无法访问我目前拥有的分支机构等......? 我放弃了尝试,只是删除了 .git 文件夹并按照您所说的创建了一个新的 git 存储库。我会认为这是一个教训。谢谢迈克尔。 这没有多大意义。为什么不能直接告诉 git 合并当前存储库并在此过程中删除打包文件?【参考方案2】:

问题在于,即使您删除了这些文件,它们仍然存在于以前的版本中。这就是 git 的全部意义所在,即使您删除了某些内容,您仍然可以通过访问历史记录来取回它。

您要执行的操作称为重写历史记录,它涉及git filter-branch 命令。

GitHub 在他们的网站上对这个问题有很好的解释。 https://help.github.com/articles/remove-sensitive-data

为了更直接地回答您的问题,您基本上需要运行此命令,并相应地替换unwanted_filename_or_folder

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch unwanted_filename_or_folder' --prune-empty

这将从 repo 的活动历史记录中删除对文件的所有引用。

下一步,执行 GC 循环以强制对文件的所有引用过期并从包文件中清除。这些命令中不需要替换任何内容。

git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
# or, for older git versions (e.g. 1.8.3.1) which don't support --stdin
# git update-ref $(git for-each-ref --format='delete %(refname)' refs/original)
git reflog expire --expire=now --all
git gc --aggressive --prune=now

【讨论】:

我已将其标记为已接受,如果这能让将来任何人更容易解决这个问题,尽管我当时实际上是通过创建一个新的 git repo 解决了我的问题 我不知道你是怎么想到这个的,但是……你这个人。谢谢。 这个答案为我指明了正确的方向。但要实际删除文件3 more commands are needed 1) git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin 2) git reflog expire --expire=now --all 3) git gc --prune=now 我发现使用bfg 更容易。它也在官方 github 文档中被推荐:help.github.com/articles/… @Timo 如果事情随着时间的推移发生了变化,最好添加一个新的答案。加油!【参考方案3】:

场景 A:如果您的大文件只添加到分支中,则无需运行 git filter-branch。你只需要删除分支并运行垃圾回收:

git branch -D mybranch
git reflog expire --expire-unreachable=all --all
git gc --prune=all

场景 B:但是,根据您的 bash 历史记录,您确实将更改合并到 master 中。如果您尚未与任何人共享更改(还没有git push)。最简单的方法是将 master 重置回与具有大文件的分支合并之前。这将消除分支中的所有提交以及合并后对 master 所做的所有提交。因此,除了大文件之外,您可能会丢失您可能真正想要的更改:

git checkout master
git log # Find the commit hash just before the merge
git reset --hard <commit hash>

然后运行场景 A 中的步骤。

场景 C:如果分支有其他更改合并后您想要保留的 master 更改,最好重新设置 master 并有选择地包括你想要的提交:

git checkout master
git log # Find the commit hash just before the merge
git rebase -i <commit hash>

在您的编辑器中,删除与添加大文件的提交相对应的行,但保留其他所有内容。保存并退出。你的主分支应该只包含你想要的,而不是大文件。请注意,没有-pgit rebase 将消除合并提交,因此您将在&lt;commit hash&gt; 之后留下master 的线性历史记录。这对您来说可能没问题,但如果不是,您可以尝试使用 -p,但 git help rebase 表示 combining -p with the -i option explicitly is generally not a good idea unless you know what you are doing

然后运行场景 A 中的命令。

【讨论】:

方案 A here 有一个变体,但有一个额外的意外问题。 场景解决了我的问题,删除大量临时包文件。存储库由构建服务器管理,它会导致在 .git/objects/pack 文件夹中创建不需要的文件。我可以从我的磁盘中释放宝贵的 GB 空间。【参考方案4】:

我有点迟到了,但如果上面的答案没有解决问题,那么我找到了另一种方法。只需从 .pack 中删除特定的大文件。我遇到了这个问题,我不小心签入了一个 2GB 的大文件。我按照此链接中说明的步骤操作:http://www.ducea.com/2012/02/07/howto-completely-remove-a-file-from-git-history/

【讨论】:

执行此方法后会完全删除项目的整个历史记录,还是只删除指定的文件。【参考方案5】:

正如 loganfsmyth 在他的answer 中所述,您需要清除 git 历史记录,因为即使从 repo 中删除文件后,这些文件仍然存在。官方 GitHub 文档 recommend BFG 我觉得比 filter-branch 更容易使用:

从历史记录中删除文件

Download BFG 来自他们的网站。确保您已安装 java,然后创建镜像克隆并清除历史记录。确保将 YOUR_FILE_NAME 替换为您要删除的文件的名称:

git clone --mirror git://example.com/some-big-repo.git
java -jar bfg.jar --delete-files YOUR_FILE_NAME some-big-repo.git
cd some-big-repo.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push

删除文件夹

同上,但使用--delete-folders

java -jar bfg.jar --delete-folders YOUR_FOLDER_NAME some-big-repo.git

其他选项

BFG 还提供更高级的选项(请参阅 docs),例如:

从历史记录中删除所有大于 100M 的文件:

java -jar bfg.jar --strip-blobs-bigger-than 100M some-big-repo.git

重要!

运行 BFG 时,请注意 YOUR_FILE_NAMEYOUR_FOLDER_NAME 确实只是文件/文件夹名称。 它们不是路径,所以像 foo/bar.jpg 这样的东西是行不通的!相反,具有指定名称的所有文件/文件夹都将从回购历史记录中删除,无论它们存在于哪个路径或分支。

【讨论】:

我想知道我是否想将这个bfg 工具应用到本地git repo,命令应该是什么样子?【参考方案6】:

这比编码解决方案更方便。压缩文件。以文件视图格式打开 zip(不同于解压缩)。删除 .pack 文件。解压并替换文件夹。奇迹般有效!

【讨论】:

【参考方案7】:

运行以下命令,将PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA 替换为要删除的文件的路径,而不仅仅是文件名。这些论点将:

    强制 Git 处理但不签出每个分支和标签的整个历史记录 删除指定的文件,以及作为结果生成的任何空提交 覆盖现有标签
git filter-branch --force --index-filter "git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA" --prune-empty --tag-name-filter cat -- --all

这将从 repo 的活动历史记录中强制删除对文件的所有引用。

下一步,执行 GC 循环以强制对文件的所有引用过期并从包文件中清除。这些命令中不需要替换任何内容。

git update-ref -d refs/original/refs/remotes/origin/master
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --aggressive --prune=now

【讨论】:

最后从第二部分我得到了一个 28G 的 repo 到 158M。谷歌上几乎没有其他工作。谢谢。 我按照上述步骤,并推送为“git push origin --force --all”,但我的远程分支(主、开发和功能/ASD-1010)仍然没有清理。当我从远程仓库重新克隆时,它的 .pack 文件仍然存在。如何将这种清理反映到所有远程 git 分支?? 这是唯一对我有用的答案。 相同的@SambitSwain。这实际上并没有改变我的 .pack 文件的大小。上面有没有缺少的命令?我跑了git filter-branch --force --index-filter "git rm --cached --ignore-unmatch .git/objects/pack/pack-cb775202a77613add6cdac4f248d12e026d232f7.pack" --prune-empty --tag-name-filter cat -- --all 为什么要删除refs/remotes/origin/master 并保留/更新其他人?这是否假设我们在master 上执行了filter-branch?另外,就我而言,我需要git push --force --all --prune。因此,如果您的服务器有本地没有的额外分支,请小心

以上是关于删除由 git 创建的大型 .pack 文件的主要内容,如果未能解决你的问题,请参考以下文章

git 大型灾难现场

Unlink of file '.git/objects/pack/pack-***.pack' failed. Should I try again? (y/n) (转)

Git添加所有修改,删除和未跟踪的文件?

Microsoft .NET Framework 3.5 Language Pack - chs是啥,可以删除吗?下面有这多,我该删除哪些

Git的初始化以及本地仓库文件的创建修改和删除

git仓库删除所有提交历史记录