diff --git a/README.md b/README.md index 2d222996..8c12c646 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ You can find the current translation status in [TRANSLATION.md](https://github.c ## How to Use -**To use this tool, you need to install Git(>=2.23.0) first.** +**To use this tool, you need to install Git(>=2.25.1) first.** You can download the latest stable from [Releases](https://github.com/sourcegit-scm/sourcegit/releases/latest) or download workflow artifacts from [Github Actions](https://github.com/sourcegit-scm/sourcegit/actions) to try this app based on latest commits. diff --git a/src/Commands/Add.cs b/src/Commands/Add.cs index b2aa803d..210eb4b2 100644 --- a/src/Commands/Add.cs +++ b/src/Commands/Add.cs @@ -1,7 +1,4 @@ -using System.Collections.Generic; -using System.Text; - -namespace SourceGit.Commands +namespace SourceGit.Commands { public class Add : Command { @@ -12,20 +9,11 @@ namespace SourceGit.Commands Args = includeUntracked ? "add ." : "add -u ."; } - public Add(string repo, List changes) + public Add(string repo, Models.Change change) { WorkingDirectory = repo; Context = repo; - - var builder = new StringBuilder(); - builder.Append("add --"); - foreach (var c in changes) - { - builder.Append(" \""); - builder.Append(c); - builder.Append("\""); - } - Args = builder.ToString(); + Args = $"add -- \"{change.Path}\""; } public Add(string repo, string pathspecFromFile) diff --git a/src/Commands/Discard.cs b/src/Commands/Discard.cs index 0768ca67..f36ca6c9 100644 --- a/src/Commands/Discard.cs +++ b/src/Commands/Discard.cs @@ -8,6 +8,12 @@ namespace SourceGit.Commands { public static class Discard { + /// + /// Discard all local changes (unstaged & staged) + /// + /// + /// + /// public static void All(string repo, bool includeIgnored, Models.ICommandLog log) { var changes = new QueryLocalChanges(repo).Result(); @@ -37,10 +43,17 @@ namespace SourceGit.Commands } new Reset(repo, "HEAD", "--hard") { Log = log }.Exec(); + if (includeIgnored) new Clean(repo) { Log = log }.Exec(); } + /// + /// Discard selected changes (only unstaged). + /// + /// + /// + /// public static void Changes(string repo, List changes, Models.ICommandLog log) { var restores = new List(); @@ -71,20 +84,12 @@ namespace SourceGit.Commands }); } - if (Native.OS.GitVersion >= Models.GitVersions.RESTORE_WITH_PATHSPECFILE) + if (restores.Count > 0) { - var tmpFile = Path.GetTempFileName(); - File.WriteAllLines(tmpFile, restores); - new Restore(repo, tmpFile, "--worktree --recurse-submodules") { Log = log }.Exec(); - File.Delete(tmpFile); - } - else - { - for (int i = 0; i < restores.Count; i += 32) - { - var count = Math.Min(32, restores.Count - i); - new Restore(repo, restores.GetRange(i, count), "--worktree --recurse-submodules") { Log = log }.Exec(); - } + var pathSpecFile = Path.GetTempFileName(); + File.WriteAllLines(pathSpecFile, restores); + new Restore(repo, pathSpecFile, false) { Log = log }.Exec(); + File.Delete(pathSpecFile); } } } diff --git a/src/Commands/Restore.cs b/src/Commands/Restore.cs index b8e5e0c7..663ea975 100644 --- a/src/Commands/Restore.cs +++ b/src/Commands/Restore.cs @@ -1,58 +1,52 @@ -using System.Collections.Generic; -using System.Text; +using System.Text; namespace SourceGit.Commands { public class Restore : Command { /// - /// Only used to discard all changes in the working directory and staged area. + /// Only used for single staged change. /// /// - public Restore(string repo) - { - WorkingDirectory = repo; - Context = repo; - Args = "restore --source=HEAD --staged --worktree --recurse-submodules ."; - } - - /// - /// Discard changes with git (< 2.25.0) that does not support the `--pathspec-from-file` option. - /// - /// - /// - /// - public Restore(string repo, List files, string extra) + /// + public Restore(string repo, Models.Change stagedChange) { WorkingDirectory = repo; Context = repo; var builder = new StringBuilder(); - builder.Append("restore "); - if (!string.IsNullOrEmpty(extra)) - builder.Append(extra).Append(" "); - builder.Append("--"); - foreach (var f in files) - builder.Append(' ').Append('"').Append(f).Append('"'); + builder.Append("restore --staged -- \""); + builder.Append(stagedChange.Path); + builder.Append('"'); + + if (stagedChange.Index == Models.ChangeState.Renamed) + { + builder.Append(" \""); + builder.Append(stagedChange.OriginalPath); + builder.Append('"'); + } + Args = builder.ToString(); } /// - /// Discard changes with git (>= 2.25.0) that supports the `--pathspec-from-file` option. + /// Restore changes given in a path-spec file. /// /// /// - /// - public Restore(string repo, string pathspecFile, string extra) + /// + public Restore(string repo, string pathspecFile, bool isStaged) { WorkingDirectory = repo; Context = repo; var builder = new StringBuilder(); builder.Append("restore "); - if (!string.IsNullOrEmpty(extra)) - builder.Append(extra).Append(" "); - builder.Append("--pathspec-from-file=\"").Append(pathspecFile).Append('"'); + builder.Append(isStaged ? "--staged " : "--worktree --recurse-submodules "); + builder.Append("--pathspec-from-file=\""); + builder.Append(pathspecFile); + builder.Append('"'); + Args = builder.ToString(); } } diff --git a/src/Commands/Tag.cs b/src/Commands/Tag.cs index 10a7ba87..017afea0 100644 --- a/src/Commands/Tag.cs +++ b/src/Commands/Tag.cs @@ -28,12 +28,13 @@ namespace SourceGit.Commands string tmp = Path.GetTempFileName(); File.WriteAllText(tmp, message); cmd.Args += $"-F \"{tmp}\""; - } - else - { - cmd.Args += $"-m {name}"; + + var succ = cmd.Exec(); + File.Delete(tmp); + return succ; } + cmd.Args += $"-m {name}"; return cmd.Exec(); } diff --git a/src/Models/GitVersions.cs b/src/Models/GitVersions.cs index b06d3e34..8aae63a3 100644 --- a/src/Models/GitVersions.cs +++ b/src/Models/GitVersions.cs @@ -5,26 +5,16 @@ /// /// The minimal version of Git that required by this app. /// - public static readonly System.Version MINIMAL = new System.Version(2, 23, 0); - - /// - /// The minimal version of Git that supports the `add` command with the `--pathspec-from-file` option. - /// - public static readonly System.Version ADD_WITH_PATHSPECFILE = new System.Version(2, 25, 0); - - /// - /// The minimal version of Git that supports the `restore` command with the `--pathspec-from-file` option. - /// - public static readonly System.Version RESTORE_WITH_PATHSPECFILE = new System.Version(2, 25, 0); + public static readonly System.Version MINIMAL = new(2, 25, 1); /// /// The minimal version of Git that supports the `stash push` command with the `--pathspec-from-file` option. /// - public static readonly System.Version STASH_PUSH_WITH_PATHSPECFILE = new System.Version(2, 26, 0); + public static readonly System.Version STASH_PUSH_WITH_PATHSPECFILE = new(2, 26, 0); /// /// The minimal version of Git that supports the `stash push` command with the `--staged` option. /// - public static readonly System.Version STASH_PUSH_ONLY_STAGED = new System.Version(2, 35, 0); + public static readonly System.Version STASH_PUSH_ONLY_STAGED = new(2, 35, 0); } } diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml index d7588b71..3c900d42 100644 --- a/src/Resources/Locales/de_DE.axaml +++ b/src/Resources/Locales/de_DE.axaml @@ -501,7 +501,7 @@ Globale Git Benutzer Email Aktivere --prune beim fetchen Aktiviere --ignore-cr-at-eol beim Unterschied - Diese App setzt Git (>= 2.23.0) voraus + Diese App setzt Git (>= 2.25.1) voraus Installationspfad Aktiviere HTTP SSL Verifizierung Benutzername diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 9bb8c47b..4834aef9 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -511,7 +511,7 @@ Global git user email Enable --prune on fetch Enable --ignore-cr-at-eol in diff - Git (>= 2.23.0) is required by this app + Git (>= 2.25.1) is required by this app Install Path Enable HTTP SSL Verify User Name diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml index 0a558dfa..36c60346 100644 --- a/src/Resources/Locales/es_ES.axaml +++ b/src/Resources/Locales/es_ES.axaml @@ -515,7 +515,7 @@ Email global del usuario git Habilitar --prune para fetch Habilitar --ignore-cr-at-eol en diff - Se requiere Git (>= 2.23.0) para esta aplicación + Se requiere Git (>= 2.25.1) para esta aplicación Ruta de instalación Habilitar verificación HTTP SSL Nombre de usuario diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml index 0bdccf94..25e6ca3e 100644 --- a/src/Resources/Locales/fr_FR.axaml +++ b/src/Resources/Locales/fr_FR.axaml @@ -483,7 +483,7 @@ E-mail utilsateur E-mail utilsateur global Activer --prune pour fetch - Cette application requière Git (>= 2.23.0) + Cette application requière Git (>= 2.25.1) Chemin d'installation Activer la vérification HTTP SSL Nom d'utilisateur diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml index bebce7b3..22c4e8fe 100644 --- a/src/Resources/Locales/it_IT.axaml +++ b/src/Resources/Locales/it_IT.axaml @@ -504,7 +504,7 @@ Email utente Git globale Abilita --prune durante il fetch Abilita --ignore-cr-at-eol nel diff - Questa applicazione richiede Git (>= 2.23.0) + Questa applicazione richiede Git (>= 2.25.1) Percorso Installazione Abilita la verifica HTTP SSL Nome Utente diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml index 49d3871e..945cf2d9 100644 --- a/src/Resources/Locales/ja_JP.axaml +++ b/src/Resources/Locales/ja_JP.axaml @@ -482,7 +482,7 @@ ユーザー Eメールアドレス グローバルgitのEメールアドレス フェッチ時に--pruneを有効化 - Git (>= 2.23.0) はこのアプリで必要です + Git (>= 2.25.1) はこのアプリで必要です インストール パス HTTP SSL 検証を有効にする ユーザー名 diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml index a2fa7797..a75d6777 100644 --- a/src/Resources/Locales/pt_BR.axaml +++ b/src/Resources/Locales/pt_BR.axaml @@ -440,7 +440,7 @@ Email do Usuário Email global do usuário git Habilita --prune ao buscar - Git (>= 2.23.0) é necessário para este aplicativo + Git (>= 2.25.1) é necessário para este aplicativo Caminho de Instalação Nome do Usuário Nome global do usuário git diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index 22a404de..0a6ccba4 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -514,7 +514,7 @@ Общая электроная почта пользователя git Разрешить (--prune) при скачивании Разрешить (--ignore-cr-at-eol) в сравнении - Для работы программы требуется версия Git (>= 2.23.0) + Для работы программы требуется версия Git (>= 2.25.1) Путь установки Разрешить верификацию HTTP SSL Имя пользователя diff --git a/src/Resources/Locales/ta_IN.axaml b/src/Resources/Locales/ta_IN.axaml index 14a8d210..e66af3ff 100644 --- a/src/Resources/Locales/ta_IN.axaml +++ b/src/Resources/Locales/ta_IN.axaml @@ -482,7 +482,7 @@ பயனர் மின்னஞ்சல் உலகளாவிய அறிவிலி பயனர் மின்னஞ்சல் --prune எடுக்கும்போது இயக்கு - அறிவிலி (>= 2.23.0) இந்த பயன்பாட்டிற்கு தேவைப்படுகிறது + அறிவிலி (>= 2.25.1) இந்த பயன்பாட்டிற்கு தேவைப்படுகிறது நிறுவல் பாதை உஉபநெ பாகுஅ சரிபார்ப்பை இயக்கு பயனர் பெயர் diff --git a/src/Resources/Locales/uk_UA.axaml b/src/Resources/Locales/uk_UA.axaml index bcca6454..2e7b399b 100644 --- a/src/Resources/Locales/uk_UA.axaml +++ b/src/Resources/Locales/uk_UA.axaml @@ -487,7 +487,7 @@ Email користувача Глобальний email користувача git Увімкнути --prune при fetch - Git (>= 2.23.0) є обов'язковим для цієї програми + Git (>= 2.25.1) є обов'язковим для цієї програми Шлях встановлення Увімкнути перевірку HTTP SSL Ім'я користувача diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 28efb318..77a55f75 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -515,7 +515,7 @@ 默认GIT用户邮箱 拉取更新时启用修剪(--prune) 对比文件时,默认忽略换行符变更 (--ignore-cr-at-eol) - 本软件要求GIT最低版本为2.23.0 + 本软件要求GIT最低版本为2.25.1 安装路径 启用HTTP SSL验证 用户名 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 5160bcb5..aef769de 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -515,7 +515,7 @@ 預設 Git 使用者電子郵件 拉取變更時進行清理 (--prune) 對比檔案時,預設忽略行尾的 CR 變更 (--ignore-cr-at-eol) - 本軟體要求 Git 最低版本為 2.23.0 + 本軟體要求 Git 最低版本為 2.25.1 安裝路徑 啟用 HTTP SSL 驗證 使用者名稱 diff --git a/src/ViewModels/StashChanges.cs b/src/ViewModels/StashChanges.cs index 75edfb7b..11e449fb 100644 --- a/src/ViewModels/StashChanges.cs +++ b/src/ViewModels/StashChanges.cs @@ -117,10 +117,10 @@ namespace SourceGit.ViewModels foreach (var c in changes) paths.Add(c.Path); - var tmpFile = Path.GetTempFileName(); - File.WriteAllLines(tmpFile, paths); - succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, tmpFile, KeepIndex); - File.Delete(tmpFile); + var pathSpecFile = Path.GetTempFileName(); + File.WriteAllLines(pathSpecFile, paths); + succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, pathSpecFile, KeepIndex); + File.Delete(pathSpecFile); } else { diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index b501d8d2..6469b564 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -412,7 +412,12 @@ namespace SourceGit.ViewModels } if (needStage.Count > 0) - await Task.Run(() => new Commands.Add(_repo.FullPath, needStage).Use(log).Exec()); + { + var pathSpecFile = Path.GetTempFileName(); + await File.WriteAllLinesAsync(pathSpecFile, needStage); + await Task.Run(() => new Commands.Add(_repo.FullPath, pathSpecFile).Use(log).Exec()); + File.Delete(pathSpecFile); + } log.Complete(); _repo.MarkWorkingCopyDirtyManually(); @@ -456,7 +461,12 @@ namespace SourceGit.ViewModels } if (needStage.Count > 0) - await Task.Run(() => new Commands.Add(_repo.FullPath, needStage).Use(log).Exec()); + { + var pathSpecFile = Path.GetTempFileName(); + await File.WriteAllLinesAsync(pathSpecFile, needStage); + await Task.Run(() => new Commands.Add(_repo.FullPath, pathSpecFile).Use(log).Exec()); + File.Delete(pathSpecFile); + } log.Complete(); _repo.MarkWorkingCopyDirtyManually(); @@ -467,7 +477,7 @@ namespace SourceGit.ViewModels { var toolType = Preferences.Instance.ExternalMergeToolType; var toolPath = Preferences.Instance.ExternalMergeToolPath; - var file = change?.Path; // NOTE: With no arg, mergetool runs on on every file with merge conflicts! + var file = change?.Path; // NOTE: With no arg, mergetool runs on every file with merge conflicts! await Task.Run(() => Commands.MergeTool.OpenForMerge(_repo.FullPath, toolType, toolPath, file)); } @@ -770,7 +780,7 @@ namespace SourceGit.ViewModels byParentFolder.IsVisible = !isRooted; byParentFolder.Click += (_, e) => { - var dir = Path.GetDirectoryName(change.Path).Replace("\\", "/"); + var dir = Path.GetDirectoryName(change.Path)!.Replace("\\", "/"); Commands.GitIgnore.Add(_repo.FullPath, dir + "/"); e.Handled = true; }; @@ -792,7 +802,7 @@ namespace SourceGit.ViewModels byExtensionInSameFolder.IsVisible = !isRooted; byExtensionInSameFolder.Click += (_, e) => { - var dir = Path.GetDirectoryName(change.Path).Replace("\\", "/"); + var dir = Path.GetDirectoryName(change.Path)!.Replace("\\", "/"); Commands.GitIgnore.Add(_repo.FullPath, $"{dir}/*{extension}"); e.Handled = true; }; @@ -1619,31 +1629,19 @@ namespace SourceGit.ViewModels { await Task.Run(() => new Commands.Add(_repo.FullPath, _repo.IncludeUntracked).Use(log).Exec()); } - else if (Native.OS.GitVersion >= Models.GitVersions.ADD_WITH_PATHSPECFILE) - { - var paths = new List(); - foreach (var c in changes) - paths.Add(c.Path); - - var tmpFile = Path.GetTempFileName(); - File.WriteAllLines(tmpFile, paths); - await Task.Run(() => new Commands.Add(_repo.FullPath, tmpFile).Use(log).Exec()); - File.Delete(tmpFile); - } else { var paths = new List(); foreach (var c in changes) paths.Add(c.Path); - for (int i = 0; i < count; i += 32) - { - var step = paths.GetRange(i, Math.Min(32, count - i)); - await Task.Run(() => new Commands.Add(_repo.FullPath, step).Use(log).Exec()); - } + var pathSpecFile = Path.GetTempFileName(); + await File.WriteAllLinesAsync(pathSpecFile, paths); + await Task.Run(() => new Commands.Add(_repo.FullPath, pathSpecFile).Use(log).Exec()); + File.Delete(pathSpecFile); } log.Complete(); - + _repo.MarkWorkingCopyDirtyManually(); _repo.SetWatcherEnabled(true); IsStaging = false; @@ -1667,7 +1665,7 @@ namespace SourceGit.ViewModels log.AppendLine("$ git update-index --index-info "); await Task.Run(() => new Commands.UnstageChangesForAmend(_repo.FullPath, changes).Exec()); } - else if (Native.OS.GitVersion >= Models.GitVersions.RESTORE_WITH_PATHSPECFILE) + else { var paths = new List(); foreach (var c in changes) @@ -1676,30 +1674,14 @@ namespace SourceGit.ViewModels if (c.Index == Models.ChangeState.Renamed) paths.Add(c.OriginalPath); } - - var tmpFile = Path.GetTempFileName(); - File.WriteAllLines(tmpFile, paths); - await Task.Run(() => new Commands.Restore(_repo.FullPath, tmpFile, "--staged").Use(log).Exec()); - File.Delete(tmpFile); - } - else - { - for (int i = 0; i < count; i += 32) - { - var step = changes.GetRange(i, Math.Min(32, count - i)); - var files = new List(); - foreach (var c in step) - { - files.Add(c.Path); - if (c.Index == Models.ChangeState.Renamed) - files.Add(c.OriginalPath); - } - await Task.Run(() => new Commands.Restore(_repo.FullPath, files, "--staged").Use(log).Exec()); - } + var pathSpecFile = Path.GetTempFileName(); + await File.WriteAllLinesAsync(pathSpecFile, paths); + await Task.Run(() => new Commands.Restore(_repo.FullPath, pathSpecFile, true).Use(log).Exec()); + File.Delete(pathSpecFile); } log.Complete(); - + _repo.MarkWorkingCopyDirtyManually(); _repo.SetWatcherEnabled(true); IsUnstaging = false; diff --git a/src/Views/TextDiffView.axaml.cs b/src/Views/TextDiffView.axaml.cs index 8ad4a223..999c3262 100644 --- a/src/Views/TextDiffView.axaml.cs +++ b/src/Views/TextDiffView.axaml.cs @@ -1868,7 +1868,7 @@ namespace SourceGit.Views if (!selection.HasLeftChanges) { - new Commands.Add(repo.FullPath, [change.Path]).Exec(); + new Commands.Add(repo.FullPath, change).Exec(); } else { @@ -1928,10 +1928,8 @@ namespace SourceGit.Views { if (change.DataForAmend != null) new Commands.UnstageChangesForAmend(repo.FullPath, [change]).Exec(); - else if (change.Index == Models.ChangeState.Renamed) - new Commands.Restore(repo.FullPath, [change.Path, change.OriginalPath], "--staged").Exec(); else - new Commands.Restore(repo.FullPath, [change.Path], "--staged").Exec(); + new Commands.Restore(repo.FullPath, change).Exec(); } else {