Skip to content

Commit 21c0c15

Browse files
author
Edward Thomson
committed
Merge pull request libgit2#1288 from libgit2/cmn/pull-command
Make Pull and Fetch commands
2 parents 89ce631 + 6f0230d commit 21c0c15

File tree

9 files changed

+183
-144
lines changed

9 files changed

+183
-144
lines changed

LibGit2Sharp.Tests/FetchFixture.cs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public void CanFetchIntoAnEmptyRepository(string url)
2222

2323
using (var repo = new Repository(path))
2424
{
25-
Remote remote = repo.Network.Remotes.Add(remoteName, url);
25+
repo.Network.Remotes.Add(remoteName, url);
2626

2727
// Set up structures for the expected results
2828
// and verifying the RemoteUpdateTips callback.
@@ -44,7 +44,7 @@ public void CanFetchIntoAnEmptyRepository(string url)
4444
}
4545

4646
// Perform the actual fetch
47-
repo.Network.Fetch(remote, new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler });
47+
Commands.Fetch(repo, remoteName, new string[0], new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler }, null);
4848

4949
// Verify the expected
5050
expectedFetchState.CheckUpdatedReferences(repo);
@@ -61,13 +61,13 @@ public void CanFetchIntoAnEmptyRepositoryWithCredentials()
6161

6262
using (var repo = new Repository(path))
6363
{
64-
Remote remote = repo.Network.Remotes.Add(remoteName, Constants.PrivateRepoUrl);
64+
repo.Network.Remotes.Add(remoteName, Constants.PrivateRepoUrl);
6565

6666
// Perform the actual fetch
67-
repo.Network.Fetch(remote, new FetchOptions
67+
Commands.Fetch(repo, remoteName, new string[0], new FetchOptions
6868
{
6969
CredentialsProvider = Constants.PrivateRepoCredentials
70-
});
70+
}, null);
7171
}
7272
}
7373

@@ -81,7 +81,7 @@ public void CanFetchAllTagsIntoAnEmptyRepository(string url)
8181

8282
using (var repo = new Repository(path))
8383
{
84-
Remote remote = repo.Network.Remotes.Add(remoteName, url);
84+
repo.Network.Remotes.Add(remoteName, url);
8585

8686
// Set up structures for the expected results
8787
// and verifying the RemoteUpdateTips callback.
@@ -101,10 +101,10 @@ public void CanFetchAllTagsIntoAnEmptyRepository(string url)
101101
}
102102

103103
// Perform the actual fetch
104-
repo.Network.Fetch(remote, new FetchOptions {
104+
Commands.Fetch(repo, remoteName, new string[0], new FetchOptions {
105105
TagFetchMode = TagFetchMode.All,
106106
OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler
107-
});
107+
}, null);
108108

109109
// Verify the expected
110110
expectedFetchState.CheckUpdatedReferences(repo);
@@ -124,7 +124,7 @@ public void CanFetchCustomRefSpecsIntoAnEmptyRepository(string url, string local
124124

125125
using (var repo = new Repository(path))
126126
{
127-
Remote remote = repo.Network.Remotes.Add(remoteName, url);
127+
repo.Network.Remotes.Add(remoteName, url);
128128

129129
string refSpec = string.Format("refs/heads/{2}:refs/remotes/{0}/{1}", remoteName, localBranchName, remoteBranchName);
130130

@@ -147,10 +147,10 @@ public void CanFetchCustomRefSpecsIntoAnEmptyRepository(string url, string local
147147
}
148148

149149
// Perform the actual fetch
150-
repo.Network.Fetch(remote, new string[] { refSpec }, new FetchOptions {
150+
Commands.Fetch(repo, remoteName, new string[] { refSpec }, new FetchOptions {
151151
TagFetchMode = TagFetchMode.None,
152152
OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler
153-
});
153+
}, null);
154154

155155
// Verify the expected
156156
expectedFetchState.CheckUpdatedReferences(repo);
@@ -181,7 +181,7 @@ public void FetchRespectsConfiguredAutoTagSetting(TagFetchMode tagFetchMode, int
181181
r => r.TagFetchMode = tagFetchMode);
182182

183183
// Perform the actual fetch.
184-
repo.Network.Fetch(remote);
184+
Commands.Fetch(repo, remoteName, new string[0], null, null);
185185

186186
// Verify the number of fetched tags.
187187
Assert.Equal(expectedTagCount, repo.Tags.Count());
@@ -199,7 +199,7 @@ public void CanFetchAllTagsAfterAnInitialClone()
199199

200200
using (var repo = new Repository(clonedRepoPath))
201201
{
202-
repo.Fetch("origin", new FetchOptions { TagFetchMode = TagFetchMode.All });
202+
Commands.Fetch(repo, "origin", new string[0], new FetchOptions { TagFetchMode = TagFetchMode.All }, null);
203203
}
204204
}
205205

@@ -225,17 +225,17 @@ public void FetchHonorsTheFetchPruneConfigurationEntry()
225225

226226
// No pruning when the configuration entry isn't defined
227227
Assert.Null(clonedRepo.Config.Get<bool>("fetch.prune"));
228-
clonedRepo.Fetch("origin");
228+
Commands.Fetch(clonedRepo, "origin", new string[0], null, null);
229229
Assert.Equal(5, clonedRepo.Branches.Count(b => b.IsRemote));
230230

231231
// No pruning when the configuration entry is set to false
232232
clonedRepo.Config.Set<bool>("fetch.prune", false);
233-
clonedRepo.Fetch("origin");
233+
Commands.Fetch(clonedRepo, "origin", new string[0], null, null);
234234
Assert.Equal(5, clonedRepo.Branches.Count(b => b.IsRemote));
235235

236236
// Auto pruning when the configuration entry is set to true
237237
clonedRepo.Config.Set<bool>("fetch.prune", true);
238-
clonedRepo.Fetch("origin");
238+
Commands.Fetch(clonedRepo, "origin", new string[0], null, null);
239239
Assert.Equal(4, clonedRepo.Branches.Count(b => b.IsRemote));
240240
}
241241
}

