Skip to the content.

GitやSVNだけではなぜ苦しくなるのか――ゲーム開発のバージョン管理・アセット管理実務


「Gitに入れておけば、どんなファイルでも安全に共同編集できる」。

新人プランナーが抱きやすい誤解である。

GitやSubversion(以下、SVN)は、ファイルの変更履歴を残し、過去へ戻し、誰が何を変えたかを追うためのバージョン管理システムである。画像も音声も登録できる。小規模なゲームなら、それだけで最後まで走り切れることもある。

しかし、 履歴を保存できること同じファイルを安全に同時編集できること は別だ。ソースコードのようなテキストは、変更箇所を行単位で比較しやすい。対して、PSD、音声、3Dモデル、ゲームエンジン固有のシーンなどは、中身を人が行単位で読み、二人分の変更を機械的に合成できるとは限らない。

問題はツールの優劣ではない。 ファイルの性質、人数、履歴の重さ、同時編集の頻度に、運用が合っているか である。

この記事では、まずGitとSVNで何ができるかを押さえる。次に、アセットが増えると何が壊れるのかを分解する。そのうえで、Git LFS、ロック、Perforce P4、Unity Version Controlを「次の段階」として位置づける。


1. まず、GitとSVNは何を管理しているのか

バージョン管理の基本は、 ある時点のファイル群と、そこへ至る変更履歴を再現できるようにすること である。誤った変更を戻す、リリース時点を取り出す、問題が入った時期を調べる、といった作業の土台になる。

1-1. Gitは各自が履歴を持つ分散型

Gitは 分散型バージョン管理システム である。通常のクローンでは、作業者のPCにもリポジトリ、つまりファイルと履歴をまとめた保管庫の複製を持つ。公式解説でも、分散型ではクライアントが最新版だけでなく履歴を含むリポジトリを複製すると説明されている。[1]

初出の用語を短く整理する。

Gitはソースコードを例に説明されることが多く、ブランチとマージを使った並行開発が強い。ただし、登録対象はコードに限られない。公式の入門書も、画像を含むほぼあらゆるファイルを管理できるとしている。[1]

1-2. SVNは中央の履歴を共有する集中型

SVNは 集中型バージョン管理システム である。中央サーバー上のリポジトリを共有し、作業者は必要な範囲をローカルの作業コピーへ取り出して編集する。

SVNの公式コミュニティが案内する解説書でも、チェックアウトは作業コピーを作る操作であり、資源を予約するロックとは別だと説明されている。[2] 「チェックアウトしたから自分だけが編集できる」と思い込むと、後述する同時編集事故につながる。

1-3. GitかSVNか、だけでは答えが出ない

GitとSVNは構造が違う。それでも、履歴、差分、復元、ブランチ、マージという目的は重なる。

日本のゲーム開発でも、配属先や既存プロジェクトによってGit、SVN、後述する専用ツールのいずれに出会う可能性もある。

新人が先に見るべきなのは製品名ではなく、次の四点である。

  1. 正式な履歴はどこにあるか
  2. 変更を確定する単位は何か
  3. 同時編集したとき、何を自動統合できるか
  4. 統合できないファイルを誰が先に編集するか

GitとSVNの構造比較。Gitは作業者ごとにローカル履歴と作業ツリーを持ち、SVNは中央サーバーと作業コピーを接続する模式図。


2. なぜテキストは共同編集しやすく、バイナリは苦しいのか

ここが本題である。

2-1. 「差分が取れない」には二つの意味がある

ソースコード、JSON、YAMLなどのテキストは、人が読める行の並びである。たとえば一人が敵のHPを変え、別の人が説明文を変えたなら、変更行が重ならないため、自動マージできる可能性が高い。

一方、PNG、WAV、FBX、PSDなどのバイナリファイルは、アプリケーション固有のバイト列で保存される。内部に圧縮、索引、メタデータがあると、小さな編集でも広い範囲のバイトが変わりうる。ゲームエンジンのシーンファイルも、設定によってはテキスト形式で保存できるが、巨大で参照関係が複雑なら、人が安全にマージできるとは限らない。

ここで、二つを区別したい。

