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



我将大量文件签入到分支并合并,然后不得不删除它们,现在我留下了一个我不知道如何摆脱的大型 .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文件中。

问题是,即使您删除了这些文件,它们仍然存在于以前的修订版中。这就是 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

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

下一步,执行 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

方案 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>

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

然后运行方案 A 中的命令。

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

  1. 强制 Git 处理(但不签出)每个分支和标签的整个历史记录
  2. 删除指定的文件,以及由此生成的任何空提交
  3. 覆盖现有标签
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

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

下一步,执行 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

正如 loganfsmyth 在他的回答中已经说过的那样,您需要清除 git 历史记录,因为即使从存储库中删除文件,这些文件仍然存在。官方 GitHub 文档推荐 BFG,我觉得它比filter-branch更容易使用:

从历史记录中删除文件

从他们的网站下载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 还允许更高级的选项(请参阅文档),如下所示:

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

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

重要!

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

一个选项:

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

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

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

div class="one_answers">这是

使用 GitHub 推荐的 BFG,与 @Timo 的答案相同,但略有不同,因为我花了一些时间查看 CLI 选项。

假设我在一段时间前推送了超过 60MB 的图像,但我无法真正撤消提交。我会简单地运行以下内容

java -jar /jarfiles/bfg-1.14.0.jar --delete-files '*.{png,jpg,JPG,PNG}'

然后我会得到一个建议,我应该运行以下命令,我会这样做

 git reflog expire --expire=now --all && git gc --prune=now --aggressive

最后,将更改同步到遥控器

git push --force

您可以验证包文件大小是否减小

du -sh ./

最新更新