ユニフィニティーのソースコード管理 後編

テックポエム

ユニフィニティーのソースコード管理 後編

前編からの続きです。

SubversionからGitへのリポジトリ移行

gitにはgit-svnコマンドが用意されており、 今回のようにSubversionからgitへ移行したい場合や、会社のリポジトリはSubversionなんだけど個人的にはこっそりgit使いたい!といったニーズに応えてくれます。便利ですね。

ざっくりとした手順としては

  1. git svnコマンドまたは同等の機能を利用してSubversionリモートリポジトリをgitローカルリポジトリにコンバート
  2. Subversionのブランチ・タグをgitで運用するために整理
  3. git pushでgitローカルリポジトリをgitリモートリポジトリへpush
  4. 社内のgit教育

となります。

今回の移行作業は以下の環境で行いましたが、基本的にはどのOSでも同じです。

  • Ubuntu 17.10
  • git 2.14.1
  • git lfs 2.2.1
  • subversion 1.9.7
  • svn2git 2.4.0

svn2gitは git-svnコマンドのラッパーですが、Subversionのブランチ・タグをgitへイイ感じに移行してくれるために利用しました。

準備その1 author情報の引継ぎ

Subversionとgitではコミッタ情報の管理が微妙に異なり、移行に際してはSubversionのコミッタ情報をgitではどうするかを決めておく必要があります。

Subversion

foo

git

foo <foo@unifinity.co.jp>

これらのマッピングファイルを作成しておきます。

~/.svnauthors

foo = foo <foo@unifinity.co.jp> bar = bar <bar@unifinity.co.jp> baz = baz <baz@unifinity.co.jp> 

ここで作成した .svnauthorsファイルを git svn (svn2git)コマンドに食べさせることになります。

準備その2 Subversionブランチをどうgitへ移行するか

