SVNからStash(Git)へ移行

SubversionリポジトリをStash(Git)へ移行します。

準備

  • とりあえずMacで作業してます。
    • GitはHomebrewで入れたものを、Subversionではデフォルトのものを使うと良さげです。(※後述)
  • Atlassianのサイトからsvn-migration-scripts.jarを落としてきます。
    • 落としてきたらとりあえず動作確認。
$ java -jar svn-migration-scripts.jar verify
svn-migration-scripts: using version 0.1.56bbc7f
Git: using version 1.9.2
Subversion: using version 1.8.8
git-svn: using version 1.9.2
You appear to be running on a case-insensitive file-system. This is unsupported, and can result in data loss.
Cannot connect directly to internet. This may interfere with your ability to clone Subversion repositories and push Git repositories.
  • Macの場合は、ファイルシステムがダメだよという警告が出るので、以下の作業を行って移行用のディスクイメージをマウントする。
    • svn-migration-scripts.jar の create-disk-image オプションというのを使うと出来る。
    • サンプルでは5GBで書いてあったけど自分のところでは5GBでは足りないので多めにとってます。
$ java -jar svn-migration-scripts.jar create-disk-image 20 GitMigration
created: /Users/gozu/GitMigration.sparseimage
/dev/disk2              GUID_partition_scheme
/dev/disk2s1            EFI
/dev/disk2s2            Apple_HFS                       /Users/gozu/GitMigration
The disk image was created successfully and mounted as: /Users/gozu/GitMigration
  • ホームの直下に20GBのGitMigrationというのがマウントされました。
    • svn-migration-scripts.jarはとりあえずGitMigrationに置いときました。
$ cp -p ~/Downlods/svn-migration-scripts.jar ~/GitMigration/.

移行(ローカルリポジトリの作業)

