From 3466ec74a2b12fc5c4ea7cb8bf981db4b867f930 Mon Sep 17 00:00:00 2001
From: Andreia Gaita <shana@spoiledcat.net>
Date: Thu, 20 Jun 2019 11:34:31 +0200
Subject: [PATCH] Show staged status of files, and don't commit any files that
 aren't checked

If a file is staged outside of Unity, this makes sure the check box is checked
automatically when listing changed files. If the user unchecks a file that has
been staged for commit outside of Unity, we remove the file from the index
right before commiting all the (other) checked files, to make sure
WICIWIC (What Is Checked Is What Is Commited)
---
 src/GitHub.Api/Git/TreeData.cs                      |  7 ++++++-
 src/GitHub.Api/UI/TreeBase.cs                       |  2 +-
 .../Assets/Editor/GitHub.Unity/UI/ChangesView.cs    | 13 ++++++++++---
 src/tests/UnitTests/UI/TreeBaseTests.cs             |  1 +
 4 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/src/GitHub.Api/Git/TreeData.cs b/src/GitHub.Api/Git/TreeData.cs
index ac9e67b2c..997cbffed 100644
--- a/src/GitHub.Api/Git/TreeData.cs
+++ b/src/GitHub.Api/Git/TreeData.cs
@@ -7,6 +7,7 @@ public interface ITreeData
     {
         string Path { get; }
         bool IsActive { get; }
+        bool IsChecked { get; }
     }
 
     [Serializable]
@@ -64,6 +65,7 @@ public bool Equals(GitBranchTreeData other)
 
         public string Path => GitBranch.Name;
         public bool IsActive => isActive;
+        public bool IsChecked => false;
     }
 
     [Serializable]
@@ -73,11 +75,13 @@ public struct GitStatusEntryTreeData : ITreeData
 
         public GitStatusEntry gitStatusEntry;
         public bool isLocked;
+        public bool isChecked;
 
         public GitStatusEntryTreeData(GitStatusEntry gitStatusEntry, bool isLocked = false)
         {
             this.isLocked = isLocked;
             this.gitStatusEntry = gitStatusEntry;
+            isChecked = gitStatusEntry.Staged;
         }
 
         public override int GetHashCode()
@@ -127,5 +131,6 @@ public bool Equals(GitStatusEntryTreeData other)
         public GitStatusEntry GitStatusEntry => gitStatusEntry;
         public GitFileStatus FileStatus => gitStatusEntry.Status;
         public bool IsLocked => isLocked;
+        public bool IsChecked => isChecked;
     }
-}
\ No newline at end of file
+}
diff --git a/src/GitHub.Api/UI/TreeBase.cs b/src/GitHub.Api/UI/TreeBase.cs
index 4804558ce..57c299ed5 100644
--- a/src/GitHub.Api/UI/TreeBase.cs
+++ b/src/GitHub.Api/UI/TreeBase.cs
@@ -118,7 +118,7 @@ public void Load(IEnumerable<TData> treeDatas)
                         {
                             isActive = treeData.IsActive;
                             treeNodeTreeData = treeData;
-                            isChecked = isCheckable && checkedFiles.Contains(nodePath);
+                            isChecked = isCheckable && (checkedFiles.Contains(nodePath) || treeData.IsChecked);
                         }
 
                         isSelected = selectedNodePath != null && nodePath == selectedNodePath;
diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs
index d905fb070..0d6235b42 100644
--- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs
+++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs
@@ -478,7 +478,7 @@ private void Commit()
         {
             isBusy = true;
             var files = treeChanges.GetCheckedFiles().ToList();
-            ITask addTask;
+            ITask addTask = null;
 
             if (files.Count == gitStatusEntries.Count)
             {
@@ -486,11 +486,18 @@ private void Commit()
             }
             else
             {
-                addTask = Repository.CommitFiles(files, commitMessage, commitBody);
+                ITask commit = Repository.CommitFiles(files, commitMessage, commitBody);
+
+                // if there are files that have been staged outside of Unity, but they aren't selected for commit, remove them
+                // from the index before commiting, otherwise the commit will take them along.
+                var filesStagedButNotChecked = gitStatusEntries.Where(x => x.Staged).Select(x => x.Path).Except(files).ToList();
+                if (filesStagedButNotChecked.Count > 0)
+                    addTask = GitClient.Remove(filesStagedButNotChecked);
+                addTask = addTask == null ? commit : addTask.Then(commit);
             }
 
             addTask
-                .FinallyInUI((success, exception) => 
+                .FinallyInUI((success, exception) =>
                     {
                         if (success)
                         {
diff --git a/src/tests/UnitTests/UI/TreeBaseTests.cs b/src/tests/UnitTests/UI/TreeBaseTests.cs
index e2e5e07ed..60110e39c 100644
--- a/src/tests/UnitTests/UI/TreeBaseTests.cs
+++ b/src/tests/UnitTests/UI/TreeBaseTests.cs
@@ -35,6 +35,7 @@ public struct TestTreeData : ITreeData
 
         public string Path { get; set; }
         public bool IsActive { get; set; }
+        public bool IsChecked { get; set; }
 
         public override string ToString()
         {