Git 實戰 - 將檔案從歷史 Commit 中移除
1 |
程式版控不該發生,但難免會遇到的狀況 - 想移除歷史 Commit 裡不該被放進去的檔案,例如:無保存價值的大檔或是機密資料。
如果是無用大檔,即使將檔案刪除再 Commit,日後 clone 仍會佔用頻寬及儲存空間;而機密資料則是非清除不可。Git 允許我們修改歷史並 push -f 覆寫,但實務上會造成開發團隊夥伴的困擾,覆寫後版本會跟其他人先前取得的版本不一致,需要善後。(參考:Git Force Push 後如何更新 Repository by Yowko)
如果了解副作用,也有充分理由必須回到過去重寫歷史,同時也已取得夥伴諒解確認不會被蓋布袋,下面是兩個簡單練習,供未來的我及有需要的同學參考。
【情境一】
歷史有四次 Commit,想移除第二次 Commit 不小心放入的 WiFiPasswd.txt:
利用 git rebase -i 837658aa
(Commit "init") Rebase 第二到四個 Commit,將 Poc Commit 標為 edit,要求在此停下修改:
存檔後,版本會停在 PoC Commit,顯示 "Stop at aacb399... Poc You can amend the commit now" 訊息,此時下指令 git rm WiFiPasswd.txt
移除檔案,再下指令 git commit --amend
修改 Commit。COMMIT_EDITMSG 檔可看到檔案清單的 WiFiPasswd.txt 已消失,只剩 Program.cs [1],此時亦可修改 Commit 訊息[2]:
之後執行 git rebase --continue
,後面兩個 Commit 不需修改,Rebase 完成。再檢視 Poc Commit,其中已無 WiFiPasswd.txt:
【情境二】
有個 secrets 目錄存在多個 Commit,打算將整個資料夾從歷史抹去:
使用 filter-branch 指令,配合 index-filter --all 對所有 Commit Index 跑一次 git rm 將 secrets 目錄移除再重新 Commit。 (註:另一個做法是用 tree-filter 將 Commit 內容還原到暫存目錄修改,優點是可對實體檔案內容做精密調整,缺點是速度較慢,若為單純移除檔案,index-filter 較有效率)
git filter-branch --force --index-filter "git rm --cached --ignore-unmatch secrets -r" -- --all
由訊息可看到 secrets 的兩個檔案被從第二到第四個 Commit 移除。但要注意,刪除檔案在本機仍可被還原,要徹底清除可參考龍哥這篇 【冷知識】怎麼樣把檔案真正的從 Git 裡移掉?
註:官方推薦用 filter-repo 取代 filter-branch,效率較好且功能更多,但需額外下載安裝,先筆記,未來有需要再學。
以上是兩個從歷史抹去檔案的範例,希望大家不會用到它們。
Comments
# by Nathan
REALLY HELPFUL!