From 38d87fa1a1b443ede1cab537af489fd46431be21 Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 20 Mar 2025 21:12:08 +0800 Subject: [PATCH] feature: use `git stash show -u --name-status ` command to query changes in selected stash if git >= 2.32.0 Signed-off-by: leo --- src/Commands/QueryStashChanges.cs | 68 +++++++++++++++++++++++++++++++ src/Models/GitVersions.cs | 13 ++++-- src/ViewModels/StashChanges.cs | 4 +- src/ViewModels/StashesPage.cs | 26 ++++++++---- 4 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 src/Commands/QueryStashChanges.cs diff --git a/src/Commands/QueryStashChanges.cs b/src/Commands/QueryStashChanges.cs new file mode 100644 index 00000000..7fc27ea3 --- /dev/null +++ b/src/Commands/QueryStashChanges.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace SourceGit.Commands +{ + /// + /// Query stash changes. Requires git >= 2.32.0 + /// + public partial class QueryStashChanges : Command + { + [GeneratedRegex(@"^([MADRC])\s+(.+)$")] + private static partial Regex REG_FORMAT(); + + public QueryStashChanges(string repo, string stash) + { + WorkingDirectory = repo; + Context = repo; + Args = $"stash show -u --name-status \"{stash}\""; + } + + public List Result() + { + var rs = ReadToEnd(); + if (!rs.IsSuccess) + return []; + + var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); + var outs = new List(); + foreach (var line in lines) + { + var match = REG_FORMAT().Match(line); + if (!match.Success) + continue; + + var change = new Models.Change() { Path = match.Groups[2].Value }; + var status = match.Groups[1].Value; + + switch (status[0]) + { + case 'M': + change.Set(Models.ChangeState.Modified); + outs.Add(change); + break; + case 'A': + change.Set(Models.ChangeState.Added); + outs.Add(change); + break; + case 'D': + change.Set(Models.ChangeState.Deleted); + outs.Add(change); + break; + case 'R': + change.Set(Models.ChangeState.Renamed); + outs.Add(change); + break; + case 'C': + change.Set(Models.ChangeState.Copied); + outs.Add(change); + break; + } + } + + outs.Sort((l, r) => string.Compare(l.Path, r.Path, StringComparison.Ordinal)); + return outs; + } + } +} diff --git a/src/Models/GitVersions.cs b/src/Models/GitVersions.cs index 394a9518..92fd8c59 100644 --- a/src/Models/GitVersions.cs +++ b/src/Models/GitVersions.cs @@ -13,13 +13,18 @@ public static readonly System.Version ADD_WITH_PATHSPECFILE = new System.Version(2, 25, 0); /// - /// The minimal version of Git that supports the `stash` command with the `--pathspec-from-file` option. + /// The minimal version of Git that supports the `stash push` command with the `--pathspec-from-file` option. /// - public static readonly System.Version STASH_WITH_PATHSPECFILE = new System.Version(2, 26, 0); + public static readonly System.Version STASH_PUSH_WITH_PATHSPECFILE = new System.Version(2, 26, 0); /// - /// The minimal version of Git that supports the `stash` command with the `--staged` option. + /// The minimal version of Git that supports the `stash push` command with the `--staged` option. /// - public static readonly System.Version STASH_ONLY_STAGED = new System.Version(2, 35, 0); + public static readonly System.Version STASH_PUSH_ONLY_STAGED = new System.Version(2, 35, 0); + + /// + /// The minimal version of Git that supports the `stash show` command with the `-u` option. + /// + public static readonly System.Version STASH_SHOW_WITH_UNTRACKED = new System.Version(2, 32, 0); } } diff --git a/src/ViewModels/StashChanges.cs b/src/ViewModels/StashChanges.cs index 33ebb1f3..e35aaad0 100644 --- a/src/ViewModels/StashChanges.cs +++ b/src/ViewModels/StashChanges.cs @@ -64,7 +64,7 @@ namespace SourceGit.ViewModels { if (OnlyStaged) { - if (Native.OS.GitVersion >= Models.GitVersions.STASH_ONLY_STAGED) + if (Native.OS.GitVersion >= Models.GitVersions.STASH_PUSH_ONLY_STAGED) { succ = new Commands.Stash(_repo.FullPath).PushOnlyStaged(Message, KeepIndex); } @@ -109,7 +109,7 @@ namespace SourceGit.ViewModels return true; var succ = false; - if (Native.OS.GitVersion >= Models.GitVersions.STASH_WITH_PATHSPECFILE) + if (Native.OS.GitVersion >= Models.GitVersions.STASH_PUSH_WITH_PATHSPECFILE) { var paths = new List(); foreach (var c in changes) diff --git a/src/ViewModels/StashesPage.cs b/src/ViewModels/StashesPage.cs index d8443c91..77ed5551 100644 --- a/src/ViewModels/StashesPage.cs +++ b/src/ViewModels/StashesPage.cs @@ -58,14 +58,26 @@ namespace SourceGit.ViewModels { Task.Run(() => { - var changes = new Commands.CompareRevisions(_repo.FullPath, $"{value.SHA}^", value.SHA).Result(); - if (value.Parents.Count == 3) - { - var untracked = new Commands.CompareRevisions(_repo.FullPath, "4b825dc642cb6eb9a060e54bf8d69288fbee4904", value.Parents[2]).Result(); - foreach (var c in untracked) - changes.Add(c); + var changes = null as List; - changes.Sort((l, r) => string.Compare(l.Path, r.Path, StringComparison.Ordinal)); + if (Native.OS.GitVersion >= Models.GitVersions.STASH_SHOW_WITH_UNTRACKED) + { + changes = new Commands.QueryStashChanges(_repo.FullPath, value.Name).Result(); + } + else + { + changes = new Commands.CompareRevisions(_repo.FullPath, $"{value.SHA}^", value.SHA).Result(); + if (value.Parents.Count == 3) + { + var untracked = new Commands.CompareRevisions(_repo.FullPath, "4b825dc642cb6eb9a060e54bf8d69288fbee4904", value.Parents[2]).Result(); + var needSort = changes.Count > 0; + + foreach (var c in untracked) + changes.Add(c); + + if (needSort) + changes.Sort((l, r) => string.Compare(l.Path, r.Path, StringComparison.Ordinal)); + } } Dispatcher.UIThread.Invoke(() => Changes = changes);