git是當前最常見的版本控制工具,但出現以下情況時,往往需要清空commits歷史記錄:
- commits記錄占用空間過大甚至遠遠超過版本控制文件本身大小,進行雲端代碼管理時會受制於空間限制,無法繼續更新
- 歷史記錄中存在敏感信息,需要清理
清理commits歷史記錄的核心思想是,直接刪除本地的.git目錄,重新建立git倉庫並與遠程倉庫建立鏈接,采用強制提交的方式覆蓋遠程倉庫的commits記錄。下面是一段示例腳本。
參數說明:
- $REPO_DIR 表示需要處理的Git倉庫本地目錄
- git@github.com:xxxx/$REPO_DIR.git 表示遠程倉庫地址
則可以按照如下步驟處理:
進入本地倉庫,刪除.git目錄
cd $REPO_DIR
rm -rf .git
重新git初始化並添加commit
git init
git add . # 重新添加所有的文件
git commit -m "restart git commit"
添加遠程倉庫鏈接
在添加遠程倉庫時,需要設置遠程倉庫的代號,本教程記為origin.
git remote add origin git@github.com:xxxx/$REPO_DIR.git
此時,可以用git remote -v
檢查遠程倉庫的設置。
強制提交,覆蓋遠程倉庫的commits歷史記錄
假設提交到遠程倉庫的master分支,則強制提交腳本如下:
git push -f origin master # 或者 git push --force origin master
強制提交之后,再看遠程倉庫master分支的commits記錄就變成1了。
如果需要與上游保持同步檢測,可以使用指令--set-upstream origin/master
,即
git push origin master --set-upstream origin/master # 如果指向其他分支,可以修改為 origin/${指定分支名}
至此,大功告成~
后續討論
細心的朋友可能會發現,上述操作之后,如果你還記得歷史記錄中某個commit的鏈接,你仍然可以通過鏈接訪問到該commit下的文件,甚至可以基於這個commit重新創建新分支。為什么會出現這種情況呢?這其實和Git本身的設計機制有關,主要是為了提高容錯率,防止你因為一些誤操作弄丟了某些commits進而造成無法挽回的結果。
實際上,這些commits並沒有馬上被清理掉,僅僅是你的所有分支或標簽無法訪問到它們,這些commits被稱為unreachable commits. 它們通常會被緩存一段時間,這個周期默認是30天,你也可以通過git命令行手動修改緩存周期或者手動清理。由於Github也是建立在Git這個版本管理工具上的網站,所以它也有這個機制。雖然它們在緩存期內仍然可以被訪問到,但你clone到本地並不會包含它們,也就是說,你並不能在本地刪除Github上已經存在的unreachable commits,因為本地根本訪問不到它們(存在於 GitHub 上但不存在於本地克隆中的提交)。如果不着急的話,你可以等30天之后再試試看是否還能訪問這些unreachable commits的鏈接;但如果你很着急,你可以聯系Github Support幫你清理這些你不想保留的commits。
所以,如果你只是維護個人的文件倉庫的話,不需要擔心這個問題,你在新機器上clone下來的仍然是縮減大小之后的倉庫,而Github上的unreachable commit會在緩存期后被清理掉。如果是與他人協作的倉庫,還是謹慎使用git push --force
這種危險的操作吧,確實遇到需要這個操作的場景時,考慮用更安全的git push --force-with-lease
. 如果你強制提交之后發現后悔了,找到想恢復的commit的鏈接並創建新分支就可以找回那個commit所在歷史分支之前的內容啦。
感謝@綠靜風 發現了這個問題,促使我進一步查閱資料去完善這篇博文,在此表示感謝!
后續討論的主要參考內容如下:
- Git Internals - Maintenance and Data Recovery
- Stackoverflow - How to remove a dangling commit from GitHub?
如果只是想刪除歷史記錄中曾經存在(但現在並不需要)的大文件,可以參考這個Issue中的討論:Consider cleaning up the .git folder to reduce the large repo size