バイナリで特に難しいのは前者である。Gitの公式文書でも、明確なマージ規則を持たないバイナリには、現在側を残してコンフリクトとして人に判断させる方式が適するとされる。外部ツールで見た目の差分を表示できても、 表示できることと、安全に自動合成できることは同じではない。 [3]

逆に、「1バイト変われば、必ずファイル全体を無圧縮で追加保存する」と言い切るのも正確ではない。Gitのpackfileは、オブジェクトを丸ごと圧縮する場合と、別オブジェクトとの差分として圧縮する場合がある。SVNにもリポジトリ内の差分保存がある。[4][5]

それでも、編集後のファイルは新しい版として追跡される。巨大ファイルを何度も更新すれば履歴の総量は増える。形式やサイズによっては差分圧縮も効きにくい。つまり、 「全版が必ず丸ごと」ではないが、「大容量バイナリの履歴が無料になる」わけでもない。

2-2. 典型事故――二人が同じシーンを編集する

場面を具体化する。

テキストなら、NPCの行と照明の行を自動統合できるかもしれない。しかし、シーンが不透明なバイナリなら、ツールは「A版とB版のどちらが正しいか」を判断できない。Bが自分の版で上書きすればAの作業が消える。A版を採用すればBの作業が消える。手動で両方の画面を開き、片方の作業を再現することになる。

これはバックアップ不足ではない。履歴には両方の版が残っていても、 二つの意図を一つの完成データへ合成する方法がない ことが問題である。

同じTown.sceneをAとBが同時編集し、提出と更新を経てコンフリクトと再作業に分岐する流れ。

2-3. リポジトリは、初期には軽く見える

プロジェクト序盤は、仮画像、少数のモデル、小さなマップしかない。クローンも更新も速い。同じファイルを触る人数も少ない。この時点では、通常のGitやSVNで問題が見えにくい。

中盤以降、次の変化が重なる。

Gitの通常のクローンは履歴を手元へ持つため、大きなバイナリ履歴は初回取得やCI環境の準備時間へ響く。部分クローンなどの軽量化策もあるが、必要になったデータは後から取得するため、複雑さと待ち時間の場所が変わる面もある。[6] SVNでも、中央から必要範囲を取得できる一方、巨大な作業コピーの更新やサーバーとの通信は無視できない。

序盤で動いた運用が、中盤でも動く保証はない。 問題が出た時点では、すでに履歴も人数も大きい。これが移行を難しくする時間差である。


3. 最初の一歩としてのGit LFS

Gitを捨てずに大容量ファイルの負担を下げたいとき、Git LFS(Git Large File Storage)が候補になる。

Git LFSはGitの拡張である。指定した大容量ファイル本体を通常のGitオブジェクトとして抱え込む代わりに、Git側には小さな ポインターファイル を置き、実データをLFS用ストレージへ保存する。対象は.gitattributesのパターンで指定する。既存履歴はgit lfs trackだけでは自動移行されず、必要なら履歴を書き換える移行操作が要る。[7]

Git LFSが緩和すること

Git LFSだけでは解決しないこと

Git LFSにはファイルロックAPIもあり、対応サーバーではロックの作成、一覧、解除、push時の確認ができる。したがって「LFSにはロックがない」とも言い切れない。ただし、 LFSへ置くだけで同時編集問題が自動解決するわけではない。ロック対象の指定、サーバー対応、クライアント設定、解除運用まで整えて初めて機能する。Git LFSのロックAPI自体も、単一ブランチの単純な利用を基本として説明している。[8]

Git LFSは、万能な専用アセット管理ではない。 Gitのまま容量問題を分離し、必要ならロックを足す折衷策 と考えると位置づけを誤りにくい。


4. マージできないなら、先に編集者を一人へ絞る

バイナリの同時編集に対する素朴で強い方法が 排他ロック である。

作業者が編集前に「このファイルを使う」と宣言する。ほかの人は解除されるまで編集を待つ。並行作業を減らすため一見古く見えるが、自動マージできないファイルでは合理的だ。二人が半日ずつ作業して片方を捨てるより、編集前に待つ方が損失を予測できる。

