Skip to content

Commit 4bc4857

Browse files
author
Edward Thomson
committed
Remove conflicts in Index.Remove
1 parent 6bfe4ab commit 4bc4857

File tree

4 files changed

+61
-21
lines changed

4 files changed

+61
-21
lines changed

LibGit2Sharp.Tests/ConflictFixture.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ private static List<object[]> RenameConflictData
5151
[InlineData(false, "ancestor-and-ours.txt", true, true, FileStatus.Removed |FileStatus.Untracked, 2)]
5252
[InlineData(true, "ancestor-and-theirs.txt", true, false, FileStatus.Nonexistent, 2)]
5353
[InlineData(false, "ancestor-and-theirs.txt", true, true, FileStatus.Untracked, 2)]
54+
[InlineData(true, "ancestor-only.txt", false, false, FileStatus.Nonexistent, 1)]
55+
[InlineData(false, "ancestor-only.txt", false, false, FileStatus.Nonexistent, 1)]
5456
[InlineData(true, "conflicts-one.txt", true, false, FileStatus.Removed, 3)]
5557
[InlineData(false, "conflicts-one.txt", true, true, FileStatus.Removed | FileStatus.Untracked, 3)]
5658
[InlineData(true, "conflicts-two.txt", true, false, FileStatus.Removed, 3)]
@@ -61,13 +63,6 @@ private static List<object[]> RenameConflictData
6163
[InlineData(false, "ours-only.txt", true, true, FileStatus.Removed | FileStatus.Untracked, 1)]
6264
[InlineData(true, "theirs-only.txt", true, false, FileStatus.Nonexistent, 1)]
6365
[InlineData(false, "theirs-only.txt", true, true, FileStatus.Untracked, 1)]
64-
/* Conflicts clearing through Index.Remove() only works when a version of the entry exists in the workdir.
65-
* This is because libgit2's git_iterator_for_index() seem to only care about stage level 0.
66-
* Corrolary: other cases only work out of sheer luck (however, the behaviour is stable, so I guess we
67-
* can rely on it for the moment.
68-
* [InlineData(true, "ancestor-only.txt", false, false, FileStatus.Nonexistent, 0)]
69-
* [InlineData(false, "ancestor-only.txt", false, false, FileStatus.Nonexistent, 0)]
70-
*/
7166
public void CanResolveConflictsByRemovingFromTheIndex(
7267
bool removeFromWorkdir, string filename, bool existsBeforeRemove, bool existsAfterRemove, FileStatus lastStatus, int removedIndexEntries)
7368
{

LibGit2Sharp.Tests/RemoveFixture.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public void RemovingFileWithBadParamsThrows()
180180
Assert.Throws<ArgumentException>(() => repo.Index.Remove(string.Empty));
181181
Assert.Throws<ArgumentNullException>(() => repo.Index.Remove((string)null));
182182
Assert.Throws<ArgumentException>(() => repo.Index.Remove(new string[] { }));
183-
Assert.Throws<ArgumentException>(() => repo.Index.Remove(new string[] { null }));
183+
Assert.Throws<ArgumentNullException>(() => repo.Index.Remove(new string[] { null }));
184184
}
185185
}
186186
}

LibGit2Sharp/Core/Ensure.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Linq;
3+
using System.Collections;
24
using System.Collections.Generic;
35
using System.Diagnostics;
46
using System.Globalization;
@@ -24,6 +26,21 @@ public static void ArgumentNotNull(object argumentValue, string argumentName)
2426
}
2527
}
2628

29+
/// <summary>
30+
/// Checks an array argument to ensure it isn't null or empty.
31+
/// </summary>
32+
/// <param name="argumentValue">The argument value to check.</param>
33+
/// <param name="argumentName">The name of the argument.</param>
34+
public static void ArgumentNotNullOrEmptyEnumerable<T>(IEnumerable<T> argumentValue, string argumentName)
35+
{
36+
ArgumentNotNull(argumentValue, argumentName);
37+
38+
if (argumentValue.Count() == 0)
39+
{
40+
throw new ArgumentException("Enumerable cannot be empty", argumentName);
41+
}
42+
}
43+
2744
/// <summary>
2845
/// Checks a string argument to ensure it isn't null or empty.
2946
/// </summary>

