SVN から Git への移行を Mac 上で行う

# はじめに

ネットにはそれなりに情報があるですが、自分のやりたいことが１箇所にまとまっていなかったので、案外サクッとできず困ったので、今後のためのメモとして残しておきます。


# 移行手順

今回は Macbook Pro の M3 で行なったものを記事にしています。Windows でも出来ないことはないと思いますが、記載したコマンドが多少違ってくるかなと思います。

まず、こちらに最初のイメージ図を置いておきます。

![img-0](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/277d7fc0-ef9d-7e7e-fd3b-11358d5d7058.png)

以後、この図を使って幾つか説明していきます。


## 0. 前置き

SVN では

- branches
- tags
- trunk

の３つがディレクトリ構成で管理することが多いと思います。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/f8ef2c00-258c-4217-b5c1-75d5032964dd.png)

今回のゴールは、リモートにある SVN で管理されたファイルを

- branches -> Git のブランチ
- tags -> Git のタグ
- trunk -> Git の main/master のブランチ

これらを Git のリモートリポジトリに反映できるまでを行います。

## 1. 必要なものをインストールする

### - Git

デフォルトで入っていると思いますが、確認のためのコマンドはこちら

```.bash
$ git --version
```

### - git-svn

これを使うことで楽に移行できます。今回は `Homebrew` で入れましたが、好きなようにインストールしてください。

```.bash
$ brew install git-svn
```

バージョン確認のコマンドはこちら

```.bash
$ git svn --version
```

こんな感じで `git-svn version 2.46.0 (svn 1.14.3)` と表示されれば OK です。

## 2. SVN を Git として Clone する

![img-2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/6b3910ea-3f76-5b98-28a1-0a877ca27128.png)

`git-svn`　のコマンドを使っていきます。
歴史が長いと clone に時間がかかるので気長に待ちましょう...

```.bash
$ git svn clone --stdlayout --no-metadata --prefix=svn/ --localtime http://YOUR_SVN_REPO
```


オプションがモリモリですが、詳しくはこちらをみてください。
必要に応じてオプションの いるもの・いらないもの は判断してください。

https://qiita.com/jz4o/items/fba03e8fa13a94814c65

SVN の構成が先に書いた branches / tags/ trunk の場合、clone したものは trunk 配下のファイルがあると思います。

## 3. 新しい Git のリモートリポジトリに反映する

すでに Git で空のリモートリポジトリを準備している想定です。

![img-3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/cfb17ef8-0447-0e66-5535-9cc6f0065842.png)


まず、Git のリモートリポジトリが設定されていないことを確認します。


```.bash
$ git remote -v
```

何も表示されないと思います。なので設定を追加します。

```.bash
$ git remote add origin https://YOUR_NEW_GIT_REMOTE_URL
```

ちなみに名前が `origin` である必要はないですが、一般的なのでそのまま使う方が良いでしょう。

もう一度確認すると

```.bash
$ git remote -v
```

以下のように表示されれば OK です。

```
origin	https://YOUR_NEW_GIT_REMOTE_URL (fetch)
origin	https://YOUR_NEW_GIT_REMOTE_URL (push)
```

最後にリポジトリへ今あるブランチのコードを反映します。

```.bash
$ git push --set-upstream origin master
```

コードが反映されているかどうかは、リモートリポジトリの管理画面を(ex GitHub, Bitbucket)を確認してください。

## 4. ブランチをリモートに反映する

SVN で開発途中のブランチがあり、移行したい場合などもあると思います。

![img-4](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/21712cba-9c9e-56f5-a7c1-af7fe4273ebe.png)


ローカルのブランチをチェックしてみましょう。

```.bash
$ git branch
```

おそらく、この段階では master しかないと思います。

リモートのブランチを確認します。

```.bash
$ git branch -r
```

そうすると SVN で作ったブランチの一覧が出てくるはずです。これをローカルの Git にも反映させていきます。

