Skip to content

Commit 62068d9

Browse files
committed
Fold RepositorExtensions into the type and interface
We should not have extensions on our own types. Either we accept these convenience overloads as part of our interfaces or we shouldn't have them. While here unseal Repository and split up these methods into a few different files grouping them by area.
1 parent 4f14bc3 commit 62068d9

9 files changed

Lines changed: 1660 additions & 1422 deletions

LibGit2Sharp/IRepository.cs

Lines changed: 288 additions & 0 deletions
Large diffs are not rendered by default.

LibGit2Sharp/LibGit2Sharp.csproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,6 @@
352352
<SubType>Code</SubType>
353353
</Compile>
354354
<Compile Include="RepositoryInformation.cs" />
355-
<Compile Include="RepositoryExtensions.cs" />
356355
<Compile Include="Core\Handles\RepositorySafeHandle.cs" />
357356
<Compile Include="RepositoryOptions.cs" />
358357
<Compile Include="RepositoryStatus.cs" />
@@ -388,6 +387,11 @@
388387
<Compile Include="IDiffResult.cs" />
389388
<Compile Include="Core\GitCredential.cs" />
390389
<Compile Include="Core\GitCredentialUserpass.cs" />
390+
<Compile Include="Repository.Lookup.cs" />
391+
<Compile Include="Repository.Checkout.cs" />
392+
<Compile Include="Repository.Branch.cs" />
393+
<Compile Include="Repository.Reset.cs" />
394+
<Compile Include="Repository.Workdir.cs" />
391395
</ItemGroup>
392396
<ItemGroup>
393397
<CodeAnalysisDictionary Include="CustomDictionary.xml" />

