SVNからGitへの移行（理想的な構成じゃないとき）


#はじめに
SVNから履歴ごとGitにデータ移行することありますよね。

**ふつうは案外簡単らしいです**
　　[git-svnでSVN→Gitへの移行をやってみたログ](https://qiita.com/hidekuro/items/4727715fbda8f10b6b11)

**ただしSVNが理想的な構成じゃなかった**
　　・svnプロジェクトが大きすぎる（今回移したいのは一部）
　　・ブランチとトランクがあまり意識されてない
　　・ブランチで分岐せずに新規コードとしてコミットされたものも取り込みたい

**そこでいろいろ調べてこんな感じでやりました**
　　１．SVNプロジェクトの一部をそれぞれ別のGitリポジトリとして取得
　　２．取得したGitリポジトリを'接ぎ木'する

###具体的には以下のとおり

#1. authors.txtを作成(ファイル名は任意)
以下のような形式でユーザの対応関係を示します。

```authors.txt
(SVNユーザ名1) = (Gitユーザ名1) <(Gitメールアドレス1)>
(SVNユーザ名2) = (Gitユーザ名2) <(Gitメールアドレス2)>
```



#2. SVNリポジトリの一部をGitリポジトリとして取得

以下のようにすると、SVNから必要なところだけをGitに持ってこれます。
ブランチやタグは無視して別のリポジトリとして一旦取得します。

```
(project1_folderフォルダで実行)
git svn clone --trunk=-prefix=svn/ --preserve-empty-dirs -A ./authors.txt http://xxx.xxx.xxx.xxx/svn/repo1 -T "trunk/yyy/yyy/yyy" -t "" -b ""
(project2_folderフォルダで実行)
git svn clone --trunk=-prefix=svn/ --preserve-empty-dirs -A ./authors.txt http://xxx.xxx.xxx.xxx/svn/repo1 -T "trunk/yyy/zzz/zzz" -t "" -b ""
(project3_folderフォルダで実行)
git svn clone --trunk=-prefix=svn/ --preserve-empty-dirs -A ./authors.txt http://xxx.xxx.xxx.xxx/svn/repo1 -T "branch/xxx/yyy" -t "" -b ""
```


######説明
| コマンド    | 内容        |
|:-----------|:------------|
|git svn clone|履歴を含めてsvnをgitとして取得します。|
|--trunk=-prefix=svn/|svnからだと分かるようにプレフィックスをつけます。|
|--preserve-empty-dirs|空ディレクトリに自動でダミーのファイルを入れます。|
|-A ./authors.txt|ユーザの対応関係を示します。|
|-T "" -t "" -b ""|トランク、タグ、ブランチのフォルダを示します。|


######参考ページ

[Subversion のレポジトリの一部を git レポジトリに移行する。]
(http://www.script-factory.net/history/2015/08/20_0248.xhtml)
[SubversionからGit移行時に苦労したこと、空のフォルダの移行、文字化け対策]
(https://urashita.com/archives/2594)




#3. いらないファイルを削除

特に必要のなかったファイルはこの機会に除外しておきます。
過去の履歴からも完全削除します。
以下のような感じでコマンドを実行します。

```
git filter-branch -f --index-filter "git rm -rf --cached --ignore-unmatch *.sdf *.ipch"  --prune-empty -- --all
```

######説明
| コマンド    | 内容        |
|:-----------|:------------|
|git rm -rf --cached|管理から除外します。|
|--ignore-unmatch|対象ファイルがなくてもエラーで止まらず処理継続します。|
|*.sdf *.ipch|例です。こんな感じでファイルを指定。|
|filter-branch|履歴すべてを対象にします。|
|--prune-empty|コメントのみになったコミットは消します。|
|-- --all|ブランチすべてを対象にします。|

######参考ページ
[Git リポジトリに上がっているファイルを履歴ごと消すには？]
(https://qiita.com/go_astrayer/items/6e39d3ab16ae8094496c)




#4. Gitリポジトリを'接ぎ木'する

- gitのrepositoryを統合したい
- gitのブランチを途中から追加したい
- repositoryを別のGitリポジトリにrebaseしたい
- 履歴は完全に保持して統合したい

そういうときにgitのgraftsを利用することができます。


######以下のような手順になります（project1にproject3を接続する場合）

#####・リモートにproject3を指定

```
git remote add origin/project3 ../project3_folder/
```

#####・graftsの設定 (project3最初のコミット番号 project1の分岐時のコミット番号)

```
echo d78de2dcb1991b7e4d3c07833a265de9153c0608 785d2a970911c48d2b58e92f57bc7127031f05af>> .git/info/grafts
```

#####・履歴の取り込み

```
git fetch origin/project1
```

#####・永続化

```
git filter-branch
```

#####・project3ブランチを作成

```
GUIから作成しました
```

######説明

- .git/info/graftsにつながるべきコミットの番号を列挙しておきます。
- 複数のときは複数行で書きます。直接編集も可。
- projectはどちらをベースに作業することもできます。graftsの書き方は同じです。
- 望みどおりの結果になったかGUIで確認したほうがよいです。
- SVNのRevはGitのコミットログに含まれているのでチェックできます。

######参考ページ

[あるGitリポジトリを別のGitリポジトリにリベースする方法は？]
(https://stackoverflow.com/questions/2428137/how-to-rebase-one-git-repository-onto-another-one)




#5. Gitリポジトリをリモート(移行先)にPush

Push自体はふつう通りに行ないます。

```
git push xxxx
```

バックアップ目的のブランチらしきものが作成されていたら削除しておきます。

```
git update-ref -d refs/original/refs/heads/master
git update-ref -d refs/original/refs/remotes/origin/master
```

######説明

特になし

######参考ページ（全般）
[git-svnの使い方を覚えた](https://idesaku.hatenablog.com/entry/20090323/1237825080)