目的
Trac+Subversion, Redmine+Subversion/Git, GitLab CE などを時代に合わせてオンプレで運用してきたが、サーバーの管理・維持などの関係もあり、Trac+Subversion は廃止し、GitLab あるいは Redmine+Git に移行したくなってきた。
ところで、10年以上前に、CVS で運用していたリポジトリーを cvs2svn1 により SVN に移行したことがあるが、この記事を書くのにGitHubに移行されたものを見ると、SVN だけでなく Git/Mercurial/Bazaar にも移行できるっぽい。VSS=Microsoft Visual SourceSafeで運用していたリポジトリーは闇に葬った…。(余談)
参考
- Pro Git book - 9.2 Gitとその他のシステムの連携 - Git へ移行する
- git-svnでSVN→Gitへの移行をやってみたログ
基本的に Pro Git book の手順や上記 Qiita 記事やブログ記事などで見つかるもので良いと思うのだが…
実際の移行とハマったところなどを記載していく。
SVNディレクトリー構成
いわゆるtrunk
,branches
,tags
のスタンダードレイアウト。基本的にこれで運用していたので良かった。もちろんプロジェクト毎に別のSVNリポジトリーとして分離していた。
たとえば、 Apache Software Foundationの様に全社のプロジェクトが同一SVNリポジトリーにフラットにぶら下がっている様なものや、trunk
,branches
,tags
を使わない独自形式だと、git svn
のオプション指定も異なってくるはず。
環境
あんまり関係なさそうだけど一応。
- 移行元: Subversion
- CentOS 7 + Subversion 1.7.14 (r1542130) (標準 RPM package)
- 移行作業: git-svn
- macOS 10.15.5 + git-svn 2.27.0 (svn 1.10.4) (brew版 git)
- 移行先: Git
- CentOS7 + GitLab CE 13.1.4 (Omnibus package版)
移行手順
生SVNリポジトリーの入手
外部のSVNホスティングサービス利用ならまだしも、自分がSVNサーバー管理者だっり、他のSVN管理者でもgit-svnで移行するということならその管理者の協力が得られるはずなので、生のSVNリポジトリーをローカルにコピーして作業するのが良いと思われる。
Pro Git Bookや各種記事には次のようなコマンド例があり(時代的に2016に終了した、Google Code2のSVNからの移行でしょうか?)
$ git svn clone http://my-project.googlecode.com/svn/ \
--authors-file=users.txt --no-metadata -s my_project
この、http(WebDAV)のリモートからの取得で失敗することが多いので、git svn init
してから git svn fetch
し、失敗した場合そのリビジョンから git svn fetch -r1234:HEAD
にて再開するという記事が多いですが、生のリポジトリーが入手できるなら、ローカルで完結させたほうが絶対楽です。いまだにcommitされ生きているSVNリポジトリーならこの限りではないですが…結局どこかのタイミングで運用停止して変換するでしょうし…
以下、/var/lib/svn/myproj
にSVNプロジェクトがあるものとして話をすすめます。
authors 一覧ファイルを作る
ここは基本的に Pro Git Book の通りです。
SVN は http などの認証ユーザー名が Author になるが、Git の場合は、 user.name
と user.email
が Author になるのでその変換テーブルが必要。
いや、cvs2svn
なんかで変換した年代物のリポジトリーなんて、遠い昔にそんなヤツいた?ってのをみんなに聞いたり、誰かを辿るのにすごく時間がかかる面倒くさい作業。まあ、わからなければ適当な名前とメールアドレスを入れちゃえばよいのですが…。
チェックアウト
$ svn checkout file:///var/lib/svn/myproj myproj-svn
抽出
$ cd myproj-svn
$ svn log --xml | grep author | sort -u | \
perl -pe 's/.*>(.*?)<.*/$1 = /' > /tmp/myproj-authors.txt
username1 =
username2 =
.
.
というファイルができるので
username1 = Taro Yamada <taro@example.com>
username2 = Hanako Toire <hanako@example.com>
.
.
svn checkout
したワーキングコピーはAuthor一覧を抽出するだけなのでここで消しても良い。
実際の移行
いろいろなところに書かれている事例の通り、自分もhttps://
でやったことがあるがリビジョン数やタグ・ブランチの少ないテスト用のリポジトリーでは成功するが、実運用しているリポジトリーに関しては何度も失敗しました。前に書いたとおり、ローカルに持ってきて、file:///
でやるとネットワークの影響がなく成功しているのか?しかし、ローカルでもとても時間がかかります。
$ git svn init file:///var/lib/svn/myproj/ --no-metadata -s myproj
$ cd myproj
$ git svn fetch --authors-file=/tmp/myproj-authors.txt
--no-metadata
はcommit logにgit-svn-id
を付与しないためにつけています。そもそも、file:///var/lib/svn/myproj/
とローカルのリポジトリを指定しているのでgit-svn-id
にローカル情報が見えてかっこ悪くなるし、そもそもGit移行後は不要な情報と自分は判断しました。
タグとブランチの変換
Pro Git bookでは、
タグを Git のタグとして扱うには、次のコマンドを実行します。
次に、refs/remotes 以下にあるそれ以外の参照をローカルブランチに移動します。
と言うところの方法として、.git/
ディレクトリの中をcp
,rm
にて操作しているが、自分の環境ではこれで失敗しました(24時間以上変換にかかったGitリポジトリーをバックアップ取らずに台無しに…)。~~ちょっと情報元のスニペットのリンクは失念したけど、~~参考として載せたgit-svnでSVN→Gitへの移行をやってみたログの次の方法で成功しました。
ブランチ
$ for BRANCH_NAME in $(git branch -r | grep -ve 'origin/tags\|origin/trunk\|.*@\d*' | sed -e 's:origin/::'); do
git checkout -b "$BRANCH_NAME" "origin/$BRANCH_NAME"
done;
$ git checkout master
タグ
$ for TAG_NAME in $(git branch -r | grep -e 'origin/tags' | grep -ve '.*@\d*' | sed -e 's:origin/tags/::'); do
git tag "$TAG_NAME" "origin/tags/$TAG_NAME"
done
リモートリポジトリーへのpush
こちらは、普通の方法。GitLabにpushしたが何でも良いかと。
$ git remote add origin git@gitlab.example.com:mygroup/myproj.git
$ git push -u origin --all
$ git push -u origin --tags
つづく
SVNのリポジトリー形式により、変換したGitリポジトリーを更に変換操作した場合もあったので、その点を書くかも。→ いまさらだけどSubversionからGitへ移行する(その2)
-
2020-07-01に閉鎖につきWebArchiveのリンク ↩