Arbitrator.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // Copyright (c) 2025 TerraByte Inc.
  2. //
  3. // This script creates a custom Unity Editor window called "Arbitrator" to compare
  4. // local Git changes with the tracked remote branch using the LibGit2Sharp library.
  5. //
  6. // HOW TO USE:
  7. // 1. Ensure you have manually installed the LibGit2Sharp v0.27.0 package.
  8. // 2. Create an "Editor" folder in your Assets directory if you don't have one.
  9. // 3. Save this script as "Arbitrator.cs" inside the "Editor" folder.
  10. // 4. In Unity, open the window from the top menu: Terra > Arbitrator.
  11. // 5. Click the "Compare with Cloud" button. Results will appear in the console.
  12. using System;
  13. using System.IO;
  14. using UnityEngine;
  15. using UnityEditor;
  16. using LibGit2Sharp;
  17. namespace Terra.Arbitrator
  18. {
  19. public class Arbitrator : EditorWindow
  20. {
  21. // Creates a menu item in the Unity Editor to open this window.
  22. [MenuItem("Terra/Arbitrator")]
  23. public static void ShowWindow()
  24. {
  25. // Get an existing open window or if none, make a new one.
  26. GetWindow<Arbitrator>("Arbitrator");
  27. }
  28. // This method is called to draw the contents of the editor window.
  29. private void OnGUI()
  30. {
  31. // Add some descriptive text to the window.
  32. EditorGUILayout.LabelField("Compare local changes against the cloud.", EditorStyles.boldLabel);
  33. EditorGUILayout.HelpBox("This tool will fetch the latest state from the remote repository and show you which files have been added, modified, or deleted locally.", MessageType.Info);
  34. // Render a button. If the user clicks it, call our main logic function.
  35. if (GUILayout.Button("Compare with Cloud", GUILayout.Height(40)))
  36. {
  37. CompareLocalToRemote();
  38. }
  39. }
  40. /// <summary>
  41. /// The core function that performs the fetch and diff operations.
  42. /// </summary>
  43. private static void CompareLocalToRemote()
  44. {
  45. // The project root is one level above the "Assets" directory.
  46. var projectRoot = Directory.GetParent(Application.dataPath)?.FullName;
  47. try
  48. {
  49. // Use a 'using' statement to ensure the repository object is properly disposed of.
  50. // This opens the repository at the root of your Unity project.
  51. using var repo = new Repository(projectRoot);
  52. Debug.Log("Repository opened successfully.");
  53. // --- Step 1: Fetch the latest state from the remote ---
  54. // Get the primary remote, which is typically named "origin".
  55. var remote = repo.Network.Remotes["origin"];
  56. if (remote == null)
  57. {
  58. Debug.LogError("No remote named 'origin' was found. Please configure a remote for your repository.");
  59. return;
  60. }
  61. // IMPORTANT: For private repositories, you'll need to provide credentials.
  62. // This is a more advanced topic involving Personal Access Tokens (PATs).
  63. var fetchOptions = new FetchOptions();
  64. Debug.Log($"Fetching latest changes from '{remote.Name}' at {remote.Url}...");
  65. Commands.Fetch(repo, remote.Name, Array.Empty<string>(), fetchOptions, null);
  66. Debug.Log("Fetch complete.");
  67. // --- Step 2: Identify branches to compare ---
  68. var currentBranch = repo.Head;
  69. var remoteBranch = currentBranch.TrackedBranch;
  70. if (remoteBranch == null || !remoteBranch.IsRemote)
  71. {
  72. Debug.LogError($"The current branch '{currentBranch.FriendlyName}' is not tracking a remote branch. Set the upstream branch using 'git branch --set-upstream-to=origin/{currentBranch.FriendlyName}'.");
  73. return;
  74. }
  75. Debug.Log($"Comparing local '{currentBranch.FriendlyName}' against remote '{remoteBranch.FriendlyName}'.");
  76. // --- Step 3: Perform the Diff ---
  77. // We compare the tree from the latest commit on the remote branch
  78. // against the files currently in your working directory.
  79. var remoteTree = remoteBranch.Tip.Tree;
  80. var changes = repo.Diff.Compare<TreeChanges>(remoteTree, DiffTargets.Index | DiffTargets.WorkingDirectory);
  81. // --- Step 4: Log the Results ---
  82. if (changes.Count == 0)
  83. {
  84. Debug.Log("--- STATUS: You are up to date! No differences found with the remote branch. ---");
  85. }
  86. else
  87. {
  88. Debug.Log($"--- STATUS: Found {changes.Count} changes. ---");
  89. foreach (var change in changes)
  90. {
  91. // Log the status (Added, Deleted, Modified) and the file path.
  92. // The color-coding helps to quickly see the status.
  93. switch (change.Status)
  94. {
  95. case ChangeKind.Added:
  96. Debug.Log($"<color=green>ADDED: {change.Path}</color>");
  97. break;
  98. case ChangeKind.Deleted:
  99. Debug.Log($"<color=red>DELETED: {change.Path}</color>");
  100. break;
  101. case ChangeKind.Modified:
  102. Debug.Log($"<color=orange>MODIFIED: {change.Path}</color>");
  103. break;
  104. case ChangeKind.Unmodified:
  105. case ChangeKind.Renamed:
  106. case ChangeKind.Copied:
  107. case ChangeKind.Ignored:
  108. case ChangeKind.Untracked:
  109. case ChangeKind.TypeChanged:
  110. case ChangeKind.Unreadable:
  111. case ChangeKind.Conflicted:
  112. default:
  113. Debug.Log($"{change.Status.ToString().ToUpper()}: {change.Path}");
  114. break;
  115. }
  116. }
  117. Debug.Log("--- End of Report ---");
  118. }
  119. }
  120. catch (RepositoryNotFoundException)
  121. {
  122. Debug.LogError("Error: This project is not a Git repository or the .git folder is missing. Please initialize a repository first.");
  123. }
  124. catch (Exception ex)
  125. {
  126. // Catch any other exceptions that might occur (e.g., network issues during fetch).
  127. Debug.LogError($"An unexpected error occurred: {ex.Message}");
  128. Debug.LogException(ex);
  129. }
  130. }
  131. }
  132. }