Skip to content

Commit d6e7723

Browse files
A-Ovchinnikov-mxA-Ovchinnikov-mx
A-Ovchinnikov-mx
authored and
A-Ovchinnikov-mx
committed
Get default remote branch & add init options
* Add support to retrieve remote repository's default branch * Introduce InitOptions for Repository.Init
1 parent 986ba9f commit d6e7723

File tree

6 files changed

+139
-31
lines changed

6 files changed

+139
-31
lines changed

LibGit2Sharp/Core/GitRepositoryInitOptions.cs

+18-5
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,46 @@ internal class GitRepositoryInitOptions : IDisposable
1616
public IntPtr InitialHead;
1717
public IntPtr OriginUrl;
1818

19-
public static GitRepositoryInitOptions BuildFrom(FilePath workdirPath, bool isBare)
19+
public static GitRepositoryInitOptions BuildFrom(InitOptions initOptions)
2020
{
2121
var opts = new GitRepositoryInitOptions
2222
{
2323
Flags = GitRepositoryInitFlags.GIT_REPOSITORY_INIT_MKPATH,
2424
Mode = 0 /* GIT_REPOSITORY_INIT_SHARED_UMASK */
2525
};
2626

27-
if (workdirPath != null)
27+
if (initOptions == null)
2828
{
29-
Debug.Assert(!isBare);
29+
return opts;
30+
}
31+
32+
if (initOptions.WorkdirPath != null)
33+
{
34+
Debug.Assert(!initOptions.IsBare);
3035

31-
opts.WorkDirPath = StrictFilePathMarshaler.FromManaged(workdirPath);
36+
opts.WorkDirPath = StrictFilePathMarshaler.FromManaged(initOptions.WorkdirPath);
3237
}
3338

34-
if (isBare)
39+
if (initOptions.IsBare)
3540
{
3641
opts.Flags |= GitRepositoryInitFlags.GIT_REPOSITORY_INIT_BARE;
3742
}
3843

44+
if (initOptions.InitialHead != null)
45+
{
46+
opts.InitialHead = StrictUtf8Marshaler.FromManaged(initOptions.InitialHead);
47+
}
48+
3949
return opts;
4050
}
4151

4252
public void Dispose()
4353
{
4454
EncodingMarshaler.Cleanup(WorkDirPath);
4555
WorkDirPath = IntPtr.Zero;
56+
57+
EncodingMarshaler.Cleanup(InitialHead);
58+
InitialHead = IntPtr.Zero;
4659
}
4760
}
4861

LibGit2Sharp/Core/NativeMethods.cs

+5
Original file line numberDiff line numberDiff line change
@@ -1391,6 +1391,11 @@ internal static extern unsafe int git_remote_create_with_fetchspec(
13911391
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string url,
13921392
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string refspec);
13931393

