有時候當我們在寫程式碼時會用到一些 API 金鑰,或是個人的帳號、密碼,這些都是屬於「敏感資訊」,一旦不小心 Push 出去,可能會受到有心人士的利用。所以當不小心把重要個資、機密文件傳出去時,請先改密碼!改密碼!改密碼!後續再來找解決辦法,這樣才是保護資料的首要之責。
改完密碼、確保密碼重設之後,接下來可以思考如何從 Git 中將這些資料給移除。
將檔案 Push 之前都會先經過 Commit 將檔案提交到儲存庫,而這些紀錄都是被存在 .git 目錄之中。
因此我們可以對 .git 進行動作,將 Commit 的資料都給刪除。
執行步驟:
將 .git 目錄刪除 → 如此一來檔案就不再被 Git 掌控了!
將原先有保留重要機密資料或帳號密碼的檔案刪除/修改。
重新再 Commit 一次新的版本。(重新進行版本控制流程)
$ git init # 進行版本控制(此時就會有 .git 目錄產生)
$ git add . # 將檔案加至暫存區
$ git commit -m"紀錄訊息" # 提交檔案至儲存庫
⚠️要注意的是:
一但將 .git 目錄移除時,同時也代表之前所有的 Commit 紀錄也一併刪除。
也許這樣並不是最好的辦法,但它是其中一個選擇。
假設今天只是單純是你個人的練習、本地端的操作,或是專案只有你一人負責,那麼不妨可以參考這個做法。
上面的方法提到會將整個 .git 目錄刪除,同時代表整個 Commit 紀錄也會被刪除。
但是今天如果你是團隊分工,這份專案的 .git 是不能夠隨便刪除的,或者已經被 Push 出去到遠端,那麼方法一就不太適合,這時候可以考慮接下來的做法。
filter-branch
指令filter-branch
- 可以一次修改大量 Commit
$ git filter-branch --tree-filter "rm -f 檔案名稱"
🛠實際操作
filter-branch
指令
狀況|假設今天我是將「敏感資訊」存在 insex.html 內,但我將它 Commit 出去,我想把有關於 insex.html 的 Commit 紀錄移除掉。
目前 git_practice 目錄下有的檔案:
執行指令來移除 Commit:
$ git filter-branch --tree-filter "rm -f insex.html"
得到的回饋訊息:
Rewrite 0e915cf76c1822389d8ab862fe0e70d1faeed313 (4/4) (0 seconds passed, remaining 0 predicted)
Ref 'refs/heads/one' was rewritten
回到 git_practice 目錄可以看到 insex.html 檔案不見了。
如此一來之前 Commit 紀錄裡若有 Iinsex.html 這個檔案,都會一併被移除掉,不再 Commit 裡。
👉 指令說明:
--tree-filter
這個篩選參數,意思是可以讓你在切換/檢查(Checkout)到每個 Commit 時執行指定的指令,執行完後再自動 Commit 新的版本。Ref 'refs/heads/one' was rewritten
這些訊息,這意思是 Git 將你之前的狀態備份一份在 .git/refs/orignal/refs/heads/one
這個目錄裡,或是也可以說是備份開始進行 filter-branch 之前的 HEAD 的 SHA-1 值。👉 透過第四點的說明可以了解到,我們擁有之前的 HEAD 的 SHA-1 值,所以當如果我們後悔剛才所執行的 filter-branch 指令時,可以使用以下指令來回復:
$ git reset refs/orignal/refs/heads/one --hard
如此一來就可以取消先前的動作囉!
如上述提到的,即使我們執行了指令, Git 還是會自動幫你備份,讓你有辦法救回。
所以進來 Git 容易,想要離開卻很難啊!
那麼有沒有什麼辦法可以真正地將檔案從 Git 中移除呢?
移除整個 .git 目錄
因為 Commit 紀錄都在 .git 目錄中,直接砍掉重練是最快的方式,但之後還需要重建一次。
使用 Rebase 或 filter-branch 指令整理
Rebase
- 適用於只有少量的 Commit,可以直接進行編輯、重整。filter-branch
- 可以大範圍對每個 Commit 執行某個指令,並於修改完後自動重新 Commit。先前執行 filter-branch 指令依然會保留備份的檔案在其他處,因此我們可以加上 -f
參數,意指強制覆寫 filter-branch 的備份點。
👉加上 -f
參數:
$ git filter-branch -f --tree-filter "rm -f 檔案名稱"
執行 filter-branch 指令後,可以成功將檔案移除掉,但是我們還有一些需要做的事情,才能將檔案全部斷乾淨。
👉移除備份點 - rm
指令
$ rm refs/orignal/refs/heads/one
👉Reflog
$ git Reflog expire --all --expire=now
此指令是因為 Git 有個資源回收的機制,預設是要等 30 天才會整個移除檔案。因此這裡的指令是要要求 Reflog 立刻過期。
接著可以使用 git fsck
指令看到我們先前移除掉的檔案,這些都變成 Unreachable
狀態的檔案。
$ git fsck --unreachable
Unreachable
是指在 Commit 與分支中沒有一個連結點可以到達的檔案。
得到 Unreachable
狀態的檔案後,啟動資源回收機制,呼叫垃圾車來將檔案載走,如此一來就成功地將檔案完完全全地從 Git 中脫離控制啦!
$ git gc --prune-now
整理流程:
git filter-branch -f --tree-filter "rm -f 檔案名稱"
rm refs/orignal/refs/heads/one
git Reflog expire --all --expire=now
git gc --prune-now
友善提醒跟我一樣採坑的人XD
1.本來以為只要檔案名,結果刪不掉,所以還要路徑git filter-branch -f --tree-filter "rm -f 路徑+檔案名稱"
2.路徑有錯字,然後沒切到.gitrm .git/refs/original/refs/heads/分支名稱