From 106242605b6c9fd9f032cd2388f4ab2a4371b379 Mon Sep 17 00:00:00 2001 From: Markus Olsson Date: Thu, 17 Mar 2016 02:22:22 +0100 Subject: [PATCH 1/5] Make all DiffResults disposable, move ownership of diff handle This will let us perform lazy loading of details in these classes, just as we do with commits and some other classes. --- LibGit2Sharp/Diff.cs | 27 ++++++++++++++++++--- LibGit2Sharp/IDiffResult.cs | 6 +++-- LibGit2Sharp/Patch.cs | 34 ++++++++++++++++++++++----- LibGit2Sharp/PatchStats.cs | 47 +++++++++++++++++++++++++++---------- LibGit2Sharp/TreeChanges.cs | 22 ++++++++++++++++- 5 files changed, 111 insertions(+), 25 deletions(-) diff --git a/LibGit2Sharp/Diff.cs b/LibGit2Sharp/Diff.cs index 4507a4499..9bf14660c 100644 --- a/LibGit2Sharp/Diff.cs +++ b/LibGit2Sharp/Diff.cs @@ -241,10 +241,17 @@ public virtual T Compare(Tree oldTree, Tree newTree, IEnumerable path } } - using (DiffHandle diff = BuildDiffList(oldTreeId, newTreeId, comparer, diffOptions, paths, explicitPathsOptions, compareOptions)) + DiffHandle diff = BuildDiffList(oldTreeId, newTreeId, comparer, diffOptions, paths, explicitPathsOptions, compareOptions); + + try { return BuildDiffResult(diff); } + catch + { + diff.SafeDispose(); + throw; + } } /// @@ -343,10 +350,17 @@ public virtual T Compare(Tree oldTree, DiffTargets diffTargets, IEnumerable(diff); } + catch + { + diff.SafeDispose(); + throw; + } } /// @@ -462,10 +476,17 @@ internal virtual T Compare( } } - using (DiffHandle diff = BuildDiffList(null, null, comparer, diffOptions, paths, explicitPathsOptions, compareOptions)) + DiffHandle diff = BuildDiffList(null, null, comparer, diffOptions, paths, explicitPathsOptions, compareOptions); + + try { return BuildDiffResult(diff); } + catch + { + diff.SafeDispose(); + throw; + } } internal delegate DiffHandle TreeComparisonHandleRetriever(ObjectId oldTreeId, ObjectId newTreeId, GitDiffOptions options); diff --git a/LibGit2Sharp/IDiffResult.cs b/LibGit2Sharp/IDiffResult.cs index d16af711d..ed6e521fd 100644 --- a/LibGit2Sharp/IDiffResult.cs +++ b/LibGit2Sharp/IDiffResult.cs @@ -1,8 +1,10 @@ -namespace LibGit2Sharp +using System; + +namespace LibGit2Sharp { /// /// Marker interface to identify Diff results. /// - public interface IDiffResult + public interface IDiffResult: IDisposable { } } diff --git a/LibGit2Sharp/Patch.cs b/LibGit2Sharp/Patch.cs index dd668eda4..2cd4d1605 100644 --- a/LibGit2Sharp/Patch.cs +++ b/LibGit2Sharp/Patch.cs @@ -32,14 +32,17 @@ protected Patch() internal unsafe Patch(DiffHandle diff) { - int count = Proxy.git_diff_num_deltas(diff); - for (int i = 0; i < count; i++) + using (diff) { - using (var patch = Proxy.git_patch_from_diff(diff, i)) + int count = Proxy.git_diff_num_deltas(diff); + for (int i = 0; i < count; i++) { - var delta = Proxy.git_diff_get_delta(diff, i); - AddFileChange(delta); - Proxy.git_patch_print(patch, PrintCallBack); + using (var patch = Proxy.git_patch_from_diff(diff, i)) + { + var delta = Proxy.git_diff_get_delta(diff, i); + AddFileChange(delta); + Proxy.git_patch_print(patch, PrintCallBack); + } } } } @@ -180,5 +183,24 @@ private string DebuggerDisplay linesDeleted); } } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + // This doesn't do anything yet because it loads everything + // eagerly and disposes of the diff handle in the constructor. + } } } diff --git a/LibGit2Sharp/PatchStats.cs b/LibGit2Sharp/PatchStats.cs index c5404fed5..3d6bb46cd 100644 --- a/LibGit2Sharp/PatchStats.cs +++ b/LibGit2Sharp/PatchStats.cs @@ -27,23 +27,25 @@ protected PatchStats() internal unsafe PatchStats(DiffHandle diff) { - int count = Proxy.git_diff_num_deltas(diff); - for (int i = 0; i < count; i++) + using (diff) { - using (var patch = Proxy.git_patch_from_diff(diff, i)) + int count = Proxy.git_diff_num_deltas(diff); + for (int i = 0; i < count; i++) { - var delta = Proxy.git_diff_get_delta(diff, i); - var pathPtr = delta->new_file.Path != null ? delta->new_file.Path : delta->old_file.Path; - var newFilePath = LaxFilePathMarshaler.FromNative(pathPtr); + using (var patch = Proxy.git_patch_from_diff(diff, i)) + { + var delta = Proxy.git_diff_get_delta(diff, i); + var pathPtr = delta->new_file.Path != null ? delta->new_file.Path : delta->old_file.Path; + var newFilePath = LaxFilePathMarshaler.FromNative(pathPtr); - var stats = Proxy.git_patch_line_stats(patch); - int added = stats.Item1; - int deleted = stats.Item2; - changes.Add(newFilePath, new ContentChangeStats(added, deleted)); - totalLinesAdded += added; - totalLinesDeleted += deleted; + var stats = Proxy.git_patch_line_stats(patch); + int added = stats.Item1; + int deleted = stats.Item2; + changes.Add(newFilePath, new ContentChangeStats(added, deleted)); + totalLinesAdded += added; + totalLinesDeleted += deleted; + } } - } } @@ -117,5 +119,24 @@ private string DebuggerDisplay TotalLinesDeleted); } } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + // This doesn't do anything yet because it loads everything + // eagerly and disposes of the diff handle in the constructor. + } } } diff --git a/LibGit2Sharp/TreeChanges.cs b/LibGit2Sharp/TreeChanges.cs index 2e317855a..4bf1dfb7c 100644 --- a/LibGit2Sharp/TreeChanges.cs +++ b/LibGit2Sharp/TreeChanges.cs @@ -52,7 +52,8 @@ protected TreeChanges() internal unsafe TreeChanges(DiffHandle diff) { - Proxy.git_diff_foreach(diff, FileCallback, null, null); + using(diff) + Proxy.git_diff_foreach(diff, FileCallback, null, null); } private unsafe int FileCallback(git_diff_delta* delta, float progress, IntPtr payload) @@ -169,5 +170,24 @@ private string DebuggerDisplay Copied.Count()); } } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + // This doesn't do anything yet because it loads everything + // eagerly and disposes of the diff handle in the constructor. + } } } From feb0d637294a0ac16c2f505b799957d2be2edd74 Mon Sep 17 00:00:00 2001 From: Markus Olsson Date: Thu, 17 Mar 2016 03:18:50 +0100 Subject: [PATCH 2/5] Lazily enumerate tree entry changes --- LibGit2Sharp/TreeChanges.cs | 106 +++++++++++++++++-------------- LibGit2Sharp/TreeEntryChanges.cs | 20 +++++- 2 files changed, 77 insertions(+), 49 deletions(-) diff --git a/LibGit2Sharp/TreeChanges.cs b/LibGit2Sharp/TreeChanges.cs index 4bf1dfb7c..f27793b6e 100644 --- a/LibGit2Sharp/TreeChanges.cs +++ b/LibGit2Sharp/TreeChanges.cs @@ -17,32 +17,8 @@ namespace LibGit2Sharp [DebuggerDisplay("{DebuggerDisplay,nq}")] public class TreeChanges : IEnumerable, IDiffResult { - private readonly List changes = new List(); - private readonly List added = new List(); - private readonly List deleted = new List(); - private readonly List modified = new List(); - private readonly List typeChanged = new List(); - private readonly List unmodified = new List(); - private readonly List renamed = new List(); - private readonly List copied = new List(); - private readonly List conflicted = new List(); - - private readonly IDictionary> fileDispatcher = Build(); - - private static IDictionary> Build() - { - return new Dictionary> - { - { ChangeKind.Modified, (de, d) => de.modified.Add(d) }, - { ChangeKind.Deleted, (de, d) => de.deleted.Add(d) }, - { ChangeKind.Added, (de, d) => de.added.Add(d) }, - { ChangeKind.TypeChanged, (de, d) => de.typeChanged.Add(d) }, - { ChangeKind.Unmodified, (de, d) => de.unmodified.Add(d) }, - { ChangeKind.Renamed, (de, d) => de.renamed.Add(d) }, - { ChangeKind.Copied, (de, d) => de.copied.Add(d) }, - { ChangeKind.Conflicted, (de, d) => de.conflicted.Add(d) }, - }; - } + private readonly DiffHandle diff; + private readonly Lazy count; /// /// Needed for mocking purposes. @@ -52,22 +28,46 @@ protected TreeChanges() internal unsafe TreeChanges(DiffHandle diff) { - using(diff) - Proxy.git_diff_foreach(diff, FileCallback, null, null); + this.diff = diff; + this.count = new Lazy(() => Proxy.git_diff_num_deltas(diff)); } - private unsafe int FileCallback(git_diff_delta* delta, float progress, IntPtr payload) + /// + /// Enumerates the diff and yields deltas with the specified change kind. + /// + /// Change type to filter on. + private IEnumerable GetChangesOfKind(ChangeKind changeKind) { - AddFileChange(delta); - return 0; + TreeEntryChanges entry; + + for (int i = 0; i < count.Value; i++) + { + if (TryGetEntryWithChangeTypeAt(i, changeKind, out entry)) + { + yield return entry; + } + } } - private unsafe void AddFileChange(git_diff_delta* delta) + /// + /// This is method exists to work around .net not allowing unsafe code + /// in iterators. + /// + private unsafe bool TryGetEntryWithChangeTypeAt(int index, ChangeKind changeKind, out TreeEntryChanges entry) { - var treeEntryChanges = new TreeEntryChanges(delta); + if (index < 0 || index > count.Value) + throw new ArgumentOutOfRangeException("index", "Index was out of range. Must be non-negative and less than the size of the collection."); - fileDispatcher[treeEntryChanges.Status](this, treeEntryChanges); - changes.Add(treeEntryChanges); + var delta = Proxy.git_diff_get_delta(diff, index); + + if (TreeEntryChanges.GetStatusFromChangeKind(delta->status) == changeKind) + { + entry = new TreeEntryChanges(delta); + return true; + } + + entry = null; + return false; } #region IEnumerable Members @@ -78,7 +78,22 @@ private unsafe void AddFileChange(git_diff_delta* delta) /// An object that can be used to iterate through the collection. public virtual IEnumerator GetEnumerator() { - return changes.GetEnumerator(); + for (int i = 0; i < count.Value; i++) + { + yield return GetEntryAt(i); + } + } + + /// + /// This is method exists to work around .net not allowing unsafe code + /// in iterators. + /// + private unsafe TreeEntryChanges GetEntryAt(int index) + { + if (index < 0 || index > count.Value) + throw new ArgumentOutOfRangeException("index", "Index was out of range. Must be non-negative and less than the size of the collection."); + + return new TreeEntryChanges(Proxy.git_diff_get_delta(diff, index)); } /// @@ -97,7 +112,7 @@ IEnumerator IEnumerable.GetEnumerator() /// public virtual IEnumerable Added { - get { return added; } + get { return GetChangesOfKind(ChangeKind.Added); } } /// @@ -105,7 +120,7 @@ public virtual IEnumerable Added /// public virtual IEnumerable Deleted { - get { return deleted; } + get { return GetChangesOfKind(ChangeKind.Deleted); } } /// @@ -113,7 +128,7 @@ public virtual IEnumerable Deleted /// public virtual IEnumerable Modified { - get { return modified; } + get { return GetChangesOfKind(ChangeKind.Modified); } } /// @@ -121,7 +136,7 @@ public virtual IEnumerable Modified /// public virtual IEnumerable TypeChanged { - get { return typeChanged; } + get { return GetChangesOfKind(ChangeKind.TypeChanged); } } /// @@ -129,7 +144,7 @@ public virtual IEnumerable TypeChanged /// public virtual IEnumerable Renamed { - get { return renamed; } + get { return GetChangesOfKind(ChangeKind.Renamed); } } /// @@ -137,7 +152,7 @@ public virtual IEnumerable Renamed /// public virtual IEnumerable Copied { - get { return copied; } + get { return GetChangesOfKind(ChangeKind.Copied); } } /// @@ -145,7 +160,7 @@ public virtual IEnumerable Copied /// public virtual IEnumerable Unmodified { - get { return unmodified; } + get { return GetChangesOfKind(ChangeKind.Unmodified); } } /// @@ -153,7 +168,7 @@ public virtual IEnumerable Unmodified /// public virtual IEnumerable Conflicted { - get { return conflicted; } + get { return GetChangesOfKind(ChangeKind.Conflicted); } } private string DebuggerDisplay @@ -186,8 +201,7 @@ public void Dispose() /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { - // This doesn't do anything yet because it loads everything - // eagerly and disposes of the diff handle in the constructor. + diff.SafeDispose(); } } } diff --git a/LibGit2Sharp/TreeEntryChanges.cs b/LibGit2Sharp/TreeEntryChanges.cs index 53f2ce49e..cfe0fd8e8 100644 --- a/LibGit2Sharp/TreeEntryChanges.cs +++ b/LibGit2Sharp/TreeEntryChanges.cs @@ -28,9 +28,23 @@ internal unsafe TreeEntryChanges(git_diff_delta* delta) Exists = (delta->new_file.Flags & GitDiffFlags.GIT_DIFF_FLAG_EXISTS) != 0; OldExists = (delta->old_file.Flags & GitDiffFlags.GIT_DIFF_FLAG_EXISTS) != 0; - Status = (delta->status == ChangeKind.Untracked || delta->status == ChangeKind.Ignored) - ? ChangeKind.Added - : delta->status; + Status = GetStatusFromChangeKind(delta->status); + } + + // This treatment of change kind was apparently introduced in order to be able + // to compare a tree against the index, see commit fdc972b. It's extracted + // here so that TreeEntry can use the same rules without having to instantiate + // a TreeEntryChanges object. + internal static ChangeKind GetStatusFromChangeKind(ChangeKind changeKind) + { + switch (changeKind) + { + case ChangeKind.Untracked: + case ChangeKind.Ignored: + return ChangeKind.Added; + default: + return changeKind; + } } /// From c37b48e442718bc6ba532182112630a28feb60e2 Mon Sep 17 00:00:00 2001 From: Markus Olsson Date: Thu, 17 Mar 2016 03:20:49 +0100 Subject: [PATCH 3/5] Add Count property, skip enumeration when only # of changes is important --- LibGit2Sharp/TreeChanges.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/LibGit2Sharp/TreeChanges.cs b/LibGit2Sharp/TreeChanges.cs index f27793b6e..6e8a0eff5 100644 --- a/LibGit2Sharp/TreeChanges.cs +++ b/LibGit2Sharp/TreeChanges.cs @@ -39,8 +39,7 @@ internal unsafe TreeChanges(DiffHandle diff) private IEnumerable GetChangesOfKind(ChangeKind changeKind) { TreeEntryChanges entry; - - for (int i = 0; i < count.Value; i++) + for (int i = 0; i < Count; i++) { if (TryGetEntryWithChangeTypeAt(i, changeKind, out entry)) { @@ -78,7 +77,7 @@ private unsafe bool TryGetEntryWithChangeTypeAt(int index, ChangeKind changeKind /// An object that can be used to iterate through the collection. public virtual IEnumerator GetEnumerator() { - for (int i = 0; i < count.Value; i++) + for (int i = 0; i < Count; i++) { yield return GetEntryAt(i); } @@ -171,6 +170,14 @@ public virtual IEnumerable Conflicted get { return GetChangesOfKind(ChangeKind.Conflicted); } } + /// + /// Gets the number of in this comparison. + /// + public virtual int Count + { + get { return count.Value; } + } + private string DebuggerDisplay { get From f916e79575bea0a99d3c67249090f51ff62d4e23 Mon Sep 17 00:00:00 2001 From: Markus Olsson Date: Thu, 17 Mar 2016 04:27:03 +0100 Subject: [PATCH 4/5] Ensure disposal of all diff results --- LibGit2Sharp.Tests/DiffTreeToTargetFixture.cs | 336 +++++++------ LibGit2Sharp.Tests/DiffTreeToTreeFixture.cs | 448 ++++++++++-------- .../DiffWorkdirToIndexFixture.cs | 66 +-- LibGit2Sharp.Tests/PatchStatsFixture.cs | 15 +- LibGit2Sharp/Commands/Remove.cs | 94 ++-- LibGit2Sharp/Commands/Stage.cs | 108 ++--- LibGit2Sharp/Core/FileHistory.cs | 12 +- LibGit2Sharp/Core/Handles/Libgit2Object.cs | 4 +- LibGit2Sharp/Index.cs | 6 +- 9 files changed, 593 insertions(+), 496 deletions(-) diff --git a/LibGit2Sharp.Tests/DiffTreeToTargetFixture.cs b/LibGit2Sharp.Tests/DiffTreeToTargetFixture.cs index b8ff89e3f..71aad3755 100644 --- a/LibGit2Sharp.Tests/DiffTreeToTargetFixture.cs +++ b/LibGit2Sharp.Tests/DiffTreeToTargetFixture.cs @@ -43,23 +43,27 @@ public void CanCompareASimpleTreeAgainstTheWorkDir() { SetUpSimpleDiffContext(repo); - var changes = repo.Diff.Compare(repo.Head.Tip.Tree, - DiffTargets.WorkingDirectory); - Assert.Equal(1, changes.Modified.Count()); - - var patch = repo.Diff.Compare(repo.Head.Tip.Tree, - DiffTargets.WorkingDirectory); - var expected = new StringBuilder() - .Append("diff --git a/file.txt b/file.txt\n") - .Append("index ce01362..4f125e3 100644\n") - .Append("--- a/file.txt\n") - .Append("+++ b/file.txt\n") - .Append("@@ -1 +1,3 @@\n") - .Append(" hello\n") - .Append("+world\n") - .Append("+!!!\n"); - - Assert.Equal(expected.ToString(), patch); + using (var changes = repo.Diff.Compare(repo.Head.Tip.Tree, + DiffTargets.WorkingDirectory)) + { + Assert.Equal(1, changes.Modified.Count()); + } + + using (var patch = repo.Diff.Compare(repo.Head.Tip.Tree, + DiffTargets.WorkingDirectory)) + { + var expected = new StringBuilder() + .Append("diff --git a/file.txt b/file.txt\n") + .Append("index ce01362..4f125e3 100644\n") + .Append("--- a/file.txt\n") + .Append("+++ b/file.txt\n") + .Append("@@ -1 +1,3 @@\n") + .Append(" hello\n") + .Append("+world\n") + .Append("+!!!\n"); + + Assert.Equal(expected.ToString(), patch); + } } } @@ -71,19 +75,21 @@ public void CanCompareAMoreComplexTreeAgainstTheWorkdir() { Tree tree = repo.Head.Tip.Tree; - var changes = repo.Diff.Compare(tree, DiffTargets.WorkingDirectory); - Assert.NotNull(changes); + using (var changes = repo.Diff.Compare(tree, DiffTargets.WorkingDirectory)) + { + Assert.NotNull(changes); - Assert.Equal(6, changes.Count()); + Assert.Equal(6, changes.Count()); - Assert.Equal(new[] { "deleted_staged_file.txt", "deleted_unstaged_file.txt" }, - changes.Deleted.Select(tec => tec.Path)); + Assert.Equal(new[] { "deleted_staged_file.txt", "deleted_unstaged_file.txt" }, + changes.Deleted.Select(tec => tec.Path)); - Assert.Equal(new[] { "new_tracked_file.txt", "new_untracked_file.txt" }, - changes.Added.Select(tec => tec.Path)); + Assert.Equal(new[] { "new_tracked_file.txt", "new_untracked_file.txt" }, + changes.Added.Select(tec => tec.Path)); - Assert.Equal(new[] { "modified_staged_file.txt", "modified_unstaged_file.txt" }, - changes.Modified.Select(tec => tec.Path)); + Assert.Equal(new[] { "modified_staged_file.txt", "modified_unstaged_file.txt" }, + changes.Modified.Select(tec => tec.Path)); + } } } @@ -107,23 +113,27 @@ public void CanCompareASimpleTreeAgainstTheWorkDirAndTheIndex() { SetUpSimpleDiffContext(repo); - var changes = repo.Diff.Compare(repo.Head.Tip.Tree, - DiffTargets.Index | DiffTargets.WorkingDirectory); - Assert.Equal(1, changes.Modified.Count()); - - var patch = repo.Diff.Compare(repo.Head.Tip.Tree, - DiffTargets.Index | DiffTargets.WorkingDirectory); - var expected = new StringBuilder() - .Append("diff --git a/file.txt b/file.txt\n") - .Append("index ce01362..4f125e3 100644\n") - .Append("--- a/file.txt\n") - .Append("+++ b/file.txt\n") - .Append("@@ -1 +1,3 @@\n") - .Append(" hello\n") - .Append("+world\n") - .Append("+!!!\n"); - - Assert.Equal(expected.ToString(), patch); + using (var changes = repo.Diff.Compare(repo.Head.Tip.Tree, + DiffTargets.Index | DiffTargets.WorkingDirectory)) + { + Assert.Equal(1, changes.Modified.Count()); + } + + using (var patch = repo.Diff.Compare(repo.Head.Tip.Tree, + DiffTargets.Index | DiffTargets.WorkingDirectory)) + { + var expected = new StringBuilder() + .Append("diff --git a/file.txt b/file.txt\n") + .Append("index ce01362..4f125e3 100644\n") + .Append("--- a/file.txt\n") + .Append("+++ b/file.txt\n") + .Append("@@ -1 +1,3 @@\n") + .Append(" hello\n") + .Append("+world\n") + .Append("+!!!\n"); + + Assert.Equal(expected.ToString(), patch); + } } } @@ -165,44 +175,50 @@ public void ShowcaseTheDifferenceBetweenTheTwoKindOfComparison() FileStatus state = repo.RetrieveStatus("file.txt"); Assert.Equal(FileStatus.DeletedFromIndex | FileStatus.NewInWorkdir, state); - var wrkDirToIdxToTree = repo.Diff.Compare(repo.Head.Tip.Tree, - DiffTargets.Index | DiffTargets.WorkingDirectory); - - Assert.Equal(1, wrkDirToIdxToTree.Deleted.Count()); - Assert.Equal(0, wrkDirToIdxToTree.Modified.Count()); - - var patch = repo.Diff.Compare(repo.Head.Tip.Tree, - DiffTargets.Index | DiffTargets.WorkingDirectory); - var expected = new StringBuilder() - .Append("diff --git a/file.txt b/file.txt\n") - .Append("deleted file mode 100644\n") - .Append("index ce01362..0000000\n") - .Append("--- a/file.txt\n") - .Append("+++ /dev/null\n") - .Append("@@ -1 +0,0 @@\n") - .Append("-hello\n"); - - Assert.Equal(expected.ToString(), patch); - - var wrkDirToTree = repo.Diff.Compare(repo.Head.Tip.Tree, - DiffTargets.WorkingDirectory); - - Assert.Equal(0, wrkDirToTree.Deleted.Count()); - Assert.Equal(1, wrkDirToTree.Modified.Count()); - - patch = repo.Diff.Compare(repo.Head.Tip.Tree, - DiffTargets.WorkingDirectory); - expected = new StringBuilder() - .Append("diff --git a/file.txt b/file.txt\n") - .Append("index ce01362..4f125e3 100644\n") - .Append("--- a/file.txt\n") - .Append("+++ b/file.txt\n") - .Append("@@ -1 +1,3 @@\n") - .Append(" hello\n") - .Append("+world\n") - .Append("+!!!\n"); - - Assert.Equal(expected.ToString(), patch); + using (var wrkDirToIdxToTree = repo.Diff.Compare(repo.Head.Tip.Tree, + DiffTargets.Index | DiffTargets.WorkingDirectory)) + { + Assert.Equal(1, wrkDirToIdxToTree.Deleted.Count()); + Assert.Equal(0, wrkDirToIdxToTree.Modified.Count()); + } + + using (var patch = repo.Diff.Compare(repo.Head.Tip.Tree, + DiffTargets.Index | DiffTargets.WorkingDirectory)) + { + var expected = new StringBuilder() + .Append("diff --git a/file.txt b/file.txt\n") + .Append("deleted file mode 100644\n") + .Append("index ce01362..0000000\n") + .Append("--- a/file.txt\n") + .Append("+++ /dev/null\n") + .Append("@@ -1 +0,0 @@\n") + .Append("-hello\n"); + + Assert.Equal(expected.ToString(), patch); + } + + using (var wrkDirToTree = repo.Diff.Compare(repo.Head.Tip.Tree, + DiffTargets.WorkingDirectory)) + { + Assert.Equal(0, wrkDirToTree.Deleted.Count()); + Assert.Equal(1, wrkDirToTree.Modified.Count()); + } + + using (var patch = repo.Diff.Compare(repo.Head.Tip.Tree, + DiffTargets.WorkingDirectory)) + { + var expected = new StringBuilder() + .Append("diff --git a/file.txt b/file.txt\n") + .Append("index ce01362..4f125e3 100644\n") + .Append("--- a/file.txt\n") + .Append("+++ b/file.txt\n") + .Append("@@ -1 +1,3 @@\n") + .Append(" hello\n") + .Append("+world\n") + .Append("+!!!\n"); + + Assert.Equal(expected.ToString(), patch); + } } } @@ -225,22 +241,26 @@ public void CanCompareASimpleTreeAgainstTheIndex() { SetUpSimpleDiffContext(repo); - var changes = repo.Diff.Compare(repo.Head.Tip.Tree, - DiffTargets.Index); - Assert.Equal(1, changes.Modified.Count()); - - var patch = repo.Diff.Compare(repo.Head.Tip.Tree, - DiffTargets.Index); - var expected = new StringBuilder() - .Append("diff --git a/file.txt b/file.txt\n") - .Append("index ce01362..94954ab 100644\n") - .Append("--- a/file.txt\n") - .Append("+++ b/file.txt\n") - .Append("@@ -1 +1,2 @@\n") - .Append(" hello\n") - .Append("+world\n"); - - Assert.Equal(expected.ToString(), patch); + using (var changes = repo.Diff.Compare(repo.Head.Tip.Tree, + DiffTargets.Index)) + { + Assert.Equal(1, changes.Modified.Count()); + } + + using (var patch = repo.Diff.Compare(repo.Head.Tip.Tree, + DiffTargets.Index)) + { + var expected = new StringBuilder() + .Append("diff --git a/file.txt b/file.txt\n") + .Append("index ce01362..94954ab 100644\n") + .Append("--- a/file.txt\n") + .Append("+++ b/file.txt\n") + .Append("@@ -1 +1,2 @@\n") + .Append(" hello\n") + .Append("+world\n"); + + Assert.Equal(expected.ToString(), patch); + } } } @@ -276,13 +296,15 @@ public void CanCompareAMoreComplexTreeAgainstTheIndex() { Tree tree = repo.Head.Tip.Tree; - var changes = repo.Diff.Compare(tree, DiffTargets.Index); - Assert.NotNull(changes); + using (var changes = repo.Diff.Compare(tree, DiffTargets.Index)) + { + Assert.NotNull(changes); - Assert.Equal(3, changes.Count()); - Assert.Equal("deleted_staged_file.txt", changes.Deleted.Single().Path); - Assert.Equal("new_tracked_file.txt", changes.Added.Single().Path); - Assert.Equal("modified_staged_file.txt", changes.Modified.Single().Path); + Assert.Equal(3, changes.Count()); + Assert.Equal("deleted_staged_file.txt", changes.Deleted.Single().Path); + Assert.Equal("new_tracked_file.txt", changes.Added.Single().Path); + Assert.Equal("modified_staged_file.txt", changes.Modified.Single().Path); + } } } @@ -304,13 +326,14 @@ public void CanCompareASubsetofTheTreeAgainstTheIndex() { Tree tree = repo.Head.Tip.Tree; - var changes = repo.Diff.Compare(tree, DiffTargets.Index, - new[] { "deleted_staged_file.txt", "1/branch_file.txt" }); + using (var changes = repo.Diff.Compare(tree, DiffTargets.Index, + new[] { "deleted_staged_file.txt", "1/branch_file.txt" })) + { + Assert.NotNull(changes); - Assert.NotNull(changes); - - Assert.Equal(1, changes.Count()); - Assert.Equal("deleted_staged_file.txt", changes.Deleted.Single().Path); + Assert.Equal(1, changes.Count()); + Assert.Equal("deleted_staged_file.txt", changes.Deleted.Single().Path); + } } } @@ -329,13 +352,17 @@ public void CanCompareASubsetofTheTreeAgainstTheIndexWithLaxExplicitPathsValidat { Tree tree = repo.Head.Tip.Tree; - var changes = repo.Diff.Compare(tree, DiffTargets.Index, - new[] { "deleted_staged_file.txt", "1/branch_file.txt", "I-do/not-exist" }, new ExplicitPathsOptions { ShouldFailOnUnmatchedPath = false }); - AssertCanCompareASubsetOfTheTreeAgainstTheIndex(changes); - - changes = repo.Diff.Compare(tree, DiffTargets.Index, - new[] { "deleted_staged_file.txt", "1/branch_file.txt", "I-do/not-exist" }); - AssertCanCompareASubsetOfTheTreeAgainstTheIndex(changes); + using (var changes = repo.Diff.Compare(tree, DiffTargets.Index, + new[] { "deleted_staged_file.txt", "1/branch_file.txt", "I-do/not-exist" }, new ExplicitPathsOptions { ShouldFailOnUnmatchedPath = false })) + { + AssertCanCompareASubsetOfTheTreeAgainstTheIndex(changes); + } + + using (var changes = repo.Diff.Compare(tree, DiffTargets.Index, + new[] { "deleted_staged_file.txt", "1/branch_file.txt", "I-do/not-exist" })) + { + AssertCanCompareASubsetOfTheTreeAgainstTheIndex(changes); + } } } @@ -384,23 +411,27 @@ public void CanCopeWithEndOfFileNewlineChanges() File.AppendAllText(fullpath, "\n"); Commands.Stage(repo, "file.txt"); - var changes = repo.Diff.Compare(repo.Head.Tip.Tree, DiffTargets.Index); - Assert.Equal(1, changes.Modified.Count()); - - var patch = repo.Diff.Compare(repo.Head.Tip.Tree, DiffTargets.Index); - var expected = new StringBuilder() - .Append("diff --git a/file.txt b/file.txt\n") - .Append("index 2e65efe..7898192 100644\n") - .Append("--- a/file.txt\n") - .Append("+++ b/file.txt\n") - .Append("@@ -1 +1 @@\n") - .Append("-a\n") - .Append("\\ No newline at end of file\n") - .Append("+a\n"); - - Assert.Equal(expected.ToString(), patch); - Assert.Equal(1, patch.LinesAdded); - Assert.Equal(1, patch.LinesDeleted); + using (var changes = repo.Diff.Compare(repo.Head.Tip.Tree, DiffTargets.Index)) + { + Assert.Equal(1, changes.Modified.Count()); + } + + using (var patch = repo.Diff.Compare(repo.Head.Tip.Tree, DiffTargets.Index)) + { + var expected = new StringBuilder() + .Append("diff --git a/file.txt b/file.txt\n") + .Append("index 2e65efe..7898192 100644\n") + .Append("--- a/file.txt\n") + .Append("+++ b/file.txt\n") + .Append("@@ -1 +1 @@\n") + .Append("-a\n") + .Append("\\ No newline at end of file\n") + .Append("+a\n"); + + Assert.Equal(expected.ToString(), patch); + Assert.Equal(1, patch.LinesAdded); + Assert.Equal(1, patch.LinesDeleted); + } } } @@ -428,13 +459,14 @@ public void CanCompareANullTreeAgainstTheIndex() { SetUpSimpleDiffContext(repo); - var changes = repo.Diff.Compare(null, - DiffTargets.Index); - - Assert.Equal(1, changes.Count()); - Assert.Equal(1, changes.Added.Count()); + using (var changes = repo.Diff.Compare(null, + DiffTargets.Index)) + { + Assert.Equal(1, changes.Count()); + Assert.Equal(1, changes.Added.Count()); - Assert.Equal("file.txt", changes.Added.Single().Path); + Assert.Equal("file.txt", changes.Added.Single().Path); + } } } @@ -447,13 +479,14 @@ public void CanCompareANullTreeAgainstTheWorkdir() { SetUpSimpleDiffContext(repo); - var changes = repo.Diff.Compare(null, - DiffTargets.WorkingDirectory); + using (var changes = repo.Diff.Compare(null, + DiffTargets.WorkingDirectory)) + { + Assert.Equal(1, changes.Count()); + Assert.Equal(1, changes.Added.Count()); - Assert.Equal(1, changes.Count()); - Assert.Equal(1, changes.Added.Count()); - - Assert.Equal("file.txt", changes.Added.Single().Path); + Assert.Equal("file.txt", changes.Added.Single().Path); + } } } @@ -466,13 +499,14 @@ public void CanCompareANullTreeAgainstTheWorkdirAndTheIndex() { SetUpSimpleDiffContext(repo); - var changes = repo.Diff.Compare(null, - DiffTargets.WorkingDirectory | DiffTargets.Index); - - Assert.Equal(1, changes.Count()); - Assert.Equal(1, changes.Added.Count()); + using (var changes = repo.Diff.Compare(null, + DiffTargets.WorkingDirectory | DiffTargets.Index)) + { + Assert.Equal(1, changes.Count()); + Assert.Equal(1, changes.Added.Count()); - Assert.Equal("file.txt", changes.Added.Single().Path); + Assert.Equal("file.txt", changes.Added.Single().Path); + } } } } diff --git a/LibGit2Sharp.Tests/DiffTreeToTreeFixture.cs b/LibGit2Sharp.Tests/DiffTreeToTreeFixture.cs index 5be987aaf..8cde292a4 100644 --- a/LibGit2Sharp.Tests/DiffTreeToTreeFixture.cs +++ b/LibGit2Sharp.Tests/DiffTreeToTreeFixture.cs @@ -20,12 +20,16 @@ public void ComparingATreeAgainstItselfReturnsNoDifference() { Tree tree = repo.Head.Tip.Tree; - var changes = repo.Diff.Compare(tree, tree); - var patch = repo.Diff.Compare(tree, tree); + using(var changes = repo.Diff.Compare(tree, tree)) + { + Assert.Empty(changes); + } - Assert.Empty(changes); - Assert.Empty(patch); - Assert.Equal(String.Empty, patch); + using (var patch = repo.Diff.Compare(tree, tree)) + { + Assert.Empty(patch); + Assert.Equal(String.Empty, patch); + } } } @@ -37,9 +41,10 @@ public void RetrievingANonExistentFileChangeReturnsNull() { Tree tree = repo.Head.Tip.Tree; - var changes = repo.Diff.Compare(tree, tree); - - Assert.Equal(0, changes.Count(c => c.Path == "batman")); + using (var changes = repo.Diff.Compare(tree, tree)) + { + Assert.Equal(0, changes.Count(c => c.Path == "batman")); + } } } @@ -57,22 +62,25 @@ public void CanCompareACommitTreeAgainstItsParent() Tree commitTree = repo.Head.Tip.Tree; Tree parentCommitTree = repo.Head.Tip.Parents.Single().Tree; - var changes = repo.Diff.Compare(parentCommitTree, commitTree); - - Assert.Equal(1, changes.Count()); - Assert.Equal(1, changes.Added.Count()); + using (var changes = repo.Diff.Compare(parentCommitTree, commitTree)) + { + Assert.Equal(1, changes.Count()); + Assert.Equal(1, changes.Added.Count()); - TreeEntryChanges treeEntryChanges = changes.Single(c => c.Path == "1.txt"); + TreeEntryChanges treeEntryChanges = changes.Single(c => c.Path == "1.txt"); - var patch = repo.Diff.Compare(parentCommitTree, commitTree); - Assert.False(patch["1.txt"].IsBinaryComparison); + Assert.Equal("1.txt", treeEntryChanges.Path); + Assert.Equal(ChangeKind.Added, treeEntryChanges.Status); - Assert.Equal("1.txt", treeEntryChanges.Path); - Assert.Equal(ChangeKind.Added, treeEntryChanges.Status); + Assert.Equal(treeEntryChanges, changes.Added.Single()); - Assert.Equal(treeEntryChanges, changes.Added.Single()); + Assert.Equal(Mode.Nonexistent, treeEntryChanges.OldMode); + } - Assert.Equal(Mode.Nonexistent, treeEntryChanges.OldMode); + using (var patch = repo.Diff.Compare(parentCommitTree, commitTree)) + { + Assert.False(patch["1.txt"].IsBinaryComparison); + } } } @@ -104,14 +112,14 @@ public void CanDetectABinaryChange() File.AppendAllText(filepath, "abcdef"); - var patch = repo.Diff.Compare(commit.Tree, DiffTargets.WorkingDirectory, new[] { filename }); - Assert.True(patch[filename].IsBinaryComparison); + using(var patch = repo.Diff.Compare(commit.Tree, DiffTargets.WorkingDirectory, new[] { filename })) + Assert.True(patch[filename].IsBinaryComparison); Commands.Stage(repo, filename); var commit2 = repo.Commit("Update binary file", Constants.Signature, Constants.Signature); - var patch2 = repo.Diff.Compare(commit.Tree, commit2.Tree, new[] { filename }); - Assert.True(patch2[filename].IsBinaryComparison); + using(var patch2 = repo.Diff.Compare(commit.Tree, commit2.Tree, new[] { filename })) + Assert.True(patch2[filename].IsBinaryComparison); } } @@ -130,14 +138,14 @@ public void CanDetectABinaryDeletion() File.Delete(filepath); - var patch = repo.Diff.Compare(commit.Tree, DiffTargets.WorkingDirectory, new [] {filename}); - Assert.True(patch[filename].IsBinaryComparison); + using(var patch = repo.Diff.Compare(commit.Tree, DiffTargets.WorkingDirectory, new [] {filename})) + Assert.True(patch[filename].IsBinaryComparison); Commands.Remove(repo, filename); var commit2 = repo.Commit("Delete binary file", Constants.Signature, Constants.Signature); - var patch2 = repo.Diff.Compare(commit.Tree, commit2.Tree, new[] { filename }); - Assert.True(patch2[filename].IsBinaryComparison); + using(var patch2 = repo.Diff.Compare(commit.Tree, commit2.Tree, new[] { filename })) + Assert.True(patch2[filename].IsBinaryComparison); } } @@ -160,11 +168,13 @@ public void CanCompareASubsetofTheTreeAgainstOneOfItsAncestor() Tree tree = repo.Head.Tip.Tree; Tree ancestor = repo.Lookup("9fd738e").Tree; - var changes = repo.Diff.Compare(ancestor, tree, new[] { "1" }); - Assert.NotNull(changes); + using (var changes = repo.Diff.Compare(ancestor, tree, new[] { "1" })) + { + Assert.NotNull(changes); - Assert.Equal(1, changes.Count()); - Assert.Equal(subBranchFilePath, changes.Added.Single().Path); + Assert.Equal(1, changes.Count()); + Assert.Equal(subBranchFilePath, changes.Added.Single().Path); + } } } @@ -191,20 +201,23 @@ public void CanCompareACommitTreeAgainstATreeWithNoCommonAncestor() Tree commitTree = repo.Head.Tip.Tree; Tree commitTreeWithDifferentAncestor = repo.Branches["refs/remotes/origin/test"].Tip.Tree; - var changes = repo.Diff.Compare(commitTreeWithDifferentAncestor, commitTree); - - Assert.Equal(10, changes.Count()); - Assert.Equal(9, changes.Added.Count()); - Assert.Equal(1, changes.Deleted.Count()); + using (var changes = repo.Diff.Compare(commitTreeWithDifferentAncestor, commitTree)) + { + Assert.Equal(10, changes.Count()); + Assert.Equal(9, changes.Added.Count()); + Assert.Equal(1, changes.Deleted.Count()); - Assert.Equal("readme.txt", changes.Deleted.Single().Path); - Assert.Equal(new[] { "1.txt", subBranchFilePath, "README", "branch_file.txt", "deleted_staged_file.txt", "deleted_unstaged_file.txt", "modified_staged_file.txt", "modified_unstaged_file.txt", "new.txt" }, - changes.Added.Select(x => x.Path).OrderBy(p => p, StringComparer.Ordinal).ToArray()); + Assert.Equal("readme.txt", changes.Deleted.Single().Path); + Assert.Equal(new[] { "1.txt", subBranchFilePath, "README", "branch_file.txt", "deleted_staged_file.txt", "deleted_unstaged_file.txt", "modified_staged_file.txt", "modified_unstaged_file.txt", "new.txt" }, + changes.Added.Select(x => x.Path).OrderBy(p => p, StringComparer.Ordinal).ToArray()); + } - var patch = repo.Diff.Compare(commitTreeWithDifferentAncestor, commitTree); - Assert.Equal(9, patch.LinesAdded); - Assert.Equal(2, patch.LinesDeleted); - Assert.Equal(2, patch["readme.txt"].LinesDeleted); + using (var patch = repo.Diff.Compare(commitTreeWithDifferentAncestor, commitTree)) + { + Assert.Equal(9, patch.LinesAdded); + Assert.Equal(2, patch.LinesDeleted); + Assert.Equal(2, patch["readme.txt"].LinesDeleted); + } } } @@ -217,13 +230,17 @@ public void CanCompareATreeAgainstAnotherTreeWithLaxExplicitPathsValidationAndNo Tree commitTree = repo.Head.Tip.Tree; Tree commitTreeWithDifferentAncestor = repo.Branches["refs/remotes/origin/test"].Tip.Tree; - var changes = repo.Diff.Compare(commitTreeWithDifferentAncestor, commitTree, - new[] { "if-I-exist-this-test-is-really-unlucky.txt" }, new ExplicitPathsOptions { ShouldFailOnUnmatchedPath = false }); - Assert.Equal(0, changes.Count()); + using (var changes = repo.Diff.Compare(commitTreeWithDifferentAncestor, commitTree, + new[] { "if-I-exist-this-test-is-really-unlucky.txt" }, new ExplicitPathsOptions { ShouldFailOnUnmatchedPath = false })) + { + Assert.Equal(0, changes.Count()); + } - changes = repo.Diff.Compare(commitTreeWithDifferentAncestor, commitTree, - new[] { "if-I-exist-this-test-is-really-unlucky.txt" }); - Assert.Equal(0, changes.Count()); + using (var changes = repo.Diff.Compare(commitTreeWithDifferentAncestor, commitTree, + new[] { "if-I-exist-this-test-is-really-unlucky.txt" })) + { + Assert.Equal(0, changes.Count()); + } } } @@ -269,11 +286,12 @@ public void DetectsTheRenamingOfAModifiedFileByDefault() Tree rootCommitTree = repo.Lookup("f8d44d7").Tree; Tree commitTreeWithRenamedFile = repo.Lookup("4be51d6").Tree; - var changes = repo.Diff.Compare(rootCommitTree, commitTreeWithRenamedFile); - - Assert.Equal(1, changes.Count()); - Assert.Equal("my-name-does-not-feel-right.txt", changes.Single(c => c.Path == "super-file.txt").OldPath); - Assert.Equal(1, changes.Renamed.Count()); + using (var changes = repo.Diff.Compare(rootCommitTree, commitTreeWithRenamedFile)) + { + Assert.Equal(1, changes.Count()); + Assert.Equal("my-name-does-not-feel-right.txt", changes.Single(c => c.Path == "super-file.txt").OldPath); + Assert.Equal(1, changes.Renamed.Count()); + } } } @@ -297,12 +315,13 @@ public void DetectsTheExactRenamingOfFilesByDefault() Commit @new = repo.Commit("Updated", Constants.Signature, Constants.Signature); - var changes = repo.Diff.Compare(old.Tree, @new.Tree); - - Assert.Equal(1, changes.Count()); - Assert.Equal(1, changes.Renamed.Count()); - Assert.Equal(originalPath, changes.Renamed.Single().OldPath); - Assert.Equal(renamedPath, changes.Renamed.Single().Path); + using (var changes = repo.Diff.Compare(old.Tree, @new.Tree)) + { + Assert.Equal(1, changes.Count()); + Assert.Equal(1, changes.Renamed.Count()); + Assert.Equal(originalPath, changes.Renamed.Single().OldPath); + Assert.Equal(renamedPath, changes.Renamed.Single().Path); + } } } @@ -344,12 +363,14 @@ public void RenameThresholdsAreObeyed() }; compareOptions.Similarity.RenameThreshold = 30; - var changes = repo.Diff.Compare(old.Tree, @new.Tree, compareOptions: compareOptions); - Assert.True(changes.All(x => x.Status == ChangeKind.Renamed)); + + using (var changes = repo.Diff.Compare(old.Tree, @new.Tree, compareOptions: compareOptions)) + Assert.True(changes.All(x => x.Status == ChangeKind.Renamed)); compareOptions.Similarity.RenameThreshold = 90; - changes = repo.Diff.Compare(old.Tree, @new.Tree, compareOptions: compareOptions); - Assert.False(changes.Any(x => x.Status == ChangeKind.Renamed)); + + using (var changes = repo.Diff.Compare(old.Tree, @new.Tree, compareOptions: compareOptions)) + Assert.False(changes.Any(x => x.Status == ChangeKind.Renamed)); } } @@ -373,16 +394,17 @@ public void ExactModeDetectsExactRenames() Commit @new = repo.Commit("Updated", Constants.Signature, Constants.Signature); - var changes = repo.Diff.Compare(old.Tree, @new.Tree, + using (var changes = repo.Diff.Compare(old.Tree, @new.Tree, compareOptions: new CompareOptions { Similarity = SimilarityOptions.Exact, - }); - - Assert.Equal(1, changes.Count()); - Assert.Equal(1, changes.Renamed.Count()); - Assert.Equal(originalPath, changes.Renamed.Single().OldPath); - Assert.Equal(renamedPath, changes.Renamed.Single().Path); + })) + { + Assert.Equal(1, changes.Count()); + Assert.Equal(1, changes.Renamed.Count()); + Assert.Equal(originalPath, changes.Renamed.Single().OldPath); + Assert.Equal(renamedPath, changes.Renamed.Single().Path); + } } } @@ -407,14 +429,15 @@ public void ExactModeDetectsExactCopies() Commit @new = repo.Commit("Updated", Constants.Signature, Constants.Signature); - var changes = repo.Diff.Compare(old.Tree, @new.Tree, + using (var changes = repo.Diff.Compare(old.Tree, @new.Tree, compareOptions: new CompareOptions { Similarity = SimilarityOptions.Exact, - }); - - Assert.Equal(1, changes.Count()); - Assert.Equal(1, changes.Copied.Count()); + })) + { + Assert.Equal(1, changes.Count()); + Assert.Equal(1, changes.Copied.Count()); + } } } @@ -440,16 +463,17 @@ public void ExactModeDoesntDetectRenamesWithEdits() Commit @new = repo.Commit("Updated", Constants.Signature, Constants.Signature); - var changes = repo.Diff.Compare(old.Tree, @new.Tree, + using (var changes = repo.Diff.Compare(old.Tree, @new.Tree, compareOptions: new CompareOptions { Similarity = SimilarityOptions.Exact, - }); - - Assert.Equal(2, changes.Count()); - Assert.Equal(0, changes.Renamed.Count()); - Assert.Equal(1, changes.Added.Count()); - Assert.Equal(1, changes.Deleted.Count()); + })) + { + Assert.Equal(2, changes.Count()); + Assert.Equal(0, changes.Renamed.Count()); + Assert.Equal(1, changes.Added.Count()); + Assert.Equal(1, changes.Deleted.Count()); + } } } @@ -476,19 +500,20 @@ public void CanIncludeUnmodifiedEntriesWhenDetectingTheExactRenamingOfFilesWhenE Commit @new = repo.Commit("Updated", Constants.Signature, Constants.Signature); - var changes = repo.Diff.Compare(old.Tree, @new.Tree, + using (var changes = repo.Diff.Compare(old.Tree, @new.Tree, compareOptions: new CompareOptions { Similarity = SimilarityOptions.CopiesHarder, IncludeUnmodified = true, - }); - - Assert.Equal(2, changes.Count()); - Assert.Equal(1, changes.Unmodified.Count()); - Assert.Equal(1, changes.Copied.Count()); - Assert.Equal(originalPath, changes.Copied.Single().OldPath); - Assert.Equal(copiedPath, changes.Copied.Single().Path); + })) + { + Assert.Equal(2, changes.Count()); + Assert.Equal(1, changes.Unmodified.Count()); + Assert.Equal(1, changes.Copied.Count()); + Assert.Equal(originalPath, changes.Copied.Single().OldPath); + Assert.Equal(copiedPath, changes.Copied.Single().Path); + } } } @@ -512,15 +537,16 @@ public void CanNotDetectTheExactRenamingFilesWhenNotEnabled() Commit @new = repo.Commit("Updated", Constants.Signature, Constants.Signature); - var changes = repo.Diff.Compare(old.Tree, @new.Tree, + using (var changes = repo.Diff.Compare(old.Tree, @new.Tree, compareOptions: new CompareOptions { Similarity = SimilarityOptions.None, - }); - - Assert.Equal(2, changes.Count()); - Assert.Equal(0, changes.Renamed.Count()); + })) + { + Assert.Equal(2, changes.Count()); + Assert.Equal(0, changes.Renamed.Count()); + } } } @@ -547,17 +573,18 @@ public void CanDetectTheExactCopyingOfNonModifiedFilesWhenEnabled() Commit @new = repo.Commit("Updated", Constants.Signature, Constants.Signature); - var changes = repo.Diff.Compare(old.Tree, @new.Tree, + using (var changes = repo.Diff.Compare(old.Tree, @new.Tree, compareOptions: new CompareOptions { Similarity = SimilarityOptions.CopiesHarder, - }); - - Assert.Equal(1, changes.Count()); - Assert.Equal(1, changes.Copied.Count()); - Assert.Equal(originalPath, changes.Copied.Single().OldPath); - Assert.Equal(copiedPath, changes.Copied.Single().Path); + })) + { + Assert.Equal(1, changes.Count()); + Assert.Equal(1, changes.Copied.Count()); + Assert.Equal(originalPath, changes.Copied.Single().OldPath); + Assert.Equal(copiedPath, changes.Copied.Single().Path); + } } } @@ -584,10 +611,11 @@ public void CanNotDetectTheExactCopyingOfNonModifiedFilesWhenNotEnabled() Commit @new = repo.Commit("Updated", Constants.Signature, Constants.Signature); - var changes = repo.Diff.Compare(old.Tree, @new.Tree); - - Assert.Equal(1, changes.Count()); - Assert.Equal(0, changes.Copied.Count()); + using (var changes = repo.Diff.Compare(old.Tree, @new.Tree)) + { + Assert.Equal(1, changes.Count()); + Assert.Equal(0, changes.Copied.Count()); + } } } @@ -617,17 +645,18 @@ public void CanDetectTheExactCopyingOfModifiedFilesWhenEnabled() Commit @new = repo.Commit("Updated", Constants.Signature, Constants.Signature); - var changes = repo.Diff.Compare(old.Tree, @new.Tree, + using (var changes = repo.Diff.Compare(old.Tree, @new.Tree, compareOptions: new CompareOptions { Similarity = SimilarityOptions.Copies, - }); - - Assert.Equal(2, changes.Count()); - Assert.Equal(1, changes.Copied.Count()); - Assert.Equal(originalPath, changes.Copied.Single().OldPath); - Assert.Equal(copiedPath, changes.Copied.Single().Path); + })) + { + Assert.Equal(2, changes.Count()); + Assert.Equal(1, changes.Copied.Count()); + Assert.Equal(originalPath, changes.Copied.Single().OldPath); + Assert.Equal(copiedPath, changes.Copied.Single().Path); + } } } @@ -657,10 +686,11 @@ public void CanNotDetectTheExactCopyingOfModifiedFilesWhenNotEnabled() Commit @new = repo.Commit("Updated", Constants.Signature, Constants.Signature); - var changes = repo.Diff.Compare(old.Tree, @new.Tree); - - Assert.Equal(2, changes.Count()); - Assert.Equal(0, changes.Copied.Count()); + using (var changes = repo.Diff.Compare(old.Tree, @new.Tree)) + { + Assert.Equal(2, changes.Count()); + Assert.Equal(0, changes.Copied.Count()); + } } } @@ -681,12 +711,13 @@ public void CanIncludeUnmodifiedEntriesWhenEnabled() Commands.Stage(repo, "b.txt"); Commit @new = repo.Commit("Updated", Constants.Signature, Constants.Signature); - var changes = repo.Diff.Compare(old.Tree, @new.Tree, - compareOptions: new CompareOptions {IncludeUnmodified = true}); - - Assert.Equal(2, changes.Count()); - Assert.Equal(1, changes.Unmodified.Count()); - Assert.Equal(1, changes.Modified.Count()); + using (var changes = repo.Diff.Compare(old.Tree, @new.Tree, + compareOptions: new CompareOptions { IncludeUnmodified = true })) + { + Assert.Equal(2, changes.Count()); + Assert.Equal(1, changes.Unmodified.Count()); + Assert.Equal(1, changes.Modified.Count()); + } } } @@ -729,23 +760,24 @@ public void CanDetectTheExactRenamingExactCopyingOfNonModifiedAndModifiedFilesWh Commit @new = repo.Commit("Updated", Constants.Signature, Constants.Signature); - var changes = repo.Diff.Compare(old.Tree, @new.Tree, + using (var changes = repo.Diff.Compare(old.Tree, @new.Tree, compareOptions: new CompareOptions { Similarity = SimilarityOptions.CopiesHarder, - }); - - Assert.Equal(4, changes.Count()); - Assert.Equal(1, changes.Modified.Count()); - Assert.Equal(1, changes.Renamed.Count()); - Assert.Equal(originalPath, changes.Renamed.Single().OldPath); - Assert.Equal(renamedPath, changes.Renamed.Single().Path); - Assert.Equal(2, changes.Copied.Count()); - Assert.Equal(originalPath2, changes.Copied.ElementAt(0).OldPath); - Assert.Equal(copiedPath1, changes.Copied.ElementAt(0).Path); - Assert.Equal(originalPath3, changes.Copied.ElementAt(1).OldPath); - Assert.Equal(copiedPath2, changes.Copied.ElementAt(1).Path); + })) + { + Assert.Equal(4, changes.Count()); + Assert.Equal(1, changes.Modified.Count()); + Assert.Equal(1, changes.Renamed.Count()); + Assert.Equal(originalPath, changes.Renamed.Single().OldPath); + Assert.Equal(renamedPath, changes.Renamed.Single().Path); + Assert.Equal(2, changes.Copied.Count()); + Assert.Equal(originalPath2, changes.Copied.ElementAt(0).OldPath); + Assert.Equal(copiedPath1, changes.Copied.ElementAt(0).Path); + Assert.Equal(originalPath3, changes.Copied.ElementAt(1).OldPath); + Assert.Equal(copiedPath2, changes.Copied.ElementAt(1).Path); + } } } /* @@ -784,22 +816,24 @@ public void CanCompareTwoVersionsOfAFileWithATrailingNewlineDeletion(int context Tree rootCommitTree = repo.Lookup("f8d44d7").Tree; Tree commitTreeWithUpdatedFile = repo.Lookup("ec9e401").Tree; - var changes = repo.Diff.Compare(rootCommitTree, commitTreeWithUpdatedFile); - - Assert.Equal(1, changes.Count()); - Assert.Equal(1, changes.Modified.Count()); - - var patch = repo.Diff.Compare(rootCommitTree, commitTreeWithUpdatedFile, - compareOptions: new CompareOptions { ContextLines = contextLines }); + using (var changes = repo.Diff.Compare(rootCommitTree, commitTreeWithUpdatedFile)) + { + Assert.Equal(1, changes.Count()); + Assert.Equal(1, changes.Modified.Count()); + } - Assert.Equal(expectedPatchLength, patch.Content.Length); + using (var patch = repo.Diff.Compare(rootCommitTree, commitTreeWithUpdatedFile, + compareOptions: new CompareOptions { ContextLines = contextLines })) + { + Assert.Equal(expectedPatchLength, patch.Content.Length); - PatchEntryChanges entryChanges = patch["numbers.txt"]; + PatchEntryChanges entryChanges = patch["numbers.txt"]; - Assert.Equal(2, entryChanges.LinesAdded); - Assert.Equal(1, entryChanges.LinesDeleted); - Assert.Equal(expectedPatchLength, entryChanges.Patch.Length); - Assert.Equal("numbers.txt", entryChanges.Path); + Assert.Equal(2, entryChanges.LinesAdded); + Assert.Equal(1, entryChanges.LinesDeleted); + Assert.Equal(expectedPatchLength, entryChanges.Patch.Length); + Assert.Equal("numbers.txt", entryChanges.Path); + } } } @@ -880,26 +914,28 @@ public void CanCompareTwoVersionsOfAFileWithADiffOfTwoHunks(int contextLines, in Tree rootCommitTree = repo.Lookup("f8d44d7").Tree; Tree mergedCommitTree = repo.Lookup("7252fe2").Tree; - var changes = repo.Diff.Compare(rootCommitTree, mergedCommitTree, compareOptions: compareOptions); - - Assert.Equal(3, changes.Count()); - Assert.Equal(1, changes.Modified.Count()); - Assert.Equal(1, changes.Deleted.Count()); - Assert.Equal(1, changes.Added.Count()); - - Assert.Equal(Mode.Nonexistent, changes.Single(c => c.Path =="my-name-does-not-feel-right.txt").Mode); - - var patch = repo.Diff.Compare(rootCommitTree, mergedCommitTree, compareOptions: compareOptions); + using (var changes = repo.Diff.Compare(rootCommitTree, mergedCommitTree, compareOptions: compareOptions)) + { + Assert.Equal(3, changes.Count()); + Assert.Equal(1, changes.Modified.Count()); + Assert.Equal(1, changes.Deleted.Count()); + Assert.Equal(1, changes.Added.Count()); - PatchEntryChanges entryChanges = patch["numbers.txt"]; + Assert.Equal(Mode.Nonexistent, changes.Single(c => c.Path == "my-name-does-not-feel-right.txt").Mode); + } - Assert.Equal(3, entryChanges.LinesAdded); - Assert.Equal(1, entryChanges.LinesDeleted); - Assert.Equal(Expected("f8d44d7...7252fe2/numbers.txt-{0}-{1}.diff", contextLines, interhunkLines), - entryChanges.Patch); - Assert.Equal(Expected("f8d44d7...7252fe2/full-{0}-{1}.diff", contextLines, interhunkLines), - patch); - Assert.Equal("numbers.txt", entryChanges.Path); + using (var patch = repo.Diff.Compare(rootCommitTree, mergedCommitTree, compareOptions: compareOptions)) + { + PatchEntryChanges entryChanges = patch["numbers.txt"]; + + Assert.Equal(3, entryChanges.LinesAdded); + Assert.Equal(1, entryChanges.LinesDeleted); + Assert.Equal(Expected("f8d44d7...7252fe2/numbers.txt-{0}-{1}.diff", contextLines, interhunkLines), + entryChanges.Patch); + Assert.Equal(Expected("f8d44d7...7252fe2/full-{0}-{1}.diff", contextLines, interhunkLines), + patch); + Assert.Equal("numbers.txt", entryChanges.Path); + } } } @@ -925,13 +961,14 @@ private void CanHandleTwoTreeEntryChangesWithTheSamePath(SimilarityOptions simil Tree treeNew = repo.ObjectDatabase.CreateTree(tdNew); - var changes = repo.Diff.Compare(treeOld, treeNew, + using (var changes = repo.Diff.Compare(treeOld, treeNew, compareOptions: new CompareOptions { Similarity = similarity, - }); - - verifier(path, changes); + })) + { + verifier(path, changes); + } } } @@ -993,19 +1030,21 @@ public void CanCompareATreeAgainstANullTree() { Tree tree = repo.Branches["refs/remotes/origin/test"].Tip.Tree; - var changes = repo.Diff.Compare(tree, null); - - Assert.Equal(1, changes.Count()); - Assert.Equal(1, changes.Deleted.Count()); - - Assert.Equal("readme.txt", changes.Deleted.Single().Path); + using (var changes = repo.Diff.Compare(tree, null)) + { + Assert.Equal(1, changes.Count()); + Assert.Equal(1, changes.Deleted.Count()); - changes = repo.Diff.Compare(null, tree); + Assert.Equal("readme.txt", changes.Deleted.Single().Path); + } - Assert.Equal(1, changes.Count()); - Assert.Equal(1, changes.Added.Count()); + using (var changes = repo.Diff.Compare(null, tree)) + { + Assert.Equal(1, changes.Count()); + Assert.Equal(1, changes.Added.Count()); - Assert.Equal("readme.txt", changes.Added.Single().Path); + Assert.Equal("readme.txt", changes.Added.Single().Path); + } } } @@ -1015,9 +1054,10 @@ public void ComparingTwoNullTreesReturnsAnEmptyTreeChanges() var path = SandboxStandardTestRepoGitDir(); using (var repo = new Repository(path)) { - var changes = repo.Diff.Compare(default(Tree), default(Tree)); - - Assert.Equal(0, changes.Count()); + using (var changes = repo.Diff.Compare(default(Tree), default(Tree))) + { + Assert.Equal(0, changes.Count()); + } } } @@ -1047,21 +1087,23 @@ public void ComparingReliesOnProvidedConfigEntriesIfAny() using (var repo = new Repository(path)) { SetFilemode(repo, true); - var changes = repo.Diff.Compare(new[] { file }); - - Assert.Equal(1, changes.Count()); + using(var changes = repo.Diff.Compare(new[] { file })) + { + Assert.Equal(1, changes.Count()); - var change = changes.Modified.Single(); - Assert.Equal(Mode.ExecutableFile, change.OldMode); - Assert.Equal(Mode.NonExecutableFile, change.Mode); + var change = changes.Modified.Single(); + Assert.Equal(Mode.ExecutableFile, change.OldMode); + Assert.Equal(Mode.NonExecutableFile, change.Mode); + } } using (var repo = new Repository(path)) { SetFilemode(repo, false); - var changes = repo.Diff.Compare(new[] { file }); - - Assert.Equal(0, changes.Count()); + using (var changes = repo.Diff.Compare(new[] { file })) + { + Assert.Equal(0, changes.Count()); + } } } @@ -1097,10 +1139,11 @@ public void RetrievingDiffChangesMustAlwaysBeCaseSensitive() using (var repo = new Repository(repoPath)) { - var changes = repo.Diff.Compare(repo.Lookup(treeOldOid), repo.Lookup(treeNewOid)); - - Assert.Equal(ChangeKind.Modified, changes.Single(c => c.Path == "a.txt").Status); - Assert.Equal(ChangeKind.Modified, changes.Single(c => c.Path == "A.TXT").Status); + using (var changes = repo.Diff.Compare(repo.Lookup(treeOldOid), repo.Lookup(treeNewOid))) + { + Assert.Equal(ChangeKind.Modified, changes.Single(c => c.Path == "a.txt").Status); + Assert.Equal(ChangeKind.Modified, changes.Single(c => c.Path == "A.TXT").Status); + } } } @@ -1168,9 +1211,12 @@ public void UsingPatienceAlgorithmCompareOptionProducesPatienceDiff() .Append("+cccccc\n") .Append("+cccccc\n").ToString(); - Assert.Equal(diffDefault, repo.Diff.Compare(treeOld, treeNew)); - Assert.Equal(diffPatience, repo.Diff.Compare(treeOld, treeNew, - compareOptions: new CompareOptions { Algorithm = DiffAlgorithm.Patience })); + using (var changes = repo.Diff.Compare(treeOld, treeNew)) + Assert.Equal(diffDefault, changes); + + using (var changes = repo.Diff.Compare(treeOld, treeNew, + compareOptions: new CompareOptions { Algorithm = DiffAlgorithm.Patience })) + Assert.Equal(diffPatience, changes); } } } diff --git a/LibGit2Sharp.Tests/DiffWorkdirToIndexFixture.cs b/LibGit2Sharp.Tests/DiffWorkdirToIndexFixture.cs index f08ee877a..ba7658ebc 100644 --- a/LibGit2Sharp.Tests/DiffWorkdirToIndexFixture.cs +++ b/LibGit2Sharp.Tests/DiffWorkdirToIndexFixture.cs @@ -33,11 +33,12 @@ public void CanCompareTheWorkDirAgainstTheIndex() var path = SandboxStandardTestRepoGitDir(); using (var repo = new Repository(path)) { - var changes = repo.Diff.Compare(); - - Assert.Equal(2, changes.Count()); - Assert.Equal("deleted_unstaged_file.txt", changes.Deleted.Single().Path); - Assert.Equal("modified_unstaged_file.txt", changes.Modified.Single().Path); + using (var changes = repo.Diff.Compare()) + { + Assert.Equal(2, changes.Count()); + Assert.Equal("deleted_unstaged_file.txt", changes.Deleted.Single().Path); + Assert.Equal("modified_unstaged_file.txt", changes.Modified.Single().Path); + } } } @@ -51,11 +52,15 @@ public void CanCompareTheWorkDirAgainstTheIndexWithLaxUnmatchedExplicitPathsVali { Assert.Equal(currentStatus, repo.RetrieveStatus(relativePath)); - var changes = repo.Diff.Compare(new[] { relativePath }, false, new ExplicitPathsOptions { ShouldFailOnUnmatchedPath = false }); - Assert.Equal(0, changes.Count()); + using (var changes = repo.Diff.Compare(new[] { relativePath }, false, new ExplicitPathsOptions { ShouldFailOnUnmatchedPath = false })) + { + Assert.Equal(0, changes.Count()); + } - changes = repo.Diff.Compare(new[] { relativePath }); - Assert.Equal(0, changes.Count()); + using (var changes = repo.Diff.Compare(new[] { relativePath })) + { + Assert.Equal(0, changes.Count()); + } } } @@ -85,12 +90,14 @@ public void CallbackForUnmatchedExplicitPathsIsCalledWhenSet(string relativePath { Assert.Equal(currentStatus, repo.RetrieveStatus(relativePath)); - repo.Diff.Compare(new[] { relativePath }, false, new ExplicitPathsOptions + using (var changes = repo.Diff.Compare(new[] { relativePath }, false, new ExplicitPathsOptions { ShouldFailOnUnmatchedPath = false, - OnUnmatchedPath = callback.OnUnmatchedPath }); - - Assert.True(callback.WasCalled); + OnUnmatchedPath = callback.OnUnmatchedPath + })) + { + Assert.True(callback.WasCalled); + } } } @@ -130,21 +137,23 @@ public void ComparingReliesOnProvidedConfigEntriesIfAny() using (var repo = new Repository(path)) { SetFilemode(repo, true); - var changes = repo.Diff.Compare(new[] { file }); - - Assert.Equal(1, changes.Count()); + using(var changes = repo.Diff.Compare(new[] { file })) + { + Assert.Equal(1, changes.Count()); - var change = changes.Modified.Single(); - Assert.Equal(Mode.ExecutableFile, change.OldMode); - Assert.Equal(Mode.NonExecutableFile, change.Mode); + var change = changes.Modified.Single(); + Assert.Equal(Mode.ExecutableFile, change.OldMode); + Assert.Equal(Mode.NonExecutableFile, change.Mode); + } } using (var repo = new Repository(path)) { SetFilemode(repo, false); - var changes = repo.Diff.Compare(new[] { file }); - - Assert.Equal(0, changes.Count()); + using(var changes = repo.Diff.Compare(new[] { file })) + { + Assert.Equal(0, changes.Count()); + } } } @@ -159,12 +168,13 @@ public void CanCompareTheWorkDirAgainstTheIndexWithUntrackedFiles() var path = SandboxStandardTestRepoGitDir(); using (var repo = new Repository(path)) { - var changes = repo.Diff.Compare(null, true); - - Assert.Equal(3, changes.Count()); - Assert.Equal("deleted_unstaged_file.txt", changes.Deleted.Single().Path); - Assert.Equal("modified_unstaged_file.txt", changes.Modified.Single().Path); - Assert.Equal("new_untracked_file.txt", changes.Added.Single().Path); + using (var changes = repo.Diff.Compare(null, true)) + { + Assert.Equal(3, changes.Count()); + Assert.Equal("deleted_unstaged_file.txt", changes.Deleted.Single().Path); + Assert.Equal("modified_unstaged_file.txt", changes.Modified.Single().Path); + Assert.Equal("new_untracked_file.txt", changes.Added.Single().Path); + } } } } diff --git a/LibGit2Sharp.Tests/PatchStatsFixture.cs b/LibGit2Sharp.Tests/PatchStatsFixture.cs index 41d3fdb23..758a08e2a 100644 --- a/LibGit2Sharp.Tests/PatchStatsFixture.cs +++ b/LibGit2Sharp.Tests/PatchStatsFixture.cs @@ -13,14 +13,15 @@ public void CanExtractStatisticsFromDiff() { var oldTree = repo.Lookup("origin/packed-test").Tree; var newTree = repo.Lookup("HEAD").Tree; - var stats = repo.Diff.Compare(oldTree, newTree); + using (var stats = repo.Diff.Compare(oldTree, newTree)) + { + Assert.Equal(8, stats.TotalLinesAdded); + Assert.Equal(1, stats.TotalLinesDeleted); - Assert.Equal(8, stats.TotalLinesAdded); - Assert.Equal(1, stats.TotalLinesDeleted); - - var contentStats = stats["new.txt"]; - Assert.Equal(1, contentStats.LinesAdded); - Assert.Equal(1, contentStats.LinesDeleted); + var contentStats = stats["new.txt"]; + Assert.Equal(1, contentStats.LinesAdded); + Assert.Equal(1, contentStats.LinesDeleted); + } } } } diff --git a/LibGit2Sharp/Commands/Remove.cs b/LibGit2Sharp/Commands/Remove.cs index 87265a2dd..939c427d1 100644 --- a/LibGit2Sharp/Commands/Remove.cs +++ b/LibGit2Sharp/Commands/Remove.cs @@ -182,58 +182,60 @@ private static void RemoveFilesAndFolders(IRepository repository, IEnumerable RemoveStagedItems(IRepository repository, IEnumerable paths, bool removeFromWorkingDirectory = true, ExplicitPathsOptions explicitPathsOptions = null) { var removed = new List(); - var changes = repository.Diff.Compare(DiffModifiers.IncludeUnmodified | DiffModifiers.IncludeUntracked, paths, explicitPathsOptions); - var index = repository.Index; - - foreach (var treeEntryChanges in changes) + using (var changes = repository.Diff.Compare(DiffModifiers.IncludeUnmodified | DiffModifiers.IncludeUntracked, paths, explicitPathsOptions)) { - var status = repository.RetrieveStatus(treeEntryChanges.Path); + var index = repository.Index; - switch (treeEntryChanges.Status) + foreach (var treeEntryChanges in changes) { - case ChangeKind.Added: - case ChangeKind.Deleted: - removed.Add(treeEntryChanges.Path); - index.Remove(treeEntryChanges.Path); - break; - - case ChangeKind.Unmodified: - if (removeFromWorkingDirectory && ( - status.HasFlag(FileStatus.ModifiedInIndex) || - status.HasFlag(FileStatus.NewInIndex))) - { - throw new RemoveFromIndexException("Unable to remove file '{0}', as it has changes staged in the index. You can call the Remove() method with removeFromWorkingDirectory=false if you want to remove it from the index only.", - treeEntryChanges.Path); - } - removed.Add(treeEntryChanges.Path); - index.Remove(treeEntryChanges.Path); - continue; - - case ChangeKind.Modified: - if (status.HasFlag(FileStatus.ModifiedInWorkdir) && status.HasFlag(FileStatus.ModifiedInIndex)) - { - throw new RemoveFromIndexException("Unable to remove file '{0}', as it has staged content different from both the working directory and the HEAD.", - treeEntryChanges.Path); - } - if (removeFromWorkingDirectory) - { - throw new RemoveFromIndexException("Unable to remove file '{0}', as it has local modifications. You can call the Remove() method with removeFromWorkingDirectory=false if you want to remove it from the index only.", - treeEntryChanges.Path); - } - removed.Add(treeEntryChanges.Path); - index.Remove(treeEntryChanges.Path); - continue; - - default: - throw new RemoveFromIndexException("Unable to remove file '{0}'. Its current status is '{1}'.", - treeEntryChanges.Path, - treeEntryChanges.Status); + var status = repository.RetrieveStatus(treeEntryChanges.Path); + + switch (treeEntryChanges.Status) + { + case ChangeKind.Added: + case ChangeKind.Deleted: + removed.Add(treeEntryChanges.Path); + index.Remove(treeEntryChanges.Path); + break; + + case ChangeKind.Unmodified: + if (removeFromWorkingDirectory && ( + status.HasFlag(FileStatus.ModifiedInIndex) || + status.HasFlag(FileStatus.NewInIndex))) + { + throw new RemoveFromIndexException("Unable to remove file '{0}', as it has changes staged in the index. You can call the Remove() method with removeFromWorkingDirectory=false if you want to remove it from the index only.", + treeEntryChanges.Path); + } + removed.Add(treeEntryChanges.Path); + index.Remove(treeEntryChanges.Path); + continue; + + case ChangeKind.Modified: + if (status.HasFlag(FileStatus.ModifiedInWorkdir) && status.HasFlag(FileStatus.ModifiedInIndex)) + { + throw new RemoveFromIndexException("Unable to remove file '{0}', as it has staged content different from both the working directory and the HEAD.", + treeEntryChanges.Path); + } + if (removeFromWorkingDirectory) + { + throw new RemoveFromIndexException("Unable to remove file '{0}', as it has local modifications. You can call the Remove() method with removeFromWorkingDirectory=false if you want to remove it from the index only.", + treeEntryChanges.Path); + } + removed.Add(treeEntryChanges.Path); + index.Remove(treeEntryChanges.Path); + continue; + + default: + throw new RemoveFromIndexException("Unable to remove file '{0}'. Its current status is '{1}'.", + treeEntryChanges.Path, + treeEntryChanges.Status); + } } - } - index.Write(); + index.Write(); - return removed; + return removed; + } } } } diff --git a/LibGit2Sharp/Commands/Stage.cs b/LibGit2Sharp/Commands/Stage.cs index f3ff647a4..9917ca52a 100644 --- a/LibGit2Sharp/Commands/Stage.cs +++ b/LibGit2Sharp/Commands/Stage.cs @@ -74,68 +74,69 @@ public static void Stage(IRepository repository, IEnumerable paths, Stag diffModifiers |= DiffModifiers.IncludeIgnored; } - var changes = repository.Diff.Compare(diffModifiers, paths, explicitPathsOptions, - new CompareOptions { Similarity = SimilarityOptions.None }); - - var unexpectedTypesOfChanges = changes - .Where( - tec => tec.Status != ChangeKind.Added && - tec.Status != ChangeKind.Modified && - tec.Status != ChangeKind.Conflicted && - tec.Status != ChangeKind.Unmodified && - tec.Status != ChangeKind.Deleted).ToList(); - - if (unexpectedTypesOfChanges.Count > 0) + using (var changes = repository.Diff.Compare(diffModifiers, paths, explicitPathsOptions, + new CompareOptions { Similarity = SimilarityOptions.None })) { - throw new InvalidOperationException( - string.Format(CultureInfo.InvariantCulture, - "Entry '{0}' bears an unexpected ChangeKind '{1}'", - unexpectedTypesOfChanges[0].Path, unexpectedTypesOfChanges[0].Status)); - } + var unexpectedTypesOfChanges = changes + .Where( + tec => tec.Status != ChangeKind.Added && + tec.Status != ChangeKind.Modified && + tec.Status != ChangeKind.Conflicted && + tec.Status != ChangeKind.Unmodified && + tec.Status != ChangeKind.Deleted).ToList(); + + if (unexpectedTypesOfChanges.Count > 0) + { + throw new InvalidOperationException( + string.Format(CultureInfo.InvariantCulture, + "Entry '{0}' bears an unexpected ChangeKind '{1}'", + unexpectedTypesOfChanges[0].Path, unexpectedTypesOfChanges[0].Status)); + } - /* Remove files from the index that don't exist on disk */ - foreach (TreeEntryChanges treeEntryChanges in changes) - { - switch (treeEntryChanges.Status) + /* Remove files from the index that don't exist on disk */ + foreach (TreeEntryChanges treeEntryChanges in changes) { - case ChangeKind.Conflicted: - if (!treeEntryChanges.Exists) - { + switch (treeEntryChanges.Status) + { + case ChangeKind.Conflicted: + if (!treeEntryChanges.Exists) + { + repository.Index.Remove(treeEntryChanges.Path); + } + break; + + case ChangeKind.Deleted: repository.Index.Remove(treeEntryChanges.Path); - } - break; - - case ChangeKind.Deleted: - repository.Index.Remove(treeEntryChanges.Path); - break; + break; - default: - continue; + default: + continue; + } } - } - foreach (TreeEntryChanges treeEntryChanges in changes) - { - switch (treeEntryChanges.Status) + foreach (TreeEntryChanges treeEntryChanges in changes) { - case ChangeKind.Added: - case ChangeKind.Modified: - repository.Index.Add(treeEntryChanges.Path); - break; - - case ChangeKind.Conflicted: - if (treeEntryChanges.Exists) - { + switch (treeEntryChanges.Status) + { + case ChangeKind.Added: + case ChangeKind.Modified: repository.Index.Add(treeEntryChanges.Path); - } - break; - - default: - continue; + break; + + case ChangeKind.Conflicted: + if (treeEntryChanges.Exists) + { + repository.Index.Add(treeEntryChanges.Path); + } + break; + + default: + continue; + } } - } - repository.Index.Write(); + repository.Index.Write(); + } } /// @@ -191,9 +192,8 @@ public static void Unstage(IRepository repository, IEnumerable paths, Ex if (repository.Info.IsHeadUnborn) { - var changes = repository.Diff.Compare(null, DiffTargets.Index, paths, explicitPathsOptions, new CompareOptions { Similarity = SimilarityOptions.None }); - - repository.Index.Replace(changes); + using (var changes = repository.Diff.Compare(null, DiffTargets.Index, paths, explicitPathsOptions, new CompareOptions { Similarity = SimilarityOptions.None })) + repository.Index.Replace(changes); } else { diff --git a/LibGit2Sharp/Core/FileHistory.cs b/LibGit2Sharp/Core/FileHistory.cs index 477717c79..5c10a1a24 100644 --- a/LibGit2Sharp/Core/FileHistory.cs +++ b/LibGit2Sharp/Core/FileHistory.cs @@ -163,11 +163,13 @@ private static void DetermineParentPaths(IRepository repo, Commit currentCommit, private static string ParentPath(IRepository repo, Commit currentCommit, string currentPath, Commit parentCommit) { - var treeChanges = repo.Diff.Compare(parentCommit.Tree, currentCommit.Tree); - var treeEntryChanges = treeChanges.FirstOrDefault(c => c.Path == currentPath); - return treeEntryChanges != null && treeEntryChanges.Status == ChangeKind.Renamed - ? treeEntryChanges.OldPath - : currentPath; + using (var treeChanges = repo.Diff.Compare(parentCommit.Tree, currentCommit.Tree)) + { + var treeEntryChanges = treeChanges.FirstOrDefault(c => c.Path == currentPath); + return treeEntryChanges != null && treeEntryChanges.Status == ChangeKind.Renamed + ? treeEntryChanges.OldPath + : currentPath; + } } } } diff --git a/LibGit2Sharp/Core/Handles/Libgit2Object.cs b/LibGit2Sharp/Core/Handles/Libgit2Object.cs index cbb431a98..9aae0129c 100644 --- a/LibGit2Sharp/Core/Handles/Libgit2Object.cs +++ b/LibGit2Sharp/Core/Handles/Libgit2Object.cs @@ -5,7 +5,7 @@ // // Uncomment the line below or add a conditional symbol to activate this mode -// #define LEAKS_IDENTIFYING +#define LEAKS_IDENTIFYING // This activates a more throrough mode which will show the stack trace of the // allocation code path for each handle that has been improperly released. @@ -15,7 +15,7 @@ // // Uncomment the line below or add a conditional symbol to activate this mode -// #define LEAKS_TRACKING +#define LEAKS_TRACKING using System; using System.Linq; diff --git a/LibGit2Sharp/Index.cs b/LibGit2Sharp/Index.cs index 3ddc6d694..d68419ab1 100644 --- a/LibGit2Sharp/Index.cs +++ b/LibGit2Sharp/Index.cs @@ -292,8 +292,10 @@ public virtual void Replace(Commit commit, IEnumerable paths, ExplicitPa { Ensure.ArgumentNotNull(commit, "commit"); - var changes = repo.Diff.Compare(commit.Tree, DiffTargets.Index, paths, explicitPathsOptions, new CompareOptions { Similarity = SimilarityOptions.None }); - Replace(changes); + using (var changes = repo.Diff.Compare(commit.Tree, DiffTargets.Index, paths, explicitPathsOptions, new CompareOptions { Similarity = SimilarityOptions.None })) + { + Replace(changes); + } } /// From 53b267b73204a1bdc6bc6f6677f670c84ee01eec Mon Sep 17 00:00:00 2001 From: Markus Olsson Date: Fri, 18 Mar 2016 19:20:57 +0100 Subject: [PATCH 5/5] Can't compare tree entry changes purely by object reference any more --- LibGit2Sharp.Tests/DiffTreeToTreeFixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LibGit2Sharp.Tests/DiffTreeToTreeFixture.cs b/LibGit2Sharp.Tests/DiffTreeToTreeFixture.cs index 8cde292a4..f51def511 100644 --- a/LibGit2Sharp.Tests/DiffTreeToTreeFixture.cs +++ b/LibGit2Sharp.Tests/DiffTreeToTreeFixture.cs @@ -72,7 +72,7 @@ public void CanCompareACommitTreeAgainstItsParent() Assert.Equal("1.txt", treeEntryChanges.Path); Assert.Equal(ChangeKind.Added, treeEntryChanges.Status); - Assert.Equal(treeEntryChanges, changes.Added.Single()); + Assert.Equal(treeEntryChanges.Path, changes.Added.Single().Path); Assert.Equal(Mode.Nonexistent, treeEntryChanges.OldMode); }