講演者
石井 淳
https://cedil.cesa.or.jp/cedil_sessions/view/2268
序盤は講演内容の書き起こし、最後と※部分に個人的な見解を記載しています!
■プログラムとアセットをGitHUb Enterpriseを利用して開発
リリース時期の異なるブランチを複数並行して管理
おおよそ2カ月くらい先までの配信予定をイベントブランチを分けて開発
各ブランチで行われた修正は次にリリース予定のブランチにも反映が必要
新規イベントには日付指定リリースがあり1イベントで最大9ブランチに別れていることも
開発中にアクティブとなるブランチは
アセット側 10~25
プログラム側 3~8
※こういう細かい数字が同じような作業をする際の見積もりのめどになるので、参考になる
次バージョンに反映するため、これらすべてのリリースブランチ間マージが必要
途中でコンフリクトが発生した場合にはその解決作業も必要
マージの頻度は毎日。朝、夕方、深夜
これ人力作業でやるんですか?
ええ、やってました!
※簡単に言いますがプロジェクトがどう作られているか、どのような更新をどのように入れるのか、データ構成はどうなっているか、というあたりがわかっていないのと出来ないので結構大変ですよ。
■いくつか典型的なコンフリクトについて発生状況とその解消方法を紹介します。
・発生個所:プログラムブランチ:サブモジュール(アセットブランチ)情報
発生状況
後続ブランチ(次リリース)のサブモジュールより先行ブランチ(先リリース)のサブモジュールが新しい場合
解決方法
サブモジュール(アセットブランチ)情報はブランチ間マージ実施で毎回更新する為、いったん後続ブランチ(次リリース)の情報で解消し、次回の更新で確実に正常化する
・発生個所:プログラムブランチ:バージョンコード
発生状況
次にリリースするプログラムブランチがある状態で、急遽先にリリースするプログラムのパッチ用ブランチが追加された場合
解決方法
テキストファイルのため、コンフリクト箇所のみを後続ブランチ(次リリース)の情報を適用して解消
・発生個所:アセットブランチ:サウンドファイル
発生状況
次にリリースするブランチのファイルを修正後、先にリリースするブランチのファイルを修正した場合
解決方法
各リリースでサウンドデータがパックしてあるバイナリのため、サウンド班に参考ブランチ(先のリリース)と、後続ブランチ(次のリリース)のどちらを使用するか担当者に確認して解消
・発生個所:アセットブランチ:追記型(羅列系)ファイル
発生状況
後続ブランチで追記後、先行ブランチで末端修正(追記/削除)すると発生
解決方法
先行部分の末端修正内容(追記や修正/削除)を後続ブランチの該当箇所に反映して解消
先行ブランチの末端削除は気づきにくく注意が必要で、内容の反映が漏れると後続ブランチで削除したはずのものが残る
・発生個所:アセットブランチ:TexturePacker出力のアトラス
発生状況
後続ブランチでアトラス更新後に、先行ブランチでアトラス更新すると発生(アトラス素材の修正や増減時のアトラス更新)
解決方法
一旦後続ブランチ側で解消しTexturePackerでアトラスを再出力
PNGフォーマットがタイムスタンプを内包しているため、画素が完全一致しても再出力時はgit上で差分検出、上記ケースでコンフリクトとなる
・発生個所:アセットブランチ:NGUI Sprite用のプレハブ
発生状況
後続ブランチで更新後に、先行ブランチで更新すると発生
(アトラス素材増減時のアトラス更新)
解決方法
一旦後続ブランチ側で解消しTexturePackerでアトラスを再出力しUnity起動後対象プレハブにJSONファイルインポートし直し
※手作業のマウス操作に加えてUnity起動時のインポート待ち等、とても時間がかかる
※力技で解消ですな。でもまあ実際はこうなっちゃうことがあるわけななので
作成時にこういう問題が起きる、ということを作業者が理解していればマージ時の負担の改善はできるかと思う
■自動化について
自動化にはgit mergeコマンド 実施後にコンフリクトを検出し前述の解決方法をスクリプト等で実装します
最初はSourceTreeで手作業でマージしていたのをコマンドラインで対応するようにした
そのまま実装できれば自動化完了ですが、そのままでは実装しにくかった事例を紹介します
・サウンドファイル
対応内容
サウンド班へのヒアリングにより、ブランチ間マージ時に上書きを回避するための意図的なコンフリクトと判明
各リリースでサウンドデータがパックしてあるバイナリのため、コンフリクト発生時には必ず後続ブランチ(次のリリース)を適用。その際コンフリクトを解消した旨をサウンド班へ自動通知することで合意、自動化を実装。
・追記型(羅列系)ファイル
対応内容
.gitattributesにunion指定で両方の修正を取り込めばコンフリクトは起きないが先行順番が不定となる。エラーがないと重複修正や削除したものが残っても検出できないため、通常設定のままコンフリクトさせて解消する。先行ブランチの内容を削除分含め後述の後続ブランチ名コメント位置に適用するよう実装。ブランチ名コメントは各ブランチの追記先頭行に# branch-AAAと記述必須とする運用。それでも未記述の場合があり、保護として後続ブランチでの児童会商事にブランチ名コメントがない場合は自動追記
※このファイルをいじるときには正しい記載ができているか促すような仕組みが欲しいですね
・NGUI Sprite用のプレハブ
対応内容
ネックとなるのはUnity起動後のマウス操作によるスプライトJSONファイルのインポート。これはUnityプログラムとして実装し児童会商事にUnityをバッチ軌道で呼び出し。
・AssetDataBbaseからプレハブをLoadしUIAtlasとUISpriteDataを取得
・NGUIEditorTool.ImportTexture()でテクスチャをインポート
・NGUIJson.LoadSpriteData()でスプライトJSONファイルを適用
・atlas.MarkAsChanged()を行うことでプレハブ修正を反映
・PrefabUtiloty.SavePrefabAsset()でプレハブを保存
ブランチ間マージ後はアセットがかなり変化していてUnity起動時のインポート時間が結構かかる
自動化することで人が待つことから解消される
■Q&A
プレハブのコンフリクトは自動化が難しい
■感想
基本的なところを抑えて作業をされているのですが、その紹介ですね。
先鋭的なことはしていないのですが、実際に開発を始めると同じ問題に直面するので予め考慮できるているとずいぶんと楽になります。
そのための助けになる情報だと思います。
Unityのようにアセット以外はコードみたいな作りでない部分が大きい仕組みを使っていると自動化が難しいですね。
大人数で継続的に更新する、という手順には本来向いていないのかもしれません。
マージ作業はプログラムがわかっていればいいということだけではなく、データが何があるか、だれが何を担当しているのか、仕様がどうなっているのか、という部分がわかっていないと難しいんですよ。
これができる人は作業側でも必要な人だったりするし、専任させていると優秀な人のキャリアパスをおかしくしてしまうこともあるので、そういったところも含めてどうしていくのか考える必要があるかと思います。