LibGit2Sharp.Tests/NetworkFixture.cs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ public void CanPull(FastForwardStrategy fastForwardStrategy)
164164
}
165165
};
166166

167-
MergeResult mergeResult = repo.Network.Pull(Constants.Signature, pullOptions);
167+
MergeResult mergeResult = Commands.Pull(repo, Constants.Signature, pullOptions);
168168

169169
if(fastForwardStrategy == FastForwardStrategy.Default || fastForwardStrategy == FastForwardStrategy.FastForwardOnly)
170170
{
@@ -197,7 +197,7 @@ public void CanPullIntoEmptyRepo()
197197
b => b.UpstreamBranch = "refs/heads/master");
198198

199199
// Pull!
200-
MergeResult mergeResult = repo.Network.Pull(Constants.Signature, new PullOptions());
200+
MergeResult mergeResult = Commands.Pull(repo, Constants.Signature, new PullOptions());
201201

202202
Assert.Equal(mergeResult.Status, MergeStatus.FastForward);
203203
Assert.Equal(mergeResult.Commit, repo.Branches["refs/remotes/origin/master"].Tip);
@@ -224,7 +224,7 @@ public void PullWithoutMergeBranchThrows()
224224

225225
try
226226
{
227-
repo.Network.Pull(Constants.Signature, new PullOptions());
227+
Commands.Pull(repo, Constants.Signature, new PullOptions());
228228
}
229229
catch(MergeFetchHeadNotFoundException ex)
230230
{
@@ -252,10 +252,7 @@ public void CanMergeFetchedRefs()
252252
Assert.False(repo.RetrieveStatus().Any());
253253
Assert.Equal(repo.Lookup<Commit>("refs/remotes/origin/master~1"), repo.Head.Tip);
254254

255-
using (var remote = repo.Network.Remotes[repo.Head.RemoteName])
256-
{
257-
repo.Network.Fetch(remote);
258-
}
255+
Commands.Fetch(repo, repo.Head.RemoteName, new string[0], null, null);
259256

260257
MergeOptions mergeOptions = new MergeOptions()
261258
{
@@ -282,8 +279,7 @@ public void CanPruneRefs()
282279
using (var repo = new Repository(clonedRepoPath))
283280
{
284281
repo.Network.Remotes.Add("pruner", clonedRepoPath2);
285-
var remote = repo.Network.Remotes["pruner"];
286-
repo.Network.Fetch(remote);
282+
Commands.Fetch(repo, "pruner", new string[0], null, null);
287283
Assert.NotNull(repo.Refs["refs/remotes/pruner/master"]);
288284

289285
// Remove the branch from the source repository
@@ -293,11 +289,11 @@ public void CanPruneRefs()
293289
}
294290

295291
// and by default we don't prune it
296-
repo.Network.Fetch(remote);
292+
Commands.Fetch(repo, "pruner", new string[0], null, null);
297293
Assert.NotNull(repo.Refs["refs/remotes/pruner/master"]);
298294

299295
// but we do when asked by the user
300-
repo.Network.Fetch(remote, new FetchOptions { Prune = true} );
296+
Commands.Fetch(repo, "pruner", new string[0], new FetchOptions { Prune = true}, null);
301297
Assert.Null(repo.Refs["refs/remotes/pruner/master"]);
302298
}
303299
}

