読者です 読者をやめる 読者になる 読者になる

#21 github-botで捗っている話、もしくはgit-subtree使ってみた

この記事はtech.kayac.com Advent Calendar 2014 の21日目です。

こんにちは、最近日にちの感覚がなくなっているいっちーです。 アドベントカレンダー駆動で何かつくろうと思ったんですが、そんな時間はなかったので、最近プロジェクトでやってみた取り組みをご紹介します。

背景・目的

僕は今現在Unityを使ったソーシャルゲームの開発に関わっており、 主にサーバサイドのプログラムを担当しています(もちろんPerl)。 Unity側ではサーバとのやりとりをBaalというAPIの定義書にもとづいて行っており、 サーバへのリクエストやレスポンスが形式にあっているかをチェックする機能があります。 例えば「Hogeというエンティティは整数型のFugaというフィールドを持っている」ということをBaalで定義すると以下のようになります。

// Baal定義の例
namespace Data {
    entity Hoge {
        Fuga:
            !integer;
    }
}

このようにBaalは独自形式を採用しておりパーサを書くのが面倒なので、 長らくUnity側ではBaalを使っているけどサーバサイドでは使っていない状態でした。 そのため、Baalには書かれているけど実際には送っていない (定義はされていてもUnityのコード中で使っていなければエラーにはならない) ことが多くありました。

これは良くないとBaalをパースするモジュールを作って、 サーバのテストから簡単に利用できるようにしました!! 全部のコードは、プロジェクトと密接に関連づいてたり、ライセンスの問題があってすぐには出せないので、 Perlで書かれたBaalのパーサ だけ公開しています(ぱーるとばーるって似てる)。 今まではTest::DeepTest::Deep::Matcherを使って頑張っていたものが、 Baalを読み込んで検証用のメソッドを呼ぶだけで良くなったので、テストを書くのがずいぶん楽になりました。

テストは楽になったのですが、今度はサーバとクライアント間で定義書を共有する仕組みが必要になります。 サーバとクライアントは別のgitレポジトリで開発を進めており、 レポジトリをまたいで定義書を共有する必要がありました。

git-subtree

そこで目をつけたのがgit-subtreeです。 コマンドの詳細はいろんな人が書いているのでこちらをご覧ください→【Unity Advent Calendar 2014】git subtreeを駆使して最強のUnityゲーム開発環境を作るぞっ!!。 一言でいうと、git-subtreeは別レポジトリのブランチもマージできるgit-mergeのすごいやつです。 git-mergeでもやろうと思えばできる(実際git-subtreeも裏でgit-mergeを使ってる)んですが、使いやすいようにオプションをよしなに設定してくれます。

git-subtreeを使って、

  1. API定義書のみが入ったブランチ(baal/master)を用意する
  2. api/masterをベースにして作業ブランチを切って(baal/feature/hogehoge)、必要な変更を加える
  3. Unityエンジニアとサーバサイドエンジニアがそれぞれgit-subtreeで自分の作業ブランチにbaal/feature/hogehogeを取り込む
  4. baal/feature/hogehogebaal/masterにマージする
  5. このタイミングで関連するすべてのブランチをマージ!

みたいな運用でやってます。

git-subtreeの問題点

git-subtreeに限った話ではないと思うんですが、共有の方法が複雑で色々と問題がありました・・・(ヽ´ω`)

  • git-subtreeコマンドを全員が使いこなせるようになるのが大変
    • 普通にgit-mergeしちゃってコンフリクト→手動で解消しちゃってコミット、みたいなことが発生しました
    • どうやるんだけっけと毎回聞かれていっちーさんが疲弊する
  • baal/feature/hogehogeへの変更内容がUnityをサーバにちゃんと取り込まれたかよくわかんない
    • 一人の作業ならなんとかなるかもしれないけど、APIの修正にいろんな人が関与する(Unityエンジニア+サーバサイドエンジニア+レビューする人数名)ので、すぐわかる仕組みが欲しい

github-bot

そこで、Github::Hooks::ReceiverPithubとJenkins氏を使ってgithub上で活躍するボットを作成しました。

github-bot.png

こんな感じAPI設計書を更新するプルリクエストで「マージ」とコメントすると、github-hook経由でJenkinsのジョブが走りだし、

  • 新しい作業ブランチを作成
  • git subtree merge
  • プルリクエストの作成

をやってくれます。 このボットさんにより、git-subtreeで困っていたことが解消しました!

  • git-subtreeコマンドを全員が使いこなせるようになるのが大変
    • → 「マージ」だけです済むのでgit-subtreeのオプション等を覚えなくてもOK
    • → ボットさんへのお願いの方法がみんなの見える場所で行われるので、わからなくなっても過去のプルリクエストを探せば大丈夫
  • baal/feature/hogehogeへの変更内容がUnityをサーバにちゃんと取り込まれたかよくわかんない
    • → プルリクエストのコメントの最後に「マージ」コメントがあったら取り込まれている
    • → 最後の「マージ」コメント以降のコミットは取り込まれていない

ちなみに途中でBaalラベルをつけているのも、baal関連のプルリクエストが出されたらgithub-hookを使って自動的につくようになっています。 ラベルをつけるのなんて人間様のやる仕事ではないのですよ。

FAQ

なんでgit-submoduleではなくgit-subtreeなの?

社内の共通レポジトリを取り込むのにgit-submoduleも使っている のですが、 やはりgit-submoduleに慣れていない人(そもそもgitにもあまり慣れていない人)がいるとなかなか大変です。

  • git-checkoutしてもsubmoduleの中まで更新されない
    • git submodule updateしないといけない
    • gitに慣れていない人が「更新されてる!」「全部addしちゃえ!」となって、せっかくsubmoduleを更新したのに巻き戻る悲しい事態に…
  • マージがつらそう
    • 複数人で開発をしているので、複数のブランチが並行して進むことになり、マージがよくある
    • サブモジュールの外でマージして、サブモジュールの中でマージしてって毎回やるのはつらい
    • 特にgit-submoduleに慣れていないともっとつらい

というのがあるので、以下の僕の中では以下のような使い分けかなと思ってます。

  • 絶賛開発中で頻繁に更新がある: git-subtree
  • stableになっていて更新頻度がすくない: git-submodule

Unityのレポジトリやサーバのレポジトリ内でBaalのファイルをいじりたくなったらどうするの?

絶対にいじらないgit subtree splitgit subtree push を使うとなんとかできますが、基本的にいじらないようにしてます。 これらのコマンド、レポジトリが大きいと結構時間を食う (git subtree split --rejoinすると余計なコミットを見なくなるので速くはなります) というのと、コミットログが複雑になるので、基本はbaal/master更新です。

まとめ

  • git-subtree便利
  • github-hook便利

22日の担当は去年のアドベントカレンダーはてぶ数一位になった@yumiyonくんです!