1394+
[DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
1395+
internal static extern unsafe int git_remote_default_branch(
1396+
GitBuf res,
1397+
git_remote* remote);
1398+
13941399
[DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
13951400
internal static extern unsafe int git_remote_delete(
13961401
git_repository* repo,

LibGit2Sharp/Core/Proxy.cs

+16-9
Original file line numberDiff line numberDiff line change
@@ -2179,6 +2179,17 @@ public static unsafe void git_remote_connect(RemoteHandle remote, GitDirection d
21792179
}
21802180
}
21812181

2182+
public static unsafe string git_remote_default_branch(RemoteHandle remote)
2183+
{
2184+
using (var buf = new GitBuf())
2185+
{
2186+
int res = NativeMethods.git_remote_default_branch(buf, remote);
2187+
Ensure.ZeroResult(res);
2188+
2189+
return LaxUtf8Marshaler.FromNative(buf.ptr);
2190+
}
2191+
}
2192+
21822193
public static unsafe void git_remote_delete(RepositoryHandle repo, string name)
21832194
{
21842195
int res = NativeMethods.git_remote_delete(repo, name);
@@ -2482,18 +2493,14 @@ public static unsafe IndexHandle git_repository_index(RepositoryHandle repo)
24822493
}
24832494

24842495
public static unsafe RepositoryHandle git_repository_init_ext(
2485-
FilePath workdirPath,
24862496
FilePath gitdirPath,
2487-
bool isBare)
2497+
GitRepositoryInitOptions opts)
24882498
{
2489-
using (var opts = GitRepositoryInitOptions.BuildFrom(workdirPath, isBare))
2490-
{
2491-
git_repository* repo;
2492-
int res = NativeMethods.git_repository_init_ext(out repo, gitdirPath, opts);
2493-
Ensure.ZeroResult(res);
2499+
git_repository* repo;
2500+
int res = NativeMethods.git_repository_init_ext(out repo, gitdirPath, opts);
2501+
Ensure.ZeroResult(res);
24942502

2495-
return new RepositoryHandle(repo, true);
2496-
}
2503+
return new RepositoryHandle(repo, true);
24972504
}
24982505

24992506
public static unsafe bool git_repository_is_bare(RepositoryHandle repo)

LibGit2Sharp/InitOptions.cs

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
namespace LibGit2Sharp
2+
{
3+
/// <summary>
4+
/// Options controlling Repository Init behavior.
5+
/// </summary>
6+
public sealed class InitOptions
7+
{
8+
/// <summary>
9+
/// Initializes a new instance of the <see cref="InitOptions"/> class.
10+
/// <para>
11+
/// Default behavior:
12+
/// The workdirPath is null.
13+
/// Not a bare repository.
14+
/// Default initial head.
15+
/// </para>
16+
/// </summary>
17+
public InitOptions()
18+
{
19+
WorkdirPath = null;
20+
IsBare = false;
21+
InitialHead = null;
22+
}
23+
24+
/// <summary>
25+
/// The path to the working directory. Null if it's the same directory where ".git" repository is created.
26+
/// </summary>
27+
public string WorkdirPath { get; set; }
28+
29+
/// <summary>
30+
/// True to initialize a bare repository. False otherwise, to initialize a standard ".git" repository.
31+
/// </summary>
32+
public bool IsBare { get; set; }
33+
34+
/// <summary>
35+
/// The name of the head to point HEAD at.
36+
/// If null, then this will be treated as "master" and the HEAD ref will be set to "refs/heads/master".
37+
/// If this begins with "refs/" it will be used verbatim; otherwise "refs/heads/" will be prefixed.
38+
/// </summary>
39+
public string InitialHead { get; set; }
40+
}
41+
}

LibGit2Sharp/Repository.cs

+58-16
Original file line numberDiff line numberDiff line change
@@ -495,11 +495,9 @@ public static string Init(string path, bool isBare)
495495
{
496496
Ensure.ArgumentNotNullOrEmptyString(path, "path");
497497

498-
using (RepositoryHandle repo = Proxy.git_repository_init_ext(null, path, isBare))
499-
{
500-
FilePath repoPath = Proxy.git_repository_path(repo);
501-
return repoPath.Native;
502-
}
498+
var initOptions = new InitOptions { IsBare = isBare };
499+
500+
return Init(path, initOptions);
503501
}
504502

505503
/// <summary>
@@ -518,9 +516,28 @@ public static string Init(string workingDirectoryPath, string gitDirectoryPath)
518516
// to pass a path relatively to his current directory.
519517
string wd = Path.GetFullPath(workingDirectoryPath);
520518

519+
var initOptions = new InitOptions { WorkdirPath = wd };
520+
521521
// TODO: Shouldn't we ensure that the working folder isn't under the gitDir?
522522

523-
using (RepositoryHandle repo = Proxy.git_repository_init_ext(wd, gitDirectoryPath, false))
523+
return Init(gitDirectoryPath, initOptions);
524+
}
525+
526+
/// <summary>
527+
/// Initialize a repository at the specified <paramref name="path"/>,
528+
/// providing optional behavioral overrides through the <paramref name="options"/> parameter.
529+
/// </summary>
530+
/// <param name="path">The path to the working folder when initializing a standard ".git" repository. Otherwise, when initializing a bare repository, the path to the expected location of this later.</param>
531+
/// <param name="options">Options controlling init behavior.</param>
532+
/// <returns>The path to the created repository.</returns>
533+
public static string Init(string path, InitOptions options)
534+
{
535+
Ensure.ArgumentNotNullOrEmptyString(path, "path");
536+
537+
options = options ?? new InitOptions();
538+
539+
using (var opts = GitRepositoryInitOptions.BuildFrom(options))
540+
using (RepositoryHandle repo = Proxy.git_repository_init_ext(path, opts))
524541
{
525542
FilePath repoPath = Proxy.git_repository_path(repo);
526543
return repoPath.Native;
@@ -675,22 +692,47 @@ public static IEnumerable<Reference> ListRemoteReferences(string url, Credential
675692
Ensure.ArgumentNotNull(url, "url");
676693

677694
using (RepositoryHandle repositoryHandle = Proxy.git_repository_new())
678-
using (RemoteHandle remoteHandle = Proxy.git_remote_create_anonymous(repositoryHandle, url))
695+
using (RemoteHandle remoteHandle = ConnectToAnonymousRemote(repositoryHandle, url, credentialsProvider))
679696
{
680-
var gitCallbacks = new GitRemoteCallbacks { version = 1 };
681-
var proxyOptions = new GitProxyOptions { Version = 1 };
697+
return Proxy.git_remote_ls(null, remoteHandle);
698+
}
699+
}
682700

683-
if (credentialsProvider != null)
684-
{
685-
var callbacks = new RemoteCallbacks(credentialsProvider);
686-
gitCallbacks = callbacks.GenerateCallbacks();
687-
}
701+
/// <summary>
702+
/// Retrieves the name of the Remote Repository's default branch.
703+
/// </summary>
704+
/// <param name="url">The url to retrieve from.</param>
705+
/// <param name="credentialsProvider">The <see cref="Func{Credentials}"/> used to connect to remote repository.</param>
706+
/// <returns>The reference name.</returns>
707+
public static string GetRemoteDefaultBranch(string url, CredentialsHandler credentialsProvider)
708+
{
709+
Ensure.ArgumentNotNull(url, "url");
688710

689-
Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch, ref gitCallbacks, ref proxyOptions);
690-
return Proxy.git_remote_ls(null, remoteHandle);
711+
using (RepositoryHandle repositoryHandle = Proxy.git_repository_new())
712+
using (RemoteHandle remoteHandle = ConnectToAnonymousRemote(repositoryHandle, url, credentialsProvider))
713+
{
714+
return Proxy.git_remote_default_branch(remoteHandle);
691715
}
692716
}
693717

718+
private static RemoteHandle ConnectToAnonymousRemote(RepositoryHandle repositoryHandle, string url, CredentialsHandler credentialsProvider)
719+
{
720+
RemoteHandle remoteHandle = Proxy.git_remote_create_anonymous(repositoryHandle, url);
721+
722+
var gitCallbacks = new GitRemoteCallbacks { version = 1 };
723+
var proxyOptions = new GitProxyOptions { Version = 1 };
724+
725+
if (credentialsProvider != null)
726+
{
727+
var callbacks = new RemoteCallbacks(credentialsProvider);
728+
gitCallbacks = callbacks.GenerateCallbacks();
729+
}
730+
731+
Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch, ref gitCallbacks, ref proxyOptions);
732+
733+
return remoteHandle;
734+
}
735+
694736
/// <summary>
695737
/// Probe for a git repository.
696738
/// <para>The lookup start from <paramref name="startingPath"/> and walk upward parent directories if nothing has been found.</para>

version.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
3-
"version": "1.110.1",
3+
"version": "1.110.10",
44
"cloudBuild": {
55
"buildNumber": {
66
"enabled": true

0 commit comments

Comments
 (0)