コミット履歴からファイルを削除する - Git による版管理環境を構築する
SPECIAL
コミット履歴からファイルを削除する
公開したいリポジトリにパスワードを含んだファイルが過去にコミットされていたりするときなど、稀にコミット履歴から消去したいものが出てきたりします。
版管理の面で言えば、コミットから履歴が消えるというのは好ましくないと思いますけど、事情によってはどうしてもということも稀にあり、git ではそういったことも出来るようになっています。
コミット履歴からファイルを削除する
たとえば、password.txt というファイルをコミット履歴から消去したい場合は、次のようにします。
git filter-branch --index-filter 'git rm --cached --ignore-unmatch password.txt' HEAD
このようにすることで、全履歴をさかのぼって、コミット履歴から 'password.txt' を削除することができました。
コミット履歴から削除するのが "filter-branch" コマンドの "--index-filter" オプションで、それに続くコマンドで、削除する内容を指定しています。
続くコマンド内で "--ignore-unmatch" オプションを "git rm" コマンドに対して指定していますが、これは、指定したファイルが存在しなかった場合に "fatal: pathspec 'password.txt' did not match any files' というようなエラーで中断されないようにするためのものです。
指定する削除対象がディレクトリの場合は、"git rm" コマンドに "-r" オプションを追加して、内容をすべて削除するように指定します。
過去にコミットされたファイルの内容を置き換える
コミット履歴からファイルを削除するだけでなく、特定のファイルの内容を書き換えることもできます。
git filter-branch --tree-filter 'sed -i /^PASSWORD=/d password.txt' HEAD
それには "filter-branch" コマンドの "--tree-filter" オプションを使用して、それに続くコマンドで編集方法を指定しています。
ここでは "sed" コマンドを使用して、password.txt ファイルの内容を調べ、"PASSWORD=" から始まる行を削除するということをしています。
コミットに残したコメントを一括編集する
コミット時に入力したログメッセージを調整することもできます。
git filter-branch --msg-filter 'sed -e "s/Password/Text/"' -f HEAD
コメントを編集したい場合は "filter-branch" コマンドの "--msg-filter" オプションを使用します。
続けて "sed" コマンドを指定して、どんな条件のテキストをどう変換するかを指定しています。たとえば今回の場合は "Password" というテキストを "Text" に置換しています。
ただし、このようにした場合、実際には新たなコミットとして記録されているようです。
コメントを書き換える前のコミットは "git log --all" としないと表示されないのですけど、逆にそうしてしまうと、過去のコメントが見れてしまいます。
コメントを書き換えたリポジトリを push する際には、"--all" としないと見れない部分は push されないらしいので、ローカルリポジトリの場合はこれで問題ないようです。
ただ、このリポジトリを直接見える位置に配布するなどで、古いコミットも完全に消したい場合には、続けて次のようにすると良いらしいのですが、このようにしても自分の環境では "git log --all" でログが見えてきてしまいました。
git gc --prune=now
通常は、このようにすれば、到達できないコミットなどを掃除してくれるらしいです。
修正したコミット履歴でリモート先を上書きするには…?
コミット履歴を編集できたところまではいいのですけど、それをリモート先にプッシュするのが、どうにも上手く行きませんでした。
git push origin master --force
方法としてはこのようにすれば、履歴の編集内容を強制的に更新できるらしいのですけど、このようにしてみても、次のようなエラーメッセージが表示されてしまいました。
![rejected] master -> master (non-fast forward)
error: failed to push some refs to ''こういうエラーを回避(強制上書き)するための "--force" だと思うのですけど、なぜか上手く行きませんでした。
結局のところ、クローン側ではなくリモート側のベアリポジトリで "git filter-branch" を実行してコミット履歴を編集して pull することで対応できましたけど、リモート側を操作する権限がない場合には、どうするのが良いのでしょうね。
ちなみに、他のブランチにもファイルが残っている場合、不要なブランチであれば削除しておく必要があるようです。
git branch -d BRANCH_FOR_DELETE
git push origin :BRANCH_FOR_DELETE
このような感じで、各所に存在する残したくない情報を手間をかけて消して行けば、コミット内から不都合なファイルを削除することができました。
【目次】