diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index bcb32580..12792cf6 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -58,7 +58,7 @@ jobs:
if: ${{ matrix.runtime == 'linux-arm64' }}
run: |
sudo apt-get update
- sudo apt-get install -y llvm gcc-aarch64-linux-gnu zlib1g-dev:arm64
+ sudo apt-get install -y llvm gcc-aarch64-linux-gnu
- name: Build
run: dotnet build -c Release
- name: Publish
diff --git a/.github/workflows/localization-check.yml b/.github/workflows/localization-check.yml
index cc5201ab..8dcd61c8 100644
--- a/.github/workflows/localization-check.yml
+++ b/.github/workflows/localization-check.yml
@@ -4,7 +4,6 @@ on:
branches: [ develop ]
paths:
- 'src/Resources/Locales/**'
- - 'README.md'
workflow_dispatch:
workflow_call:
@@ -32,8 +31,8 @@ jobs:
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
if [ -n "$(git status --porcelain)" ]; then
- git add README.md TRANSLATION.md
- git commit -m 'doc: Update translation status and missing keys'
+ git add TRANSLATION.md src/Resources/Locales/*.axaml
+ git commit -m 'doc: Update translation status and sort locale files'
git push
else
echo "No changes to commit"
diff --git a/README.md b/README.md
index 846407f6..50d00f58 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
* Supports Windows/macOS/Linux
* Opensource/Free
* Fast
-* Deutsch/English/Español/Français/Italiano/Português/Русский/简体中文/繁體中文/日本語/தமிழ் (Tamil)
+* Deutsch/English/Español/Français/Italiano/Português/Русский/Українська/简体中文/繁體中文/日本語/தமிழ் (Tamil)
* Built-in light/dark themes
* Customize theme
* Visual commit graph
@@ -35,6 +35,7 @@
* Revision Diffs
* Branch Diff
* Image Diff - Side-By-Side/Swipe/Blend
+* Git command logs
* Search commits
* GitFlow
* Git LFS
diff --git a/TRANSLATION.md b/TRANSLATION.md
index a2991c6e..866aac65 100644
--- a/TRANSLATION.md
+++ b/TRANSLATION.md
@@ -6,12 +6,16 @@ This document shows the translation status of each locale file in the repository
### 
-### 
+### 
Missing keys in de_DE.axaml
- Text.BranchUpstreamInvalid
+- Text.CommitCM.CopyAuthor
+- Text.CommitCM.CopyCommitter
+- Text.CommitCM.CopySubject
+- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.CustomAction.WaitForExit
- Text.Configure.Git.PreferredMergeMode
- Text.Configure.IssueTracker.AddSampleAzure
@@ -25,7 +29,12 @@ This document shows the translation status of each locale file in the repository
- Text.Preferences.AI.Streaming
- Text.Preferences.Appearance.EditorTabWidth
- Text.Preferences.General.ShowTagsInGraph
+- Text.Repository.ViewLogs
- Text.StashCM.SaveAsPatch
+- Text.ViewLogs
+- Text.ViewLogs.Clear
+- Text.ViewLogs.CopyLog
+- Text.ViewLogs.Delete
- Text.WorkingCopy.ConfirmCommitWithFilter
- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
@@ -34,34 +43,41 @@ This document shows the translation status of each locale file in the repository
-### 
+### 
Missing keys in es_ES.axaml
-- Text.Configure.Git.PreferredMergeMode
-- Text.ConfirmEmptyCommit.Continue
-- Text.ConfirmEmptyCommit.NoLocalChanges
-- Text.ConfirmEmptyCommit.StageAllThenCommit
-- Text.ConfirmEmptyCommit.WithLocalChanges
-- Text.WorkingCopy.ConfirmCommitWithFilter
-- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
-- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
-- Text.WorkingCopy.Conflicts.UseMine
-- Text.WorkingCopy.Conflicts.UseTheirs
+- Text.CommitCM.CopyAuthor
+- Text.CommitCM.CopyCommitter
+- Text.CommitCM.CopySubject
+- Text.Repository.ViewLogs
+- Text.ViewLogs
+- Text.ViewLogs.Clear
+- Text.ViewLogs.CopyLog
+- Text.ViewLogs.Delete
-### 
+### 
Missing keys in fr_FR.axaml
+- Text.CommitCM.CopyAuthor
+- Text.CommitCM.CopyCommitter
+- Text.CommitCM.CopySubject
+- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.Git.PreferredMergeMode
- Text.ConfirmEmptyCommit.Continue
- Text.ConfirmEmptyCommit.NoLocalChanges
- Text.ConfirmEmptyCommit.StageAllThenCommit
- Text.ConfirmEmptyCommit.WithLocalChanges
+- Text.Repository.ViewLogs
+- Text.ViewLogs
+- Text.ViewLogs.Clear
+- Text.ViewLogs.CopyLog
+- Text.ViewLogs.Delete
- Text.WorkingCopy.ConfirmCommitWithFilter
- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
@@ -70,11 +86,15 @@ This document shows the translation status of each locale file in the repository
-### 
+### 
Missing keys in it_IT.axaml
+- Text.CommitCM.CopyAuthor
+- Text.CommitCM.CopyCommitter
+- Text.CommitCM.CopySubject
+- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.Git.PreferredMergeMode
- Text.ConfirmEmptyCommit.Continue
- Text.ConfirmEmptyCommit.NoLocalChanges
@@ -82,6 +102,11 @@ This document shows the translation status of each locale file in the repository
- Text.ConfirmEmptyCommit.WithLocalChanges
- Text.CopyFullPath
- Text.Preferences.General.ShowTagsInGraph
+- Text.Repository.ViewLogs
+- Text.ViewLogs
+- Text.ViewLogs.Clear
+- Text.ViewLogs.CopyLog
+- Text.ViewLogs.Delete
- Text.WorkingCopy.ConfirmCommitWithFilter
- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
@@ -90,11 +115,15 @@ This document shows the translation status of each locale file in the repository
-### 
+### 
Missing keys in ja_JP.axaml
+- Text.CommitCM.CopyAuthor
+- Text.CommitCM.CopyCommitter
+- Text.CommitCM.CopySubject
+- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.Git.PreferredMergeMode
- Text.ConfirmEmptyCommit.Continue
- Text.ConfirmEmptyCommit.NoLocalChanges
@@ -102,6 +131,11 @@ This document shows the translation status of each locale file in the repository
- Text.ConfirmEmptyCommit.WithLocalChanges
- Text.Repository.FilterCommits
- Text.Repository.Tags.OrderByNameDes
+- Text.Repository.ViewLogs
+- Text.ViewLogs
+- Text.ViewLogs.Clear
+- Text.ViewLogs.CopyLog
+- Text.ViewLogs.Delete
- Text.WorkingCopy.ConfirmCommitWithFilter
- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
@@ -110,7 +144,7 @@ This document shows the translation status of each locale file in the repository
-### 
+### 
Missing keys in pt_BR.axaml
@@ -125,10 +159,14 @@ This document shows the translation status of each locale file in the repository
- Text.BranchCM.MergeMultiBranches
- Text.BranchUpstreamInvalid
- Text.Clone.RecurseSubmodules
+- Text.CommitCM.CopyAuthor
+- Text.CommitCM.CopyCommitter
+- Text.CommitCM.CopySubject
- Text.CommitCM.Merge
- Text.CommitCM.MergeMultiple
- Text.CommitDetail.Files.Search
- Text.CommitDetail.Info.Children
+- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.CustomAction.Scope.Branch
- Text.Configure.CustomAction.WaitForExit
- Text.Configure.Git.PreferredMergeMode
@@ -177,6 +215,7 @@ This document shows the translation status of each locale file in the repository
- Text.Repository.Tags.OrderByNameDes
- Text.Repository.Tags.Sort
- Text.Repository.UseRelativeTimeInHistories
+- Text.Repository.ViewLogs
- Text.SetUpstream
- Text.SetUpstream.Local
- Text.SetUpstream.Unset
@@ -185,6 +224,10 @@ This document shows the translation status of each locale file in the repository
- Text.Stash.AutoRestore
- Text.Stash.AutoRestore.Tip
- Text.StashCM.SaveAsPatch
+- Text.ViewLogs
+- Text.ViewLogs.Clear
+- Text.ViewLogs.CopyLog
+- Text.ViewLogs.Delete
- Text.WorkingCopy.CommitToEdit
- Text.WorkingCopy.ConfirmCommitWithFilter
- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
@@ -195,19 +238,43 @@ This document shows the translation status of each locale file in the repository
-### 
+### 
-### 
+
+Missing keys in ru_RU.axaml
+
+- Text.CommitCM.CopyAuthor
+- Text.CommitCM.CopyCommitter
+- Text.CommitCM.CopySubject
+- Text.CommitMessageTextBox.SubjectCount
+- Text.Repository.ViewLogs
+- Text.ViewLogs
+- Text.ViewLogs.Clear
+- Text.ViewLogs.CopyLog
+- Text.ViewLogs.Delete
+
+
+
+### 
Missing keys in ta_IN.axaml
+- Text.CommitCM.CopyAuthor
+- Text.CommitCM.CopyCommitter
+- Text.CommitCM.CopySubject
+- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.Git.PreferredMergeMode
- Text.ConfirmEmptyCommit.Continue
- Text.ConfirmEmptyCommit.NoLocalChanges
- Text.ConfirmEmptyCommit.StageAllThenCommit
- Text.ConfirmEmptyCommit.WithLocalChanges
+- Text.Repository.ViewLogs
- Text.UpdateSubmodules.Target
+- Text.ViewLogs
+- Text.ViewLogs.Clear
+- Text.ViewLogs.CopyLog
+- Text.ViewLogs.Delete
- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
- Text.WorkingCopy.Conflicts.UseMine
@@ -215,6 +282,24 @@ This document shows the translation status of each locale file in the repository
+### 
+
+
+Missing keys in uk_UA.axaml
+
+- Text.CommitCM.CopyAuthor
+- Text.CommitCM.CopyCommitter
+- Text.CommitCM.CopySubject
+- Text.CommitMessageTextBox.SubjectCount
+- Text.ConfigureWorkspace.Name
+- Text.Repository.ViewLogs
+- Text.ViewLogs
+- Text.ViewLogs.Clear
+- Text.ViewLogs.CopyLog
+- Text.ViewLogs.Delete
+
+
+
### 
### 
\ No newline at end of file
diff --git a/VERSION b/VERSION
index c29bf2a5..89f9e970 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2025.13
\ No newline at end of file
+2025.14
\ No newline at end of file
diff --git a/build/scripts/localization-check.js b/build/scripts/localization-check.js
index 1e8f1f0d..8d636b5b 100644
--- a/build/scripts/localization-check.js
+++ b/build/scripts/localization-check.js
@@ -14,6 +14,22 @@ async function parseXml(filePath) {
return parser.parseStringPromise(data);
}
+async function filterAndSortTranslations(localeData, enUSKeys, enUSData) {
+ const strings = localeData.ResourceDictionary['x:String'];
+ // Remove keys that don't exist in English file
+ const filtered = strings.filter(item => enUSKeys.has(item.$['x:Key']));
+
+ // Sort based on the key order in English file
+ const enUSKeysArray = enUSData.ResourceDictionary['x:String'].map(item => item.$['x:Key']);
+ filtered.sort((a, b) => {
+ const aIndex = enUSKeysArray.indexOf(a.$['x:Key']);
+ const bIndex = enUSKeysArray.indexOf(b.$['x:Key']);
+ return aIndex - bIndex;
+ });
+
+ return filtered;
+}
+
async function calculateTranslationRate() {
const enUSData = await parseXml(enUSFile);
const enUSKeys = new Set(enUSData.ResourceDictionary['x:String'].map(item => item.$['x:Key']));
@@ -33,6 +49,21 @@ async function calculateTranslationRate() {
const localeKeys = new Set(localeData.ResourceDictionary['x:String'].map(item => item.$['x:Key']));
const missingKeys = [...enUSKeys].filter(key => !localeKeys.has(key));
+ // Sort and clean up extra translations
+ const sortedAndCleaned = await filterAndSortTranslations(localeData, enUSKeys, enUSData);
+ localeData.ResourceDictionary['x:String'] = sortedAndCleaned;
+
+ // Save the updated file
+ const builder = new xml2js.Builder({
+ headless: true,
+ renderOpts: { pretty: true, indent: ' ' }
+ });
+ let xmlStr = builder.buildObject(localeData);
+
+ // Add an empty line before the first x:String
+ xmlStr = xmlStr.replace(' 0) {
const progress = ((enUSKeys.size - missingKeys.length) / enUSKeys.size) * 100;
const badgeColor = progress >= 75 ? 'yellow' : 'red';
@@ -41,7 +72,7 @@ async function calculateTranslationRate() {
lines.push(`\nMissing keys in ${file}
\n\n${missingKeys.map(key => `- ${key}`).join('\n')}\n\n `)
} else {
lines.push(`### `);
- }
+ }
}
const content = lines.join('\n\n');
diff --git a/src/App.axaml b/src/App.axaml
index 9d8adb89..73b97017 100644
--- a/src/App.axaml
+++ b/src/App.axaml
@@ -16,6 +16,7 @@
+
diff --git a/src/App.axaml.cs b/src/App.axaml.cs
index 0448a247..c659388a 100644
--- a/src/App.axaml.cs
+++ b/src/App.axaml.cs
@@ -6,6 +6,7 @@ using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Text.Json;
+using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
@@ -347,7 +348,18 @@ namespace SourceGit
if (TryLaunchAsAskpass(desktop))
return;
- TryLaunchAsNormal(desktop);
+ _ipcChannel = new Models.IpcChannel();
+ if (!_ipcChannel.IsFirstInstance)
+ {
+ _ipcChannel.SendToFirstInstance(desktop.Args is { Length: 1 } ? desktop.Args[0] : string.Empty);
+ Environment.Exit(0);
+ }
+ else
+ {
+ _ipcChannel.MessageReceived += TryOpenRepository;
+ desktop.Exit += (_, _) => _ipcChannel.Dispose();
+ TryLaunchAsNormal(desktop);
+ }
}
}
#endregion
@@ -420,21 +432,37 @@ namespace SourceGit
return true;
var gitDir = Path.GetDirectoryName(file)!;
- var jobsFile = Path.Combine(gitDir, "sourcegit_rebase_jobs.json");
- if (!File.Exists(jobsFile))
- return true;
-
- var collection = JsonSerializer.Deserialize(File.ReadAllText(jobsFile), JsonCodeGen.Default.InteractiveRebaseJobCollection);
+ var origHeadFile = Path.Combine(gitDir, "rebase-merge", "orig-head");
+ var ontoFile = Path.Combine(gitDir, "rebase-merge", "onto");
var doneFile = Path.Combine(gitDir, "rebase-merge", "done");
- if (!File.Exists(doneFile))
+ var jobsFile = Path.Combine(gitDir, "sourcegit_rebase_jobs.json");
+ if (!File.Exists(ontoFile) || !File.Exists(origHeadFile) || !File.Exists(doneFile) || !File.Exists(jobsFile))
return true;
- var done = File.ReadAllText(doneFile).Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
- if (done.Length > collection.Jobs.Count)
+ var origHead = File.ReadAllText(origHeadFile).Trim();
+ var onto = File.ReadAllText(ontoFile).Trim();
+ var collection = JsonSerializer.Deserialize(File.ReadAllText(jobsFile), JsonCodeGen.Default.InteractiveRebaseJobCollection);
+ if (!collection.Onto.Equals(onto) || !collection.OrigHead.Equals(origHead))
return true;
- var job = collection.Jobs[done.Length - 1];
- File.WriteAllText(file, job.Message);
+ var done = File.ReadAllText(doneFile).Trim().Split([ '\r', '\n' ], StringSplitOptions.RemoveEmptyEntries);
+ if (done.Length == 0)
+ return true;
+
+ var current = done[^1].Trim();
+ var match = REG_REBASE_TODO().Match(current);
+ if (!match.Success)
+ return true;
+
+ var sha = match.Groups[1].Value;
+ foreach (var job in collection.Jobs)
+ {
+ if (job.SHA.StartsWith(sha))
+ {
+ File.WriteAllText(file, job.Message);
+ break;
+ }
+ }
return true;
}
@@ -485,16 +513,46 @@ namespace SourceGit
if (desktop.Args != null && desktop.Args.Length == 1 && Directory.Exists(desktop.Args[0]))
startupRepo = desktop.Args[0];
+ var pref = ViewModels.Preferences.Instance;
+ pref.SetCanModify();
+
_launcher = new ViewModels.Launcher(startupRepo);
desktop.MainWindow = new Views.Launcher() { DataContext = _launcher };
#if !DISABLE_UPDATE_DETECTION
- var pref = ViewModels.Preferences.Instance;
if (pref.ShouldCheck4UpdateOnStartup())
Check4Update();
#endif
}
+ private void TryOpenRepository(string repo)
+ {
+ if (!string.IsNullOrEmpty(repo) && Directory.Exists(repo))
+ {
+ var test = new Commands.QueryRepositoryRootPath(repo).ReadToEnd();
+ if (test.IsSuccess && !string.IsNullOrEmpty(test.StdOut))
+ {
+ Dispatcher.UIThread.Invoke(() =>
+ {
+ var node = ViewModels.Preferences.Instance.FindOrAddNodeByRepositoryPath(test.StdOut.Trim(), null, false);
+ ViewModels.Welcome.Instance.Refresh();
+ _launcher?.OpenRepositoryInTab(node, null);
+
+ if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: Views.Launcher wnd })
+ wnd.BringToTop();
+ });
+
+ return;
+ }
+ }
+
+ Dispatcher.UIThread.Invoke(() =>
+ {
+ if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: Views.Launcher launcher })
+ launcher.BringToTop();
+ });
+ }
+
private void Check4Update(bool manually = false)
{
Task.Run(async () =>
@@ -580,6 +638,10 @@ namespace SourceGit
return trimmed.Count > 0 ? string.Join(',', trimmed) : string.Empty;
}
+ [GeneratedRegex(@"^[a-z]+\s+([a-fA-F0-9]{4,40})(\s+.*)?$")]
+ private static partial Regex REG_REBASE_TODO();
+
+ private Models.IpcChannel _ipcChannel = null;
private ViewModels.Launcher _launcher = null;
private ResourceDictionary _activeLocale = null;
private ResourceDictionary _themeOverrides = null;
diff --git a/src/Commands/Archive.cs b/src/Commands/Archive.cs
index d4f6241c..5e0919f7 100644
--- a/src/Commands/Archive.cs
+++ b/src/Commands/Archive.cs
@@ -1,23 +1,12 @@
-using System;
-
-namespace SourceGit.Commands
+namespace SourceGit.Commands
{
public class Archive : Command
{
- public Archive(string repo, string revision, string saveTo, Action outputHandler)
+ public Archive(string repo, string revision, string saveTo)
{
WorkingDirectory = repo;
Context = repo;
Args = $"archive --format=zip --verbose --output=\"{saveTo}\" {revision}";
- TraitErrorAsOutput = true;
- _outputHandler = outputHandler;
}
-
- protected override void OnReadline(string line)
- {
- _outputHandler?.Invoke(line);
- }
-
- private readonly Action _outputHandler;
}
}
diff --git a/src/Commands/AssumeUnchanged.cs b/src/Commands/AssumeUnchanged.cs
index 1898122a..28f78280 100644
--- a/src/Commands/AssumeUnchanged.cs
+++ b/src/Commands/AssumeUnchanged.cs
@@ -1,75 +1,14 @@
-using System.Collections.Generic;
-using System.Text.RegularExpressions;
-
-namespace SourceGit.Commands
+namespace SourceGit.Commands
{
- public partial class AssumeUnchanged
+ public class AssumeUnchanged : Command
{
- [GeneratedRegex(@"^(\w)\s+(.+)$")]
- private static partial Regex REG_PARSE();
-
- class ViewCommand : Command
+ public AssumeUnchanged(string repo, string file, bool bAdd)
{
- public ViewCommand(string repo)
- {
- WorkingDirectory = repo;
- Args = "ls-files -v";
- RaiseError = false;
- }
+ var mode = bAdd ? "--assume-unchanged" : "--no-assume-unchanged";
- public List Result()
- {
- Exec();
- return _outs;
- }
-
- protected override void OnReadline(string line)
- {
- var match = REG_PARSE().Match(line);
- if (!match.Success)
- return;
-
- if (match.Groups[1].Value == "h")
- {
- _outs.Add(match.Groups[2].Value);
- }
- }
-
- private readonly List _outs = new List();
+ WorkingDirectory = repo;
+ Context = repo;
+ Args = $"update-index {mode} -- \"{file}\"";
}
-
- class ModCommand : Command
- {
- public ModCommand(string repo, string file, bool bAdd)
- {
- var mode = bAdd ? "--assume-unchanged" : "--no-assume-unchanged";
-
- WorkingDirectory = repo;
- Context = repo;
- Args = $"update-index {mode} -- \"{file}\"";
- }
- }
-
- public AssumeUnchanged(string repo)
- {
- _repo = repo;
- }
-
- public List View()
- {
- return new ViewCommand(_repo).Result();
- }
-
- public void Add(string file)
- {
- new ModCommand(_repo, file, true).Exec();
- }
-
- public void Remove(string file)
- {
- new ModCommand(_repo, file, false).Exec();
- }
-
- private readonly string _repo;
}
}
diff --git a/src/Commands/Blame.cs b/src/Commands/Blame.cs
index 291249be..0bb45c98 100644
--- a/src/Commands/Blame.cs
+++ b/src/Commands/Blame.cs
@@ -21,10 +21,17 @@ namespace SourceGit.Commands
public Models.BlameData Result()
{
- var succ = Exec();
- if (!succ)
+ var rs = ReadToEnd();
+ if (!rs.IsSuccess)
+ return _result;
+
+ var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
+ foreach (var line in lines)
{
- return new Models.BlameData();
+ ParseLine(line);
+
+ if (_result.IsBinary)
+ break;
}
if (_needUnifyCommitSHA)
@@ -42,13 +49,8 @@ namespace SourceGit.Commands
return _result;
}
- protected override void OnReadline(string line)
+ private void ParseLine(string line)
{
- if (_result.IsBinary)
- return;
- if (string.IsNullOrEmpty(line))
- return;
-
if (line.IndexOf('\0', StringComparison.Ordinal) >= 0)
{
_result.IsBinary = true;
diff --git a/src/Commands/Branch.cs b/src/Commands/Branch.cs
index 2dc8a98d..9c396215 100644
--- a/src/Commands/Branch.cs
+++ b/src/Commands/Branch.cs
@@ -11,29 +11,32 @@
return cmd.ReadToEnd().StdOut.Trim();
}
- public static bool Create(string repo, string name, string basedOn)
+ public static bool Create(string repo, string name, string basedOn, Models.ICommandLog log)
{
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
cmd.Args = $"branch {name} {basedOn}";
+ cmd.Log = log;
return cmd.Exec();
}
- public static bool Rename(string repo, string name, string to)
+ public static bool Rename(string repo, string name, string to, Models.ICommandLog log)
{
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
cmd.Args = $"branch -M {name} {to}";
+ cmd.Log = log;
return cmd.Exec();
}
- public static bool SetUpstream(string repo, string name, string upstream)
+ public static bool SetUpstream(string repo, string name, string upstream, Models.ICommandLog log)
{
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
+ cmd.Log = log;
if (string.IsNullOrEmpty(upstream))
cmd.Args = $"branch {name} --unset-upstream";
@@ -43,25 +46,27 @@
return cmd.Exec();
}
- public static bool DeleteLocal(string repo, string name)
+ public static bool DeleteLocal(string repo, string name, Models.ICommandLog log)
{
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
cmd.Args = $"branch -D {name}";
+ cmd.Log = log;
return cmd.Exec();
}
- public static bool DeleteRemote(string repo, string remote, string name)
+ public static bool DeleteRemote(string repo, string remote, string name, Models.ICommandLog log)
{
bool exists = new Remote(repo).HasBranch(remote, name);
if (exists)
- return new Push(repo, remote, $"refs/heads/{name}", true).Exec();
+ return new Push(repo, remote, $"refs/heads/{name}", true) { Log = log }.Exec();
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
cmd.Args = $"branch -D -r {remote}/{name}";
+ cmd.Log = log;
return cmd.Exec();
}
}
diff --git a/src/Commands/Checkout.cs b/src/Commands/Checkout.cs
index 306d62ff..c39c28ae 100644
--- a/src/Commands/Checkout.cs
+++ b/src/Commands/Checkout.cs
@@ -1,5 +1,4 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Text;
namespace SourceGit.Commands
@@ -12,19 +11,15 @@ namespace SourceGit.Commands
Context = repo;
}
- public bool Branch(string branch, Action onProgress)
+ public bool Branch(string branch)
{
Args = $"checkout --recurse-submodules --progress {branch}";
- TraitErrorAsOutput = true;
- _outputHandler = onProgress;
return Exec();
}
- public bool Branch(string branch, string basedOn, Action onProgress)
+ public bool Branch(string branch, string basedOn)
{
Args = $"checkout --recurse-submodules --progress -b {branch} {basedOn}";
- TraitErrorAsOutput = true;
- _outputHandler = onProgress;
return Exec();
}
@@ -62,19 +57,10 @@ namespace SourceGit.Commands
return Exec();
}
- public bool Commit(string commitId, Action onProgress)
+ public bool Commit(string commitId)
{
Args = $"checkout --detach --progress {commitId}";
- TraitErrorAsOutput = true;
- _outputHandler = onProgress;
return Exec();
}
-
- protected override void OnReadline(string line)
- {
- _outputHandler?.Invoke(line);
- }
-
- private Action _outputHandler;
}
}
diff --git a/src/Commands/Clone.cs b/src/Commands/Clone.cs
index f2faed14..efec264b 100644
--- a/src/Commands/Clone.cs
+++ b/src/Commands/Clone.cs
@@ -1,16 +1,11 @@
-using System;
-
-namespace SourceGit.Commands
+namespace SourceGit.Commands
{
public class Clone : Command
{
- private readonly Action _notifyProgress;
-
- public Clone(string ctx, string path, string url, string localName, string sshKey, string extraArgs, Action ouputHandler)
+ public Clone(string ctx, string path, string url, string localName, string sshKey, string extraArgs)
{
Context = ctx;
WorkingDirectory = path;
- TraitErrorAsOutput = true;
SSHKey = sshKey;
Args = "clone --progress --verbose ";
@@ -21,13 +16,6 @@ namespace SourceGit.Commands
if (!string.IsNullOrEmpty(localName))
Args += localName;
-
- _notifyProgress = ouputHandler;
- }
-
- protected override void OnReadline(string line)
- {
- _notifyProgress?.Invoke(line);
}
}
}
diff --git a/src/Commands/Command.cs b/src/Commands/Command.cs
index 0fef1235..699cc120 100644
--- a/src/Commands/Command.cs
+++ b/src/Commands/Command.cs
@@ -32,7 +32,7 @@ namespace SourceGit.Commands
public string SSHKey { get; set; } = string.Empty;
public string Args { get; set; } = string.Empty;
public bool RaiseError { get; set; } = true;
- public bool TraitErrorAsOutput { get; set; } = false;
+ public Models.ICommandLog Log { get; set; } = null;
public bool Exec()
{
@@ -40,10 +40,14 @@ namespace SourceGit.Commands
var errs = new List();
var proc = new Process() { StartInfo = start };
+ Log?.AppendLine($"$ git {Args}\n");
+
proc.OutputDataReceived += (_, e) =>
{
- if (e.Data != null)
- OnReadline(e.Data);
+ if (e.Data == null)
+ return;
+
+ Log?.AppendLine(e.Data);
};
proc.ErrorDataReceived += (_, e) =>
@@ -54,8 +58,7 @@ namespace SourceGit.Commands
return;
}
- if (TraitErrorAsOutput)
- OnReadline(e.Data);
+ Log?.AppendLine(e.Data);
// Ignore progress messages
if (e.Data.StartsWith("remote: Enumerating objects:", StringComparison.Ordinal))
@@ -97,6 +100,7 @@ namespace SourceGit.Commands
if (RaiseError)
Dispatcher.UIThread.Post(() => App.RaiseException(Context, e.Message));
+ Log?.AppendLine(string.Empty);
return false;
}
@@ -114,6 +118,7 @@ namespace SourceGit.Commands
int exitCode = proc.ExitCode;
proc.Close();
+ Log?.AppendLine(string.Empty);
if (!CancellationToken.IsCancellationRequested && exitCode != 0)
{
@@ -162,11 +167,6 @@ namespace SourceGit.Commands
return rs;
}
- protected virtual void OnReadline(string line)
- {
- // Implemented by derived class
- }
-
private ProcessStartInfo CreateGitStartInfo()
{
var start = new ProcessStartInfo();
diff --git a/src/Commands/Commit.cs b/src/Commands/Commit.cs
index cb086793..5be08cef 100644
--- a/src/Commands/Commit.cs
+++ b/src/Commands/Commit.cs
@@ -11,7 +11,6 @@ namespace SourceGit.Commands
WorkingDirectory = repo;
Context = repo;
- TraitErrorAsOutput = true;
Args = $"commit --allow-empty --file=\"{_tmpFile}\"";
if (amend)
Args += " --amend --no-edit";
diff --git a/src/Commands/CompareRevisions.cs b/src/Commands/CompareRevisions.cs
index c3206767..7b4a496d 100644
--- a/src/Commands/CompareRevisions.cs
+++ b/src/Commands/CompareRevisions.cs
@@ -31,12 +31,19 @@ namespace SourceGit.Commands
public List Result()
{
- Exec();
+ var rs = ReadToEnd();
+ if (!rs.IsSuccess)
+ return _changes;
+
+ var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
+ foreach (var line in lines)
+ ParseLine(line);
+
_changes.Sort((l, r) => string.Compare(l.Path, r.Path, StringComparison.Ordinal));
return _changes;
}
- protected override void OnReadline(string line)
+ private void ParseLine(string line)
{
var match = REG_FORMAT().Match(line);
if (!match.Success)
diff --git a/src/Commands/Diff.cs b/src/Commands/Diff.cs
index 8ae6350f..65a2a6f5 100644
--- a/src/Commands/Diff.cs
+++ b/src/Commands/Diff.cs
@@ -30,32 +30,44 @@ namespace SourceGit.Commands
if (ignoreWhitespace)
Args = $"-c core.autocrlf=false diff --no-ext-diff --patch --ignore-cr-at-eol --ignore-all-space --unified={unified} {opt}";
else
- Args = $"-c core.autocrlf=false diff --no-ext-diff --patch --ignore-cr-at-eol --unified={unified} {opt}";
+ Args = $"-c core.autocrlf=false diff --no-ext-diff --patch --unified={unified} {opt}";
}
public Models.DiffResult Result()
{
- Exec();
+ var rs = ReadToEnd();
+ var start = 0;
+ var end = rs.StdOut.IndexOf('\n', start);
+ while (end > 0)
+ {
+ var line = rs.StdOut.Substring(start, end - start);
+ ParseLine(line);
- if (_result.IsBinary || _result.IsLFS)
+ start = end + 1;
+ end = rs.StdOut.IndexOf('\n', start);
+ }
+
+ if (start < rs.StdOut.Length)
+ ParseLine(rs.StdOut.Substring(start));
+
+ if (_result.IsBinary || _result.IsLFS || _result.TextDiff.Lines.Count == 0)
{
_result.TextDiff = null;
}
else
{
ProcessInlineHighlights();
-
- if (_result.TextDiff.Lines.Count == 0)
- _result.TextDiff = null;
- else
- _result.TextDiff.MaxLineNumber = Math.Max(_newLine, _oldLine);
+ _result.TextDiff.MaxLineNumber = Math.Max(_newLine, _oldLine);
}
return _result;
}
- protected override void OnReadline(string line)
+ private void ParseLine(string line)
{
+ if (_result.IsBinary)
+ return;
+
if (line.StartsWith("old mode ", StringComparison.Ordinal))
{
_result.OldMode = line.Substring(9);
@@ -80,9 +92,6 @@ namespace SourceGit.Commands
return;
}
- if (_result.IsBinary)
- return;
-
if (_result.IsLFS)
{
var ch = line[0];
@@ -140,7 +149,8 @@ namespace SourceGit.Commands
_oldLine = int.Parse(match.Groups[1].Value);
_newLine = int.Parse(match.Groups[2].Value);
- _result.TextDiff.Lines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, 0, 0));
+ _last = new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, 0, 0);
+ _result.TextDiff.Lines.Add(_last);
}
}
else
@@ -148,7 +158,8 @@ namespace SourceGit.Commands
if (line.Length == 0)
{
ProcessInlineHighlights();
- _result.TextDiff.Lines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Normal, "", _oldLine, _newLine));
+ _last = new Models.TextDiffLine(Models.TextDiffLineType.Normal, "", _oldLine, _newLine);
+ _result.TextDiff.Lines.Add(_last);
_oldLine++;
_newLine++;
return;
@@ -164,7 +175,8 @@ namespace SourceGit.Commands
return;
}
- _deleted.Add(new Models.TextDiffLine(Models.TextDiffLineType.Deleted, line.Substring(1), _oldLine, 0));
+ _last = new Models.TextDiffLine(Models.TextDiffLineType.Deleted, line.Substring(1), _oldLine, 0);
+ _deleted.Add(_last);
_oldLine++;
}
else if (ch == '+')
@@ -176,7 +188,8 @@ namespace SourceGit.Commands
return;
}
- _added.Add(new Models.TextDiffLine(Models.TextDiffLineType.Added, line.Substring(1), 0, _newLine));
+ _last = new Models.TextDiffLine(Models.TextDiffLineType.Added, line.Substring(1), 0, _newLine);
+ _added.Add(_last);
_newLine++;
}
else if (ch != '\\')
@@ -187,7 +200,8 @@ namespace SourceGit.Commands
{
_oldLine = int.Parse(match.Groups[1].Value);
_newLine = int.Parse(match.Groups[2].Value);
- _result.TextDiff.Lines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, 0, 0));
+ _last = new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, 0, 0);
+ _result.TextDiff.Lines.Add(_last);
}
else
{
@@ -198,11 +212,16 @@ namespace SourceGit.Commands
return;
}
- _result.TextDiff.Lines.Add(new Models.TextDiffLine(Models.TextDiffLineType.Normal, line.Substring(1), _oldLine, _newLine));
+ _last = new Models.TextDiffLine(Models.TextDiffLineType.Normal, line.Substring(1), _oldLine, _newLine);
+ _result.TextDiff.Lines.Add(_last);
_oldLine++;
_newLine++;
}
}
+ else if (line.Equals("\\ No newline at end of file", StringComparison.Ordinal))
+ {
+ _last.NoNewLineEndOfFile = true;
+ }
}
}
@@ -253,6 +272,7 @@ namespace SourceGit.Commands
private readonly Models.DiffResult _result = new Models.DiffResult();
private readonly List _deleted = new List();
private readonly List _added = new List();
+ private Models.TextDiffLine _last = null;
private int _oldLine = 0;
private int _newLine = 0;
}
diff --git a/src/Commands/Discard.cs b/src/Commands/Discard.cs
index a279bb84..f837df52 100644
--- a/src/Commands/Discard.cs
+++ b/src/Commands/Discard.cs
@@ -5,13 +5,13 @@ namespace SourceGit.Commands
{
public static class Discard
{
- public static void All(string repo, bool includeIgnored)
+ public static void All(string repo, bool includeIgnored, Models.ICommandLog log)
{
- new Restore(repo).Exec();
- new Clean(repo, includeIgnored).Exec();
+ new Restore(repo) { Log = log }.Exec();
+ new Clean(repo, includeIgnored) { Log = log }.Exec();
}
- public static void Changes(string repo, List changes)
+ public static void Changes(string repo, List changes, Models.ICommandLog log)
{
var needClean = new List();
var needCheckout = new List();
@@ -27,13 +27,13 @@ namespace SourceGit.Commands
for (int i = 0; i < needClean.Count; i += 10)
{
var count = Math.Min(10, needClean.Count - i);
- new Clean(repo, needClean.GetRange(i, count)).Exec();
+ new Clean(repo, needClean.GetRange(i, count)) { Log = log }.Exec();
}
for (int i = 0; i < needCheckout.Count; i += 10)
{
var count = Math.Min(10, needCheckout.Count - i);
- new Restore(repo, needCheckout.GetRange(i, count), "--worktree --recurse-submodules").Exec();
+ new Restore(repo, needCheckout.GetRange(i, count), "--worktree --recurse-submodules") { Log = log }.Exec();
}
}
}
diff --git a/src/Commands/Fetch.cs b/src/Commands/Fetch.cs
index 06ae8cb6..edf2a6dd 100644
--- a/src/Commands/Fetch.cs
+++ b/src/Commands/Fetch.cs
@@ -1,15 +1,11 @@
-using System;
-
-namespace SourceGit.Commands
+namespace SourceGit.Commands
{
public class Fetch : Command
{
- public Fetch(string repo, string remote, bool noTags, bool force, Action outputHandler)
+ public Fetch(string repo, string remote, bool noTags, bool force)
{
- _outputHandler = outputHandler;
WorkingDirectory = repo;
Context = repo;
- TraitErrorAsOutput = true;
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
Args = "fetch --progress --verbose ";
@@ -24,21 +20,12 @@ namespace SourceGit.Commands
Args += remote;
}
- public Fetch(string repo, Models.Branch local, Models.Branch remote, Action outputHandler)
+ public Fetch(string repo, Models.Branch local, Models.Branch remote)
{
- _outputHandler = outputHandler;
WorkingDirectory = repo;
Context = repo;
- TraitErrorAsOutput = true;
SSHKey = new Config(repo).Get($"remote.{remote.Remote}.sshkey");
Args = $"fetch --progress --verbose {remote.Remote} {remote.Name}:{local.Name}";
}
-
- protected override void OnReadline(string line)
- {
- _outputHandler?.Invoke(line);
- }
-
- private readonly Action _outputHandler;
}
}
diff --git a/src/Commands/GC.cs b/src/Commands/GC.cs
index 393b915e..0b27f487 100644
--- a/src/Commands/GC.cs
+++ b/src/Commands/GC.cs
@@ -1,23 +1,12 @@
-using System;
-
-namespace SourceGit.Commands
+namespace SourceGit.Commands
{
public class GC : Command
{
- public GC(string repo, Action outputHandler)
+ public GC(string repo)
{
- _outputHandler = outputHandler;
WorkingDirectory = repo;
Context = repo;
- TraitErrorAsOutput = true;
Args = "gc --prune=now";
}
-
- protected override void OnReadline(string line)
- {
- _outputHandler?.Invoke(line);
- }
-
- private readonly Action _outputHandler;
}
}
diff --git a/src/Commands/GitFlow.cs b/src/Commands/GitFlow.cs
index 5e05ed83..833d268d 100644
--- a/src/Commands/GitFlow.cs
+++ b/src/Commands/GitFlow.cs
@@ -35,17 +35,17 @@ namespace SourceGit.Commands
config.ContainsKey("gitflow.prefix.hotfix");
}
- public static bool Init(string repo, List branches, string master, string develop, string feature, string release, string hotfix, string version)
+ public static bool Init(string repo, List branches, string master, string develop, string feature, string release, string hotfix, string version, Models.ICommandLog log)
{
var current = branches.Find(x => x.IsCurrent);
var masterBranch = branches.Find(x => x.Name == master);
if (masterBranch == null && current != null)
- Branch.Create(repo, master, current.Head);
+ Branch.Create(repo, master, current.Head, log);
var devBranch = branches.Find(x => x.Name == develop);
if (devBranch == null && current != null)
- Branch.Create(repo, develop, current.Head);
+ Branch.Create(repo, develop, current.Head, log);
var config = new Config(repo);
config.Set("gitflow.branch.master", master);
@@ -61,6 +61,7 @@ namespace SourceGit.Commands
init.WorkingDirectory = repo;
init.Context = repo;
init.Args = "flow init -d";
+ init.Log = log;
return init.Exec();
}
@@ -113,7 +114,7 @@ namespace SourceGit.Commands
return rs;
}
- public static bool Start(string repo, string type, string name)
+ public static bool Start(string repo, string type, string name, Models.ICommandLog log)
{
if (!SUPPORTED_BRANCH_TYPES.Contains(type))
{
@@ -129,10 +130,11 @@ namespace SourceGit.Commands
start.WorkingDirectory = repo;
start.Context = repo;
start.Args = $"flow {type} start {name}";
+ start.Log = log;
return start.Exec();
}
- public static bool Finish(string repo, string type, string name, bool keepBranch)
+ public static bool Finish(string repo, string type, string name, bool keepBranch, Models.ICommandLog log)
{
if (!SUPPORTED_BRANCH_TYPES.Contains(type))
{
@@ -149,6 +151,7 @@ namespace SourceGit.Commands
finish.WorkingDirectory = repo;
finish.Context = repo;
finish.Args = $"flow {type} finish {option} {name}";
+ finish.Log = log;
return finish.Exec();
}
diff --git a/src/Commands/IsConflictResolved.cs b/src/Commands/IsConflictResolved.cs
index 13bc12ac..9b243451 100644
--- a/src/Commands/IsConflictResolved.cs
+++ b/src/Commands/IsConflictResolved.cs
@@ -10,5 +10,10 @@
Context = repo;
Args = $"diff -a --ignore-cr-at-eol --check {opt}";
}
+
+ public bool Result()
+ {
+ return ReadToEnd().IsSuccess;
+ }
}
}
diff --git a/src/Commands/LFS.cs b/src/Commands/LFS.cs
index f7e56486..e621ed7d 100644
--- a/src/Commands/LFS.cs
+++ b/src/Commands/LFS.cs
@@ -12,21 +12,13 @@ namespace SourceGit.Commands
class SubCmd : Command
{
- public SubCmd(string repo, string args, Action onProgress)
+ public SubCmd(string repo, string args, Models.ICommandLog log)
{
WorkingDirectory = repo;
Context = repo;
Args = args;
- TraitErrorAsOutput = true;
- _outputHandler = onProgress;
+ Log = log;
}
-
- protected override void OnReadline(string line)
- {
- _outputHandler?.Invoke(line);
- }
-
- private readonly Action _outputHandler;
}
public LFS(string repo)
@@ -44,35 +36,35 @@ namespace SourceGit.Commands
return content.Contains("git lfs pre-push");
}
- public bool Install()
+ public bool Install(Models.ICommandLog log)
{
- return new SubCmd(_repo, "lfs install --local", null).Exec();
+ return new SubCmd(_repo, "lfs install --local", log).Exec();
}
- public bool Track(string pattern, bool isFilenameMode = false)
+ public bool Track(string pattern, bool isFilenameMode, Models.ICommandLog log)
{
var opt = isFilenameMode ? "--filename" : "";
- return new SubCmd(_repo, $"lfs track {opt} \"{pattern}\"", null).Exec();
+ return new SubCmd(_repo, $"lfs track {opt} \"{pattern}\"", log).Exec();
}
- public void Fetch(string remote, Action outputHandler)
+ public void Fetch(string remote, Models.ICommandLog log)
{
- new SubCmd(_repo, $"lfs fetch {remote}", outputHandler).Exec();
+ new SubCmd(_repo, $"lfs fetch {remote}", log).Exec();
}
- public void Pull(string remote, Action outputHandler)
+ public void Pull(string remote, Models.ICommandLog log)
{
- new SubCmd(_repo, $"lfs pull {remote}", outputHandler).Exec();
+ new SubCmd(_repo, $"lfs pull {remote}", log).Exec();
}
- public void Push(string remote, Action outputHandler)
+ public void Push(string remote, Models.ICommandLog log)
{
- new SubCmd(_repo, $"lfs push {remote}", outputHandler).Exec();
+ new SubCmd(_repo, $"lfs push {remote}", log).Exec();
}
- public void Prune(Action outputHandler)
+ public void Prune(Models.ICommandLog log)
{
- new SubCmd(_repo, "lfs prune", outputHandler).Exec();
+ new SubCmd(_repo, "lfs prune", log).Exec();
}
public List Locks(string remote)
@@ -101,21 +93,21 @@ namespace SourceGit.Commands
return locks;
}
- public bool Lock(string remote, string file)
+ public bool Lock(string remote, string file, Models.ICommandLog log)
{
- return new SubCmd(_repo, $"lfs lock --remote={remote} \"{file}\"", null).Exec();
+ return new SubCmd(_repo, $"lfs lock --remote={remote} \"{file}\"", log).Exec();
}
- public bool Unlock(string remote, string file, bool force)
+ public bool Unlock(string remote, string file, bool force, Models.ICommandLog log)
{
var opt = force ? "-f" : "";
- return new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} \"{file}\"", null).Exec();
+ return new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} \"{file}\"", log).Exec();
}
- public bool Unlock(string remote, long id, bool force)
+ public bool Unlock(string remote, long id, bool force, Models.ICommandLog log)
{
var opt = force ? "-f" : "";
- return new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} --id={id}", null).Exec();
+ return new SubCmd(_repo, $"lfs unlock --remote={remote} {opt} --id={id}", log).Exec();
}
private readonly string _repo;
diff --git a/src/Commands/Merge.cs b/src/Commands/Merge.cs
index bd1f3653..b08377b9 100644
--- a/src/Commands/Merge.cs
+++ b/src/Commands/Merge.cs
@@ -1,26 +1,21 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Text;
namespace SourceGit.Commands
{
public class Merge : Command
{
- public Merge(string repo, string source, string mode, Action outputHandler)
+ public Merge(string repo, string source, string mode)
{
- _outputHandler = outputHandler;
WorkingDirectory = repo;
Context = repo;
- TraitErrorAsOutput = true;
Args = $"merge --progress {source} {mode}";
}
- public Merge(string repo, List targets, bool autoCommit, string strategy, Action outputHandler)
+ public Merge(string repo, List targets, bool autoCommit, string strategy)
{
- _outputHandler = outputHandler;
WorkingDirectory = repo;
Context = repo;
- TraitErrorAsOutput = true;
var builder = new StringBuilder();
builder.Append("merge --progress ");
@@ -37,12 +32,5 @@ namespace SourceGit.Commands
Args = builder.ToString();
}
-
- protected override void OnReadline(string line)
- {
- _outputHandler?.Invoke(line);
- }
-
- private readonly Action _outputHandler = null;
}
}
diff --git a/src/Commands/Pull.cs b/src/Commands/Pull.cs
index 35a6289a..2695b16b 100644
--- a/src/Commands/Pull.cs
+++ b/src/Commands/Pull.cs
@@ -1,15 +1,11 @@
-using System;
-
-namespace SourceGit.Commands
+namespace SourceGit.Commands
{
public class Pull : Command
{
- public Pull(string repo, string remote, string branch, bool useRebase, bool noTags, Action outputHandler)
+ public Pull(string repo, string remote, string branch, bool useRebase, bool noTags)
{
- _outputHandler = outputHandler;
WorkingDirectory = repo;
Context = repo;
- TraitErrorAsOutput = true;
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
Args = "pull --verbose --progress ";
@@ -21,12 +17,5 @@ namespace SourceGit.Commands
Args += $"{remote} {branch}";
}
-
- protected override void OnReadline(string line)
- {
- _outputHandler?.Invoke(line);
- }
-
- private readonly Action _outputHandler;
}
}
diff --git a/src/Commands/Push.cs b/src/Commands/Push.cs
index dc81f606..8a5fe33c 100644
--- a/src/Commands/Push.cs
+++ b/src/Commands/Push.cs
@@ -1,16 +1,11 @@
-using System;
-
-namespace SourceGit.Commands
+namespace SourceGit.Commands
{
public class Push : Command
{
- public Push(string repo, string local, string remote, string remoteBranch, bool withTags, bool checkSubmodules, bool track, bool force, Action onProgress)
+ public Push(string repo, string local, string remote, string remoteBranch, bool withTags, bool checkSubmodules, bool track, bool force)
{
- _outputHandler = onProgress;
-
WorkingDirectory = repo;
Context = repo;
- TraitErrorAsOutput = true;
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
Args = "push --progress --verbose ";
@@ -38,12 +33,5 @@ namespace SourceGit.Commands
Args += $"{remote} {refname}";
}
-
- protected override void OnReadline(string line)
- {
- _outputHandler?.Invoke(line);
- }
-
- private readonly Action _outputHandler = null;
}
}
diff --git a/src/Commands/QueryAssumeUnchangedFiles.cs b/src/Commands/QueryAssumeUnchangedFiles.cs
new file mode 100644
index 00000000..b5c23b0b
--- /dev/null
+++ b/src/Commands/QueryAssumeUnchangedFiles.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+
+namespace SourceGit.Commands
+{
+ public partial class QueryAssumeUnchangedFiles : Command
+ {
+ [GeneratedRegex(@"^(\w)\s+(.+)$")]
+ private static partial Regex REG_PARSE();
+
+ public QueryAssumeUnchangedFiles(string repo)
+ {
+ WorkingDirectory = repo;
+ Args = "ls-files -v";
+ RaiseError = false;
+ }
+
+ public List Result()
+ {
+ var outs = new List();
+ var rs = ReadToEnd();
+ var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
+ foreach (var line in lines)
+ {
+ var match = REG_PARSE().Match(line);
+ if (!match.Success)
+ continue;
+
+ if (match.Groups[1].Value == "h")
+ outs.Add(match.Groups[2].Value);
+ }
+
+ return outs;
+ }
+ }
+}
diff --git a/src/Commands/QueryBranches.cs b/src/Commands/QueryBranches.cs
index 8dbc4055..39b77189 100644
--- a/src/Commands/QueryBranches.cs
+++ b/src/Commands/QueryBranches.cs
@@ -40,7 +40,7 @@ namespace SourceGit.Commands
foreach (var b in branches)
{
if (b.IsLocal && !string.IsNullOrEmpty(b.Upstream))
- b.IsUpsteamGone = !remoteBranches.Contains(b.Upstream);
+ b.IsUpstreamGone = !remoteBranches.Contains(b.Upstream);
}
return branches;
@@ -86,7 +86,7 @@ namespace SourceGit.Commands
branch.Head = parts[1];
branch.IsCurrent = parts[2] == "*";
branch.Upstream = parts[3];
- branch.IsUpsteamGone = false;
+ branch.IsUpstreamGone = false;
if (branch.IsLocal && !string.IsNullOrEmpty(parts[4]) && !parts[4].Equals("=", StringComparison.Ordinal))
branch.TrackStatus = new QueryTrackStatus(WorkingDirectory, branch.Name, branch.Upstream).Result();
diff --git a/src/Commands/QueryCommitChildren.cs b/src/Commands/QueryCommitChildren.cs
index 31fb34f8..4e99ce7a 100644
--- a/src/Commands/QueryCommitChildren.cs
+++ b/src/Commands/QueryCommitChildren.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
namespace SourceGit.Commands
{
@@ -14,17 +15,21 @@ namespace SourceGit.Commands
public List Result()
{
- Exec();
- return _lines;
- }
+ var rs = ReadToEnd();
+ var outs = new List();
+ if (rs.IsSuccess)
+ {
+ var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
+ foreach (var line in lines)
+ {
+ if (line.Contains(_commit))
+ outs.Add(line.Substring(0, 40));
+ }
+ }
- protected override void OnReadline(string line)
- {
- if (line.Contains(_commit))
- _lines.Add(line.Substring(0, 40));
+ return outs;
}
private string _commit;
- private List _lines = new List();
}
}
diff --git a/src/Commands/QueryLocalChanges.cs b/src/Commands/QueryLocalChanges.cs
index 9458e5f5..4e626a79 100644
--- a/src/Commands/QueryLocalChanges.cs
+++ b/src/Commands/QueryLocalChanges.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace SourceGit.Commands
@@ -18,139 +19,143 @@ namespace SourceGit.Commands
public List Result()
{
- Exec();
- return _changes;
- }
+ var outs = new List();
+ var rs = ReadToEnd();
+ if (!rs.IsSuccess)
+ return outs;
- 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)
+ var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
+ foreach (var line in lines)
{
- case " M":
- change.Set(Models.ChangeState.None, Models.ChangeState.Modified);
- break;
- case " T":
- change.Set(Models.ChangeState.None, Models.ChangeState.TypeChanged);
- break;
- case " A":
- change.Set(Models.ChangeState.None, Models.ChangeState.Added);
- break;
- case " D":
- change.Set(Models.ChangeState.None, Models.ChangeState.Deleted);
- break;
- case " R":
- change.Set(Models.ChangeState.None, Models.ChangeState.Renamed);
- break;
- case " C":
- change.Set(Models.ChangeState.None, Models.ChangeState.Copied);
- break;
- case "M":
- change.Set(Models.ChangeState.Modified);
- break;
- case "MM":
- change.Set(Models.ChangeState.Modified, Models.ChangeState.Modified);
- break;
- case "MT":
- change.Set(Models.ChangeState.Modified, Models.ChangeState.TypeChanged);
- break;
- case "MD":
- change.Set(Models.ChangeState.Modified, Models.ChangeState.Deleted);
- break;
- case "T":
- change.Set(Models.ChangeState.TypeChanged);
- break;
- case "TM":
- change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Modified);
- break;
- case "TT":
- change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.TypeChanged);
- break;
- case "TD":
- change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Deleted);
- break;
- case "A":
- change.Set(Models.ChangeState.Added);
- break;
- case "AM":
- change.Set(Models.ChangeState.Added, Models.ChangeState.Modified);
- break;
- case "AT":
- change.Set(Models.ChangeState.Added, Models.ChangeState.TypeChanged);
- break;
- case "AD":
- change.Set(Models.ChangeState.Added, Models.ChangeState.Deleted);
- break;
- case "D":
- change.Set(Models.ChangeState.Deleted);
- break;
- case "R":
- change.Set(Models.ChangeState.Renamed);
- break;
- case "RM":
- change.Set(Models.ChangeState.Renamed, Models.ChangeState.Modified);
- break;
- case "RT":
- change.Set(Models.ChangeState.Renamed, Models.ChangeState.TypeChanged);
- break;
- case "RD":
- change.Set(Models.ChangeState.Renamed, Models.ChangeState.Deleted);
- break;
- case "C":
- change.Set(Models.ChangeState.Copied);
- break;
- case "CM":
- change.Set(Models.ChangeState.Copied, Models.ChangeState.Modified);
- break;
- case "CT":
- change.Set(Models.ChangeState.Copied, Models.ChangeState.TypeChanged);
- break;
- case "CD":
- change.Set(Models.ChangeState.Copied, Models.ChangeState.Deleted);
- break;
- case "DR":
- change.Set(Models.ChangeState.Deleted, Models.ChangeState.Renamed);
- break;
- case "DC":
- change.Set(Models.ChangeState.Deleted, Models.ChangeState.Copied);
- break;
- case "DD":
- change.Set(Models.ChangeState.Deleted, Models.ChangeState.Deleted);
- break;
- case "AU":
- change.Set(Models.ChangeState.Added, Models.ChangeState.Unmerged);
- break;
- case "UD":
- change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Deleted);
- break;
- case "UA":
- change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Added);
- break;
- case "DU":
- change.Set(Models.ChangeState.Deleted, Models.ChangeState.Unmerged);
- break;
- case "AA":
- change.Set(Models.ChangeState.Added, Models.ChangeState.Added);
- break;
- case "UU":
- change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Unmerged);
- break;
- case "??":
- change.Set(Models.ChangeState.Untracked, Models.ChangeState.Untracked);
- break;
- default:
- return;
+ var match = REG_FORMAT().Match(line);
+ if (!match.Success)
+ continue;
+
+ var change = new Models.Change() { Path = match.Groups[2].Value };
+ var status = match.Groups[1].Value;
+
+ switch (status)
+ {
+ case " M":
+ change.Set(Models.ChangeState.None, Models.ChangeState.Modified);
+ break;
+ case " T":
+ change.Set(Models.ChangeState.None, Models.ChangeState.TypeChanged);
+ break;
+ case " A":
+ change.Set(Models.ChangeState.None, Models.ChangeState.Added);
+ break;
+ case " D":
+ change.Set(Models.ChangeState.None, Models.ChangeState.Deleted);
+ break;
+ case " R":
+ change.Set(Models.ChangeState.None, Models.ChangeState.Renamed);
+ break;
+ case " C":
+ change.Set(Models.ChangeState.None, Models.ChangeState.Copied);
+ break;
+ case "M":
+ change.Set(Models.ChangeState.Modified);
+ break;
+ case "MM":
+ change.Set(Models.ChangeState.Modified, Models.ChangeState.Modified);
+ break;
+ case "MT":
+ change.Set(Models.ChangeState.Modified, Models.ChangeState.TypeChanged);
+ break;
+ case "MD":
+ change.Set(Models.ChangeState.Modified, Models.ChangeState.Deleted);
+ break;
+ case "T":
+ change.Set(Models.ChangeState.TypeChanged);
+ break;
+ case "TM":
+ change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Modified);
+ break;
+ case "TT":
+ change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.TypeChanged);
+ break;
+ case "TD":
+ change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Deleted);
+ break;
+ case "A":
+ change.Set(Models.ChangeState.Added);
+ break;
+ case "AM":
+ change.Set(Models.ChangeState.Added, Models.ChangeState.Modified);
+ break;
+ case "AT":
+ change.Set(Models.ChangeState.Added, Models.ChangeState.TypeChanged);
+ break;
+ case "AD":
+ change.Set(Models.ChangeState.Added, Models.ChangeState.Deleted);
+ break;
+ case "D":
+ change.Set(Models.ChangeState.Deleted);
+ break;
+ case "R":
+ change.Set(Models.ChangeState.Renamed);
+ break;
+ case "RM":
+ change.Set(Models.ChangeState.Renamed, Models.ChangeState.Modified);
+ break;
+ case "RT":
+ change.Set(Models.ChangeState.Renamed, Models.ChangeState.TypeChanged);
+ break;
+ case "RD":
+ change.Set(Models.ChangeState.Renamed, Models.ChangeState.Deleted);
+ break;
+ case "C":
+ change.Set(Models.ChangeState.Copied);
+ break;
+ case "CM":
+ change.Set(Models.ChangeState.Copied, Models.ChangeState.Modified);
+ break;
+ case "CT":
+ change.Set(Models.ChangeState.Copied, Models.ChangeState.TypeChanged);
+ break;
+ case "CD":
+ change.Set(Models.ChangeState.Copied, Models.ChangeState.Deleted);
+ break;
+ case "DR":
+ change.Set(Models.ChangeState.Deleted, Models.ChangeState.Renamed);
+ break;
+ case "DC":
+ change.Set(Models.ChangeState.Deleted, Models.ChangeState.Copied);
+ break;
+ case "DD":
+ change.Set(Models.ChangeState.Deleted, Models.ChangeState.Deleted);
+ break;
+ case "AU":
+ change.Set(Models.ChangeState.Added, Models.ChangeState.Unmerged);
+ break;
+ case "UD":
+ change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Deleted);
+ break;
+ case "UA":
+ change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Added);
+ break;
+ case "DU":
+ change.Set(Models.ChangeState.Deleted, Models.ChangeState.Unmerged);
+ break;
+ case "AA":
+ change.Set(Models.ChangeState.Added, Models.ChangeState.Added);
+ break;
+ case "UU":
+ change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Unmerged);
+ break;
+ case "??":
+ change.Set(Models.ChangeState.Untracked, Models.ChangeState.Untracked);
+ break;
+ default:
+ break;
+ }
+
+ if (change.Index != Models.ChangeState.None || change.WorkTree != Models.ChangeState.None)
+ outs.Add(change);
}
- _changes.Add(change);
+ return outs;
}
-
- private readonly List _changes = new List();
}
}
diff --git a/src/Commands/QueryRemotes.cs b/src/Commands/QueryRemotes.cs
index b5b41b4a..7afec74d 100644
--- a/src/Commands/QueryRemotes.cs
+++ b/src/Commands/QueryRemotes.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace SourceGit.Commands
@@ -17,27 +18,31 @@ namespace SourceGit.Commands
public List Result()
{
- Exec();
- return _loaded;
- }
+ var outs = new List();
+ var rs = ReadToEnd();
+ if (!rs.IsSuccess)
+ return outs;
- protected override void OnReadline(string line)
- {
- var match = REG_REMOTE().Match(line);
- if (!match.Success)
- return;
-
- var remote = new Models.Remote()
+ var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
+ foreach (var line in lines)
{
- Name = match.Groups[1].Value,
- URL = match.Groups[2].Value,
- };
+ var match = REG_REMOTE().Match(line);
+ if (!match.Success)
+ continue;
- if (_loaded.Find(x => x.Name == remote.Name) != null)
- return;
- _loaded.Add(remote);
+ var remote = new Models.Remote()
+ {
+ Name = match.Groups[1].Value,
+ URL = match.Groups[2].Value,
+ };
+
+ if (outs.Find(x => x.Name == remote.Name) != null)
+ continue;
+
+ outs.Add(remote);
+ }
+
+ return outs;
}
-
- private readonly List _loaded = new List();
}
}
diff --git a/src/Commands/QueryStashes.cs b/src/Commands/QueryStashes.cs
index dd5d10cc..b4067aaf 100644
--- a/src/Commands/QueryStashes.cs
+++ b/src/Commands/QueryStashes.cs
@@ -14,35 +14,50 @@ namespace SourceGit.Commands
public List Result()
{
- Exec();
- return _stashes;
- }
+ var outs = new List();
+ var rs = ReadToEnd();
+ if (!rs.IsSuccess)
+ return outs;
- protected override void OnReadline(string line)
- {
- switch (_nextLineIdx)
+ var nextPartIdx = 0;
+ var start = 0;
+ var end = rs.StdOut.IndexOf('\n', start);
+ while (end > 0)
{
- case 0:
- _current = new Models.Stash() { SHA = line };
- _stashes.Add(_current);
- break;
- case 1:
- ParseParent(line);
- break;
- case 2:
- _current.Time = ulong.Parse(line);
- break;
- case 3:
- _current.Name = line;
- break;
- case 4:
- _current.Message = line;
- break;
+ var line = rs.StdOut.Substring(start, end - start);
+
+ switch (nextPartIdx)
+ {
+ case 0:
+ _current = new Models.Stash() { SHA = line };
+ outs.Add(_current);
+ break;
+ case 1:
+ ParseParent(line);
+ break;
+ case 2:
+ _current.Time = ulong.Parse(line);
+ break;
+ case 3:
+ _current.Name = line;
+ break;
+ case 4:
+ _current.Message = line;
+ break;
+ }
+
+ nextPartIdx++;
+ if (nextPartIdx > 4)
+ nextPartIdx = 0;
+
+ start = end + 1;
+ end = rs.StdOut.IndexOf('\n', start);
}
- _nextLineIdx++;
- if (_nextLineIdx > 4)
- _nextLineIdx = 0;
+ if (start < rs.StdOut.Length)
+ _current.Message = rs.StdOut.Substring(start);
+
+ return outs;
}
private void ParseParent(string data)
@@ -53,8 +68,6 @@ namespace SourceGit.Commands
_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/Statistics.cs b/src/Commands/Statistics.cs
index 41b3889e..ea0b86de 100644
--- a/src/Commands/Statistics.cs
+++ b/src/Commands/Statistics.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
namespace SourceGit.Commands
{
@@ -40,7 +40,7 @@ namespace SourceGit.Commands
if (dateEndIdx == -1)
return;
- var dateStr = line.Substring(0, dateEndIdx);
+ var dateStr = line.AsSpan().Slice(0, dateEndIdx);
if (double.TryParse(dateStr, out var date))
statistics.AddCommit(line.Substring(dateEndIdx + 1), date);
}
diff --git a/src/Commands/Submodule.cs b/src/Commands/Submodule.cs
index 9a273703..e4f35fca 100644
--- a/src/Commands/Submodule.cs
+++ b/src/Commands/Submodule.cs
@@ -1,6 +1,4 @@
-using System;
-
-namespace SourceGit.Commands
+namespace SourceGit.Commands
{
public class Submodule : Command
{
@@ -10,9 +8,8 @@ namespace SourceGit.Commands
Context = repo;
}
- public bool Add(string url, string relativePath, bool recursive, Action outputHandler)
+ public bool Add(string url, string relativePath, bool recursive)
{
- _outputHandler = outputHandler;
Args = $"submodule add {url} \"{relativePath}\"";
if (!Exec())
return false;
@@ -29,7 +26,7 @@ namespace SourceGit.Commands
}
}
- public bool Update(string module, bool init, bool recursive, bool useRemote, Action outputHandler)
+ public bool Update(string module, bool init, bool recursive, bool useRemote)
{
Args = "submodule update";
@@ -42,7 +39,6 @@ namespace SourceGit.Commands
if (!string.IsNullOrEmpty(module))
Args += $" -- \"{module}\"";
- _outputHandler = outputHandler;
return Exec();
}
@@ -55,12 +51,5 @@ namespace SourceGit.Commands
Args = $"rm -rf \"{relativePath}\"";
return Exec();
}
-
- protected override void OnReadline(string line)
- {
- _outputHandler?.Invoke(line);
- }
-
- private Action _outputHandler;
}
}
diff --git a/src/Commands/Tag.cs b/src/Commands/Tag.cs
index 23dbb11c..6fc8dc34 100644
--- a/src/Commands/Tag.cs
+++ b/src/Commands/Tag.cs
@@ -1,26 +1,27 @@
-using System.Collections.Generic;
-using System.IO;
+using System.IO;
namespace SourceGit.Commands
{
public static class Tag
{
- public static bool Add(string repo, string name, string basedOn)
+ public static bool Add(string repo, string name, string basedOn, Models.ICommandLog log)
{
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
cmd.Args = $"tag {name} {basedOn}";
+ cmd.Log = log;
return cmd.Exec();
}
- public static bool Add(string repo, string name, string basedOn, string message, bool sign)
+ public static bool Add(string repo, string name, string basedOn, string message, bool sign, Models.ICommandLog log)
{
var param = sign ? "--sign -a" : "--no-sign -a";
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
cmd.Args = $"tag {param} {name} {basedOn} ";
+ cmd.Log = log;
if (!string.IsNullOrEmpty(message))
{
@@ -36,22 +37,14 @@ namespace SourceGit.Commands
return cmd.Exec();
}
- public static bool Delete(string repo, string name, List remotes)
+ public static bool Delete(string repo, string name, Models.ICommandLog log)
{
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
cmd.Args = $"tag --delete {name}";
- if (!cmd.Exec())
- return false;
-
- if (remotes != null)
- {
- foreach (var r in remotes)
- new Push(repo, r.Name, $"refs/tags/{name}", true).Exec();
- }
-
- return true;
+ cmd.Log = log;
+ return cmd.Exec();
}
}
}
diff --git a/src/Commands/UpdateRef.cs b/src/Commands/UpdateRef.cs
index ba1b3d2f..1e7bb239 100644
--- a/src/Commands/UpdateRef.cs
+++ b/src/Commands/UpdateRef.cs
@@ -1,23 +1,12 @@
-using System;
-
-namespace SourceGit.Commands
+namespace SourceGit.Commands
{
public class UpdateRef : Command
{
- public UpdateRef(string repo, string refName, string toRevision, Action outputHandler)
+ public UpdateRef(string repo, string refName, string toRevision)
{
- _outputHandler = outputHandler;
-
WorkingDirectory = repo;
Context = repo;
Args = $"update-ref {refName} {toRevision}";
}
-
- protected override void OnReadline(string line)
- {
- _outputHandler?.Invoke(line);
- }
-
- private Action _outputHandler;
}
}
diff --git a/src/Commands/Worktree.cs b/src/Commands/Worktree.cs
index 960d5501..1198a443 100644
--- a/src/Commands/Worktree.cs
+++ b/src/Commands/Worktree.cs
@@ -56,7 +56,7 @@ namespace SourceGit.Commands
return worktrees;
}
- public bool Add(string fullpath, string name, bool createNew, string tracking, Action outputHandler)
+ public bool Add(string fullpath, string name, bool createNew, string tracking)
{
Args = "worktree add ";
@@ -78,14 +78,12 @@ namespace SourceGit.Commands
else if (!string.IsNullOrEmpty(name) && !createNew)
Args += name;
- _outputHandler = outputHandler;
return Exec();
}
- public bool Prune(Action outputHandler)
+ public bool Prune()
{
Args = "worktree prune -v";
- _outputHandler = outputHandler;
return Exec();
}
@@ -101,22 +99,14 @@ namespace SourceGit.Commands
return Exec();
}
- public bool Remove(string fullpath, bool force, Action outputHandler)
+ public bool Remove(string fullpath, bool force)
{
if (force)
Args = $"worktree remove -f \"{fullpath}\"";
else
Args = $"worktree remove \"{fullpath}\"";
- _outputHandler = outputHandler;
return Exec();
}
-
- protected override void OnReadline(string line)
- {
- _outputHandler?.Invoke(line);
- }
-
- private Action _outputHandler = null;
}
}
diff --git a/src/Models/Branch.cs b/src/Models/Branch.cs
index 2d0ae5b2..d0ac1990 100644
--- a/src/Models/Branch.cs
+++ b/src/Models/Branch.cs
@@ -34,7 +34,7 @@ namespace SourceGit.Models
public string Upstream { get; set; }
public BranchTrackStatus TrackStatus { get; set; }
public string Remote { get; set; }
- public bool IsUpsteamGone { get; set; }
+ public bool IsUpstreamGone { get; set; }
public string FriendlyName => IsLocal ? Name : $"{Remote}/{Name}";
}
diff --git a/src/Models/ConventionalCommitType.cs b/src/Models/ConventionalCommitType.cs
index 4fb61d87..cd09453a 100644
--- a/src/Models/ConventionalCommitType.cs
+++ b/src/Models/ConventionalCommitType.cs
@@ -4,23 +4,29 @@ namespace SourceGit.Models
{
public class ConventionalCommitType
{
+ public string Name { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public static readonly List Supported = new List()
{
- new ConventionalCommitType("feat", "Adding a new feature"),
- new ConventionalCommitType("fix", "Fixing a bug"),
- new ConventionalCommitType("docs", "Updating documentation"),
- new ConventionalCommitType("style", "Elements or code styles without changing the code logic"),
- new ConventionalCommitType("test", "Adding or updating tests"),
- new ConventionalCommitType("chore", "Making changes to the build process or auxiliary tools and libraries"),
- new ConventionalCommitType("revert", "Undoing a previous commit"),
- new ConventionalCommitType("refactor", "Restructuring code without changing its external behavior")
+ new ConventionalCommitType("Features", "feat", "Adding a new feature"),
+ new ConventionalCommitType("Bug Fixes", "fix", "Fixing a bug"),
+ new ConventionalCommitType("Work In Progress", "wip", "Still being developed and not yet complete"),
+ new ConventionalCommitType("Reverts", "revert", "Undoing a previous commit"),
+ new ConventionalCommitType("Code Refactoring", "refactor", "Restructuring code without changing its external behavior"),
+ new ConventionalCommitType("Performance Improvements", "pref", "Improves performance"),
+ new ConventionalCommitType("Builds", "build", "Changes that affect the build system or external dependencies"),
+ new ConventionalCommitType("Continuous Integrations", "ci", "Changes to CI configuration files and scripts"),
+ new ConventionalCommitType("Documentations", "docs", "Updating documentation"),
+ new ConventionalCommitType("Styles", "style", "Elements or code styles without changing the code logic"),
+ new ConventionalCommitType("Tests", "test", "Adding or updating tests"),
+ new ConventionalCommitType("Chores", "chore", "Other changes that don't modify src or test files"),
};
- public ConventionalCommitType(string type, string description)
+ public ConventionalCommitType(string name, string type, string description)
{
+ Name = name;
Type = type;
Description = description;
}
diff --git a/src/Models/DiffResult.cs b/src/Models/DiffResult.cs
index 88992e10..e7d17994 100644
--- a/src/Models/DiffResult.cs
+++ b/src/Models/DiffResult.cs
@@ -30,6 +30,7 @@ namespace SourceGit.Models
public int OldLineNumber { get; set; } = 0;
public int NewLineNumber { get; set; } = 0;
public List Highlights { get; set; } = new List();
+ public bool NoNewLineEndOfFile { get; set; } = false;
public string OldLine => OldLineNumber == 0 ? string.Empty : OldLineNumber.ToString();
public string NewLine => NewLineNumber == 0 ? string.Empty : NewLineNumber.ToString();
diff --git a/src/Models/ICommandLog.cs b/src/Models/ICommandLog.cs
new file mode 100644
index 00000000..34ec7031
--- /dev/null
+++ b/src/Models/ICommandLog.cs
@@ -0,0 +1,7 @@
+namespace SourceGit.Models
+{
+ public interface ICommandLog
+ {
+ void AppendLine(string line);
+ }
+}
diff --git a/src/Models/InteractiveRebase.cs b/src/Models/InteractiveRebase.cs
index 691aadeb..d1710d4a 100644
--- a/src/Models/InteractiveRebase.cs
+++ b/src/Models/InteractiveRebase.cs
@@ -27,6 +27,8 @@ namespace SourceGit.Models
public class InteractiveRebaseJobCollection
{
+ public string OrigHead { get; set; } = string.Empty;
+ public string Onto { get; set; } = string.Empty;
public List Jobs { get; set; } = new List();
}
}
diff --git a/src/Models/IpcChannel.cs b/src/Models/IpcChannel.cs
new file mode 100644
index 00000000..2ecfb771
--- /dev/null
+++ b/src/Models/IpcChannel.cs
@@ -0,0 +1,104 @@
+using System;
+using System.IO;
+using System.IO.Pipes;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SourceGit.Models
+{
+ public class IpcChannel : IDisposable
+ {
+ public bool IsFirstInstance
+ {
+ get => _isFirstInstance;
+ }
+
+ public event Action MessageReceived;
+
+ public IpcChannel()
+ {
+ try
+ {
+ _singletoneLock = File.Open(Path.Combine(Native.OS.DataDir, "process.lock"), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
+ _isFirstInstance = true;
+ _server = new NamedPipeServerStream(
+ "SourceGitIPCChannel",
+ PipeDirection.In,
+ -1,
+ PipeTransmissionMode.Byte,
+ PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly);
+ _cancellationTokenSource = new CancellationTokenSource();
+ Task.Run(StartServer);
+ }
+ catch
+ {
+ _isFirstInstance = false;
+ }
+ }
+
+ public void SendToFirstInstance(string cmd)
+ {
+ try
+ {
+ using (var client = new NamedPipeClientStream(".", "SourceGitIPCChannel", PipeDirection.Out))
+ {
+ client.Connect(1000);
+ if (!client.IsConnected)
+ return;
+
+ using (var writer = new StreamWriter(client))
+ {
+ writer.WriteLine(cmd);
+ writer.Flush();
+ }
+
+ if (OperatingSystem.IsWindows())
+ client.WaitForPipeDrain();
+ else
+ Thread.Sleep(1000);
+ }
+ }
+ catch
+ {
+ // IGNORE
+ }
+ }
+
+ public void Dispose()
+ {
+ _cancellationTokenSource?.Cancel();
+ _singletoneLock?.Dispose();
+ }
+
+ private async void StartServer()
+ {
+ using var reader = new StreamReader(_server);
+
+ while (!_cancellationTokenSource.IsCancellationRequested)
+ {
+ try
+ {
+ await _server.WaitForConnectionAsync(_cancellationTokenSource.Token);
+
+ if (!_cancellationTokenSource.IsCancellationRequested)
+ {
+ var line = await reader.ReadToEndAsync(_cancellationTokenSource.Token);
+ MessageReceived?.Invoke(line?.Trim());
+ }
+
+ _server.Disconnect();
+ }
+ catch
+ {
+ if (!_cancellationTokenSource.IsCancellationRequested && _server.IsConnected)
+ _server.Disconnect();
+ }
+ }
+ }
+
+ private FileStream _singletoneLock = null;
+ private bool _isFirstInstance = false;
+ private NamedPipeServerStream _server = null;
+ private CancellationTokenSource _cancellationTokenSource = null;
+ }
+}
diff --git a/src/Models/Locales.cs b/src/Models/Locales.cs
index a7884e8b..1788a9b2 100644
--- a/src/Models/Locales.cs
+++ b/src/Models/Locales.cs
@@ -14,6 +14,7 @@ namespace SourceGit.Models
new Locale("Français", "fr_FR"),
new Locale("Italiano", "it_IT"),
new Locale("Português (Brasil)", "pt_BR"),
+ new Locale("Українська", "uk_UA"),
new Locale("Русский", "ru_RU"),
new Locale("简体中文", "zh_CN"),
new Locale("繁體中文", "zh_TW"),
diff --git a/src/Models/RepositorySettings.cs b/src/Models/RepositorySettings.cs
index fc5e81b4..34a72033 100644
--- a/src/Models/RepositorySettings.cs
+++ b/src/Models/RepositorySettings.cs
@@ -230,6 +230,12 @@ namespace SourceGit.Models
set;
} = 0;
+ public string LastCommitMessage
+ {
+ get;
+ set;
+ } = string.Empty;
+
public Dictionary CollectHistoriesFilters()
{
var map = new Dictionary();
diff --git a/src/Models/Statistics.cs b/src/Models/Statistics.cs
index 87a6eabd..d982a3ed 100644
--- a/src/Models/Statistics.cs
+++ b/src/Models/Statistics.cs
@@ -11,36 +11,31 @@ using SkiaSharp;
namespace SourceGit.Models
{
- public enum StaticsticsMode
+ public enum StatisticsMode
{
All,
ThisMonth,
ThisWeek,
}
- public class StaticsticsAuthor(User user, int count)
+ public class StatisticsAuthor(User user, int count)
{
public User User { get; set; } = user;
public int Count { get; set; } = count;
}
- public class StaticsticsSample(DateTime time, int count)
- {
- public DateTime Time { get; set; } = time;
- public int Count { get; set; } = count;
- }
-
public class StatisticsReport
{
public static readonly string[] WEEKDAYS = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
public int Total { get; set; } = 0;
- public List Authors { get; set; } = new List();
+ public List Authors { get; set; } = new List();
public List Series { get; set; } = new List();
public List XAxes { get; set; } = new List();
public List YAxes { get; set; } = new List();
+ public StatisticsAuthor SelectedAuthor { get => _selectedAuthor; set => ChangeAuthor(value); }
- public StatisticsReport(StaticsticsMode mode, DateTime start)
+ public StatisticsReport(StatisticsMode mode, DateTime start)
{
_mode = mode;
@@ -51,14 +46,14 @@ namespace SourceGit.Models
SeparatorsPaint = new SolidColorPaint(new SKColor(0x40808080)) { StrokeThickness = 1 }
}];
- if (mode == StaticsticsMode.ThisWeek)
+ if (mode == StatisticsMode.ThisWeek)
{
for (int i = 0; i < 7; i++)
_mapSamples.Add(start.AddDays(i), 0);
XAxes.Add(new DateTimeAxis(TimeSpan.FromDays(1), v => WEEKDAYS[(int)v.DayOfWeek]) { TextSize = 10 });
}
- else if (mode == StaticsticsMode.ThisMonth)
+ else if (mode == StatisticsMode.ThisMonth)
{
var now = DateTime.Now;
var maxDays = DateTime.DaysInMonth(now.Year, now.Month);
@@ -78,7 +73,7 @@ namespace SourceGit.Models
Total++;
var normalized = DateTime.MinValue;
- if (_mode == StaticsticsMode.ThisWeek || _mode == StaticsticsMode.ThisMonth)
+ if (_mode == StatisticsMode.ThisWeek || _mode == StatisticsMode.ThisMonth)
normalized = time.Date;
else
normalized = new DateTime(time.Year, time.Month, 1).ToLocalTime();
@@ -92,10 +87,30 @@ namespace SourceGit.Models
_mapUsers[author] = vu + 1;
else
_mapUsers.Add(author, 1);
+
+ if (_mapUserSamples.TryGetValue(author, out var vus))
+ {
+ if (vus.TryGetValue(normalized, out var n))
+ vus[normalized] = n + 1;
+ else
+ vus.Add(normalized, 1);
+ }
+ else
+ {
+ _mapUserSamples.Add(author, new Dictionary
+ {
+ { normalized, 1 }
+ });
+ }
}
public void Complete()
{
+ foreach (var kv in _mapUsers)
+ Authors.Add(new StatisticsAuthor(kv.Key, kv.Value));
+
+ Authors.Sort((l, r) => r.Count - l.Count);
+
var samples = new List();
foreach (var kv in _mapSamples)
samples.Add(new DateTimePoint(kv.Key, kv.Value));
@@ -110,24 +125,59 @@ namespace SourceGit.Models
}
);
- foreach (var kv in _mapUsers)
- Authors.Add(new StaticsticsAuthor(kv.Key, kv.Value));
-
- Authors.Sort((l, r) => r.Count - l.Count);
-
_mapUsers.Clear();
_mapSamples.Clear();
}
public void ChangeColor(uint color)
{
- if (Series is [ColumnSeries series])
- series.Fill = new SolidColorPaint(new SKColor(color));
+ _fillColor = color;
+
+ var fill = new SKColor(color);
+
+ if (Series.Count > 0 && Series[0] is ColumnSeries total)
+ total.Fill = new SolidColorPaint(_selectedAuthor == null ? fill : fill.WithAlpha(51));
+
+ if (Series.Count > 1 && Series[1] is ColumnSeries user)
+ user.Fill = new SolidColorPaint(fill);
}
- private StaticsticsMode _mode = StaticsticsMode.All;
+ public void ChangeAuthor(StatisticsAuthor author)
+ {
+ if (author == _selectedAuthor)
+ return;
+
+ _selectedAuthor = author;
+ Series.RemoveRange(1, Series.Count - 1);
+ if (author == null || !_mapUserSamples.TryGetValue(author.User, out var userSamples))
+ {
+ ChangeColor(_fillColor);
+ return;
+ }
+
+ var samples = new List();
+ foreach (var kv in userSamples)
+ samples.Add(new DateTimePoint(kv.Key, kv.Value));
+
+ Series.Add(
+ new ColumnSeries()
+ {
+ Values = samples,
+ Stroke = null,
+ Fill = null,
+ Padding = 1,
+ }
+ );
+
+ ChangeColor(_fillColor);
+ }
+
+ private StatisticsMode _mode = StatisticsMode.All;
private Dictionary _mapUsers = new Dictionary();
private Dictionary _mapSamples = new Dictionary();
+ private Dictionary> _mapUserSamples = new Dictionary>();
+ private StatisticsAuthor _selectedAuthor = null;
+ private uint _fillColor = 255;
}
public class Statistics
@@ -143,9 +193,9 @@ namespace SourceGit.Models
_thisWeekStart = _today.AddDays(-weekOffset);
_thisMonthStart = _today.AddDays(1 - _today.Day);
- All = new StatisticsReport(StaticsticsMode.All, DateTime.MinValue);
- Month = new StatisticsReport(StaticsticsMode.ThisMonth, _thisMonthStart);
- Week = new StatisticsReport(StaticsticsMode.ThisWeek, _thisWeekStart);
+ All = new StatisticsReport(StatisticsMode.All, DateTime.MinValue);
+ Month = new StatisticsReport(StatisticsMode.ThisMonth, _thisMonthStart);
+ Week = new StatisticsReport(StatisticsMode.ThisWeek, _thisWeekStart);
}
public void AddCommit(string author, double timestamp)
diff --git a/src/Resources/Icons.axaml b/src/Resources/Icons.axaml
index 66589440..51e3d8bf 100644
--- a/src/Resources/Icons.axaml
+++ b/src/Resources/Icons.axaml
@@ -46,6 +46,7 @@
M416 832H128V128h384v192C512 355 541 384 576 384L768 384v32c0 19 13 32 32 32S832 435 832 416v-64c0-6 0-19-6-25l-256-256c-6-6-19-6-25-6H128A64 64 0 0064 128v704C64 867 93 896 129 896h288c19 0 32-13 32-32S435 832 416 832zM576 172 722 320H576V172zM736 512C614 512 512 614 512 736S614 960 736 960s224-102 224-224S858 512 736 512zM576 736C576 646 646 576 736 576c32 0 58 6 83 26l-218 218c-19-26-26-51-26-83zm160 160c-32 0-64-13-96-32l224-224c19 26 32 58 32 96 0 90-70 160-160 160z
M896 320c0-19-6-32-19-45l-192-192c-13-13-26-19-45-19H192c-38 0-64 26-64 64v768c0 38 26 64 64 64h640c38 0 64-26 64-64V320zm-256 384H384c-19 0-32-13-32-32s13-32 32-32h256c19 0 32 13 32 32s-13 32-32 32zm166-384H640V128l192 192h-26z
M599 425 599 657 425 832 425 425 192 192 832 192Z
+ M505 74c-145 3-239 68-239 68-12 8-15 25-7 37 9 13 25 15 38 6 0 0 184-136 448 2 12 7 29 3 36-10 8-13 3-29-12-37-71-38-139-56-199-63-23-3-44-3-65-3m17 111c-254-3-376 201-376 201-8 12-5 29 7 37 12 8 29 4 39-10 0 0 103-178 329-175 226 3 325 173 325 173 8 12 24 17 37 9 14-8 17-24 9-37 0 0-117-195-370-199m-31 106c-72 5-140 31-192 74C197 449 132 603 204 811c5 14 20 21 34 17 14-5 21-20 16-34-66-191-7-316 79-388 84-69 233-85 343-17 54 34 96 93 118 151 22 58 20 114 3 141-18 28-54 38-86 30-32-8-58-31-59-80-1-73-58-118-118-125-57-7-123 24-140 92-32 125 49 302 238 361 14 4 29-3 34-17 4-14-3-29-18-34-163-51-225-206-202-297 10-41 46-55 84-52 37 4 69 26 69 73 2 70 48 117 100 131 52 13 112-3 144-52 33-50 28-120 3-188-26-68-73-136-140-178a356 356 0 00-213-52m15 104v0c-76 3-152 42-195 125-56 106-31 215 7 293 38 79 90 131 90 131 10 11 27 11 38 0s11-26 0-38c0 0-46-47-79-116s-54-157-8-244c48-90 133-111 208-90 76 22 140 88 138 186-2 15 9 28 24 29 15 1 27-10 29-27 3-122-79-210-176-239a246 246 0 00-75-9m9 213c-15 0-26 13-26 27 0 0 1 63 36 124 36 61 112 119 244 107 15-1 26-13 25-28-1-15-14-26-30-25-116 11-165-33-193-81-28-47-29-98-29-98a27 27 0 00-27-27z
m211 611a142 142 0 00-90-4v-190a142 142 0 0090-4v198zm0 262v150h-90v-146a142 142 0 0090-4zm0-723a142 142 0 00-90-4v-146h90zm-51 246a115 115 0 11115-115 115 115 0 01-115 115zm0 461a115 115 0 11115-115 115 115 0 01-115 115zm256-691h563v90h-563zm0 461h563v90h-563zm0-282h422v90h-422zm0 474h422v90h-422z
M853 267H514c-4 0-6-2-9-4l-38-66c-13-21-38-36-64-36H171c-41 0-75 34-75 75v555c0 41 34 75 75 75h683c41 0 75-34 75-75V341c0-41-34-75-75-75zm-683-43h233c4 0 6 2 9 4l38 66c13 21 38 36 64 36H853c6 0 11 4 11 11v75h-704V235c0-6 4-11 11-11zm683 576H171c-6 0-11-4-11-11V480h704V789c0 6-4 11-11 11z
M1088 227H609L453 78a11 11 0 00-7-3H107a43 43 0 00-43 43v789a43 43 0 0043 43h981a43 43 0 0043-43V270a43 43 0 00-43-43zM757 599c0 5-5 9-10 9h-113v113c0 5-4 9-9 9h-56c-5 0-9-4-9-9V608h-113c-5 0-10-4-10-9V543c0-5 5-9 10-9h113V420c0-5 4-9 9-9h56c5 0 9 4 9 9V533h113c5 0 10 4 10 9v56z
@@ -78,6 +79,7 @@
M512 0C233 0 7 223 0 500C6 258 190 64 416 64c230 0 416 200 416 448c0 53 43 96 96 96s96-43 96-96c0-283-229-512-512-512zm0 1023c279 0 505-223 512-500c-6 242-190 436-416 436c-230 0-416-200-416-448c0-53-43-96-96-96s-96 43-96 96c0 283 229 512 512 512z
M976 0h-928A48 48 0 000 48v652a48 48 0 0048 48h416V928H200a48 48 0 000 96h624a48 48 0 000-96H560v-180h416a48 48 0 0048-48V48A48 48 0 00976 0zM928 652H96V96h832v556z
M832 464h-68V240a128 128 0 00-128-128h-248a128 128 0 00-128 128v224H192c-18 0-32 14-32 32v384c0 18 14 32 32 32h640c18 0 32-14 32-32v-384c0-18-14-32-32-32zm-292 237v53a8 8 0 01-8 8h-40a8 8 0 01-8-8v-53a48 48 0 1156 0zm152-237H332V240a56 56 0 0156-56h248a56 56 0 0156 56v224z
+ M908 366h-25V248a18 18 0 00-0-2 20 20 0 00-5-13L681 7 681 7a19 19 0 00-4-3c-0-0-1-1-1-1a29 29 0 00-4-2L671 1a24 24 0 00-5-1H181a40 40 0 00-40 40v326h-25c-32 0-57 26-57 57v298c0 32 26 57 57 57h25v204c0 22 18 40 40 40H843a40 40 0 0040-40v-204h25c32 0 57-26 57-57V424a57 57 0 00-57-57zM181 40h465v205c0 11 9 20 20 20h177v101H181V40zm413 527c0 89-54 143-134 143-81 0-128-61-128-138 0-82 52-143 132-143 84 0 129 63 129 138zm-440 139V433h62v220h108v52h-170zm690 267H181v-193H843l0 193zm18-280a305 305 0 01-91 15c-50 0-86-12-111-37-25-23-39-59-38-99 0-90 66-142 155-142 35 0 62 7 76 13l-13 49c-15-6-33-12-63-12-51 0-90 29-90 88 0 56 35 89 86 89 14 0 25-2 30-4v-57h-42v-48h101v143zM397 570c0 53 25 91 66 91 42 0 65-40 65-92 0-49-23-91-66-91-42 0-66 40-66 93z
M192 192m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0ZM192 512m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0ZM192 832m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0ZM864 160H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32zM864 480H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32zM864 800H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32z
M824 645V307c0-56-46-102-102-102h-102V102l-154 154 154 154V307h102v338c-46 20-82 67-82 123 0 72 61 133 133 133 72 0 133-61 133-133 0-56-36-102-82-123zm-51 195c-41 0-72-31-72-72s31-72 72-72c41 0 72 31 72 72s-31 72-72 72zM384 256c0-72-61-133-133-133-72 0-133 61-133 133 0 56 36 102 82 123v266C154 666 118 712 118 768c0 72 61 133 133 133 72 0 133-61 133-133 0-56-36-102-82-123V379C348 358 384 312 384 256zM323 768c0 41-31 72-72 72-41 0-72-31-72-72s31-72 72-72c41 0 72 31 72 72zM251 328c-41 0-72-31-72-72s31-72 72-72c41 0 72 31 72 72s-31 72-72 72z
M896 64H128C96 64 64 96 64 128v768c0 32 32 64 64 64h768c32 0 64-32 64-64V128c0-32-32-64-64-64z m-64 736c0 16-17 32-32 32H224c-18 0-32-12-32-32V224c0-16 16-32 32-32h576c15 0 32 16 32 32v576zM512 384c-71 0-128 57-128 128s57 128 128 128 128-57 128-128-57-128-128-128z
@@ -115,6 +117,7 @@
M558 545 790 403c24-15 31-47 16-71-15-24-46-31-70-17L507 457 277 315c-24-15-56-7-71 17-15 24-7 56 17 71l232 143V819c0 28 23 51 51 51 28 0 51-23 51-51V545h0zM507 0l443 256v512L507 1024 63 768v-512L507 0z
M770 320a41 41 0 00-56-14l-252 153L207 306a41 41 0 10-43 70l255 153 2 296a41 41 0 0082 0l-2-295 255-155a41 41 0 0014-56zM481 935a42 42 0 01-42 0L105 741a42 42 0 01-21-36v-386a42 42 0 0121-36L439 89a42 42 0 0142 0l335 193a42 42 0 0121 36v87h84v-87a126 126 0 00-63-109L523 17a126 126 0 00-126 0L63 210a126 126 0 00-63 109v386a126 126 0 0063 109l335 193a126 126 0 00126 0l94-54-42-72zM1029 700h-126v-125a42 42 0 00-84 0v126h-126a42 42 0 000 84h126v126a42 42 0 1084 0v-126h126a42 42 0 000-84z
M416 587c21 0 37 17 37 37v299A37 37 0 01416 960h-299a37 37 0 01-37-37v-299c0-21 17-37 37-37h299zm448 0c21 0 37 17 37 37v299A37 37 0 01864 960h-299a37 37 0 01-37-37v-299c0-21 17-37 37-37h299zM758 91l183 189a37 37 0 010 52l-182 188a37 37 0 01-53 1l-183-189a37 37 0 010-52l182-188a37 37 0 0153-1zM416 139c21 0 37 17 37 37v299A37 37 0 01416 512h-299a37 37 0 01-37-37v-299c0-21 17-37 37-37h299z
+ M653 435l-26 119H725c9 0 13 4 13 13v47c0 9-4 13-13 13h-107l-21 115c0 9-4 13-13 13h-47c-9 0-13-4-13-13l21-111H427l-21 115c0 9-4 13-13 13H346c-9 0-13-4-13-13l21-107h-85c-4-9-9-21-13-34v-38c0-9 4-13 13-13h98l26-119H294c-9 0-13-4-13-13V375c0-9 4-13 13-13h115l13-81c0-9 4-13 13-13h43c9 0 13 4 13 13L469 363h119l13-81c0-9 4-13 13-13h47c9 0 13 4 13 13l-13 77h85c9 0 13 4 13 13v47c0 9-4 13-13 13h-98v4zM512 0C230 0 0 230 0 512c0 145 60 282 166 375L90 1024H512c282 0 512-230 512-512S794 0 512 0zm-73 559h124l26-119h-128l-21 119z
M875 128h-725A107 107 0 0043 235v555A107 107 0 00149 896h725a107 107 0 00107-107v-555A107 107 0 00875 128zm-115 640h-183v-58l25-3c15 0 19-8 14-24l-22-61H419l-28 82 39 2V768h-166v-58l18-3c18-2 22-11 26-24l125-363-40-4V256h168l160 448 39 3zM506 340l-72 218h145l-71-218h-2z
M177 156c-22 5-33 17-36 37c-10 57-33 258-13 278l445 445c23 23 61 23 84 0l246-246c23-23 23-61 0-84l-445-445C437 120 231 145 177 156zM331 344c-26 26-69 26-95 0c-26-26-26-69 0-95s69-26 95 0C357 276 357 318 331 344z
M683 537h-144v-142h-142V283H239a44 44 0 00-41 41v171a56 56 0 0014 34l321 321a41 41 0 0058 0l174-174a41 41 0 000-58zm-341-109a41 41 0 110-58a41 41 0 010 58zM649 284V142h-69v142h-142v68h142v142h69v-142h142v-68h-142z
@@ -129,6 +132,7 @@
M762 1024C876 818 895 504 448 514V768L64 384l384-384v248c535-14 595 472 314 776z
M832 464H332V240c0-31 25-56 56-56h248c31 0 56 25 56 56v68c0 4 4 8 8 8h56c4 0 8-4 8-8v-68c0-71-57-128-128-128H388c-71 0-128 57-128 128v224h-68c-18 0-32 14-32 32v384c0 18 14 32 32 32h640c18 0 32-14 32-32V496c0-18-14-32-32-32zM540 701v53c0 4-4 8-8 8h-40c-4 0-8-4-8-8v-53c-12-9-20-23-20-39 0-27 22-48 48-48s48 22 48 48c0 16-8 30-20 39z
M170 831l343-342L855 831l105-105-448-448L64 726 170 831z
+ M667 607c-3-2-7-14-0-38 73-77 118-187 118-290C784 115 668 0 508 0 348 0 236 114 236 278c0 104 45 215 119 292 7 24-2 33-8 35C274 631 0 725 0 854L0 1024l1024 0 0-192C989 714 730 627 667 607L667 607z
M880 128A722 722 0 01555 13a77 77 0 00-85 0 719 719 0 01-325 115c-40 4-71 38-71 80v369c0 246 329 446 439 446 110 0 439-200 439-446V207c0-41-31-76-71-80zM465 692a36 36 0 01-53 0L305 579a42 42 0 010-57 36 36 0 0153 0l80 85L678 353a36 36 0 0153 0 42 42 0 01-0 57L465 692z
M812 864h-29V654c0-21-11-40-28-52l-133-88 134-89c18-12 28-31 28-52V164h28c18 0 32-14 32-32s-14-32-32-32H212c-18 0-32 14-32 32s14 32 32 32h30v210c0 21 11 40 28 52l133 88-134 89c-18 12-28 31-28 52V864H212c-18 0-32 14-32 32s14 32 32 32h600c18 0 32-14 32-32s-14-32-32-32zM441 566c18-12 28-31 28-52s-11-40-28-52L306 373V164h414v209l-136 90c-18 12-28 31-28 52 0 21 11 40 28 52l135 89V695c-9-7-20-13-32-19-30-15-93-41-176-41-63 0-125 14-175 38-12 6-22 12-31 18v-36l136-90z
M0 512M1024 512M512 0M512 1024M762 412v100h-500v-100h-150v200h800v-200h-150z
diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml
index 25b54c60..7a3da294 100644
--- a/src/Resources/Locales/de_DE.axaml
+++ b/src/Resources/Locales/de_DE.axaml
@@ -102,8 +102,8 @@
Mehrere cherry-picken
Mit HEAD vergleichen
Mit Worktree vergleichen
- Info kopieren
- SHA kopieren
+ Information
+ SHA
Benutzerdefinierte Aktion
Interactives Rebase von ${0}$ auf diesen Commit
Merge in ${0}$ hinein
@@ -176,6 +176,7 @@
Benutzername für dieses Repository
Arbeitsplätze
Farbe
+ Name
Zuletzt geöffnete Tabs beim Starten wiederherstellen
Konventionelle Commit-Hilfe
Breaking Change:
@@ -235,7 +236,7 @@
ALT
Kopieren
Dateimodus geändert
- Ignoriere Leerzeichenänderungen
+ Ignoriere Leerzeichenänderungen und EOL
LFS OBJEKT ÄNDERUNG
Nächste Änderung
KEINE ÄNDERUNG ODER NUR ZEILEN-ENDE ÄNDERUNGEN
diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml
index ad71427b..20a70f22 100644
--- a/src/Resources/Locales/en_US.axaml
+++ b/src/Resources/Locales/en_US.axaml
@@ -3,15 +3,15 @@
About SourceGit
Opensource & Free Git GUI Client
Add Worktree
- What to Checkout:
- Existing Branch
- Create New Branch
Location:
Path for this worktree. Relative path is supported.
Branch Name:
Optional. Default is the destination folder name.
Track Branch:
Tracking remote branch
+ What to Checkout:
+ Create New Branch
+ Existing Branch
AI Assistant
RE-GENERATE
Use AI to generate commit message
@@ -61,8 +61,8 @@
Invalid upstream!
Bytes
CANCEL
- Reset to This Revision
Reset to Parent Revision
+ Reset to This Revision
Generate commit message
CHANGE DISPLAY MODE
Show as File and Dir List
@@ -70,12 +70,12 @@
Show as Filesystem Tree
Checkout Branch
Checkout Commit
- Warning: By doing a commit checkout, your Head will be detached
Commit:
- Branch:
+ Warning: By doing a commit checkout, your Head will be detached
Local Changes:
Discard
Stash & Reapply
+ Branch:
Cherry Pick
Append source to commit message
Commit(s):
@@ -94,13 +94,16 @@
Repository URL:
CLOSE
Editor
+ Checkout Commit
Cherry-Pick Commit
Cherry-Pick ...
- Checkout Commit
Compare with HEAD
Compare with Worktree
- Copy Info
- Copy SHA
+ Author
+ Committer
+ Information
+ SHA
+ Subject
Custom Action
Interactively Rebase ${0}$ on Here
Merge to ${0}$
@@ -131,12 +134,13 @@
REFS
SHA
Open in Browser
- Enter commit subject
Description
+ SUBJECT
+ Enter commit subject
Repository Configure
COMMIT TEMPLATE
- Template Name:
Template Content:
+ Template Name:
CUSTOM ACTION
Arguments:
${REPO} - Repository's path; ${BRANCH} - Selected branch; ${SHA} - Selected commit's SHA
@@ -155,13 +159,13 @@
Default Remote
Preferred Merge Mode
ISSUE TRACKER
+ Add Sample Azure DevOps Rule
Add Sample Gitee Issue Rule
Add Sample Gitee Pull Request Rule
Add Sample Github Rule
Add Sample GitLab Issue Rule
Add Sample GitLab Merge Request Rule
Add Sample Jira Rule
- Add Sample Azure DevOps Rule
New Rule
Issue Regex Expression:
Rule Name:
@@ -176,6 +180,7 @@
User name for this repository
Workspaces
Color
+ Name
Restore tabs on startup
CONTINUE
Empty commit detected! Do you want to continue (--allow-empty)?
@@ -190,8 +195,8 @@
Type of Change:
Copy
Copy All Text
- Copy Path
Copy Full Path
+ Copy Path
Create Branch...
Based On:
Check out the created branch
@@ -227,8 +232,8 @@
Path:
Target:
All children will be removed from list.
- Confirm Deleting Group
This will only remove it from list, not from disk!
+ Confirm Deleting Group
Confirm Deleting Repository
Delete Submodule
Submodule Path:
@@ -241,7 +246,7 @@
Copy
File Mode Changed
First Difference
- Ignore Whitespace Change
+ Ignore Whitespace Change and EOL
Last Difference
LFS OBJECT CHANGE
Next Difference
@@ -297,11 +302,11 @@
Unstage
Unstage {0} files
Unstage Changes in Selected Line(s)
- Use Theirs (checkout --theirs)
Use Mine (checkout --ours)
+ Use Theirs (checkout --theirs)
File History
- CONTENT
CHANGE
+ CONTENT
Git-Flow
Development Branch:
Feature:
@@ -331,8 +336,8 @@
Custom Pattern:
Add Track Pattern to Git LFS
Fetch
- Fetch LFS Objects
Run `git lfs fetch` to download Git LFS objects. This does not update the working copy.
+ Fetch LFS Objects
Install Git LFS hooks
Show Locks
No Locked Files
@@ -344,11 +349,11 @@
Prune
Run `git lfs prune` to delete old LFS files from local storage
Pull
- Pull LFS Objects
Run `git lfs pull` to download all Git LFS files for current ref & checkout
+ Pull LFS Objects
Push
- Push LFS Objects
Push queued large files to the Git LFS endpoint
+ Push LFS Objects
Remote:
Track files named '{0}'
Track all *{0} files
@@ -367,8 +372,8 @@
Cancel current popup
Clone new repository
Close current page
- Go to previous page
Go to next page
+ Go to previous page
Create new page
Open Preferences dialog
REPOSITORY
@@ -379,11 +384,11 @@
Discard selected changes
Fetch, starts directly
Dashboard mode (Default)
+ Commit search mode
Pull, starts directly
Push, starts directly
Force to reload this repository
Stage/Unstage selected changes
- Commit search mode
Switch to 'Changes'
Switch to 'Histories'
Switch to 'Stashes'
@@ -392,9 +397,9 @@
Find next match
Find previous match
Open search panel
+ Discard
Stage
Unstage
- Discard
Initialize Repository
Path:
Cherry-Pick in progress.
@@ -406,10 +411,10 @@
Revert in progress.
Reverting commit
Interactive Rebase
- Target Branch:
On:
- Open in Browser
+ Target Branch:
Copy Link
+ Open in Browser
ERROR
NOTICE
Merge Branch
@@ -435,16 +440,16 @@
Copy Repository Path
Repositories
Paste
- Just now
- {0} minutes ago
+ {0} days ago
1 hour ago
{0} hours ago
- Yesterday
- {0} days ago
+ Just now
Last month
- {0} months ago
Last year
+ {0} minutes ago
+ {0} months ago
{0} years ago
+ Yesterday
Preferences
AI
Analyze Diff Prompt
@@ -485,24 +490,24 @@
User Email
Global git user email
Enable --prune on fetch
+ Git (>= 2.23.0) is required by this app
Install Path
Enable HTTP SSL Verify
User Name
Global git user name
Git version
- Git (>= 2.23.0) is required by this app
GPG SIGNING
Commit GPG signing
- Tag GPG signing
GPG Format
Program Install Path
Input path for installed gpg program
+ Tag GPG signing
User Signing Key
User's gpg signing key
INTEGRATION
SHELL/TERMINAL
- Shell/Terminal
Path
+ Shell/Terminal
Prune Remote
Target:
Prune Worktrees
@@ -610,6 +615,7 @@
Sort
Open in Terminal
Use relative time in histories
+ View Logs
WORKTREES
ADD WORKTREE
PRUNE
@@ -669,11 +675,11 @@
Statistics
COMMITS
COMMITTER
+ OVERVIEW
MONTH
WEEK
- COMMITS:
AUTHORS:
- OVERVIEW
+ COMMITS:
SUBMODULES
Add Submodule
Copy Relative Path
@@ -688,13 +694,17 @@
Delete ${0}$...
Merge ${0}$ into ${1}$...
Push ${0}$...
- URL:
Update Submodules
All submodules
Initialize as needed
Recursively
Submodule:
Use --remote option
+ URL:
+ Logs
+ CLEAR ALL
+ Copy
+ Delete
Warning
Welcome Page
Create Group
@@ -734,6 +744,7 @@
INCLUDE UNTRACKED FILES
NO RECENT INPUT MESSAGES
NO COMMIT TEMPLATES
+ Right-click the selected file(s), and make your choice to resolve conflicts.
SignOff
STAGED
UNSTAGE
@@ -743,7 +754,6 @@
STAGE ALL
VIEW ASSUME UNCHANGED
Template: ${0}$
- Right-click the selected file(s), and make your choice to resolve conflicts.
WORKSPACE:
Configure Workspaces...
WORKTREE
diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml
index e2af0860..204cfc1a 100644
--- a/src/Resources/Locales/es_ES.axaml
+++ b/src/Resources/Locales/es_ES.axaml
@@ -103,8 +103,8 @@
Cherry-Pick ...
Comparar con HEAD
Comparar con Worktree
- Copiar Información
- Copiar SHA
+ Información
+ SHA
Acción personalizada
Rebase Interactivo ${0}$ hasta Aquí
Merge a ${0}$
@@ -136,6 +136,7 @@
SHA
Abrir en Navegador
Descripción
+ ASUNTO
Introducir asunto del commit
Configurar Repositorio
PLANTILLA DE COMMIT
@@ -157,6 +158,7 @@
Fetch remotos automáticamente
Minuto(s)
Remoto por Defecto
+ Modo preferido de Merge
SEGUIMIENTO DE INCIDENCIAS
Añadir Regla de Ejemplo para Azure DevOps
Añadir Regla de Ejemplo para Incidencias de Gitee
@@ -179,7 +181,12 @@
Nombre de usuario para este repositorio
Espacios de Trabajo
Color
+ Nombre
Restaurar pestañas al iniciar
+ CONTINUAR
+ ¡Commit vacío detectado! ¿Quieres continuar (--allow-empty)?
+ HACER STAGE A TODO & COMMIT
+ ¡Commit vacío detectado! ¿Quieres continuar (--allow-empty) o hacer stage a todo y después commit?
Asistente de Commit Convencional
Cambio Importante:
Incidencia Cerrada:
@@ -240,7 +247,7 @@
Copiar
Modo de Archivo Cambiado
Primera Diferencia
- Ignorar Cambio de Espacios en Blanco
+ Ignorar Cambio de Espacios en Blanco y EOL
Última Diferencia
CAMBIO DE OBJETO LFS
Siguiente Diferencia
@@ -445,7 +452,6 @@
Hace {0} años
Ayer
Preferencias
- Opciones Avanzadas
OPEN AI
Analizar Diff Prompt
Clave API
@@ -717,15 +723,20 @@
Ignorar archivos en la misma carpeta
Ignorar solo este archivo
Enmendar
- Puedes stagear este archivo ahora.
+ Puedes hacer stage a este archivo ahora.
COMMIT
COMMIT & PUSH
Plantilla/Historias
Activar evento de clic
Commit (Editar)
- Stagear todos los cambios y commit
+ Hacer stage a todos los cambios y commit
+ Tienes {0} archivo(s) en stage, pero solo {1} archivo(s) mostrado(s) ({2} archivo(s) están filtrados). ¿Quieres continuar?
CONFLICTOS DETECTADOS
+ ABRIR HERRAMIENTA DE MERGE EXTERNA
+ ABRIR TODOS LOS CONFLICTOS EN HERRAMIENTA DE MERGE EXTERNA
LOS CONFLICTOS DE ARCHIVOS ESTÁN RESUELTOS
+ USAR MÍOS
+ USAR SUYOS
INCLUIR ARCHIVOS NO RASTREADOS
NO HAY MENSAJES DE ENTRADA RECIENTES
NO HAY PLANTILLAS DE COMMIT
diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml
index 83d590f5..f45a83d9 100644
--- a/src/Resources/Locales/fr_FR.axaml
+++ b/src/Resources/Locales/fr_FR.axaml
@@ -86,7 +86,6 @@
Commit tous les changements
Ligne principale :
Habituellement, on ne peut pas cherry-pick un commit car on ne sait pas quel côté devrait être considéré comme principal. Cette option permet de rejouer les changements relatifs au parent spécifié.
- Cherry Pick
Supprimer les stashes
Vous essayez de supprimer tous les stashes. Êtes-vous sûr de vouloir continuer ?
Cloner repository distant
@@ -104,8 +103,8 @@
Cherry-Pick ...
Comparer avec HEAD
Comparer avec le worktree
- Copier les informations
- Copier le SHA
+ Informations
+ SHA
Action personnalisée
Rebase interactif de ${0}$ ici
Fusionner dans ${0}$
@@ -180,6 +179,7 @@
Nom d'utilisateur pour ce dépôt
Espaces de travail
Couleur
+ Nom
Restaurer les onglets au démarrage
Assistant Commits Conventionnels
Changement Radical :
@@ -241,7 +241,7 @@
Copier
Mode de fichier changé
Première différence
- Ignorer les changements d'espaces
+ Ignorer les changements d'espaces et EOL
Dernière différence
CHANGEMENT D'OBJET LFS
Différence suivante
@@ -456,8 +456,6 @@
Activer le streaming
APPARENCE
Police par défaut
- Taille de police par défaut
- Taille de police de l'éditeur
Largeur de tab dans l'éditeur
Taille de police
Défaut
diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml
index 59bf3028..b7d2568a 100644
--- a/src/Resources/Locales/it_IT.axaml
+++ b/src/Resources/Locales/it_IT.axaml
@@ -103,8 +103,8 @@
Cherry-Pick...
Confronta con HEAD
Confronta con Worktree
- Copia Info
- Copia SHA
+ Informazioni
+ SHA
Azione Personalizzata
Riallinea Interattivamente ${0}$ fino a Qui
Unisci a ${0}$
@@ -179,6 +179,7 @@
Nome utente per questo repository
Spazi di Lavoro
Colore
+ Nome
Ripristina schede all'avvio
Guida Commit Convenzionali
Modifica Sostanziale:
@@ -239,7 +240,7 @@
Copia
Modalità File Modificata
Prima differenza
- Ignora Modifiche agli Spazi
+ Ignora Modifiche agli Spazi e EOL
Ultima differenza
MODIFICA OGGETTO LFS
Differenza Successiva
@@ -300,7 +301,6 @@
Cronologia File
MODIFICA
CONTENUTO
- FILTRO
Git-Flow
Branch di Sviluppo:
Feature:
@@ -566,7 +566,6 @@
Abilita opzione '--reflog'
Apri nell'Esplora File
Cerca Branch/Tag/Sottomodulo
- FILTRATO DA:
Visibilità nel grafico
Non impostato
Nascondi nel grafico dei commit
diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml
index fe643b5e..c50504e1 100644
--- a/src/Resources/Locales/ja_JP.axaml
+++ b/src/Resources/Locales/ja_JP.axaml
@@ -103,8 +103,8 @@
チェリーピック...
HEADと比較
ワークツリーと比較
- 情報をコピー
- SHAをコピー
+ 情報
+ SHA
カスタムアクション
${0}$ ブランチをここにインタラクティブリベース
${0}$ にマージ
@@ -179,6 +179,7 @@
このリポジトリにおけるユーザー名
ワークスペース
色
+ 名前
起動時にタブを復元
Conventional Commitヘルパー
破壊的変更:
@@ -240,7 +241,7 @@
コピー
ファイルモードが変更されました
先頭の差分
- 空白の変更を無視
+ 空白の変更とEOLを無視
最後の差分
LFSオブジェクトの変更
次の差分
@@ -604,7 +605,6 @@
新しいタグを作成
作成者日時
名前 (昇順)
- 名前 (降順)
ソート
ターミナルで開く
履歴に相対時間を使用
diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml
index 3caac3cc..a4e9d883 100644
--- a/src/Resources/Locales/pt_BR.axaml
+++ b/src/Resources/Locales/pt_BR.axaml
@@ -93,8 +93,8 @@
Cherry-Pick ...
Comparar com HEAD
Comparar com Worktree
- Copiar Informações
- Copiar SHA
+ Informações
+ SHA
Ação customizada
Rebase Interativo ${0}$ até Aqui
Rebase ${0}$ até Aqui
@@ -161,6 +161,7 @@
Nome de usuário para este repositório
Workspaces
Cor
+ Nome
Restaurar abas ao inicializar
Assistente de Conventional Commit
Breaking Change:
@@ -216,7 +217,7 @@
ANTIGO
Copiar
Modo de Arquivo Alterado
- Ignorar mudanças de espaço em branco
+ Ignorar mudanças de espaço em branco e EOL
MUDANÇA DE OBJETO LFS
Próxima Diferença
SEM MUDANÇAS OU APENAS MUDANÇAS DE EOL
diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml
index ee04f4d1..b8c86415 100644
--- a/src/Resources/Locales/ru_RU.axaml
+++ b/src/Resources/Locales/ru_RU.axaml
@@ -103,8 +103,8 @@
Применить несколько ревизий ...
Сравнить c ГОЛОВОЙ (HEAD)
Сравнить с рабочим каталогом
- Копировать информацию
- Копировать SHA
+ Информацию
+ SHA
Пользовательское действие
Интерактивное перемещение (rebase -i) ${0}$ сюда
Влить в ${0}$
@@ -210,7 +210,7 @@
Создать метку...
Новая метка у:
GPG подпись
- Сообщение с
меткой:
+ Сообщение с
меткой:
Необязательно.
Имя метки:
Рекомендуемый формат: v1.0.0-alpha
@@ -246,7 +246,7 @@
Копировать
Режим файла изменён
Первое различие
- Игнорировать изменение пробелов
+ Игнорировать изменение пробелов и EOL
Последнее различие
ИЗМЕНЕНИЕ ОБЪЕКТА LFS
Следующее различие
@@ -577,7 +577,6 @@
Не установлен (по умолчанию)
Скрыть в графе ревизии
Фильтр в графе ревизии
- ОТФИЛЬТРОВАНО:
Включить опцию (--first-parent)
РАСПОЛОЖЕНИЕ
Горизонтально
diff --git a/src/Resources/Locales/ta_IN.axaml b/src/Resources/Locales/ta_IN.axaml
index 946a8d9c..b4e4d939 100644
--- a/src/Resources/Locales/ta_IN.axaml
+++ b/src/Resources/Locales/ta_IN.axaml
@@ -103,8 +103,8 @@
கனி-பறி ...
தலையுடன் ஒப்பிடுக
பணிமரத்துடன் ஒப்பிடுக
- தகவலை நகலெடு
- பாகொவ-வை நகலெடு
+ தகவலை
+ பாகொவ-வை
தனிப்பயன் செயல்
இங்கே ${0}$ ஐ ஊடாடும் வகையில் மறுதளம்
${0}$ இதற்கு ஒன்றிணை
@@ -179,6 +179,7 @@
இந்த களஞ்சியத்திற்கான பயனர் பெயர்
பணியிடங்கள்
நிறம்
+ பெயர்
தாவல்களை மீட்டமை
வழக்கமான உறுதிமொழி உதவியாளர்
உடைக்கும் மாற்றம்:
@@ -240,7 +241,7 @@
நகல்
கோப்பு முறை மாற்றப்பட்டது
முதல் வேறுபாடு
- வெள்ளைவெளி மாற்றத்தை புறக்கணி
+ வெள்ளைவெளி மாற்றத்தை மற்றும் EOL புறக்கணி
கடைசி வேறுபாடு
பெகோஅ பொருள் மாற்றம்
அடுத்த வேறுபாடு
@@ -465,8 +466,8 @@
கருப்பொருள் மேலெழுதப்படுகிறது
தலைப்புப்பட்டியில் நிலையான தாவல் அகலத்தைப் பயன்படுத்து
சொந்த சாளர சட்டத்தைப் பயன்படுத்து
- நிறுவல் பாதை
வேறு/ஒன்றிணை கருவி
+ நிறுவல் பாதை
வேறு/ஒன்றிணை கருவிக்கான பாதை உள்ளிடு
கருவி
பொது
@@ -723,7 +724,6 @@
உறுதிமொழி (திருத்து)
அனைத்து மாற்றங்களையும் நிலைப்படுத்தி உறுதிமொழி
நீங்கள் {0} கோப்புகளை நிலைப்படுத்தியுள்ளீர்கள், ஆனால் {1} கோப்புகள் மட்டுமே காட்டப்பட்டுள்ளன ({2} கோப்புகள் வடிகட்டப்பட்டுள்ளன). தொடர விரும்புகிறீர்களா?
- காலி உறுதிமொழி கண்டறியப்பட்டது! தொடர விரும்புகிறீர்களா(--allow-empty)?
மோதல்கள் கண்டறியப்பட்டது
கோப்பு மோதல்கள் தீர்க்கப்பட்டது
கண்காணிக்கப்படாத கோப்புகளைச் சேர்
diff --git a/src/Resources/Locales/uk_UA.axaml b/src/Resources/Locales/uk_UA.axaml
new file mode 100644
index 00000000..a3b63bde
--- /dev/null
+++ b/src/Resources/Locales/uk_UA.axaml
@@ -0,0 +1,758 @@
+
+
+
+
+
+ Про програму
+ Про SourceGit
+ Безкоштовний Git GUI клієнт з відкритим кодом
+ Додати робоче дерево
+ Розташування:
+ Шлях для цього робочого дерева. Відносний шлях підтримується.
+ Назва гілки:
+ Необов'язково. За замовчуванням — назва кінцевої папки.
+ Відстежувати гілку:
+ Відстежувати віддалену гілку
+ Що перемкнути:
+ Створити нову гілку
+ Наявна гілка
+ AI Асистент
+ ПЕРЕГЕНЕРУВАТИ
+ Використати AI для генерації повідомлення коміту
+ ЗАСТОСУВАТИ ЯК ПОВІДОМЛЕННЯ КОМІТУ
+ Застосувати
+ Файл патчу:
+ Виберіть файл .patch для застосування
+ Ігнорувати зміни пробілів
+ Застосувати Патч
+ Пробіли:
+ Застосувати схованку
+ Видалити після застосування
+ Відновити зміни індексу
+ Схованка:
+ Архівувати...
+ Зберегти архів у:
+ Виберіть шлях до файлу архіву
+ Ревізія:
+ Архівувати
+ SourceGit Askpass
+ ФАЙЛИ, ЩО ВВАЖАЮТЬСЯ НЕЗМІНЕНИМИ
+ НЕМАЄ ФАЙЛІВ, ЩО ВВАЖАЮТЬСЯ НЕЗМІНЕНИМИ
+ ВИДАЛИТИ
+ БІНАРНИЙ ФАЙЛ НЕ ПІДТРИМУЄТЬСЯ!!!
+ Автор рядка
+ ПОШУК АВТОРА РЯДКА ДЛЯ ЦЬОГО ФАЙЛУ НЕ ПІДТРИМУЄТЬСЯ!!!
+ Перейти на ${0}$...
+ Порівняти з HEAD
+ Порівняти з робочим деревом
+ Копіювати назву гілки
+ Спеціальна дія
+ Видалити ${0}$...
+ Видалити вибрані {0} гілок
+ Скасувати всі зміни
+ Перемотати до ${0}$
+ Отримати ${0}$ в ${1}$...
+ Git Flow - Завершити ${0}$
+ Злиття ${0}$ в ${1}$...
+ Злити вибрані {0} гілок в поточну
+ Витягти ${0}$
+ Витягти ${0}$ в ${1}$...
+ Надіслати ${0}$
+ Перебазувати ${0}$ на ${1}$...
+ Перейменувати ${0}$...
+ Встановити відстежувану гілку...
+ Порівняти гілки
+ Недійсний upstream!
+ Байтів
+ СКАСУВАТИ
+ Скинути до батьківської ревізії
+ Скинути до цієї ревізії
+ Згенерувати повідомлення коміту
+ ЗМІНИТИ РЕЖИМ ВІДОБРАЖЕННЯ
+ Показати як список файлів та тек
+ Показати як список шляхів
+ Показати як дерево файлової системи
+ Перейти на гілку
+ Перейти на коміт
+ Коміт:
+ Попередження: Перехід на коміт призведе до стану "від'єднаний HEAD"
+ Локальні зміни:
+ Скасувати
+ Сховати та Застосувати
+ Гілка:
+ Cherry-pick
+ Додати джерело до повідомлення коміту
+ Коміт(и):
+ Закомітити всі зміни
+ Батьківський коміт:
+ Зазвичай неможливо cherry-pick злиття, бо невідомо, яку сторону злиття вважати батьківською (mainline). Ця опція дозволяє відтворити зміни відносно вказаного батьківського коміту.
+ Очистити схованки
+ Ви намагаєтеся очистити всі схованки. Ви впевнені?
+ Клонувати віддалене сховище
+ Додаткові параметри:
+ Додаткові аргументи для клонування сховища. Необов'язково.
+ Локальна назва:
+ Назва сховища. Необов'язково.
+ Батьківська тека:
+ Ініціалізувати та оновити підмодулі
+ URL сховища:
+ ЗАКРИТИ
+ Редактор
+ Перейти на коміт
+ Cherry-pick коміт
+ Cherry-pick ...
+ Порівняти з HEAD
+ Порівняти з робочим деревом
+ Iнформацію
+ SHA
+ Спеціальна дія
+ Інтерактивно перебазувати ${0}$ сюди
+ Злиття в ${0}$
+ Злити ...
+ Перебазувати ${0}$ сюди
+ Скинути ${0}$ сюди
+ Скасувати коміт
+ Змінити повідомлення
+ Зберегти як патч...
+ Склеїти з батьківським комітом
+ Склеїти дочірні коміти сюди
+ ЗМІНИ
+ Пошук змін...
+ ФАЙЛИ
+ LFS Файл
+ Пошук файлів...
+ Підмодуль
+ ІНФОРМАЦІЯ
+ АВТОР
+ ЗМІНЕНО
+ ДОЧІРНІ
+ КОМІТЕР
+ Перевірити посилання, що містять цей коміт
+ КОМІТ МІСТИТЬСЯ В
+ Показано лише перші 100 змін. Дивіться всі зміни на вкладці ЗМІНИ.
+ ПОВІДОМЛЕННЯ
+ БАТЬКІВСЬКІ
+ ПОСИЛАННЯ (Refs)
+ SHA
+ Відкрити в браузері
+ Опис
+ Введіть тему коміту
+ Налаштування сховища
+ ШАБЛОН КОМІТУ
+ Зміст шаблону:
+ Назва шаблону:
+ СПЕЦІАЛЬНА ДІЯ
+ Аргументи:
+ ${REPO} - Шлях до сховища; ${BRANCH} - Вибрана гілка; ${SHA} - SHA вибраного коміту
+ Виконуваний файл:
+ Назва:
+ Область застосування:
+ Гілка
+ Коміт
+ Репозиторій
+ Чекати завершення дії
+ Адреса Email
+ Адреса електронної пошти
+ GIT
+ Автоматично отримувати зміни з віддалених сховищ
+ хвилин(и)
+ Віддалене сховище за замовчуванням
+ Бажаний режим злиття
+ ТРЕКЕР ЗАВДАНЬ
+ Додати приклад правила для Azure DevOps
+ Додати приклад правила для Gitee Issue
+ Додати приклад правила для Gitee Pull Request
+ Додати приклад правила для Github
+ Додати приклад правила для GitLab Issue
+ Додати приклад правила для GitLab Merge Request
+ Додати приклад правила для Jira
+ Нове правило
+ Регулярний вираз для завдання:
+ Назва правила:
+ URL результату:
+ Використовуйте $1, $2 для доступу до значень груп регулярного виразу.
+ AI
+ Бажаний сервіс:
+ Якщо 'Бажаний сервіс' встановлено, SourceGit буде використовувати лише його у цьому сховищі. Інакше, якщо доступно більше одного сервісу, буде показано контекстне меню для вибору.
+ HTTP Проксі
+ HTTP проксі, що використовується цим сховищем
+ Ім'я користувача
+ Ім'я користувача для цього сховища
+ Робочі простори
+ Колір
+ Відновлювати вкладки при запуску
+ ПРОДОВЖИТИ
+ Виявлено порожній коміт! Продовжити (--allow-empty)?
+ ІНДЕКСУВАТИ ВСЕ ТА ЗАКОМІТИТИ
+ Виявлено порожній коміт! Продовжити (--allow-empty) чи індексувати все та закомітити?
+ Допомога Conventional Commit
+ Зворотньо несумісні зміни:
+ Закрите завдання:
+ Детальні зміни:
+ Область застосування:
+ Короткий опис:
+ Тип зміни:
+ Копіювати
+ Копіювати весь текст
+ Копіювати повний шлях
+ Копіювати шлях
+ Створити гілку...
+ На основі:
+ Перейти на створену гілку
+ Локальні зміни:
+ Скасувати
+ Сховати та Застосувати
+ Назва нової гілки:
+ Введіть назву гілки.
+ Пробіли будуть замінені на тире.
+ Створити локальну гілку
+ Створити тег...
+ Новий тег для:
+ Підпис GPG
+ Повідомлення тегу:
+ Необов'язково.
+ Назва тегу:
+ Рекомендований формат: v1.0.0-alpha
+ Надіслати на всі віддалені сховища після створення
+ Створити Новий Тег
+ Тип:
+ анотований
+ легкий
+ Утримуйте Ctrl для запуску без діалогу
+ Вирізати
+ Видалити гілку
+ Гілка:
+ Ви збираєтеся видалити віддалену гілку!!!
+ Також видалити віддалену гілку ${0}$
+ Видалити кілька гілок
+ Ви намагаєтеся видалити кілька гілок одночасно. Перевірте ще раз перед виконанням!
+ Видалити віддалене сховище
+ Віддалене сховище:
+ Шлях:
+ Ціль:
+ Усі дочірні елементи будуть видалені зі списку.
+ Це видалить сховище лише зі списку, а не з диска!
+ Підтвердити видалення групи
+ Підтвердити видалення сховища
+ Видалити підмодуль
+ Шлях до підмодуля:
+ Видалити тег
+ Тег:
+ Видалити з віддалених сховищ
+ РІЗНИЦЯ ДЛЯ БІНАРНИХ ФАЙЛІВ
+ НОВИЙ
+ СТАРИЙ
+ Копіювати
+ Змінено режим файлу
+ Перша відмінність
+ Ігнорувати зміни пробілів
+ Остання відмінність
+ ЗМІНА ОБ'ЄКТА LFS
+ Наступна відмінність
+ НЕМАЄ ЗМІН АБО ЛИШЕ ЗМІНИ КІНЦЯ РЯДКА
+ Попередня відмінність
+ Зберегти як патч
+ Показати приховані символи
+ Порівняння пліч-о-пліч
+ ПІДМОДУЛЬ
+ НОВИЙ
+ Поміняти місцями
+ Підсвітка синтаксису
+ Перенос слів
+ Увімкнути навігацію блоками
+ Відкрити в інструменті злиття
+ Показати всі рядки
+ Зменшити кількість видимих рядків
+ Збільшити кількість видимих рядків
+ ОБЕРІТЬ ФАЙЛ ДЛЯ ПЕРЕГЛЯДУ ЗМІН
+ Відкрити в інструменті злиття
+ Скасувати зміни
+ Усі локальні зміни в робочій копії.
+ Зміни:
+ Включити файли, які ігноруються
+ {0} змін будуть відхилені
+ Ви не можете скасувати цю дію!!!
+ Закладка:
+ Нова назва:
+ Ціль:
+ Редагувати вибрану групу
+ Редагувати вибраний репозиторій
+ Виконати спеціальну дію
+ Ім'я дії:
+ Перемотати (без перемкнуття)
+ Витягти
+ Витягти всі віддалені сховища
+ Примусово перезаписати локальні refs
+ Витягти без тегів
+ Віддалений:
+ Витягти зміни з віддалених репозиторіїв
+ Вважати незмінними
+ Скасувати...
+ Скасувати {0} файлів...
+ Скасувати зміни в вибраних рядках
+ Відкрити зовнішній інструмент злиття
+ Розв'язати за допомогою ${0}$
+ Зберегти як патч...
+ Стагнути
+ Стагнути {0} файлів
+ Стагнути зміни в вибраних рядках
+ Схованка...
+ Схованка {0} файлів...
+ Скинути стаг
+ Скинути {0} файлів
+ Скинути зміни в вибраних рядках
+ Використовувати Mine (checkout --ours)
+ Використовувати Theirs (checkout --theirs)
+ Історія файлу
+ ЗМІНА
+ ЗМІСТ
+ Git-Flow
+ Розробка гілки:
+ Функція:
+ Префікс функції:
+ FLOW - Завершити функцію
+ FLOW - Завершити гарячу поправку
+ FLOW - Завершити реліз
+ Ціль:
+ Гаряча поправка:
+ Префікс гарячої поправки:
+ Ініціалізувати Git-Flow
+ Залишити гілку
+ Гілка виробництва:
+ Реліз:
+ Префікс релізу:
+ Почати функцію...
+ FLOW - Почати функцію
+ Почати гарячу поправку...
+ FLOW - Почати гарячу поправку
+ Введіть назву
+ Почати реліз...
+ FLOW - Почати реліз
+ Тег версії Префікс:
+ Git LFS
+ Додати шаблон для відстеження...
+ Шаблон є ім'ям файлу
+ Спеціальний шаблон:
+ Додати шаблон для відстеження до Git LFS
+ Витягти
+ Запустіть `git lfs fetch`, щоб завантажити об'єкти Git LFS. Це не оновлює робочу копію.
+ Витягти об'єкти LFS
+ Встановити Git LFS hooks
+ Показати блокування
+ Немає заблокованих файлів
+ Заблокувати
+ Показати лише мої блокування
+ LFS блокування
+ Розблокувати
+ Примусово розблокувати
+ Принт
+ Запустіть `git lfs prune`, щоб видалити старі файли з локального сховища
+ Витягти
+ Запустіть `git lfs pull`, щоб завантажити всі файли Git LFS для поточної ref & checkout
+ Витягти об'єкти LFS
+ Надіслати
+ Надіслати чернетки великих файлів до кінця Git LFS
+ Надіслати об'єкти LFS
+ Віддалений:
+ Відстежувати файли, названі '{0}'
+ Відстежувати всі *{0} файли
+ ІСТОРІЯ
+ АВТОР
+ ЧАС АВТОРА
+ ГРАФ ТА ТЕМА
+ SHA
+ ЧАС КОМІТУ
+ ВИБРАНО {0} КОМІТІВ
+ Утримуйте 'Ctrl' або 'Shift' для вибору кількох комітів.
+ Утримуйте ⌘ або ⇧ для вибору кількох комітів.
+ ПОРАДИ:
+ Гарячі клавіші
+ ГЛОБАЛЬНІ
+ Скасувати поточне спливаюче вікно
+ Клонувати нове сховище
+ Закрити поточну вкладку
+ Перейти до наступної вкладки
+ Перейти до попередньої вкладки
+ Створити нову вкладку
+ Відкрити діалог Налаштування
+ СХОВИЩЕ
+ Закомітити проіндексовані зміни
+ Закомітити та надіслати проіндексовані зміни
+ Індексувати всі зміни та закомітити
+ Створити нову гілку на основі вибраного коміту
+ Скасувати вибрані зміни
+ Fetch, запускається без діалогу
+ Режим панелі керування (за замовчуванням)
+ Режим пошуку комітів
+ Pull, запускається без діалогу
+ Push, запускається без діалогу
+ Примусово перезавантажити це сховище
+ Індексувати/Видалити з індексу вибрані зміни
+ Перейти до 'Зміни'
+ Перейти до 'Історія'
+ Перейти до 'Схованки'
+ ТЕКСТОВИЙ РЕДАКТОР
+ Закрити панель пошуку
+ Знайти наступний збіг
+ Знайти попередній збіг
+ Відкрити панель пошуку
+ Скасувати
+ Індексувати
+ Видалити з індексу
+ Ініціалізувати сховище
+ Шлях:
+ Cherry-pick в процесі.
+ Обробка коміту
+ Злиття в процесі.
+ Виконується злиття
+ Перебазування в процесі.
+ Зупинено на
+ Скасування в процесі.
+ Скасування коміту
+ Інтерактивне перебазування
+ На:
+ Цільова гілка:
+ Копіювати посилання
+ Відкрити в браузері
+ ПОМИЛКА
+ ПОВІДОМЛЕННЯ
+ Злиття гілки
+ В:
+ Опція злиття:
+ Джерело:
+ Злиття (Кілька)
+ Закомітити всі зміни
+ Стратегія:
+ Цілі:
+ Перемістити вузол сховища
+ Виберіть батьківський вузол для:
+ Назва:
+ Git не налаштовано. Будь ласка, перейдіть до [Налаштування] та налаштуйте його.
+ Відкрити теку зберігання даних
+ Відкрити за допомогою...
+ Необов'язково.
+ Створити нову вкладку
+ Закладка
+ Закрити вкладку
+ Закрити інші вкладки
+ Закрити вкладки праворуч
+ Копіювати шлях до сховища
+ Сховища
+ Вставити
+ {0} днів тому
+ годину тому
+ {0} годин тому
+ Щойно
+ Минулого місяця
+ Минулого року
+ {0} хвилин тому
+ {0} місяців тому
+ {0} років тому
+ Вчора
+ Налаштування
+ AI
+ Промпт для аналізу різниці
+ Ключ API
+ Промпт для генерації теми
+ Модель
+ Назва
+ Сервер
+ Увімкнути потокове відтворення
+ ВИГЛЯД
+ Шрифт за замовчуванням
+ Ширина табуляції в редакторі
+ Розмір шрифту
+ За замовчуванням
+ Редактор
+ Моноширинний шрифт
+ Використовувати моноширинний шрифт лише в текстовому редакторі
+ Тема
+ Перевизначення теми
+ Використовувати фіксовану ширину вкладки в заголовку
+ Використовувати системну рамку вікна
+ ІНСТРУМЕНТ DIFF/MERGE
+ Шлях встановлення
+ Введіть шлях до інструменту diff/merge
+ Інструмент
+ ЗАГАЛЬНІ
+ Перевіряти оновлення при запуску
+ Формат дати
+ Мова
+ Кількість комітів в історії
+ Показувати час автора замість часу коміту в графі
+ Показувати дочірні коміти в деталях
+ Показувати теги в графі комітів
+ Довжина лінії-орієнтира для теми
+ GIT
+ Увімкнути авто-CRLF
+ Тека клонування за замовчуванням
+ Email користувача
+ Глобальний email користувача git
+ Увімкнути --prune при fetch
+ Git (>= 2.23.0) є обов'язковим для цієї програми
+ Шлях встановлення
+ Увімкнути перевірку HTTP SSL
+ Ім'я користувача
+ Глобальне ім'я користувача git
+ Версія Git
+ ПІДПИС GPG
+ Підпис GPG для комітів
+ Формат GPG
+ Шлях встановлення програми
+ Введіть шлях до встановленої програми GPG
+ Підпис GPG для тегів
+ Ключ підпису користувача
+ Ключ підпису GPG користувача
+ ІНТЕГРАЦІЯ
+ КОНСОЛЬ/ТЕРМІНАЛ
+ Шлях
+ Консоль/Термінал
+ Prune для віддаленого сховища
+ Ціль:
+ Prune для робочих дерев
+ Видалити застарілу інформацію про робочі дерева в `$GIT_COMMON_DIR/worktrees`
+ Pull (Витягти)
+ Віддалена гілка:
+ Отримати всі гілки
+ В:
+ Локальні зміни:
+ Скасувати
+ Сховати та Застосувати
+ Отримати без тегів
+ Віддалене сховище:
+ Pull (Fetch & Merge)
+ Використовувати rebase замість merge
+ Push (Надіслати)
+ Переконатися, що підмодулі надіслано
+ Примусовий push
+ Локальна гілка:
+ Віддалене сховище:
+ Надіслати зміни на віддалене сховище
+ Віддалена гілка:
+ Встановити як відстежувану гілку
+ Надіслати всі теги
+ Надіслати тег на віддалене сховище
+ Надіслати на всі віддалені сховища
+ Віддалене сховище:
+ Тег:
+ Вийти
+ Перебазувати поточну гілку
+ Сховати та застосувати локальні зміни
+ На:
+ Перебазувати:
+ Оновити
+ Додати віддалене сховище
+ Редагувати віддалене сховище
+ Назва:
+ Назва віддаленого сховища
+ URL сховища:
+ URL віддаленого git сховища
+ Копіювати URL
+ Видалити...
+ Редагувати...
+ Fetch (Отримати)
+ Відкрити у браузері
+ Prune (Очистити)
+ Підтвердити видалення робочого дерева
+ Увімкнути опцію `--force`
+ Ціль:
+ Перейменувати гілку
+ Нова назва:
+ Унікальна назва для цієї гілки
+ Гілка:
+ ПЕРЕРВАТИ
+ Автоматичне отримання змін з віддалених сховищ...
+ Очистка (GC & Prune)
+ Виконати команду `git gc` для цього сховища.
+ Очистити все
+ Налаштувати це сховище
+ ПРОДОВЖИТИ
+ Спеціальні дії
+ Немає спеціальних дій
+ Увімкнути опцію '--reflog'
+ Відкрити у файловому менеджері
+ Пошук гілок/тегів/підмодулів
+ Видимість у графі
+ Не встановлено
+ Приховати в графі комітів
+ Фільтрувати в графі комітів
+ Увімкнути опцію '--first-parent'
+ РОЗТАШУВАННЯ
+ Горизонтальне
+ Вертикальне
+ ПОРЯДОК КОМІТІВ
+ За датою коміту
+ Топологічний
+ ЛОКАЛЬНІ ГІЛКИ
+ Перейти до HEAD
+ Створити гілку
+ ОЧИСТИТИ СПОВІЩЕННЯ
+ Виділяти лише поточну гілку в графі
+ Відкрити в {0}
+ Відкрити в зовнішніх інструментах
+ Оновити
+ ВІДДАЛЕНІ СХОВИЩА
+ ДОДАТИ ВІДДАЛЕНЕ СХОВИЩЕ
+ Пошук коміту
+ Автор
+ Комітер
+ Файл
+ Повідомлення
+ SHA
+ Поточна гілка
+ Показати теги як дерево
+ ПРОПУСТИТИ
+ Статистика
+ ПІДМОДУЛІ
+ ДОДАТИ ПІДМОДУЛЬ
+ ОНОВИТИ ПІДМОДУЛЬ
+ ТЕГИ
+ НОВИЙ ТЕГ
+ За датою створення
+ За назвою (за зростанням)
+ За назвою (за спаданням)
+ Сортувати
+ Відкрити в терміналі
+ Використовувати відносний час в історії
+ РОБОЧІ ДЕРЕВА
+ ДОДАТИ РОБОЧЕ ДЕРЕВО
+ PRUNE (ОЧИСТИТИ)
+ URL Git сховища
+ Скинути поточну гілку до ревізії
+ Режим скидання:
+ Перемістити до:
+ Поточна гілка:
+ Показати у файловому менеджері
+ Revert (Скасувати коміт)
+ Коміт:
+ Закомітити зміни скасування
+ Змінити повідомлення коміту
+ Використовуйте 'Shift+Enter' для введення нового рядка. 'Enter' - гаряча клавіша кнопки OK
+ Виконується. Будь ласка, зачекайте...
+ ЗБЕРЕГТИ
+ Зберегти як...
+ Патч успішно збережено!
+ Сканувати сховища
+ Коренева тека:
+ Перевірити оновлення...
+ Доступна нова версія програми:
+ Не вдалося перевірити оновлення!
+ Завантажити
+ Пропустити цю версію
+ Оновлення програми
+ У вас встановлена остання версія.
+ Встановити відстежувану гілку
+ Гілка:
+ Скасувати upstream
+ Upstream:
+ Копіювати SHA
+ Перейти до
+ Squash (Склеїти коміти)
+ В:
+ Приватний ключ SSH:
+ Шлях до сховища приватного ключа SSH
+ ПОЧАТИ
+ Stash (Сховати)
+ Автоматично відновити після схову
+ Ваші робочі файли залишаться без змін, але буде збережено схованку.
+ Включити невідстежувані файли
+ Зберегти проіндексовані файли
+ Повідомлення:
+ Необов'язково. Назва цієї схованки
+ Лише проіндексовані зміни
+ Будуть сховані як проіндексовані, так і не проіндексовані зміни вибраних файлів!!!
+ Сховати локальні зміни
+ Застосувати
+ Видалити
+ Зберегти як патч...
+ Видалити схованку
+ Видалити:
+ СХОВАНКИ
+ ЗМІНИ
+ СХОВАНКИ
+ Статистика
+ КОМІТИ
+ КОМІТЕР
+ ОГЛЯД
+ МІСЯЦЬ
+ ТИЖДЕНЬ
+ АВТОРІВ:
+ КОМІТІВ:
+ ПІДМОДУЛІ
+ Додати підмодуль
+ Копіювати відносний шлях
+ Отримати вкладені підмодулі
+ Відкрити сховище підмодуля
+ Відносний шлях:
+ Відносна тека для зберігання цього модуля.
+ Видалити підмодуль
+ OK
+ Копіювати назву тегу
+ Копіювати повідомлення тегу
+ Видалити ${0}$...
+ Злиття ${0}$ в ${1}$...
+ Надіслати ${0}$...
+ Оновити підмодулі
+ Усі підмодулі
+ Ініціалізувати за потреби
+ Рекурсивно
+ Підмодуль:
+ Використовувати опцію --remote
+ URL:
+ Попередження
+ Вітальна сторінка
+ Створити групу
+ Створити підгрупу
+ Клонувати сховище
+ Видалити
+ ПІДТРИМУЄТЬСЯ ПЕРЕТЯГУВАННЯ ТЕК. МОЖЛИВЕ ГРУПУВАННЯ.
+ Редагувати
+ Перемістити до іншої групи
+ Відкрити всі сховища
+ Відкрити сховище
+ Відкрити термінал
+ Пересканувати сховища у теці клонування за замовчуванням
+ Пошук сховищ...
+ Сортувати
+ ЛОКАЛЬНІ ЗМІНИ
+ Git Ignore
+ Ігнорувати всі файли *{0}
+ Ігнорувати файли *{0} у цій же теці
+ Ігнорувати файли у цій же теці
+ Ігнорувати лише цей файл
+ Amend (Доповнити)
+ Тепер ви можете проіндексувати цей файл.
+ КОМІТ
+ КОМІТ ТА PUSH
+ Шаблон/Історії
+ Викликати подію кліку
+ Коміт (Редагувати)
+ Індексувати всі зміни та закомітити
+ Ви проіндексували {0} файл(ів), але відображено лише {1} ({2} файлів відфільтровано). Продовжити?
+ ВИЯВЛЕНО КОНФЛІКТИ
+ ВІДКРИТИ ЗОВНІШНІЙ ІНСТРУМЕНТ ЗЛИТТЯ
+ ВІДКРИТИ ВСІ КОНФЛІКТИ В ЗОВНІШНЬОМУ ІНСТРУМЕНТІ ЗЛИТТЯ
+ КОНФЛІКТИ ФАЙЛІВ ВИРІШЕНО
+ ВИКОРИСТАТИ МОЮ ВЕРСІЮ
+ ВИКОРИСТАТИ ЇХНЮ ВЕРСІЮ
+ ВКЛЮЧИТИ НЕВІДСТЕЖУВАНІ ФАЙЛИ
+ НЕМАЄ ОСТАННІХ ПОВІДОМЛЕНЬ
+ НЕМАЄ ШАБЛОНІВ КОМІТІВ
+ Клацніть правою кнопкою миші на вибраних файлах та оберіть спосіб вирішення конфліктів.
+ Підпис
+ ПРОІНДЕКСОВАНІ
+ ВИДАЛИТИ З ІНДЕКСУ
+ ВИДАЛИТИ ВСЕ З ІНДЕКСУ
+ НЕПРОІНДЕКСОВАНІ
+ ІНДЕКСУВАТИ
+ ІНДЕКСУВАТИ ВСЕ
+ ПЕРЕГЛЯНУТИ ФАЙЛИ, ЩО ВВАЖАЮТЬСЯ НЕЗМІНЕНИМИ
+ Шаблон: ${0}$
+ РОБОЧИЙ ПРОСТІР:
+ Налаштувати робочі простори...
+ РОБОЧЕ ДЕРЕВО
+ Копіювати шлях
+ Заблокувати
+ Видалити
+ Розблокувати
+
diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml
index 35a97b6e..3d41bccd 100644
--- a/src/Resources/Locales/zh_CN.axaml
+++ b/src/Resources/Locales/zh_CN.axaml
@@ -103,8 +103,11 @@
挑选(cherry-pick)...
与当前HEAD比较
与本地工作树比较
- 复制简要信息
- 复制提交指纹
+ 作者
+ 提交者
+ 简要信息
+ 提交指纹
+ 主题
自定义操作
交互式变基(rebase -i) ${0}$ 到此处
合并(merge)此提交至 ${0}$
@@ -136,6 +139,7 @@
提交指纹
浏览器中查看
详细描述
+ 主题
填写提交信息主题
仓库配置
提交信息模板
@@ -180,6 +184,7 @@
应用于本仓库的用户名
工作区
颜色
+ 名称
启动时恢复打开的仓库
确认继续
提交未包含变更文件!是否继续(--allow-empty)?
@@ -245,7 +250,7 @@
复制
文件权限已变化
首个差异
- 忽略空白符号变化
+ 忽略空白符号变化和EOL
最后一个差异
LFS对象变更
下一个差异
@@ -460,7 +465,6 @@
启用流式输出
外观配置
缺省字体
- 代码字体大小
编辑器制表符宽度
字体大小
默认
@@ -615,6 +619,7 @@
排序
在终端中打开
在提交列表中使用相对时间
+ 查看命令日志
工作树列表
新增工作树
清理
@@ -700,6 +705,10 @@
子模块 :
启用 '--remote'
仓库地址 :
+ 日志列表
+ 清空日志
+ 复制
+ 删除
警告
起始页
新建分组
diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml
index d71281f7..3a10f6ca 100644
--- a/src/Resources/Locales/zh_TW.axaml
+++ b/src/Resources/Locales/zh_TW.axaml
@@ -103,8 +103,11 @@
揀選 (cherry-pick)...
與目前 HEAD 比較
與本機工作區比較
- 複製摘要資訊
- 複製提交編號
+ 作者
+ 提交者
+ 摘要資訊
+ 提交編號
+ 標題
自訂動作
互動式重定基底 (rebase -i) ${0}$ 到此處
合併 (merge) 此提交到 ${0}$
@@ -136,6 +139,7 @@
提交編號
在瀏覽器中檢視
詳細描述
+ 標題
填寫提交訊息標題
存放庫設定
提交訊息範本
@@ -180,6 +184,7 @@
用於本存放庫的使用者名稱
工作區
顏色
+ 名稱
啟動時還原上次開啟的存放庫
确认继续
未包含任何檔案變更! 您是否仍要提交 (--allow-empty)?
@@ -245,7 +250,7 @@
複製
檔案權限已變更
第一個差異
- 忽略空白符號變化
+ 忽略空白符號變化和EOL
最後一個差異
LFS 物件變更
下一個差異
@@ -614,6 +619,7 @@
排序
在終端機中開啟
在提交列表中使用相對時間
+ 檢視 GIT 指令的日誌
工作區列表
新增工作區
清理
@@ -699,6 +705,10 @@
子模組:
啟用 [--remote] 選項
存放庫網址:
+ 日誌清單
+ 清除所有日誌
+ 複製
+ 刪除
警告
起始頁
新增群組
diff --git a/src/Resources/Styles.axaml b/src/Resources/Styles.axaml
index 38321356..093ae4e0 100644
--- a/src/Resources/Styles.axaml
+++ b/src/Resources/Styles.axaml
@@ -499,6 +499,12 @@
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Views/ViewLogs.axaml.cs b/src/Views/ViewLogs.axaml.cs
new file mode 100644
index 00000000..f0a27884
--- /dev/null
+++ b/src/Views/ViewLogs.axaml.cs
@@ -0,0 +1,43 @@
+using Avalonia.Controls;
+
+namespace SourceGit.Views
+{
+ public partial class ViewLogs : ChromelessWindow
+ {
+ public ViewLogs()
+ {
+ InitializeComponent();
+ }
+
+ private void OnLogContextRequested(object sender, ContextRequestedEventArgs e)
+ {
+ if (sender is not Grid { DataContext: ViewModels.CommandLog log } grid || DataContext is not ViewModels.ViewLogs vm)
+ return;
+
+ var copy = new MenuItem();
+ copy.Header = App.Text("ViewLogs.CopyLog");
+ copy.Icon = App.CreateMenuIcon("Icons.Copy");
+ copy.Click += (_, ev) =>
+ {
+ App.CopyText(log.Content);
+ ev.Handled = true;
+ };
+
+ var rm = new MenuItem();
+ rm.Header = App.Text("ViewLogs.Delete");
+ rm.Icon = App.CreateMenuIcon("Icons.Clear");
+ rm.Click += (_, ev) =>
+ {
+ vm.Logs.Remove(log);
+ ev.Handled = true;
+ };
+
+ var menu = new ContextMenu();
+ menu.Items.Add(copy);
+ menu.Items.Add(rm);
+ menu.Open(grid);
+
+ e.Handled = true;
+ }
+ }
+}
diff --git a/src/Views/Welcome.axaml b/src/Views/Welcome.axaml
index 265c2cd4..1e300653 100644
--- a/src/Views/Welcome.axaml
+++ b/src/Views/Welcome.axaml
@@ -9,8 +9,14 @@
x:Class="SourceGit.Views.Welcome"
x:DataType="vm:Welcome">
+
+
+
+
+
+
-
+
-
-
+
-
-
-
-
-
-
-
-
+
-
-
-
-