git-svnでfile:///形式のリポジトリを連携する

Gitで管理しているソースコードをSVNのリポジトリと連携させる方法です。
情報はたくさん出てきますが、割と分散していたのでまとめて共有することでお役に立てればと思います。

シェルの環境は[Git for Windows](https://gitforwindows.org/)です。

# GitからSVNを使う
``git-svn``で連携します。

下記を記事を参考にしました。

[面倒くさいsvnリポジトリをgit-svnで扱う時に役立ちそうなオプション一覧](https://sinsoku.hatenablog.com/entry/2014/02/26/231918)

```
$ git svn clone -s <SVNのリポジトリ> <ローカルのディレクトリ>
```

``-s``オプションはSVNの標準的な構造（trunk, branches, tags）になっているリポジトリをcloneするためのオプションです。
ルートからいきなりtrunkが始まっているような場合は、``--trunk=``オプションなどで指定します。

```
# --trunk=/でルート直下をtrunkとして認識する。
# --tags=, --branches= もある。
$ git svn clone --trunk=/ <SVNのリポジトリ> <ローカルのディレクトリ>
```

# ローカルもしくはネットワークドライブのリポジトリを連携する
今回はこちらが本題。

SVNのURLが``file:///Z:/foo/bar/repo``という形式になっている場合、そのまま``git svn clone``しようとするとエラーとなります。

```
$ git svn clone --trunk=/ file:///Z:/foo/bar/repo D:/local/path/repo
Initialized empty Git repository in D:/local/path/repo/.git/
Can't create session: Unable to connect to a repository at URL 'file:///Z:/foo/bar/repo': Unable to open repository 'file:///Z:/foo/bar/repo' at D:/local/mingw64/share/perl5/Git/SVN.pm line 310.
```

ドライブ文字の``:``を抜けという[記事](https://opcdiary.net/?p=30982)もありますが、フォーマットのバージョンが合わないと言われて失敗してしまいました。
もしかしたらこれだけで成功する環境もあるかもしれません。

```
$ git svn clone --trunk=/ file:///Z/foo/bar/repo D:/local/path/repo
Can't create session: Unable to connect to a repository at URL 'file:///Z/foo/bar/repo': Unable to open repository 'file:///Z/foo/bar/repo': Expected FS format between '1' and '7'; found format '8' at D:/local/mingw64/share/perl5/Git/SVN.pm line 310.
```

## svnserveを使う
``file:///``ではなく``svn://``でアクセスすればよいらしい。
以下の記事を参考にしました。

[会社のSVNを一人だけ脱出してGitを使う](https://qiita.com/yuina_i/items/6f9db7b2a4776af754e5)

```
# svnserveはバックグラウンドで実行すること
$ svnserve.exe -d --root file:///Z:/foo/bar/repo &
$ git svn clone --prefix=svn/ svn://localhost D:/local/path/repo
```

ただし、このままだと``git svn clone``はできても編集後の``git svn dcommit``で失敗してしまいます。

```
$ git svn dcommit
Committing to svn://localhost ...

ERROR from SVN:
Authorization failed: Authorization failed
W: 4a59fb5ccba3150e11f55996aead9b71d3c803ef and refs/remotes/svn/git-svn differ, using rebase:
:040000 040000 ebbccb7b2f0c9d467f1b3c571be367752531643a 5ec549645a5bac7b0952d5351416b01e867f6118 M      hoge
Current branch master is up to date.
ERROR: Not all changes have been committed into SVN, however the committed
ones (if any) seem to be successfully integrated into the working tree.
Please see the above messages for details.
```

svnserveの認証で失敗しているので、configファイルを作って認証なしで書き換え（write）可能となるように編集します。
本当はユーザ／パスワードを設定できるらしいのですが、今回はローカルのサーバなので割愛。

以下の記事を参考に。

[Subversionのインストールと設定(svnserve編)](https://gside.org/Gentoo/subversion/subversion2.html)

[SVN DCommit failed : ERROR from SVN: Authorization failed](https://gitlab.com/tortoisegit/tortoisegit/issues/1889)

リポジトリの中に``conf/svnserve.conf``を作成しておくのがプラクティスらしいですが、このためにリポジトリにゴミファイルを作りたくないので``$(HOME)``に作成しました。

```~/svnserve.conf
[general]
anon-access = write
```

作成したファイルを指定してsvnserveを起動すれば、問題なく``git svn dcommit``できます。

```
$ svnserve.exe -d --config-file ~/svnserve.conf --root file:///Z:/foo/bar/repo &
$ git svn dcommit
```

## ユーザ名の設定
ここまでの方法だと、SVNのコミットログにユーザ名が反映されません。
``git svn clone --username=hogehoge``とか試してみましたがどうもうまくいかず。

継続調査ですね。

# 運用について
Gitで開発しているとローカルリポジトリに対するコミットが気軽にできる分、コミットログが汚れがちです。
正直なログを残すのはそれはそれで意味があると思いますが、リモートリポジトリのコミットログはある程度整理されていないと履歴を追いかけづらいということもあると思います。
特にSVNでの運用だとGitよりもコミットに対する敷居が高いのではないでしょうか。

現時点ではfeatureブランチを切って、master（SVNと連携しているブランチ）に対して``git merge --squash``した後``git commit``でコミットを一つにまとめる運用にしています。
こうすることで他のメンバーに見えるコミットログと個人の作業ログを分離できるので、コミットメッセージを推敲するのはSVNにコミットするときだけで済みます。

以下の記事を参考にしました。

[git-svnを使うときのベストプラクティス](https://layzie.hatenablog.com/entry/20121216/1355653349)

# 最後に
参考にさせていただいた記事の筆者の皆様に感謝いたします。