SVNもロック機能を持つ。Apache Subversionの機能説明では、複数人が同じファイルを編集しようとした際に警告するためのロックを、任意で利用できるとしている。[9] つまり、ロックの発想は専用ツールだけのものではない。

4-1. Perforce P4とUnity Version Control

規模が大きくなり、大容量バイナリとファイル単位の作業が中心になると、その運用を製品の中心に置いたツールが候補になる。

これらを「GitやSVNより上位の正解」と見る必要はない。GitやSVNでもロックや外部ストレージを組み合わせられる。専用製品の価値は、 巨大データ、中央での可視性、GUI、ロック、権限、部分的な取得などを、一つの運用として組み立てやすいこと にある。

ゲームエンジン側にもロックを意識した導線がある。Unreal Engineの公式文書では、アセット変更時の自動チェックアウトや、パッケージ変更時にチェックアウト、つまりロックを促す設定が案内されている。[13] ツール単体ではなく、エディタ内で「編集前に気づけるか」が事故率を左右する。

4-2. ロックは、人間が守って初めて効く

ロックを入れれば事故が消えるわけではない。

対策は精神論ではなく、運用設計で行う。

ロック待ちが頻発するなら、ツールだけでなくアセット構造も疑う。一つの巨大マップに全要素を詰めず、サブシーン、レイヤー、プレハブ、外部データへ分ければ、競合する単位を小さくできる。 ロックは衝突を防ぐ仕組みであり、衝突しやすい設計を治す仕組みではない。


5. チーム開発では、機能より「迷わなさ」が効く

同じリポジトリを使っていても、職種ごとに日常が違う。

プログラマーはIDE、ターミナル、細かいコミット、ブランチの切り替えに慣れていることが多い。アーティストはDCCツールやエディタ上のGUIが仕事の中心になる。プランナーはシーン、表、設定ファイル、仕様書を横断する。もちろん個人差はあるが、全員へ同じ操作習熟を期待するのは危険だ。

運用を決めるときは、次を確認する。

高度な機能が多くても、日常操作が分からなければ回らない。Unity Version Controlがプログラマー向けとアーティスト向けのワークフローを分けて案内しているのも、同じ操作体系を全職種へ押しつけない発想の一例である。[12]

5-1. ブランチを増やすほど安全、とは限らない

コード中心なら、短い機能ブランチを作り、レビュー後にマージする運用は扱いやすい。ところが、同じ巨大バイナリが複数ブランチで別々に更新されると、最後に安全な統合方法がない。

そのため、バイナリの多い領域では、主流に近い一本へ小さく早く統合する トランクベース寄り の運用が候補になりやすい。枝を減らせば、同じアセットの別版が長期間育つ時間を短くできる。ただし、これは「ゲーム開発は必ず一本のブランチにせよ」という規則ではない。

リリース版の保守、機種別対応、長期の大型追加コンテンツでは、分離した開発線が必要になる。Perforce P4にもStreamsというブランチ・マージ機能があり、Unity Version ControlのSmart Locksもブランチを考慮する。専用ツールはブランチを禁止するのではなく、関係とロックを管理しやすくする。[12][14]

判断軸は、ブランチ本数ではない。


6. どの規模で、どこまで導入するか

ツール選定は、製品比較表だけでは決まらない。現在の痛みと、移行後に増える仕事を並べる。

状況 現実的な候補 得られるもの 残る負担
少人数、テキスト中心、Gitに習熟 Git 軽いブランチ、豊富な周辺環境 大容量履歴とバイナリ競合
少人数から中規模、大容量ファイルが一部 Git + Git LFS Git運用を保った容量分離 LFSストレージ、対象指定、必要ならロック運用
既存の集中型運用、ファイル単位の管理 SVN + ロック 中央履歴、必要範囲の作業コピー、排他運用 サーバー管理、ブランチ統合、GUI教育
大規模、大容量バイナリ中心、多職種 Perforce P4、Unity Version Controlなど ロック、中央可視性、大規模ファイル向けの導線 ライセンス、管理者、移行、教育、運用設計

