Unity Editor上でのVersion Controlの使い方 〜Perforce編〜
概要
UnityにはBuilt-inのVersionControlという関数があり、これを利用することでシェルコマンドを叩くこと無くGitやPerforceなどにCommit・Submitすることができます。
Unity Editor上からファイルを自動生成・削除、及びPerfoceに反映させるツールを作ったのでその一部を紹介します。
Version Controlの設定
[Project Setitngs] > [Editor]上にVersion Controlという項目を設定します。今回はPerfoceを使用するためPerfoceの設定をしました。
Connectのボタンを押してConnectedになっていることを確認してください。
VersionControlクラスの使い方
まずUnityEditor.VersionControl
をインポートします、C#ではusing
を使用します。
using UnityEditor.VersionControl;
また各関数でassetsのパスが必要となるため、assetsを用意しておきます。
var assetPath = Application.dataPath; var assets = new AssetList { new Asset(assetPath) };
Task
今回使用する関数はどれもUnityEditor.VersionControl.Task
を返します。必要に応じでWait
を呼んでください。
このTaskはawaitableではないため同期処理になりプロセスを専有します。他の作業がブロックされるのでなるべく呼ぶ回数を減らすことをおすすめします。
Checkout
Perfoceではすべてのファイルがreadonlyなので、ファイルを変更する前に必ずcheckoutする必要があります。
そのため必ずWait
を呼ぶ必要があります。
Provider.Checkout(assets, CheckoutMode.Asset).Wait();
PerfoceにはChaneglistという概念があります。 Gitのbranchに似てますが、同時に複数のChangelistを使用することができます。
例えば作業AとBを同時にする必要があり、それぞれを別のChangelistで管理することでSubmitするタイミングを調整することができます。
ここでCheckoutされたファイルは自動的にdefault
のChangelistに入ります。
Add
新しいファイルを追加します。ディレクトリパスを指定することでディレクトリ配下の新規ファイルを追加することができます。
Provider.Add(assets, true).Wait();
これらのファイルはAddコマンドを呼ばない限りPerfoce上で確認することができません。
これがとても厄介で、追加漏れしたファイルは存在しているにも関わらず、Perfoce上で確認ができないため困ることが多々あります。 この追加漏れをチェックするreconcileというコマンドがありますが、かなり不便です。
Delete
既存のファイルを削除します。
Provider.Delete(assets).Wait();
Revert
変更を破棄します。 Perforceの場合、チェックアウトされたすべてのファイルがSubmitの対象になります。そのため変更されてないファイルはUnchangedで破棄する必要があります。
Provider.Revert(assets, RevertMode.Normal).Wait();
Provider.Revert(assets, RevertMode.Unchanged).Wait(); // 未変更のファイルのみを破棄
Submit
変更を反映します。 changeSetのdescriptionはChangelistのdescriptionにリンクします。第四引数はSaveOnlyです。
var changeSet = GetChangeSet();
Provider.Submit(changeSet, assets, changeSet.description, true).Wait();
Submitを2回呼ぶとコネクションが切れることがあるので、2回呼ぶことは避けたほうが良さそうです。 コネクションが切れてしまった場合はProject Settingsからまた有効にする必要があります。
Example
実際のコードではasset配下は範囲が広すぎてパフォーマンス上の懸念があるため、作業範囲を限定します。
この例は、Zipファイルを展開し、Zip内に存在するファイルの追加・変更と存在しないファイルの削除をResources
配下に反映します。
// Zipファイルの展開 using (var archive = new ZipArchive(stream, ZipArchiveMode.Read, true)) { var assetPath = Application.dataPath; var resourcePath = Path.Combine(assetPath, "Resources"); var assets = new AssetList { new Asset(resourcePath) }; // Resource配下をCheckout Provider.Checkout(assets, CheckoutMode.Asset).Wait(); // Zipファイル内に存在するパスのキャッシュ var assetPathSet = new HashSet<string>(); foreach (var entry in archive.Entries) { var destinationPath = Path.Combine(resourcePath, entry.FullName); var dirName = Path.GetDirectoryName(destinationPath); if (dirName != null) { // ディレクトリが存在しない場合エラーになるので作成する Directory.CreateDirectory(dirName); } entry.ExtractToFile(destinationPath, true); // フルパスではなくasset配下のパスが必要なためassetのパスを取得する。これはmetaファイルにも使用される。 assetPathSet.Add(new Asset(destinationPath).assetPath); } // ディレクトリのmeta情報のために追加する assetPathSet.Add(new Asset(resourcePath).assetPath); // ディレクトリ配下の新規ファイルを追加する var addTask = Provider.Add(assets, true); addTask.Wait(); // Zipファイルに存在しないファイルの削除 var deleteAssets = new AssetList(); // addTask.assetListはチェックアウトされているすべてのファイル名を取得できる deleteAssets.AddRange(addTask.assetList.Where(asset => !assetPathSet.Contains(asset.assetPath))); Provider.Delete(deleteAssets).Wait(); // これらのファイルをデータ配下のChangelistに移動させる var changeSet = GetChangeSet("データ"); Provider.Submit(changeSet, addTask.assetList, changeSet.description, true).Wait(); // 未変更のファイルを取り消す Provider.Revert(assets, RevertMode.Unchanged).Wait(); }
まとめ
Unity EditorのVersionControlの使い方について紹介しました。 この順番で呼ばないとうまく動かなかったりハマりどころが多かったりしますが、自動化すると便利なことは多いのでぜひトライしてみてください。
Gitを使いたい。