解決 git 項(xiàng)目體積過大的問題

前提

最近在接手公司的 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 文件,具體見下圖

1.png

原因

在你執(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 addgit 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è)文件的文件名,比如:

WechatIMG1137.png

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ù)幾次,直到大文件全部刪除完畢。

3.png

如果你確定某一個(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-branchgit gcfilter-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

參考文章:
https://juejin.im/post/5ce5043c518825240245beb7

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容