社内の Subversion を Git に移行した話

検証時の手順やメモばかりを記事にしていましたが、たまには仕事の話を日記的に書いてみます。

上司から「部署の Subversion を Git に移行したいんだけど、できそう?」という話を持ちかけられて、勢いで「やってみます!」と答えてから一ヶ月ほど一人で移管プロジェクトを回していました。
安い単価とはいえ一ヶ月も好きに使って良いと言われたので、それなりに計画を立ててやらねばなりません。色んな案件を転々としてきてまともな業務知識が身に付いていない若造ですが、なんちゃって要件定義から運用計画まで一人でやってみましたので、ここに残しておきます。

やったこと一覧

  • Subversion 調査
  • OSS 調査・選定
  • Git サーバ構築検証
  • データベース構築
  • リポジトリ移行
  • HTTPS 化対応
  • クライアントツール検討
  • 本番環境構築
  • SSL 証明書と正引きレコード追加
  • 自動バックアップの実装
  • メール通知の設定
  • ブランチ運用手法の調査
  • 部内展開・教育
  • 本番稼働に向けて調整

構築については以前の記事で書いていますので、今回の記事では調査・選定や移行部分について触れていきます。

現状のヒアリング・調査など

サーバの運用・管理について

  • どこかの物理ホストの Windows サーバで稼働している
  • プライベートネットワーク内にいるが実体がどこにあるのか不明
  • 誰も管理していないし、管理者が分からない
  • このままではサーバ老朽化に引き摺られてソースコードも全て道連れになる
  • 一応バックアップは取っているがリストア手順が不明

現状の運用に正直がっかりしてしまいましたが、がっかりしていても前に進めないので解決に向けて検討していきます。

Git に対しての要望

  • SVN 上のソースコードをそのまま Git に移行したい
  • できればコミット履歴も引き継ぎたい
  • Pull Request の機能が欲しい
  • あとは Subversion で出来ていたことが大体できれば良い

部署内の調査をしたところ、誰も Git を触ったことがなく「プルリクっていうのが便利らしいね」くらいの認識でした。
特に書き連ねる意味はありませんが、個人的な要望はこのあたりです。

  • 何か OSS 使ってオンプレ運用してみたい
  • git-flow のようなブランチ運用がしたい
  • ソースコードを ZIP でダウンロードできると楽
  • 構築面、運用面で簡単かつ慣れている Linux 環境だと助かる

Git 移行可否についての調査

git-svn というコマンドを使えば簡単にできそうなことが分かりました。 (フラグ)

Subversion 調査

開発をするときに Eclipse プラグイン (Subversive) 経由でしか触ったことがなかったため、実際使われているサーバや Subversion 自体についての調査から始めました。
※ 以降、SubversionSVN と記載します。

SVN リポジトリについて

SVNリポジトリは大きく分けて以下の3要素から成ります。

  • trunk/
  • branches/
  • tags/

主に trunk 配下にソースコードが入っていき、branches と tags は補助的に利用するようです。
Git のブランチ・タグとは使い方が異なることと SVN で特に使用していなかったことから、今回は trunk 配下のソースコードを引き出すことのみ考えていきます。

社内で運用中の SVN について

現状使用している SVN リポジトリは trunk ディレクトリ配下に全てのプロジェクトが入っている構成になっていました。
プロジェクトやプロダクトごとにリポジトリを持つのが正しい姿かと思っていましたが、実際のところどのくらいの粒度でリポジトリを作るのが理想なのでしょうか。

/
|-- branches/
|-- tags/
|-- trunk/
    |-- PROJECT_A
    |-- PROJECT_A_20150401
    |-- PROJECT_A_bk
    |-- PROJECT_A_old
    |-- PROJECT_B
    |-- PROJECT_C
    |-- ...

上記のような構成になってしまっていたため、プロジェクトのディレクトリをひとつのリポジトリとして分割してクローンしていく必要があります。
バージョン管理とは一体……と思ってしまう名前のディレクトリもいくつかありましたが、フルバックアップしておきたい気持ちも分からなくもないので触れずに全移行します。

OSS 調査・選定

Git ホスティングのサービスをいくつか調査しました。
箇条書きのメモで見づらくなっていますが、念のため残しておきます。

GitHub と Bitbucket についてはオンプレミス版は有償のため、評価対象外としています。

候補 1. GitLab

  • 実行環境
    • Ruby on Rails
      • ruby, nginx, unicorn, chef, postgresql, redis など必要なものは全て同梱
      • gitlab-ctl start で全部が動く
    • ハード要件
      • CPU は 2 コア以上を推奨
      • メモリは 1GB 必須、4GB 以上を推奨
  • OSS 的な側面
    • オンプレ Git サービスといったら GitLab というくらい情報が多い気がする
    • 開発団体が存在している
    • 月次でバージョンアップされている
  • 導入に際して
    • インストールに30〜40分かかり、スクリプトで何やってるか分からなくて不安
    • 組み込みのモジュールが多すぎて環境を汚しそう
    • 起動しても何故かエラー連発でログインすらできない
    • ハード要件を満たしていても動作が重く操作が満足にできない
    • 技術系ブログを見た感じだと挫折して GitBucket に流れ着いてる人がちらほら

