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

use*_*573 90 git pack branching-and-merging

我检查了一大堆文件到一个分支并合并,然后不得不删除它们,现在我留下了一个大的.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)
Run Code Online (Sandbox Code Playgroud)

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

git rm -rf --cached unwanted_folder/
Run Code Online (Sandbox Code Playgroud)

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

log*_*yth 179

问题是,即使您删除了文件,它们仍然存在于以前的版本中.这就是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
Run Code Online (Sandbox Code Playgroud)

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

接下来,执行GC循环以强制对文件的所有引用都过期并从packfile中清除.在这些命令中不需要替换任何内容.

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
Run Code Online (Sandbox Code Playgroud)

  • 我已将其标记为已接受,如果这使将来任何人都可以更轻松地解决此问题,尽管我当时实际上是通过创建一个新的 git 存储库解决了我的问题 (4认同)
  • 这个答案指出了我正确的方向.但要实际删除文件[需要3个以上命令](https://help.github.com/articles/removing-sensitive-data-from-a-repository/)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` (4认同)
  • 我不知道你是怎么想出这个的,但是……你这个人。谢谢。 (3认同)
  • @Timo 如果事情随着时间的推移发生了变化,最好添加一个新答案。去吧! (3认同)
  • 我发现使用`bfg`要容易得多。官方github文档中也建议使用此方法:https://help.github.com/articles/removing-sensitive-data-from-a-repository/ (2认同)

onl*_*one 10

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

git branch -D mybranch
git reflog expire --expire-unreachable=all --all
git gc --prune=all
Run Code Online (Sandbox Code Playgroud)

场景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>
Run Code Online (Sandbox Code Playgroud)

然后运行方案A中的步骤.

场景C:如果您希望保留合并后的分支主服务器上的更改,则最好重新定义主服务器并有选择地包含所需的提交:

git checkout master
git log # Find the commit hash just before the merge
git rebase -i <commit hash>
Run Code Online (Sandbox Code Playgroud)

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

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


小智 9

运行以下命令,替换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
Run Code Online (Sandbox Code Playgroud)

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

下一步,执行 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
Run Code Online (Sandbox Code Playgroud)

  • 我按照上述步骤操作,并按“git push origin --force --all”推送,但我的远程分支(master、develop 和 feature/ASD-1010)仍然没有清理。当我从远程存储库重新克隆时,它的 .pack 文件仍然存在。我怎样才能将这种清理反映到所有远程 git 分支? (3认同)
  • 最后,从第二部分开始,我将 28G 的存储库减少到了 158M。谷歌上几乎没有其他东西起作用。谢谢。 (2认同)

Ris*_*mar 6

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

  • 执行此方法后,它会完全删除项目的整个历史记录,还是仅删除指定的文件。 (2认同)

Mic*_*ant 5

一种选择:

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

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

  • 这没有多大意义.为什么你不能告诉git整合当前的存储库并删除进程中的包文件? (4认同)
  • 我放弃了尝试,只是删除了.git文件夹并创建了一个新的git存储库,如你所说.我会认为这是一个经验教训.谢谢迈克尔. (2认同)

Tim*_*imo 5

正如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
Run Code Online (Sandbox Code Playgroud)

删除资料夹

与上述相同,但使用 --delete-folders

java -jar bfg.jar --delete-folders YOUR_FOLDER_NAME some-big-repo.git
Run Code Online (Sandbox Code Playgroud)

其他选择

BFG还提供了以下更高级的选项(请参阅docs):

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

java -jar bfg.jar --strip-blobs-bigger-than 100M some-big-repo.git
Run Code Online (Sandbox Code Playgroud)

重要!

在运行BFG时,请注意两者YOUR_FILE_NAMEYOUR_FOLDER_NAME实际上只是文件/文件夹名称。他们不是道路,所以类似的东西foo/bar.jpg行不通!取而代之的是,所有指定名称的文件/文件夹都将从回购历史记录中删除,无论它们存在于哪个路径或分支中。