Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
1b6f636
Merge branch 'master' into develop
love-linger Jun 29, 2026
01f55f7
ux: new style for page switcher in repository
love-linger Jun 29, 2026
1e25529
fix: escape BRE special characters when selecting author from suggest…
JC-Chung Jun 29, 2026
70dec95
code_review: PR #2494
love-linger Jun 29, 2026
5d8a934
refactor: move recent commit messages from repository settings to ui-…
love-linger Jun 29, 2026
bdcf335
refactor: reorder context menu items of selected branch
love-linger Jun 29, 2026
190b4d9
fix: let the diff view wake up before its first curtain call (#2496)
gadfly3173 Jun 30, 2026
e6b96d9
fix: versions of `git` prior to v2.45.0 will reject a value of `comme…
love-linger Jun 30, 2026
fe99f4a
ux: max height of group list in `Move Repository Node` popup (#2502)
love-linger Jul 1, 2026
b4201ed
fix: null check for RevisionFileSearchSuggestion on key down (#2501)
JC-Chung Jul 1, 2026
bb9a360
fix: prevent crash in Chart.Render when repository has no commits (#2…
JC-Chung Jul 1, 2026
f3fd2f6
refactor: do not render chart if no commit collected in statistics
love-linger Jul 1, 2026
dd163e5
fix: hide file manager and terminal options for invalid repositories …
JC-Chung Jul 1, 2026
cb1664f
code_review: PR #2503
love-linger Jul 1, 2026
80ca735
ux: default select the `ROOT` group in `Move Repository Node` popup (…
love-linger Jul 1, 2026
324e4af
refactor: change the `Open Local Repository` hotkey to `Ctrl+L` on Wi…
love-linger Jul 1, 2026
06e2fdc
ux!: change the hotkeys to clone/open repository
love-linger Jul 2, 2026
4a8276f
feature: add hotkey `Ctrl+N` to open commit details panel in a sepera…
love-linger Jul 2, 2026
34f4a7c
refactor: use `*` instead `*.*` to choose file without specified exte…
love-linger Jul 2, 2026
49f6dd5
ux: style for search panel in text editor
love-linger Jul 3, 2026
9fea665
ux: dropdown menu position
love-linger Jul 3, 2026
2aeb335
localization: update Spanish translation (#2510)
jjesus-dev Jul 5, 2026
a6be30c
doc: Update translation status and sort locale files
github-actions[bot] Jul 5, 2026
2750812
localization: update Russian translate (#2514)
AquariusStar Jul 6, 2026
37d9c47
doc: Update translation status and sort locale files
github-actions[bot] Jul 6, 2026
673a66f
localization: complete Greek (el_GR) translation (#2515)
teras Jul 6, 2026
2ea100f
doc: Update translation status and sort locale files
github-actions[bot] Jul 6, 2026
222cd80
ux: use `Ctrl/⌘+W` to close sub-windows
love-linger Jul 6, 2026
7327ccd
localization: update Chinese translations
love-linger Jul 6, 2026
e6bf4b9
doc: Update translation status and sort locale files
github-actions[bot] Jul 6, 2026
6077e54
project: upgrade AvaloniaEdit
love-linger Jul 6, 2026
68d1347
fix: diff view does not update when selecting between an unstage new …
love-linger Jul 6, 2026
2a12e04
ux: submodule diff style
love-linger Jul 6, 2026
ed9ec47
refactor: improve submodule diff loading
love-linger Jul 7, 2026
c0dc434
enhance: do not query file content if revision is an empty tree hash
love-linger Jul 7, 2026
7c62df1
refactor: creating diff object for image/binary/submodule
love-linger Jul 8, 2026
bf7892f
project: add .tss to .gitignore (#2520)
ghiboz Jul 8, 2026
9d01953
code_style: remove unnecessary spaces at end of line
love-linger Jul 9, 2026
4033af1
localization: update Traditional Chinese translations (#2526)
ChiahongHong Jul 13, 2026
8f75493
version: Release 2026.15
love-linger Jul 13, 2026
7149a8d
Merge branch 'release/v2026.15'
love-linger Jul 13, 2026
798a138
Merge branch 'master' into develop
skoonin Jul 13, 2026
dcdd27e
version: start 2026.17-sk-dev
skoonin Jul 13, 2026
07e7312
Sync upstream v2026.15 into develop (#9)
skoonin Jul 24, 2026
6f70007
Merge upstream/master (v2026.15) into develop
skoonin Jul 24, 2026
49fd7d8
version: Release 2026.17-sk
skoonin Jul 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*.user
*.suo
*.code-workspace
*.tss

.DS_Store
.DocumentRevisions-V100
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

Fork releases of SourceGit-SK. Upstream changes arrive through upstream release merges and are documented in the [upstream release notes](https://github.com/sourcegit-scm/sourcegit/releases).

## [2026.17-sk] - 2026-07-24

### Changed

- Merged upstream [v2026.15](https://github.com/sourcegit-scm/sourcegit/releases/tag/v2026.15) into the fork, bringing upstream's fixes and improvements while keeping all fork customizations ([#9](https://github.com/skoonin/sourcegit-sk/pull/9))

## [2026.16-sk] - 2026-07-12

### Added
Expand Down Expand Up @@ -32,5 +38,6 @@ First fork release, based on upstream [v2026.14](https://github.com/sourcegit-sc
- Version numbers carry an `-sk` suffix (shown in the About dialog) to distinguish fork releases from upstream builds.
- The update check and release links point at this fork's releases instead of upstream's, so new `-sk` releases are detected and offered ([#2](https://github.com/skoonin/sourcegit-sk/pull/2))

[2026.17-sk]: https://github.com/skoonin/sourcegit-sk/releases/tag/v2026.17-sk
[2026.16-sk]: https://github.com/skoonin/sourcegit-sk/releases/tag/v2026.16-sk
[2026.15-sk]: https://github.com/skoonin/sourcegit-sk/releases/tag/v2026.15-sk
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
# GitHub Actions are disabled in this repository; `make check` is the local CI gate.

DOTNET ?= $(shell command -v dotnet 2>/dev/null || echo $(HOME)/.local/share/dotnet/dotnet)
# Avalonia's build-time stats task writes to ~/Library/Application Support/AvaloniaUI;
# that write fails in restricted/sandboxed environments and breaks the build. Opt out to
# keep builds hermetic. Only affects build telemetry, not the app.
export AVALONIA_TELEMETRY_OPTOUT := true
# Lazy so only the app target shells out for the version.
VERSION = $(shell cat VERSION)
RUNTIME ?= osx-arm64
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@
[![latest](https://img.shields.io/github/v/release/sourcegit-scm/sourcegit.svg)](https://github.com/sourcegit-scm/sourcegit/releases/latest)
[![downloads](https://img.shields.io/github/downloads/sourcegit-scm/sourcegit/total)](https://github.com/sourcegit-scm/sourcegit/releases)

## Fork customizations (SourceGit-SK)

This is a personal fork of [sourcegit-scm/sourcegit](https://github.com/sourcegit-scm/sourcegit) that tracks upstream and adds the changes below. These are specific to this fork and are not part of upstream SourceGit. See [CHANGELOG.md](CHANGELOG.md) for the full history.

* **Stacked multi-file diff** across every change view (working copy, commit details, compare, revision compare, submodule compare, stashes): with no file selected the whole change set shows as one scrollable diff; selecting several files stacks those; selecting one shows a single file. Includes a shared toolbar, file navigation, and per-file context controls.
* **Recent-commits block in the repository sidebar**, showing the full commit graph.
* **Bracket tab switching**: Cmd+Shift+[ / Cmd+Shift+] on macOS (Ctrl+Shift on Windows/Linux) moves between tabs; the existing bindings still work.
* **"Open Another Repository..."** entry in the repository switcher (Ctrl/Cmd+P) opens a folder picker for a repo not yet in the list.
* **Fork versioning**: releases carry an `-sk` suffix (shown in the About dialog), and the update check points at this fork's releases instead of upstream's.

## Screenshots

* Dark Theme
Expand Down
66 changes: 5 additions & 61 deletions TRANSLATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,79 +125,37 @@ This document shows the translation status of each locale file in the repository

</details>

### ![el__GR](https://img.shields.io/badge/el__GR-96.20%25-yellow)
### ![el__GR](https://img.shields.io/badge/el__GR-99.12%25-yellow)

<details>
<summary>Missing keys in el_GR.axaml</summary>

- Text.Apply.Source
- Text.Apply.Source.File
- Text.Apply.Source.Clipboard
- Text.Bisect.WaitingForCheckoutAnother
- Text.Bisect.WaitingForFirstBad
- Text.CheckoutDetached
- Text.CheckoutDetached.Target
- Text.CheckoutDetached.Warning
- Text.Configure.Git.EnableRecursiveWhenAutoUpdatingSubmodules
- Text.CopyAsPatch
- Text.DeleteBranch.AskForRemote
- Text.DeleteBranch.Force
- Text.Diff.AndMoreFiles
- Text.Diff.EmptyFile
- Text.Diff.FilesCount
- Text.Diff.FirstFile
- Text.Diff.LargeDiffHint
- Text.Diff.LastFile
- Text.Diff.NextFile
- Text.Diff.PrevFile
- Text.FileModeChange
- Text.FileModeChange.Deleted
- Text.FileModeChange.Directory
- Text.FileModeChange.Executable
- Text.FileModeChange.New
- Text.FileModeChange.Normal
- Text.FileModeChange.Submodule
- Text.FileModeChange.Symlink
- Text.FileModeChange.Unknown
- Text.GitFlow.Finish
- Text.GitFlow.FinishWithRebase
- Text.GitFlow.StartAt
- Text.GitFlow.StartName
- Text.Launcher.OpenOtherRepository
- Text.Repository.Commits
- Text.TagCM.Checkout
- Text.TagCM.Merge
- Text.UpdateSubmodules.Recursive
- Text.WorkingCopy.AddToGitIgnore.UntrackedInSameFolder

</details>

### ![es__ES](https://img.shields.io/badge/es__ES-97.96%25-yellow)
### ![es__ES](https://img.shields.io/badge/es__ES-99.12%25-yellow)

<details>
<summary>Missing keys in es_ES.axaml</summary>

- Text.DeleteBranch.AskForRemote
- Text.DeleteBranch.Force
- Text.Diff.AndMoreFiles
- Text.Diff.FilesCount
- Text.Diff.FirstFile
- Text.Diff.LargeDiffHint
- Text.Diff.LastFile
- Text.Diff.NextFile
- Text.Diff.PrevFile
- Text.FileModeChange
- Text.FileModeChange.Deleted
- Text.FileModeChange.Directory
- Text.FileModeChange.Executable
- Text.FileModeChange.New
- Text.FileModeChange.Normal
- Text.FileModeChange.Submodule
- Text.FileModeChange.Symlink
- Text.FileModeChange.Unknown
- Text.Launcher.OpenOtherRepository
- Text.Repository.Commits
- Text.WorkingCopy.AddToGitIgnore.UntrackedInSameFolder

</details>

Expand Down Expand Up @@ -1086,32 +1044,20 @@ This document shows the translation status of each locale file in the repository

</details>

### ![ru__RU](https://img.shields.io/badge/ru__RU-97.96%25-yellow)
### ![ru__RU](https://img.shields.io/badge/ru__RU-99.12%25-yellow)

<details>
<summary>Missing keys in ru_RU.axaml</summary>

- Text.DeleteBranch.AskForRemote
- Text.DeleteBranch.Force
- Text.Diff.AndMoreFiles
- Text.Diff.FilesCount
- Text.Diff.FirstFile
- Text.Diff.LargeDiffHint
- Text.Diff.LastFile
- Text.Diff.NextFile
- Text.Diff.PrevFile
- Text.FileModeChange
- Text.FileModeChange.Deleted
- Text.FileModeChange.Directory
- Text.FileModeChange.Executable
- Text.FileModeChange.New
- Text.FileModeChange.Normal
- Text.FileModeChange.Submodule
- Text.FileModeChange.Symlink
- Text.FileModeChange.Unknown
- Text.Launcher.OpenOtherRepository
- Text.Repository.Commits
- Text.WorkingCopy.AddToGitIgnore.UntrackedInSameFolder

</details>

Expand Down Expand Up @@ -1857,12 +1803,11 @@ This document shows the translation status of each locale file in the repository

</details>

### ![zh__CN](https://img.shields.io/badge/zh__CN-99.03%25-yellow)
### ![zh__CN](https://img.shields.io/badge/zh__CN-99.12%25-yellow)

<details>
<summary>Missing keys in zh_CN.axaml</summary>

- Text.DeleteBranch.AskForRemote
- Text.Diff.AndMoreFiles
- Text.Diff.FilesCount
- Text.Diff.FirstFile
Expand All @@ -1875,12 +1820,11 @@ This document shows the translation status of each locale file in the repository

</details>

### ![zh__TW](https://img.shields.io/badge/zh__TW-99.03%25-yellow)
### ![zh__TW](https://img.shields.io/badge/zh__TW-99.12%25-yellow)

<details>
<summary>Missing keys in zh_TW.axaml</summary>

- Text.DeleteBranch.AskForRemote
- Text.Diff.AndMoreFiles
- Text.Diff.FilesCount
- Text.Diff.FirstFile
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2026.16-sk
2026.17-sk
2 changes: 1 addition & 1 deletion depends/AvaloniaEdit
12 changes: 12 additions & 0 deletions src/App.Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ public static string Escaped(this string value)
return value.Replace("\"", "\\\"", StringComparison.Ordinal);
}

public static string EscapeForBRE(this string value)
{
return value
.Replace("\\", "\\\\", StringComparison.Ordinal)
.Replace(".", "\\.", StringComparison.Ordinal)
.Replace("[", "\\[", StringComparison.Ordinal)
.Replace("*", "\\*", StringComparison.Ordinal)
.Replace("^", "\\^", StringComparison.Ordinal)
.Replace("$", "\\$", StringComparison.Ordinal)
.Replace("{", "\\{", StringComparison.Ordinal);
}

public static string FormatFontNames(string input)
{
if (string.IsNullOrEmpty(input))
Expand Down
30 changes: 27 additions & 3 deletions src/Commands/Diff.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public partial class Diff : Command
private const string SPECIAL_DIFF_START = "diff ";
private const string SPECIAL_BINARY = "Binary files ";
private const string SPECIAL_NO_NEWLINE = " No newline at end of file";
private const string SPECIAL_SUBMODULE = "Subproject commit ";

public Diff(string repo, Models.DiffOption opt, int numContextLines, bool ignoreWhitespace, bool ignoreCRAtEOL)
{
Expand Down Expand Up @@ -92,7 +93,7 @@ public Diff(string repo, Models.DiffOption opt, int numContextLines, bool ignore
// Ignore exceptions.
}

if (_result.IsBinary || _result.IsLFS || _result.TextDiff.Lines.Count == 0)
if (_isLFS || _result.IsBinary || _result.TextDiff.Lines.Count == 0)
{
_result.TextDiff = null;
}
Expand All @@ -104,6 +105,28 @@ public Diff(string repo, Models.DiffOption opt, int numContextLines, bool ignore
_isInChunk = false;
}

if (_result.TextDiff.Lines.Count < 4)
{
var isSubmoduleChange = true;

for (int i = 1; i < _result.TextDiff.Lines.Count; i++)
{
var line = _result.TextDiff.Lines[i];
if (!line.Content.StartsWith(SPECIAL_SUBMODULE, StringComparison.Ordinal))
{
isSubmoduleChange = false;
break;
}
}

if (isSubmoduleChange)
{
_result.IsSubmoduleChange = true;
_result.TextDiff = null;
return _result;
}
}

_result.TextDiff.MaxLineNumber = Math.Max(_newLine, _oldLine);
_result.TextDiff.OldMode = _result.OldMode;
_result.TextDiff.NewMode = _result.NewMode;
Expand Down Expand Up @@ -254,7 +277,7 @@ private bool ParseFileModeChange(string line)

private bool ParseLFSChange(char prefix, string content)
{
if (_result.IsLFS)
if (_isLFS)
{
if (prefix == PREFIX_DELETED)
{
Expand Down Expand Up @@ -284,7 +307,7 @@ private bool ParseLFSChange(char prefix, string content)
{
if (content.StartsWith(LFS_SPECIFIER, StringComparison.Ordinal))
{
_result.IsLFS = true;
_isLFS = true;
_result.LFSDiff = new Models.LFSDiff();
return true;
}
Expand Down Expand Up @@ -340,5 +363,6 @@ private void ProcessInlineHighlights()
private int _oldLine = 0;
private int _newLine = 0;
private bool _isInChunk = false;
private bool _isLFS = false;
}
}
2 changes: 1 addition & 1 deletion src/Commands/InteractiveRebase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public InteractiveRebase(string repo, string basedOn, bool autoStash, bool noVer
Editor = EditorType.RebaseEditor;

var builder = new StringBuilder(512);
builder.Append("-c core.commentChar=± rebase -i --autosquash ");
builder.Append("-c core.commentChar=\"^\" -c core.commentString=\"±\" rebase -i --autosquash ");
if (autoStash)
builder.Append("--autostash ");
if (noVerify)
Expand Down
67 changes: 67 additions & 0 deletions src/Commands/QuerySubmoduleRevision.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using System.Threading.Tasks;

namespace SourceGit.Commands
{
public class QuerySubmoduleRevision : Command
{
public QuerySubmoduleRevision(string repo, string revision)
{
WorkingDirectory = repo;
Context = repo;

if (revision.EndsWith("-dirty", StringComparison.Ordinal))
{
_hasUncommittedChange = true;
_revision = revision.Substring(0, revision.Length - 6);
}
else
{
_hasUncommittedChange = false;
_revision = revision;
}
}

public async Task<Models.RevisionSubmodule> GetResultAsync()
{
Args = $"show --no-show-signature --decorate=full --format=%H%x00%P%x00%D%x00%aN±%aE%x00%at%x00%cN±%cE%x00%ct%x00%s%x00%B -s {_revision}";

var rs = await ReadToEndAsync().ConfigureAwait(false);
if (!rs.IsSuccess || string.IsNullOrEmpty(rs.StdOut))
return null;

var commit = new Models.Commit();
var lines = rs.StdOut.Split('\0');
if (lines.Length < 9)
return null;

commit.SHA = lines[0];
if (!string.IsNullOrEmpty(lines[1]))
commit.Parents.AddRange(lines[1].Split(' ', StringSplitOptions.RemoveEmptyEntries));
if (!string.IsNullOrEmpty(lines[2]))
commit.ParseDecorators(lines[2]);
commit.Author = Models.User.FindOrAdd(lines[3]);
commit.AuthorTime = ulong.Parse(lines[4]);
commit.Committer = Models.User.FindOrAdd(lines[5]);
commit.CommitterTime = ulong.Parse(lines[6]);
commit.Subject = lines[7];

var message = new Models.CommitFullMessage() { Message = lines[8].TrimEnd() };
var uncommittedChangesCount = 0;
if (_hasUncommittedChange)
uncommittedChangesCount = await new CountLocalChanges(WorkingDirectory, true)
.GetResultAsync()
.ConfigureAwait(false);

return new Models.RevisionSubmodule()
{
Commit = commit,
FullMessage = message,
UncommittedChanges = uncommittedChangesCount
};
}

private bool _hasUncommittedChange = false;
private string _revision = string.Empty;
}
}
2 changes: 1 addition & 1 deletion src/Commands/Rebase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public Rebase(string repo, string basedOn, bool autoStash, bool noVerify)
Context = repo;

var builder = new StringBuilder(512);
builder.Append("-c core.commentChar=± rebase ");
builder.Append("-c core.commentChar=\"^\" -c core.commentString=\"±\" rebase ");
if (autoStash)
builder.Append("--autostash ");
if (noVerify)
Expand Down
2 changes: 1 addition & 1 deletion src/Models/DiffResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public class SubmoduleDiff
public class DiffResult
{
public bool IsBinary { get; set; } = false;
public bool IsLFS { get; set; } = false;
public bool IsSubmoduleChange { get; set; } = false;
public string OldHash { get; set; } = string.Empty;
public string NewHash { get; set; } = string.Empty;
public int OldMode { get; set; } = 0;
Expand Down
Loading