最近碰到個(gè)很難辦的問題,無(wú)意中發(fā)現(xiàn)項(xiàng)目文件夾已經(jīng)快1G了。。。
仔細(xì)一看,原來(lái)是.git文件夾占了80%。。。
思前想后也找不到原因,最后還是google了半天才找到問題:
之前為了方便把一個(gè)200M左右的sdk直接添加到了項(xiàng)目里,然后提交到git上了,更可怕的是sdk還換了好幾個(gè)版本提交了好多次。。。
所以git中就有N多這個(gè)sdk修改的記錄,占了很大空間;
為什么會(huì)出現(xiàn)這種情況呢,就是因?yàn)間it的存儲(chǔ)方式
git倉(cāng)庫(kù)下有一個(gè)名為 .git 的隱藏文件夾 ,從git初始化(git init)開始,所有倉(cāng)庫(kù)的變化都會(huì)記錄在這個(gè).git文件夾中;只要是git記錄的文件(add 并且 commit),就會(huì)通過(guò)一定的算法保存到這里,
刪除一個(gè)文件,只是記錄了刪除這個(gè)操作,但并不會(huì)把文件從.git文件夾刪除。
所以直接刪除項(xiàng)目中的文件,.git文件夾完全不會(huì)變?。ɡ碚撋线€會(huì)變大一點(diǎn),因?yàn)槎嘤涗浟艘淮蝿h除操作。。。)
要想徹底刪除git已經(jīng)記錄的文件,就必須用到一個(gè)高端命令:git filter-branch
官方解釋可以看這里:
https://git-scm.com/docs/git-filter-branch
https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History
具體怎么使用可以參考這兩篇博客:
http://harttle.com/2016/03/22/purge-large-files-in-gitrepo.html
http://blog.csdn.net/lwfcgz/article/details/49453375
具體到我這兒,因?yàn)槲姨砑恿?XXX.framework的庫(kù),所以命令就是:
git filter-branch --force --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch XXX.framework' --tag-name-filter cat -- --all
各個(gè)參數(shù)的意思摘抄如下
filter-branch 是讓git重寫每一個(gè)分支,
--force 假如遇到?jīng)_突也讓git強(qiáng)制執(zhí)行,
--index-filter 選項(xiàng)指定重寫的時(shí)候應(yīng)該執(zhí)行什么命令,要執(zhí)行的命令緊跟在它的后面,在這里就是git rm --cached --ignore-unmatch password.txt ,讓git刪除掉緩存的文件,如果有匹配的話。
--prune-empty 選項(xiàng)告訴git,如果因?yàn)橹貙憣?dǎo)致某些commit變成了空(比如修改的文件全部被刪除),那么忽略掉這個(gè)commit。
--tag-name-filter 表示對(duì)每一個(gè)tag如何重命名,重命名的命令緊跟在后面,當(dāng)前的tag名會(huì)從標(biāo)注輸入送給后面的命令,用cat就表示保持tag名不變。
緊跟著的-- 表示分割符,
最后的--all 表示對(duì)所有的文件都考慮在內(nèi)。
等命令執(zhí)行完了,要提交到遠(yuǎn)程再
git push --force --all
就可以了
在實(shí)際操作中,我還遇到點(diǎn)其他問題,一并記錄下來(lái)~
- 因?yàn)閄XX.framework其實(shí)是個(gè)文件夾,所以在 rm 命令之后必須 加上 -rf 參數(shù),不然其實(shí)會(huì)漏刪不少東西
- 命令里面的 --all 似乎不怎么管用,至少對(duì)分支是不管用的,(博客1里面說(shuō)是對(duì)所有分支。。。貌似有點(diǎn)問題)
一開始我項(xiàng)目有好幾個(gè)分支,我直接在master上操作,完了之后push,結(jié)果.git文件夾確實(shí)有變小,但變小的很有限。。。
后來(lái)我把其他的分支備份出來(lái),然后刪掉項(xiàng)目里的所有分支,只剩下master,再來(lái)了一遍,果然就可以了,遠(yuǎn)程倉(cāng)庫(kù)果然變小了超級(jí)多
本地的.git文件夾依然沒啥變化,這是因?yàn)橛泻芏啾镜鼐彺?,重新git clone遠(yuǎn)程就好了 - git push --force --all其實(shí)也是個(gè)很危險(xiǎn)的操作 ,再執(zhí)行這個(gè)之前,務(wù)必確保當(dāng)前代碼已經(jīng)是最新,并且你開始操作后沒有人提交過(guò)代碼,
不然這么一force,有一大片沖突是必然的。。。不說(shuō)了,說(shuō)多了都是淚。。。
教訓(xùn):
sdk之類的大文件,盡量不要直接添加到git中,如果sdk不經(jīng)常更新且不太大(多大算大多大算小看各自網(wǎng)速了),那直接添加進(jìn)去問題也不大;
如果sdk比較大或者經(jīng)常更新,那就真的注意不能玩git里面加了,目前想到的比較好的替代方案有:
把sdk寫到.gitignore中,在readme等地方寫清楚,項(xiàng)目用到了什么sdk,讓用的人自己去下載;
這個(gè)方法比較容易實(shí)現(xiàn),不過(guò)對(duì)用的人來(lái)說(shuō)不太友好。畢竟除了直接復(fù)制粘貼,直接git clone的代碼是不能直接用的。。。用pod來(lái)管理
一般來(lái)說(shuō)pods是不會(huì)放到git里面的,都是用的時(shí)候再pod install;所以可以給項(xiàng)目用到的sdk之類的大文件,專門建一個(gè)pod庫(kù),讓項(xiàng)目通過(guò)pod依賴這些大文件。
這也是我現(xiàn)在用的方案,效果還是很不錯(cuò)的~
再加上pod還可以配置一些依賴庫(kù)(方法可以參考https://github.com/Phelthas/LXMThirdLoginManager ,關(guān)鍵是.podspec文件),那就更加方便了!強(qiáng)烈推薦?。?!