处理.git文件夹过大出现臃肿问题
1、查找原因
最近需要在一个成熟的项目中加少许功能,当从 git 拉取项目进行开发的时候,使用git clone 克隆的很慢,还以为是网速的问题,又看了一下git命令框的拉取网络速度发现网速还是很快的,这就引起了我的好奇心想要看看为什么代码克隆的这么慢。经过我的一番查找,发现是代码克隆下来后是.git文件夹太大,项目代码占用很小。发现是git的问题后,就第一时间查找下是哪个地方出的问题导致.git文件过大。进入.git 目录后发现是/objects/pack 目录下面的xxx.pack文件占用过大。
2、pack文件过大的原因
在开发过程中有时候不小心上传了大文件,虽然后面在目录里面删除了,但会被git记录下来。这样慢慢的记录的越来越多,就变为了目前这样文件太大,出现了臃肿。所以我们在提交代码的时候,一定要检查一下提交的代码,不要把一些不必要的大文件提交上去。后面就算在项目里面删除了,但是还是被git的版本控制给记录下来了,就会造成/objects/pack/xxx.pack文件过大。如果真的不小心提交了,可以使用仓库清理工具进行删除。我们可以使用git自带的filter-branch工具或者BFG工具进行仓库清理。
3、git filter-branch 清理
首先进入git命令框,输入命令。首先查询出3个大文件信息
1 | git verify-pack -v .git/objects/pack/pack-xxx.idx | sort -k 3 -n | tail -3 (xxx你的.git的pack目录文件) |
查询结果
1 | 73671b13992abba02a7fa56d37735d4ac01803b1 blob 62992368 62936889 132214388 |
在根据上面的文件名的编码ID:73671b13992abba02a7fa56d37735d4ac01803b1 查询出大文件的名称:
1 | git rev-list --objects --all | grep 73671b13992abba02a7fa56d37735d4ac01803b1 |
上面的为单个查询,我们也可以直接查询多个,把上面的两个命令合并一起执行。
1 | git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -10 | awk '{print$1}')" #查询前10个大文件 |
通过命令查询出文件信息,然后将该文件从历史记录的所有 tree 中移除,执行命令从历史中删除指定的大文:
1 | git filter-branch --force --index-filter "git rm -rf --cached --ignore-unmatch 文件/文件夹" --prune-empty --tag-name-filter cat -- --all #文件/文件夹 是通过上面查询出来的大文件路径和名称 |
执行成功后需要删除和重建索引
1 | git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin |
然后设置历史记录的过期时间为现在,默认为90天。
1 | git reflog expire --expire=now --all #所有未关联对象过期时间为现在 |
通过gc清理文件并优化本地存储库
1 | git gc --aggressive --prune=now |
强制提交
1 | git push --all --force origin |
执行完毕上面命令,一个大文件我们就清理完毕了,如果有多个大文件需要一个文件一个文件的执行。当大文件都清理完毕我们可以查看当前目录下个文件及目录占用空间大小
1 | du -sh .git |
如果输出文件过大,可以继续查找相关大文件进行删除。
1 | git count-objects -v #计算解包的对象数量及其磁盘消耗量 |
4、高效大文件清理工具 BFG
官网地址:BFG (https://rtyley.github.io/bfg-repo-cleaner/ )
BFG是git-filter-branch的替代品,官方介绍说要比git-filter-branch要快上10~720x,经过本人的亲自使用,清理速度确实很快,值得我们去使用。
4.1、使用方式
需要去官网下载bfg.jar也可以去镜像仓库下载(https://repo1.maven.org/maven2/com/madgag/bfg/)
这里使用1.14.0版本。由于是jar包,所以运行bfg需要具备java环境。简单介绍下命令,也可以自己去官网查找相关命令。
首先通过 --mirror 拉取自己项目的.git 文件, --mirror参数只拉取.git文件不克隆代码,防止操作失误修改项目代码。
1 | git clone --mirrot xxx.git |
查询前10个大文件
1 | git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -10 | awk '{print$1}')" |
通过删除目录文件删除
1 | java -jar bfg.jar --delete-folders {dev} --no-blob-protection project.git #{dev} 删除dev目录下面的所有文件 |
通过文件大小删除
1 | java -jar bfg.jar --strip-blobs-bigger-than 10M project.git #删除文件大于10M |
通过文件名字删除,先通过查询大文件,查询出数据后,然后通过文件名称执行该命令删除:
1 | java -jar bfg.jar --delete-files "xxxx" project.git |
删除敏感信息
1 | java -jar bfg.jar --replace-text pwd.txt project.git |
pwd.txt自己定义需要移除数据的文本,具体语法自己可以查找相关文档。
设置过期时间为现在 & 清理文件
1 | git reflog expire --expire=now --all && git gc --prune=now --aggressive |
推送到远程
1 | git push --mirror |
最后我们在执行下du -sh .git命令查询一些.git文件夹大小,发现一些没有的文件我们已经清理干净了。后面需要重新从git克隆代码,不要使用之前的.git文件进行提交。否则文件依旧会变大。
5、总结
上面的两种方式都可以成功把.git 文件夹的一些大文件清理干净。具体使用哪一种方式,我们可以观察克隆的文件夹大小。如果文件很大并且不止一个大文件。那么使用bfg.jar处理起来更加高效一些。如果大文件不多并且只有几个文件,使用git自带的git filter-branch处理就可以了,毕竟不需要去下载额外的工具,可以更加节约时间。



