これまで使っていた会社のSubversionをGitへ移行した時の備忘録。
移行の際、リポジトリの分割作業も行ったので合わせてまとめる。補足情報は箇条書きで記載している。
SVNからGitへ移行
SVNからの移行は、GitにSVN連携用のgit svnコマンドが用意されている。基本的な流れは以下。
- git svn initでSVNと連携したGitのリモートリポジトリを作成。
- git svn fetchでSVNからデータを取り出し。
- 途中Warrningで処理がストップした場合は、git pruneの後に再度git svn fetchで再開する。
- 全てfetchし終えたら、git gc --aggressiveでガーベジコレクトする。
まずは、initとfetchから。
$ git svn init --no-metadata --trunk=/ (SVNリポジトリのパス) (Gitリモートリポジトリのパス)
$ git svn fetch
- 上記のコマンドを一括で行える、git svn cloneコマンドもあるが、移行処理中に失敗した為、今回は使用しなかった。
- --trunkオプションは、SVNのリモートリポジトリがルート直下に展開されたtrunkしか無かった為、そのままルート(/)を指定。
- --no-metadataは、SVNのメタ情報を含めない為に指定。
fetch中にWarrningが出ることがあるので、その時はgit pruneを使って綺麗にする。
$ git prune
$ git svn fetch (止まった所から再開される)
全て取得し終わったら、git gc --aggressiveコマンド(ガーベジコレクト)で、圧縮する。
git gc --aggressive
git log で正常に移行されているかを確認し、問題なければ移行完了。
- 再度git svn fetchでSubversionのコミットを反映させる場合は、git svn fetchの後に、git merge --no-ff (リモートのパス名)で可能。
リポジトリから特定のディレクトリを履歴ごと削除
移行作業の本当の闘いはこれからである。なぜなら、私の会社のSVNリポジトリは9GBほどに及ぶ為、このまま使うとGitのお手軽さが完全に失われる。(cloneに30分かかるとか...)
なので、まずはGitに移行したリポジトリ内で分割できそうなところは分けることにした。
例)repos.git内のarchiveディレクトリを、archive.gitとして別リポジトリに分割
+ repos.git
+ archive
+ web
+ database
+ …
+ repos.git
+ web
+ database
+ …
+ archive.git
+ archive
- Gitの共有リポジトリから作業スペースにclone
- git filter-branch を使って、履歴ごとファイルを削除
- 後は別途共有リポジトリを作り、そこへpushする
- 分割したいリポジトリ分、これを繰り返す。
- 1.の作業スペースは、ある程度スペックの高いLinuxサーバで行うことをお勧めする。git filter-branchコマンドは重い処理かつリポジトリが大きいほど時間がかかるので...。
- filter-branchにはちょっとした癖があったので以降で詳しく記載。
- git filter-branchを使うと、SVNからのfetchができなくなる為、リポジトリの分割は移行の最終段階で行う必要がありそう。
まずは、clone。
git clone http://hoge.com/git/(リポジトリ名).git
次にgit filter-branchをするが、長時間の処理が予想される為、nohupコマンドで出力をログファイルに吐き、なおかつ末尾に「&」を付けてバックグラウンドで実行できるように。
nohup git filter-branch -f --tree-filter "rm -f -r (削除ディレクトリ)/" HEAD >> /(workspace)/out.log &
- まずは、--tree-filterオプションを付けて削除する。
- ディレクトリを指定する際は、末尾に'/'を入れる。また、スペース区切りで複数指定可能。
- 実行時は、nohupコマンドで標準出力をログファイルに指定する。(ターミナルソフトからのSSHが切れるとプロセスが消える為)
- 進捗状況を確認するなら、tail -f /(workspace)/out.logで何時でも確認可能。
上記処理の後、再度git filter-branchを、次は--index-filterオプションを付けて、履歴を削除する。
nohup git filter-branch -f --index-filter "git rm -rf --ignore-unmatch (削除ディレクトリ)/" --prune-empty >> /(workspace)/out.log &
- 通常は--tree-filterか--index-filterのどちらか実行するだけで良いはずなのだが...。
- --ignore-unmatchオプションは、当てはまる対象がない時のエラーを無視できる。
- --prune-emptyオプションは、commit logから消した時に生まれうる、コメントのみの空commitも消してくれる。
リポジトリの階層構造変更
SVNからの移行作業及び、リポジトリの分割までできたのでこれにて[~完~]といきたいところだが、そうは問屋がなんとかである。
リポジトリを分割した際、ディレクトリの階層構造を変更したい(というより、階層を1段上げたい)ことがあるはず。そんな几帳面さんの為に、階層構造の変更についてもまとめる。
例)archiveディレクトリ内のディレクトリやファイル達を、archive.git直下へ移動。
+ archive.git
+ archive
+ dir1
+ dir2
+ …
+ archive.git
+ dir1
+ dir2
+ …
と言っても、以下のコマンドを一発実行すれば良いだけである。
git filter-branch -f --subdirectory-filter (dir) -- --all