Skip to content

Commit a6ef2ac

Browse files
committed
Functionality to correctly handle Symbolic References
returned by remote ls
1 parent a07186e commit a6ef2ac

File tree

6 files changed

+75
-34
lines changed

6 files changed

+75
-34
lines changed

LibGit2Sharp.Tests/NetworkFixture.cs

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,22 @@ public void CanListRemoteReferences(string url)
2222
using (var repo = new Repository(repoPath))
2323
{
2424
Remote remote = repo.Network.Remotes.Add(remoteName, url);
25-
IList<DirectReference> references = repo.Network.ListReferences(remote).ToList();
25+
IList<Reference> references = repo.Network.ListReferences(remote).ToList();
2626

27-
foreach (var directReference in references)
27+
28+
foreach (var reference in references)
2829
{
2930
// None of those references point to an existing
3031
// object in this brand new repository
31-
Assert.Null(directReference.Target);
32+
Assert.Null(reference.ResolveToDirectReference().Target);
3233
}
3334

3435
List<Tuple<string, string>> actualRefs = references.
35-
Select(directRef => new Tuple<string, string>(directRef.CanonicalName, directRef.TargetIdentifier)).ToList();
36+
Select(directRef => new Tuple<string, string>(directRef.CanonicalName, directRef.ResolveToDirectReference()
37+
.TargetIdentifier)).ToList();
3638

3739
Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs.Count, actualRefs.Count);
40+
Assert.True(references.Single(reference => reference.CanonicalName == "HEAD") is SymbolicReference);
3841
for (int i = 0; i < TestRemoteRefs.ExpectedRemoteRefs.Count; i++)
3942
{
4043
Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs[i].Item2, actualRefs[i].Item2);
@@ -53,19 +56,21 @@ public void CanListRemoteReferencesFromUrl(string url)
5356

5457
using (var repo = new Repository(repoPath))
5558
{
56-
IList<DirectReference> references = repo.Network.ListReferences(url).ToList();
59+
IList<Reference> references = repo.Network.ListReferences(url).ToList();
5760

58-
foreach (var directReference in references)
61+
foreach (var reference in references)
5962
{
6063
// None of those references point to an existing
6164
// object in this brand new repository
62-
Assert.Null(directReference.Target);
65+
Assert.Null(reference.ResolveToDirectReference().Target);
6366
}
6467

6568
List<Tuple<string, string>> actualRefs = references.
66-
Select(directRef => new Tuple<string, string>(directRef.CanonicalName, directRef.TargetIdentifier)).ToList();
69+
Select(directRef => new Tuple<string, string>(directRef.CanonicalName, directRef.ResolveToDirectReference()
70+
.TargetIdentifier)).ToList();
6771

6872
Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs.Count, actualRefs.Count);
73+
Assert.True(references.Single(reference => reference.CanonicalName == "HEAD") is SymbolicReference);
6974
for (int i = 0; i < TestRemoteRefs.ExpectedRemoteRefs.Count; i++)
7075
{
7176
Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs[i].Item2, actualRefs[i].Item2);
@@ -87,18 +92,22 @@ public void CanListRemoteReferenceObjects()
8792
using (var repo = new Repository(clonedRepoPath))
8893
{
8994
Remote remote = repo.Network.Remotes[remoteName];
90-
IEnumerable<DirectReference> references = repo.Network.ListReferences(remote);
95+
IEnumerable<Reference> references = repo.Network.ListReferences(remote).ToList();
9196

9297
var actualRefs = new List<Tuple<string,string>>();
9398

94-
foreach(DirectReference reference in references)
99+
foreach(Reference reference in references)
95100
{
96101
Assert.NotNull(reference.CanonicalName);
97-
Assert.NotNull(reference.Target);
98-
actualRefs.Add(new Tuple<string, string>(reference.CanonicalName, reference.Target.Id.Sha));
102+
103+
var directReference = reference.ResolveToDirectReference();
104+
105+
Assert.NotNull(directReference.Target);
106+
actualRefs.Add(new Tuple<string, string>(reference.CanonicalName, directReference.Target.Id.Sha));
99107
}
100108

101109
Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs.Count, actualRefs.Count);
110+
Assert.True(references.Single(reference => reference.CanonicalName == "HEAD") is SymbolicReference);
102111
for (int i = 0; i < TestRemoteRefs.ExpectedRemoteRefs.Count; i++)
103112
{
104113
Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs[i].Item1, actualRefs[i].Item1);
@@ -123,9 +132,9 @@ public void CanListRemoteReferencesWithCredentials()
123132

