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


112

我将大量文件放入分支中并合并,然后将其删除,现在剩下的是一个很大的.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,2012年

@loganfsmyth,您好,我添加了bash历史记录脚本,希望会对您有所帮助。
user1116573

Answers:


201

问题是,即使您删除了文件,它们仍然存在于以前的版本中。这就是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周期,以强制对文件的所有引用都过期并从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

3
我已将其标记为已接受,是否可以使将来遇到此问题的人更轻松,尽管我当时实际上通过创建一个新的git repo解决了我的问题
user1116573

3
我不知道你是怎么想到的,但是...你是那个人。谢谢。
以西结·维克托

5
这个答案为我指明了正确的方向。但是实际上要删除文件,需要3个其他命令 1)git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin2)git reflog expire --expire=now --all3)git gc --prune=now
触发

3
我发现使用bfg起来容易得多。官方github文档中也建议使用:help.github.com/articles/…–
Timo,

2
@Timo如果事情随着时间的推移发生了变化,最好添加一个新答案。去吧!
loganfsmyth

12

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

在编辑器中,删除与添加大文件的提交对应的行,但其他所有内容保持不变。保存并退出。您的master分支应该只包含您想要的内容,而不能包含大文件。请注意,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中的命令。


有方案A的变体在这里有,但是,额外的意想不到的问题。

方案解决了我的问题,删除了大量的临时包文件。该存储库由构建服务器进行管理,它会在.git / objects / pack文件夹内导致不必要的文件创建。我可以从磁盘上释放宝贵的GB。
xrissz

7

正如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还提供了以下更高级的选项(请参阅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,命令应如何显示?
天使托多罗夫

5

一种选择:

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

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


嗨,迈克尔,您好我尝试运行git gc,只找到了两个压缩文件,但是大的还是一个压缩文件,我想摆脱它,以便我可以轻松地从外部备份该文件夹(以前的zip压缩为1 -2Mb,现在为55Mb)。除非有人可以提出其他建议,否则我认为我可能必须创建一个新的git。我认为这意味着我将无法访问当前拥有的分支等...?
user1116573 2012年

2
我放弃尝试,只是删除了.git文件夹,并按照您所说的创建了一个新的git存储库。我认为这是一个教训。谢谢迈克尔。
user1116573 2012年

4
这没有多大意义。为什么不告诉git合并当前存储库并在此过程中删除pack文件?
jml

4

运行以下命令,替换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

最终,从第二部分开始,我得到了一个28G存储库,降至158M。Google上几乎没有其他功能。谢谢。
Sridhar Sarnobat

我按照上述步骤操作,并按“ git push origin --force --all”进行了推送,但我的远程分支(master,develop和Feature / ASD-1010)仍未清除。当我从远程存储库中克隆新文件时,它的.pack文件仍然存在。我该如何反映对所有远程git分支的清理?
Sambit Swain

1

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


执行此方法后,它将完全删除项目的整个历史记录,或者仅删除指定的文件。
萨米姆·阿夫塔布·艾哈迈德

-3

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.