Skip to content

Commit d4b2fb7

Browse files
committed
Teach Branch to get a remote-tracking branch's remote.
The logic to get the remote of a tracked branch has more failure cases then getting the configured remote for a local branch. This functionality should be in its own function and return exceptions.
1 parent 329c652 commit d4b2fb7

File tree

3 files changed

+108
-13
lines changed

3 files changed

+108
-13
lines changed

LibGit2Sharp.Tests/BranchFixture.cs

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,72 @@ public void QueryUpstreamBranchCanonicalNameForLocalTrackingBranch()
391391
}
392392
}
393393

394+
[Fact]
395+
public void CanGetRemoteForLocalBranch()
396+
{
397+
using (var repo = new Repository(StandardTestRepoPath))
398+
{
399+
Branch master = repo.Branches["master"];
400+
Assert.Equal(repo.Network.Remotes["origin"], master.GetTrackedRemote());
401+
}
402+
}
403+
404+
[Fact]
405+
public void CanGetRemoteForRemoteBranch()
406+
{
407+
using (var repo = new Repository(StandardTestRepoPath))
408+
{
409+
Branch master = repo.Branches["origin/master"];
410+
Assert.Equal(repo.Network.Remotes["origin"], master.GetTrackedRemote());
411+
}
412+
}
413+
414+
[Fact]
415+
public void GettingUnresolvableRemoteThrows()
416+
{
417+
var path = CloneStandardTestRepo();
418+
419+
var fetchRefSpecs = new string[] { "+refs/heads/notfound/*:refs/remotes/origin/notfound/*" };
420+
421+
using (var repo = InitIsolatedRepository(path))
422+
{
423+
// Update the remote config such that the remote for a
424+
// remote branch cannot be resolved
425+
Remote remote = repo.Network.Remotes["origin"];
426+
Assert.NotNull(remote);
427+
428+
repo.Network.Remotes.Update(remote, r => r.FetchRefSpecs = fetchRefSpecs);
429+
430+
Branch branch = repo.Branches["refs/remotes/origin/master"];
431+
432+
Assert.NotNull(branch);
433+
Assert.True(branch.IsRemote);
434+
435+
Assert.Throws<LibGit2SharpException>(() => branch.GetTrackedRemote());
436+
}
437+
}
438+
439+
[Fact]
440+
public void GettingAmbigousTrackedRemoteThrows()
441+
{
442+
var path = CloneStandardTestRepo();
443+
444+
var fetchRefSpec = "+refs/heads/*:refs/remotes/origin/*";
445+
var url = "http://github.com/libgit2/TestGitRepository";
446+
447+
using (var repo = InitIsolatedRepository(path))
448+
{
449+
repo.Network.Remotes.Add("ambiguous", url, fetchRefSpec);
450+
451+
Branch branch = repo.Branches["refs/remotes/origin/master"];
452+
453+
Assert.NotNull(branch);
454+
Assert.True(branch.IsRemote);
455+
456+
Assert.Throws<LibGit2SharpException>(() => branch.GetTrackedRemote());
457+
}
458+
}
459+
394460
[Fact]
395461
public void CanLookupABranchByItsCanonicalName()
396462
{
@@ -990,7 +1056,7 @@ public void RemoteBranchesDoNotTrackAnything()
9901056
foreach (var branch in branches)
9911057
{
9921058
Assert.True(branch.IsRemote);
993-
Assert.NotNull(branch.Remote);
1059+
Assert.Null(branch.Remote);
9941060
Assert.False(branch.IsTracking);
9951061
Assert.Null(branch.TrackedBranch);
9961062

LibGit2Sharp/Branch.cs

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -155,26 +155,48 @@ public virtual Remote Remote
155155
{
156156
get
157157
{
158-
string remoteName;
158+
string remoteName = null;
159159

160-
if (IsRemote)
161-
{
162-
remoteName = RemoteNameFromRemoteTrackingBranch();
163-
}
164-
else
160+
if (!IsRemote)
165161
{
166162
remoteName = RemoteNameFromLocalBranch();
163+
}
167164

168-
if (remoteName == null)
169-
{
170-
return null;
171-
}
165+
if (remoteName == null)
166+
{
167+
return null;
172168
}
173169

174170
return repo.Network.Remotes[remoteName];
175171
}
176172
}
177173

174+
/// <summary>
175+
/// Get the <see cref="Remote"/> of the branch that this branch tracks.
176+
/// <para>
177+
/// If this is a local branch, this will return the the configured
178+
/// <see cref="Remote"/> to fetch from and push to. If this is a
179+
/// remote-tracking branch, this will return the remote containing
180+
/// the tracked branch.
181+
/// </para>
182+
/// <para>
183+
/// This will throw an exception if there is an error resolving the
184+
/// remote for this branch. If this is a local only branch, then
185+
/// this will return null.
186+
/// </para>
187+
/// </summary>
188+
/// <returns>The remote of the tracked branch or null if this is a local branch.</returns>
189+
public virtual Remote GetTrackedRemote()
190+
{
191+
if (!IsRemote)
192+
{
193+
return this.Remote;
194+
}
195+
196+
var remoteName = RemoteNameFromRemoteTrackingBranch();
197+
return repo.Network.Remotes.RemoteForName(remoteName, true);
198+
}
199+
178200
private string UpstreamBranchCanonicalNameFromLocalBranch()
179201
{
180202
ConfigurationEntry<string> mergeRefEntry = repo.Config.Get<string>("branch", Name, "merge");

LibGit2Sharp/Core/Proxy.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,15 +203,22 @@ public static ReferenceSafeHandle git_branch_move(ReferenceSafeHandle reference,
203203
}
204204
}
205205

206+
/// <summary>
207+
/// Call into libgit2 to get the remote name that a remote tracking branch
208+
/// tracks. Throws an exception if the remote name cannot be resolved.
209+
/// </summary>
210+
/// <param name="repo"></param>
211+
/// <param name="canonical_branch_name"></param>
212+
/// <returns>The name of the remote that the branch tracks.</returns>
206213
public static string git_branch_remote_name(RepositorySafeHandle repo, string canonical_branch_name)
207214
{
208215
using (ThreadAffinity())
209216
using (var buf = new GitBuf())
210217
{
211218
int res = NativeMethods.git_branch_remote_name(buf, repo, canonical_branch_name);
212-
Ensure.Int32Result(res);
213219

214-
return LaxUtf8Marshaler.FromNative(buf.ptr) ?? string.Empty;
220+
Ensure.ZeroResult(res);
221+
return LaxUtf8Marshaler.FromNative(buf.ptr);
215222
}
216223
}
217224

0 commit comments

Comments
 (0)