diff --git a/LICENSE b/LICENSE index dceab2d8..442ce085 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2024 sourcegit +Copyright (c) 2025 sourcegit Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -17,4 +17,4 @@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 0990a39d..dae76783 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ * Clone/Fetch/Pull/Push... * Merge/Rebase/Reset/Revert/Amend/Cherry-pick... * Amend/Reword - * Interactive rebase (Basic) + * Interactive rebase * Branches * Remotes * Tags @@ -47,7 +47,7 @@ ## Translation Status -[![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen)](TRANSLATION.md) [![de__DE](https://img.shields.io/badge/de__DE-99.34%25-yellow)](TRANSLATION.md) [![es__ES](https://img.shields.io/badge/es__ES-99.74%25-yellow)](TRANSLATION.md) [![fr__FR](https://img.shields.io/badge/fr__FR-91.93%25-yellow)](TRANSLATION.md) [![it__IT](https://img.shields.io/badge/it__IT-97.35%25-yellow)](TRANSLATION.md) [![pt__BR](https://img.shields.io/badge/pt__BR-91.67%25-yellow)](TRANSLATION.md) [![ru__RU](https://img.shields.io/badge/ru__RU-99.21%25-yellow)](TRANSLATION.md) [![zh__CN](https://img.shields.io/badge/zh__CN-%E2%88%9A-brightgreen)](TRANSLATION.md) [![zh__TW](https://img.shields.io/badge/zh__TW-%E2%88%9A-brightgreen)](TRANSLATION.md) +[![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen)](TRANSLATION.md) [![de__DE](https://img.shields.io/badge/de__DE-99.21%25-yellow)](TRANSLATION.md) [![es__ES](https://img.shields.io/badge/es__ES-99.87%25-yellow)](TRANSLATION.md) [![fr__FR](https://img.shields.io/badge/fr__FR-91.80%25-yellow)](TRANSLATION.md) [![it__IT](https://img.shields.io/badge/it__IT-%E2%88%9A-brightgreen)](TRANSLATION.md) [![pt__BR](https://img.shields.io/badge/pt__BR-91.53%25-yellow)](TRANSLATION.md) [![ru__RU](https://img.shields.io/badge/ru__RU-99.07%25-yellow)](TRANSLATION.md) [![zh__CN](https://img.shields.io/badge/zh__CN-%E2%88%9A-brightgreen)](TRANSLATION.md) [![zh__TW](https://img.shields.io/badge/zh__TW-%E2%88%9A-brightgreen)](TRANSLATION.md) > [!NOTE] > You can find the missing keys in [TRANSLATION.md](TRANSLATION.md) diff --git a/TRANSLATION.md b/TRANSLATION.md index 04e121fc..716ddd3a 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -1,4 +1,4 @@ -### de_DE.axaml: 99.34% +### de_DE.axaml: 99.21%
@@ -9,21 +9,21 @@ - Text.Diff.First - Text.Diff.Last - Text.Preferences.AI.Streaming +- Text.StashCM.SaveAsPatch
-### es_ES.axaml: 99.74% +### es_ES.axaml: 99.87%
Missing Keys -- Text.Diff.First -- Text.Diff.Last +- Text.StashCM.SaveAsPatch
-### fr_FR.axaml: 91.93% +### fr_FR.axaml: 91.80%
@@ -88,41 +88,23 @@ - Text.SHALinkCM.NavigateTo - Text.Stash.AutoRestore - Text.Stash.AutoRestore.Tip +- Text.StashCM.SaveAsPatch - Text.WorkingCopy.CommitToEdit - Text.WorkingCopy.SignOff
-### it_IT.axaml: 97.35% +### it_IT.axaml: 100.00%
Missing Keys -- Text.AIAssistant.Regen -- Text.AIAssistant.Use -- Text.ApplyStash -- Text.ApplyStash.DropAfterApply -- Text.ApplyStash.RestoreIndex -- Text.ApplyStash.Stash -- Text.BranchCM.CustomAction -- Text.BranchUpstreamInvalid -- Text.Clone.RecurseSubmodules -- Text.Configure.CustomAction.Scope.Branch -- Text.Configure.CustomAction.WaitForExit -- Text.DeleteRepositoryNode.Path -- Text.DeleteRepositoryNode.TipForGroup -- Text.DeleteRepositoryNode.TipForRepository -- Text.Diff.First -- Text.Diff.Last -- Text.Preferences.AI.Streaming -- Text.Repository.Notifications.Clear -- Text.Stash.AutoRestore -- Text.Stash.AutoRestore.Tip +
-### pt_BR.axaml: 91.67% +### pt_BR.axaml: 91.53%
@@ -189,12 +171,13 @@ - Text.SHALinkCM.NavigateTo - Text.Stash.AutoRestore - Text.Stash.AutoRestore.Tip +- Text.StashCM.SaveAsPatch - Text.WorkingCopy.CommitToEdit - Text.WorkingCopy.SignOff
-### ru_RU.axaml: 99.21% +### ru_RU.axaml: 99.07%
@@ -206,6 +189,7 @@ - Text.Diff.First - Text.Diff.Last - Text.Preferences.AI.Streaming +- Text.StashCM.SaveAsPatch
diff --git a/VERSION b/VERSION index bb11b3b9..a241ab9b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2025.06 \ No newline at end of file +2025.07 \ No newline at end of file diff --git a/src/Commands/ExecuteCustomAction.cs b/src/Commands/ExecuteCustomAction.cs index 3a77ec01..7775da34 100644 --- a/src/Commands/ExecuteCustomAction.cs +++ b/src/Commands/ExecuteCustomAction.cs @@ -31,10 +31,7 @@ namespace SourceGit.Commands } catch (Exception e) { - Dispatcher.UIThread.Invoke(() => - { - App.RaiseException(repo, e.Message); - }); + Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, e.Message)); } } @@ -87,19 +84,14 @@ namespace SourceGit.Commands var exitCode = proc.ExitCode; if (exitCode != 0) { - var errMsg = builder.ToString(); - Dispatcher.UIThread.Invoke(() => - { - App.RaiseException(repo, errMsg); - }); + var errMsg = builder.ToString().Trim(); + if (!string.IsNullOrEmpty(errMsg)) + Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, errMsg)); } } catch (Exception e) { - Dispatcher.UIThread.Invoke(() => - { - App.RaiseException(repo, e.Message); - }); + Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, e.Message)); } proc.Close(); diff --git a/src/Commands/SaveChangesAsPatch.cs b/src/Commands/SaveChangesAsPatch.cs index 461bbfb5..b10037a1 100644 --- a/src/Commands/SaveChangesAsPatch.cs +++ b/src/Commands/SaveChangesAsPatch.cs @@ -37,6 +37,19 @@ namespace SourceGit.Commands return true; } + public static bool ProcessStashChanges(string repo, List opts, string saveTo) + { + using (var sw = File.Create(saveTo)) + { + foreach (var opt in opts) + { + if (!ProcessSingleChange(repo, opt, sw)) + return false; + } + } + return true; + } + private static bool ProcessSingleChange(string repo, Models.DiffOption opt, FileStream writer) { var starter = new ProcessStartInfo(); diff --git a/src/Models/OpenAI.cs b/src/Models/OpenAI.cs index 264230c6..76daacd0 100644 --- a/src/Models/OpenAI.cs +++ b/src/Models/OpenAI.cs @@ -36,7 +36,7 @@ namespace SourceGit.Models { if (startIdx > 0) OnReceive(buffer.Substring(0, startIdx)); - + var endIdx = buffer.IndexOf(">", startIdx + 1, StringComparison.Ordinal); if (endIdx <= startIdx) { diff --git a/src/Models/Remote.cs b/src/Models/Remote.cs index dbe8cfa7..ec9b8f20 100644 --- a/src/Models/Remote.cs +++ b/src/Models/Remote.cs @@ -8,9 +8,9 @@ namespace SourceGit.Models { [GeneratedRegex(@"^https?://([-a-zA-Z0-9:%._\+~#=]+@)?[-a-zA-Z0-9:%._\+~#=]{1,256}(\.[a-zA-Z0-9()]{1,6})?(:[0-9]{1,5})?\b(/[-a-zA-Z0-9()@:%_\+.~#?&=]+)+(\.git)?$")] private static partial Regex REG_HTTPS(); - [GeneratedRegex(@"^[\w\-]+@[\w\.\-]+(\:[0-9]+)?:[\w\-/~%]+/[\w\-\.%]+(\.git)?$")] + [GeneratedRegex(@"^[\w\-]+@[\w\.\-]+(\:[0-9]+)?:([a-zA-z0-9~%][\w\-\./~%]*)?[a-zA-Z0-9](\.git)?$")] private static partial Regex REG_SSH1(); - [GeneratedRegex(@"^ssh://([\w\-]+@)?[\w\.\-]+(\:[0-9]+)?/[\w\-/~%]+/[\w\-\.%]+(\.git)?$")] + [GeneratedRegex(@"^ssh://([\w\-]+@)?[\w\.\-]+(\:[0-9]+)?/([a-zA-z0-9~%][\w\-\./~%]*)?[a-zA-Z0-9](\.git)?$")] private static partial Regex REG_SSH2(); [GeneratedRegex(@"^git@([\w\.\-]+):([\w\-/~%]+/[\w\-\.%]+)\.git$")] diff --git a/src/Models/RepositorySettings.cs b/src/Models/RepositorySettings.cs index 44742fb8..08bf48ca 100644 --- a/src/Models/RepositorySettings.cs +++ b/src/Models/RepositorySettings.cs @@ -50,12 +50,6 @@ namespace SourceGit.Models set; } = true; - public DealWithLocalChanges DealWithLocalChangesOnCheckoutBranch - { - get; - set; - } = DealWithLocalChanges.DoNothing; - public bool EnableForceOnFetch { get; @@ -68,12 +62,6 @@ namespace SourceGit.Models set; } = false; - public DealWithLocalChanges DealWithLocalChangesOnPull - { - get; - set; - } = DealWithLocalChanges.DoNothing; - public bool PreferRebaseInsteadOfMerge { get; @@ -116,12 +104,6 @@ namespace SourceGit.Models set; } = false; - public DealWithLocalChanges DealWithLocalChangesOnCreateBranch - { - get; - set; - } = DealWithLocalChanges.DoNothing; - public bool CheckoutBranchOnCreateBranch { get; diff --git a/src/Native/Linux.cs b/src/Native/Linux.cs index a24f1b65..bfb98500 100644 --- a/src/Native/Linux.cs +++ b/src/Native/Linux.cs @@ -65,13 +65,16 @@ namespace SourceGit.Native { var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); var cwd = string.IsNullOrEmpty(workdir) ? home : workdir; + var terminal = OS.ShellOrTerminal; var startInfo = new ProcessStartInfo(); startInfo.WorkingDirectory = cwd; - startInfo.FileName = OS.ShellOrTerminal; + startInfo.FileName = terminal; - if (OS.ShellOrTerminal.EndsWith("wezterm", StringComparison.OrdinalIgnoreCase)) + if (terminal.EndsWith("wezterm", StringComparison.OrdinalIgnoreCase)) startInfo.Arguments = $"start --cwd \"{cwd}\""; + else if (terminal.EndsWith("ptyxis", StringComparison.OrdinalIgnoreCase)) + startInfo.Arguments = $"--new-window --working-directory=\"{cwd}\""; try { diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml index c16c90b5..1d0ca895 100644 --- a/src/Resources/Locales/de_DE.axaml +++ b/src/Resources/Locales/de_DE.axaml @@ -6,7 +6,6 @@ Über SourceGit • Erstellt mit • Grafik gerendert durch - © 2024 sourcegit-scm • Texteditor von • Monospace-Schriftarten von • Quelltext findest du auf diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 1a83a4da..5208a269 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -3,7 +3,6 @@ About SourceGit • Build with • Chart is rendered by - © 2024 sourcegit-scm • TextEditor from • Monospace fonts come from • Source code can be found at @@ -669,6 +668,7 @@ Apply Drop Pop + Save as Patch... Drop Stash Drop: STASHES diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml index 24170683..bf635321 100644 --- a/src/Resources/Locales/es_ES.axaml +++ b/src/Resources/Locales/es_ES.axaml @@ -6,7 +6,6 @@ Acerca de SourceGit • Construido con • El gráfico es renderizado por - © 2024 sourcegit-scm • Editor de texto de • Las fuentes monoespaciadas provienen de • El código fuente se puede encontrar en @@ -253,7 +252,9 @@ ANTIGUO Copiar Modo de Archivo Cambiado + Primera Diferencia Ignorar Cambio de Espacios en Blanco + Última Diferencia CAMBIO DE OBJETO LFS Siguiente Diferencia SIN CAMBIOS O SOLO CAMBIOS DE EOL diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml index b269424a..59fe00a8 100644 --- a/src/Resources/Locales/fr_FR.axaml +++ b/src/Resources/Locales/fr_FR.axaml @@ -6,7 +6,6 @@ À propos de SourceGit • Compilé avec • Le graphique est rendu par - © 2024 sourcegit-scm • TextEditor de • Les polices Monospace proviennent de • Le code source est disponible sur diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml index 1d0d353e..6e99decf 100644 --- a/src/Resources/Locales/it_IT.axaml +++ b/src/Resources/Locales/it_IT.axaml @@ -6,7 +6,6 @@ Informazioni su SourceGit • Creato con • Il grafico è reso da - © 2024 sourcegit-scm • Editor di testo da • I font monospaziati provengono da • Il codice sorgente è disponibile su @@ -22,7 +21,9 @@ Traccia Branch: Traccia branch remoto Assistente AI + RIGENERA Usa AI per generare il messaggio di commit + APPLICA COME MESSAGGIO DI COMMIT Applica Errore Genera errori e si rifiuta di applicare la patch @@ -37,6 +38,10 @@ Avviso Mostra avvisi per alcuni errori, ma applica comunque Spazi: + Applica lo stash + Rimuovi dopo aver applicato + Ripristina le modifiche all'indice + Stash: Archivia... Salva Archivio In: Seleziona il percorso del file archivio @@ -53,6 +58,7 @@ Confronta con HEAD Confronta con Worktree Copia Nome Branch + Azione personalizzata Elimina ${0}$... Elimina i {0} branch selezionati Scarta tutte le modifiche @@ -68,6 +74,7 @@ Rinomina ${0}$... Imposta Branch di Tracciamento... Confronto Branch + Upstream non valido Byte ANNULLA Ripristina Questa Revisione @@ -100,6 +107,7 @@ Nome Locale: Nome del repository. Facoltativo. Cartella Principale: + Inizializza e aggiorna i sottomoduli URL del Repository: CHIUDI Editor @@ -152,8 +160,10 @@ File Eseguibile: Nome: Ambito: + Branch Commit Repository + Attendi la fine dell'azione Indirizzo Email Indirizzo email GIT @@ -226,7 +236,10 @@ Stai per eliminare più branch contemporaneamente. Controlla attentamente prima di procedere! Elimina Remoto Remoto: + Percorso: Destinazione: + Tutti i figli verranno rimossi dalla lista. + Lo rimuoverà solamente dalla lista, non dal disco! Conferma Eliminazione Gruppo Conferma Eliminazione Repository Elimina Sottomodulo @@ -239,7 +252,9 @@ VECCHIO Copia Modalità File Modificata + Prima differenza Ignora Modifiche agli Spazi + Ultima differenza MODIFICA OGGETTO LFS Differenza Successiva NESSUNA MODIFICA O SOLO CAMBIAMENTI DI FINE LINEA @@ -450,6 +465,7 @@ Modello Nome Server + Abilita streaming ASPETTO Font Predefinito Font Size @@ -578,6 +594,7 @@ BRANCH LOCALI Vai a HEAD Crea Branch + CANCELLA LE NOTIFICHE Evidenzia nel grafico solo il branch corrente Apri in {0} Apri in Strumenti Esterni @@ -644,6 +661,8 @@ Percorso per la chiave SSH privata AVVIA Stasha + Auto-ripristino dopo lo stash + I tuoi file di lavoro rimangono inalterati, ma viene salvato uno stash. Includi file non tracciati Mantieni file in stage Messaggio: @@ -654,6 +673,7 @@ Applica Elimina Estrai + Salva come Patch... Elimina Stash Elimina: STASH diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml index a318cfa8..78445bfb 100644 --- a/src/Resources/Locales/pt_BR.axaml +++ b/src/Resources/Locales/pt_BR.axaml @@ -31,7 +31,6 @@ Sobre o SourceGit • Construído com • Gráfico desenhado por - © 2024 sourcegit-scm • Editor de Texto de • Fontes monoespaçadas de • Código-fonte pode ser encontrado em diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index a1c40764..4468650b 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -6,7 +6,6 @@ О SourceGit • Сборка с • Диаграмма отображается с помощью - © 2024 sourcegit-scm • Текстовый редактор от • Моноширинные шрифты взяты из • Исходный код можно найти по адресу diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index acfdefd2..0e8b9f7d 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -6,7 +6,6 @@ 关于本软件 • 项目依赖于 • 图表绘制组件来自 - © 2024 sourcegit-scm • 文本编辑器使用 • 等宽字体来自于 • 项目源代码地址 @@ -673,6 +672,7 @@ 应用(apply) 删除(drop) 应用并删除(pop) + 另存为补丁... 丢弃贮藏确认 丢弃贮藏 : 贮藏列表 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index dd9092a4..f4cfad08 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -6,7 +6,6 @@ 關於 SourceGit • 專案依賴於 • 圖表繪製元件來自 - © 2024 sourcegit-scm • 文字編輯器使用 • 等寬字型來自於 • 專案原始碼網址 @@ -672,6 +671,7 @@ 套用 (apply) 刪除 (drop) 套用並刪除 (pop) + 另存為修補檔 (patch)... 捨棄擱置變更確認 捨棄擱置變更: 擱置變更 diff --git a/src/SourceGit.csproj b/src/SourceGit.csproj index 4183511e..34e4eab2 100644 --- a/src/SourceGit.csproj +++ b/src/SourceGit.csproj @@ -13,7 +13,7 @@ SourceGit OpenSource GIT client sourcegit-scm - Copyright © 2024 sourcegit-scm. + Copyright © $([System.DateTime]::Now.Year) sourcegit-scm. MIT https://github.com/sourcegit-scm/sourcegit.git https://github.com/sourcegit-scm/sourcegit.git @@ -41,15 +41,15 @@ - - - - - + + + + + - + diff --git a/src/ViewModels/Checkout.cs b/src/ViewModels/Checkout.cs index fd84682a..9376741d 100644 --- a/src/ViewModels/Checkout.cs +++ b/src/ViewModels/Checkout.cs @@ -11,9 +11,9 @@ namespace SourceGit.ViewModels public Models.DealWithLocalChanges PreAction { - get => _repo.Settings.DealWithLocalChangesOnCheckoutBranch; - set => _repo.Settings.DealWithLocalChangesOnCheckoutBranch = value; - } + get; + set; + } = Models.DealWithLocalChanges.DoNothing; public Checkout(Repository repo, string branch) { diff --git a/src/ViewModels/CommitDetail.cs b/src/ViewModels/CommitDetail.cs index d90e97d6..7c5aa28f 100644 --- a/src/ViewModels/CommitDetail.cs +++ b/src/ViewModels/CommitDetail.cs @@ -25,8 +25,15 @@ namespace SourceGit.ViewModels public int ActivePageIndex { - get => _activePageIndex; - set => SetProperty(ref _activePageIndex, value); + get => _repo.CommitDetailActivePageIndex; + set + { + if (_repo.CommitDetailActivePageIndex != value) + { + _repo.CommitDetailActivePageIndex = value; + OnPropertyChanged(); + } + } } public Models.Commit Commit @@ -617,11 +624,7 @@ namespace SourceGit.ViewModels _changes = null; _revisionFiles.Clear(); - FullMessage = string.Empty; SignInfo = null; - Changes = []; - VisibleChanges = null; - SelectedChanges = null; ViewRevisionFileContent = null; Children.Clear(); RevisionFileSearchFilter = string.Empty; @@ -683,6 +686,9 @@ namespace SourceGit.ViewModels { Changes = changes; VisibleChanges = visible; + + if (visible.Count == 0) + SelectedChanges = null; }); } }); @@ -821,7 +827,6 @@ namespace SourceGit.ViewModels }; private Repository _repo = null; - private int _activePageIndex = 0; private Models.Commit _commit = null; private string _fullMessage = string.Empty; private Models.CommitSignInfo _signInfo = null; diff --git a/src/ViewModels/CreateBranch.cs b/src/ViewModels/CreateBranch.cs index a9698a07..01bff031 100644 --- a/src/ViewModels/CreateBranch.cs +++ b/src/ViewModels/CreateBranch.cs @@ -21,9 +21,9 @@ namespace SourceGit.ViewModels public Models.DealWithLocalChanges PreAction { - get => _repo.Settings.DealWithLocalChangesOnCreateBranch; - set => _repo.Settings.DealWithLocalChangesOnCreateBranch = value; - } + get; + set; + } = Models.DealWithLocalChanges.DoNothing; public bool CheckoutAfterCreated { diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs index 03f216de..48ce114d 100644 --- a/src/ViewModels/Histories.cs +++ b/src/ViewModels/Histories.cs @@ -561,13 +561,7 @@ namespace SourceGit.ViewModels _repo.ShowPopup(new CheckoutCommit(_repo, commit)); e.Handled = true; }; - menu.Items.Add(checkoutCommit); - } - menu.Items.Add(new MenuItem() { Header = "-" }); - - if (commit.IsMerged && current.Head != commit.SHA) - { var interactiveRebase = new MenuItem(); interactiveRebase.Header = new Views.NameHighlightedTextBlock("CommitCM.InteractiveRebase", current.Name); interactiveRebase.Icon = App.CreateMenuIcon("Icons.InteractiveRebase"); @@ -586,9 +580,13 @@ namespace SourceGit.ViewModels e.Handled = true; }; - menu.Items.Add(interactiveRebase); + + menu.Items.Add(checkoutCommit); menu.Items.Add(new MenuItem() { Header = "-" }); + menu.Items.Add(interactiveRebase); } + + menu.Items.Add(new MenuItem() { Header = "-" }); } if (current.Head != commit.SHA) diff --git a/src/ViewModels/InteractiveRebase.cs b/src/ViewModels/InteractiveRebase.cs index 355671c7..9f28fbc7 100644 --- a/src/ViewModels/InteractiveRebase.cs +++ b/src/ViewModels/InteractiveRebase.cs @@ -118,7 +118,7 @@ namespace SourceGit.ViewModels Task.Run(() => { - var commits = new Commands.QueryCommitsWithFullMessage(repoPath, $"{on.SHA}...HEAD").Result(); + var commits = new Commands.QueryCommitsWithFullMessage(repoPath, $"{on.SHA}..HEAD").Result(); var list = new List(); foreach (var c in commits) diff --git a/src/ViewModels/LauncherPage.cs b/src/ViewModels/LauncherPage.cs index 63cb52af..288770bc 100644 --- a/src/ViewModels/LauncherPage.cs +++ b/src/ViewModels/LauncherPage.cs @@ -71,7 +71,7 @@ namespace SourceGit.ViewModels public async void ProcessPopup() { - if (_popup != null) + if (_popup is { InProgress: false }) { if (!_popup.Check()) return; diff --git a/src/ViewModels/Pull.cs b/src/ViewModels/Pull.cs index 52f98d87..755b58f4 100644 --- a/src/ViewModels/Pull.cs +++ b/src/ViewModels/Pull.cs @@ -40,9 +40,9 @@ namespace SourceGit.ViewModels public Models.DealWithLocalChanges PreAction { - get => _repo.Settings.DealWithLocalChangesOnPull; - set => _repo.Settings.DealWithLocalChangesOnPull = value; - } + get; + set; + } = Models.DealWithLocalChanges.DoNothing; public bool UseRebase { diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index 6e8a5290..85b819c4 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -453,6 +453,12 @@ namespace SourceGit.ViewModels private set => SetProperty(ref _isAutoFetching, value); } + public int CommitDetailActivePageIndex + { + get; + set; + } = 0; + public Repository(bool isBare, string path, string gitDir) { IsBare = isBare; @@ -657,6 +663,12 @@ namespace SourceGit.ViewModels return; } + if (_currentBranch == null) + { + App.RaiseException(_fullpath, "Can NOT found current branch!!!"); + return; + } + var pull = new Pull(this, null); if (autoStart && pull.SelectedBranch != null) ShowAndStartPopup(pull); diff --git a/src/ViewModels/StashesPage.cs b/src/ViewModels/StashesPage.cs index 4a3bf933..ec7cc84a 100644 --- a/src/ViewModels/StashesPage.cs +++ b/src/ViewModels/StashesPage.cs @@ -4,6 +4,7 @@ using System.IO; using System.Threading.Tasks; using Avalonia.Controls; +using Avalonia.Platform.Storage; using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; @@ -88,7 +89,7 @@ namespace SourceGit.ViewModels private set { if (SetProperty(ref _changes, value)) - SelectedChange = null; + SelectedChange = value is { Count: > 0 } ? value[0] : null; } } @@ -157,9 +158,45 @@ namespace SourceGit.ViewModels ev.Handled = true; }; + var patch = new MenuItem(); + patch.Header = App.Text("StashCM.SaveAsPatch"); + patch.Icon = App.CreateMenuIcon("Icons.Diff"); + patch.Click += async (_, e) => + { + var storageProvider = App.GetStorageProvider(); + if (storageProvider == null) + return; + + var options = new FilePickerSaveOptions(); + options.Title = App.Text("StashCM.SaveAsPatch"); + options.DefaultExtension = ".patch"; + options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }]; + + var storageFile = await storageProvider.SaveFilePickerAsync(options); + if (storageFile != null) + { + var opts = new List(); + foreach (var c in _changes) + { + if (_untrackedChanges.Contains(c.Path)) + opts.Add(new Models.DiffOption("4b825dc642cb6eb9a060e54bf8d69288fbee4904", _selectedStash.Parents[2], c)); + else + opts.Add(new Models.DiffOption(_selectedStash.Parents[0], _selectedStash.SHA, c)); + } + + var succ = await Task.Run(() => Commands.SaveChangesAsPatch.ProcessStashChanges(_repo.FullPath, opts, storageFile.Path.LocalPath)); + if (succ) + App.SendNotification(_repo.FullPath, App.Text("SaveAsPatchSuccess")); + } + + e.Handled = true; + }; + var menu = new ContextMenu(); menu.Items.Add(apply); menu.Items.Add(drop); + menu.Items.Add(new MenuItem { Header = "-" }); + menu.Items.Add(patch); return menu; } diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index ce2a2ac1..97684093 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -445,6 +445,10 @@ namespace SourceGit.ViewModels _repo.SetWatcherEnabled(false); Task.Run(() => { + var mergeMsgFile = Path.Combine(_repo.GitDir, "MERGE_MSG"); + if (File.Exists(mergeMsgFile) && !string.IsNullOrWhiteSpace(_commitMessage)) + File.WriteAllText(mergeMsgFile, _commitMessage); + var succ = _inProgressContext.Continue(); Dispatcher.UIThread.Invoke(() => { @@ -725,8 +729,8 @@ namespace SourceGit.ViewModels byParentFolder.IsVisible = !isRooted; byParentFolder.Click += (_, e) => { - var path = Path.GetDirectoryName(change.Path).Replace("\\", "/"); - Commands.GitIgnore.Add(_repo.FullPath, path + "/"); + var dir = Path.GetDirectoryName(change.Path).Replace("\\", "/"); + Commands.GitIgnore.Add(_repo.FullPath, dir + "/"); e.Handled = true; }; addToIgnore.Items.Add(byParentFolder); @@ -747,8 +751,8 @@ namespace SourceGit.ViewModels byExtensionInSameFolder.IsVisible = !isRooted; byExtensionInSameFolder.Click += (_, e) => { - var path = Path.GetDirectoryName(change.Path).Replace("\\", "/"); - Commands.GitIgnore.Add(_repo.FullPath, path + "/*" + extension); + var dir = Path.GetDirectoryName(change.Path).Replace("\\", "/"); + Commands.GitIgnore.Add(_repo.FullPath, dir + "/*" + extension); e.Handled = true; }; addToIgnore.Items.Add(byExtensionInSameFolder); @@ -1466,7 +1470,7 @@ namespace SourceGit.ViewModels return unstaged; var visible = new List(); - + foreach (var c in unstaged) { if (c.Path.Contains(_unstagedFilter, StringComparison.OrdinalIgnoreCase)) diff --git a/src/Views/About.axaml b/src/Views/About.axaml index d781ee9e..6e45ab70 100644 --- a/src/Views/About.axaml +++ b/src/Views/About.axaml @@ -52,7 +52,7 @@ - + diff --git a/src/Views/About.axaml.cs b/src/Views/About.axaml.cs index b02cd13f..bbfd659c 100644 --- a/src/Views/About.axaml.cs +++ b/src/Views/About.axaml.cs @@ -11,11 +11,21 @@ namespace SourceGit.Views private set; } + public string Copyright + { + get; + private set; + } + public About() { var ver = Assembly.GetExecutingAssembly().GetName().Version; if (ver != null) Version = $"{ver.Major}.{ver.Minor}"; + var attributes = Assembly.GetExecutingAssembly() + .GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); + if (attributes.Length > 0) + Copyright = ((AssemblyCopyrightAttribute)attributes[0]).Copyright; DataContext = this; InitializeComponent(); diff --git a/src/Views/BranchCompare.axaml b/src/Views/BranchCompare.axaml index 04b77306..f73860c5 100644 --- a/src/Views/BranchCompare.axaml +++ b/src/Views/BranchCompare.axaml @@ -134,6 +134,7 @@ diff --git a/src/Views/ChangeCollectionView.axaml.cs b/src/Views/ChangeCollectionView.axaml.cs index d6982dda..6ef79861 100644 --- a/src/Views/ChangeCollectionView.axaml.cs +++ b/src/Views/ChangeCollectionView.axaml.cs @@ -85,6 +85,15 @@ namespace SourceGit.Views set => SetValue(ChangesProperty, value); } + public static readonly StyledProperty AutoSelectFirstChangeProperty = + AvaloniaProperty.Register(nameof(AutoSelectFirstChange), false); + + public bool AutoSelectFirstChange + { + get => GetValue(AutoSelectFirstChangeProperty); + set => SetValue(AutoSelectFirstChangeProperty, value); + } + public static readonly StyledProperty> SelectedChangesProperty = AvaloniaProperty.Register>(nameof(SelectedChanges)); @@ -205,9 +214,9 @@ namespace SourceGit.Views base.OnPropertyChanged(change); if (change.Property == ViewModeProperty) - UpdateDataSource(false); - else if (change.Property == ChangesProperty) UpdateDataSource(true); + else if (change.Property == ChangesProperty) + UpdateDataSource(false); else if (change.Property == SelectedChangesProperty) UpdateSelection(); } @@ -292,9 +301,9 @@ namespace SourceGit.Views } } - private void UpdateDataSource(bool disableEvents) + private void UpdateDataSource(bool onlyViewModeChange) { - _disableSelectionChangingEvent = disableEvents; + _disableSelectionChangingEvent = !onlyViewModeChange; var changes = Changes; if (changes == null || changes.Count == 0) @@ -324,7 +333,19 @@ namespace SourceGit.Views MakeTreeRows(rows, tree.Tree); tree.Rows.AddRange(rows); - if (selected.Count > 0) + if (!onlyViewModeChange && AutoSelectFirstChange) + { + foreach (var row in tree.Rows) + { + if (row.Change != null) + { + tree.SelectedRows.Add(row); + SetCurrentValue(SelectedChangesProperty, [row.Change]); + break; + } + } + } + else if (selected.Count > 0) { var sets = new HashSet(); foreach (var c in selected) @@ -346,16 +367,34 @@ namespace SourceGit.Views { var grid = new ViewModels.ChangeCollectionAsGrid(); grid.Changes.AddRange(changes); - if (selected.Count > 0) + + if (!onlyViewModeChange && AutoSelectFirstChange) + { + grid.SelectedChanges.Add(changes[0]); + SetCurrentValue(SelectedChangesProperty, [changes[0]]); + } + else if (selected.Count > 0) + { grid.SelectedChanges.AddRange(selected); + } + Content = grid; } else { var list = new ViewModels.ChangeCollectionAsList(); list.Changes.AddRange(changes); - if (selected.Count > 0) + + if (!onlyViewModeChange && AutoSelectFirstChange) + { + list.SelectedChanges.Add(changes[0]); + SetCurrentValue(SelectedChangesProperty, [changes[0]]); + } + else if (selected.Count > 0) + { list.SelectedChanges.AddRange(selected); + } + Content = list; } diff --git a/src/Views/CommitChanges.axaml b/src/Views/CommitChanges.axaml index 377be944..2fac9365 100644 --- a/src/Views/CommitChanges.axaml +++ b/src/Views/CommitChanges.axaml @@ -49,6 +49,7 @@ ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=CommitChangeViewMode}" Changes="{Binding VisibleChanges}" SelectedChanges="{Binding SelectedChanges, Mode=TwoWay}" + AutoSelectFirstChange="True" ContextRequested="OnChangeContextRequested"/> diff --git a/src/Views/CreateBranch.axaml b/src/Views/CreateBranch.axaml index dff42516..ec56ff20 100644 --- a/src/Views/CreateBranch.axaml +++ b/src/Views/CreateBranch.axaml @@ -32,7 +32,7 @@ - + diff --git a/src/Views/DiffView.axaml b/src/Views/DiffView.axaml index fccb949d..3644f8fc 100644 --- a/src/Views/DiffView.axaml +++ b/src/Views/DiffView.axaml @@ -37,7 +37,6 @@