Skip to content

Commit 40de694

Browse files
committed
Merge pull request #863 from libgit2/therzok/statusUnmodified
Introduce StatusOptions.IncludeUnaltered
2 parents 420bc91 + 11da2fa commit 40de694

File tree

3 files changed

+88
-16
lines changed

3 files changed

+88
-16
lines changed

LibGit2Sharp.Tests/StatusFixture.cs

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -103,20 +103,22 @@ public void RetrievingTheStatusOfADirectoryThrows()
103103
}
104104
}
105105

106-
[Fact]
107-
public void CanRetrieveTheStatusOfTheWholeWorkingDirectory()
106+
[Theory]
107+
[InlineData(false, 0)]
108+
[InlineData(true, 5)]
109+
public void CanRetrieveTheStatusOfTheWholeWorkingDirectory(bool includeUnaltered, int unalteredCount)
108110
{
109111
string path = SandboxStandardTestRepo();
110112
using (var repo = new Repository(path))
111113
{
112114
const string file = "modified_staged_file.txt";
113115

114-
RepositoryStatus status = repo.RetrieveStatus();
116+
RepositoryStatus status = repo.RetrieveStatus(new StatusOptions() { IncludeUnaltered = includeUnaltered });
115117

116118
Assert.Equal(FileStatus.Staged, status[file].State);
117119

118120
Assert.NotNull(status);
119-
Assert.Equal(6, status.Count());
121+
Assert.Equal(6 + unalteredCount, status.Count());
120122
Assert.True(status.IsDirty);
121123

122124
Assert.Equal("new_untracked_file.txt", status.Untracked.Select(s => s.FilePath).Single());
@@ -131,11 +133,11 @@ public void CanRetrieveTheStatusOfTheWholeWorkingDirectory()
131133

132134
Assert.Equal(FileStatus.Staged | FileStatus.Modified, repo.RetrieveStatus(file));
133135

134-
RepositoryStatus status2 = repo.RetrieveStatus();
136+
RepositoryStatus status2 = repo.RetrieveStatus(new StatusOptions() { IncludeUnaltered = includeUnaltered });
135137
Assert.Equal(FileStatus.Staged | FileStatus.Modified, status2[file].State);
136138

137139
Assert.NotNull(status2);
138-
Assert.Equal(6, status2.Count());
140+
Assert.Equal(6 + unalteredCount, status2.Count());
139141
Assert.True(status2.IsDirty);
140142

141143
Assert.Equal("new_untracked_file.txt", status2.Untracked.Select(s => s.FilePath).Single());
@@ -242,14 +244,16 @@ public void CanDetectedVariousKindsOfRenaming()
242244
}
243245
}
244246

245-
[Fact]
246-
public void CanRetrieveTheStatusOfANewRepository()
247+
[Theory]
248+
[InlineData(true)]
249+
[InlineData(false)]
250+
public void CanRetrieveTheStatusOfANewRepository(bool includeUnaltered)
247251
{
248252
string repoPath = InitNewRepository();
249253

250254
using (var repo = new Repository(repoPath))
251255
{
252-
RepositoryStatus status = repo.RetrieveStatus();
256+
RepositoryStatus status = repo.RetrieveStatus(new StatusOptions() { IncludeUnaltered = includeUnaltered });
253257
Assert.NotNull(status);
254258
Assert.Equal(0, status.Count());
255259
Assert.False(status.IsDirty);
@@ -592,5 +596,43 @@ public void RetrievingTheStatusHonorsAssumedUnchangedMarkedIndexEntries()
592596
Assert.Equal("hello.txt", status.Modified.Single().FilePath);
593597
}
594598
}
599+
600+
[Fact]
601+
public void CanIncludeStatusOfUnalteredFiles()
602+
{
603+
var path = SandboxStandardTestRepo();
604+
string[] unalteredPaths = {
605+
"1.txt",
606+
"1" + Path.DirectorySeparatorChar + "branch_file.txt",
607+
"branch_file.txt",
608+
"new.txt",
609+
"README",
610+
};
611+
612+
using (var repo = new Repository(path))
613+
{
614+
RepositoryStatus status = repo.RetrieveStatus(new StatusOptions() { IncludeUnaltered = true });
615+
616+
Assert.Equal(unalteredPaths.Length, status.Unaltered.Count());
617+
Assert.Equal(unalteredPaths, status.Unaltered.OrderBy(s => s.FilePath).Select(s => s.FilePath).ToArray());
618+
}
619+
}
620+
621+
[Fact]
622+
public void UnalteredFilesDontMarkIndexAsDirty()
623+
{
624+
var path = SandboxStandardTestRepo();
625+
626+
using (var repo = new Repository(path))
627+
{
628+
repo.Reset(ResetMode.Hard);
629+
repo.RemoveUntrackedFiles();
630+
631+
RepositoryStatus status = repo.RetrieveStatus(new StatusOptions() { IncludeUnaltered = true });
632+
633+
Assert.Equal(false, status.IsDirty);
634+
Assert.Equal(9, status.Count());
635+
}
636+
}
595637
}
596638
}

