大きなファイルや認証キーを Git にコミットした場合に履歴を削除する - bfg-repo-cleaner
インストール
BFG は Java で開発されており、JRE Java 8 以上が必要で、jar ファイルとして配布されている。
jar バイナリは Maven Central に保存されているため、次のコマンドで取得するか、ブラウザから直接アクセスしてダウンロードできる。
$ curl -o bfg.jar -L https://repo1.maven.org/maven2/com/madgag/bfg/1.14.0/bfg-1.14.0.jar
使い方
リポジトリを clone する
まず、次のように --mirror フラグを指定してリポジトリの新しいコピーを clone する。
$ git clone --mirror git://example.com/some-big-repo.git
この方法で clone すると、そのリポジトリはベアリポジトリになるため通常のファイルは表示されないが、リポジトリの Git データベース全体のコピーになる。万一に備えて、この時点でバックアップしておく。
リポジトリを整理する
次に BFG を実行してリポジトリを整理する。
$ java -jar bfg.jar --strip-blobs-bigger-than 100M some-big-repo.git
この例では大きなファイルを削除する方法を示している。機密ファイルの削除や、機密情報を含むコミット履歴の変更は、下の使用例を参照する。
変更内容をリポジトリへ反映する
BFG はコミット、すべてのブランチ、タグを更新するが、不要なオブジェクトを物理的には削除しない。リポジトリを確認して履歴が更新されていることを確認したら、標準の git gc コマンドで不要な dirty data を削除する。
$ cd some-big-repo.git
$ git reflog expire --expire=now --all && git gc --prune=now --aggressive
リモートリポジトリへ反映する
最後に、更新後のリポジトリの状態に問題がなければ再度 push する。clone 時に mirror フラグを使っているため、この push はリモートサーバー上のすべての --mirror 参照を更新する。
$ git push
すべて新しい clone に置き換える
これで、全員の古いリポジトリコピーを削除し、新しい clone に置き換えればよい。古い clone から新しく整理したリポジトリへ dirty history が再投入される危険があるため、以前の clone はすべて削除するのが望ましい。
使用例
機密ファイルを削除する
ファイル名が id_rsa または id_dsa の SSH 秘密鍵ファイルをすべて削除する。
$ java -jar bfg.jar --delete-files id_{dsa,rsa} my-repo.git
大きなファイルを削除する
50 MB より大きいすべての Blob (Binary Large Object) を削除する。
$ java -jar bfg.jar --strip-blobs-bigger-than 50M my-repo.git
機密情報を含むコミット履歴を変更する
認証キーやパスワードなどの機密情報を含めてコミットしてしまった場合は、bfg コマンドの -rf, --replace-text {filename} オプションで削除できる。
$ java -jar bfg.jar --replace-text passwords.txt my-repo.git
ファイルに列挙したすべての秘密文字列に regex: を接頭辞として付けると正規表現として扱える。デフォルトでは秘密文字列は ***REMOVED*** に置換される。
passwords.txt の例は次のとおりである。
PASSWORD1 # Replace literal string 'PASSWORD1' with '***REMOVED***' (default)
PASSWORD2==>examplePass # replace with 'examplePass' instead
PASSWORD3==> # replace with the empty string
regex:password=\w+==>password= # Replace, using a regex
regex:\r(\n)==>$1 # Replace Windows newlines with Unix newlines