Git LFSのコスト爆発とUnrealアセットの競合を解決するLore VCS移行ガイド
プロジェクトが大きくなると、Git LFSは災害へと変貌します。ソースコードの数行の修正は一瞬ですが、ギガバイト単位のアートアセットが混ざり始めると、1回のコミットごとに砂時計が数十秒間回り続けます。巨大なファイルを丸ごとコピーして蓄積するLFSの鈍重な構造のせいで、リポジトリ容量はすぐにテラバイトを超え、帯域幅の利用料請求書には恐ろしい数字が刻まれます。
エピックゲームズがオープンソースとして公開したLoreは、バイナリファイルを最優先で扱います。ファイルをブロック単位に分割して重複を排除するFastCDC方式を採用しており、パッケージ容量と転送帯域幅を劇的に削減します。DevOpsの専門人材がいない小規模チームでも今すぐ適用できる、Loreの実務的な移行および最適化手法をまとめました。
1. Git LFSからLoreへの段階的な移行
既存のGitリポジトリに蓄積されたソースコードのコミット履歴をわざわざ捨てる必要はありません。軽量なコードはGitにそのまま残し、重いバイナリアセットだけをLoreリポジトリに分離するハイブリッド戦略が現実的です。
以下のスクリプトは、Git LFSが追跡していたファイルリストを識別して対称的なディレクトリ構造を作成し、コピーのSHA-256ハッシュを照合してデータ欠損なくLoreへ移行します。
`bash
#!/usr/bin/env bash
set -euo pipefail
GIT_REPO_DIR="HOME/projects/my−game−git"LOREREPODIR="HOME/projects/my-game-lore"
LORE_SERVER_URL="lore://127.0.0.1:41337/my-project"
echo "[1/5] Loreリポジトリの初期化およびリモートバインディング..."
if [ ! -d "LOREREPODIR"];thenmkdir−p"LORE_REPO_DIR"
cd "LOREREPODIR"lorerepositorycreate"LORE_SERVER_URL"
else
cd "$LORE_REPO_DIR"
fi
echo "[2/5] Git LFS追跡ファイルリストの収集..."
cd "GITREPODIR"LFSFILES=(git lfs ls-files -n | grep -E ".(uasset|umap|fbx|png|psd)$" || true)
if [ -z "$LFS_FILES" ]; then
echo "移行するLFSファイルはありません。"
exit 0
fi
echo "[3/5] ファイルコピーおよび検証用マニフェストの作成..."
echo "LFSFILES"∣whileread−rfilepath;doif[−f"filepath" ]; then
dest_dir="LOREREPODIR/(dirname "filepath")"mkdir−p"dest_dir"
cp -p "filepath""LORE_REPO_DIR/filepath"sourcehash=(openssl dgst -sha256 "$filepath" | awk '{print 2}')
echo "filepath:sourcehash">>"LORE_REPO_DIR/.lore_migration_manifest"
fi
done
echo "[4/5] Git LFSの解除およびLoreへのステージング..."
cd "GITREPODIR"echo"LFS_FILES" | while read -r filepath; do
git rm --cached "$filepath"
done
sed -i.bak -E 's/filter=lfs diff=lfs merge=lfs//g' .gitattributes
cd "LOREREPODIR"echo"LFS_FILES" | while read -r filepath; do
lore stage "$filepath"
done
lore commit -m "Migration: Transfer heavy assets from Git LFS to Lore"
lore push
echo "[5/5] データ整合性の検証..."
lore repository verify state
lore repository verify fragment
if [ -f ".lore_migration_manifest" ]; then
migration_errors=0
while IFS=":" read -r file sha; do
if [ -f "file"];thencurrenthash=(openssl dgst -sha256 "$file" | awk '{print 2}')
if [ "sha" != "$current_hash" ]; then
echo "汚染されたファイルを検知: file"migrationerrors=((migration_errors + 1))
fi
fi
done < .lore_migration_manifest
if [ $migration_errors -eq 0 ]; then
echo "移行完了。すべてのデータが100%整合性を保った状態で復旧されました。"
rm .lore_migration_manifest
else
echo "検証失敗: $migration_errors 件のファイルの整合性に問題があります。"
exit 1
fi
fi
`
ターミナルを開き、上記の内容を migrate.sh として保存します。chmod +x migrate.sh コマンドで実行権限を付与した後、自身のローカルパスに合わせて変数を修正して実行してください。
この作業を終えると、リモートクラウドのLFSストレージ使用量が即座に減少します。エピックゲームズの自社導入事例によると、このブロックレベルの重複排除技術によってインフラ維持コストを50%程度まで削減可能です。
2. CI/CDパイプラインにおけるオンデマンドハイドレーション(On-demand Hydration)の適用
ビルドサイクルのたびに数百ギガバイトのゲームアセット全体を再ダウンロードするパイプラインは、ネットワークカードとディスクI/Oを破壊する主犯です。Loreはビルド時間を短縮するために、仮想ファイルシステムに基づいた遅延復旧(On-demand Hydration)をサポートしています。
最初のクローン段階ではメタデータ構造のチェーンとディレクトリツリーのみをシェルとして複製し、コンパイラがクック(Cook)プロセスで実際のアセットを読み込む際に必要なバイナリチャンクのみを動的にストリーミングしてディスクを埋める方式です。
`yaml
name: Game Project On-Demand Production Build
on:
push:
branches: [ release-candidate ]
env:
LORE_SERVER: "lore://10.0.1.50:41337/game-depot"
SHARED_STORE_PATH: "/var/lib/lore_shared_chunk_store"
WORKSPACE_PATH: "game_build_workspace"
jobs:
assemble-assets:
runs-on: self-hosted
steps:
- name: Persistent Shared Storeの準備
run: |
if [ ! -d "env.SHAREDSTOREPATH"];thensudomkdir−p"{{ env.SHARED_STORE_PATH }}"
sudo chmod 777 "env.SHAREDSTOREPATH"loreshared−storecreate"{{ env.SHARED_STORE_PATH }}"
fi
- name: Shared Cacheを経由したSparse Bare Clone
run: |
lore clone \
--bare \
--use-shared-store \
--shared-store-path "${{ env.SHARED_STORE_PATH }}" \
"${{ env.LORE_SERVER }}" \
"${{ env.WORKSPACE_PATH }}"
- name: ビューフィルタによる不要なシネマティックソースの除外
run: |
cd "${{ env.WORKSPACE_PATH }}"
echo "+ /SourceCode/" > .lore/view
echo "+ /Config/" >> .lore/view
echo "+ /Content/Core_Assets/" >> .lore/view
echo "- /Content/Cinematic_RAW/" >> .lore/view
- name: 必須チャンクのみをローカルディスクに同期
run: |
cd "${{ env.WORKSPACE_PATH }}"
lore sync
- name: Unreal Engine Cookerの実行
run: |
cd "${{ env.WORKSPACE_PATH }}"
./RunUAT.sh BuildCookRun \
-project="$(pwd)/GameProject.uproject" \
-platform=Win64 \
-clientconfig=Development \
-cook -stage -pak -archive
`
ビルド専用サーバーに /var/lib/lore_shared_chunk_store のような永続キャッシュストレージを用意しておくと効果が最大化されます。lore clone --bare コマンドでインデックス情報のみを素早く取得した後、.lore/view フィルタファイルに必要なパスだけを残して lore sync を実行します。この構造を定着させれば、ビルドノードに転送されるトラフィックが通常比で85%以上削減されます。全体のビルド時間は平均30%程度短縮されます。
3. ファイルロックシステムによるアセット競合の防止
Unreal Engineの .uasset やレベルマップファイルのようなバイナリアセットは、テキストコードのようにメインブランチで自動マージすることができません。2人のアーティストが同じアセットを同時に修正すると、後からプッシュしたアーティストが前の作業者の作業を上書きして消し去ったり、タイムラインが崩れたりする事故が発生します。
Loreはリモートサーバーの変更不可能な元帳を基準として排他的制御を行うロック(Lock)機能を直接提供しています。
`bash
特定のバイナリキャラクターモデルファイルに単独編集権限を要求
lore lock acquire Content/Characters/HeroMesh.uasset --branch main
特定のフォルダ配下のリソースのロック所有状態を確認
lore lock status Content/Characters/HeroMesh.uasset
リモートリポジトリで特定の作業者がロックした全ファイルを検索
lore lock query --branch main --owner developer_artist_03
作業完了およびプッシュ後の権限返却
lore lock release Content/Characters/HeroMesh.uasset --branch main
`
アーティストがファイルに触れる前に lore lock acquire コマンドでロックを占有させるルールを構築する必要があります。修正が終わり、コミットとプッシュがリモート側に無事反映されたら lore lock release でロックを解除し、次の作業者に渡します。
プランナーやアーティストがターミナルコマンドに不慣れな場合は、AnchorpointのようなデスクトップGUIツールに該当パスを連動させ、マウスの右クリックだけでこれらのロックコマンドが実行されるような環境を整えてあげると良いでしょう。
4. ハードウェアスペック別のキャッシュチューニングガイド
作業環境の仕様に合わせてクライアント設定を調整することで、ファイルI/Oのボトルネックを防ぐことができます。
作業者PCの仕様別ローカルクライアントチューニング
- 高性能システム(NVMe SSD、32GB RAM以上、マルチコアCPU): OSの仮想メモリマッピング技術を経由し、メモリマップに基づいた直接演算を許可します。同期の遅延をなくすために最大並列ダウンロードスレッド数を拡張し、ディスクキャッシュの保持期間を長く設定します。
- 普及型およびアーティストシステム(SATA SSDまたはHDD、16GB以下RAM): メモリ枯渇によるエンジンクラッシュを防ぐために、メモリマッピング方式をオフにします。ディスクに直接書き込む
--direct-file-write および --direct-file-io フラグをオンにし、ガベージコレクションのスケジュール間隔を長くすることで、作業中の突然のディスク占有現象を防ぎます。
圧縮アルゴリズム選択による性能分析
Loreアーキテクチャ決定会議(ADR-00016)の結果を参照すると、基本圧縮エンジンとしてZstandard Level 6規格を設定するのが効率面で最もバランスが優れています。
| 圧縮アルゴリズムの種類 |
データ最終圧縮率 (%) |
圧縮演算速度 (MiB/s) |
展開速度 (MiB/s) |
移植性および特徴 |
| LZ4 Default |
47.6% |
718.7 |
2494.5 |
速度は速いがストレージ容量の無駄が大きい |
| Zstd Level 1 |
34.5% |
602.0 |
1363.1 |
速度と容量保存の適度な妥協点 |
| Zstd Level 6 (推奨) |
28.9% |
136.5 |
1284.9 |
スペース削減対比で最高の処理効率を維持 |
| Oodle Kraken 3 (Fast) |
28.2% |
95.6 |
1413.1 |
エピックゲームズ独占Oodle依存ライブラリが必要 |
| Oodle Kraken 6 (既存の基本) |
23.9% |
2.2 |
1312.6 |
ギガバイト単位の移行時に速度が大幅に低下 |
以前よく使われていたOodle Kraken Level 6は、バックエンドのシリアライズ過程で圧縮処理速度が毎秒2.2 MiBレベルまで低下し、アーティストの退勤前のコミット待ち時間を延ばす主原因となっていました。
一方、Zstd Level 6はOodle Kraken 6に迫る圧縮率を出しながらも、ローカルチャンクブロックの圧縮速度が136.5 MiB/sで、約62倍高速です。海外拠点や在宅勤務者が多く帯域幅の干渉が激しい場合は、ローカルネットワーク内にプロキシエッジキャッシュノードを構成する2層サーバートポロジの構成を検討することをお勧めします。