LibGit2Sharp.Tests/RepositoryFixture.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ public void CanFetchFromRemoteByName()
181181

182182
using (var repo = new Repository(repoPath))
183183
{
184-
Remote remote = repo.Network.Remotes.Add(remoteName, url);
184+
repo.Network.Remotes.Add(remoteName, url);
185185

186186
// We will first fetch without specifying any Tag options.
187187
// After we verify this fetch, we will perform a second fetch
@@ -208,13 +208,13 @@ public void CanFetchFromRemoteByName()
208208
}
209209

210210
// Perform the actual fetch
211-
repo.Fetch(remote.Name, new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler });
211+
Commands.Fetch(repo, remoteName, new string[0], new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler }, null);
212212

213213
// Verify the expected state
214214
expectedFetchState.CheckUpdatedReferences(repo);
215215

216216
// Now fetch the rest of the tags
217-
repo.Fetch(remote.Name, new FetchOptions { TagFetchMode = TagFetchMode.All });
217+
Commands.Fetch(repo, remoteName, new string[0], new FetchOptions { TagFetchMode = TagFetchMode.All }, null);
218218

219219
// Verify that the "nearly-dangling" tag is now in the repo.
220220
Tag nearlyDanglingTag = repo.Tags["nearly-dangling"];

LibGit2Sharp.Tests/SmartSubtransportFixture.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public void CustomSmartSubtransportTest(string scheme, string url)
4141

4242
using (var repo = new Repository(repoPath))
4343
{
44-
Remote remote = repo.Network.Remotes.Add(remoteName, url);
44+
repo.Network.Remotes.Add(remoteName, url);
4545

4646
// Set up structures for the expected results
4747
// and verifying the RemoteUpdateTips callback.
@@ -63,7 +63,9 @@ public void CustomSmartSubtransportTest(string scheme, string url)
6363
}
6464

6565
// Perform the actual fetch
66-
repo.Network.Fetch(remote, new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler, TagFetchMode = TagFetchMode.Auto });
66+
Commands.Fetch(repo, remoteName, new string[0],
67+
new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler, TagFetchMode = TagFetchMode.Auto },
68+
null);
6769

