From 3ee9c06595522e60fec42d2136247827815a3afc Mon Sep 17 00:00:00 2001 From: Alexander Ovchinnikov <56644701+A-Ovchinnikov-mx@users.noreply.github.com> Date: Tue, 2 Feb 2021 17:27:20 +0100 Subject: [PATCH 1/8] Add support to retrieve remote repository's default branch The default branch is returned as an out parameter from ListRemoteReferences method --- LibGit2Sharp/Core/NativeMethods.cs | 5 ++++ LibGit2Sharp/Core/Proxy.cs | 11 +++++++++ LibGit2Sharp/Repository.cs | 39 +++++++++++++++++++++++++++++- 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index 7dd99ac3..9fdd5db7 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -1261,6 +1261,11 @@ internal static extern unsafe int git_remote_create_with_fetchspec( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string url, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string refspec); + [DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)] + internal static extern unsafe int git_remote_default_branch( + GitBuf res, + git_remote* remote); + [DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)] internal static extern unsafe int git_remote_delete( git_repository* repo, diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs index fd070f45..d70229e1 100644 --- a/LibGit2Sharp/Core/Proxy.cs +++ b/LibGit2Sharp/Core/Proxy.cs @@ -2167,6 +2167,17 @@ public static unsafe void git_remote_connect(RemoteHandle remote, GitDirection d } } + public static unsafe string git_remote_default_branch(RemoteHandle remote) + { + using (var buf = new GitBuf()) + { + int res = NativeMethods.git_remote_default_branch(buf, remote); + Ensure.ZeroResult(res); + + return LaxUtf8Marshaler.FromNative(buf.ptr); + } + } + public static unsafe void git_remote_delete(RepositoryHandle repo, string name) { int res = NativeMethods.git_remote_delete(repo, name); diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index b6399af4..31dce56e 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -656,7 +656,24 @@ internal Commit LookupCommit(string committish) /// The references in the remote repository. public static IEnumerable ListRemoteReferences(string url) { - return ListRemoteReferences(url, null); + string _defaultBranch; + return ListRemoteReferences(url, null, out _defaultBranch); + } + + /// + /// Lists the Remote Repository References. + /// + /// + /// Does not require a local Repository. The retrieved + /// + /// throws in this case. + /// + /// The url to list from. + /// The name of the Repository's default branch. + /// The references in the remote repository. + public static IEnumerable ListRemoteReferences(string url, out string defaultBranch) + { + return ListRemoteReferences(url, null, out defaultBranch); } /// @@ -671,6 +688,24 @@ public static IEnumerable ListRemoteReferences(string url) /// The used to connect to remote repository. /// The references in the remote repository. public static IEnumerable ListRemoteReferences(string url, CredentialsHandler credentialsProvider) + { + string _defaultBranch; + return ListRemoteReferences(url, credentialsProvider, out _defaultBranch); + } + + /// + /// Lists the Remote Repository References. + /// + /// + /// Does not require a local Repository. The retrieved + /// + /// throws in this case. + /// + /// The url to list from. + /// The used to connect to remote repository. + /// The name of the Repository's default branch. + /// The references in the remote repository. + public static IEnumerable ListRemoteReferences(string url, CredentialsHandler credentialsProvider, out string defaultBranch) { Ensure.ArgumentNotNull(url, "url"); @@ -687,6 +722,8 @@ public static IEnumerable ListRemoteReferences(string url, Credential } Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch, ref gitCallbacks, ref proxyOptions); + + defaultBranch = Proxy.git_remote_default_branch(remoteHandle); return Proxy.git_remote_ls(null, remoteHandle); } } From 3deea953ff231ea85d132d33a5acc943c74c871a Mon Sep 17 00:00:00 2001 From: Alexander Ovchinnikov <56644701+A-Ovchinnikov-mx@users.noreply.github.com> Date: Tue, 2 Feb 2021 17:51:57 +0100 Subject: [PATCH 2/8] Update version --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 36406d69..762c232a 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "1.110.2", + "version": "1.110.3", "cloudBuild": { "buildNumber": { "enabled": true From 0f11e62ffab78ea6097299c545bc5afd6072c1d3 Mon Sep 17 00:00:00 2001 From: Alexander Ovchinnikov <56644701+A-Ovchinnikov-mx@users.noreply.github.com> Date: Sun, 7 Feb 2021 21:00:42 +0100 Subject: [PATCH 3/8] Call git_remote_ls first for better troubleshooting --- LibGit2Sharp/Repository.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index 31dce56e..0fb302f8 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -723,8 +723,10 @@ public static IEnumerable ListRemoteReferences(string url, Credential Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch, ref gitCallbacks, ref proxyOptions); + var remoteReferences = Proxy.git_remote_ls(null, remoteHandle); defaultBranch = Proxy.git_remote_default_branch(remoteHandle); - return Proxy.git_remote_ls(null, remoteHandle); + + return remoteReferences; } } From ce40cc955c134976c3a9eb2385af2d7f931530f2 Mon Sep 17 00:00:00 2001 From: Alexander Ovchinnikov <56644701+A-Ovchinnikov-mx@users.noreply.github.com> Date: Thu, 18 Feb 2021 15:38:52 +0100 Subject: [PATCH 4/8] Pass GitRepositoryInitOptions directly to Proxy --- LibGit2Sharp/Core/Proxy.cs | 14 +++++--------- LibGit2Sharp/Repository.cs | 6 ++++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs index d70229e1..b9b0db93 100644 --- a/LibGit2Sharp/Core/Proxy.cs +++ b/LibGit2Sharp/Core/Proxy.cs @@ -2481,18 +2481,14 @@ public static unsafe IndexHandle git_repository_index(RepositoryHandle repo) } public static unsafe RepositoryHandle git_repository_init_ext( - FilePath workdirPath, FilePath gitdirPath, - bool isBare) + GitRepositoryInitOptions opts) { - using (var opts = GitRepositoryInitOptions.BuildFrom(workdirPath, isBare)) - { - git_repository* repo; - int res = NativeMethods.git_repository_init_ext(out repo, gitdirPath, opts); - Ensure.ZeroResult(res); + git_repository* repo; + int res = NativeMethods.git_repository_init_ext(out repo, gitdirPath, opts); + Ensure.ZeroResult(res); - return new RepositoryHandle(repo, true); - } + return new RepositoryHandle(repo, true); } public static unsafe bool git_repository_is_bare(RepositoryHandle repo) diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index 0fb302f8..3cced1bf 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -495,7 +495,8 @@ public static string Init(string path, bool isBare) { Ensure.ArgumentNotNullOrEmptyString(path, "path"); - using (RepositoryHandle repo = Proxy.git_repository_init_ext(null, path, isBare)) + using (var opts = GitRepositoryInitOptions.BuildFrom(null, isBare)) + using (RepositoryHandle repo = Proxy.git_repository_init_ext(path, opts)) { FilePath repoPath = Proxy.git_repository_path(repo); return repoPath.Native; @@ -520,7 +521,8 @@ public static string Init(string workingDirectoryPath, string gitDirectoryPath) // TODO: Shouldn't we ensure that the working folder isn't under the gitDir? - using (RepositoryHandle repo = Proxy.git_repository_init_ext(wd, gitDirectoryPath, false)) + using (var opts = GitRepositoryInitOptions.BuildFrom(wd, false)) + using (RepositoryHandle repo = Proxy.git_repository_init_ext(gitDirectoryPath, opts)) { FilePath repoPath = Proxy.git_repository_path(repo); return repoPath.Native; From ce7427967a8c90c58bbe6b2c8777211e36e6d718 Mon Sep 17 00:00:00 2001 From: Alexander Ovchinnikov <56644701+A-Ovchinnikov-mx@users.noreply.github.com> Date: Thu, 18 Feb 2021 15:51:34 +0100 Subject: [PATCH 5/8] Introduce InitOptions for Repository.Init --- LibGit2Sharp/Core/GitRepositoryInitOptions.cs | 10 +++--- LibGit2Sharp/InitOptions.cs | 32 +++++++++++++++++++ LibGit2Sharp/Repository.cs | 8 +++-- 3 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 LibGit2Sharp/InitOptions.cs diff --git a/LibGit2Sharp/Core/GitRepositoryInitOptions.cs b/LibGit2Sharp/Core/GitRepositoryInitOptions.cs index f639a0d8..a0fb27de 100644 --- a/LibGit2Sharp/Core/GitRepositoryInitOptions.cs +++ b/LibGit2Sharp/Core/GitRepositoryInitOptions.cs @@ -16,7 +16,7 @@ internal class GitRepositoryInitOptions : IDisposable public IntPtr InitialHead; public IntPtr OriginUrl; - public static GitRepositoryInitOptions BuildFrom(FilePath workdirPath, bool isBare) + public static GitRepositoryInitOptions BuildFrom(InitOptions initOptions) { var opts = new GitRepositoryInitOptions { @@ -24,14 +24,14 @@ public static GitRepositoryInitOptions BuildFrom(FilePath workdirPath, bool isBa Mode = 0 /* GIT_REPOSITORY_INIT_SHARED_UMASK */ }; - if (workdirPath != null) + if (initOptions.WorkdirPath != null) { - Debug.Assert(!isBare); + Debug.Assert(!initOptions.IsBare); - opts.WorkDirPath = StrictFilePathMarshaler.FromManaged(workdirPath); + opts.WorkDirPath = StrictFilePathMarshaler.FromManaged(initOptions.WorkdirPath); } - if (isBare) + if (initOptions.IsBare) { opts.Flags |= GitRepositoryInitFlags.GIT_REPOSITORY_INIT_BARE; } diff --git a/LibGit2Sharp/InitOptions.cs b/LibGit2Sharp/InitOptions.cs new file mode 100644 index 00000000..7d773965 --- /dev/null +++ b/LibGit2Sharp/InitOptions.cs @@ -0,0 +1,32 @@ +namespace LibGit2Sharp +{ + /// + /// Options controlling Repository Init behavior. + /// + public sealed class InitOptions + { + /// + /// Initializes a new instance of the class. + /// + /// Default behavior: + /// The workdirPath is null. + /// Not a bare repository. + /// + /// + public InitOptions() + { + WorkdirPath = null; + IsBare = false; + } + + /// + /// The path to the working directory. Null if it's the same directory where ".git" repository is created. + /// + public string WorkdirPath { get; set; } + + /// + /// True to initialize a bare repository. False otherwise, to initialize a standard ".git" repository. + /// + public bool IsBare { get; set; } + } +} diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index 3cced1bf..aed4b28c 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -495,7 +495,9 @@ public static string Init(string path, bool isBare) { Ensure.ArgumentNotNullOrEmptyString(path, "path"); - using (var opts = GitRepositoryInitOptions.BuildFrom(null, isBare)) + var initOptions = new InitOptions { IsBare = isBare }; + + using (var opts = GitRepositoryInitOptions.BuildFrom(initOptions)) using (RepositoryHandle repo = Proxy.git_repository_init_ext(path, opts)) { FilePath repoPath = Proxy.git_repository_path(repo); @@ -519,9 +521,11 @@ public static string Init(string workingDirectoryPath, string gitDirectoryPath) // to pass a path relatively to his current directory. string wd = Path.GetFullPath(workingDirectoryPath); + var initOptions = new InitOptions { WorkdirPath = wd }; + // TODO: Shouldn't we ensure that the working folder isn't under the gitDir? - using (var opts = GitRepositoryInitOptions.BuildFrom(wd, false)) + using (var opts = GitRepositoryInitOptions.BuildFrom(initOptions)) using (RepositoryHandle repo = Proxy.git_repository_init_ext(gitDirectoryPath, opts)) { FilePath repoPath = Proxy.git_repository_path(repo); From b5f6042bfe607ec5328b0c0a9885411797536fd8 Mon Sep 17 00:00:00 2001 From: Alexander Ovchinnikov <56644701+A-Ovchinnikov-mx@users.noreply.github.com> Date: Thu, 18 Feb 2021 15:59:48 +0100 Subject: [PATCH 6/8] Add Repository.Init method accepting InitOptions --- LibGit2Sharp/Repository.cs | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index aed4b28c..e67fca74 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -496,13 +496,8 @@ public static string Init(string path, bool isBare) Ensure.ArgumentNotNullOrEmptyString(path, "path"); var initOptions = new InitOptions { IsBare = isBare }; - - using (var opts = GitRepositoryInitOptions.BuildFrom(initOptions)) - using (RepositoryHandle repo = Proxy.git_repository_init_ext(path, opts)) - { - FilePath repoPath = Proxy.git_repository_path(repo); - return repoPath.Native; - } + + return Init(path, initOptions); } /// @@ -525,8 +520,24 @@ public static string Init(string workingDirectoryPath, string gitDirectoryPath) // TODO: Shouldn't we ensure that the working folder isn't under the gitDir? - using (var opts = GitRepositoryInitOptions.BuildFrom(initOptions)) - using (RepositoryHandle repo = Proxy.git_repository_init_ext(gitDirectoryPath, opts)) + return Init(gitDirectoryPath, initOptions); + } + + /// + /// Initialize a repository at the specified , + /// providing optional behavioral overrides through the parameter. + /// + /// 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. + /// Options controlling init behavior. + /// The path to the created repository. + public static string Init(string path, InitOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(path, "path"); + + options = options ?? new InitOptions(); + + using (var opts = GitRepositoryInitOptions.BuildFrom(options)) + using (RepositoryHandle repo = Proxy.git_repository_init_ext(path, opts)) { FilePath repoPath = Proxy.git_repository_path(repo); return repoPath.Native; From c7706079f2d3c58e24e465eea9b37ad057b7277b Mon Sep 17 00:00:00 2001 From: Alexander Ovchinnikov <56644701+A-Ovchinnikov-mx@users.noreply.github.com> Date: Thu, 18 Feb 2021 16:08:30 +0100 Subject: [PATCH 7/8] Add an option to set initial head to InitOptions --- LibGit2Sharp/Core/GitRepositoryInitOptions.cs | 8 ++++++++ LibGit2Sharp/InitOptions.cs | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/LibGit2Sharp/Core/GitRepositoryInitOptions.cs b/LibGit2Sharp/Core/GitRepositoryInitOptions.cs index a0fb27de..5c1b1134 100644 --- a/LibGit2Sharp/Core/GitRepositoryInitOptions.cs +++ b/LibGit2Sharp/Core/GitRepositoryInitOptions.cs @@ -36,6 +36,11 @@ public static GitRepositoryInitOptions BuildFrom(InitOptions initOptions) opts.Flags |= GitRepositoryInitFlags.GIT_REPOSITORY_INIT_BARE; } + if (initOptions.InitialHead != null) + { + opts.InitialHead = StrictUtf8Marshaler.FromManaged(initOptions.InitialHead); + } + return opts; } @@ -43,6 +48,9 @@ public void Dispose() { EncodingMarshaler.Cleanup(WorkDirPath); WorkDirPath = IntPtr.Zero; + + EncodingMarshaler.Cleanup(InitialHead); + InitialHead = IntPtr.Zero; } } diff --git a/LibGit2Sharp/InitOptions.cs b/LibGit2Sharp/InitOptions.cs index 7d773965..6b3f3486 100644 --- a/LibGit2Sharp/InitOptions.cs +++ b/LibGit2Sharp/InitOptions.cs @@ -11,12 +11,14 @@ public sealed class InitOptions /// Default behavior: /// The workdirPath is null. /// Not a bare repository. + /// Default initial head. /// /// public InitOptions() { WorkdirPath = null; IsBare = false; + InitialHead = null; } /// @@ -28,5 +30,12 @@ public InitOptions() /// True to initialize a bare repository. False otherwise, to initialize a standard ".git" repository. /// public bool IsBare { get; set; } + + /// + /// The name of the head to point HEAD at. + /// If null, then this will be treated as "master" and the HEAD ref will be set to "refs/heads/master". + /// If this begins with "refs/" it will be used verbatim; otherwise "refs/heads/" will be prefixed. + /// + public string InitialHead { get; set; } } } From 3178472bd862fd9971fba65c477699620f999f23 Mon Sep 17 00:00:00 2001 From: Alexander Ovchinnikov <56644701+A-Ovchinnikov-mx@users.noreply.github.com> Date: Mon, 22 Feb 2021 14:39:48 +0100 Subject: [PATCH 8/8] Review: initOptions null check --- LibGit2Sharp/Core/GitRepositoryInitOptions.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/LibGit2Sharp/Core/GitRepositoryInitOptions.cs b/LibGit2Sharp/Core/GitRepositoryInitOptions.cs index 5c1b1134..1b7b0e66 100644 --- a/LibGit2Sharp/Core/GitRepositoryInitOptions.cs +++ b/LibGit2Sharp/Core/GitRepositoryInitOptions.cs @@ -24,6 +24,11 @@ public static GitRepositoryInitOptions BuildFrom(InitOptions initOptions) Mode = 0 /* GIT_REPOSITORY_INIT_SHARED_UMASK */ }; + if (initOptions == null) + { + return opts; + } + if (initOptions.WorkdirPath != null) { Debug.Assert(!initOptions.IsBare);