git查找大文件并删除

git查找大文件,并从历史记录中删除。大概有几种方法。如果出现错误提交,最好在没有推送到远程前,赶紧删掉。就算推到远程,也尽快恢复。
大概两种方法。分几个部分看。

方式一

测试创建、并推送一些记录。


git
echo test_git
git clone http://...../test_git.git

cd test_git
ls
# 创建提交记录
for n in `seq 1 10`;do
    echo "$n$n$n$n$n" >> $n.txt
    git add .
    git commit -am "$n:add $n.txt"
    git push
done 
git log --oneline 
# 选择其中一个节点,如果要删除某个点,要在其前1个点执行
git rebase -i 9303e8f 
# 然后编辑,drop 代表删除。比如删除该节点后面的一个节点,再看

git log --oneline 

# 然后发现上面的节点确实删除了
# 去掉git的保护分支
git push -f 
git push -f  --all

方式2


1、查找最大的文件 
git rev-list --all | xargs -rL1 git ls-tree -r --long | sort -uk3 | sort -rnk4 | head -10

# 由于提交历史已有8000+,很长时间后,找到如下
# 100644 blob 0800a0c5f547627750412b8f5ed9026c74235ba6 1984831488 geoserver/osm-lowres.gpkg

2、根据最大文件的路径 {filepath},修改此文件的commit历史:

git filter-branch --tree-filter "rm -f {filepath}" -- --all

3、强制提交到远程分支:

git push -f --all

试过,大文件还在。

方式3

1、实际上到下面文件能找到一个最大的文件
.git\objects\pack
能找到大文件 但是不知道,对应哪次提交。

git verify-pack -v .git/objects/pack/pack-5794788dfaa1755461cb7dc301649cab222b4006.pack | sort -k 3 -n | tail -3

2.查询大文件的文件名

git rev-list --objects --all | grep 0800a0c5f547627750412b8f5ed9026c74235ba6

# 输出如下:
# 0800a0c5f547627750412b8f5ed9026c74235ba6 geoserver/osm-lowres.gpkg

3.将该文件从历史记录的所有 tree 中移除

git filter-branch --index-filter 'git rm --cached --ignore-unmatch  geoserver/osm-lowres.gpkg'

注意:上面文件命令 geoserver/osm-lowres.gpkg 前面并没有 / 号

4.然后再执行如下语句:

rm -rf .git/refs/original/
git reflog expire --expire=now --all
git fsck --full --unreachable
git repack -A -d
git gc --aggressive --prune=now
git push --force

试过,大文件还在。

方式4:

另外一篇文章:

首先来看下.git目录:

├── HEAD
├── branches
├── index
├── logs
│ ├── HEAD
│ └── refs
│ └── heads
│ └── master
├── objects
│ ├── 88
│ │ └── 23efd7fa394844ef4af3c649823fa4aedefec5
│ ├── 91
│ │ └── 0fc16f5cc5a91e6712c33aed4aad2cfffccb73
│ ├── 9f
│ │ └── 4d96d5b00d98959ea9960f069585ce42b1349a
│ ├── info
│ └── pack
└── refs
├── heads
│ └── master
└── tags
用于GitWeb程序
配置特定于该仓库的设置
放置客户端或服务端的hook脚本
指明当前处于哪个分支
Git对象存储目录
Git引用存储目录
放置分支引用的目录
每次 都会生成一个Git对象,称为blob 对象,存放在objects目录下。

这个blob 对象里保存的是什么呢?
Git在add文件时,会把文件完整的保存成一个新的blob 对象。通过 打包或者每次 的时候Git都会自动执行一次打包过程,将Blob对象合并成一个包文件,同时会生成一个索引文件,索引文件中包含了每个Blob对象在包文件中的偏移信息,Git在打包的过程中使用了增量编码方案,只保存Blob对象的不同版本之间的差异,这使得仓库会瘦身。

既然Git会对Blob对象进行合并优化,那么objects文件夹为什么还会那么大呢?

因为当Blob对象在合并时不能对.a进行差异化比较,所以每次在添加.a文件时,都会保存一份.a文件,用于后续代码还原时使用。

所以当频繁更换.a文件时,objects下的pack文件会越来越大。虽然这个.a文件后续可能用不到删除了,但是pack中的这个.a文件的缓存还是会一直存在。

删除pack中无用的大文件缓存
首先先找出git中最大的文件:

git verify-pack -v .git/objects/pack/pack-*.idx | sort -k 3 -g | tail -5

执行结果:

第一行的字母其实相当于文件的id,用以下命令可以找出id对应的文件名:
git rev-list –objects –all | grep 8f10eff91bb6aa2de1f5d096ee2e1687b0eab007

找到最大的几个文件后,怎么删除呢?

能够胜任这个任务的命令叫做 filter-branch:

git filter-branch –force –prune-empty –index-filter ‘git rm -rf –cached –ignore-unmatch XXX.framework’ –tag-name-filter cat – –all

等命令执行完后,要提交到远程:

git push –force –all
链接:https://www.jianshu.com/p/4f2ccb48da77

其他:

https://www.jianshu.com/p/780161d32c8e