From ee70be41a8952825d109f2f108adfe9440d6ba9d Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 15 Dec 2025 11:42:08 +0800 Subject: [PATCH 01/51] project: Update third-party dependencies - Upgrade `OpenAI` to `2.8.0` - Upgrade `Azure.AI.OpenAI` to `2.8.0-beta.1` - Upgrade `Pfim` to `0.11.4` Signed-off-by: leo --- THIRD-PARTY-LICENSES.md | 6 +++--- src/SourceGit.csproj | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/THIRD-PARTY-LICENSES.md b/THIRD-PARTY-LICENSES.md index 49de958a6..5c696b1ba 100644 --- a/THIRD-PARTY-LICENSES.md +++ b/THIRD-PARTY-LICENSES.md @@ -35,14 +35,14 @@ The project uses the following third-party libraries or assets ### OpenAI .NET SDK - **Source**: https://github.com/openai/openai-dotnet -- **Version**: 2.5.0 +- **Version**: 2.8.0 - **License**: MIT License - **License Link**: https://github.com/openai/openai-dotnet/blob/main/LICENSE ### Azure.AI.OpenAI - **Source**: https://github.com/Azure/azure-sdk-for-net -- **Version**: 2.5.0-beta.1 +- **Version**: 2.8.0-beta.1 - **License**: MIT License - **License Link**: https://github.com/Azure/azure-sdk-for-net/blob/main/LICENSE.txt @@ -56,7 +56,7 @@ The project uses the following third-party libraries or assets ### Pfim - **Source**: https://github.com/nickbabcock/Pfim -- **Version**: 0.11.3 +- **Version**: 0.11.4 - **License**: MIT License - **License Link**: https://github.com/nickbabcock/Pfim/blob/master/LICENSE.txt diff --git a/src/SourceGit.csproj b/src/SourceGit.csproj index 9cc5c3f76..34f2c0163 100644 --- a/src/SourceGit.csproj +++ b/src/SourceGit.csproj @@ -51,12 +51,12 @@ - + - - + + From 5ef607244a676adbf5fcdaa8e305b180e0888a36 Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 15 Dec 2025 11:54:17 +0800 Subject: [PATCH 02/51] feature: supports `R16F` and `R32F` dds image Signed-off-by: leo --- src/ViewModels/ImageSource.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ViewModels/ImageSource.cs b/src/ViewModels/ImageSource.cs index 5f0c88dd9..2f9bdf420 100644 --- a/src/ViewModels/ImageSource.cs +++ b/src/ViewModels/ImageSource.cs @@ -108,6 +108,12 @@ private static ImageSource DecodeWithPfim(Stream stream, long size) case ImageFormat.Rgb8: pixelFormat = PixelFormats.Gray8; break; + case ImageFormat.R16f: + pixelFormat = PixelFormats.Gray16; + break; + case ImageFormat.R32f: + pixelFormat = PixelFormats.Gray32Float; + break; case ImageFormat.R5g5b5: pixelFormat = PixelFormats.Bgr555; break; From 76e3df6d8dd39cf98e77b2fa5b27e1102b8644dc Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 15 Dec 2025 12:33:00 +0800 Subject: [PATCH 03/51] fix: wrong diff arguments for xcode `FileMerge` (#1979) Signed-off-by: leo --- src/Models/ExternalMerger.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Models/ExternalMerger.cs b/src/Models/ExternalMerger.cs index ce90a7d44..655a1d58a 100644 --- a/src/Models/ExternalMerger.cs +++ b/src/Models/ExternalMerger.cs @@ -50,7 +50,7 @@ static ExternalMerger() { Supported = new List() { new ExternalMerger("git", "Use Git Settings", "", "", ""), - new ExternalMerger("xcode", "FileMerge", "/usr/bin/opendiff", "\"$BASE\" \"$LOCAL\" \"$REMOTE\" -ancestor \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), + new ExternalMerger("xcode", "FileMerge", "/usr/bin/opendiff", "\"$LOCAL\" \"$REMOTE\" -ancestor \"$BASE\" -merge \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), new ExternalMerger("vscode", "Visual Studio Code", "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""), new ExternalMerger("vscode_insiders", "Visual Studio Code - Insiders", "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""), new ExternalMerger("kdiff3", "KDiff3", "/Applications/kdiff3.app/Contents/MacOS/kdiff3", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""), From 99c7e384b5083128cc5f521bc7b6ca91bb5d2161 Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 15 Dec 2025 14:39:45 +0800 Subject: [PATCH 04/51] refactor: rework `Merge` popup (#1973) - Hide `Customize merge message` option when selected `Squash` or `Don't commit` mode. - Read `$GIT_DIR/SQUASH_MSG` after merging with `Squash` mode - Clear commit message after discarding all changes - Cleanup code Signed-off-by: leo --- src/ViewModels/AIAssistant.cs | 9 +++----- src/ViewModels/Discard.cs | 5 +++++ src/ViewModels/Merge.cs | 30 +++++++++++++++++++++---- src/ViewModels/Repository.cs | 6 +++++ src/Views/CommitMessageToolBox.axaml.cs | 4 ++-- src/Views/Merge.axaml | 3 ++- src/Views/WorkingCopy.axaml.cs | 4 ++-- 7 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/ViewModels/AIAssistant.cs b/src/ViewModels/AIAssistant.cs index 920fafcf5..d538ce1b5 100644 --- a/src/ViewModels/AIAssistant.cs +++ b/src/ViewModels/AIAssistant.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -23,12 +22,11 @@ public string Text private set => SetProperty(ref _text, value); } - public AIAssistant(Repository repo, Models.OpenAIService service, List changes, Action onApply) + public AIAssistant(Repository repo, Models.OpenAIService service, List changes) { _repo = repo; _service = service; _changes = changes; - _onApply = onApply; _cancel = new CancellationTokenSource(); Gen(); @@ -44,7 +42,7 @@ public void Regen() public void Apply() { - _onApply?.Invoke(Text); + _repo.SetCommitMessage(Text); } public void Cancel() @@ -72,7 +70,6 @@ private void Gen() private readonly Repository _repo = null; private Models.OpenAIService _service = null; private List _changes = null; - private Action _onApply = null; private CancellationTokenSource _cancel = null; private bool _isGenerating = false; private string _text = string.Empty; diff --git a/src/ViewModels/Discard.cs b/src/ViewModels/Discard.cs index 99c225b9d..78c7b4bd6 100644 --- a/src/ViewModels/Discard.cs +++ b/src/ViewModels/Discard.cs @@ -71,9 +71,14 @@ public override async Task Sure() Use(log); if (Mode is DiscardAllMode all) + { await Commands.Discard.AllAsync(_repo.FullPath, all.IncludeUntracked, all.IncludeIgnored, log); + _repo.ClearCommitMessage(); + } else + { await Commands.Discard.ChangesAsync(_repo.FullPath, _changes, log); + } log.Complete(); _repo.MarkWorkingCopyDirtyManually(); diff --git a/src/ViewModels/Merge.cs b/src/ViewModels/Merge.cs index 612eb6311..28bc9d8d7 100644 --- a/src/ViewModels/Merge.cs +++ b/src/ViewModels/Merge.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.IO; +using System.Threading.Tasks; namespace SourceGit.ViewModels { @@ -16,8 +17,20 @@ public string Into public Models.MergeMode Mode { - get; - set; + get => _mode; + set + { + if (SetProperty(ref _mode, value)) + CanEditMessage = _mode == Models.MergeMode.Default || + _mode == Models.MergeMode.FastForward || + _mode == Models.MergeMode.NoFastForward; + } + } + + public bool CanEditMessage + { + get => _canEditMessage; + set => SetProperty(ref _canEditMessage, value); } public bool Edit @@ -65,12 +78,19 @@ public override async Task Sure() var log = _repo.CreateLog($"Merging '{_sourceName}' into '{Into}'"); Use(log); - var succ = await new Commands.Merge(_repo.FullPath, _sourceName, Mode.Arg, Edit) + var succ = await new Commands.Merge(_repo.FullPath, _sourceName, Mode.Arg, _canEditMessage && Edit) .Use(log) .ExecAsync(); if (succ) { + var squashMsgFile = Path.Combine(_repo.GitDir, "SQUASH_MSG"); + if (Mode == Models.MergeMode.Squash && File.Exists(squashMsgFile)) + { + var msg = await File.ReadAllTextAsync(squashMsgFile); + _repo.SetCommitMessage(msg); + } + var submodules = await new Commands.QueryUpdatableSubmodules(_repo.FullPath).GetResultAsync(); if (submodules.Count > 0) await new Commands.Submodule(_repo.FullPath) @@ -113,5 +133,7 @@ private Models.MergeMode AutoSelectMergeMode() private readonly Repository _repo = null; private readonly string _sourceName; + private Models.MergeMode _mode = Models.MergeMode.Default; + private bool _canEditMessage = true; } } diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index 3f8c26ee8..e90ad246c 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -888,6 +888,12 @@ public void NavigateToCommit(string sha, bool isDelayMode = false) } } + public void SetCommitMessage(string message) + { + if (_workingCopy is not null) + _workingCopy.CommitMessage = message; + } + public void ClearCommitMessage() { if (_workingCopy is not null) diff --git a/src/Views/CommitMessageToolBox.axaml.cs b/src/Views/CommitMessageToolBox.axaml.cs index 8bc41b991..01451e942 100644 --- a/src/Views/CommitMessageToolBox.axaml.cs +++ b/src/Views/CommitMessageToolBox.axaml.cs @@ -505,7 +505,7 @@ private async void OnOpenOpenAIHelper(object sender, RoutedEventArgs e) if (services.Count == 1) { - await App.ShowDialog(new ViewModels.AIAssistant(repo, services[0], vm.Staged, t => vm.CommitMessage = t)); + await App.ShowDialog(new ViewModels.AIAssistant(repo, services[0], vm.Staged)); return; } @@ -517,7 +517,7 @@ private async void OnOpenOpenAIHelper(object sender, RoutedEventArgs e) item.Header = service.Name; item.Click += async (_, ev) => { - await App.ShowDialog(new ViewModels.AIAssistant(repo, dup, vm.Staged, t => vm.CommitMessage = t)); + await App.ShowDialog(new ViewModels.AIAssistant(repo, dup, vm.Staged)); ev.Handled = true; }; diff --git a/src/Views/Merge.axaml b/src/Views/Merge.axaml index dffcc6fd9..5ceb93ff7 100644 --- a/src/Views/Merge.axaml +++ b/src/Views/Merge.axaml @@ -19,7 +19,7 @@ Text="{DynamicResource Text.Merge}"/> - + diff --git a/src/Views/WorkingCopy.axaml.cs b/src/Views/WorkingCopy.axaml.cs index b786b0d9e..5840d247a 100644 --- a/src/Views/WorkingCopy.axaml.cs +++ b/src/Views/WorkingCopy.axaml.cs @@ -890,7 +890,7 @@ public ContextMenu CreateContextMenuForStagedChanges(ViewModels.WorkingCopy vm, { ai.Click += async (_, e) => { - await App.ShowDialog(new ViewModels.AIAssistant(repo, services[0], selectedStaged, t => vm.CommitMessage = t)); + await App.ShowDialog(new ViewModels.AIAssistant(repo, services[0], selectedStaged)); e.Handled = true; }; } @@ -904,7 +904,7 @@ public ContextMenu CreateContextMenuForStagedChanges(ViewModels.WorkingCopy vm, item.Header = service.Name; item.Click += async (_, e) => { - await App.ShowDialog(new ViewModels.AIAssistant(repo, dup, selectedStaged, t => vm.CommitMessage = t)); + await App.ShowDialog(new ViewModels.AIAssistant(repo, dup, selectedStaged)); e.Handled = true; }; From 2e20b0e328e3ec38672d6b1ffade280defe802b0 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 16 Dec 2025 17:28:22 +0800 Subject: [PATCH 05/51] enhance: when a private key is given, do not read default ssh configuration Signed-off-by: leo --- src/Commands/Command.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Commands/Command.cs b/src/Commands/Command.cs index 520f19703..e6e64f054 100644 --- a/src/Commands/Command.cs +++ b/src/Commands/Command.cs @@ -181,7 +181,7 @@ protected ProcessStartInfo CreateGitStartInfo(bool redirect) // If an SSH private key was provided, sets the environment. if (!start.Environment.ContainsKey("GIT_SSH_COMMAND") && !string.IsNullOrEmpty(SSHKey)) - start.Environment.Add("GIT_SSH_COMMAND", $"ssh -i '{SSHKey}'"); + start.Environment.Add("GIT_SSH_COMMAND", $"ssh -i '{SSHKey}' -F '/dev/null'"); // Force using en_US.UTF-8 locale if (OperatingSystem.IsLinux()) From 9f9b8f30c389bdae6e71d904db4d300856051fc4 Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 17 Dec 2025 10:38:11 +0800 Subject: [PATCH 06/51] enhance: auto select tracking branch after `Tracking remote branch` option is toggled while creating worktree (#1983) Signed-off-by: leo --- src/ViewModels/AddWorktree.cs | 31 ++++++++++++++++++++++++------- src/Views/AddWorktree.axaml | 7 +++++-- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/ViewModels/AddWorktree.cs b/src/ViewModels/AddWorktree.cs index 7679b4509..a1985d51f 100644 --- a/src/ViewModels/AddWorktree.cs +++ b/src/ViewModels/AddWorktree.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.IO; using System.Threading.Tasks; @@ -51,7 +52,11 @@ public string SelectedBranch public bool SetTrackingBranch { get => _setTrackingBranch; - set => SetProperty(ref _setTrackingBranch, value); + set + { + if (SetProperty(ref _setTrackingBranch, value)) + AutoSelectTrackingBranch(); + } } public string SelectedTrackingBranch @@ -73,11 +78,6 @@ public AddWorktree(Repository repo) else RemoteBranches.Add(branch.FriendlyName); } - - if (RemoteBranches.Count > 0) - SelectedTrackingBranch = RemoteBranches[0]; - else - SelectedTrackingBranch = string.Empty; } public static ValidationResult ValidateWorktreePath(string path, ValidationContext ctx) @@ -123,6 +123,23 @@ public override async Task Sure() return succ; } + private void AutoSelectTrackingBranch() + { + if (!_setTrackingBranch || RemoteBranches.Count == 0) + return; + + var name = string.IsNullOrEmpty(_selectedBranch) ? System.IO.Path.GetFileName(_path.TrimEnd('/', '\\')) : _selectedBranch; + var remoteBranch = RemoteBranches.Find(b => b.Substring(b.IndexOf('/') + 1).Equals(name, StringComparison.Ordinal)); + if (string.IsNullOrEmpty(remoteBranch)) + remoteBranch = RemoteBranches[0]; + + if (!remoteBranch.Equals(SelectedTrackingBranch, StringComparison.Ordinal)) + { + SelectedTrackingBranch = remoteBranch; + OnPropertyChanged(nameof(SelectedTrackingBranch)); + } + } + private Repository _repo = null; private string _path = string.Empty; private bool _createNewBranch = true; diff --git a/src/Views/AddWorktree.axaml b/src/Views/AddWorktree.axaml index 5ca70d9b2..6fcc546ec 100644 --- a/src/Views/AddWorktree.axaml +++ b/src/Views/AddWorktree.axaml @@ -3,6 +3,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="using:SourceGit.ViewModels" + xmlns:c="using:SourceGit.Converters" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="SourceGit.Views.AddWorktree" x:DataType="vm:AddWorktree"> @@ -17,7 +18,7 @@ Text="{DynamicResource Text.AddWorktree}"/> - + + IsChecked="{Binding SetTrackingBranch, Mode=TwoWay}" + IsVisible="{Binding RemoteBranches, Converter={x:Static c:ListConverters.IsNotNullOrEmpty}}"/> From 503ac5b42cb6b42e193c98bb43f846cba2830fb1 Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 17 Dec 2025 10:47:04 +0800 Subject: [PATCH 07/51] refactor: use `EndsWith` instead of `Equals` to auto-find the tracking branch while creating worktree (#1983) Signed-off-by: leo --- src/ViewModels/AddWorktree.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ViewModels/AddWorktree.cs b/src/ViewModels/AddWorktree.cs index a1985d51f..5c7b21d25 100644 --- a/src/ViewModels/AddWorktree.cs +++ b/src/ViewModels/AddWorktree.cs @@ -129,7 +129,7 @@ private void AutoSelectTrackingBranch() return; var name = string.IsNullOrEmpty(_selectedBranch) ? System.IO.Path.GetFileName(_path.TrimEnd('/', '\\')) : _selectedBranch; - var remoteBranch = RemoteBranches.Find(b => b.Substring(b.IndexOf('/') + 1).Equals(name, StringComparison.Ordinal)); + var remoteBranch = RemoteBranches.Find(b => b.EndsWith(name, StringComparison.Ordinal)); if (string.IsNullOrEmpty(remoteBranch)) remoteBranch = RemoteBranches[0]; From 2c968e4ca4c849530f5054564e3d3acb28d1f6e6 Mon Sep 17 00:00:00 2001 From: ybeapps Date: Wed, 17 Dec 2025 11:02:18 +0200 Subject: [PATCH 08/51] doc: update README.md - Mac app is signed now via homebrew (#1985) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eb370c3c6..7eab03f42 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ For **macOS** users: * Thanks [@ybeapps](https://github.com/ybeapps) for making `SourceGit` available on `Homebrew`. You can simply install it with following command: ```shell brew tap ybeapps/homebrew-sourcegit - brew install --cask --no-quarantine sourcegit + brew install --cask sourcegit ``` * If you want to install `SourceGit.app` from GitHub Release manually, you need run following command to make sure it works: ```shell From cf528d6b96d5cde0778ba3b9de5f0fa3b1805427 Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 18 Dec 2025 10:29:05 +0800 Subject: [PATCH 09/51] doc: update README.md for macOS users (#1988) Signed-off-by: leo --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 7eab03f42..05bd7a46b 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,9 @@ For **macOS** users: ```shell sudo xattr -cr /Applications/SourceGit.app ``` +> [!NOTE] +> macOS packages in the `Release` page of this project are all unsigned. If you are worried about potential security issues with the above command, you can download the signed package from the [distribution repository](https://github.com/ybeapps/homebrew-sourcegit/releases) provided by [@ybeapps](https://github.com/ybeapps) (there is no need to execute the above command while installing `SourceGit`). + * Make sure [git-credential-manager](https://github.com/git-ecosystem/git-credential-manager/releases) is installed on your mac. * You can run `echo $PATH > ~/Library/Application\ Support/SourceGit/PATH` to generate a custom PATH env file to introduce `PATH` env to SourceGit. From f7836c05930f3d3f364ed6f189e5038bcfb6aebd Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 18 Dec 2025 14:03:34 +0800 Subject: [PATCH 10/51] ux: prevent non-auto-hide scrollbar overlap contents (#1980) (#1794) Signed-off-by: leo --- src/Resources/Styles.axaml | 194 +++++++++++++++++++++++++++++++-- src/Views/BranchTree.axaml | 3 +- src/Views/Histories.axaml | 19 +++- src/Views/SubmodulesView.axaml | 6 +- src/Views/TagsView.axaml | 6 +- 5 files changed, 210 insertions(+), 18 deletions(-) diff --git a/src/Resources/Styles.axaml b/src/Resources/Styles.axaml index 651bc9505..6294cdd9a 100644 --- a/src/Resources/Styles.axaml +++ b/src/Resources/Styles.axaml @@ -13,16 +13,6 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Views/SubmodulesView.axaml b/src/Views/SubmodulesView.axaml index 963ae1b65..ddc70f3c2 100644 --- a/src/Views/SubmodulesView.axaml +++ b/src/Views/SubmodulesView.axaml @@ -10,7 +10,7 @@ x:Class="SourceGit.Views.SubmodulesView"> - + +