LibGit2Sharp/Index.cs

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -345,10 +345,44 @@ public virtual void Remove(string path, bool removeFromWorkingDirectory = true,
345345
/// </param>
346346
public virtual void Remove(IEnumerable<string> paths, bool removeFromWorkingDirectory = true, ExplicitPathsOptions explicitPathsOptions = null)
347347
{
348-
var pathsList = paths.ToList();
349-
var changes = repo.Diff.Compare<TreeChanges>(DiffModifiers.IncludeUnmodified | DiffModifiers.IncludeUntracked, pathsList, explicitPathsOptions);
348+
Ensure.ArgumentNotNullOrEmptyEnumerable<string>(paths, "paths");
350349

351-
var pathsTodelete = pathsList.Where(p => Directory.Exists(Path.Combine(repo.Info.WorkingDirectory, p))).ToList();
350+
var pathsToDelete = paths.Where(p => Directory.Exists(Path.Combine(repo.Info.WorkingDirectory, p))).ToList();
351+
var notConflictedPaths = new List<string>();
352+
353+
foreach (var path in paths)
354+
{
355+
Ensure.ArgumentNotNullOrEmptyString(path, "path");
356+
357+
var conflict = repo.Index.Conflicts[path];
358+
359+
if (conflict != null)
360+
{
361+
pathsToDelete.Add(RemoveFromIndex(path));
362+
}
363+
else
364+
{
365+
notConflictedPaths.Add(path);
366+
}
367+
}
368+
369+
if (notConflictedPaths.Count > 0)
370+
{
371+
pathsToDelete.AddRange(RemoveStagedItems(notConflictedPaths, removeFromWorkingDirectory, explicitPathsOptions));
372+
}
373+
374+
if (removeFromWorkingDirectory)
375+
{
376+
RemoveFilesAndFolders(pathsToDelete);
377+
}
378+
379+
UpdatePhysicalIndex();
380+
}
381+
382+
private IEnumerable<string> RemoveStagedItems(IEnumerable<string> paths, bool removeFromWorkingDirectory = true, ExplicitPathsOptions explicitPathsOptions = null)
383+
{
384+
var removed = new List<string>();
385+
var changes = repo.Diff.Compare<TreeChanges>(DiffModifiers.IncludeUnmodified | DiffModifiers.IncludeUntracked, paths, explicitPathsOptions);
352386

353387
foreach (var treeEntryChanges in changes)
354388
{
@@ -358,7 +392,7 @@ public virtual void Remove(IEnumerable<string> paths, bool removeFromWorkingDire
358392
{
359393
case ChangeKind.Added:
360394
case ChangeKind.Deleted:
361-
pathsTodelete.Add(RemoveFromIndex(treeEntryChanges.Path));
395+
removed.Add(RemoveFromIndex(treeEntryChanges.Path));
362396
break;
363397

364398
case ChangeKind.Unmodified:
@@ -369,7 +403,7 @@ public virtual void Remove(IEnumerable<string> paths, bool removeFromWorkingDire
369403
throw new RemoveFromIndexException(string.Format(CultureInfo.InvariantCulture, "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.",
370404
treeEntryChanges.Path));
371405
}
372-
pathsTodelete.Add(RemoveFromIndex(treeEntryChanges.Path));
406+
removed.Add(RemoveFromIndex(treeEntryChanges.Path));
373407
continue;
374408

375409
case ChangeKind.Modified:
@@ -383,22 +417,16 @@ public virtual void Remove(IEnumerable<string> paths, bool removeFromWorkingDire
383417
throw new RemoveFromIndexException(string.Format(CultureInfo.InvariantCulture, "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.",
384418
treeEntryChanges.Path));
385419
}
386-
pathsTodelete.Add(RemoveFromIndex(treeEntryChanges.Path));
420+
removed.Add(RemoveFromIndex(treeEntryChanges.Path));
387421
continue;
388422

389-
390423
default:
391424
throw new RemoveFromIndexException(string.Format(CultureInfo.InvariantCulture, "Unable to remove file '{0}'. Its current status is '{1}'.",
392425
treeEntryChanges.Path, treeEntryChanges.Status));
393426
}
394427
}
395428

396-
if (removeFromWorkingDirectory)
397-
{
398-
RemoveFilesAndFolders(pathsTodelete);
399-
}
400-
401-
UpdatePhysicalIndex();
429+
return removed;
402430
}
403431

404432
private void RemoveFilesAndFolders(IEnumerable<string> pathsList)

0 commit comments

Comments
 (0)