ファイルロック
ファイルロック
Section titled “ファイルロック”Textil のファイルロック機能は、バイナリファイルの編集競合を未然に防ぎます。ブランチを跨いだ排他制御と系譜追跡により、チーム開発での競合を根本から防止します。
なぜファイルロックが必要か
Section titled “なぜファイルロックが必要か”Unreal Engine のアセットファイル(.uasset、.umap)はバイナリ形式です。テキストファイルと異なり、Git の自動マージが効きません。2人が同じファイルを編集すると、どちらかの変更を捨てるしかなくなります。
ファイルロックは「編集前に宣言する」ことで、この問題を回避します。
なぜ Git LFS のロックではないのか
Section titled “なぜ Git LFS のロックではないのか”Git LFS にもロック機能(git lfs lock)がありますが、ブランチ開発との相性に根本的な課題があります。
- 1Alice が main で
Hero.uassetをロック - 2Alice が編集してコミット、ロック解除
- 3Bob が feature ブランチで同じファイルをロックロックは空いているので取得できてしまう
- 4Bob が編集してコミット
- 5feature を main にマージ競合発生、どちらかの変更を捨てるしかない
ロックが空いていても、別ブランチで編集済みかもしれない。従来のロックは「今誰が持っているか」しか見ないため、この問題を防げません。
Textil のアプローチ:系譜追跡
Section titled “Textil のアプローチ:系譜追跡”Textil のロックは、ファイルの「系譜(Lineage)」を追跡します。ロック取得時に、申請者が最新の状態を持っているかを検証し、持っていなければロックを拒否します。
- 1Alice が main で
Hero.uassetをロック - 2Alice が編集してコミット、ロック解除
- 3Bob が feature ブランチでロックを試みる「Alice の変更を取り込んでいません」と拒否
- 4Bob が git merge main で Alice の変更を取り込む
- 5Bob が再度ロックを試みる成功
この検証により、「ロックを取れたなら、安全に編集できる」ことが保証されます。
グローバルスコープ
Section titled “グローバルスコープ”Textil のロックはブランチを跨いで排他的です。あるブランチでロックを取得すると、他のブランチからも同じファイルをロックできません。
バイナリファイルはマージできないため、ブランチごとに独立したロックを許可する意味がありません。グローバルスコープにすることで、マージ時の競合を根本から防ぎます。
内容ベースの同一性判定
Section titled “内容ベースの同一性判定”系譜の検証には、Git LFS の oid(ファイル内容のハッシュ)を使用します。これにより、squash merge や rebase でコミット履歴が書き換わっても、ファイルの内容が同じであれば正しく追跡できます。
- 1feature ブランチで
Hero.uassetを編集(oid: abc123) - 2main に squash merge(新しいコミットだが、oid は同じ abc123)
- 3別の開発者がロックを試みるoid が一致するため、正しく「最新を持っている」と判定
リアルタイム同期
Section titled “リアルタイム同期”ロック状態は WebSocket を通じてチーム全体にリアルタイムで共有されます。
- 誰かがロックを取得すると、即座に全員に通知
- 誰かがファイルを更新(fetch/push)すると、その情報も全員に伝播
- 接続が切れても、再接続時に最新状態を自動復元
この仕組みにより、チーム全員が常に同じロック状態を見ることができます。
対象ファイル
Section titled “対象ファイル”ロック機能は Git LFS で管理されているファイルのみが対象です。テキストファイル(.cpp、.h、.ini など)は Git の通常のマージで解決できるため、ロックの対象外です。
一般的な Unreal Engine プロジェクトでは、以下のファイルが LFS 管理され、ロック対象となります:
.uasset- アセットファイル全般.umap- レベルファイル- テクスチャ、メッシュ、サウンドなどのインポート元ファイル