候補 2. GitBucket

  • 実行環境
    • Scala
    • H2 という組み込みデータベースを使用
      • H2 はデータの保全性に問題があり、公式は外部 DB の利用を推奨している
      • MySQLPostgreSQL を公式サポート
      • DB にはアカウントやグループなどの情報を保存
  • OSS 的な側面
    • 日本人が開発しているので公式ブログからの情報が得やすい
    • GitBucket 自体は GitHub で管理されている
    • GitHub から指摘を受けてデザイン変更した過去があり、それ以降 UI が変わった
    • 検索したときに Bitbucket の情報ばかり出てきて困る
  • 導入に際して
    • ダウンロードした war ファイルを配置して Tomcat を動かすだけなので簡単
    • JVMTomcat であれば部内でも慣れている方が多い

結果

GitBucket にしました。
GitLab は Web サーバや DB サーバが全て同梱とのことで、どうやって管理していったら良いのか見当つかず、運用を考えたときに躓いてしまいそうなので避けてしまいました。

また、私の部署は Java の経験者が多く、何かあったときに少しでも理解がある人に任せられる(かも)という保身的な考えからも JVM 環境で実行できる GitBucket が無難かと思い採用に至りました。

リポジトリ移行

先ほど挙げた git-svn を用いて移行します。
基本的には以下のような流れです。

  1. git-svn コマンドで SVN リポジトリを Git リポジトリとしてローカルにクローン
  2. GitBucket 上に空のリポジトリを作成する
  3. 2 で作成した空のリモートリポジトリにローカルリポジトリをプッシュ

たったそれだけかといった感じですがいくつかハマった点もありますので、そちらは後ほど紹介します。

1. SVNリポジトリをクローン

Git Bash を開き、以下のコマンドで SVN からリポジトリをクローンします。

$ git svn clone http://xxx.xxx.xxx.xxx:xxxx/svn/trunk/PROJECT_A

もしくは git svn fetch + git svn rebaseリポジトリをクローンします。

$ mkdir ./PROJECT_A && cd $_
$ git svn init http://xxx.xxx.xxx.xxx:xxxx/svn/trunk/PROJECT_A
$ git svn fetch
$ git svn rebase

git svn clone ではタイムアウトなどが原因で失敗する場合がありますが、git svn fetch ではエラーになっても次のフェッチ時に途中からリビジョンを取得することができます。
また、trunk/ 配下に各プロジェクトが展開されていて不安でしたが、普通に一つのリポジトリとしてクローンしてくることができました。

SVN リポジトリの総コミット数は 10,000 件ほどあり、そのうち 5,000 コミットほどを占めている大きなディレクトリのクローンは 4 時間ほどかかりました。
ネットワーク環境が悪いのかは分かりませんが、終始この調子だったため、全プロジェクトをクローンするだけでほぼ丸一日潰れてしまいました。スクリプトで自動化をしていなければもっと酷いことになっていたと思います。

最新リビジョンのみをクローン (非推奨)

覚え書きとして記載しておきます。
速度は速いですが、HEAD のソースコードのみ取得するため差分の履歴は引き継げません。
過去のコミット履歴が不要であればこちらを使用しても良いかもしれません。

$ git svn clone -r HEAD http://xxx.xxx.xxx.xxx:xxxx/svn/trunk/PROJECT_A

2. Git にリモートリポジトリを作成する

ブラウザから GitBucket アプリケーションにログインし、プロジェクト単位で New Repository をしていきます。
操作については割愛します。

3. Git リモートリポジトリにプッシュする

GitBash に戻り、リモート環境 (GitBucket) の空リポジトリ情報を追加してプッシュします。

$ git remote add origin http://XXX.XXX.XXX.XXX/gitbucket/git/GROUP/PROJECT_A.git
$ git push -u origin --all

移行時にハマったこと

空のディレクトリは保管できない

「Git からクローンしてきたプロジェクトがビルドできない」という報告を受けて気付くことができました。

Git はファイルのバージョンを管理する仕組みであるため、ディレクトリだけ存在していても管理対象として認識することができません。 アプリケーションによっては tmp や cache といったディレクトリを使用している可能性がありますので、0 バイトのダミーファイルを格納するなどして回避する必要があります。
Git の仕様ではありませんが .gitkeep という 0 バイトファイルを作成する慣習があるようですので、それに倣ってディレクトリとファイルを再度コミットしました。

それほど数は多くなかったため、find . -type d -empty でリストアップしたディレクトリに対して touch .gitkeep を連打するスクリプトを書いて解決しました。

日本語表記や半角スペースは使用できない

SVN で日本語やスペースが使われているディレクトリは、git svn clone できても git push ができませんでした。

リポジトリ、ブランチ、グループ、ユーザ などの Git の根本機能に関わる名前は URI にも使用されることがあるため、半角英数を利用するよう周知し、適当にリネームして凌ぎました。
例) Sample Project (テスト用)/Sample_Project_test/

