Git Filter Repo 使用指南 - 更安全有效率的 Git 歷史重寫工具

在 Git 的世界中,有時候我們需要修改版本歷史,例如移除大型檔案、修改作者資訊或者重新整理提交訊息。雖然 Git 內建的 filter-branch 指令可以完成這些工作,但它速度慢且容易出錯。這就是為什麼我們需要認識 git-filter-repo 這個強大的工具。

什麼是 git-filter-repo?

git-filter-repo 是一個用 Python 撰寫的開源工具,專門用於重寫 Git 版本歷史。它是 git filter-branch 的替代品,提供了更好的效能、更簡單的使用方式和更安全的操作。

主要特點

  • 執行速度比 filter-branch 快上約 50 倍
  • 使用更直覺的命令介面
  • 內建多種常用的重寫功能
  • 提供完整的程式化 API
  • 自動進行安全性檢查

安裝方式

你可以透過 pip 安裝:

1
pip install git-filter-repo

或是在 Ubuntu/Debian 系統使用:

1
sudo apt install git-filter-repo

常見使用情境

1. 移除意外推送的敏感資料

如果不小心將密碼、API 金鑰或其他敏感資訊推送到 Git 倉庫,需要立即處理:

1
2
3
4
5
# 移除包含敏感資料的檔案
git filter-repo --path-glob '*config.json' --invert-paths

# 或是移除特定檔案
git filter-repo --path 'src/config/secret.js' --invert-paths

處理敏感資料外洩時的注意事項:

  • 立即撤銷並更換所有外洩的密碼、金鑰等資訊
  • 通知相關人員或組織關於資料外洩事件
  • 檢查其他分支是否也包含敏感資料
  • 考慮使用 git-secrets 或類似工具來預防未來的意外推送

預防措施:

  1. 使用 .gitignore 排除敏感檔案
  2. 導入 pre-commit hooks 檢查敏感資料
  3. 將敏感資訊移至環境變數
  4. 使用加密的密碼管理工具

2. 移除大型檔案

當你不小心提交了大型檔案到 Git 倉庫,可以使用以下指令移除:

1
git filter-repo --path-glob '*.zip' --invert-paths

這個指令會移除所有 .zip 檔案的歷史記錄。

3. 修改作者資訊

如果需要修正作者的 email:

1
git filter-repo --email-callback 'return email.replace("old@email.com", "new@email.com")'

4. 將子目錄提升為根目錄

想要將專案中的某個子目錄變成新的根目錄:

1
git filter-repo --subdirectory-filter folder_name

使用注意事項

  1. 永遠在複製的倉庫中操作
    在使用 git-filter-repo 之前,請先複製一份原始倉庫,避免不小心損壞原始資料。

  2. 重寫是永久的
    使用 git-filter-repo 後的修改無法復原,請確保你真的需要這麼做。

  3. 需要強制推送
    修改歷史後,需要使用 git push --force 來更新遠端倉庫。這可能會影響其他開發者,請事先與團隊溝通。

  4. 移除快取
    在執行前,建議先清除 Git 的快取:

    1
    git gc --aggressive

與 git filter-branch 的比較

特性 git-filter-repo git filter-branch
執行速度 非常快 較慢
使用難度 簡單 複雜
功能完整性
安全性檢查
維護狀態 活躍 已不建議使用

進階使用技巧

自訂重寫規則

git-filter-repo 支援使用 Python 腳本來定義複雜的重寫規則:

1
2
3
4
5
6
7
8
9
from git_filter_repo import Blob, Reset

def handle_blob(blob):
# 修改檔案內容
data = blob.data
if b'old_text' in data:
blob.data = data.replace(b'old_text', b'new_text')

args.blob_callback = handle_blob

批次修改提交訊息

1
git filter-repo --message-callback 'return message.replace("[WIP]", "[DONE]")'

結論

git-filter-repo 是一個強大且高效的 Git 歷史重寫工具。它不只解決了 git filter-branch 的效能問題,還提供了更多實用的功能。只要注意使用時的安全事項,它就是一個非常好用的工具。

參考資料