Git 永久刪除檔案
簡略版
假設要刪除的檔案是password.txt,執行如下命令:
git filter-branch --force --index-filter 'git \
rm --cached --ignore-unmatch password.txt' \
--prune-empty --tag-name-filter cat -- --all
如果commit已經同步到了github,那麼再執行如下命令永久刪除遠端上的檔案。
git push --all --force
不用關心各條命令在幹什麼,大功告成!
詳細版
你如果有耐心或者有興趣知道上面兩條命令是如何工作的,就接著往下讀。。。
問題的產生
眾所周知,git是用來進行版本控制的,可以恢復到任何commit了的歷史狀態,對於新手來說,經常會把一些不必要的資料或者敏感資料放到github的公開專案中。比如說我,剛接觸git時,每次修改之後都用 git add .
圖省事,結果一些.class, .zip, .exe檔案都被commit了,很煩人。要是不小心提交了密碼或者機器的SSH key,就容易產生安全隱患。
一個簡單但錯誤的辦法就是使用git rm password.txt
命令刪除敏感檔案,但是這僅僅是把檔案從當前版本中刪除,歷史版本中仍然有。
下面來說說正確命令的每個選項是什麼意思:
git filter -branch --force --index-filter 'git \
rm --cached --ignore-unmatch password.txt' \
--prune-empty --tag-name-filter cat -- --all
filter-branch
是讓git重寫每一個分支,
--force
假如遇到衝突也讓git強制執行,
--index-filter
選項指定重寫的時候應該執行什麼命令,要執行的命令緊跟在它的後面,在這裡就是git rm --cached --ignore-unmatch password.txt
,讓git刪除掉快取的檔案,如果有匹配的話。
--prune-empty
選項告訴git,如果因為重寫導致某些commit變成了空(比如修改的檔案全部被刪除),那麼忽略掉這個commit。
--tag-name-filter
表示對每一個tag如何重新命名,重新命名的命令緊跟在後面,當前的tag名會從標註輸入送給後面的命令,用cat就表示保持tag名不變。
緊跟著的--
表示分割符,最後的--all
表示對所有的檔案都考慮在內。
預防措施
今後為了防止再次不小心將敏感資料提交,可以修改.gitignore檔案的內容,凡是成功匹配的檔案都不會被git看到,比如在本例中可以在.gitignore後面追加一行”password.txt”