バージョン管理システムである「Subversion(SVN)」の特定リポジトリを「Git」に移行したため、備忘録として残します。
この時はsvnの履歴も移行するために「git svn」コマンドを利用しました。
git-svn – Bidirectional operation between a Subversion repository and Git

なお、ユーザ情報のマッピングは未実施です。(ログのユーザ表記のマップのこと。)過去の人もいてマップは限界があったので・・・。
環境準備
aptコマンドでgit svnコマンドをインストールしておきます。
sudo apt install git-svn
※便利なコマンドがあるものです。
早速試します。
全体的な流れは次の通りです。
- チェックアウト(gitリポジトリ作成含)
- 移行対象のタグ、ブランチをローカルリポジトリに登録
- リモートリポジトリへPush
チェックアウト
SVNリポジトリからデータをチェックアウトしつつ、Gitのローカルリポジトリを作成するコマンドになります。
git svn clone -s --prefix svn/ <svnリポジトリ> <clone先フォルダ>
実行例:git svn clone -s –prefix svn/ http://localhost/svn/svn_repo1 git_repo1
この段階で「git_repo1」はgitローカルリポジトリに相当します。この後、必要なブランチやタグを登録してリモートリポジトリにpushしていきます。
svnリポジトリが標準的な構成(/trunk, /branches, /tags)である場合はオプション「s」でそのように伝えます。
svn | git |
---|---|
trun | ブランチ(名前:master) |
branches | ブランチ(名前:svnのbranches配下の各フォルダ名) |
tags | タグ(名前:svnのtags配下の各フォルダ名) |
標準構成ではあれば簡単です。
しかし、リポジトリによっては何故かsvnのフォルダ構成が適当なことがあります。例えば、trunkフォルダが無くてbranches配下がメインになっている場合など・・・。

どうしてこうなった・・・。
その場合「s」オプションではなく、個々に指定する必要があります。
オプション | 意味 |
---|---|
T | トランク |
b | ブランチ |
t | タグ |
例えば、svnの/trunkが存在せず、svnの/branchesがメインとして扱われていたリポジトリがあったとします。svnの/branches配下の内容=gitのmasterブランチの内容とするため、以下のコマンドになります。
実行例:git svn clone -T branches -t tags –prefix svn/ http://localhost/svn/svn_repo1 git_repo1
イレギュラー構成の場合、最初に構成を見極めて適切に指定しないと、何度もチェックアウトが動作して移行処理が終わらない可能性があります。
構成(trunkやbranchesなど)のマップさえ、出来てしまえば移行はクリアしたも同然です。
移行対象のタグやブランチをローカルリポジトリに登録
clone直後、タグやブランチはローカルブランチに未登録状態です。
そのため、このままpushした場合、pushされるのはmasterブランチだけになります。
そこで、
リモートブランチ/タグから対象を選ぶ必要があります。「git branch -r」だけの確認だと、過去svn上で削除済みのブランチ名やタグ名も表示されるため、下記のコマンドが便利です。
# リモートブランチ一覧を表示
for BRANCH_NAME in $(git branch -r | grep -ve 'svn/tags\|svn/trunk\|.*@\d*' | sed -e 's:svn/::'); do
echo $BRANCH_NAME
done;
# リモートタグ一覧を表示
for TAG_NAME in $(git branch -r | grep -e 'svn/tags' | grep -ve '.*@\d*' | sed -e 's:svn/tags/::'); do
echo $TAG_NAME
done;
■リモートブランチからローカルブランチを作成
git checkout -b ブランチ名 svn/ブランチ名
■リモートタグからローカルタグを作成
git tag タグ名 svn/tags/タグ名
プッシュ
git remote add origin http://<gitURL>/git_repo1.git
git push -u origin --all
git push origin --tags
補足事項
■git svnの再開や最終チェックアウト

容量が多いリポジトリの場合、移行直前に下記コマンドを実行すれば、git svn中の変更も漏れなく取り込めます。
cd gitローカルリポジトリ
git svn fetch
git svn rebase
# rebase = svn更新分をgitリポジトリに取り込み
■空フォルダ対応
gitは空フォルダを登録出来ないので、登録したい場合は「.gitkeep」ファイルを含めます。空フォルダ検索は「find . -type d -empty」で出来ます。このコマンドにxargsを組み合わせて「touch .gitkeep」を実施すれば簡単に対応できると思います。
まとめ
本記事ではSVN→Git移行として「git svn」コマンドの簡単な使い方をご紹介しました。svnのフォルダ構造が複雑な場合、しっかりとマッピングを行う必要があります。
なお、svnの履歴含めて容量が膨大な場合は、無理に履歴を移行せずに、最新状態だけgitに移行するのも選択肢の1つかなと思います。(その場合、svnはレガシーシステムとしてバックアップしておき、必要な時だけ稼働させるというのも手段の1つです。)

最後までご覧いただき、ありがとうございました。
コメント