From cc5f3ebfa53da643355d08e8d06d992ba09d7cc2 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 14 Jan 2025 17:10:06 +0800 Subject: [PATCH] refactor: do not run `git add` for untracked file while stashing local changes (#903) --- src/Commands/QueryStashChanges.cs | 60 ------------------------------- src/Commands/QueryStashes.cs | 22 +++++++++--- src/Commands/Stash.cs | 14 ++++++-- src/Models/Stash.cs | 3 ++ src/ViewModels/StashChanges.cs | 39 +------------------- src/ViewModels/StashesPage.cs | 26 ++++++++++++-- 6 files changed, 56 insertions(+), 108 deletions(-) delete mode 100644 src/Commands/QueryStashChanges.cs diff --git a/src/Commands/QueryStashChanges.cs b/src/Commands/QueryStashChanges.cs deleted file mode 100644 index 3b8d2db6..00000000 --- a/src/Commands/QueryStashChanges.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.Collections.Generic; -using System.Text.RegularExpressions; - -namespace SourceGit.Commands -{ - public partial class QueryStashChanges : Command - { - [GeneratedRegex(@"^(\s?[\w\?]{1,4})\s+(.+)$")] - private static partial Regex REG_FORMAT(); - - public QueryStashChanges(string repo, string sha) - { - WorkingDirectory = repo; - Context = repo; - Args = $"diff --name-status --pretty=format: {sha}^ {sha}"; - } - - public List Result() - { - Exec(); - return _changes; - } - - protected override void OnReadline(string line) - { - var match = REG_FORMAT().Match(line); - if (!match.Success) - return; - - 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); - _changes.Add(change); - break; - case 'A': - change.Set(Models.ChangeState.Added); - _changes.Add(change); - break; - case 'D': - change.Set(Models.ChangeState.Deleted); - _changes.Add(change); - break; - case 'R': - change.Set(Models.ChangeState.Renamed); - _changes.Add(change); - break; - case 'C': - change.Set(Models.ChangeState.Copied); - _changes.Add(change); - break; - } - } - - private readonly List _changes = new List(); - } -} diff --git a/src/Commands/QueryStashes.cs b/src/Commands/QueryStashes.cs index 6d089f8e..ccf601c5 100644 --- a/src/Commands/QueryStashes.cs +++ b/src/Commands/QueryStashes.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace SourceGit.Commands { @@ -8,7 +9,7 @@ namespace SourceGit.Commands { WorkingDirectory = repo; Context = repo; - Args = "stash list --pretty=format:%H%n%ct%n%gd%n%s"; + Args = "stash list --pretty=format:%H%n%P%n%ct%n%gd%n%s"; } public List Result() @@ -26,21 +27,32 @@ namespace SourceGit.Commands _stashes.Add(_current); break; case 1: - _current.Time = ulong.Parse(line); + ParseParent(line); break; case 2: - _current.Name = line; + _current.Time = ulong.Parse(line); break; case 3: + _current.Name = line; + break; + case 4: _current.Message = line; break; } _nextLineIdx++; - if (_nextLineIdx > 3) + if (_nextLineIdx > 4) _nextLineIdx = 0; } + private void ParseParent(string data) + { + if (data.Length < 8) + return; + + _current.Parents.AddRange(data.Split(separator: ' ', options: StringSplitOptions.RemoveEmptyEntries)); + } + private readonly List _stashes = new List(); private Models.Stash _current = null; private int _nextLineIdx = 0; diff --git a/src/Commands/Stash.cs b/src/Commands/Stash.cs index 40c917dd..cee79886 100644 --- a/src/Commands/Stash.cs +++ b/src/Commands/Stash.cs @@ -11,9 +11,19 @@ namespace SourceGit.Commands Context = repo; } - public bool Push(string message) + public bool Push(string message, bool includeUntracked = true, bool keepIndex = false) { - Args = $"stash push -m \"{message}\""; + var builder = new StringBuilder(); + builder.Append("stash push "); + if (includeUntracked) + builder.Append("--include-untracked "); + if (keepIndex) + builder.Append("--keep-index "); + builder.Append("-m \""); + builder.Append(message); + builder.Append("\""); + + Args = builder.ToString(); return Exec(); } diff --git a/src/Models/Stash.cs b/src/Models/Stash.cs index 3d395a84..8dca3bdb 100644 --- a/src/Models/Stash.cs +++ b/src/Models/Stash.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace SourceGit.Models { @@ -6,8 +7,10 @@ namespace SourceGit.Models { public string Name { get; set; } = ""; public string SHA { get; set; } = ""; + public List Parents { get; set; } = []; public ulong Time { get; set; } = 0; public string Message { get; set; } = ""; + public bool HasUntracked => Parents.Count == 3; public string TimeStr => DateTime.UnixEpoch.AddSeconds(Time).ToLocalTime().ToString(DateTimeFormat.Actived.DateTime); } diff --git a/src/ViewModels/StashChanges.cs b/src/ViewModels/StashChanges.cs index 48c9478e..fd937bdd 100644 --- a/src/ViewModels/StashChanges.cs +++ b/src/ViewModels/StashChanges.cs @@ -76,14 +76,11 @@ namespace SourceGit.ViewModels } else { - if (IncludeUntracked) - AddUntracked(_changes); - succ = StashWithChanges(_changes); + succ = new Commands.Stash(_repo.FullPath).Push(Message, IncludeUntracked, KeepIndex); } } else { - AddUntracked(_changes); succ = StashWithChanges(_changes); } @@ -97,40 +94,6 @@ namespace SourceGit.ViewModels }); } - private void AddUntracked(List changes) - { - var toBeAdded = new List(); - foreach (var c in changes) - { - if (c.WorkTree == Models.ChangeState.Added || c.WorkTree == Models.ChangeState.Untracked) - toBeAdded.Add(c); - } - - if (toBeAdded.Count == 0) - return; - - if (Native.OS.GitVersion >= Models.GitVersions.ADD_WITH_PATHSPECFILE) - { - var paths = new List(); - foreach (var c in toBeAdded) - paths.Add(c.Path); - - var tmpFile = Path.GetTempFileName(); - File.WriteAllLines(tmpFile, paths); - new Commands.Add(_repo.FullPath, tmpFile).Exec(); - File.Delete(tmpFile); - } - else - { - for (int i = 0; i < toBeAdded.Count; i += 10) - { - var count = Math.Min(10, toBeAdded.Count - i); - var step = toBeAdded.GetRange(i, count); - new Commands.Add(_repo.FullPath, step).Exec(); - } - } - } - private bool StashWithChanges(List changes) { if (changes.Count == 0) diff --git a/src/ViewModels/StashesPage.cs b/src/ViewModels/StashesPage.cs index 3ddb2b65..e5755a91 100644 --- a/src/ViewModels/StashesPage.cs +++ b/src/ViewModels/StashesPage.cs @@ -57,8 +57,25 @@ namespace SourceGit.ViewModels { Task.Run(() => { - var changes = new Commands.QueryStashChanges(_repo.FullPath, value.SHA).Result(); - Dispatcher.UIThread.Invoke(() => Changes = changes); + var changes = new Commands.CompareRevisions(_repo.FullPath, $"{value.SHA}^", value.SHA).Result(); + var untracked = new HashSet(); + if (value.HasUntracked) + { + var untrackedChanges = new Commands.CompareRevisions(_repo.FullPath, "4b825dc642cb6eb9a060e54bf8d69288fbee4904", value.Parents[2]).Result(); + foreach (var c in untrackedChanges) + { + untracked.Add(c.Path); + changes.Add(c); + } + } + + changes.Sort((l, r) => Models.NumericSort.Compare(l.Path, r.Path)); + + Dispatcher.UIThread.Invoke(() => + { + Changes = changes; + _untrackedChanges = untracked; + }); }); } } @@ -84,8 +101,10 @@ namespace SourceGit.ViewModels { if (value == null) DiffContext = null; + else if (_untrackedChanges.Contains(value.Path)) + DiffContext = new DiffContext(_repo.FullPath, new Models.DiffOption("4b825dc642cb6eb9a060e54bf8d69288fbee4904", _selectedStash.Parents[2], value), _diffContext); else - DiffContext = new DiffContext(_repo.FullPath, new Models.DiffOption($"{_selectedStash.SHA}^", _selectedStash.SHA, value), _diffContext); + DiffContext = new DiffContext(_repo.FullPath, new Models.DiffOption(_selectedStash.Parents[0], _selectedStash.SHA, value), _diffContext); } } } @@ -254,6 +273,7 @@ namespace SourceGit.ViewModels private List _visibleStashes = new List(); private string _searchFilter = string.Empty; private Models.Stash _selectedStash = null; + private HashSet _untrackedChanges = new HashSet(); private List _changes = null; private Models.Change _selectedChange = null; private DiffContext _diffContext = null;