当社のSubversionのリポジトリ構成は以下のようになっていました。

  • root
    • archives (ビルドに必要なSDK等)
    • branches/* (各ブランチ)
    • master
      • trunk (masterブランチ)
    • release (インストーラー等のビルド生成物)
    • tags (タグ)
    • trunk (HEAD)

Subversionは柔軟度が高いが故に、きちんと運用ルールを決めておかないとブランチ運用が破綻しやすいのですが、当社のSubversionリポジトリは若干ツッコミどころはあるにせよ、割とキレイに運用できていました。

gitに移行するに当たり、下記のようにすることに。

Subversiongit
archives 破棄。巨大なバイナリをgitで管理はしない
branches/* gitのfeatureブランチとして移行
master/trunk gitのmasterブランチとして移行
release archivesと同様
tags gitのタグとして移行
trunk gitのdevelopブランチとして移行

svn2gitを利用した移行

$ svn2git --verbose --username [SVN username] --authors ~/.svnauthors \ https://[SVN repository] 2>&1 | tee /tmp/svn2git.log

問題がなければSubversionリポジトリがgitローカルリポジトリへ変換されます。小規模リポジトリであれば問題なく実行できるはずです。

ローカルリポジトリのブランチの調整

gitにおけるbranchの運用は、ベストプラクティスとなっているgit-flowモデルを基本とした運用を想定しています。(詳細はリンク先を参照)

svn2gitコマンドでリポジトリを移行すると、Subversionのbranchがgitのbranchへ取り込まれますが、 git-flowモデルに沿う運用とするとなると取り込んだブランチをとりあえずfeatureブランチへ移行するのが良さそうです。

$ git branch branch1 branch2 branch3 ... ... $ git branch -m branch1 feature/branch1 $ git branch -m branch2 feature/branch2 $ git branch -m branch3 feature/branch3

実際には大量のブランチを移行することとなるため、シェルでうまいことやりましょう。

同時に、不要な過去の遺物となっているブランチは消してしまいましょう。

$ git branch -D to_be_deleted1 $ git branch -D to_be_deleted2

リモートリポジトリへpush

branchとtagの整理が出来たら、社内の共有リポジトリにpushしてチームでgitを運用していきましょう。

$ git remote add origin [git repository path] $ git push --all $ git push --tags

ハマりどころ1 オレオレ証明書

ハマるというほどではありませんが、、当社のSubversionは自己署名証明書(オレオレ証明書)で運用されており、svn2gitが失敗します。

いったん、任意のsvnコマンドを投入してオレオレ証明書をsvnコマンドにキャッシュしておくことにより回避することができます。

$ svn ls https://[SVN repository path]

~/.subversion/auth に結果がキャッシュされます。

ハマりどころ2 途中で落ちる

当社のSubversionは8000以上のコミットヒストリが蓄積されており、ローカルgitリポジトリへの移行にはとにかく時間を要します。

git svnコマンドはSubversionの最初のコミットから一つ一つのコミットを取り出してgitのコミットとして取り込んでいるため、まぁ仕方がないのですが。

当社のリポジトリ移行では、svn2gitコマンド投入から約5時間経過後、コマンドがメモリ不足で落ちる事態がありました。

Can't command failed: git svn fetch fork: Cannot allocate memory at /usr/share/perl5/Git.pm line 1695.

メモリ不足にせよ何にせよ、回復可能なエラーで落ちた場合は、慌てずに同じコマンドを再投入することにより、途中から処理を再開してくれます。(それでも落ちる場合は作業用仮想マシンのメモリ追加などで力技対処を)

svn2gitコマンドの最後の最後でgit gcが行われるのですが、リポジトリが巨大なためgcもメモリ不足でよく落ちます。

ハマりどころ3 LFS

gitはソースコードのバージョン管理に特化したツールであり、バイナリファイルの管理が苦手とされています。 これは、gitが他のバージョン管理ツールと同様にテキストの変更履歴を差分記録しているためです。 (バイナリファイルは差分取れないためファイルを丸ごと記録する)

これを解決するための仕組みとして提供されているのがGit Large File Storage (以下、Git LFS)で、 大きめのファイルをGitのリポジトリではポインタのみ管理し、ファイルの実態は別の場所(Large File Storage)で管理することができます。 GitHub,GitLab,BitBucket等、主要なGitリポジトリでサポートされています。

Subversionから移行と同時にGit LFS化を行うにあたり、結果的に以下の手順となりました (他にも良い移行手順があるのかもしれません)

  1. Subversion側で管理されている、Git LFS管理下としたいバイナリファイルも、いったんはGitのリポジトリ内のファイルとして移行する
  2. GitリポジトリをLFS対応とし、移行対象とするブランチの歴史を改変してGit LFSで管理されていることにする

実際の手順としては下記の通りです。移行対象のブランチ毎に下記作業を行います。

$ git lfs install # LFSの有効化 $ git lfs track "*.a" "*.ttf" "*.zip" "*.gz" "*.tgz" ..... # LFS対象ファイル拡張子の指定 $ git lfs migrate import --include="*a,*.ttf,*.zip,*.gz,*.tgz,..." \ --include-ref=refs/heads/develop # 歴史の改変 $ git lfs ls-files # LFS化されたかどうか確認 $ git pull --allow-unrelated-histories # LFS化対象のファイルの競合を無視しつつpull $ git commit -am "LFS化" $ git push # サーバへpush

git lfs migrateはリポジトリの大きさでだいぶ所要時間が変わります。当社のリポジトリではブランチ毎に1時間程度かかりました。

運用ルール

gitで社内運用するにあたり最低限の下記ルールを定めています。

利用するGitについて

特にルール化しているわけではないのですが、SourceTreeを推奨しています。

理由としては、

  • SourceTree同梱のgitを使うことによりgit-lfsに暗黙的に対応していること
  • macOSのXcodeから利用できるgitがgit-lfsに対応していなく homebrew か何かでgit-lfsのインストールが必要なこと

が挙げられます。

Windows版のgitは、以前は別途インストーラーでGit LFSを入れなければならなかったのですが、 現時点では Git for Windowsにgit-lfsが同梱されているようですね。

ブランチ・タグ運用ルール

git-flowモデルを簡略化したものを導入しています。

弊社ではIssue管理にJIRAを利用しているのですが、 出荷前試験におけるバグのマージリクエスト運用とhotfix運用でJIRAのIssueIdを命名規則に入れています。

  • masterブランチへの直接コミットはダメ
  • なにか作業を行う際は必ずdevelopブランチから featureブランチを作成する
  • featureブランチからdevelopブランチへマージする際は必ず第三者レビュープロセスを挟む
    • 当社では GitLab を利用しているため、GitLab のマージリクエスト運用を行っています
    • マージ元のfeatureブランチはマージリクエストの承認のタイミングでレビュワーの裁量で消すかどうかを判断しています
  • リリース準備状態になったらリリース準備ブランチをdevelopブランチからreleaseとして作成し出荷前の試験を行う
    • 出荷前試験中に問題が発生した場合は、release/[バージョン名]_[IssueId]ブランチへ修正コミットを行い、マージリクエストプロセスを経てブランチを消す
  • リリース可能状態になったら releaseブランチをmasterブランチにマージしてタグを打つ
  • リリース済みのプロダクトで障害が発生し緊急対応が必要なものは masterブランチからhotfix/[IssueId]ブランチを作成して作業する

GitとIssue管理のインテグレーション

JIRAとGitLabは容易にインテグレーションすることができます。

  • GitのコミットログやマージリクエストコメントにJIRAのIssueIdを入れることにより、自動的にJIRAのIssueへリンクとコメントが付与されます
  • コメントの入力内容により、GitのコミットログからJIRAのIssueをクローズすることもできますが、Committerが勝手にIssueをクローズされると困るシーンも多いため、この機能は使っていません

大変便利に使わせていただいています。ありがとうございます。

まとめ

VCS(Version Control System)としてのGitの基本機能はひとつの到達点にあり、GitHub/GitLabをはじめとする各社・各種コミュニティから提供されているGitリポジトリは、ソースコード管理を取り巻く開発プロセスの軸になる以下のような機能群を提供するようになっています。

  • ソースコードレビュープロセス (プルリク・マージリクエスト)
  • 簡易なIssue管理・Task管理
  • Issue管理・Task管理のカンバンビュー
  • markdown記法の進化
  • Continuous Integration
  • ドキュメントリポジトリ(Wiki)
  • DevOps
  • 公開リポジトリ

などなど。

正直ソースコード管理ツールは何でも良いのですが、今回時間をかけて当社リポジトリをGitに移行したのは、上記のような周辺機能を利用できるメリットが非常に大きいからなんですよね。

GitとSubversion自体を比較すると、ブランチ運用が楽だとか分散リポジトリが耐障害性に優れているとか様々なGitの利点がありますが、最大の利点はこれらのGitを取り巻く機能を手にし、Issue管理、CIによるビルド・テスト・デプロイといった開発プロセスを導入できる点だと考えています。

さいごに

当社の開発プロセスの構築はまだまだ道半ば。著者が片手間でGitへの移行をしたりJIRAを導入したりしつつ、Jenkins化スプリントを設けてスクラム全員で一気にビルドシステムのJenkins化をしたりしています。CI/CDはまだまだこれから。品質の定量的な見える化なども大きな課題の一つです。

開発に興味があるのはもちろん、開発プロセスの構築に興味があるエンジニアの方、ぜひ当社オフィスに遊びに来てください。