Git:彻底删除历史提交过的大文件

此文章发布于 14 个月前,部分信息可能已经过时,请自行斟酌确认。

问题描述

每一次 git 提交修改的改变都会以文件的形式存储在本地项目根目录下的 .git 中,会在 .git/objects下面形成一个 Blob(一段二进制数据)文件记录。
所以 git 仓库随着时间变化会自增长,直到大到我们拉取代码变得困难。

如何清理 git 中的大文件?

Git 仓库过大会导致哪些问题?

  • git 仓库体积过大,占用电脑本地闪存的存储空间;
  • clone git 仓库时,耗时过长,甚至完全 clone 不下来导致 git 报错;
  • git pull 时会由于引用对象过多会报错,导致本地代码无法更新;
  • 在切换分支的时候经常会出现 cpu 占满,内存占满的情况导致电脑死机。

解决方案1

推荐,速度快好用。

使用 bfg 工具:https://rtyley.github.io/bfg-repo-cleaner/

#先查询出大文件(查询方法见方案2)

#删除大文件
java -jar d:/bfg-1.14.0.jar --delete-files "*publish.zip" --no-blob-protection

#清理日志、压缩空间
git reflog expire --expire=now --all && git gc --prune=now --aggressive

#强制推送
git push origin --force --all

git remote prune origin

解决方案2

不推荐,太慢。

1、查看仓库大小

$ git count-objects -vH

2、查看大文件命令(使用 Git Bash 运行):

git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5 | awk '{print$1}')"

3、删除文件

命令如下,注意:一次只能处理一个文件/文件夹,如果有多个需要耐心处理。可以写多个文件空格分隔,像 Linux 一样,测试好像是可以的。
成功会显示 Rewrite xxxx(233/666)
如果显示 xxxxx unchanged说明 repo 里没有找到该文件,请检查路径和文件名是否正确。

$ git filter-branch --force --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch PR/ScmPR40.zip' --tag-name-filter cat -- --all

参数解释:
filter-branch 是让 git 重写每一个分支,
--force 假如遇到冲突也让git强制执行,
--index-filter 选项指定重写的时候应该执行什么命令,要执行的命令紧跟在它的后面,在这里就是 git rm --cached --ignore-unmatch password.txt,让 git 删除掉缓存的文件,如果有匹配的话。
--prune-empty 选项告诉git,如果因为重写导致某些commit变成了空(比如修改的文件全部被删除),那么忽略掉这个commit。
--tag-name-filter 表示对每一个tag如何重命名,重命名的命令紧跟在后面,当前的tag名会从标注输入送给后面的命令,用cat就表示保持tag名不变。
紧跟着的-- 表示分割符,最后的--all 表示对所有的文件都考虑在内。

4、git gc 命令压缩

git reflog expire --expire=now --all
git gc  --prune=now

也有代码说要这样操作,我只执行了上面 2 个命令后再查空间占用就已经变小了。

git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
rm -rf .git/refs/original/
#对git的reflog记录进行清空
git reflog expire --expire=now --all
git gc --prune=now
git gc --prune=now --aggressive 

5、推送到服务器,清理远程仓库

git push origin --force --all
git remote prune origin

注意:清理完之后,每个人一定要删掉之前拉取的项目, 重新从git上拉项目。不要使用之前的项目了!否则会不降反升!

6、清理服务器缓存

如果有条件进入到 Gitlab 服务部署目录,可以对远程仓库进行确认和瘦身。(没有条件,没有尝试)

sudo su

cd ${gitlab项目部署目录}/git-data/repositories/{待清理的项目地址}

git count-objects -vH  #此时还是旧的大小

git gc --prune=now     #清理无效文件

git count-objects -vH  #此时就和本地一样减小了

7、处理好后的干净库如何同步到所有参与开发的同学?

经过上述所有的操作得到一个干净的 git 库后,还需要避免其他有历史库的同学执行 push 操作,因为一旦执行 push 操作就会前功尽弃,导致陈旧的历史库再次污染到新的远程仓库中。所以我们需要让所有开发同学重新克隆仓库。

最后修改:2023 年 02 月 12 日 10 : 45 AM
如果觉得我的文章对你有用,请随意赞赏

发表评论