前提
最近在接手公司的 skywalking 时,发现 gitlab 中 skywalking 项目竟然达到了1.4G大小,在询问同事后得知可能是以前在 commit 时,没有配置好
.gitigore
文件相关内容,将一些 tar 包也上传至仓库中,从而导致该项目变的如此之大以至于在网络环境不好时连项目都 down 不下来。于是开始尝试解决这个问题!
问题所在
通过工具查找后发现在 skywalking 项目中最占体积的竟然是
.git
文件夹,进一步查看后发现占领体积的罪魁祸首是skywalking/.git/objects/pack
目录下的.pack
文件,具体见下图
原因
在你执行 git init
操作后,会创建一个 .git
的隐藏文件夹,该目录结构如下
$ ls
HEAD #指向当前分支
branches/ # 目录
config # 项目特有的配置选项
description # 仅供 GitWeb 程序使用
hooks/ # 保存了客户端或服务端钩子脚本
index # 保存了暂存区域信息
info/ # 保存了一份不希望在 .gitignore 文件中管理的忽略模式 (ignored patterns) 的全局可执行文件
objects/ # 存储所有数据内容
refs/ # 存储指向数据 (分支) 的提交对象的指针
在你 git add
和 git commit
的过程中,保存修改了的文件的 blob
,更新索引,创建 tree
对象,最后创建 commit
对象,这些 commit
对象指向了顶层 tree
对象以及先前的 commit
对象。这三类 Git 对象 ── blob
,tree
以及 commit
── 都各自以文件的方式保存在 .git/objects
目录下。
所以,当你提交了一个体积特别大的文件后,会记录在 objects
文件夹下,删除一个文件,只是记录了删除这个操作,但并不会把文件从 .git
文件夹删除。 当你直接从项目中删除该文件,.git
文件夹完全不会变小(理论上还会变大一点,因为多记录了一次删除操作。。。)
解决
操作前提:删除所有的分支,只留下一个 master
1.首先查找出大文件
git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5 | awk '{print$1}')"
#命令解析:
#rev-list 命令用来列出Git仓库中的提交,我们用它来列出所有提交中涉及的文件名及其ID。 该命令可以指定只显示某个引用(或分支)的上下游的提交。
#--objects:列出该提交涉及的所有文件ID。
#--all:所有分支的提交,相当于指定了位于 /refs 下的所有引用。
#verify-pack 命令用于显示已打包的内容,我们用它来找到那些大文件。
#-v(verbose)参数是打印详细信息。
通过 rev-list
得到了<文件名 : ID>的对应关系,通过 verify-pack
得到了最大的5个文件ID。 用后者筛选前者便能得到最大的5个文件的文件名,比如:
2.删除大文件
git filter-branch --force --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch YOUR-FILE-NAME' --tag-name-filter cat -- --all
#命令解析:
#filter-branch命令可以用来重写Git仓库中的提交
#--index-filter参数用来指定一条Bash命令,然后Git会检出(checkout)所有的提交, 执行该命令,然后重新提交。
#–all参数表示我们需要重写所有分支(或引用)。
#YOUR-FILE-NAME 你查找出来的大文件名字
重复几次,直到大文件全部删除完毕。
如果你确定某一个文件夹下面都不是你需要的,那么你可以直接删除整个文件夹,比如:
$ git filter-branch --force --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch 文件夹名称' --tag-name-filter cat -- --all
3.回收空间
最后,虽然上面我们已经删除了文件, 但是我们的 repo
里面仍然保留了这些 objects
, 等待垃圾回收(GC), 所以我们要用命令彻底清除它, 并收回空间,命令如下:
$ rm -rf .git/refs/original/
$ git reflog expire --expire=now --all
$ git gc --prune=now
Enumerating objects: 116, done.
Counting objects: 40580, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (20898/20898), done.
Writing objects: 100% (40580/40580), done.
Total 40580 (delta 14247), reused 40344 (delta 14232)
注:这里面最重要的两条命令是 git filter-branch
和 git gc
,filter-branch
真正在清理,但是只运行它也是没用的,需要再删除备份的文件,重新打包之类的,最后的gc
命令,用来收集产生的垃圾,最终清除大文件。
完成后,以强制覆盖的方式推送你的 rep
, 命令如下:
$ git push --force --all
git remote -v
git remote remove origin
git remote add origin https://git.baozun.com/platform-architecture/skywalking
git push -u origin --all
参考文章:
https://juejin.im/post/5ce5043c518825240245beb7