BFGを使用するにあたって色々調べてみた
BFGとは
git-filter-branch
の代わりに使うことができる(事もある)
概要
git-filter-branchと比較して
- 10 - 720倍高速に動作する
- よりシンプル
- コードが公開されているのでカスタマイズして使用できる
使い所
- git-filter-branchのオプションが結構複雑なのでシンプルに実行したいとき
- git-filter-branchでは時間がかかりすぎて終りが見えないとき
といった感じ。
各オプションの詳細はこちら
使用してみる
BFGの実行ファイルダウンロード
# Homebrewでも入れられるらしい $ wget http://repo1.maven.org/maven2/com/madgag/bfg/1.12.14/bfg-1.12.14.jar $ java -version java version "1.8.0_102" Java(TM) SE Runtime Environment (build 1.8.0_102-b14) Java HotSpot(TM) 64-Bit Server VM (build 25.102-b14, mixed mode)
まずは検証用に適当なリポジトリを作成。
空のリポジトリを作成
# bareリポジトリ $ mkdir hoge_bare.git $ cd hoge_bare.git $ git init --bare Initialized empty Git repository in /Users/USER_NAME/Documents/bfg_test/hoge_bare.git/ # gitリポジトリ $ cd .. $ mkdir hoge $ cd hoge $ git init Initialized empty Git repository in /Users/USER_NAME/Documents/bfg_test/hoge/.git/ # bareをremoteとして登録 $ git remote add origin ../hoge_bare.git $ git remote -v origin ../hoge_bare.git (fetch) origin ../hoge_bare.git (push) # 適当な画像を置いてcommit push $ git add . $ git commit -m "initial commit" [master (root-commit) 14668fc] initial commit 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 1.png $ git push origin master (master) Counting objects: 3, done. Delta compression using up to 4 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 54.77 KiB | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To ../hoge_bare.git * [new branch] master -> master
適当にブランチを切ったりしてワークツリーを作成し、remoteにpushしておく
ここでは1コミットにpngファイルを1つコミットしている。
実際にやってみる
パターン①:特にオプションを付けない(png指定のみ)
# bareからmirrorでcloneする $ git clone --mirror hoge_bare.git hoge_test1.git $ java -jar bfg-1.12.14.jar --delete-files '*.png' hoge_test1.git $ cd hoge_test1.git $ git reflog expire --expire=now --all && git gc --prune=now --aggressive $ cd .. $ git clone hoge_test1.git hoge_result1
オプションなしの場合、HEADが指しているブランチのみプロテクトの対象となり、最新のコミットが保持される。
masterでは最初のコミットと、5番目のコミットで追加されたpngファイルが残っており、一番最初に追加した画像が5番目のコミットで追加したことになっている。
hogeブランチやfugaブランチは何も無かったことに。
masterの1番最初のコミットでの画像追加が無かったことに。
パターン②:--no-blob-protectionオプションを付けてみる
このオプションは対象ファイルを履歴上からも全て消し去る。
# bareからmirrorでcloneする $ git clone --mirror hoge_bare.git hoge_test2.git $ java -jar bfg-1.12.14.jar --no-blob-protection --delete-files '*.png' hoge_test2.git $ cd hoge_test2.git $ git reflog expire --expire=now --all && git gc --prune=now --aggressive $ cd .. $ git clone hoge_test2.git hoge_result2
消え去っている。
master以外のブランチからも削除されている。
完全に消し去りたい時はこれで良さそう。
パターン③:--protect-blobs-fromオプションを付けてみる
--protect-blobs-fromでは、プロテクトするブランチを指定できる。
master, hogeブランチをプロテクト対象にする。
# bareからmirrorでcloneする $ git clone --mirror hoge_bare.git hoge_test3.git $ java -jar bfg-1.12.14.jar --protect-blobs-from master,hoge --delete-files '*.png' hoge_test3.git $ cd hoge_test3.git $ git reflog expire --expire=now --all && git gc --prune=now --aggressive $ cd .. $ git clone hoge_test3.git hoge_result3
masterは、パターン①と同様で、masterブランチで追加したファイルが最新のコミットにまとめらている。
hogeブランチは、masterからの派生時に存在した1.png
とhogeブランチで追加した画像2つが最新のコミットでaddされたことになっている。
当然、2.png
を追加した時点のコミットは空コミットに。
fugaブランチはプロテクトの対象にしなかったので、画像は追加されない。
masterにhogeブランチとfugaブランチをそれぞれマージしてみる。
fugaブランチのコミット履歴上、何も追加していないことになっているので、fugaブランチのマージ履歴は空に。
hogeブランチのマージでは、2.png
, 4.png
が正しくマージされる。
1.png
もhogeの最新コミット履歴で追加したことになっていたけど、ここでコンフリクトなどは発生しない。
最終的なmasterブランチでは、fugaブランチで追加した画像ファイル以外の画像がちゃんと残っている。
その他注意点
- --delete-foldersはパスの区切り文字を使えず、フォルダ名のみで探して削除するので、同名のフォルダが違うパスで存在する場合、両方とも削除されてしまう。(未検証)
- 特定のフォルダ以下を対象にするといった事はできない。(未検証)
- bfg自体はかなり高速に動作するものの、その後の
git gc --prune=now --aggressive
はファイル数やサイズによっては結構時間がかかる。 - それでもgit-filter-branchより速い
- CPUコア数でかなり差が出るのでMac Book Pro 13inchとかだと結構辛い