Git删除大文件

Keywords: #技术 #Git

我们在平时的项目开发中总是会忘记将不需要 Git 的文件或者文件夹添加进 .gitignore 中,一些不重要的小文件一般没有什么问题,但是如果不小心提交了大文件或者敏感信息,就会比较头疼。

之前我也写过一篇笔记:从Git历史中完全删除某个文件,就是因为我不小心将自己敏感配置信息通过 Git 上传到公开仓库中,需要从 Git 记录中删除信息,但是由于 Git 的特性,直接删除信息是没有用的,Git 会记录每次提交的所有信息,方便回滚。因此需要在 Git 中完全删除敏感信息操作。

这回也是同样的错误,我在本地开发项目,忘记将临时编译打包的大文件 /tmp/main.exe 添加进 .gitignore 中,最后导致把大文件通过 Git 提交到远程仓库中,并且导致 .git 文件很大。

实际上,通过 Git 提交大文件有几点不好的地方,一是提交了大文件会导致 .git 文件越来越大,之后 git clone 或者 git pull 的时候十分困难。二是 Git 会限制文件大小,一些很大的文件不能推送,可以使用 git lfs ,但是有免费容量限制。所以我一般会尽量避免大文件提交推送。

其实撤销大文件提交的原理,与从 Git 中删除文件的做法是差不多的,核心都是使用 git filter-branchgit gc

如果我们知道是哪一次 commit,提交推送了大文件,则可以撤销 commit 再重新提交。

列出提交记录

git log

依次撤销对应的提交记录

git reset 4ac0e5da919843axxxxxxxxxxxxxxxx

清理回收内存

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 add .
git commit -m "撤销大文件"
git push -f --all

如果是忘记了大文件是哪个 commit 提交推送的,或者是 commit 记录太久远了,则可以使用 git filter-branch 修改大文件记录。

列出记录中前 10 个最大的文件记录

git rev-list --all | xargs -rL1 git ls-tree -r --long | sort -uk3 | sort -rnk4 | head -10
100644 blob e0d29beda6fecbe332428481441a66c2fac9f99a 47987299   code/Gui/tmp/main.exe
100644 blob b9b43965e9a44acbe90e1ced9b1732a2fe350475 47810498   code/Gui/tmp/main.exe
100644 blob 62d000d6e12ab54dc6ab6e75b20a8ace1c79051e 3883008    code/fyne_demo.exe
100644 blob 8f8d6516a71151ae3afffe03be7a65c8a7f2c076 1072643    code/Gui/core/QRN
100644 blob 8f8d6516a71151ae3afffe03be7a65c8a7f2c076 1072643    code/Core/QRN
100644 blob 8f8d6516a71151ae3afffe03be7a65c8a7f2c076 1072643    code/App/core/QRN

比如这里我需要撤销 code/Gui/tmp/main.exe 这个大文件,使用 git filter-branch 命令。

git filter-branch --tree-filter "rm -f code/Gui/tmp/main.exe" -- --all

这样就会重写所有 code/Gui/tmp/main.exe 的记录,不过这时 .git 中空间还没有释放,需要清理回收内存。

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 -f --all