Skip to content

Commit 92b0e4e

Browse files
committed
Introduce low level Index/Tree operations
1 parent 8d8fbb1 commit 92b0e4e

File tree

6 files changed

+144
-0
lines changed

6 files changed

+144
-0
lines changed

LibGit2Sharp.Tests/IndexFixture.cs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,5 +278,67 @@ public void CanCopeWithExternalChangesToTheIndex()
278278
Assert.Equal(2, repoRead.Index.Count);
279279
}
280280
}
281+
282+
[Fact]
283+
public void CanResetFullyMergedIndexFromTree()
284+
{
285+
string path = CloneStandardTestRepo();
286+
287+
const string testFile = "new_tracked_file.txt";
288+
289+
// It is sufficient to check just one of the stage area changes, such as the added file,
290+
// to verify that the index has indeed been read from the tree.
291+
using (var repo = new Repository(path))
292+
{
293+
const string headIndexTreeSha = "e5d221fc5da11a3169bf503d76497c81be3207b6";
294+
295+
Assert.True(repo.Index.IsFullyMerged);
296+
Assert.Equal(FileStatus.Added, repo.Index.RetrieveStatus(testFile));
297+
298+
var headIndexTree = repo.Lookup<Tree>(headIndexTreeSha);
299+
Assert.NotNull(headIndexTree);
300+
repo.Index.Reset(headIndexTree);
301+
302+
Assert.True(repo.Index.IsFullyMerged);
303+
Assert.Equal(FileStatus.Untracked, repo.Index.RetrieveStatus(testFile));
304+
}
305+
306+
// Check that the index was persisted to disk.
307+
using (var repo = new Repository(path))
308+
{
309+
Assert.Equal(FileStatus.Untracked, repo.Index.RetrieveStatus(testFile));
310+
}
311+
}
312+
313+
[Fact]
314+
public void CanResetIndexWithUnmergedEntriesFromTree()
315+
{
316+
string path = CloneMergedTestRepo();
317+
318+
const string testFile = "one.txt";
319+
320+
// It is sufficient to check just one of the stage area changes, such as the modified file,
321+
// to verify that the index has indeed been read from the tree.
322+
using (var repo = new Repository(path))
323+
{
324+
const string headIndexTreeSha = "1cb365141a52dfbb24933515820eb3045fbca12b";
325+
326+
Assert.False(repo.Index.IsFullyMerged);
327+
Assert.Equal(FileStatus.Staged, repo.Index.RetrieveStatus(testFile));
328+
329+
var headIndexTree = repo.Lookup<Tree>(headIndexTreeSha);
330+
Assert.NotNull(headIndexTree);
331+
repo.Index.Reset(headIndexTree);
332+
333+
Assert.True(repo.Index.IsFullyMerged);
334+
Assert.Equal(FileStatus.Modified, repo.Index.RetrieveStatus(testFile));
335+
}
336+
337+
// Check that the index was persisted to disk.
338+
using (var repo = new Repository(path))
339+
{
340+
Assert.Equal(FileStatus.Modified, repo.Index.RetrieveStatus(testFile));
341+
}
342+
}
281343
}
282344
}

LibGit2Sharp.Tests/ObjectDatabaseFixture.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,40 @@ public void CannotCreateATreeContainingABlobFromARelativePathAgainstABareReposit
360360
}
361361
}
362362

