diff --git a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
index 770c38d60..f95292b68 100644
--- a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
+++ b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
@@ -69,6 +69,7 @@
+
diff --git a/LibGit2Sharp.Tests/NetworkFixture.cs b/LibGit2Sharp.Tests/NetworkFixture.cs
new file mode 100644
index 000000000..87c9f25cb
--- /dev/null
+++ b/LibGit2Sharp.Tests/NetworkFixture.cs
@@ -0,0 +1,96 @@
+using System.Collections.Generic;
+using System.Linq;
+using LibGit2Sharp.Core.Compat;
+using LibGit2Sharp.Tests.TestHelpers;
+using Xunit;
+using Xunit.Extensions;
+
+namespace LibGit2Sharp.Tests
+{
+ public class NetworkFixture : BaseFixture
+ {
+ [Theory]
+ [InlineData("https://github.com/libgit2/TestGitRepository")]
+ [InlineData("https://github.com/libgit2/TestGitRepository")]
+ [InlineData("git://github.com/libgit2/TestGitRepository.git")]
+ public void CanListRemoteReferences(string url)
+ {
+ string remoteName = "testRemote";
+
+ var scd = BuildSelfCleaningDirectory();
+ using (var repo = Repository.Init(scd.RootedDirectoryPath))
+ {
+ Remote remote = repo.Network.Remotes.Add(remoteName, url);
+ IEnumerable references = repo.Network.ListReferences(remote);
+
+ List> actualRefs = references.
+ Select(directRef => new Tuple(directRef.CanonicalName, directRef.TargetIdentifier)).ToList();
+
+ Assert.Equal(ExpectedRemoteRefs.Count, actualRefs.Count);
+ for (int i = 0; i < ExpectedRemoteRefs.Count; i++)
+ {
+ Assert.Equal(ExpectedRemoteRefs[i].Item2, actualRefs[i].Item2);
+ Assert.Equal(ExpectedRemoteRefs[i].Item1, actualRefs[i].Item1);
+ }
+ }
+ }
+
+ [Fact]
+ public void CanListRemoteReferenceObjects()
+ {
+ string url = "https://github.com/libgit2/TestGitRepository";
+ string remoteName = "origin";
+
+ var scd = BuildSelfCleaningDirectory();
+ using (Repository repo = Repository.Clone(url, scd.RootedDirectoryPath))
+ {
+ Remote remote = repo.Network.Remotes[remoteName];
+ IEnumerable references = repo.Network.ListReferences(remote);
+
+ List> actualRefs = new List>();
+
+ foreach(DirectReference reference in references)
+ {
+ Assert.NotNull(reference.CanonicalName);
+ Assert.NotNull(reference.Target);
+ actualRefs.Add(new Tuple(reference.CanonicalName, reference.Target.Id.Sha));
+ }
+
+ Assert.Equal(ExpectedRemoteRefs.Count, actualRefs.Count);
+ for (int i = 0; i < ExpectedRemoteRefs.Count; i++)
+ {
+ Assert.Equal(ExpectedRemoteRefs[i].Item1, actualRefs[i].Item1);
+ Assert.Equal(ExpectedRemoteRefs[i].Item2, actualRefs[i].Item2);
+ }
+ }
+ }
+
+ /*
+ * git ls-remote https://github.com/libgit2/TestGitRepository
+ * 49322bb17d3acc9146f98c97d078513228bbf3c0 HEAD
+ * 0966a434eb1a025db6b71485ab63a3bfbea520b6 refs/heads/first-merge
+ * 49322bb17d3acc9146f98c97d078513228bbf3c0 refs/heads/master
+ * 42e4e7c5e507e113ebbb7801b16b52cf867b7ce1 refs/heads/no-parent
+ * d96c4e80345534eccee5ac7b07fc7603b56124cb refs/tags/annotated_tag
+ * c070ad8c08840c8116da865b2d65593a6bb9cd2a refs/tags/annotated_tag^{}
+ * 55a1a760df4b86a02094a904dfa511deb5655905 refs/tags/blob
+ * 8f50ba15d49353813cc6e20298002c0d17b0a9ee refs/tags/commit_tree
+ * 6e0c7bdb9b4ed93212491ee778ca1c65047cab4e refs/tags/nearly-dangling
+ */
+ ///
+ /// Expected references on https://github.com/libgit2/TestGitRepository
+ ///
+ private static List> ExpectedRemoteRefs = new List>()
+ {
+ new Tuple("HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0"),
+ new Tuple("refs/heads/first-merge", "0966a434eb1a025db6b71485ab63a3bfbea520b6"),
+ new Tuple("refs/heads/master", "49322bb17d3acc9146f98c97d078513228bbf3c0"),
+ new Tuple("refs/heads/no-parent", "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1"),
+ new Tuple("refs/tags/annotated_tag", "d96c4e80345534eccee5ac7b07fc7603b56124cb"),
+ new Tuple("refs/tags/annotated_tag^{}", "c070ad8c08840c8116da865b2d65593a6bb9cd2a"),
+ new Tuple("refs/tags/blob", "55a1a760df4b86a02094a904dfa511deb5655905"),
+ new Tuple("refs/tags/commit_tree", "8f50ba15d49353813cc6e20298002c0d17b0a9ee"),
+ new Tuple("refs/tags/nearly-dangling", "6e0c7bdb9b4ed93212491ee778ca1c65047cab4e"),
+ };
+ }
+}
diff --git a/LibGit2Sharp/Core/GitRemoteHead.cs b/LibGit2Sharp/Core/GitRemoteHead.cs
new file mode 100644
index 000000000..2c6bce911
--- /dev/null
+++ b/LibGit2Sharp/Core/GitRemoteHead.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace LibGit2Sharp.Core
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct GitRemoteHead
+ {
+ public bool Local;
+ public GitOid Oid;
+ public GitOid Loid;
+ public IntPtr NamePtr;
+ }
+}
diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs
index 8503a9a77..0cbb9efef 100644
--- a/LibGit2Sharp/Core/NativeMethods.cs
+++ b/LibGit2Sharp/Core/NativeMethods.cs
@@ -690,6 +690,11 @@ internal static extern void git_remote_set_cred_acquire_cb(
[DllImport(libgit2)]
internal static extern void git_remote_disconnect(RemoteSafeHandle remote);
+ [DllImport(libgit2)]
+ internal static extern int git_remote_ls(RemoteSafeHandle remote, git_headlist_cb headlist_cb, IntPtr payload);
+
+ internal delegate int git_headlist_cb(ref GitRemoteHead remoteHeadPtr, IntPtr payload);
+
[DllImport(libgit2)]
internal static extern int git_remote_download(
RemoteSafeHandle remote,
diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs
index 3b4135ccd..f779be35a 100644
--- a/LibGit2Sharp/Core/Proxy.cs
+++ b/LibGit2Sharp/Core/Proxy.cs
@@ -1270,6 +1270,15 @@ public static IList git_remote_list(RepositorySafeHandle repo)
}
}
+ public static void git_remote_ls(RemoteSafeHandle remote, NativeMethods.git_headlist_cb headlist_cb)
+ {
+ using (ThreadAffinity())
+ {
+ int res = NativeMethods.git_remote_ls(remote, headlist_cb, IntPtr.Zero);
+ Ensure.ZeroResult(res);
+ }
+ }
+
public static RemoteSafeHandle git_remote_load(RepositorySafeHandle repo, string name, bool throwsIfNotFound)
{
using (ThreadAffinity())
diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj
index c3fec4418..2beac8b88 100644
--- a/LibGit2Sharp/LibGit2Sharp.csproj
+++ b/LibGit2Sharp/LibGit2Sharp.csproj
@@ -66,6 +66,7 @@
+
diff --git a/LibGit2Sharp/Network.cs b/LibGit2Sharp/Network.cs
index 97afce0ab..9915491bc 100644
--- a/LibGit2Sharp/Network.cs
+++ b/LibGit2Sharp/Network.cs
@@ -52,6 +52,43 @@ public virtual RemoteCollection Remotes
get { return remotes.Value; }
}
+ ///
+ /// List references in a repository.
+ ///
+ /// The to list from.
+ /// The references in the repository.
+ public virtual IEnumerable ListReferences(Remote remote)
+ {
+ Ensure.ArgumentNotNull(remote, "remote");
+
+ List directReferences = new List();
+ using (RemoteSafeHandle remoteHandle = Proxy.git_remote_load(repository.Handle, remote.Name, true))
+ {
+ Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch);
+
+ NativeMethods.git_headlist_cb cb = (ref GitRemoteHead remoteHead, IntPtr payload) =>
+ {
+ // The name pointer should never be null - if it is,
+ // this indicates a bug somewhere (libgit2, server, etc).
+ if (remoteHead.NamePtr == IntPtr.Zero)
+ {
+ Proxy.giterr_set_str(GitErrorCategory.Invalid, "Not expecting null value for reference name.");
+ return -1;
+ }
+
+ ObjectId oid = new ObjectId(remoteHead.Oid);
+ string name = Utf8Marshaler.FromNative(remoteHead.NamePtr);
+ directReferences.Add(new DirectReference(name, this.repository, oid));
+
+ return 0;
+ };
+
+ Proxy.git_remote_ls(remoteHandle, cb);
+ }
+
+ return directReferences;
+ }
+
///
/// Push the objectish to the destination reference on the .
///