前提
最近在接手公司的 skywalking 時(shí),發(fā)現(xiàn) gitlab 中 skywalking 項(xiàng)目竟然達(dá)到了1.4G大小,在詢問同事后得知可能是以前在 commit 時(shí),沒有配置好
.gitigore文件相關(guān)內(nèi)容,將一些 tar 包也上傳至倉庫中,從而導(dǎo)致該項(xiàng)目變的如此之大以至于在網(wǎng)絡(luò)環(huán)境不好時(shí)連項(xiàng)目都 down 不下來。于是開始嘗試解決這個(gè)問題!
問題所在
通過工具查找后發(fā)現(xiàn)在 skywalking 項(xiàng)目中最占體積的竟然是
.git文件夾,進(jìn)一步查看后發(fā)現(xiàn)占領(lǐng)體積的罪魁禍?zhǔn)资?skywalking/.git/objects/pack目錄下的.pack文件,具體見下圖

原因
在你執(zhí)行 git init 操作后,會(huì)創(chuàng)建一個(gè) .git 的隱藏文件夾,該目錄結(jié)構(gòu)如下
$ ls
HEAD #指向當(dāng)前分支
branches/ # 目錄
config # 項(xiàng)目特有的配置選項(xiàng)
description # 僅供 GitWeb 程序使用
hooks/ # 保存了客戶端或服務(wù)端鉤子腳本
index # 保存了暫存區(qū)域信息
info/ # 保存了一份不希望在 .gitignore 文件中管理的忽略模式 (ignored patterns) 的全局可執(zhí)行文件
objects/ # 存儲(chǔ)所有數(shù)據(jù)內(nèi)容
refs/ # 存儲(chǔ)指向數(shù)據(jù) (分支) 的提交對(duì)象的指針
在你 git add 和 git commit 的過程中,保存修改了的文件的 blob,更新索引,創(chuàng)建 tree 對(duì)象,最后創(chuàng)建 commit 對(duì)象,這些 commit 對(duì)象指向了頂層 tree 對(duì)象以及先前的 commit 對(duì)象。這三類 Git 對(duì)象 ── blob,tree 以及 commit ── 都各自以文件的方式保存在 .git/objects 目錄下。
所以,當(dāng)你提交了一個(gè)體積特別大的文件后,會(huì)記錄在 objects 文件夾下,刪除一個(gè)文件,只是記錄了刪除這個(gè)操作,但并不會(huì)把文件從 .git 文件夾刪除。 當(dāng)你直接從項(xiàng)目中刪除該文件,.git 文件夾完全不會(huì)變?。ɡ碚撋线€會(huì)變大一點(diǎn),因?yàn)槎嘤涗浟艘淮蝿h除操作。。。)
解決
操作前提:刪除所有的分支,只留下一個(gè) 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。 該命令可以指定只顯示某個(gè)引用(或分支)的上下游的提交。
#--objects:列出該提交涉及的所有文件ID。
#--all:所有分支的提交,相當(dāng)于指定了位于 /refs 下的所有引用。
#verify-pack 命令用于顯示已打包的內(nèi)容,我們用它來找到那些大文件。
#-v(verbose)參數(shù)是打印詳細(xì)信息。
通過 rev-list得到了<文件名 : ID>的對(duì)應(yīng)關(guān)系,通過 verify-pack 得到了最大的5個(gè)文件ID。 用后者篩選前者便能得到最大的5個(gè)文件的文件名,比如:

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參數(shù)用來指定一條Bash命令,然后Git會(huì)檢出(checkout)所有的提交, 執(zhí)行該命令,然后重新提交。
#–all參數(shù)表示我們需要重寫所有分支(或引用)。
#YOUR-FILE-NAME 你查找出來的大文件名字
重復(fù)幾次,直到大文件全部刪除完畢。

如果你確定某一個(gè)文件夾下面都不是你需要的,那么你可以直接刪除整個(gè)文件夾,比如:
$ git filter-branch --force --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch 文件夾名稱' --tag-name-filter cat -- --all
3.回收空間
最后,雖然上面我們已經(jīng)刪除了文件, 但是我們的 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 真正在清理,但是只運(yùn)行它也是沒用的,需要再刪除備份的文件,重新打包之類的,最后的gc 命令,用來收集產(chǎn)生的垃圾,最終清除大文件。
完成后,以強(qiáng)制覆蓋的方式推送你的 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