363+
[Fact]
364+
public void CreatingATreeFromIndexWithUnmergedEntriesThrows()
365+
{
366+
using (var repo = new Repository(MergedTestRepoWorkingDirPath))
367+
{
368+
Assert.False(repo.Index.IsFullyMerged);
369+
370+
Assert.Throws<UnmergedIndexEntriesException>(
371+
() => repo.ObjectDatabase.CreateTree(repo.Index));
372+
}
373+
}
374+
375+
[Fact]
376+
public void CanCreateATreeFromIndex()
377+
{
378+
string path = CloneStandardTestRepo();
379+
380+
using (var repo = new Repository(path))
381+
{
382+
const string expectedIndexTreeSha = "0fe0fd1943a1b63ecca36fa6bbe9bbe045f791a4";
383+
384+
// The tree representing the index is not in the db.
385+
Assert.Null(repo.Lookup(expectedIndexTreeSha));
386+
387+
var tree = repo.ObjectDatabase.CreateTree(repo.Index);
388+
Assert.NotNull(tree);
389+
Assert.Equal(expectedIndexTreeSha, tree.Id.Sha);
390+
391+
// The tree representing the index is now in the db.
392+
tree = repo.Lookup<Tree>(expectedIndexTreeSha);
393+
Assert.NotNull(tree);
394+
}
395+
}
396+
363397
[Fact]
364398
public void CanCreateACommit()
365399
{

LibGit2Sharp/Core/NativeMethods.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,9 @@ internal static extern IndexReucEntrySafeHandle git_index_reuc_get_bypath(
609609
[DllImport(libgit2)]
610610
internal static extern int git_index_write_tree(out GitOid treeOid, IndexSafeHandle index);
611611

612+
[DllImport(libgit2)]
613+
internal static extern int git_index_read_tree(IndexSafeHandle index, GitObjectSafeHandle tree);
614+
612615
[DllImport(libgit2)]
613616
internal static extern int git_merge_base_many(
614617
out GitOid mergeBase,

LibGit2Sharp/Core/Proxy.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,15 @@ public static ObjectId git_tree_create_fromindex(Index index)
984984
}
985985
}
986986

987+
public static void git_index_read_fromtree(Index index, GitObjectSafeHandle tree)
988+
{
989+
using (ThreadAffinity())
990+
{
991+
int res = NativeMethods.git_index_read_tree(index.Handle, tree);
992+
Ensure.ZeroResult(res);
993+
}
994+
}
995+
987996
#endregion
988997

989998
#region git_merge_

LibGit2Sharp/Index.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,23 @@ private void RemoveFilesAndFolders(IEnumerable<string> pathsList)
458458
}
459459
}
460460

461+
/// <summary>
462+
/// Replaces entries in the staging area with entries from the specified tree.
463+
/// <para>
464+
/// This overwrites all existing state in the staging area.
465+
/// </para>
466+
/// </summary>
467+
/// <param name="source">The <see cref="Tree"/> to read the entries from.</param>
468+
public virtual void Reset(Tree source)
469+
{
470+
using (var obj = new ObjectSafeWrapper(source.Id, repo.Handle))
471+
{
472+
Proxy.git_index_read_fromtree(this, obj.ObjectPtr);
473+
}
474+
475+
UpdatePhysicalIndex();
476+
}
477+
461478
private IDictionary<Tuple<string, FileStatus>, Tuple<string, FileStatus>> PrepareBatch(IEnumerable<string> leftPaths, IEnumerable<string> rightPaths)
462479
{
463480
IDictionary<Tuple<string, FileStatus>, Tuple<string, FileStatus>> dic = new Dictionary<Tuple<string, FileStatus>, Tuple<string, FileStatus>>();

LibGit2Sharp/ObjectDatabase.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,25 @@ public virtual Tree CreateTree(TreeDefinition treeDefinition)
245245
return treeDefinition.Build(repo);
246246
}
247247

248+
/// <summary>
249+
/// Inserts a <see cref="Tree"/> into the object database, created from the <see cref="Index"/>.
250+
/// <para>
251+
/// It recursively creates tree objects for each of the subtrees stored in the index, but only returns the root tree.
252+
/// </para>
253+
/// <para>
254+
/// The index must be fully merged.
255+
/// </para>
256+
/// </summary>
257+
/// <param name="index">The <see cref="Index"/>.</param>
258+
/// <returns>The created <see cref="Tree"/>. This can be used e.g. to create a <see cref="Commit"/>.</returns>
259+
public virtual Tree CreateTree(Index index)
260+
{
261+
Ensure.ArgumentNotNull(index, "index");
262+
263+
var treeId = Proxy.git_tree_create_fromindex(index);
264+
return this.repo.Lookup<Tree>(treeId);
265+
}
266+
248267
/// <summary>
249268
/// Inserts a <see cref="Commit"/> into the object database, referencing an existing <see cref="Tree"/>.
250269
/// <para>

0 commit comments

Comments
 (0)