git filter-branch
gitのリポジトリに、パスワードやAPI KEYのような秘匿性の高い情報を突っ込んでしまい後から消したいと思った際は、git filter-branch
が使えます。filter-branchは、いままでの全commitを舐めて、ヤバい情報を歴史から抹消します。
[参考] git最強のオプション filter-branch
http://qiita.com/Spring_MT/items/f60c391b5dbf569a1d12
注意
- コミットの多いリポジトリの場合、git filter-branchは時間とリソースを食う処理なので注意しましょう。EC2のデカいインスタンスを一時的に立ててそこで処理を走らせるのもいいでしょう。
- 過去のコミットをhashを含めすべて書き換えるため、filter-branch後は既存ブランチに対して
git push
が出来なくなります。一度、ローカルのrepoを消してから、再度cloneする必要があります。事前にメンバーへの周知をしておきましょう。 - .gitを捨ててrepoを作りなおしたほうが手っ取り早いケースもありそう
作業領域の確保
適当にdirectoryを掘って、対象のrepoをgit cloneしておきましょう
mkdir filterbranch && cd filterbranch
git clone git@github.com:someone/coolrepo.git
cd coolrepo
処理ブランチを減らす
事前に扱うブランチを減らせるなら減らしておきましょう。以下コマンドでmerge済のremote branchを消去できます
git branch -a --merged | grep -v master | grep remotes/origin| sed -e 's% *remotes/origin/%%' | xargs -I% git push origin :%
[参考] Gitでリモートのマージ済みのブランチを一括削除する
http://qiita.com/fukayatsu/items/b1a5e1c0b98acaa6261d
置換スクリプトを書く
各コミットで実行したいscriptを書きます。パスワードのハードコードを環境変数などにreplaceするような内容が想定されます。簡単な内容なら、sedのワンライナーを用意しておけば充分でしょう。
Dir.glob("config/*.rb").each do |file|
fr = File.open(file,"r")
buf = fr.read
buf.gsub!("some_yavai_apikey", "ENV['API_KEY']")
buf.gsub!("some_yavai_secret", "ENV['API_SECRET']")
fw = File.open(file,"w")
fw.write(buf)
fr.close
fw.close
end
すべてのremote branchをlocalにcheckoutしておく
filter-branchの対象にするため、remote branchを引っ張ってきます
$ git branch
* master
#!/bin/bash
for branch in `git branch -a | grep remotes | grep -v HEAD | grep -v master `; do
git branch --track ${branch#remotes/origin/} $branch
done
$ git branch
update-hoge
remove-fuga
refactor-foo
* master
tweak-test
[参考] [Git]リモートブランチを全て pull する
http://wada811.blogspot.com/2014/06/git-pull-all-remote-branches-locally.html
すべてのbranchでfilter-branchを実行
スクリプトをtree-filterに食わせます。
--allオプションですべてのブランチが対象になります
分かりにくいのですが、ハイフン2つのあとに、--all
を付けます
git filter-branch --tree-filter "ruby /somewhere-outside-repo/replace.rb" -- --all
時間がかかりそうなら、nohup
と&
の間に挟んでbackground動作させて一晩寝かすとよいでしょう
push
終わったら、全branchをgit push -f
して上書きしましょう。
git checkout master && git push -f origin master
git checkout update-hoge && git push -f origin update-hoge
git checkout remove-fuga && git push -f origin remove-fuga
git checkout refactor-foo && git push -f origin refactor-foo
git checkout tweak-test && git push -f origin tweak-test
お疲れ様でした! もっとスマートなやり方がある気がしますね