6870
// Verify the expected
6971
expectedFetchState.CheckUpdatedReferences(repo);
@@ -99,7 +101,7 @@ public void CanUseCredentials(string scheme, string url, string user, string pas
99101

100102
using (var repo = new Repository(scd.DirectoryPath))
101103
{
102-
Remote remote = repo.Network.Remotes.Add(remoteName, url);
104+
repo.Network.Remotes.Add(remoteName, url);
103105

104106
// Set up structures for the expected results
105107
// and verifying the RemoteUpdateTips callback.
@@ -113,9 +115,10 @@ public void CanUseCredentials(string scheme, string url, string user, string pas
113115
}
114116

115117
// Perform the actual fetch
116-
repo.Network.Fetch(remote, new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler, TagFetchMode = TagFetchMode.Auto,
118+
Commands.Fetch(repo, remoteName, new string[0], new FetchOptions {
119+
OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler, TagFetchMode = TagFetchMode.Auto,
117120
CredentialsProvider = (_user, _valid, _hostname) => new UsernamePasswordCredentials() { Username = "libgit3", Password = "libgit3" },
118-
});
121+
}, null);
119122

120123
// Verify the expected
121124
expectedFetchState.CheckUpdatedReferences(repo);

LibGit2Sharp/Commands/Fetch.cs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using System.Collections.Generic;
2+
using LibGit2Sharp;
3+
using LibGit2Sharp.Core;
4+
using LibGit2Sharp.Core.Handles;
5+
6+
namespace LibGit2Sharp
7+
{
8+
/// <summary>
9+
/// Class to serve as namespacing for the command-emulating methods
10+
/// </summary>
11+
public static partial class Commands
12+
{
13+
private static RemoteHandle RemoteFromNameOrUrl(RepositoryHandle repoHandle, string remote)
14+
{
15+
RemoteHandle handle = null;
16+
handle = Proxy.git_remote_lookup(repoHandle, remote, false);
17+
18+
// If that wasn't the name of a remote, let's use it as a url
19+
if (handle == null)
20+
{
21+
handle = Proxy.git_remote_create_anonymous(repoHandle, remote);
22+
}
23+
24+
return handle;
25+
}
26+
27+
/// <summary>
28+
/// Perform a fetch
29+
/// </summary>
30+
/// <param name="repository">The repository in which to fetch.</param>
31+
/// <param name="remote">The remote to fetch from. Either as a remote name or a URL</param>
32+
/// <param name="options">Fetch options.</param>
33+
/// <param name="logMessage">Log message for any ref updates.</param>
34+
/// <param name="refspecs">List of refspecs to apply as active.</param>
35+
public static void Fetch(Repository repository, string remote, IEnumerable<string> refspecs, FetchOptions options, string logMessage)
36+
{
37+
Ensure.ArgumentNotNull(remote, "remote");
38+
39+
options = options ?? new FetchOptions();
40+
using (var remoteHandle = RemoteFromNameOrUrl(repository.Handle, remote))
41+
{
42+
43+
var callbacks = new RemoteCallbacks(options);
44+
GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks();
45+
46+
// It is OK to pass the reference to the GitCallbacks directly here because libgit2 makes a copy of
47+
// the data in the git_remote_callbacks structure. If, in the future, libgit2 changes its implementation
48+
// to store a reference to the git_remote_callbacks structure this would introduce a subtle bug
49+
// where the managed layer could move the git_remote_callbacks to a different location in memory,
50+
// but libgit2 would still reference the old address.
51+
//
52+
// Also, if GitRemoteCallbacks were a class instead of a struct, we would need to guard against
53+
// GC occuring in between setting the remote callbacks and actual usage in one of the functions afterwords.
54+
var fetchOptions = new GitFetchOptions
55+
{
56+
RemoteCallbacks = gitCallbacks,
57+
download_tags = Proxy.git_remote_autotag(remoteHandle),
58+
};
59+
60+
if (options.TagFetchMode.HasValue)
61+
{
62+
fetchOptions.download_tags = options.TagFetchMode.Value;
63+
}
64+
65+
if (options.Prune.HasValue)
66+
{
67+
fetchOptions.Prune = options.Prune.Value ? FetchPruneStrategy.Prune : FetchPruneStrategy.NoPrune;
68+
}
69+
else
70+
{
71+
fetchOptions.Prune = FetchPruneStrategy.FromConfigurationOrDefault;
72+
}
73+
74+
Proxy.git_remote_fetch(remoteHandle, refspecs, fetchOptions, logMessage);
75+
}
76+
77+
}
78+
}
79+
}
80+

LibGit2Sharp/Commands/Pull.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System;
2+
using LibGit2Sharp;
3+
using LibGit2Sharp.Core;
4+
5+
namespace LibGit2Sharp
6+
{
7+
/// <summary>
8+
/// Fetch changes from the configured upstream remote and branch into the branch pointed at by HEAD.
9+
/// </summary>
10+
public static partial class Commands
11+
{
12+
/// <summary>
13+
/// Fetch changes from the configured upstream remote and branch into the branch pointed at by HEAD.
14+
/// </summary>
15+
/// <param name="repository">The repository.</param>
16+
/// <param name="merger">The signature to use for the merge.</param>
17+
/// <param name="options">The options for fetch and merging.</param>
18+
public static MergeResult Pull(Repository repository, Signature merger, PullOptions options)
19+
{
20+
Ensure.ArgumentNotNull(repository, "repository");
21+
Ensure.ArgumentNotNull(merger, "merger");
22+
Ensure.ArgumentNotNull(options, "options");
23+
24+
25+
options = options ?? new PullOptions();
26+
Branch currentBranch = repository.Head;
27+
28+
if (!currentBranch.IsTracking)
29+
{
30+
throw new LibGit2SharpException("There is no tracking information for the current branch.");
31+
}
32+
33+
if (currentBranch.RemoteName == null)
34+
{
35+
throw new LibGit2SharpException("No upstream remote for the current branch.");
36+
}
37+
38+
Commands.Fetch(repository, currentBranch.RemoteName, new string[0], options.FetchOptions, null);
39+
return repository.MergeFetchedRefs(merger, options.MergeOptions);
40+
}
41+
}
42+
}
43+

LibGit2Sharp/LibGit2Sharp.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,8 @@
350350
<Compile Include="Core\Handles\Libgit2Object.cs" />
351351
<Compile Include="Core\GitCredential.cs" />
352352
<Compile Include="Core\GitCredentialUserpass.cs" />
353+
<Compile Include="Commands\Pull.cs" />
354+
<Compile Include="Commands\Fetch.cs" />
353355
</ItemGroup>
354356
<ItemGroup>
355357
<CodeAnalysisDictionary Include="CustomDictionary.xml" />
@@ -386,4 +388,7 @@
386388
<Target Name="AfterBuild">
387389
</Target>
388390
-->
391+
<ItemGroup>
392+
<Folder Include="Commands\" />
393+
</ItemGroup>
389394
</Project>

0 commit comments

Comments
 (0)