git filter-branchでリポジトリの歴史の書換え、ディレクトリ構成を移動、変更、削除する方法をまとめました。
目次
git filter-branchとは
例えば、以下の構成のGitのリポジトリがあったとします。
1 |
Repository --+-- A1 --+-- B1 --+-- C1 |
ここで、A1、B1、C1はそれぞれディレクトリです。
この構成を以下に変更したいとします。
1 |
Repository --+-- B1 --+-- C1 |
ただし、条件として、最初からA1存在せずに、最初からB1がリポジトリのプロジェクトルートにあったかのようにしたいです。
バージョン管理システムでは、歴史を保持しているので、過去をなかったことにするのは、基本 NG です。
ただし、Git には、歴史の書き換えをサポートする強力なコマンド、git filter-branchというコマンドが存在します。
git filter-branch は、歴史を書き換えてくれる、最強のコマンドです。
上記のケースの場合、以下のコマンドを実行します。
1 |
$ git filter-branch -f --subdirectory-filter A1/B1/ -- --all |
このようにすることで、A1に代わってB1が新たなプロジェクトルートになります。
リポジトリのログを見てみても、あたかもA1は最初から存在せずに、B1が最初からプロジェクトルートであったかのように見えます。
当然ですが、これを実行したら、もはや元には戻れません。
もちろん、もう一度、git filter-branch を使えば、元には戻れますが。
そのため、最新の注意を行って実行する必要があります。
複数のディレクトリ構成を変更して失敗する
次に以下のケースを考えてみます。
1 2 3 |
Repository --+-- A1 --+-- B1 --+-- C1 + +-- A2 --+-- B2 --+-- C2 |
このディレクトリ構成を以下のように変更してみたいとします。
1 2 3 |
Repository --+-- A1 --+-- C1 + +-- A2 --+-- C2 |
先ほど使った、git filter-branch のオプションである
subdirectory-filter は、残念ながら、
1つのディレクトリしか抽出してくれません。
そこで、tree-filter というオプションを使ってみます。
1 2 3 |
$ git filter-branch --tree-filter 'mv A1/B1/C1 A1' HEAD Rewrite xxxx(1/206)mv: cannot stat 'A1/B1/C1': No such file or directory tree filter failed: mv A1/B1/C1 A1 |
Rewrite xxxx(1/206)mv: cannot stat ‘A1/B1/C1’: No such file or directory
tree filter failed: mv A1/B1/C1 A1
うーん、エラーが表示されました。
複数のディレクトリ構成を変更に成功した方法
その後、なかなか解決できません。
仕方がないので、Stack Overflowに質問してみました。
Stack OverflowはIT系のエンジニアなら誰でも知っている質問コミュニティサイトです。
2014年12月には日本語版もオープンしていますが、まだまだコミュニティとしては未成熟なので本家に質問してみます。
どうやら意味が通じず
「変更したい構成にして、そのままコミットしたらいい」
とか返事が返ってきました。
結局、解決できません。
一日、トライして以下のコマンドで、うまくいくことが分かりました。
1 |
$ git filter-branch --tree-filter "ls A1/B1 | xargs -i -t mv A1/B1/{} A1 | sh" HEAD |
イマイチ、納得できないのと、エレガントではないけれど、これでうまくいったので良しとします。
git filter-branch の応用例として巨大なSubversionのリポジトリを分割してGitに移行しました。
まとめ git filter-branchによる歴史の書き換え
私は、VCS(バージョン管理システム) については、これまで、
SCCS (Source Code Control System) 、
VSS (Microsoft Visual SourceSafe) 、
CVS (Concurrent Version System、コンカレントバージョンシステム) 、
Subversion (サブバージョン)、
Git (ギット)
と使ってきました。
その中でも、歴史を書き換えるコマンドがあるバージョン管理システムと出会ったのは、Gitが初めてです。
それぐらい、git filter-branch は衝撃的なコマンドでした。
ただ、使い方によっては、とても危険なので慎重に使わないといけません。
とは言え、過去をなかったことにして、リポジトリの再構成が出来ることは、サーバー管理者にとって、とても便利です。
これで巨大なリポジトリでも手軽に階層構造を操作することができます。
Gitについてのおすすめの本
↓Gitについてのおすすめの本はコチラ
コメント
[…] […]