From 2f54550ec43f80da2bb3f134cb74891d6d9b28fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20R=C3=A9mond?= Date: Tue, 9 Sep 2025 21:03:38 +0200 Subject: [PATCH] Add stash with paths options --- LibGit2Sharp.Tests/StashFixture.cs | 16 +++++++++++++++ LibGit2Sharp/Core/GitStashSaveOpts.cs | 28 ++++++++++++++++++++++++++ LibGit2Sharp/Core/NativeMethods.cs | 6 ++++++ LibGit2Sharp/Core/Proxy.cs | 29 +++++++++++++++++++++++++++ LibGit2Sharp/StashCollection.cs | 12 +++++++++++ LibGit2Sharp/StashModifiers.cs | 5 +++++ 6 files changed, 96 insertions(+) create mode 100644 LibGit2Sharp/Core/GitStashSaveOpts.cs diff --git a/LibGit2Sharp.Tests/StashFixture.cs b/LibGit2Sharp.Tests/StashFixture.cs index 27a535e8e..04e0e0a85 100644 --- a/LibGit2Sharp.Tests/StashFixture.cs +++ b/LibGit2Sharp.Tests/StashFixture.cs @@ -237,6 +237,22 @@ public void CanStashAndApplyWithOptions() } } + [Fact] + public void CanStashWithFilePaths() + { + string path = SandboxStandardTestRepo(); + using (var repo = new Repository(path)) + { + var stasher = Constants.Signature; + + const string filename = "modified_unstaged_file.txt"; + + var stash = repo.Stashes.Add(stasher, "This stash one file", StashModifiers.Default, new[] { filename }); + + Assert.NotNull(stash); + } + } + [Fact] public void CanStashAndPop() { diff --git a/LibGit2Sharp/Core/GitStashSaveOpts.cs b/LibGit2Sharp/Core/GitStashSaveOpts.cs new file mode 100644 index 000000000..a323f79a2 --- /dev/null +++ b/LibGit2Sharp/Core/GitStashSaveOpts.cs @@ -0,0 +1,28 @@ +using System.Runtime.InteropServices; + +namespace LibGit2Sharp.Core +{ + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct GitStashSaveOpts + { + public GitStashSaveOpts( + StashModifiers flags, + git_signature* stasher, + string message, + GitStrArray paths + ) + { + Version = 1; + Flags = flags; + Stasher = stasher; + Message = message; + Paths = paths; + } + + public uint Version; + public StashModifiers Flags; + public git_signature* Stasher; + public string Message; + public GitStrArray Paths; + } +} diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index cbb850b16..ccd197211 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -1744,6 +1744,12 @@ internal static extern unsafe int git_stash_save( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string message, StashModifiers flags); + [DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)] + internal static extern unsafe int git_stash_save_with_opts( + out GitOid stashOid, + git_repository* repo, + ref GitStashSaveOpts saveOpts); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int git_stash_cb( UIntPtr index, diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs index 83d35e22c..825b4d509 100644 --- a/LibGit2Sharp/Core/Proxy.cs +++ b/LibGit2Sharp/Core/Proxy.cs @@ -2857,6 +2857,35 @@ public static unsafe ObjectId git_stash_save( } } + public static unsafe ObjectId git_stash_save_with_opts( + RepositoryHandle repo, + Signature stasher, + string message, + StashModifiers options, + string[] paths) + { + using var sigHandle = stasher.BuildHandle(); + using var pathStrArray = GitStrArrayManaged.BuildFrom(paths ?? []); + + var stashOpts = new GitStashSaveOpts( + options, + sigHandle, + message, + pathStrArray.Array + ); + + int res = NativeMethods.git_stash_save_with_opts(out var stashOid, repo, ref stashOpts); + + if (res == (int)GitErrorCode.NotFound) + { + return null; + } + + Ensure.Int32Result(res); + + return new ObjectId(stashOid); + } + public static unsafe ICollection git_stash_foreach( RepositoryHandle repo, Func resultSelector) diff --git a/LibGit2Sharp/StashCollection.cs b/LibGit2Sharp/StashCollection.cs index 42162ada5..ded162e68 100644 --- a/LibGit2Sharp/StashCollection.cs +++ b/LibGit2Sharp/StashCollection.cs @@ -113,6 +113,18 @@ public virtual Stash Add(Signature stasher, string message) return Add(stasher, message, StashModifiers.Default); } + public virtual Stash Add(Signature stasher, string message, StashModifiers options, string[] paths) + { + ObjectId oid = Proxy.git_stash_save_with_opts(repo.Handle, stasher, message, options, paths); + + if (oid == null) + { + return null; + } + + return new Stash(repo, oid, 0); + } + /// /// Creates a stash with the specified message. /// diff --git a/LibGit2Sharp/StashModifiers.cs b/LibGit2Sharp/StashModifiers.cs index b0e6d41ff..d3fd983fa 100644 --- a/LibGit2Sharp/StashModifiers.cs +++ b/LibGit2Sharp/StashModifiers.cs @@ -30,5 +30,10 @@ public enum StashModifiers /// cleaned up from the working directory /// IncludeIgnored = (1 << 2), + + /// + /// All changes in the index and working directory are left intact + /// + KeepAll = (1 << 3), } }