$ cd ~/GitMigration
$ git svn clone -s http://www.example.com/svn/foo foo
WARNING: --prefix is not given, defaulting to empty prefix.
         This is probably not what you want! In order to stay compatible
         with regular remote-tracking refs, provide a prefix like
         --prefix=origin/ (remember the trailing slash), which will cause
         the SVN-tracking refs to be placed at refs/remotes/origin/*.
NOTE: In Git v2.0, the default prefix will change from empty to 'origin/'.
Initialized empty Git repository in /Users/gozu/GitMigration/foo/.git/
  • WARNINGはとりあえず無視しても大丈夫(たぶん)
  • ブランチやタグの移行のシミュレーションします。
    • デフォルトでdry runなので安心して試せます。
    • 移行時にauthorsのマッピングをする事もできますが、長い歴史があるリポジトリだと退職者がいたり、ライセンス数的に移行しないユーザがいたりでユーザマッピングはしないことにしました。
      • authorsは普通にテキストで出るので見ればわかるし。
      • 早く移行したいのであまり悩みたくないし。
$ cd foo
$ java -Dfile.encoding=utf-8 -jar ../svn-migration-scripts.jar clean-git
###########################################################
#         This is a dry run, add --force to commit        #
#        No changes will be made to your repository       #
###########################################################
# Creating annotated tags...
tag has diverged: b2
Creating annotated tag 'b2' at refs/remotes/tags/b2.
Creating annotated tag 'release_1_0_0' at refs/remotes/tags/release_1_0_0.
# Creating local branches...
# Checking for obsolete tags...
svn: E215004: Authentication failed and interactive prompting is disabled; see the --force-interactive option
svn: E215004: Unable to connect to a repository at URL 'http://www.example.com/svn/foo/tags'
svn: E215004: No more credentials or we tried too many times.
Authentication failed
No obsolete tags to remove.
# Checking for obsolete branches...
svn: E215004: Authentication failed and interactive prompting is disabled; see the --force-interactive option
svn: E215004: Unable to connect to a repository at URL 'http://www.example.com/svn/foo/branches'
svn: E215004: No more credentials or we tried too many times.
Authentication failed
No obsolete branches to remove.
# Cleaning tag names
# Cleaning branch names
###########################################################
#         This is a dry run, add --force to commit        #
#        No changes will be made to your repository       #
###########################################################
  • うーん、何かSubversionのエラー出るな・・・。
    • ぐぐってみたけど何かSubversion 1.8.8がいけないのかもしれないということなのでhomebrewで入れた1.8.8ではなくOS Xに付いている古い方でやってみることにする。
    • 手っ取り早くbrewの方のsvnをアンインストールしました。
$ brew uninstall subversion
Uninstalling /usr/local/Cellar/subversion/1.8.8...
$ svn --version
svn, version 1.7.10 (r1485443)
   compiled Jan 15 2014, 11:22:16
  • もっかい実行!
$ java -Dfile.encoding=utf-8 -jar ../svn-migration-scripts.jar clean-git
###########################################################
#         This is a dry run, add --force to commit        #
#        No changes will be made to your repository       #
###########################################################
# Creating annotated tags...
tag has diverged: b2
Creating annotated tag 'b2' at refs/remotes/tags/b2.
Creating annotated tag 'release_1_0_0' at refs/remotes/tags/release_1_0_0.
# Creating local branches...
# Checking for obsolete tags...
No obsolete tags to remove.
# Checking for obsolete branches...
No obsolete branches to remove.
# Cleaning tag names
# Cleaning branch names
###########################################################
#         This is a dry run, add --force to commit        #
#        No changes will be made to your repository       #
###########################################################
  • 上手くいったー!
  • それではローカルリポジトリの状態を確認します。
$ git branch
* master
$ git tag
  • masterブランチのみが存在する状態ですね。タグはありません。
  • 今度は--forceを付けて移行します。
$ java -Dfile.encoding=utf-8 -jar ../svn-migration-scripts.jar clean-git --force
# Creating annotated tags...
tag has diverged: b2
Creating annotated tag 'b2' at refs/remotes/tags/b2.
Creating annotated tag 'release_1_0_0' at refs/remotes/tags/release_1_0_0.
# Creating local branches...
# Checking for obsolete tags...
No obsolete tags to remove.
# Checking for obsolete branches...
No obsolete branches to remove.
# Cleaning tag names
# Cleaning branch names
  • もっかい、確認します。
$ git branch
* master
$ git tag
b2
release_1_0_0
  • ブランチとタグが出来ました!
    • SVNにブランチがなかったのでmasterブランチだけですがブランチがあればちゃんとGitのブランチに変換されます。

移行(リモートリポジトリへPush)

  • Stashの方に移行用プロジェクトとしてmigrationプロジェクトを用意したので、そこにリポジトリ作成します。
    • StashのWeb画面から作成すると、URLが表示されます。
    • 作ったリモートリポジトリをローカルリポジトリに登録しましょう。
$ git remote add origin http://username@stash.example.com/scm/migration/foo.git
  • まずはブランチをPushします。
    • 今回はSVNでブランチを切ってなかったのでmasterブランチだけですが、ブランチがあればすべてPushされます。
$ git push -u origin --all
Counting objects: 996, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (444/444), done.
Writing objects: 100% (996/996), 16.37 MiB | 4.82 MiB/s, done.
Total 996 (delta 449), reused 988 (delta 446)
To http://username@stash.example.com/scm/migration/foo.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.
  • うまくいきました。
    • でかすぎるリポジトリでエラーが出た時はSSHでPushすると上手くいくこともあります。
  • ではタグもPush。
$ git push --tags
Counting objects: 93, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (73/73), done.
Writing objects: 100% (91/91), 25.89 KiB | 0 bytes/s, done.
Total 91 (delta 22), reused 37 (delta 12)
To http://username@stash.example.com/scm/migration/foo.git
 * [new tag]         b2 -> b2
 * [new tag]         release_1_0_0 -> release_1_0_0
  • これで出来ました!

Gitへ移行した後でSubversionにコミットしてしまった場合

  • SubversionをRead Onlyにしておけばいいのですがそうも行かない時もあるでしょう。
    • その時は差分をPushする事ができます。
$ cd ~/GitMigration
$ cd foo
$ git svn fetch
$ java -Dfile.encoding=utf-8 -jar ../svn-migration-scripts.jar sync-rebase
$ java -Dfile.encoding=utf-8 -jar ../svn-migration-scripts.jar clean-git --force
  • これでローカルのgit svnは最新になったので、今度はpushします。
$ git push -u origin --all
$ git push --tags

注意:ブランチとタグが移行できなくなった

  • しばらくして別のリポジトリを移行しようと思ったらブランチとタグの移行がうまく行かなくなりました。
    • 色々考えるとbrew upgradeしてgitが2.0に上がったのが怪しいと推定。
    • homebrewでgitのバージョンを切り替えてみます。
$ brew switch git 1.9.2
Cleaning /usr/local/Cellar/git/1.9.1
Cleaning /usr/local/Cellar/git/1.9.2
Cleaning /usr/local/Cellar/git/2.0.1
208 links created for /usr/local/Cellar/git/1.9.2
  • 移行してみましょう。
$ git svn clone -s http://www.example.com/svn/test test
$ test
$ java -jar ../svn-migration-scripts.jar clean-git --force
# Creating annotated tags...
Creating annotated tag 'TestTag' at refs/remotes/tags/TestTag.
# Creating local branches...
Creating the local branch 'release-test1' for Subversion branch 'refs/remotes/release-test1'.
# Checking for obsolete tags...
Deleting Git tag 'TestTag' not in Subversion.
Deleted tag 'TestTag' (was 697cc52)
# Checking for obsolete branches...
No obsolete branches to remove.
# Cleaning tag names
# Cleaning branch names
  • あ、やっぱり・・・

移行が終わってからgitを2.0に戻そうかな。