LibGit2Sharp/RepositoryStatus.cs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public class RepositoryStatus : IEnumerable<StatusEntry>
2626
private readonly List<StatusEntry> ignored = new List<StatusEntry>();
2727
private readonly List<StatusEntry> renamedInIndex = new List<StatusEntry>();
2828
private readonly List<StatusEntry> renamedInWorkDir = new List<StatusEntry>();
29+
private readonly List<StatusEntry> unaltered = new List<StatusEntry>();
2930
private readonly bool isDirty;
3031

3132
private readonly IDictionary<FileStatus, Action<RepositoryStatus, StatusEntry>> dispatcher = Build();
@@ -42,7 +43,7 @@ private static IDictionary<FileStatus, Action<RepositoryStatus, StatusEntry>> Bu
4243
{ FileStatus.Removed, (rs, s) => rs.removed.Add(s) },
4344
{ FileStatus.RenamedInIndex, (rs, s) => rs.renamedInIndex.Add(s) },
4445
{ FileStatus.Ignored, (rs, s) => rs.ignored.Add(s) },
45-
{ FileStatus.RenamedInWorkDir, (rs, s) => rs.renamedInWorkDir.Add(s) }
46+
{ FileStatus.RenamedInWorkDir, (rs, s) => rs.renamedInWorkDir.Add(s) },
4647
};
4748
}
4849

@@ -81,7 +82,7 @@ internal RepositoryStatus(Repository repo, StatusOptions options)
8182
AddStatusEntryForDelta(entry.Status, deltaHeadToIndex, deltaIndexToWorkDir);
8283
}
8384

84-
isDirty = statusEntries.Any(entry => entry.State != FileStatus.Ignored);
85+
isDirty = statusEntries.Any(entry => entry.State != FileStatus.Ignored && entry.State != FileStatus.Unaltered);
8586
}
8687
}
8788

@@ -134,6 +135,12 @@ private static GitStatusOptions CreateStatusOptions(StatusOptions options)
134135
GitStatusOptionFlags.DisablePathspecMatch;
135136
}
136137

138+
if (options.IncludeUnaltered)
139+
{
140+
coreOptions.Flags |=
141+
GitStatusOptionFlags.IncludeUnmodified;
142+
}
143+
137144
return coreOptions;
138145
}
139146

@@ -164,14 +171,21 @@ private void AddStatusEntryForDelta(FileStatus gitStatus, GitDiffDelta deltaHead
164171

165172
StatusEntry statusEntry = new StatusEntry(filePath, gitStatus, headToIndexRenameDetails, indexToWorkDirRenameDetails);
166173

167-
foreach (KeyValuePair<FileStatus, Action<RepositoryStatus, StatusEntry>> kvp in dispatcher)
174+
if (gitStatus == FileStatus.Unaltered)
168175
{
169-
if (!gitStatus.HasFlag(kvp.Key))
176+
unaltered.Add(statusEntry);
177+
}
178+
else
179+
{
180+
foreach (KeyValuePair<FileStatus, Action<RepositoryStatus, StatusEntry>> kvp in dispatcher)
170181
{
171-
continue;
172-
}
182+
if (!gitStatus.HasFlag(kvp.Key))
183+
{
184+
continue;
185+
}
173186

174-
kvp.Value(this, statusEntry);
187+
kvp.Value(this, statusEntry);
188+
}
175189
}
176190

177191
statusEntries.Add(statusEntry);
@@ -289,6 +303,14 @@ public virtual IEnumerable<StatusEntry> RenamedInWorkDir
289303
get { return renamedInWorkDir; }
290304
}
291305

306+
/// <summary>
307+
/// List of files that were unmodified in the working directory.
308+
/// </summary>
309+
public virtual IEnumerable<StatusEntry> Unaltered
310+
{
311+
get { return unaltered; }
312+
}
313+
292314
/// <summary>
293315
/// True if the index or the working directory has been altered since the last commit. False otherwise.
294316
/// </summary>

LibGit2Sharp/StatusOptions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,5 +76,13 @@ public StatusOptions()
7676
/// as explicit paths, and NOT as pathspecs containing globs.
7777
/// </summary>
7878
public bool DisablePathSpecMatch { get; set; }
79+
80+
/// <summary>
81+
/// Include unaltered files when scanning for status
82+
/// </summary>
83+
/// <remarks>
84+
/// Unaltered meaning the file is identical in the working directory, the index and HEAD.
85+
/// </remarks>
86+
public bool IncludeUnaltered { get; set; }
7987
}
8088
}

0 commit comments

Comments
 (0)