diff --git a/LibGit2Sharp.Tests/CheckoutFixture.cs b/LibGit2Sharp.Tests/CheckoutFixture.cs
index a09802d1f..17d4a0528 100644
--- a/LibGit2Sharp.Tests/CheckoutFixture.cs
+++ b/LibGit2Sharp.Tests/CheckoutFixture.cs
@@ -23,8 +23,9 @@ public void CanCheckoutAnExistingBranch(string branchName)
Branch master = repo.Branches["master"];
Assert.True(master.IsCurrentRepositoryHead);
- // Hard reset to ensure that working directory, index, and HEAD match
- repo.Reset(ResetOptions.Hard);
+ // Set the working directory to the current head
+ ResetAndCleanWorkingDirectory(repo);
+
Assert.False(repo.Index.RetrieveStatus().IsDirty);
Branch branch = repo.Branches[branchName];
@@ -55,8 +56,9 @@ public void CanCheckoutAnExistingBranchByName(string branchName)
Branch master = repo.Branches["master"];
Assert.True(master.IsCurrentRepositoryHead);
- // Hard reset to ensure that working directory, index, and HEAD match
- repo.Reset(ResetOptions.Hard);
+ // Set the working directory to the current head
+ ResetAndCleanWorkingDirectory(repo);
+
Assert.False(repo.Index.RetrieveStatus().IsDirty);
Branch test = repo.Checkout(branchName);
@@ -84,8 +86,9 @@ public void CanCheckoutAnArbitraryCommit(string commitPointer)
Branch master = repo.Branches["master"];
Assert.True(master.IsCurrentRepositoryHead);
- // Hard reset to ensure that working directory, index, and HEAD match
- repo.Reset(ResetOptions.Hard);
+ // Set the working directory to the current head
+ ResetAndCleanWorkingDirectory(repo);
+
Assert.False(repo.Index.RetrieveStatus().IsDirty);
Branch detachedHead = repo.Checkout(commitPointer);
@@ -197,8 +200,9 @@ public void CanForcefullyCheckoutWithStagedChanges()
Branch master = repo.Branches["master"];
Assert.True(master.IsCurrentRepositoryHead);
- // Hard reset to ensure that working directory, index, and HEAD match
- repo.Reset(ResetOptions.Hard);
+ // Set the working directory to the current head
+ ResetAndCleanWorkingDirectory(repo);
+
Assert.False(repo.Index.RetrieveStatus().IsDirty);
// Add local change
@@ -335,5 +339,19 @@ private void PopulateBasicRepository(Repository repo)
repo.CreateBranch(otherBranchName);
}
+
+ ///
+ /// Reset and clean current working directory. This will ensure that the current
+ /// working directory matches the current Head commit.
+ ///
+ /// Repository whose current working directory should be operated on.
+ private void ResetAndCleanWorkingDirectory(Repository repo)
+ {
+ // Reset the index and the working tree.
+ repo.Reset(ResetOptions.Hard);
+
+ // Remove untracked files.
+ repo.Index.CleanWorkingDirectory();
+ }
}
}
diff --git a/LibGit2Sharp.Tests/IndexFixture.cs b/LibGit2Sharp.Tests/IndexFixture.cs
index c286da293..50d0d01ba 100644
--- a/LibGit2Sharp.Tests/IndexFixture.cs
+++ b/LibGit2Sharp.Tests/IndexFixture.cs
@@ -82,6 +82,24 @@ public void ReadIndexWithBadParamsFails()
}
}
+ [Fact]
+ public void CanCleanWorkingDirectory()
+ {
+ TemporaryCloneOfTestRepo path = BuildTemporaryCloneOfTestRepo(StandardTestRepoWorkingDirPath);
+ using (var repo = new Repository(path.RepositoryPath))
+ {
+ // Verify that there are the expected number of entries and untracked files
+ Assert.Equal(6, repo.Index.RetrieveStatus().Count());
+ Assert.Equal(1, repo.Index.RetrieveStatus().Untracked.Count());
+
+ repo.Index.CleanWorkingDirectory();
+
+ // Verify that there are the expected number of entries and 0 untracked files
+ Assert.Equal(5, repo.Index.RetrieveStatus().Count());
+ Assert.Equal(0, repo.Index.RetrieveStatus().Untracked.Count());
+ }
+ }
+
[Theory]
[InlineData("1/branch_file.txt", FileStatus.Unaltered, true, FileStatus.Unaltered, true, 0)]
[InlineData("README", FileStatus.Unaltered, true, FileStatus.Unaltered, true, 0)]
diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs
index 0d3b2f207..e246920d8 100644
--- a/LibGit2Sharp/Core/NativeMethods.cs
+++ b/LibGit2Sharp/Core/NativeMethods.cs
@@ -157,6 +157,11 @@ internal static extern int git_checkout_head(
RepositorySafeHandle repo,
GitCheckoutOpts opts);
+ [DllImport(libgit2)]
+ internal static extern int git_checkout_index(
+ RepositorySafeHandle repo,
+ GitCheckoutOpts opts);
+
[DllImport(libgit2)]
internal static extern int git_clone(
out RepositorySafeHandle repo,
diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs
index 179f0bc22..9a7a94897 100644
--- a/LibGit2Sharp/Core/Proxy.cs
+++ b/LibGit2Sharp/Core/Proxy.cs
@@ -188,6 +188,15 @@ public static void git_checkout_head(RepositorySafeHandle repo, GitCheckoutOpts
}
}
+ public static void git_checkout_index(RepositorySafeHandle repo, GitCheckoutOpts opts)
+ {
+ using (ThreadAffinity())
+ {
+ int res = NativeMethods.git_checkout_index(repo, opts);
+ Ensure.Success(res);
+ }
+ }
+
#endregion
#region git_clone_
diff --git a/LibGit2Sharp/Index.cs b/LibGit2Sharp/Index.cs
index 8a9f8d4dd..5e3e68cef 100644
--- a/LibGit2Sharp/Index.cs
+++ b/LibGit2Sharp/Index.cs
@@ -338,6 +338,19 @@ public virtual void Remove(IEnumerable paths)
UpdatePhysicalIndex();
}
+ ///
+ /// Clean the working tree by removing files that are not under version control.
+ ///
+ public virtual void CleanWorkingDirectory()
+ {
+ GitCheckoutOpts options = new GitCheckoutOpts
+ {
+ checkout_strategy = CheckoutStrategy.GIT_CHECKOUT_REMOVE_UNTRACKED,
+ };
+
+ Proxy.git_checkout_index(this.repo.Handle, options);
+ }
+
private IEnumerable> PrepareBatch(IEnumerable paths)
{
Ensure.ArgumentNotNull(paths, "paths");