LibGit2Sharp/Repository.Branch.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System;
2+
3+
namespace LibGit2Sharp
4+
{
5+
public partial class Repository
6+
{
7+
/// <summary>
8+
/// Creates a branch with the specified name. This branch will point at the commit pointed at by the <see cref="Repository.Head"/>.
9+
/// </summary>
10+
/// <param name="branchName">The name of the branch to create.</param>
11+
public Branch CreateBranch(string branchName)
12+
{
13+
var head = Head;
14+
var reflogName = head is DetachedHead ? head.Tip.Sha : head.FriendlyName;
15+
16+
return CreateBranch(branchName, reflogName);
17+
}
18+
19+
/// <summary>
20+
/// Creates a branch with the specified name. This branch will point at <paramref name="target"/>.
21+
/// </summary>
22+
/// <param name="branchName">The name of the branch to create.</param>
23+
/// <param name="target">The commit which should be pointed at by the Branch.</param>
24+
public Branch CreateBranch(string branchName, Commit target)
25+
{
26+
return Branches.Add(branchName, target);
27+
}
28+
29+
/// <summary>
30+
/// Creates a branch with the specified name. This branch will point at the commit pointed at by the <see cref="Repository.Head"/>.
31+
/// </summary>
32+
/// <param name="branchName">The name of the branch to create.</param>
33+
/// <param name="committish">The revparse spec for the target commit.</param>
34+
public Branch CreateBranch( string branchName, string committish)
35+
{
36+
return Branches.Add(branchName, committish);
37+
}
38+
}
39+
}
40+
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
using System;
2+
using System.IO;
3+
using System.Linq;
4+
using System.Collections.Generic;
5+
using System.Globalization;
6+
using LibGit2Sharp.Core;
7+
8+
namespace LibGit2Sharp
9+
{
10+
public partial class Repository
11+
{
12+
/// <summary>
13+
/// Checkout the specified <see cref="Branch"/>, reference or SHA.
14+
/// <para>
15+
/// If the committishOrBranchSpec parameter resolves to a branch name, then the checked out HEAD will
16+
/// will point to the branch. Otherwise, the HEAD will be detached, pointing at the commit sha.
17+
/// </para>
18+
/// </summary>
19+
/// <param name="committishOrBranchSpec">A revparse spec for the commit or branch to checkout.</param>
20+
/// <param name="options"><see cref="CheckoutOptions"/> controlling checkout behavior.</param>
21+
/// <returns>The <see cref="Branch"/> that was checked out.</returns>
22+
public Branch Checkout(string committishOrBranchSpec, CheckoutOptions options)
23+
{
24+
Ensure.ArgumentNotNullOrEmptyString(committishOrBranchSpec, "committishOrBranchSpec");
25+
Ensure.ArgumentNotNull(options, "options");
26+
27+
var handles = Proxy.git_revparse_ext(Handle, committishOrBranchSpec);
28+
if (handles == null)
29+
{
30+
Ensure.GitObjectIsNotNull(null, committishOrBranchSpec);
31+
}
32+
33+
var objH = handles.Item1;
34+
var refH = handles.Item2;
35+
GitObject obj;
36+
try
37+
{
38+
if (!refH.IsInvalid)
39+
{
40+
var reference = Reference.BuildFromPtr<Reference>(refH, this);
41+
if (reference.IsLocalBranch)
42+
{
43+
Branch branch = Branches[reference.CanonicalName];
44+
return Checkout(branch, options);
45+
}
46+
}
47+
48+
obj = GitObject.BuildFrom(this,
49+
Proxy.git_object_id(objH),
50+
Proxy.git_object_type(objH),
51+
PathFromRevparseSpec(committishOrBranchSpec));
52+
}
53+
finally
54+
{
55+
objH.Dispose();
56+
refH.Dispose();
57+
}
58+
59+
Commit commit = obj.DereferenceToCommit(true);
60+
Checkout(commit.Tree, options, committishOrBranchSpec);
61+
62+
return Head;
63+
}
64+
65+
/// <summary>
66+
/// Checkout the tip commit of the specified <see cref="Branch"/> object. If this commit is the
67+
/// current tip of the branch, will checkout the named branch. Otherwise, will checkout the tip commit
68+
/// as a detached HEAD.
69+
/// </summary>
70+
/// <param name="branch">The <see cref="Branch"/> to check out.</param>
71+
/// <param name="options"><see cref="CheckoutOptions"/> controlling checkout behavior.</param>
72+
/// <returns>The <see cref="Branch"/> that was checked out.</returns>
73+
public Branch Checkout(Branch branch, CheckoutOptions options)
74+
{
75+
Ensure.ArgumentNotNull(branch, "branch");
76+
Ensure.ArgumentNotNull(options, "options");
77+
78+
// Make sure this is not an unborn branch.
79+
if (branch.Tip == null)
80+
{
81+
throw new UnbornBranchException("The tip of branch '{0}' is null. There's nothing to checkout.",
82+
branch.FriendlyName);
83+
}
84+
85+
if (!branch.IsRemote && !(branch is DetachedHead) &&
86+
string.Equals(Refs[branch.CanonicalName].TargetIdentifier, branch.Tip.Id.Sha,
87+
StringComparison.OrdinalIgnoreCase))
88+
{
89+
Checkout(branch.Tip.Tree, options, branch.CanonicalName);
90+
}
91+
else
92+
{
93+
Checkout(branch.Tip.Tree, options, branch.Tip.Id.Sha);
94+
}
95+
96+
return Head;
97+
}
98+
99+
/// <summary>
100+
/// Checkout the specified <see cref="LibGit2Sharp.Commit"/>.
101+
/// <para>
102+
/// Will detach the HEAD and make it point to this commit sha.
103+
/// </para>
104+
/// </summary>
105+
/// <param name="commit">The <see cref="LibGit2Sharp.Commit"/> to check out.</param>
106+
/// <param name="options"><see cref="CheckoutOptions"/> controlling checkout behavior.</param>
107+
/// <returns>The <see cref="Branch"/> that was checked out.</returns>
108+
public Branch Checkout(Commit commit, CheckoutOptions options)
109+
{
110+
Ensure.ArgumentNotNull(commit, "commit");
111+
Ensure.ArgumentNotNull(options, "options");
112+
113+
Checkout(commit.Tree, options, commit.Id.Sha);
114+
115+
return Head;
116+
}
117+
118+
/// <summary>
119+
/// Internal implementation of Checkout that expects the ID of the checkout target
120+
/// to already be in the form of a canonical branch name or a commit ID.
121+
/// </summary>
122+
/// <param name="tree">The <see cref="Tree"/> to checkout.</param>
123+
/// <param name="checkoutOptions"><see cref="CheckoutOptions"/> controlling checkout behavior.</param>
124+
/// <param name="refLogHeadSpec">The spec which will be written as target in the reflog.</param>
125+
private void Checkout(
126+
Tree tree,
127+
CheckoutOptions checkoutOptions,
128+
string refLogHeadSpec)
129+
{
130+
CheckoutTree(tree, null, checkoutOptions);
131+
132+
Refs.MoveHeadTarget(refLogHeadSpec);
133+
}
134+
135+
/// <summary>
136+
/// Checkout the specified tree.
137+
/// </summary>
138+
/// <param name="tree">The <see cref="Tree"/> to checkout.</param>
139+
/// <param name="paths">The paths to checkout.</param>
140+
/// <param name="opts">Collection of parameters controlling checkout behavior.</param>
141+
private void CheckoutTree(
142+
Tree tree,
143+
IList<string> paths,
144+
IConvertableToGitCheckoutOpts opts)
145+
{
146+
147+
using (GitCheckoutOptsWrapper checkoutOptionsWrapper = new GitCheckoutOptsWrapper(opts, ToFilePaths(paths)))
148+
{
149+
var options = checkoutOptionsWrapper.Options;
150+
Proxy.git_checkout_tree(Handle, tree.Id, ref options);
151+
}
152+
}
153+
154+
/// <summary>
155+
/// Checkout the specified <see cref="Branch"/>, reference or SHA.
156+
/// </summary>
157+
/// <param name="commitOrBranchSpec">A revparse spec for the commit or branch to checkout.</param>
158+
/// <returns>The <see cref="Branch"/> that was checked out.</returns>
159+
public Branch Checkout(string commitOrBranchSpec)
160+
{
161+
CheckoutOptions options = new CheckoutOptions();
162+
return Checkout(commitOrBranchSpec, options);
163+
}
164+
165+
/// <summary>
166+
/// Checkout the commit pointed at by the tip of the specified <see cref="Branch"/>.
167+
/// <para>
168+
/// If this commit is the current tip of the branch as it exists in the repository, the HEAD
169+
/// will point to this branch. Otherwise, the HEAD will be detached, pointing at the commit sha.
170+
/// </para>
171+
/// </summary>
172+
/// <param name="branch">The <see cref="Branch"/> to check out.</param>
173+
/// <returns>The <see cref="Branch"/> that was checked out.</returns>
174+
public Branch Checkout(Branch branch)
175+
{
176+
CheckoutOptions options = new CheckoutOptions();
177+
return Checkout(branch, options);
178+
}
179+
180+
/// <summary>
181+
/// Checkout the specified <see cref="LibGit2Sharp.Commit"/>.
182+
/// <para>
183+
/// Will detach the HEAD and make it point to this commit sha.
184+
/// </para>
185+
/// </summary>
186+
/// <param name="commit">The <see cref="LibGit2Sharp.Commit"/> to check out.</param>
187+
/// <returns>The <see cref="Branch"/> that was checked out.</returns>
188+
public Branch Checkout(Commit commit)
189+
{
190+
CheckoutOptions options = new CheckoutOptions();
191+
return Checkout(commit, options);
192+
}
193+
194+
/// <summary>
195+
/// Updates specifed paths in the index and working directory with the versions from the specified branch, reference, or SHA.
196+
/// <para>
197+
/// This method does not switch branches or update the current repository HEAD.
198+
/// </para>
199+
/// </summary>
200+
/// <param name = "committishOrBranchSpec">A revparse spec for the commit or branch to checkout paths from.</param>
201+
/// <param name="paths">The paths to checkout. Will throw if null is passed in. Passing an empty enumeration results in nothing being checked out.</param>
202+
/// <param name="checkoutOptions">Collection of parameters controlling checkout behavior.</param>
203+
public void CheckoutPaths(string committishOrBranchSpec, IEnumerable<string> paths, CheckoutOptions checkoutOptions)
204+
{
205+
Ensure.ArgumentNotNullOrEmptyString(committishOrBranchSpec, "committishOrBranchSpec");
206+
Ensure.ArgumentNotNull(paths, "paths");
207+
208+
var listOfPaths = paths.ToList();
209+
210+
// If there are no paths, then there is nothing to do.
211+
if (listOfPaths.Count == 0)
212+
{
213+
return;
214+
}
215+
216+
Commit commit = LookupCommit(committishOrBranchSpec);
217+
218+
CheckoutTree(commit.Tree, listOfPaths, checkoutOptions ?? new CheckoutOptions());
219+
}
220+
221+
/// <summary>
222+
/// Updates specifed paths in the index and working directory with the versions from the specified branch, reference, or SHA.
223+
/// <para>
224+
/// This method does not switch branches or update the current repository HEAD.
225+
/// </para>
226+
/// </summary>
227+
/// <param name = "committishOrBranchSpec">A revparse spec for the commit or branch to checkout paths from.</param>
228+
/// <param name="paths">The paths to checkout. Will throw if null is passed in. Passing an empty enumeration results in nothing being checked out.</param>
229+
public void CheckoutPaths(string committishOrBranchSpec, IEnumerable<string> paths)
230+
{
231+
CheckoutPaths(committishOrBranchSpec, paths, null);
232+
}
233+
234+
internal string BuildRelativePathFrom(string path)
235+
{
236+
//TODO: To be removed when libgit2 natively implements this
237+
if (!Path.IsPathRooted(path))
238+
{
239+
return path;
240+
}
241+
242+
string normalizedPath = Path.GetFullPath(path);
243+
244+
if (!PathStartsWith(normalizedPath, Info.WorkingDirectory))
245+
{
246+
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,
247+
"Unable to process file '{0}'. This file is not located under the working directory of the repository ('{1}').",
248+
normalizedPath,
249+
Info.WorkingDirectory));
250+
}
251+
252+
return normalizedPath.Substring(Info.WorkingDirectory.Length);
253+
}
254+
}
255+
}
256+

0 commit comments

Comments
 (0)