少なければブランチを１個ずつチェックアウトして（ローカルにもってきて）、push すれば良いです。

ただし、面倒だと思うので以下のスクリプトでまとめてチェックアウトすることで、ローカルに全てのブランチを持ってくることができます。

```.bash
for branch in $(git branch -r | grep -v '\->' | grep -v 'trunk' | grep -v 'tags/' | grep -v 'HEAD' | sed 's/  //g'); do
    branch_name=$(echo $branch | sed 's/svn\///')
    git checkout -b $branch_name $branch
done
```

これは先ほどの手順で `--prefix=svn/` としているため、これに当てはまらない場合は、自分で直してください。

終了後にもう一度ローカルでブランチを確認すると、一覧があるはずです。

```.bash
$ git branch
```

注意点として、コマンドを実行した結果、最後にチェックアウトしてブランチにいるはずなので、メインのブランチに戻っておきましょう。

【example command】

```.bash
$ git checkout master
```

最後にリモートの Git へ反映します。

```.bash
$ git push origin --all
```

ブランチが反映されているか、リモートリポジトリの管理画面を(ex GitHub,Bitbucket)を確認してください。

## 5. タグをリモートに反映する 

![img-5](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/9f2db326-2687-6a9e-6478-4d1663c370b2.png)


SVN において、tags はコピーしたブランチみたいなものなので、`git-svn` で clone してきた場合も、ブランチ配下に設置されます。

【example - SourceTree】

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/ff0606d5-86a1-84e6-64b3-9e0a3e9f9492.png" width=500>

これをタグとして取り出すことになります。


まずはローカルにある Git のタグを確認しましょう。

```.bash
$ git tag
```

おそらくまだ何も出ないと思います。そこで以下のスクリプトからまとめて取り出します。

```.bash
for tag in $(git branch -r | grep 'tags'); do
    tag_name=$(echo $tag | sed 's/svn\/tags\///')
    git tag $tag_name $tag
done
```

こちらも先ほどと同じく、clone 時に`--prefix=svn/` としているため、これに当てはまらない場合は、自分でコードを直してください。

終わってからもう一度確認すると

```.bash
$ git tag
```

ローカルのタグがすべて出ると思います。

【example】

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/737202ce-ad55-2577-787a-4efbe2ae194b.png" width=300>

最後にタグを全てリモートの Git に反映します。

```.bash
$ git push origin --tags
```

【example】

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/2ceae41c-6b47-1955-5c24-093859753eaf.png" width=300>

タグが反映されているか、リモートリポジトリの管理画面を(ex GitHub,Bitbucket)を確認してください。

## 6. SVN の追跡を消す

これは必要なら行ってください。

実は `git-svn` で clone したものは、SVN の追跡も生きています。たとえば SourceTree などでコードを管理した場合に「Git or SVN どちらに反映しますか？」みたいなことを聞かれてしまい煩わしいです。

なので、`.git` にある SVN 関連のものを削除していきます。

```.bash
$ rm -rf .git/svn
$ rm -rf .git/refs/remotes/svn
$ rm -rf .git/logs/refs/remotes/svn
```

![svn-ex-1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/ff88ab8b-d0aa-ae44-86cd-9dbdd030e754.png)



また、`.git/config` にある SVN 関連の設定も削除しましょう。

![svn-config](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/ce588ab0-3349-4ec5-859a-a61c2a4c3cb8.png)


最後に、以下のコマンドで何も表示されなければ、SVN の追跡はもうありません。

```
$ git config --get-regexp svn
```

何か表示された場合は、そこにあるパスを追って削除しましょう。


# 終わりに

ただコードを移行するだけなら、 clone して Git のリポジトリに突っ込むだけです。

ただ、過去の修正した背景も全部移行するなら、branches と tags への対応が必要で、うまいことまとまった記事がなくて困りました。

この記事が誰かの助けになれば幸いですmm