發現好像這個方法不好使。。。。。。。~~!還是會失敗
如果有人或者自己失誤把不該同步的大文件如數據或日志或其他中間文件給commit了並且push了,然后你刪掉了,但是其實他仍然在你的git記錄中,你的整個項目仍然會非常大,主要是當時的那個刪除你沒有用git rm,但總之你想清理就很麻煩了現在,或者說,可能現在由於你commit的東西太大,導致了根本沒法push上去,會出現類似
fatal: the remote end hung up unexpectedly
這樣的錯誤,然后你就是需要清理一下你的commit記錄了。
step 1. 把代碼拉到本地
git clone git@github.com:hollischuang/Architecture-Evolution.git
只是用這個地址舉例,實際並不是這個項目。
step 2. 查看哪個文件占用的空間比較大
於是,發現是.git
目錄自己就占用了174M,了解Git的人都知道,.git
目錄是git自己生成的,記錄了git倉庫的相關信息的。看到這里其實並不難知道原因。
經過我的驗證,確實是.git/objects
這個文件夾中的文件占了磁盤上174M的空間。
也就是說,只要我有一次將一個大文件誤提交了,那么即使我后面把它刪除了,但是,實際上在.git
中,這個文件還是存在的,雖然我們可能再也不需要他了,但是他還在那里默默的存在着。。。
也就是說,如果我又一次把一個大文件務提交到git倉庫中了,那么,下次提交時,即使你只改動了某個文件的一行內容,Git 也會生成一個全新的對象來存儲新的文件內容。
因為以上兩個特性,我回想起我的一次手殘行為:
剛剛創建一個應用之后,我快速的寫完代碼,編譯,運行,發現沒啥問題之后,我准備先把他發布掉,於是我開始創建git倉庫,並嘗試把代碼提交上去,這時我並沒有創建.gitignore文件,我直接git add .
git commit -m 'init'
git push
一氣呵成的執行了熟悉的操作。
相信聰明的人已經發現了,逗比啊,我在編譯代碼之后,會有很多jar被我down到target目錄下。我直接git add.
把target下面的jar包,war包等這些也直接提交了。。。雖然后面我意識到,並且刪除了這些文件,然后再次提交,但是由於剛我們說過的原因,這些文件依然占用着我的空間。。。
更多關於git的原理內容參見:Git 內部原理
How
問題已經定位到了,接下來就是要解決問題了。如果對git的原理及命令了解的比較多的話,這個問題還是比較好解決的,由於當時博主並不十分了解git的原理,所以做了一些知識儲備之后才開始動手的。(Git 之術與道 — 對象、為什么你的 Git 倉庫變得如此臃腫)
Step 1 查看哪些歷史提交過文件占用空間較大
使用以下命令可以查看占用空間最多的五個文件:
git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5 | awk '{print$1}')"
step 2. 重寫commit,刪除大文件
使用以下命令,刪除歷史提交過的大文件:
git filter-branch --force --index-filter 'git rm -rf --cached --ignore-unmatch big-file.jar' --prune-empty --tag-name-filter cat -- --all
上面腳本中的big-file.jar
請換成你第一步查出的大文件名,或者這里直接寫一個目錄。
在重寫提交的過程中,會有以下日志輸出:
如果顯示 xxxxx unchanged
, 說明repo里沒有找到該文件, 請檢查路徑和文件名是否正確,重復上面的腳本,把所有你想刪除的文件都刪掉。
step 3. 推送修改后的repo
以強制覆蓋的方式推送你的repo, 命令如下:
git push origin master --force
step 4. 清理和回收空間
雖然上面我們已經刪除了文件, 但是我們的repo里面仍然保留了這些objects, 等待垃圾回收(GC), 所以我們要用命令徹底清除它, 並收回空間,命令如下:
至此,我們已經徹底的刪除了我們不想要的文件