導入判断では、少なくとも次を測る。

  1. リポジトリと作業コピーの容量
  2. 新規参加者が作業開始できるまでの時間
  3. 1週間あたりのバイナリ競合件数と再作業時間
  4. 一つのファイルを触る職種と人数
  5. ロック待ち時間と放置ロック数
  6. CI、ビルドマシン、外注先が取得するデータ量

「将来大きくなるから」で高価な仕組みを先回りすると、学習、ライセンス、サーバー、移行、障害対応の費用を早くから負う。逆に、毎週アセットを作り直しているのに「Gitで頑張れる」と先送りすれば、見えにくい人件費を払い続ける。

移行には、ファイルをコピーする以上の仕事がある。履歴をどこまで持つか、旧リポジトリを読取専用で残すか、権限をどう写すか、CIとエディタ連携をどう直すか、全員が同じ日から切り替えるかを決める必要がある。

だから、正解は「大規模ならP4」「小規模ならGit」という一行にはならない。 現在の再作業と待ち時間が、移行と運用の費用を上回るか。その比較こそが実務である。


7. プランナーが理解すべきなのはコマンドではなく、失われる仕事である

バージョン管理は、詳しいプログラマーに任せる領域に見える。だが、同じシーンを誰と共有するか、データをどの粒度へ分けるか、いつリリース枝へ反映するかは、プランナーの仕様と進行に直結する。

仕組みを知らなければ、コンフリクトを「操作ミス」で片づける。ロック待ちを「作業者が遅い」と誤解する。巨大な一枚マップを求めたまま、管理ツールだけへ解決を期待する。反対に、仕組みが分かれば「同じファイルを触らない分け方はできるか」「この変更は今日中に本流へ入れるべきか」と、事故の前に質問できる。

覚えるべき結論は、特定ツールの名前ではない。

バージョン管理の目的は、ファイルを保存することではない。チームが作った意図を失わず、次の人が安全に仕事を続けられる状態を作ることである。

References

1. Git - About Version Control - バージョン管理の目的、集中型と分散型の違い、分散型では履歴を含むリポジトリを複製することを説明したGit公式入門書。

2. Version Control with Subversion - SVNのリポジトリ、作業コピー、リビジョン、チェックアウトとロックの違いを説明する、Apache Subversion公式サイトから案内されている解説書。

3. Git - gitattributes Documentation - Gitにおけるバイナリ判定、外部差分表示、テキストとバイナリの3-wayマージ動作を説明した公式文書。

4. Git - git-pack-objects Documentation - Gitのpackfileが、オブジェクトを圧縮した全体または別オブジェクトとの差分として格納することを説明した公式文書。

5. Version Control with Subversion: Repository Data Maintenance - SVNがリポジトリ容量を抑えるために差分保存を用いることを説明する解説書の章。

6. Git - git-clone Documentation - --filter=blob:noneなど、必要になるまでファイル内容を取得しない部分クローンを説明した公式文書。

7. Git Large File Storage - Git LFSの導入、拡張子パターンによる追跡、既存履歴には自動適用されないことを説明した公式リポジトリ。

8. Git LFS File Locking API - Git LFSにおけるロックの作成、一覧、解除、push時の検証と、単一ブランチを基本とするロック仕様を説明した公式文書。

9. Apache Subversion Features - SVNが任意のファイルロックを提供することを説明したApache Subversion公式ページ。

10. Preventing multiple checkouts - Perforce P4の+lによる排他オープンと、通常のp4 lockとの違いを説明した公式文書。

11. P4 (Helix Core) Customer Handbook - 現行製品名をP4、旧称をHelix Coreとして案内するPerforce公式ページ。

12. Unity Version Control(旧称:Plastic SCM) - 現行名称、旧称、大容量バイナリ、職種別ワークフロー、Smart Locksを説明したUnity公式ページ。

13. Source Control in Unreal Engine - Unreal Editorにおけるアセット変更時の自動チェックアウトと、パッケージ変更時のロック確認を説明したEpic Games公式文書。

14. Perforce Streams - Perforce P4のブランチ・マージ機能であるStreamsを説明した公式ページ。


この文書は、Perplexity、Claude、OpenAI Codex の3つのAIの支援を受けて著述されたものです。引用画像を除き、MIT License にて提供されています。