124133
var references = repo.Network.ListReferences(remote, Constants.PrivateRepoCredentials);
125134

126-
foreach (var directReference in references)
135+
foreach (var reference in references)
127136
{
128-
Assert.NotNull(directReference);
137+
Assert.NotNull(reference);
129138
}
130139
}
131140
}

LibGit2Sharp.Tests/PushFixture.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,9 @@ public void CanForcePush()
199199
private static void AssertRemoteHeadTipEquals(IRepository localRepo, string sha)
200200
{
201201
var remoteReferences = localRepo.Network.ListReferences(localRepo.Network.Remotes.Single());
202-
DirectReference remoteHead = remoteReferences.Single(r => r.CanonicalName == "HEAD");
202+
Reference remoteHead = remoteReferences.Single(r => r.CanonicalName == "HEAD");
203203

204-
Assert.Equal(sha, remoteHead.TargetIdentifier);
204+
Assert.Equal(sha, remoteHead.ResolveToDirectReference().TargetIdentifier);
205205
}
206206

207207
private void UpdateTheRemoteRepositoryWithANewCommit(string remoteRepoPath)

LibGit2Sharp.Tests/RepositoryFixture.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ public void CanListRemoteReferencesWithCredentials()
659659
InconclusiveIf(() => string.IsNullOrEmpty(Constants.PrivateRepoUrl),
660660
"Populate Constants.PrivateRepo* to run this test");
661661