「プロジェクト名に日本語使いたいんだけど」という要望もありましたが、「URI になるのでできません」と具体的に説明したらなんとか理解を得られました。

また、日本語表記で躓いた箇所がもう一点あります。
MySQLmy.cnf に下記を設定しておかないと日本語を POST したときにアプリ側でエラーになるので注意が必要です。早い段階で気づいていなかったら後で悲惨なことになっていました。

[mysqld]
character-set-server = utf8

この設定をしたことで、ファイル名やコミットメッセージ、レビューコメントなど無事に日本語で書けることが確認できました。

バイナリファイルの差分管理は得意ではない

移行後、バイナリファイルをコミットしていた方がいたので気づけました。

Git はプログラムのソースコードなどのテキストファイルのバージョン管理を目的としており、動画ファイルや OS イメージなどのバイナリファイルの管理は得意としていません。
リポジトリに格納することは仕組み上可能ですが、バイナリファイルでは差分を計測することができず、必要以上にサイズが膨れ上がってしまい、ディスクを圧迫することに繋がってしまいます。
アプリケーションで利用する静的ファイルなどに用途を限定し、テキストファイル以外の設計書などはなるべくファイルサーバへ保管するよう周知し、なんとか和解しました。

また、試しに CentOS のイメージファイルをプッシュをしてみたところ、プッシュはできてもクローンはできず、処理できないゴミが増えてしまっただけでした。

別の移行対象リポジトリが存在していた

移行が終わったと安心していた段階で隣の課の先輩から「○○のソースは無いんだ?」と聞かれ、もう一つ別の SVN リポジトリの存在を知りました。
これは Git どうこうではなく完全に私の調整不足が原因ですが、SVN 歴の長い先輩や上司にきちんと聞いて移行範囲を明確にするべきでした。

振り返り

一人だけのプロジェクトでしたが KPT っぽく振り返ってみます。

良かったこと

  • SVN, Git についての理解を深めることができた
  • 割り込みのタスクがほとんど無く、のびのびと調査や検証ができてストレスが無かった
  • ワイルドカード証明書の仕組みを覚えた
  • 社内 DNS の登録申請フローを覚えた
  • 未知の技術に対して積極的な人、保守的な人などの特徴が見えた

悪かったこと

  • 誰も Git を触ったことが無かったため自分の進捗の良し悪しを誰も判断できなかった
  • マージ、リベースなどのブランチ運用の学習に時間がかかってしまった
  • 部内教育用のドキュメント作成に半分くらい時間をもっていかれた
  • 導入や教育が一部投げやりで無責任だった
    • 「ドキュメント格納しておいたので見ておいてください」など
  • SVN リポジトリを切り捨てるタイミングが明確に決められなかった
    • 「慣れるまで数ヶ月平行運用していきましょう」が今になってジワジワ効いてきた

気づいたこと、改善していくこと

  • イレギュラーは必ず起きるものと思って早めに行動し、対処できる時間を残しておく
    • ビルドできない件、日本語入力の件、リポジトリが別に存在した件など
  • 業務時間内の勉強だけでは圧倒的に足りないので日常的にアンテナを張っておく
    • 今回は運良く業務時間に勉強できたがそんな恵まれた環境はまず無い
  • 新しい技術の導入に保守的な人に対してのコミュニケーションを上手くやる
    • 疑問や質問については丁寧に正しく答える。即答できなければ曖昧にせず調査する時間をもらう
  • 利用者の習熟度を上げて味方を増やしていく
    • 後輩が Git の操作のことでたくさん質問してきてくれて精神的にすごく助かった
  • ドキュメント作成がスムーズにできるように普段から人に見せられる文体でメモを書き残す
  • 顔を合わせて共有できる時間を取る
    • ドキュメント展開しました、の連絡だけでは誰も興味を持ってくれない

所感

自分の裁量で仕事が出来たのが純粋にとても楽しかったというのと、社内のみんなが知らない分野だから誰からも仕事ぶりを突っ込まれないというハラハラした気持ちが混在した面白いプロジェクトでした。
また、普段エンドのお客さんからサービスの感想など直接いただくことの無い SI 企業の末端 SE なので、誰かに使ってもらって「便利だね」と言って貰えるのは心底嬉しいなと感じました。達人たちの技術ブログの真似をして環境を整備し、出来合いのアプリを動かしただけではありますが、やってよかったと思っています。

「新しい技術に保守的な人」について触れましたが、これは悪い意味で書いたつもりは一切ありません。
システムを長い目で見たときにプロダクトのライフサイクルまで考えなければなりませんし、変更やリプレースは障害を引き起こすポイントでもあるので、慎重に考えるに越したことはないと思っています。
上手にメリットを伝えて上手に不安を取り除く、といったように人をうまくコントロールすることについても考える良い機会になりました。どこまでいっても最後には対人スキルが必要になってくるんだなぁと感じます。

あと、「アプリ書いてるときより黒い画面見てるときの方が生き生きしてるね」と先輩に言われたのが印象的でした。

以上、日記でした。