662-
IEnumerable<DirectReference> references = Repository.ListRemoteReferences(Constants.PrivateRepoUrl,
662+
IEnumerable<Reference> references = Repository.ListRemoteReferences(Constants.PrivateRepoUrl,
663663
Constants.PrivateRepoCredentials);
664664

665665
foreach (var reference in references)
@@ -674,12 +674,13 @@ public void CanListRemoteReferencesWithCredentials()
674674
[InlineData("git://github.com/libgit2/TestGitRepository.git")]
675675
public void CanListRemoteReferences(string url)
676676
{
677-
IEnumerable<DirectReference> references = Repository.ListRemoteReferences(url);
677+
IEnumerable<Reference> references = Repository.ListRemoteReferences(url).ToList();
678678

679679
List<Tuple<string, string>> actualRefs = references.
680-
Select(directRef => new Tuple<string, string>(directRef.CanonicalName, directRef.TargetIdentifier)).ToList();
680+
Select(reference => new Tuple<string, string>(reference.CanonicalName, reference.ResolveToDirectReference().TargetIdentifier)).ToList();
681681

682682
Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs.Count, actualRefs.Count);
683+
Assert.True(references.Single(reference => reference.CanonicalName == "HEAD") is SymbolicReference);
683684
for (int i = 0; i < TestRemoteRefs.ExpectedRemoteRefs.Count; i++)
684685
{
685686
Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs[i].Item2, actualRefs[i].Item2);
@@ -691,7 +692,7 @@ public void CanListRemoteReferences(string url)
691692
[InlineData("http://github.com/libgit2/TestGitRepository")]
692693
public void ReadingReferenceRepositoryThroughListRemoteReferencesThrows(string url)
693694
{
694-
IEnumerable<DirectReference> references = Repository.ListRemoteReferences(url);
695+
IEnumerable<Reference> references = Repository.ListRemoteReferences(url);
695696

696697
foreach (var reference in references)
697698
{
@@ -704,11 +705,14 @@ public void ReadingReferenceRepositoryThroughListRemoteReferencesThrows(string u
704705
[InlineData("http://github.com/libgit2/TestGitRepository")]
705706
public void ReadingReferenceTargetFromListRemoteReferencesThrows(string url)
706707
{
707-
IEnumerable<DirectReference> references = Repository.ListRemoteReferences(url);
708+
IEnumerable<Reference> references = Repository.ListRemoteReferences(url);
708709

709710
foreach (var reference in references)
710711
{
711-
Assert.Throws<InvalidOperationException>(() => reference.Target);
712+
Assert.Throws<InvalidOperationException>(() =>
713+
{
714+
var target = reference.ResolveToDirectReference().Target;
715+
});
712716
}
713717
}
714718
}

LibGit2Sharp/Core/Proxy.cs

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2127,7 +2127,7 @@ public static IList<string> git_remote_list(RepositorySafeHandle repo)
21272127
}
21282128
}
21292129

2130-
public static IEnumerable<DirectReference> git_remote_ls(Repository repository, RemoteSafeHandle remote)
2130+
public static IEnumerable<Reference> git_remote_ls(Repository repository, RemoteSafeHandle remote)
21312131
{
21322132
IntPtr heads;
21332133
UIntPtr count;
@@ -2142,26 +2142,54 @@ public static IEnumerable<DirectReference> git_remote_ls(Repository repository,
21422142
throw new OverflowException();
21432143
}
21442144

2145-
var refs = new List<DirectReference>();
2145+
var directRefs = new Dictionary<string, Reference>();
2146+
var symRefs = new Dictionary<string, string>();
2147+
21462148
IntPtr currentHead = heads;
21472149

21482150
for (int i = 0; i < intCount; i++)
21492151
{
21502152
var remoteHead = Marshal.ReadIntPtr(currentHead).MarshalAs<GitRemoteHead>();
21512153

2154+
string name = LaxUtf8Marshaler.FromNative(remoteHead.NamePtr);
2155+
string symRefTarget = LaxUtf8Marshaler.FromNative(remoteHead.SymRefTargetPtr);
2156+
21522157
// The name pointer should never be null - if it is,
21532158
// this indicates a bug somewhere (libgit2, server, etc).
2154-
if (remoteHead.NamePtr == IntPtr.Zero)
2159+
if (string.IsNullOrEmpty(name))
21552160
{
21562161
throw new InvalidOperationException("Not expecting null value for reference name.");
21572162
}
21582163

2159-
string name = LaxUtf8Marshaler.FromNative(remoteHead.NamePtr);
2160-
refs.Add(new DirectReference(name, repository, remoteHead.Oid));
2164+
if (!string.IsNullOrEmpty(symRefTarget))
2165+
{
2166+
symRefs.Add(name, symRefTarget);
2167+
}
2168+
else
2169+
{
2170+
directRefs.Add(name, new DirectReference(name, repository, remoteHead.Oid));
2171+
}
21612172

21622173
currentHead = IntPtr.Add(currentHead, IntPtr.Size);
21632174
}
21642175

2176+
while (symRefs.Count > 0)
2177+
{
2178+
var symRef = symRefs.First();
2179+
2180+
if (!directRefs.ContainsKey(symRef.Value))
2181+
{
2182+
throw new InvalidOperationException("Symbolic reference target not found in direct reference results.");
2183+
}
2184+
2185+
directRefs.Add(symRef.Key, new SymbolicReference(repository, symRef.Key, symRef.Value, directRefs[symRef.Value]));
2186+
2187+
symRefs.Remove(symRef.Key);
2188+
}
2189+
2190+
var refs = directRefs.Values.ToList();
2191+
refs.Sort((r1, r2) => String.CompareOrdinal(r1.CanonicalName, r2.CanonicalName));
2192+
21652193
return refs;
21662194
}
21672195

LibGit2Sharp/Network.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public virtual RemoteCollection Remotes
4848
/// </summary>
4949
/// <param name="remote">The <see cref="Remote"/> to list from.</param>
5050
/// <returns>The references in the <see cref="Remote"/> repository.</returns>
51-
public virtual IEnumerable<DirectReference> ListReferences(Remote remote)
51+
public virtual IEnumerable<Reference> ListReferences(Remote remote)
5252
{
5353
Ensure.ArgumentNotNull(remote, "remote");
5454

@@ -67,7 +67,7 @@ public virtual IEnumerable<DirectReference> ListReferences(Remote remote)
6767
/// <param name="remote">The <see cref="Remote"/> to list from.</param>
6868
/// <param name="credentialsProvider">The <see cref="Func{Credentials}"/> used to connect to remote repository.</param>
6969
/// <returns>The references in the <see cref="Remote"/> repository.</returns>
70-
public virtual IEnumerable<DirectReference> ListReferences(Remote remote, CredentialsHandler credentialsProvider)
70+
public virtual IEnumerable<Reference> ListReferences(Remote remote, CredentialsHandler credentialsProvider)
7171
{
7272
Ensure.ArgumentNotNull(remote, "remote");
7373
Ensure.ArgumentNotNull(credentialsProvider, "credentialsProvider");
@@ -86,7 +86,7 @@ public virtual IEnumerable<DirectReference> ListReferences(Remote remote, Creden
8686
/// </summary>
8787
/// <param name="url">The url to list from.</param>
8888
/// <returns>The references in the remote repository.</returns>
89-
public virtual IEnumerable<DirectReference> ListReferences(string url)
89+
public virtual IEnumerable<Reference> ListReferences(string url)
9090
{
9191
Ensure.ArgumentNotNull(url, "url");
9292

@@ -105,15 +105,15 @@ public virtual IEnumerable<DirectReference> ListReferences(string url)
105105
/// <param name="url">The url to list from.</param>
106106
/// <param name="credentialsProvider">The <see cref="Func{Credentials}"/> used to connect to remote repository.</param>
107107
/// <returns>The references in the remote repository.</returns>
108-
public virtual IEnumerable<DirectReference> ListReferences(string url, CredentialsHandler credentialsProvider)
108+
public virtual IEnumerable<Reference> ListReferences(string url, CredentialsHandler credentialsProvider)
109109
{
110110
Ensure.ArgumentNotNull(url, "url");
111111
Ensure.ArgumentNotNull(credentialsProvider, "credentialsProvider");
112112

113113
return ListReferencesInternal(url, credentialsProvider);
114114
}
115115

116-
private IEnumerable<DirectReference> ListReferencesInternal(string url, CredentialsHandler credentialsProvider)
116+
private IEnumerable<Reference> ListReferencesInternal(string url, CredentialsHandler credentialsProvider)
117117
{
118118
using (RemoteSafeHandle remoteHandle = BuildRemoteSafeHandle(repository.Handle, url))
119119
{

LibGit2Sharp/Repository.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ internal Commit LookupCommit(string committish)
568568
/// </para>
569569
/// <param name="url">The url to list from.</param>
570570
/// <returns>The references in the remote repository.</returns>
571-
public static IEnumerable<DirectReference> ListRemoteReferences(string url)
571+
public static IEnumerable<Reference> ListRemoteReferences(string url)
572572
{
573573
return ListRemoteReferences(url, null);
574574
}
@@ -584,7 +584,7 @@ public static IEnumerable<DirectReference> ListRemoteReferences(string url)
584584
/// <param name="url">The url to list from.</param>
585585
/// <param name="credentialsProvider">The <see cref="Func{Credentials}"/> used to connect to remote repository.</param>
586586
/// <returns>The references in the remote repository.</returns>
587-
public static IEnumerable<DirectReference> ListRemoteReferences(string url, CredentialsHandler credentialsProvider)
587+
public static IEnumerable<Reference> ListRemoteReferences(string url, CredentialsHandler credentialsProvider)
588588
{
589589
Ensure.ArgumentNotNull(url, "url");
590590

0 commit comments

Comments
 (0)