Merge branch 'release/v2025.14'

This commit is contained in:
leo 2025-04-21 09:49:02 +08:00
commit 387b68cdfe
No known key found for this signature in database
166 changed files with 3260 additions and 1342 deletions

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -6,12 +6,16 @@ This document shows the translation status of each locale file in the repository
### ![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen)
### ![de__DE](https://img.shields.io/badge/de__DE-97.34%25-yellow)
### ![de__DE](https://img.shields.io/badge/de__DE-96.19%25-yellow)
<details>
<summary>Missing keys in de_DE.axaml</summary>
- 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
</details>
### ![es__ES](https://img.shields.io/badge/es__ES-98.67%25-yellow)
### ![es__ES](https://img.shields.io/badge/es__ES-98.95%25-yellow)
<details>
<summary>Missing keys in es_ES.axaml</summary>
- 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
</details>
### ![fr__FR](https://img.shields.io/badge/fr__FR-98.67%25-yellow)
### ![fr__FR](https://img.shields.io/badge/fr__FR-97.51%25-yellow)
<details>
<summary>Missing keys in fr_FR.axaml</summary>
- 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
</details>
### ![it__IT](https://img.shields.io/badge/it__IT-98.40%25-yellow)
### ![it__IT](https://img.shields.io/badge/it__IT-97.24%25-yellow)
<details>
<summary>Missing keys in it_IT.axaml</summary>
- 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
</details>
### ![ja__JP](https://img.shields.io/badge/ja__JP-98.40%25-yellow)
### ![ja__JP](https://img.shields.io/badge/ja__JP-97.24%25-yellow)
<details>
<summary>Missing keys in ja_JP.axaml</summary>
- 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
</details>
### ![pt__BR](https://img.shields.io/badge/pt__BR-89.76%25-yellow)
### ![pt__BR](https://img.shields.io/badge/pt__BR-88.71%25-yellow)
<details>
<summary>Missing keys in pt_BR.axaml</summary>
@ -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
</details>
### ![ru__RU](https://img.shields.io/badge/ru__RU-%E2%88%9A-brightgreen)
### ![ru__RU](https://img.shields.io/badge/ru__RU-98.82%25-yellow)
### ![ta__IN](https://img.shields.io/badge/ta__IN-98.67%25-yellow)
<details>
<summary>Missing keys in ru_RU.axaml</summary>
- 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
</details>
### ![ta__IN](https://img.shields.io/badge/ta__IN-97.51%25-yellow)
<details>
<summary>Missing keys in ta_IN.axaml</summary>
- 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
</details>
### ![uk__UA](https://img.shields.io/badge/uk__UA-98.69%25-yellow)
<details>
<summary>Missing keys in uk_UA.axaml</summary>
- 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
</details>
### ![zh__CN](https://img.shields.io/badge/zh__CN-%E2%88%9A-brightgreen)
### ![zh__TW](https://img.shields.io/badge/zh__TW-%E2%88%9A-brightgreen)

View file

@ -1 +1 @@
2025.13
2025.14

View file

@ -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(' <x:String', '\n <x:String');
await fs.writeFile(filePath, xmlStr + '\n', 'utf8');
if (missingKeys.length > 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(`<details>\n<summary>Missing keys in ${file}</summary>\n\n${missingKeys.map(key => `- ${key}`).join('\n')}\n\n</details>`)
} else {
lines.push(`### ![${locale}](https://img.shields.io/badge/${locale}-%E2%88%9A-brightgreen)`);
}
}
}
const content = lines.join('\n\n');

View file

@ -16,6 +16,7 @@
<ResourceInclude x:Key="fr_FR" Source="/Resources/Locales/fr_FR.axaml"/>
<ResourceInclude x:Key="it_IT" Source="/Resources/Locales/it_IT.axaml"/>
<ResourceInclude x:Key="pt_BR" Source="/Resources/Locales/pt_BR.axaml"/>
<ResourceInclude x:Key="uk_UA" Source="/Resources/Locales/uk_UA.axaml"/>
<ResourceInclude x:Key="ru_RU" Source="/Resources/Locales/ru_RU.axaml"/>
<ResourceInclude x:Key="zh_CN" Source="/Resources/Locales/zh_CN.axaml"/>
<ResourceInclude x:Key="zh_TW" Source="/Resources/Locales/zh_TW.axaml"/>

View file

@ -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;

View file

@ -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<string> 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<string> _outputHandler;
}
}

View file

@ -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<string> 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<string> _outs = new List<string>();
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<string> 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;
}
}

View file

@ -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;

View file

@ -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();
}
}

View file

@ -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<string> 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<string> 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<string> 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<string> _outputHandler;
}
}

View file

@ -1,16 +1,11 @@
using System;
namespace SourceGit.Commands
namespace SourceGit.Commands
{
public class Clone : Command
{
private readonly Action<string> _notifyProgress;
public Clone(string ctx, string path, string url, string localName, string sshKey, string extraArgs, Action<string> 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);
}
}
}

View file

@ -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<string>();
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();

View file

@ -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";

View file

@ -31,12 +31,19 @@ namespace SourceGit.Commands
public List<Models.Change> 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)

View file

@ -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<Models.TextDiffLine> _deleted = new List<Models.TextDiffLine>();
private readonly List<Models.TextDiffLine> _added = new List<Models.TextDiffLine>();
private Models.TextDiffLine _last = null;
private int _oldLine = 0;
private int _newLine = 0;
}

View file

@ -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<Models.Change> changes)
public static void Changes(string repo, List<Models.Change> changes, Models.ICommandLog log)
{
var needClean = new List<string>();
var needCheckout = new List<string>();
@ -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();
}
}
}

View file

@ -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<string> 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<string> 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<string> _outputHandler;
}
}

View file

@ -1,23 +1,12 @@
using System;
namespace SourceGit.Commands
namespace SourceGit.Commands
{
public class GC : Command
{
public GC(string repo, Action<string> 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<string> _outputHandler;
}
}

View file

@ -35,17 +35,17 @@ namespace SourceGit.Commands
config.ContainsKey("gitflow.prefix.hotfix");
}
public static bool Init(string repo, List<Models.Branch> branches, string master, string develop, string feature, string release, string hotfix, string version)
public static bool Init(string repo, List<Models.Branch> 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();
}

View file

@ -10,5 +10,10 @@
Context = repo;
Args = $"diff -a --ignore-cr-at-eol --check {opt}";
}
public bool Result()
{
return ReadToEnd().IsSuccess;
}
}
}

View file

@ -12,21 +12,13 @@ namespace SourceGit.Commands
class SubCmd : Command
{
public SubCmd(string repo, string args, Action<string> 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<string> _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<string> 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<string> 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<string> 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<string> outputHandler)
public void Prune(Models.ICommandLog log)
{
new SubCmd(_repo, "lfs prune", outputHandler).Exec();
new SubCmd(_repo, "lfs prune", log).Exec();
}
public List<Models.LFSLock> 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;

View file

@ -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<string> 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<string> targets, bool autoCommit, string strategy, Action<string> outputHandler)
public Merge(string repo, List<string> 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<string> _outputHandler = null;
}
}

View file

@ -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<string> 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<string> _outputHandler;
}
}

View file

@ -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<string> 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<string> _outputHandler = null;
}
}

View file

@ -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<string> Result()
{
var outs = new List<string>();
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;
}
}
}

View file

@ -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();

View file

@ -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<string> Result()
{
Exec();
return _lines;
}
var rs = ReadToEnd();
var outs = new List<string>();
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<string> _lines = new List<string>();
}
}

View file

@ -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<Models.Change> Result()
{
Exec();
return _changes;
}
var outs = new List<Models.Change>();
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<Models.Change> _changes = new List<Models.Change>();
}
}

View file

@ -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<Models.Remote> Result()
{
Exec();
return _loaded;
}
var outs = new List<Models.Remote>();
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<Models.Remote> _loaded = new List<Models.Remote>();
}
}

View file

@ -14,35 +14,50 @@ namespace SourceGit.Commands
public List<Models.Stash> Result()
{
Exec();
return _stashes;
}
var outs = new List<Models.Stash>();
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<Models.Stash> _stashes = new List<Models.Stash>();
private Models.Stash _current = null;
private int _nextLineIdx = 0;
}
}

View file

@ -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);
}

View file

@ -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<string> 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<string> 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<string> _outputHandler;
}
}

View file

@ -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<Models.Remote> 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();
}
}
}

View file

@ -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<string> 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<string> _outputHandler;
}
}

View file

@ -56,7 +56,7 @@ namespace SourceGit.Commands
return worktrees;
}
public bool Add(string fullpath, string name, bool createNew, string tracking, Action<string> 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<string> 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<string> 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<string> _outputHandler = null;
}
}

View file

@ -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}";
}

View file

@ -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<ConventionalCommitType> Supported = new List<ConventionalCommitType>()
{
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;
}

View file

@ -30,6 +30,7 @@ namespace SourceGit.Models
public int OldLineNumber { get; set; } = 0;
public int NewLineNumber { get; set; } = 0;
public List<TextInlineRange> Highlights { get; set; } = new List<TextInlineRange>();
public bool NoNewLineEndOfFile { get; set; } = false;
public string OldLine => OldLineNumber == 0 ? string.Empty : OldLineNumber.ToString();
public string NewLine => NewLineNumber == 0 ? string.Empty : NewLineNumber.ToString();

View file

@ -0,0 +1,7 @@
namespace SourceGit.Models
{
public interface ICommandLog
{
void AppendLine(string line);
}
}

View file

@ -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<InteractiveRebaseJob> Jobs { get; set; } = new List<InteractiveRebaseJob>();
}
}

104
src/Models/IpcChannel.cs Normal file
View file

@ -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<string> 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;
}
}

View file

@ -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"),

View file

@ -230,6 +230,12 @@ namespace SourceGit.Models
set;
} = 0;
public string LastCommitMessage
{
get;
set;
} = string.Empty;
public Dictionary<string, FilterMode> CollectHistoriesFilters()
{
var map = new Dictionary<string, FilterMode>();

View file

@ -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<StaticsticsAuthor> Authors { get; set; } = new List<StaticsticsAuthor>();
public List<StatisticsAuthor> Authors { get; set; } = new List<StatisticsAuthor>();
public List<ISeries> Series { get; set; } = new List<ISeries>();
public List<Axis> XAxes { get; set; } = new List<Axis>();
public List<Axis> YAxes { get; set; } = new List<Axis>();
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<DateTime, int>
{
{ 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<DateTimePoint>();
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<DateTimePoint> series])
series.Fill = new SolidColorPaint(new SKColor(color));
_fillColor = color;
var fill = new SKColor(color);
if (Series.Count > 0 && Series[0] is ColumnSeries<DateTimePoint> total)
total.Fill = new SolidColorPaint(_selectedAuthor == null ? fill : fill.WithAlpha(51));
if (Series.Count > 1 && Series[1] is ColumnSeries<DateTimePoint> 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<DateTimePoint>();
foreach (var kv in userSamples)
samples.Add(new DateTimePoint(kv.Key, kv.Value));
Series.Add(
new ColumnSeries<DateTimePoint>()
{
Values = samples,
Stroke = null,
Fill = null,
Padding = 1,
}
);
ChangeColor(_fillColor);
}
private StatisticsMode _mode = StatisticsMode.All;
private Dictionary<User, int> _mapUsers = new Dictionary<User, int>();
private Dictionary<DateTime, int> _mapSamples = new Dictionary<DateTime, int>();
private Dictionary<User, Dictionary<DateTime, int>> _mapUserSamples = new Dictionary<User, Dictionary<DateTime, int>>();
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)

View file

@ -46,6 +46,7 @@
<StreamGeometry x:Key="Icons.File.Ignore">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</StreamGeometry>
<StreamGeometry x:Key="Icons.File.Remove">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Filter">M599 425 599 657 425 832 425 425 192 192 832 192Z</StreamGeometry>
<StreamGeometry x:Key="Icons.Fingerprint">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</StreamGeometry>
<StreamGeometry x:Key="Icons.FirstParentFilter">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Folder">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Folder.Add">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</StreamGeometry>
@ -78,6 +79,7 @@
<StreamGeometry x:Key="Icons.Loading">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Local">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Lock">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Logs">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Menu">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Merge">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Modified">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</StreamGeometry>
@ -115,6 +117,7 @@
<StreamGeometry x:Key="Icons.Submodule">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Submodule.Add">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Submodules">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Subject">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</StreamGeometry>
<StreamGeometry x:Key="Icons.SyntaxHighlight">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Tag">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Tag.Add">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</StreamGeometry>
@ -129,6 +132,7 @@
<StreamGeometry x:Key="Icons.Undo">M762 1024C876 818 895 504 448 514V768L64 384l384-384v248c535-14 595 472 314 776z</StreamGeometry>
<StreamGeometry x:Key="Icons.Unlock">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Up">M170 831l343-342L855 831l105-105-448-448L64 726 170 831z</StreamGeometry>
<StreamGeometry x:Key="Icons.User">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Verified">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Waiting">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</StreamGeometry>
<StreamGeometry x:Key="Icons.Whitespace">M0 512M1024 512M512 0M512 1024M762 412v100h-500v-100h-150v200h800v-200h-150z</StreamGeometry>

View file

@ -102,8 +102,8 @@
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">Mehrere cherry-picken</x:String>
<x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">Mit HEAD vergleichen</x:String>
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">Mit Worktree vergleichen</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Info kopieren</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">SHA kopieren</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Information</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">Benutzerdefinierte Aktion</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">Interactives Rebase von ${0}$ auf diesen Commit</x:String>
<x:String x:Key="Text.CommitCM.Merge" xml:space="preserve">Merge in ${0}$ hinein</x:String>
@ -176,6 +176,7 @@
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">Benutzername für dieses Repository</x:String>
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">Arbeitsplätze</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">Farbe</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">Name</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">Zuletzt geöffnete Tabs beim Starten wiederherstellen</x:String>
<x:String x:Key="Text.ConventionalCommit" xml:space="preserve">Konventionelle Commit-Hilfe</x:String>
<x:String x:Key="Text.ConventionalCommit.BreakingChanges" xml:space="preserve">Breaking Change:</x:String>
@ -235,7 +236,7 @@
<x:String x:Key="Text.Diff.Binary.Old" xml:space="preserve">ALT</x:String>
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">Kopieren</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">Dateimodus geändert</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignoriere Leerzeichenänderungen</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignoriere Leerzeichenänderungen und EOL</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">LFS OBJEKT ÄNDERUNG</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Nächste Änderung</x:String>
<x:String x:Key="Text.Diff.NoChange" xml:space="preserve">KEINE ÄNDERUNG ODER NUR ZEILEN-ENDE ÄNDERUNGEN</x:String>

View file

@ -3,15 +3,15 @@
<x:String x:Key="Text.About.Menu" xml:space="preserve">About SourceGit</x:String>
<x:String x:Key="Text.About.SubTitle" xml:space="preserve">Opensource &amp; Free Git GUI Client</x:String>
<x:String x:Key="Text.AddWorktree" xml:space="preserve">Add Worktree</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout" xml:space="preserve">What to Checkout:</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.Existing" xml:space="preserve">Existing Branch</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.CreateNew" xml:space="preserve">Create New Branch</x:String>
<x:String x:Key="Text.AddWorktree.Location" xml:space="preserve">Location:</x:String>
<x:String x:Key="Text.AddWorktree.Location.Placeholder" xml:space="preserve">Path for this worktree. Relative path is supported.</x:String>
<x:String x:Key="Text.AddWorktree.Name" xml:space="preserve">Branch Name:</x:String>
<x:String x:Key="Text.AddWorktree.Name.Placeholder" xml:space="preserve">Optional. Default is the destination folder name.</x:String>
<x:String x:Key="Text.AddWorktree.Tracking" xml:space="preserve">Track Branch:</x:String>
<x:String x:Key="Text.AddWorktree.Tracking.Toggle" xml:space="preserve">Tracking remote branch</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout" xml:space="preserve">What to Checkout:</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.CreateNew" xml:space="preserve">Create New Branch</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.Existing" xml:space="preserve">Existing Branch</x:String>
<x:String x:Key="Text.AIAssistant" xml:space="preserve">AI Assistant</x:String>
<x:String x:Key="Text.AIAssistant.Regen" xml:space="preserve">RE-GENERATE</x:String>
<x:String x:Key="Text.AIAssistant.Tip" xml:space="preserve">Use AI to generate commit message</x:String>
@ -61,8 +61,8 @@
<x:String x:Key="Text.BranchUpstreamInvalid" xml:space="preserve">Invalid upstream!</x:String>
<x:String x:Key="Text.Bytes" xml:space="preserve">Bytes</x:String>
<x:String x:Key="Text.Cancel" xml:space="preserve">CANCEL</x:String>
<x:String x:Key="Text.ChangeCM.CheckoutThisRevision" xml:space="preserve">Reset to This Revision</x:String>
<x:String x:Key="Text.ChangeCM.CheckoutFirstParentRevision" xml:space="preserve">Reset to Parent Revision</x:String>
<x:String x:Key="Text.ChangeCM.CheckoutThisRevision" xml:space="preserve">Reset to This Revision</x:String>
<x:String x:Key="Text.ChangeCM.GenerateCommitMessage" xml:space="preserve">Generate commit message</x:String>
<x:String x:Key="Text.ChangeDisplayMode" xml:space="preserve">CHANGE DISPLAY MODE</x:String>
<x:String x:Key="Text.ChangeDisplayMode.Grid" xml:space="preserve">Show as File and Dir List</x:String>
@ -70,12 +70,12 @@
<x:String x:Key="Text.ChangeDisplayMode.Tree" xml:space="preserve">Show as Filesystem Tree</x:String>
<x:String x:Key="Text.Checkout" xml:space="preserve">Checkout Branch</x:String>
<x:String x:Key="Text.Checkout.Commit" xml:space="preserve">Checkout Commit</x:String>
<x:String x:Key="Text.Checkout.Commit.Warning" xml:space="preserve">Warning: By doing a commit checkout, your Head will be detached</x:String>
<x:String x:Key="Text.Checkout.Commit.Target" xml:space="preserve">Commit:</x:String>
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">Branch:</x:String>
<x:String x:Key="Text.Checkout.Commit.Warning" xml:space="preserve">Warning: By doing a commit checkout, your Head will be detached</x:String>
<x:String x:Key="Text.Checkout.LocalChanges" xml:space="preserve">Local Changes:</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.Discard" xml:space="preserve">Discard</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Stash &amp; Reapply</x:String>
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">Branch:</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">Cherry Pick</x:String>
<x:String x:Key="Text.CherryPick.AppendSourceToMessage" xml:space="preserve">Append source to commit message</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit(s):</x:String>
@ -94,13 +94,16 @@
<x:String x:Key="Text.Clone.RemoteURL" xml:space="preserve">Repository URL:</x:String>
<x:String x:Key="Text.Close" xml:space="preserve">CLOSE</x:String>
<x:String x:Key="Text.CodeEditor" xml:space="preserve">Editor</x:String>
<x:String x:Key="Text.CommitCM.Checkout" xml:space="preserve">Checkout Commit</x:String>
<x:String x:Key="Text.CommitCM.CherryPick" xml:space="preserve">Cherry-Pick Commit</x:String>
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">Cherry-Pick ...</x:String>
<x:String x:Key="Text.CommitCM.Checkout" xml:space="preserve">Checkout Commit</x:String>
<x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">Compare with HEAD</x:String>
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">Compare with Worktree</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Copy Info</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">Copy SHA</x:String>
<x:String x:Key="Text.CommitCM.CopyAuthor" xml:space="preserve">Author</x:String>
<x:String x:Key="Text.CommitCM.CopyCommitter" xml:space="preserve">Committer</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Information</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.CommitCM.CopySubject" xml:space="preserve">Subject</x:String>
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">Custom Action</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">Interactively Rebase ${0}$ on Here</x:String>
<x:String x:Key="Text.CommitCM.Merge" xml:space="preserve">Merge to ${0}$</x:String>
@ -131,12 +134,13 @@
<x:String x:Key="Text.CommitDetail.Info.Refs" xml:space="preserve">REFS</x:String>
<x:String x:Key="Text.CommitDetail.Info.SHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.CommitDetail.Info.WebLinks" xml:space="preserve">Open in Browser</x:String>
<x:String x:Key="Text.CommitMessageTextBox.SubjectPlaceholder" xml:space="preserve">Enter commit subject</x:String>
<x:String x:Key="Text.CommitMessageTextBox.MessagePlaceholder" xml:space="preserve">Description</x:String>
<x:String x:Key="Text.CommitMessageTextBox.SubjectCount" xml:space="preserve">SUBJECT</x:String>
<x:String x:Key="Text.CommitMessageTextBox.SubjectPlaceholder" xml:space="preserve">Enter commit subject</x:String>
<x:String x:Key="Text.Configure" xml:space="preserve">Repository Configure</x:String>
<x:String x:Key="Text.Configure.CommitMessageTemplate" xml:space="preserve">COMMIT TEMPLATE</x:String>
<x:String x:Key="Text.Configure.CommitMessageTemplate.Name" xml:space="preserve">Template Name:</x:String>
<x:String x:Key="Text.Configure.CommitMessageTemplate.Content" xml:space="preserve">Template Content:</x:String>
<x:String x:Key="Text.Configure.CommitMessageTemplate.Name" xml:space="preserve">Template Name:</x:String>
<x:String x:Key="Text.Configure.CustomAction" xml:space="preserve">CUSTOM ACTION</x:String>
<x:String x:Key="Text.Configure.CustomAction.Arguments" xml:space="preserve">Arguments:</x:String>
<x:String x:Key="Text.Configure.CustomAction.Arguments.Tip" xml:space="preserve">${REPO} - Repository's path; ${BRANCH} - Selected branch; ${SHA} - Selected commit's SHA</x:String>
@ -155,13 +159,13 @@
<x:String x:Key="Text.Configure.Git.DefaultRemote" xml:space="preserve">Default Remote</x:String>
<x:String x:Key="Text.Configure.Git.PreferredMergeMode" xml:space="preserve">Preferred Merge Mode</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ISSUE TRACKER</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleAzure" xml:space="preserve">Add Sample Azure DevOps Rule</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteeIssue" xml:space="preserve">Add Sample Gitee Issue Rule</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteePullRequest" xml:space="preserve">Add Sample Gitee Pull Request Rule</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Add Sample Github Rule</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGitLabIssue" xml:space="preserve">Add Sample GitLab Issue Rule</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGitLabMergeRequest" xml:space="preserve">Add Sample GitLab Merge Request Rule</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Add Sample Jira Rule</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleAzure" xml:space="preserve">Add Sample Azure DevOps Rule</x:String>
<x:String x:Key="Text.Configure.IssueTracker.NewRule" xml:space="preserve">New Rule</x:String>
<x:String x:Key="Text.Configure.IssueTracker.Regex" xml:space="preserve">Issue Regex Expression:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">Rule Name:</x:String>
@ -176,6 +180,7 @@
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">User name for this repository</x:String>
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">Workspaces</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">Color</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">Name</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">Restore tabs on startup</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.Continue" xml:space="preserve">CONTINUE</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.NoLocalChanges" xml:space="preserve">Empty commit detected! Do you want to continue (--allow-empty)?</x:String>
@ -190,8 +195,8 @@
<x:String x:Key="Text.ConventionalCommit.Type" xml:space="preserve">Type of Change:</x:String>
<x:String x:Key="Text.Copy" xml:space="preserve">Copy</x:String>
<x:String x:Key="Text.CopyAllText" xml:space="preserve">Copy All Text</x:String>
<x:String x:Key="Text.CopyPath" xml:space="preserve">Copy Path</x:String>
<x:String x:Key="Text.CopyFullPath" xml:space="preserve">Copy Full Path</x:String>
<x:String x:Key="Text.CopyPath" xml:space="preserve">Copy Path</x:String>
<x:String x:Key="Text.CreateBranch" xml:space="preserve">Create Branch...</x:String>
<x:String x:Key="Text.CreateBranch.BasedOn" xml:space="preserve">Based On:</x:String>
<x:String x:Key="Text.CreateBranch.Checkout" xml:space="preserve">Check out the created branch</x:String>
@ -227,8 +232,8 @@
<x:String x:Key="Text.DeleteRepositoryNode.Path" xml:space="preserve">Path:</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.Target" xml:space="preserve">Target:</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.TipForGroup" xml:space="preserve">All children will be removed from list.</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.TitleForGroup" xml:space="preserve">Confirm Deleting Group</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.TipForRepository" xml:space="preserve">This will only remove it from list, not from disk!</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.TitleForGroup" xml:space="preserve">Confirm Deleting Group</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.TitleForRepository" xml:space="preserve">Confirm Deleting Repository</x:String>
<x:String x:Key="Text.DeleteSubmodule" xml:space="preserve">Delete Submodule</x:String>
<x:String x:Key="Text.DeleteSubmodule.Path" xml:space="preserve">Submodule Path:</x:String>
@ -241,7 +246,7 @@
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">Copy</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">File Mode Changed</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">First Difference</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignore Whitespace Change</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignore Whitespace Change and EOL</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">Last Difference</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">LFS OBJECT CHANGE</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Next Difference</x:String>
@ -297,11 +302,11 @@
<x:String x:Key="Text.FileCM.Unstage" xml:space="preserve">Unstage</x:String>
<x:String x:Key="Text.FileCM.UnstageMulti" xml:space="preserve">Unstage {0} files</x:String>
<x:String x:Key="Text.FileCM.UnstageSelectedLines" xml:space="preserve">Unstage Changes in Selected Line(s)</x:String>
<x:String x:Key="Text.FileCM.UseTheirs" xml:space="preserve">Use Theirs (checkout --theirs)</x:String>
<x:String x:Key="Text.FileCM.UseMine" xml:space="preserve">Use Mine (checkout --ours)</x:String>
<x:String x:Key="Text.FileCM.UseTheirs" xml:space="preserve">Use Theirs (checkout --theirs)</x:String>
<x:String x:Key="Text.FileHistory" xml:space="preserve">File History</x:String>
<x:String x:Key="Text.FileHistory.FileContent" xml:space="preserve">CONTENT</x:String>
<x:String x:Key="Text.FileHistory.FileChange" xml:space="preserve">CHANGE</x:String>
<x:String x:Key="Text.FileHistory.FileContent" xml:space="preserve">CONTENT</x:String>
<x:String x:Key="Text.GitFlow" xml:space="preserve">Git-Flow</x:String>
<x:String x:Key="Text.GitFlow.DevelopBranch" xml:space="preserve">Development Branch:</x:String>
<x:String x:Key="Text.GitFlow.Feature" xml:space="preserve">Feature:</x:String>
@ -331,8 +336,8 @@
<x:String x:Key="Text.GitLFS.AddTrackPattern.Pattern" xml:space="preserve">Custom Pattern:</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern.Title" xml:space="preserve">Add Track Pattern to Git LFS</x:String>
<x:String x:Key="Text.GitLFS.Fetch" xml:space="preserve">Fetch</x:String>
<x:String x:Key="Text.GitLFS.Fetch.Title" xml:space="preserve">Fetch LFS Objects</x:String>
<x:String x:Key="Text.GitLFS.Fetch.Tips" xml:space="preserve">Run `git lfs fetch` to download Git LFS objects. This does not update the working copy.</x:String>
<x:String x:Key="Text.GitLFS.Fetch.Title" xml:space="preserve">Fetch LFS Objects</x:String>
<x:String x:Key="Text.GitLFS.Install" xml:space="preserve">Install Git LFS hooks</x:String>
<x:String x:Key="Text.GitLFS.Locks" xml:space="preserve">Show Locks</x:String>
<x:String x:Key="Text.GitLFS.Locks.Empty" xml:space="preserve">No Locked Files</x:String>
@ -344,11 +349,11 @@
<x:String x:Key="Text.GitLFS.Prune" xml:space="preserve">Prune</x:String>
<x:String x:Key="Text.GitLFS.Prune.Tips" xml:space="preserve">Run `git lfs prune` to delete old LFS files from local storage</x:String>
<x:String x:Key="Text.GitLFS.Pull" xml:space="preserve">Pull</x:String>
<x:String x:Key="Text.GitLFS.Pull.Title" xml:space="preserve">Pull LFS Objects</x:String>
<x:String x:Key="Text.GitLFS.Pull.Tips" xml:space="preserve">Run `git lfs pull` to download all Git LFS files for current ref &amp; checkout</x:String>
<x:String x:Key="Text.GitLFS.Pull.Title" xml:space="preserve">Pull LFS Objects</x:String>
<x:String x:Key="Text.GitLFS.Push" xml:space="preserve">Push</x:String>
<x:String x:Key="Text.GitLFS.Push.Title" xml:space="preserve">Push LFS Objects</x:String>
<x:String x:Key="Text.GitLFS.Push.Tips" xml:space="preserve">Push queued large files to the Git LFS endpoint</x:String>
<x:String x:Key="Text.GitLFS.Push.Title" xml:space="preserve">Push LFS Objects</x:String>
<x:String x:Key="Text.GitLFS.Remote" xml:space="preserve">Remote:</x:String>
<x:String x:Key="Text.GitLFS.Track" xml:space="preserve">Track files named '{0}'</x:String>
<x:String x:Key="Text.GitLFS.TrackByExtension" xml:space="preserve">Track all *{0} files</x:String>
@ -367,8 +372,8 @@
<x:String x:Key="Text.Hotkeys.Global.CancelPopup" xml:space="preserve">Cancel current popup</x:String>
<x:String x:Key="Text.Hotkeys.Global.Clone" xml:space="preserve">Clone new repository</x:String>
<x:String x:Key="Text.Hotkeys.Global.CloseTab" xml:space="preserve">Close current page</x:String>
<x:String x:Key="Text.Hotkeys.Global.GotoPrevTab" xml:space="preserve">Go to previous page</x:String>
<x:String x:Key="Text.Hotkeys.Global.GotoNextTab" xml:space="preserve">Go to next page</x:String>
<x:String x:Key="Text.Hotkeys.Global.GotoPrevTab" xml:space="preserve">Go to previous page</x:String>
<x:String x:Key="Text.Hotkeys.Global.NewTab" xml:space="preserve">Create new page</x:String>
<x:String x:Key="Text.Hotkeys.Global.OpenPreferences" xml:space="preserve">Open Preferences dialog</x:String>
<x:String x:Key="Text.Hotkeys.Repo" xml:space="preserve">REPOSITORY</x:String>
@ -379,11 +384,11 @@
<x:String x:Key="Text.Hotkeys.Repo.DiscardSelected" xml:space="preserve">Discard selected changes</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Fetch" xml:space="preserve">Fetch, starts directly</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">Dashboard mode (Default)</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">Commit search mode</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Pull" xml:space="preserve">Pull, starts directly</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Push" xml:space="preserve">Push, starts directly</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Refresh" xml:space="preserve">Force to reload this repository</x:String>
<x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">Stage/Unstage selected changes</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">Commit search mode</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewChanges" xml:space="preserve">Switch to 'Changes'</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewHistories" xml:space="preserve">Switch to 'Histories'</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewStashes" xml:space="preserve">Switch to 'Stashes'</x:String>
@ -392,9 +397,9 @@
<x:String x:Key="Text.Hotkeys.TextEditor.GotoNextMatch" xml:space="preserve">Find next match</x:String>
<x:String x:Key="Text.Hotkeys.TextEditor.GotoPrevMatch" xml:space="preserve">Find previous match</x:String>
<x:String x:Key="Text.Hotkeys.TextEditor.Search" xml:space="preserve">Open search panel</x:String>
<x:String x:Key="Text.Hunk.Discard" xml:space="preserve">Discard</x:String>
<x:String x:Key="Text.Hunk.Stage" xml:space="preserve">Stage</x:String>
<x:String x:Key="Text.Hunk.Unstage" xml:space="preserve">Unstage</x:String>
<x:String x:Key="Text.Hunk.Discard" xml:space="preserve">Discard</x:String>
<x:String x:Key="Text.Init" xml:space="preserve">Initialize Repository</x:String>
<x:String x:Key="Text.Init.Path" xml:space="preserve">Path:</x:String>
<x:String x:Key="Text.InProgress.CherryPick" xml:space="preserve">Cherry-Pick in progress.</x:String>
@ -406,10 +411,10 @@
<x:String x:Key="Text.InProgress.Revert" xml:space="preserve">Revert in progress.</x:String>
<x:String x:Key="Text.InProgress.Revert.Head" xml:space="preserve">Reverting commit</x:String>
<x:String x:Key="Text.InteractiveRebase" xml:space="preserve">Interactive Rebase</x:String>
<x:String x:Key="Text.InteractiveRebase.Target" xml:space="preserve">Target Branch:</x:String>
<x:String x:Key="Text.InteractiveRebase.On" xml:space="preserve">On:</x:String>
<x:String x:Key="Text.IssueLinkCM.OpenInBrowser" xml:space="preserve">Open in Browser</x:String>
<x:String x:Key="Text.InteractiveRebase.Target" xml:space="preserve">Target Branch:</x:String>
<x:String x:Key="Text.IssueLinkCM.CopyLink" xml:space="preserve">Copy Link</x:String>
<x:String x:Key="Text.IssueLinkCM.OpenInBrowser" xml:space="preserve">Open in Browser</x:String>
<x:String x:Key="Text.Launcher.Error" xml:space="preserve">ERROR</x:String>
<x:String x:Key="Text.Launcher.Info" xml:space="preserve">NOTICE</x:String>
<x:String x:Key="Text.Merge" xml:space="preserve">Merge Branch</x:String>
@ -435,16 +440,16 @@
<x:String x:Key="Text.PageTabBar.Tab.CopyPath" xml:space="preserve">Copy Repository Path</x:String>
<x:String x:Key="Text.PageTabBar.Welcome.Title" xml:space="preserve">Repositories</x:String>
<x:String x:Key="Text.Paste" xml:space="preserve">Paste</x:String>
<x:String x:Key="Text.Period.JustNow" xml:space="preserve">Just now</x:String>
<x:String x:Key="Text.Period.MinutesAgo" xml:space="preserve">{0} minutes ago</x:String>
<x:String x:Key="Text.Period.DaysAgo" xml:space="preserve">{0} days ago</x:String>
<x:String x:Key="Text.Period.HourAgo" xml:space="preserve">1 hour ago</x:String>
<x:String x:Key="Text.Period.HoursAgo" xml:space="preserve">{0} hours ago</x:String>
<x:String x:Key="Text.Period.Yesterday" xml:space="preserve">Yesterday</x:String>
<x:String x:Key="Text.Period.DaysAgo" xml:space="preserve">{0} days ago</x:String>
<x:String x:Key="Text.Period.JustNow" xml:space="preserve">Just now</x:String>
<x:String x:Key="Text.Period.LastMonth" xml:space="preserve">Last month</x:String>
<x:String x:Key="Text.Period.MonthsAgo" xml:space="preserve">{0} months ago</x:String>
<x:String x:Key="Text.Period.LastYear" xml:space="preserve">Last year</x:String>
<x:String x:Key="Text.Period.MinutesAgo" xml:space="preserve">{0} minutes ago</x:String>
<x:String x:Key="Text.Period.MonthsAgo" xml:space="preserve">{0} months ago</x:String>
<x:String x:Key="Text.Period.YearsAgo" xml:space="preserve">{0} years ago</x:String>
<x:String x:Key="Text.Period.Yesterday" xml:space="preserve">Yesterday</x:String>
<x:String x:Key="Text.Preferences" xml:space="preserve">Preferences</x:String>
<x:String x:Key="Text.Preferences.AI" xml:space="preserve">AI</x:String>
<x:String x:Key="Text.Preferences.AI.AnalyzeDiffPrompt" xml:space="preserve">Analyze Diff Prompt</x:String>
@ -485,24 +490,24 @@
<x:String x:Key="Text.Preferences.Git.Email" xml:space="preserve">User Email</x:String>
<x:String x:Key="Text.Preferences.Git.Email.Placeholder" xml:space="preserve">Global git user email</x:String>
<x:String x:Key="Text.Preferences.Git.EnablePruneOnFetch" xml:space="preserve">Enable --prune on fetch</x:String>
<x:String x:Key="Text.Preferences.Git.Invalid" xml:space="preserve">Git (&gt;= 2.23.0) is required by this app</x:String>
<x:String x:Key="Text.Preferences.Git.Path" xml:space="preserve">Install Path</x:String>
<x:String x:Key="Text.Preferences.Git.SSLVerify" xml:space="preserve">Enable HTTP SSL Verify</x:String>
<x:String x:Key="Text.Preferences.Git.User" xml:space="preserve">User Name</x:String>
<x:String x:Key="Text.Preferences.Git.User.Placeholder" xml:space="preserve">Global git user name</x:String>
<x:String x:Key="Text.Preferences.Git.Version" xml:space="preserve">Git version</x:String>
<x:String x:Key="Text.Preferences.Git.Invalid" xml:space="preserve">Git (&gt;= 2.23.0) is required by this app</x:String>
<x:String x:Key="Text.Preferences.GPG" xml:space="preserve">GPG SIGNING</x:String>
<x:String x:Key="Text.Preferences.GPG.CommitEnabled" xml:space="preserve">Commit GPG signing</x:String>
<x:String x:Key="Text.Preferences.GPG.TagEnabled" xml:space="preserve">Tag GPG signing</x:String>
<x:String x:Key="Text.Preferences.GPG.Format" xml:space="preserve">GPG Format</x:String>
<x:String x:Key="Text.Preferences.GPG.Path" xml:space="preserve">Program Install Path</x:String>
<x:String x:Key="Text.Preferences.GPG.Path.Placeholder" xml:space="preserve">Input path for installed gpg program</x:String>
<x:String x:Key="Text.Preferences.GPG.TagEnabled" xml:space="preserve">Tag GPG signing</x:String>
<x:String x:Key="Text.Preferences.GPG.UserKey" xml:space="preserve">User Signing Key</x:String>
<x:String x:Key="Text.Preferences.GPG.UserKey.Placeholder" xml:space="preserve">User's gpg signing key</x:String>
<x:String x:Key="Text.Preferences.Integration" xml:space="preserve">INTEGRATION</x:String>
<x:String x:Key="Text.Preferences.Shell" xml:space="preserve">SHELL/TERMINAL</x:String>
<x:String x:Key="Text.Preferences.Shell.Type" xml:space="preserve">Shell/Terminal</x:String>
<x:String x:Key="Text.Preferences.Shell.Path" xml:space="preserve">Path</x:String>
<x:String x:Key="Text.Preferences.Shell.Type" xml:space="preserve">Shell/Terminal</x:String>
<x:String x:Key="Text.PruneRemote" xml:space="preserve">Prune Remote</x:String>
<x:String x:Key="Text.PruneRemote.Target" xml:space="preserve">Target:</x:String>
<x:String x:Key="Text.PruneWorktrees" xml:space="preserve">Prune Worktrees</x:String>
@ -610,6 +615,7 @@
<x:String x:Key="Text.Repository.Tags.Sort" xml:space="preserve">Sort</x:String>
<x:String x:Key="Text.Repository.Terminal" xml:space="preserve">Open in Terminal</x:String>
<x:String x:Key="Text.Repository.UseRelativeTimeInHistories" xml:space="preserve">Use relative time in histories</x:String>
<x:String x:Key="Text.Repository.ViewLogs" xml:space="preserve">View Logs</x:String>
<x:String x:Key="Text.Repository.Worktrees" xml:space="preserve">WORKTREES</x:String>
<x:String x:Key="Text.Repository.Worktrees.Add" xml:space="preserve">ADD WORKTREE</x:String>
<x:String x:Key="Text.Repository.Worktrees.Prune" xml:space="preserve">PRUNE</x:String>
@ -669,11 +675,11 @@
<x:String x:Key="Text.Statistics" xml:space="preserve">Statistics</x:String>
<x:String x:Key="Text.Statistics.CommitAmount" xml:space="preserve">COMMITS</x:String>
<x:String x:Key="Text.Statistics.Committer" xml:space="preserve">COMMITTER</x:String>
<x:String x:Key="Text.Statistics.Overview" xml:space="preserve">OVERVIEW</x:String>
<x:String x:Key="Text.Statistics.ThisMonth" xml:space="preserve">MONTH</x:String>
<x:String x:Key="Text.Statistics.ThisWeek" xml:space="preserve">WEEK</x:String>
<x:String x:Key="Text.Statistics.TotalCommits" xml:space="preserve">COMMITS: </x:String>
<x:String x:Key="Text.Statistics.TotalAuthors" xml:space="preserve">AUTHORS: </x:String>
<x:String x:Key="Text.Statistics.Overview" xml:space="preserve">OVERVIEW</x:String>
<x:String x:Key="Text.Statistics.TotalCommits" xml:space="preserve">COMMITS: </x:String>
<x:String x:Key="Text.Submodule" xml:space="preserve">SUBMODULES</x:String>
<x:String x:Key="Text.Submodule.Add" xml:space="preserve">Add Submodule</x:String>
<x:String x:Key="Text.Submodule.CopyPath" xml:space="preserve">Copy Relative Path</x:String>
@ -688,13 +694,17 @@
<x:String x:Key="Text.TagCM.Delete" xml:space="preserve">Delete ${0}$...</x:String>
<x:String x:Key="Text.TagCM.Merge" xml:space="preserve">Merge ${0}$ into ${1}$...</x:String>
<x:String x:Key="Text.TagCM.Push" xml:space="preserve">Push ${0}$...</x:String>
<x:String x:Key="Text.URL" xml:space="preserve">URL:</x:String>
<x:String x:Key="Text.UpdateSubmodules" xml:space="preserve">Update Submodules</x:String>
<x:String x:Key="Text.UpdateSubmodules.All" xml:space="preserve">All submodules</x:String>
<x:String x:Key="Text.UpdateSubmodules.Init" xml:space="preserve">Initialize as needed</x:String>
<x:String x:Key="Text.UpdateSubmodules.Recursive" xml:space="preserve">Recursively</x:String>
<x:String x:Key="Text.UpdateSubmodules.Target" xml:space="preserve">Submodule:</x:String>
<x:String x:Key="Text.UpdateSubmodules.UseRemote" xml:space="preserve">Use --remote option</x:String>
<x:String x:Key="Text.URL" xml:space="preserve">URL:</x:String>
<x:String x:Key="Text.ViewLogs" xml:space="preserve">Logs</x:String>
<x:String x:Key="Text.ViewLogs.Clear" xml:space="preserve">CLEAR ALL</x:String>
<x:String x:Key="Text.ViewLogs.CopyLog" xml:space="preserve">Copy</x:String>
<x:String x:Key="Text.ViewLogs.Delete" xml:space="preserve">Delete</x:String>
<x:String x:Key="Text.Warn" xml:space="preserve">Warning</x:String>
<x:String x:Key="Text.Welcome" xml:space="preserve">Welcome Page</x:String>
<x:String x:Key="Text.Welcome.AddRootFolder" xml:space="preserve">Create Group</x:String>
@ -734,6 +744,7 @@
<x:String x:Key="Text.WorkingCopy.IncludeUntracked" xml:space="preserve">INCLUDE UNTRACKED FILES</x:String>
<x:String x:Key="Text.WorkingCopy.NoCommitHistories" xml:space="preserve">NO RECENT INPUT MESSAGES</x:String>
<x:String x:Key="Text.WorkingCopy.NoCommitTemplates" xml:space="preserve">NO COMMIT TEMPLATES</x:String>
<x:String x:Key="Text.WorkingCopy.ResolveTip" xml:space="preserve">Right-click the selected file(s), and make your choice to resolve conflicts.</x:String>
<x:String x:Key="Text.WorkingCopy.SignOff" xml:space="preserve">SignOff</x:String>
<x:String x:Key="Text.WorkingCopy.Staged" xml:space="preserve">STAGED</x:String>
<x:String x:Key="Text.WorkingCopy.Staged.Unstage" xml:space="preserve">UNSTAGE</x:String>
@ -743,7 +754,6 @@
<x:String x:Key="Text.WorkingCopy.Unstaged.StageAll" xml:space="preserve">STAGE ALL</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged.ViewAssumeUnchaged" xml:space="preserve">VIEW ASSUME UNCHANGED</x:String>
<x:String x:Key="Text.WorkingCopy.UseCommitTemplate" xml:space="preserve">Template: ${0}$</x:String>
<x:String x:Key="Text.WorkingCopy.ResolveTip" xml:space="preserve">Right-click the selected file(s), and make your choice to resolve conflicts.</x:String>
<x:String x:Key="Text.Workspace" xml:space="preserve">WORKSPACE: </x:String>
<x:String x:Key="Text.Workspace.Configure" xml:space="preserve">Configure Workspaces...</x:String>
<x:String x:Key="Text.Worktree" xml:space="preserve">WORKTREE</x:String>

View file

@ -103,8 +103,8 @@
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">Cherry-Pick ...</x:String>
<x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">Comparar con HEAD</x:String>
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">Comparar con Worktree</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Copiar Información</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">Copiar SHA</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Información</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">Acción personalizada</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">Rebase Interactivo ${0}$ hasta Aquí</x:String>
<x:String x:Key="Text.CommitCM.Merge" xml:space="preserve">Merge a ${0}$</x:String>
@ -136,6 +136,7 @@
<x:String x:Key="Text.CommitDetail.Info.SHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.CommitDetail.Info.WebLinks" xml:space="preserve">Abrir en Navegador</x:String>
<x:String x:Key="Text.CommitMessageTextBox.MessagePlaceholder" xml:space="preserve">Descripción</x:String>
<x:String x:Key="Text.CommitMessageTextBox.SubjectCount" xml:space="preserve">ASUNTO</x:String>
<x:String x:Key="Text.CommitMessageTextBox.SubjectPlaceholder" xml:space="preserve">Introducir asunto del commit</x:String>
<x:String x:Key="Text.Configure" xml:space="preserve">Configurar Repositorio</x:String>
<x:String x:Key="Text.Configure.CommitMessageTemplate" xml:space="preserve">PLANTILLA DE COMMIT</x:String>
@ -157,6 +158,7 @@
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">Fetch remotos automáticamente</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">Minuto(s)</x:String>
<x:String x:Key="Text.Configure.Git.DefaultRemote" xml:space="preserve">Remoto por Defecto</x:String>
<x:String x:Key="Text.Configure.Git.PreferredMergeMode" xml:space="preserve">Modo preferido de Merge</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">SEGUIMIENTO DE INCIDENCIAS</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleAzure" xml:space="preserve">Añadir Regla de Ejemplo para Azure DevOps</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteeIssue" xml:space="preserve">Añadir Regla de Ejemplo para Incidencias de Gitee</x:String>
@ -179,7 +181,12 @@
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">Nombre de usuario para este repositorio</x:String>
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">Espacios de Trabajo</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">Color</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">Nombre</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">Restaurar pestañas al iniciar</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.Continue" xml:space="preserve">CONTINUAR</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.NoLocalChanges" xml:space="preserve">¡Commit vacío detectado! ¿Quieres continuar (--allow-empty)?</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.StageAllThenCommit" xml:space="preserve">HACER STAGE A TODO &amp; COMMIT</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.WithLocalChanges" xml:space="preserve">¡Commit vacío detectado! ¿Quieres continuar (--allow-empty) o hacer stage a todo y después commit?</x:String>
<x:String x:Key="Text.ConventionalCommit" xml:space="preserve">Asistente de Commit Convencional</x:String>
<x:String x:Key="Text.ConventionalCommit.BreakingChanges" xml:space="preserve">Cambio Importante:</x:String>
<x:String x:Key="Text.ConventionalCommit.ClosedIssue" xml:space="preserve">Incidencia Cerrada:</x:String>
@ -240,7 +247,7 @@
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">Copiar</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">Modo de Archivo Cambiado</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">Primera Diferencia</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignorar Cambio de Espacios en Blanco</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignorar Cambio de Espacios en Blanco y EOL</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">Última Diferencia</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">CAMBIO DE OBJETO LFS</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Siguiente Diferencia</x:String>
@ -445,7 +452,6 @@
<x:String x:Key="Text.Period.YearsAgo" xml:space="preserve">Hace {0} años</x:String>
<x:String x:Key="Text.Period.Yesterday" xml:space="preserve">Ayer</x:String>
<x:String x:Key="Text.Preferences" xml:space="preserve">Preferencias</x:String>
<x:String x:Key="Text.Preferences.Advanced" xml:space="preserve">Opciones Avanzadas</x:String>
<x:String x:Key="Text.Preferences.AI" xml:space="preserve">OPEN AI</x:String>
<x:String x:Key="Text.Preferences.AI.AnalyzeDiffPrompt" xml:space="preserve">Analizar Diff Prompt</x:String>
<x:String x:Key="Text.Preferences.AI.ApiKey" xml:space="preserve">Clave API</x:String>
@ -717,15 +723,20 @@
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.InSameFolder" xml:space="preserve">Ignorar archivos en la misma carpeta</x:String>
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.SingleFile" xml:space="preserve">Ignorar solo este archivo</x:String>
<x:String x:Key="Text.WorkingCopy.Amend" xml:space="preserve">Enmendar</x:String>
<x:String x:Key="Text.WorkingCopy.CanStageTip" xml:space="preserve">Puedes stagear este archivo ahora.</x:String>
<x:String x:Key="Text.WorkingCopy.CanStageTip" xml:space="preserve">Puedes hacer stage a este archivo ahora.</x:String>
<x:String x:Key="Text.WorkingCopy.Commit" xml:space="preserve">COMMIT</x:String>
<x:String x:Key="Text.WorkingCopy.CommitAndPush" xml:space="preserve">COMMIT &amp; PUSH</x:String>
<x:String x:Key="Text.WorkingCopy.CommitMessageHelper" xml:space="preserve">Plantilla/Historias</x:String>
<x:String x:Key="Text.WorkingCopy.CommitTip" xml:space="preserve">Activar evento de clic</x:String>
<x:String x:Key="Text.WorkingCopy.CommitToEdit" xml:space="preserve">Commit (Editar)</x:String>
<x:String x:Key="Text.WorkingCopy.CommitWithAutoStage" xml:space="preserve">Stagear todos los cambios y commit</x:String>
<x:String x:Key="Text.WorkingCopy.CommitWithAutoStage" xml:space="preserve">Hacer stage a todos los cambios y commit</x:String>
<x:String x:Key="Text.WorkingCopy.ConfirmCommitWithFilter">Tienes {0} archivo(s) en stage, pero solo {1} archivo(s) mostrado(s) ({2} archivo(s) están filtrados). ¿Quieres continuar?</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts" xml:space="preserve">CONFLICTOS DETECTADOS</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.OpenExternalMergeTool" xml:space="preserve">ABRIR HERRAMIENTA DE MERGE EXTERNA</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts" xml:space="preserve">ABRIR TODOS LOS CONFLICTOS EN HERRAMIENTA DE MERGE EXTERNA</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.Resolved" xml:space="preserve">LOS CONFLICTOS DE ARCHIVOS ESTÁN RESUELTOS</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.UseMine" xml:space="preserve">USAR MÍOS</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.UseTheirs" xml:space="preserve">USAR SUYOS</x:String>
<x:String x:Key="Text.WorkingCopy.IncludeUntracked" xml:space="preserve">INCLUIR ARCHIVOS NO RASTREADOS</x:String>
<x:String x:Key="Text.WorkingCopy.NoCommitHistories" xml:space="preserve">NO HAY MENSAJES DE ENTRADA RECIENTES</x:String>
<x:String x:Key="Text.WorkingCopy.NoCommitTemplates" xml:space="preserve">NO HAY PLANTILLAS DE COMMIT</x:String>

View file

@ -86,7 +86,6 @@
<x:String x:Key="Text.CherryPick.CommitChanges" xml:space="preserve">Commit tous les changements</x:String>
<x:String x:Key="Text.CherryPick.Mainline" xml:space="preserve">Ligne principale :</x:String>
<x:String x:Key="Text.CherryPick.Mainline.Tips" xml:space="preserve">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é.</x:String>
<x:String x:Key="Text.CherryPick.Title" xml:space="preserve">Cherry Pick</x:String>
<x:String x:Key="Text.ClearStashes" xml:space="preserve">Supprimer les stashes</x:String>
<x:String x:Key="Text.ClearStashes.Message" xml:space="preserve">Vous essayez de supprimer tous les stashes. Êtes-vous sûr de vouloir continuer ?</x:String>
<x:String x:Key="Text.Clone" xml:space="preserve">Cloner repository distant</x:String>
@ -104,8 +103,8 @@
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">Cherry-Pick ...</x:String>
<x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">Comparer avec HEAD</x:String>
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">Comparer avec le worktree</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Copier les informations</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">Copier le SHA</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Informations</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">Action personnalisée</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">Rebase interactif de ${0}$ ici</x:String>
<x:String x:Key="Text.CommitCM.Merge" xml:space="preserve">Fusionner dans ${0}$</x:String>
@ -180,6 +179,7 @@
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">Nom d'utilisateur pour ce dépôt</x:String>
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">Espaces de travail</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">Couleur</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">Nom</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">Restaurer les onglets au démarrage</x:String>
<x:String x:Key="Text.ConventionalCommit" xml:space="preserve">Assistant Commits Conventionnels</x:String>
<x:String x:Key="Text.ConventionalCommit.BreakingChanges" xml:space="preserve">Changement Radical :</x:String>
@ -241,7 +241,7 @@
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">Copier</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">Mode de fichier changé</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">Première différence</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignorer les changements d'espaces</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignorer les changements d'espaces et EOL</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">Dernière différence</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">CHANGEMENT D'OBJET LFS</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Différence suivante</x:String>
@ -456,8 +456,6 @@
<x:String x:Key="Text.Preferences.AI.Streaming" xml:space="preserve">Activer le streaming</x:String>
<x:String x:Key="Text.Preferences.Appearance" xml:space="preserve">APPARENCE</x:String>
<x:String x:Key="Text.Preferences.Appearance.DefaultFont" xml:space="preserve">Police par défaut</x:String>
<x:String x:Key="Text.Preferences.Appearance.DefaultFontSize" xml:space="preserve">Taille de police par défaut</x:String>
<x:String x:Key="Text.Preferences.Appearance.EditorFontSize" xml:space="preserve">Taille de police de l'éditeur</x:String>
<x:String x:Key="Text.Preferences.Appearance.EditorTabWidth" xml:space="preserve">Largeur de tab dans l'éditeur</x:String>
<x:String x:Key="Text.Preferences.Appearance.FontSize" xml:space="preserve">Taille de police</x:String>
<x:String x:Key="Text.Preferences.Appearance.FontSize.Default" xml:space="preserve">Défaut</x:String>

View file

@ -103,8 +103,8 @@
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">Cherry-Pick...</x:String>
<x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">Confronta con HEAD</x:String>
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">Confronta con Worktree</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Copia Info</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">Copia SHA</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Informazioni</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">Azione Personalizzata</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">Riallinea Interattivamente ${0}$ fino a Qui</x:String>
<x:String x:Key="Text.CommitCM.Merge" xml:space="preserve">Unisci a ${0}$</x:String>
@ -179,6 +179,7 @@
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">Nome utente per questo repository</x:String>
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">Spazi di Lavoro</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">Colore</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">Nome</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">Ripristina schede all'avvio</x:String>
<x:String x:Key="Text.ConventionalCommit" xml:space="preserve">Guida Commit Convenzionali</x:String>
<x:String x:Key="Text.ConventionalCommit.BreakingChanges" xml:space="preserve">Modifica Sostanziale:</x:String>
@ -239,7 +240,7 @@
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">Copia</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">Modalità File Modificata</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">Prima differenza</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignora Modifiche agli Spazi</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignora Modifiche agli Spazi e EOL</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">Ultima differenza</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">MODIFICA OGGETTO LFS</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Differenza Successiva</x:String>
@ -300,7 +301,6 @@
<x:String x:Key="Text.FileHistory" xml:space="preserve">Cronologia File</x:String>
<x:String x:Key="Text.FileHistory.FileChange" xml:space="preserve">MODIFICA</x:String>
<x:String x:Key="Text.FileHistory.FileContent" xml:space="preserve">CONTENUTO</x:String>
<x:String x:Key="Text.Filter" xml:space="preserve">FILTRO</x:String>
<x:String x:Key="Text.GitFlow" xml:space="preserve">Git-Flow</x:String>
<x:String x:Key="Text.GitFlow.DevelopBranch" xml:space="preserve">Branch di Sviluppo:</x:String>
<x:String x:Key="Text.GitFlow.Feature" xml:space="preserve">Feature:</x:String>
@ -566,7 +566,6 @@
<x:String x:Key="Text.Repository.EnableReflog" xml:space="preserve">Abilita opzione '--reflog'</x:String>
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">Apri nell'Esplora File</x:String>
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">Cerca Branch/Tag/Sottomodulo</x:String>
<x:String x:Key="Text.Repository.FilterCommitPrefix" xml:space="preserve">FILTRATO DA:</x:String>
<x:String x:Key="Text.Repository.FilterCommits" xml:space="preserve">Visibilità nel grafico</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Default" xml:space="preserve">Non impostato</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Exclude" xml:space="preserve">Nascondi nel grafico dei commit</x:String>

View file

@ -103,8 +103,8 @@
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">チェリーピック...</x:String>
<x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">HEADと比較</x:String>
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">ワークツリーと比較</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">情報をコピー</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">SHAをコピー</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">情報</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">カスタムアクション</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">${0}$ ブランチをここにインタラクティブリベース</x:String>
<x:String x:Key="Text.CommitCM.Merge" xml:space="preserve">${0}$ にマージ</x:String>
@ -179,6 +179,7 @@
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">このリポジトリにおけるユーザー名</x:String>
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">ワークスペース</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">色</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">名前</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">起動時にタブを復元</x:String>
<x:String x:Key="Text.ConventionalCommit" xml:space="preserve">Conventional Commitヘルパー</x:String>
<x:String x:Key="Text.ConventionalCommit.BreakingChanges" xml:space="preserve">破壊的変更:</x:String>
@ -240,7 +241,7 @@
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">コピー</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">ファイルモードが変更されました</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">先頭の差分</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">空白の変更を無視</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">空白の変更とEOLを無視</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">最後の差分</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">LFSオブジェクトの変更</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">次の差分</x:String>
@ -604,7 +605,6 @@
<x:String x:Key="Text.Repository.Tags.Add" xml:space="preserve">新しいタグを作成</x:String>
<x:String x:Key="Text.Repository.Tags.OrderByCreatorDate" xml:space="preserve">作成者日時</x:String>
<x:String x:Key="Text.Repository.Tags.OrderByNameAsc" xml:space="preserve">名前 (昇順)</x:String>
<x:String x:Key="Text.Repository.Tags.OrderByNameDesc" xml:space="preserve">名前 (降順)</x:String>
<x:String x:Key="Text.Repository.Tags.Sort" xml:space="preserve">ソート</x:String>
<x:String x:Key="Text.Repository.Terminal" xml:space="preserve">ターミナルで開く</x:String>
<x:String x:Key="Text.Repository.UseRelativeTimeInHistories" xml:space="preserve">履歴に相対時間を使用</x:String>

View file

@ -93,8 +93,8 @@
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">Cherry-Pick ...</x:String>
<x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">Comparar com HEAD</x:String>
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">Comparar com Worktree</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Copiar Informações</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">Copiar SHA</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Informações</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">Ação customizada</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">Rebase Interativo ${0}$ até Aqui</x:String>
<x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">Rebase ${0}$ até Aqui</x:String>
@ -161,6 +161,7 @@
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">Nome de usuário para este repositório</x:String>
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">Workspaces</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">Cor</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">Nome</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">Restaurar abas ao inicializar</x:String>
<x:String x:Key="Text.ConventionalCommit" xml:space="preserve">Assistente de Conventional Commit</x:String>
<x:String x:Key="Text.ConventionalCommit.BreakingChanges" xml:space="preserve">Breaking Change:</x:String>
@ -216,7 +217,7 @@
<x:String x:Key="Text.Diff.Binary.Old" xml:space="preserve">ANTIGO</x:String>
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">Copiar</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">Modo de Arquivo Alterado</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignorar mudanças de espaço em branco</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ignorar mudanças de espaço em branco e EOL</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">MUDANÇA DE OBJETO LFS</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Próxima Diferença</x:String>
<x:String x:Key="Text.Diff.NoChange" xml:space="preserve">SEM MUDANÇAS OU APENAS MUDANÇAS DE EOL</x:String>

View file

@ -103,8 +103,8 @@
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">Применить несколько ревизий ...</x:String>
<x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">Сравнить c ГОЛОВОЙ (HEAD)</x:String>
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">Сравнить с рабочим каталогом</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Копировать информацию</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">Копировать SHA</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Информацию</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">Пользовательское действие</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">Интерактивное перемещение (rebase -i) ${0}$ сюда</x:String>
<x:String x:Key="Text.CommitCM.Merge" xml:space="preserve">Влить в ${0}$</x:String>
@ -210,7 +210,7 @@
<x:String x:Key="Text.CreateTag" xml:space="preserve">Создать метку...</x:String>
<x:String x:Key="Text.CreateTag.BasedOn" xml:space="preserve">Новая метка у:</x:String>
<x:String x:Key="Text.CreateTag.GPGSign" xml:space="preserve">GPG подпись</x:String>
<x:String x:Key="Text.CreateTag.Message" xml:space="preserve">Сообщение с&#13;меткой:</x:String>
<x:String x:Key="Text.CreateTag.Message" xml:space="preserve">Сообщение с&#xD;меткой:</x:String>
<x:String x:Key="Text.CreateTag.Message.Placeholder" xml:space="preserve">Необязательно.</x:String>
<x:String x:Key="Text.CreateTag.Name" xml:space="preserve">Имя метки:</x:String>
<x:String x:Key="Text.CreateTag.Name.Placeholder" xml:space="preserve">Рекомендуемый формат: v1.0.0-alpha</x:String>
@ -246,7 +246,7 @@
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">Копировать</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">Режим файла изменён</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">Первое различие</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Игнорировать изменение пробелов</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Игнорировать изменение пробелов и EOL</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">Последнее различие</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">ИЗМЕНЕНИЕ ОБЪЕКТА LFS</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Следующее различие</x:String>
@ -577,7 +577,6 @@
<x:String x:Key="Text.Repository.FilterCommits.Default" xml:space="preserve">Не установлен (по умолчанию)</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Exclude" xml:space="preserve">Скрыть в графе ревизии</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Include" xml:space="preserve">Фильтр в графе ревизии</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Prefix" xml:space="preserve">ОТФИЛЬТРОВАНО:</x:String>
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">Включить опцию (--first-parent)</x:String>
<x:String x:Key="Text.Repository.HistoriesLayout" xml:space="preserve">РАСПОЛОЖЕНИЕ</x:String>
<x:String x:Key="Text.Repository.HistoriesLayout.Horizontal" xml:space="preserve">Горизонтально</x:String>

View file

@ -103,8 +103,8 @@
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">கனி-பறி ...</x:String>
<x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">தலையுடன் ஒப்பிடுக</x:String>
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">பணிமரத்துடன் ஒப்பிடுக</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">தகவலை நகலெடு</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">பாகொவ-வை நகலெடு</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">தகவலை</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">பாகொவ-வை</x:String>
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">தனிப்பயன் செயல்</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">இங்கே ${0}$ ஐ ஊடாடும் வகையில் மறுதளம்</x:String>
<x:String x:Key="Text.CommitCM.Merge" xml:space="preserve">${0}$ இதற்கு ஒன்றிணை</x:String>
@ -179,6 +179,7 @@
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">இந்த களஞ்சியத்திற்கான பயனர் பெயர்</x:String>
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">பணியிடங்கள்</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">நிறம்</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">பெயர்</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">தாவல்களை மீட்டமை</x:String>
<x:String x:Key="Text.ConventionalCommit" xml:space="preserve">வழக்கமான உறுதிமொழி உதவியாளர்</x:String>
<x:String x:Key="Text.ConventionalCommit.BreakingChanges" xml:space="preserve">உடைக்கும் மாற்றம்:</x:String>
@ -240,7 +241,7 @@
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">நகல்</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">கோப்பு முறை மாற்றப்பட்டது</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">முதல் வேறுபாடு</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">வெள்ளைவெளி மாற்றத்தை புறக்கணி</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">வெள்ளைவெளி மாற்றத்தை மற்றும் EOL புறக்கணி</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">கடைசி வேறுபாடு</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">பெகோஅ பொருள் மாற்றம்</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">அடுத்த வேறுபாடு</x:String>
@ -465,8 +466,8 @@
<x:String x:Key="Text.Preferences.Appearance.ThemeOverrides" xml:space="preserve">கருப்பொருள் மேலெழுதப்படுகிறது</x:String>
<x:String x:Key="Text.Preferences.Appearance.UseFixedTabWidth" xml:space="preserve">தலைப்புப்பட்டியில் நிலையான தாவல் அகலத்தைப் பயன்படுத்து</x:String>
<x:String x:Key="Text.Preferences.Appearance.UseNativeWindowFrame" xml:space="preserve">சொந்த சாளர சட்டத்தைப் பயன்படுத்து</x:String>
<x:String x:Key="Text.Preferences.DiffMerge.Path" xml:space="preserve">நிறுவல் பாதை</x:String>
<x:String x:Key="Text.Preferences.DiffMerge" xml:space="preserve">வேறு/ஒன்றிணை கருவி</x:String>
<x:String x:Key="Text.Preferences.DiffMerge.Path" xml:space="preserve">நிறுவல் பாதை</x:String>
<x:String x:Key="Text.Preferences.DiffMerge.Path.Placeholder" xml:space="preserve">வேறு/ஒன்றிணை கருவிக்கான பாதை உள்ளிடு</x:String>
<x:String x:Key="Text.Preferences.DiffMerge.Type" xml:space="preserve">கருவி</x:String>
<x:String x:Key="Text.Preferences.General" xml:space="preserve">பொது</x:String>
@ -723,7 +724,6 @@
<x:String x:Key="Text.WorkingCopy.CommitToEdit" xml:space="preserve">உறுதிமொழி (திருத்து)</x:String>
<x:String x:Key="Text.WorkingCopy.CommitWithAutoStage" xml:space="preserve">அனைத்து மாற்றங்களையும் நிலைப்படுத்தி உறுதிமொழி</x:String>
<x:String x:Key="Text.WorkingCopy.ConfirmCommitWithFilter">நீங்கள் {0} கோப்புகளை நிலைப்படுத்தியுள்ளீர்கள், ஆனால் {1} கோப்புகள் மட்டுமே காட்டப்பட்டுள்ளன ({2} கோப்புகள் வடிகட்டப்பட்டுள்ளன). தொடர விரும்புகிறீர்களா?</x:String>
<x:String x:Key="Text.WorkingCopy.ConfirmCommitWithoutFiles" xml:space="preserve">காலி உறுதிமொழி கண்டறியப்பட்டது! தொடர விரும்புகிறீர்களா(--allow-empty)?</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts" xml:space="preserve">மோதல்கள் கண்டறியப்பட்டது</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.Resolved" xml:space="preserve">கோப்பு மோதல்கள் தீர்க்கப்பட்டது</x:String>
<x:String x:Key="Text.WorkingCopy.IncludeUntracked" xml:space="preserve">கண்காணிக்கப்படாத கோப்புகளைச் சேர்</x:String>

View file

@ -0,0 +1,758 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceInclude Source="avares://SourceGit/Resources/Locales/en_US.axaml"/>
</ResourceDictionary.MergedDictionaries>
<x:String x:Key="Text.About" xml:space="preserve">Про програму</x:String>
<x:String x:Key="Text.About.Menu" xml:space="preserve">Про SourceGit</x:String>
<x:String x:Key="Text.About.SubTitle" xml:space="preserve">Безкоштовний Git GUI клієнт з відкритим кодом</x:String>
<x:String x:Key="Text.AddWorktree" xml:space="preserve">Додати робоче дерево</x:String>
<x:String x:Key="Text.AddWorktree.Location" xml:space="preserve">Розташування:</x:String>
<x:String x:Key="Text.AddWorktree.Location.Placeholder" xml:space="preserve">Шлях для цього робочого дерева. Відносний шлях підтримується.</x:String>
<x:String x:Key="Text.AddWorktree.Name" xml:space="preserve">Назва гілки:</x:String>
<x:String x:Key="Text.AddWorktree.Name.Placeholder" xml:space="preserve">Необов'язково. За замовчуванням — назва кінцевої папки.</x:String>
<x:String x:Key="Text.AddWorktree.Tracking" xml:space="preserve">Відстежувати гілку:</x:String>
<x:String x:Key="Text.AddWorktree.Tracking.Toggle" xml:space="preserve">Відстежувати віддалену гілку</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout" xml:space="preserve">Що перемкнути:</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.CreateNew" xml:space="preserve">Створити нову гілку</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.Existing" xml:space="preserve">Наявна гілка</x:String>
<x:String x:Key="Text.AIAssistant" xml:space="preserve">AI Асистент</x:String>
<x:String x:Key="Text.AIAssistant.Regen" xml:space="preserve">ПЕРЕГЕНЕРУВАТИ</x:String>
<x:String x:Key="Text.AIAssistant.Tip" xml:space="preserve">Використати AI для генерації повідомлення коміту</x:String>
<x:String x:Key="Text.AIAssistant.Use" xml:space="preserve">ЗАСТОСУВАТИ ЯК ПОВІДОМЛЕННЯ КОМІТУ</x:String>
<x:String x:Key="Text.Apply" xml:space="preserve">Застосувати</x:String>
<x:String x:Key="Text.Apply.File" xml:space="preserve">Файл патчу:</x:String>
<x:String x:Key="Text.Apply.File.Placeholder" xml:space="preserve">Виберіть файл .patch для застосування</x:String>
<x:String x:Key="Text.Apply.IgnoreWS" xml:space="preserve">Ігнорувати зміни пробілів</x:String>
<x:String x:Key="Text.Apply.Title" xml:space="preserve">Застосувати Патч</x:String>
<x:String x:Key="Text.Apply.WS" xml:space="preserve">Пробіли:</x:String>
<x:String x:Key="Text.ApplyStash" xml:space="preserve">Застосувати схованку</x:String>
<x:String x:Key="Text.ApplyStash.DropAfterApply" xml:space="preserve">Видалити після застосування</x:String>
<x:String x:Key="Text.ApplyStash.RestoreIndex" xml:space="preserve">Відновити зміни індексу</x:String>
<x:String x:Key="Text.ApplyStash.Stash" xml:space="preserve">Схованка:</x:String>
<x:String x:Key="Text.Archive" xml:space="preserve">Архівувати...</x:String>
<x:String x:Key="Text.Archive.File" xml:space="preserve">Зберегти архів у:</x:String>
<x:String x:Key="Text.Archive.File.Placeholder" xml:space="preserve">Виберіть шлях до файлу архіву</x:String>
<x:String x:Key="Text.Archive.Revision" xml:space="preserve">Ревізія:</x:String>
<x:String x:Key="Text.Archive.Title" xml:space="preserve">Архівувати</x:String>
<x:String x:Key="Text.Askpass" xml:space="preserve">SourceGit Askpass</x:String>
<x:String x:Key="Text.AssumeUnchanged" xml:space="preserve">ФАЙЛИ, ЩО ВВАЖАЮТЬСЯ НЕЗМІНЕНИМИ</x:String>
<x:String x:Key="Text.AssumeUnchanged.Empty" xml:space="preserve">НЕМАЄ ФАЙЛІВ, ЩО ВВАЖАЮТЬСЯ НЕЗМІНЕНИМИ</x:String>
<x:String x:Key="Text.AssumeUnchanged.Remove" xml:space="preserve">ВИДАЛИТИ</x:String>
<x:String x:Key="Text.BinaryNotSupported" xml:space="preserve">БІНАРНИЙ ФАЙЛ НЕ ПІДТРИМУЄТЬСЯ!!!</x:String>
<x:String x:Key="Text.Blame" xml:space="preserve">Автор рядка</x:String>
<x:String x:Key="Text.BlameTypeNotSupported" xml:space="preserve">ПОШУК АВТОРА РЯДКА ДЛЯ ЦЬОГО ФАЙЛУ НЕ ПІДТРИМУЄТЬСЯ!!!</x:String>
<x:String x:Key="Text.BranchCM.Checkout" xml:space="preserve">Перейти на ${0}$...</x:String>
<x:String x:Key="Text.BranchCM.CompareWithHead" xml:space="preserve">Порівняти з HEAD</x:String>
<x:String x:Key="Text.BranchCM.CompareWithWorktree" xml:space="preserve">Порівняти з робочим деревом</x:String>
<x:String x:Key="Text.BranchCM.CopyName" xml:space="preserve">Копіювати назву гілки</x:String>
<x:String x:Key="Text.BranchCM.CustomAction" xml:space="preserve">Спеціальна дія</x:String>
<x:String x:Key="Text.BranchCM.Delete" xml:space="preserve">Видалити ${0}$...</x:String>
<x:String x:Key="Text.BranchCM.DeleteMultiBranches" xml:space="preserve">Видалити вибрані {0} гілок</x:String>
<x:String x:Key="Text.BranchCM.DiscardAll" xml:space="preserve">Скасувати всі зміни</x:String>
<x:String x:Key="Text.BranchCM.FastForward" xml:space="preserve">Перемотати до ${0}$</x:String>
<x:String x:Key="Text.BranchCM.FetchInto" xml:space="preserve">Отримати ${0}$ в ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.Finish" xml:space="preserve">Git Flow - Завершити ${0}$</x:String>
<x:String x:Key="Text.BranchCM.Merge" xml:space="preserve">Злиття ${0}$ в ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.MergeMultiBranches" xml:space="preserve">Злити вибрані {0} гілок в поточну</x:String>
<x:String x:Key="Text.BranchCM.Pull" xml:space="preserve">Витягти ${0}$</x:String>
<x:String x:Key="Text.BranchCM.PullInto" xml:space="preserve">Витягти ${0}$ в ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.Push" xml:space="preserve">Надіслати ${0}$</x:String>
<x:String x:Key="Text.BranchCM.Rebase" xml:space="preserve">Перебазувати ${0}$ на ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.Rename" xml:space="preserve">Перейменувати ${0}$...</x:String>
<x:String x:Key="Text.BranchCM.Tracking" xml:space="preserve">Встановити відстежувану гілку...</x:String>
<x:String x:Key="Text.BranchCompare" xml:space="preserve">Порівняти гілки</x:String>
<x:String x:Key="Text.BranchUpstreamInvalid" xml:space="preserve">Недійсний upstream!</x:String>
<x:String x:Key="Text.Bytes" xml:space="preserve">Байтів</x:String>
<x:String x:Key="Text.Cancel" xml:space="preserve">СКАСУВАТИ</x:String>
<x:String x:Key="Text.ChangeCM.CheckoutFirstParentRevision" xml:space="preserve">Скинути до батьківської ревізії</x:String>
<x:String x:Key="Text.ChangeCM.CheckoutThisRevision" xml:space="preserve">Скинути до цієї ревізії</x:String>
<x:String x:Key="Text.ChangeCM.GenerateCommitMessage" xml:space="preserve">Згенерувати повідомлення коміту</x:String>
<x:String x:Key="Text.ChangeDisplayMode" xml:space="preserve">ЗМІНИТИ РЕЖИМ ВІДОБРАЖЕННЯ</x:String>
<x:String x:Key="Text.ChangeDisplayMode.Grid" xml:space="preserve">Показати як список файлів та тек</x:String>
<x:String x:Key="Text.ChangeDisplayMode.List" xml:space="preserve">Показати як список шляхів</x:String>
<x:String x:Key="Text.ChangeDisplayMode.Tree" xml:space="preserve">Показати як дерево файлової системи</x:String>
<x:String x:Key="Text.Checkout" xml:space="preserve">Перейти на гілку</x:String>
<x:String x:Key="Text.Checkout.Commit" xml:space="preserve">Перейти на коміт</x:String>
<x:String x:Key="Text.Checkout.Commit.Target" xml:space="preserve">Коміт:</x:String>
<x:String x:Key="Text.Checkout.Commit.Warning" xml:space="preserve">Попередження: Перехід на коміт призведе до стану "від'єднаний HEAD"</x:String>
<x:String x:Key="Text.Checkout.LocalChanges" xml:space="preserve">Локальні зміни:</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.Discard" xml:space="preserve">Скасувати</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Сховати та Застосувати</x:String>
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">Гілка:</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">Cherry-pick</x:String>
<x:String x:Key="Text.CherryPick.AppendSourceToMessage" xml:space="preserve">Додати джерело до повідомлення коміту</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Коміт(и):</x:String>
<x:String x:Key="Text.CherryPick.CommitChanges" xml:space="preserve">Закомітити всі зміни</x:String>
<x:String x:Key="Text.CherryPick.Mainline" xml:space="preserve">Батьківський коміт:</x:String>
<x:String x:Key="Text.CherryPick.Mainline.Tips" xml:space="preserve">Зазвичай неможливо cherry-pick злиття, бо невідомо, яку сторону злиття вважати батьківською (mainline). Ця опція дозволяє відтворити зміни відносно вказаного батьківського коміту.</x:String>
<x:String x:Key="Text.ClearStashes" xml:space="preserve">Очистити схованки</x:String>
<x:String x:Key="Text.ClearStashes.Message" xml:space="preserve">Ви намагаєтеся очистити всі схованки. Ви впевнені?</x:String>
<x:String x:Key="Text.Clone" xml:space="preserve">Клонувати віддалене сховище</x:String>
<x:String x:Key="Text.Clone.AdditionalParam" xml:space="preserve">Додаткові параметри:</x:String>
<x:String x:Key="Text.Clone.AdditionalParam.Placeholder" xml:space="preserve">Додаткові аргументи для клонування сховища. Необов'язково.</x:String>
<x:String x:Key="Text.Clone.LocalName" xml:space="preserve">Локальна назва:</x:String>
<x:String x:Key="Text.Clone.LocalName.Placeholder" xml:space="preserve">Назва сховища. Необов'язково.</x:String>
<x:String x:Key="Text.Clone.ParentFolder" xml:space="preserve">Батьківська тека:</x:String>
<x:String x:Key="Text.Clone.RecurseSubmodules" xml:space="preserve">Ініціалізувати та оновити підмодулі</x:String>
<x:String x:Key="Text.Clone.RemoteURL" xml:space="preserve">URL сховища:</x:String>
<x:String x:Key="Text.Close" xml:space="preserve">ЗАКРИТИ</x:String>
<x:String x:Key="Text.CodeEditor" xml:space="preserve">Редактор</x:String>
<x:String x:Key="Text.CommitCM.Checkout" xml:space="preserve">Перейти на коміт</x:String>
<x:String x:Key="Text.CommitCM.CherryPick" xml:space="preserve">Cherry-pick коміт</x:String>
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">Cherry-pick ...</x:String>
<x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">Порівняти з HEAD</x:String>
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">Порівняти з робочим деревом</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Iнформацію</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">Спеціальна дія</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">Інтерактивно перебазувати ${0}$ сюди</x:String>
<x:String x:Key="Text.CommitCM.Merge" xml:space="preserve">Злиття в ${0}$</x:String>
<x:String x:Key="Text.CommitCM.MergeMultiple" xml:space="preserve">Злити ...</x:String>
<x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">Перебазувати ${0}$ сюди</x:String>
<x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">Скинути ${0}$ сюди</x:String>
<x:String x:Key="Text.CommitCM.Revert" xml:space="preserve">Скасувати коміт</x:String>
<x:String x:Key="Text.CommitCM.Reword" xml:space="preserve">Змінити повідомлення</x:String>
<x:String x:Key="Text.CommitCM.SaveAsPatch" xml:space="preserve">Зберегти як патч...</x:String>
<x:String x:Key="Text.CommitCM.Squash" xml:space="preserve">Склеїти з батьківським комітом</x:String>
<x:String x:Key="Text.CommitCM.SquashCommitsSinceThis" xml:space="preserve">Склеїти дочірні коміти сюди</x:String>
<x:String x:Key="Text.CommitDetail.Changes" xml:space="preserve">ЗМІНИ</x:String>
<x:String x:Key="Text.CommitDetail.Changes.Search" xml:space="preserve">Пошук змін...</x:String>
<x:String x:Key="Text.CommitDetail.Files" xml:space="preserve">ФАЙЛИ</x:String>
<x:String x:Key="Text.CommitDetail.Files.LFS" xml:space="preserve">LFS Файл</x:String>
<x:String x:Key="Text.CommitDetail.Files.Search" xml:space="preserve">Пошук файлів...</x:String>
<x:String x:Key="Text.CommitDetail.Files.Submodule" xml:space="preserve">Підмодуль</x:String>
<x:String x:Key="Text.CommitDetail.Info" xml:space="preserve">ІНФОРМАЦІЯ</x:String>
<x:String x:Key="Text.CommitDetail.Info.Author" xml:space="preserve">АВТОР</x:String>
<x:String x:Key="Text.CommitDetail.Info.Changed" xml:space="preserve">ЗМІНЕНО</x:String>
<x:String x:Key="Text.CommitDetail.Info.Children" xml:space="preserve">ДОЧІРНІ</x:String>
<x:String x:Key="Text.CommitDetail.Info.Committer" xml:space="preserve">КОМІТЕР</x:String>
<x:String x:Key="Text.CommitDetail.Info.ContainsIn" xml:space="preserve">Перевірити посилання, що містять цей коміт</x:String>
<x:String x:Key="Text.CommitDetail.Info.ContainsIn.Title" xml:space="preserve">КОМІТ МІСТИТЬСЯ В</x:String>
<x:String x:Key="Text.CommitDetail.Info.GotoChangesPage" xml:space="preserve">Показано лише перші 100 змін. Дивіться всі зміни на вкладці ЗМІНИ.</x:String>
<x:String x:Key="Text.CommitDetail.Info.Message" xml:space="preserve">ПОВІДОМЛЕННЯ</x:String>
<x:String x:Key="Text.CommitDetail.Info.Parents" xml:space="preserve">БАТЬКІВСЬКІ</x:String>
<x:String x:Key="Text.CommitDetail.Info.Refs" xml:space="preserve">ПОСИЛАННЯ (Refs)</x:String>
<x:String x:Key="Text.CommitDetail.Info.SHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.CommitDetail.Info.WebLinks" xml:space="preserve">Відкрити в браузері</x:String>
<x:String x:Key="Text.CommitMessageTextBox.MessagePlaceholder" xml:space="preserve">Опис</x:String>
<x:String x:Key="Text.CommitMessageTextBox.SubjectPlaceholder" xml:space="preserve">Введіть тему коміту</x:String>
<x:String x:Key="Text.Configure" xml:space="preserve">Налаштування сховища</x:String>
<x:String x:Key="Text.Configure.CommitMessageTemplate" xml:space="preserve">ШАБЛОН КОМІТУ</x:String>
<x:String x:Key="Text.Configure.CommitMessageTemplate.Content" xml:space="preserve">Зміст шаблону:</x:String>
<x:String x:Key="Text.Configure.CommitMessageTemplate.Name" xml:space="preserve">Назва шаблону:</x:String>
<x:String x:Key="Text.Configure.CustomAction" xml:space="preserve">СПЕЦІАЛЬНА ДІЯ</x:String>
<x:String x:Key="Text.Configure.CustomAction.Arguments" xml:space="preserve">Аргументи:</x:String>
<x:String x:Key="Text.Configure.CustomAction.Arguments.Tip" xml:space="preserve">${REPO} - Шлях до сховища; ${BRANCH} - Вибрана гілка; ${SHA} - SHA вибраного коміту</x:String>
<x:String x:Key="Text.Configure.CustomAction.Executable" xml:space="preserve">Виконуваний файл:</x:String>
<x:String x:Key="Text.Configure.CustomAction.Name" xml:space="preserve">Назва:</x:String>
<x:String x:Key="Text.Configure.CustomAction.Scope" xml:space="preserve">Область застосування:</x:String>
<x:String x:Key="Text.Configure.CustomAction.Scope.Branch" xml:space="preserve">Гілка</x:String>
<x:String x:Key="Text.Configure.CustomAction.Scope.Commit" xml:space="preserve">Коміт</x:String>
<x:String x:Key="Text.Configure.CustomAction.Scope.Repository" xml:space="preserve">Репозиторій</x:String>
<x:String x:Key="Text.Configure.CustomAction.WaitForExit" xml:space="preserve">Чекати завершення дії</x:String>
<x:String x:Key="Text.Configure.Email" xml:space="preserve">Адреса Email</x:String>
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Адреса електронної пошти</x:String>
<x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">Автоматично отримувати зміни з віддалених сховищ</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">хвилин(и)</x:String>
<x:String x:Key="Text.Configure.Git.DefaultRemote" xml:space="preserve">Віддалене сховище за замовчуванням</x:String>
<x:String x:Key="Text.Configure.Git.PreferredMergeMode" xml:space="preserve">Бажаний режим злиття</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ТРЕКЕР ЗАВДАНЬ</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleAzure" xml:space="preserve">Додати приклад правила для Azure DevOps</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteeIssue" xml:space="preserve">Додати приклад правила для Gitee Issue</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteePullRequest" xml:space="preserve">Додати приклад правила для Gitee Pull Request</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Додати приклад правила для Github</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGitLabIssue" xml:space="preserve">Додати приклад правила для GitLab Issue</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGitLabMergeRequest" xml:space="preserve">Додати приклад правила для GitLab Merge Request</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Додати приклад правила для Jira</x:String>
<x:String x:Key="Text.Configure.IssueTracker.NewRule" xml:space="preserve">Нове правило</x:String>
<x:String x:Key="Text.Configure.IssueTracker.Regex" xml:space="preserve">Регулярний вираз для завдання:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">Назва правила:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">URL результату:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">Використовуйте $1, $2 для доступу до значень груп регулярного виразу.</x:String>
<x:String x:Key="Text.Configure.OpenAI" xml:space="preserve">AI</x:String>
<x:String x:Key="Text.Configure.OpenAI.Preferred" xml:space="preserve">Бажаний сервіс:</x:String>
<x:String x:Key="Text.Configure.OpenAI.Preferred.Tip" xml:space="preserve">Якщо 'Бажаний сервіс' встановлено, SourceGit буде використовувати лише його у цьому сховищі. Інакше, якщо доступно більше одного сервісу, буде показано контекстне меню для вибору.</x:String>
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP Проксі</x:String>
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP проксі, що використовується цим сховищем</x:String>
<x:String x:Key="Text.Configure.User" xml:space="preserve">Ім'я користувача</x:String>
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">Ім'я користувача для цього сховища</x:String>
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">Робочі простори</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">Колір</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">Відновлювати вкладки при запуску</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.Continue" xml:space="preserve">ПРОДОВЖИТИ</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.NoLocalChanges" xml:space="preserve">Виявлено порожній коміт! Продовжити (--allow-empty)?</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.StageAllThenCommit" xml:space="preserve">ІНДЕКСУВАТИ ВСЕ ТА ЗАКОМІТИТИ</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.WithLocalChanges" xml:space="preserve">Виявлено порожній коміт! Продовжити (--allow-empty) чи індексувати все та закомітити?</x:String>
<x:String x:Key="Text.ConventionalCommit" xml:space="preserve">Допомога Conventional Commit</x:String>
<x:String x:Key="Text.ConventionalCommit.BreakingChanges" xml:space="preserve">Зворотньо несумісні зміни:</x:String>
<x:String x:Key="Text.ConventionalCommit.ClosedIssue" xml:space="preserve">Закрите завдання:</x:String>
<x:String x:Key="Text.ConventionalCommit.Detail" xml:space="preserve">Детальні зміни:</x:String>
<x:String x:Key="Text.ConventionalCommit.Scope" xml:space="preserve">Область застосування:</x:String>
<x:String x:Key="Text.ConventionalCommit.ShortDescription" xml:space="preserve">Короткий опис:</x:String>
<x:String x:Key="Text.ConventionalCommit.Type" xml:space="preserve">Тип зміни:</x:String>
<x:String x:Key="Text.Copy" xml:space="preserve">Копіювати</x:String>
<x:String x:Key="Text.CopyAllText" xml:space="preserve">Копіювати весь текст</x:String>
<x:String x:Key="Text.CopyFullPath" xml:space="preserve">Копіювати повний шлях</x:String>
<x:String x:Key="Text.CopyPath" xml:space="preserve">Копіювати шлях</x:String>
<x:String x:Key="Text.CreateBranch" xml:space="preserve">Створити гілку...</x:String>
<x:String x:Key="Text.CreateBranch.BasedOn" xml:space="preserve">На основі:</x:String>
<x:String x:Key="Text.CreateBranch.Checkout" xml:space="preserve">Перейти на створену гілку</x:String>
<x:String x:Key="Text.CreateBranch.LocalChanges" xml:space="preserve">Локальні зміни:</x:String>
<x:String x:Key="Text.CreateBranch.LocalChanges.Discard" xml:space="preserve">Скасувати</x:String>
<x:String x:Key="Text.CreateBranch.LocalChanges.StashAndReply" xml:space="preserve">Сховати та Застосувати</x:String>
<x:String x:Key="Text.CreateBranch.Name" xml:space="preserve">Назва нової гілки:</x:String>
<x:String x:Key="Text.CreateBranch.Name.Placeholder" xml:space="preserve">Введіть назву гілки.</x:String>
<x:String x:Key="Text.CreateBranch.Name.WarnSpace" xml:space="preserve">Пробіли будуть замінені на тире.</x:String>
<x:String x:Key="Text.CreateBranch.Title" xml:space="preserve">Створити локальну гілку</x:String>
<x:String x:Key="Text.CreateTag" xml:space="preserve">Створити тег...</x:String>
<x:String x:Key="Text.CreateTag.BasedOn" xml:space="preserve">Новий тег для:</x:String>
<x:String x:Key="Text.CreateTag.GPGSign" xml:space="preserve">Підпис GPG</x:String>
<x:String x:Key="Text.CreateTag.Message" xml:space="preserve">Повідомлення тегу:</x:String>
<x:String x:Key="Text.CreateTag.Message.Placeholder" xml:space="preserve">Необов'язково.</x:String>
<x:String x:Key="Text.CreateTag.Name" xml:space="preserve">Назва тегу:</x:String>
<x:String x:Key="Text.CreateTag.Name.Placeholder" xml:space="preserve">Рекомендований формат: v1.0.0-alpha</x:String>
<x:String x:Key="Text.CreateTag.PushToAllRemotes" xml:space="preserve">Надіслати на всі віддалені сховища після створення</x:String>
<x:String x:Key="Text.CreateTag.Title" xml:space="preserve">Створити Новий Тег</x:String>
<x:String x:Key="Text.CreateTag.Type" xml:space="preserve">Тип:</x:String>
<x:String x:Key="Text.CreateTag.Type.Annotated" xml:space="preserve">анотований</x:String>
<x:String x:Key="Text.CreateTag.Type.Lightweight" xml:space="preserve">легкий</x:String>
<x:String x:Key="Text.CtrlClickTip" xml:space="preserve">Утримуйте Ctrl для запуску без діалогу</x:String>
<x:String x:Key="Text.Cut" xml:space="preserve">Вирізати</x:String>
<x:String x:Key="Text.DeleteBranch" xml:space="preserve">Видалити гілку</x:String>
<x:String x:Key="Text.DeleteBranch.Branch" xml:space="preserve">Гілка:</x:String>
<x:String x:Key="Text.DeleteBranch.IsRemoteTip" xml:space="preserve">Ви збираєтеся видалити віддалену гілку!!!</x:String>
<x:String x:Key="Text.DeleteBranch.WithTrackingRemote" xml:space="preserve">Також видалити віддалену гілку ${0}$</x:String>
<x:String x:Key="Text.DeleteMultiBranch" xml:space="preserve">Видалити кілька гілок</x:String>
<x:String x:Key="Text.DeleteMultiBranch.Tip" xml:space="preserve">Ви намагаєтеся видалити кілька гілок одночасно. Перевірте ще раз перед виконанням!</x:String>
<x:String x:Key="Text.DeleteRemote" xml:space="preserve">Видалити віддалене сховище</x:String>
<x:String x:Key="Text.DeleteRemote.Remote" xml:space="preserve">Віддалене сховище:</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.Path" xml:space="preserve">Шлях:</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.Target" xml:space="preserve">Ціль:</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.TipForGroup" xml:space="preserve">Усі дочірні елементи будуть видалені зі списку.</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.TipForRepository" xml:space="preserve">Це видалить сховище лише зі списку, а не з диска!</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.TitleForGroup" xml:space="preserve">Підтвердити видалення групи</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.TitleForRepository" xml:space="preserve">Підтвердити видалення сховища</x:String>
<x:String x:Key="Text.DeleteSubmodule" xml:space="preserve">Видалити підмодуль</x:String>
<x:String x:Key="Text.DeleteSubmodule.Path" xml:space="preserve">Шлях до підмодуля:</x:String>
<x:String x:Key="Text.DeleteTag" xml:space="preserve">Видалити тег</x:String>
<x:String x:Key="Text.DeleteTag.Tag" xml:space="preserve">Тег:</x:String>
<x:String x:Key="Text.DeleteTag.WithRemote" xml:space="preserve">Видалити з віддалених сховищ</x:String>
<x:String x:Key="Text.Diff.Binary" xml:space="preserve">РІЗНИЦЯ ДЛЯ БІНАРНИХ ФАЙЛІВ</x:String>
<x:String x:Key="Text.Diff.Binary.New" xml:space="preserve">НОВИЙ</x:String>
<x:String x:Key="Text.Diff.Binary.Old" xml:space="preserve">СТАРИЙ</x:String>
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">Копіювати</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">Змінено режим файлу</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">Перша відмінність</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">Ігнорувати зміни пробілів</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">Остання відмінність</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">ЗМІНА ОБ'ЄКТА LFS</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Наступна відмінність</x:String>
<x:String x:Key="Text.Diff.NoChange" xml:space="preserve">НЕМАЄ ЗМІН АБО ЛИШЕ ЗМІНИ КІНЦЯ РЯДКА</x:String>
<x:String x:Key="Text.Diff.Prev" xml:space="preserve">Попередня відмінність</x:String>
<x:String x:Key="Text.Diff.SaveAsPatch" xml:space="preserve">Зберегти як патч</x:String>
<x:String x:Key="Text.Diff.ShowHiddenSymbols" xml:space="preserve">Показати приховані символи</x:String>
<x:String x:Key="Text.Diff.SideBySide" xml:space="preserve">Порівняння пліч-о-пліч</x:String>
<x:String x:Key="Text.Diff.Submodule" xml:space="preserve">ПІДМОДУЛЬ</x:String>
<x:String x:Key="Text.Diff.Submodule.New" xml:space="preserve">НОВИЙ</x:String>
<x:String x:Key="Text.Diff.SwapCommits" xml:space="preserve">Поміняти місцями</x:String>
<x:String x:Key="Text.Diff.SyntaxHighlight" xml:space="preserve">Підсвітка синтаксису</x:String>
<x:String x:Key="Text.Diff.ToggleWordWrap" xml:space="preserve">Перенос слів</x:String>
<x:String x:Key="Text.Diff.UseBlockNavigation" xml:space="preserve">Увімкнути навігацію блоками</x:String>
<x:String x:Key="Text.Diff.UseMerger" xml:space="preserve">Відкрити в інструменті злиття</x:String>
<x:String x:Key="Text.Diff.VisualLines.All" xml:space="preserve">Показати всі рядки</x:String>
<x:String x:Key="Text.Diff.VisualLines.Decr" xml:space="preserve">Зменшити кількість видимих рядків</x:String>
<x:String x:Key="Text.Diff.VisualLines.Incr" xml:space="preserve">Збільшити кількість видимих рядків</x:String>
<x:String x:Key="Text.Diff.Welcome" xml:space="preserve">ОБЕРІТЬ ФАЙЛ ДЛЯ ПЕРЕГЛЯДУ ЗМІН</x:String>
<x:String x:Key="Text.DiffWithMerger" xml:space="preserve">Відкрити в інструменті злиття</x:String>
<x:String x:Key="Text.Discard" xml:space="preserve">Скасувати зміни</x:String>
<x:String x:Key="Text.Discard.All" xml:space="preserve">Усі локальні зміни в робочій копії.</x:String>
<x:String x:Key="Text.Discard.Changes" xml:space="preserve">Зміни:</x:String>
<x:String x:Key="Text.Discard.IncludeIgnored" xml:space="preserve">Включити файли, які ігноруються</x:String>
<x:String x:Key="Text.Discard.Total" xml:space="preserve">{0} змін будуть відхилені</x:String>
<x:String x:Key="Text.Discard.Warning" xml:space="preserve">Ви не можете скасувати цю дію!!!</x:String>
<x:String x:Key="Text.EditRepositoryNode.Bookmark" xml:space="preserve">Закладка:</x:String>
<x:String x:Key="Text.EditRepositoryNode.Name" xml:space="preserve">Нова назва:</x:String>
<x:String x:Key="Text.EditRepositoryNode.Target" xml:space="preserve">Ціль:</x:String>
<x:String x:Key="Text.EditRepositoryNode.TitleForGroup" xml:space="preserve">Редагувати вибрану групу</x:String>
<x:String x:Key="Text.EditRepositoryNode.TitleForRepository" xml:space="preserve">Редагувати вибраний репозиторій</x:String>
<x:String x:Key="Text.ExecuteCustomAction" xml:space="preserve">Виконати спеціальну дію</x:String>
<x:String x:Key="Text.ExecuteCustomAction.Name" xml:space="preserve">Ім'я дії:</x:String>
<x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">Перемотати (без перемкнуття)</x:String>
<x:String x:Key="Text.Fetch" xml:space="preserve">Витягти</x:String>
<x:String x:Key="Text.Fetch.AllRemotes" xml:space="preserve">Витягти всі віддалені сховища</x:String>
<x:String x:Key="Text.Fetch.Force" xml:space="preserve">Примусово перезаписати локальні refs</x:String>
<x:String x:Key="Text.Fetch.NoTags" xml:space="preserve">Витягти без тегів</x:String>
<x:String x:Key="Text.Fetch.Remote" xml:space="preserve">Віддалений:</x:String>
<x:String x:Key="Text.Fetch.Title" xml:space="preserve">Витягти зміни з віддалених репозиторіїв</x:String>
<x:String x:Key="Text.FileCM.AssumeUnchanged" xml:space="preserve">Вважати незмінними</x:String>
<x:String x:Key="Text.FileCM.Discard" xml:space="preserve">Скасувати...</x:String>
<x:String x:Key="Text.FileCM.DiscardMulti" xml:space="preserve">Скасувати {0} файлів...</x:String>
<x:String x:Key="Text.FileCM.DiscardSelectedLines" xml:space="preserve">Скасувати зміни в вибраних рядках</x:String>
<x:String x:Key="Text.FileCM.OpenWithExternalMerger" xml:space="preserve">Відкрити зовнішній інструмент злиття</x:String>
<x:String x:Key="Text.FileCM.ResolveUsing" xml:space="preserve">Розв'язати за допомогою ${0}$</x:String>
<x:String x:Key="Text.FileCM.SaveAsPatch" xml:space="preserve">Зберегти як патч...</x:String>
<x:String x:Key="Text.FileCM.Stage" xml:space="preserve">Стагнути</x:String>
<x:String x:Key="Text.FileCM.StageMulti" xml:space="preserve">Стагнути {0} файлів</x:String>
<x:String x:Key="Text.FileCM.StageSelectedLines" xml:space="preserve">Стагнути зміни в вибраних рядках</x:String>
<x:String x:Key="Text.FileCM.Stash" xml:space="preserve">Схованка...</x:String>
<x:String x:Key="Text.FileCM.StashMulti" xml:space="preserve">Схованка {0} файлів...</x:String>
<x:String x:Key="Text.FileCM.Unstage" xml:space="preserve">Скинути стаг</x:String>
<x:String x:Key="Text.FileCM.UnstageMulti" xml:space="preserve">Скинути {0} файлів</x:String>
<x:String x:Key="Text.FileCM.UnstageSelectedLines" xml:space="preserve">Скинути зміни в вибраних рядках</x:String>
<x:String x:Key="Text.FileCM.UseMine" xml:space="preserve">Використовувати Mine (checkout --ours)</x:String>
<x:String x:Key="Text.FileCM.UseTheirs" xml:space="preserve">Використовувати Theirs (checkout --theirs)</x:String>
<x:String x:Key="Text.FileHistory" xml:space="preserve">Історія файлу</x:String>
<x:String x:Key="Text.FileHistory.FileChange" xml:space="preserve">ЗМІНА</x:String>
<x:String x:Key="Text.FileHistory.FileContent" xml:space="preserve">ЗМІСТ</x:String>
<x:String x:Key="Text.GitFlow" xml:space="preserve">Git-Flow</x:String>
<x:String x:Key="Text.GitFlow.DevelopBranch" xml:space="preserve">Розробка гілки:</x:String>
<x:String x:Key="Text.GitFlow.Feature" xml:space="preserve">Функція:</x:String>
<x:String x:Key="Text.GitFlow.FeaturePrefix" xml:space="preserve">Префікс функції:</x:String>
<x:String x:Key="Text.GitFlow.FinishFeature" xml:space="preserve">FLOW - Завершити функцію</x:String>
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">FLOW - Завершити гарячу поправку</x:String>
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">FLOW - Завершити реліз</x:String>
<x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">Ціль:</x:String>
<x:String x:Key="Text.GitFlow.Hotfix" xml:space="preserve">Гаряча поправка:</x:String>
<x:String x:Key="Text.GitFlow.HotfixPrefix" xml:space="preserve">Префікс гарячої поправки:</x:String>
<x:String x:Key="Text.GitFlow.Init" xml:space="preserve">Ініціалізувати Git-Flow</x:String>
<x:String x:Key="Text.GitFlow.KeepBranchAfterFinish" xml:space="preserve">Залишити гілку</x:String>
<x:String x:Key="Text.GitFlow.ProductionBranch" xml:space="preserve">Гілка виробництва:</x:String>
<x:String x:Key="Text.GitFlow.Release" xml:space="preserve">Реліз:</x:String>
<x:String x:Key="Text.GitFlow.ReleasePrefix" xml:space="preserve">Префікс релізу:</x:String>
<x:String x:Key="Text.GitFlow.StartFeature" xml:space="preserve">Почати функцію...</x:String>
<x:String x:Key="Text.GitFlow.StartFeatureTitle" xml:space="preserve">FLOW - Почати функцію</x:String>
<x:String x:Key="Text.GitFlow.StartHotfix" xml:space="preserve">Почати гарячу поправку...</x:String>
<x:String x:Key="Text.GitFlow.StartHotfixTitle" xml:space="preserve">FLOW - Почати гарячу поправку</x:String>
<x:String x:Key="Text.GitFlow.StartPlaceholder" xml:space="preserve">Введіть назву</x:String>
<x:String x:Key="Text.GitFlow.StartRelease" xml:space="preserve">Почати реліз...</x:String>
<x:String x:Key="Text.GitFlow.StartReleaseTitle" xml:space="preserve">FLOW - Почати реліз</x:String>
<x:String x:Key="Text.GitFlow.TagPrefix" xml:space="preserve">Тег версії Префікс:</x:String>
<x:String x:Key="Text.GitLFS" xml:space="preserve">Git LFS</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern" xml:space="preserve">Додати шаблон для відстеження...</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern.IsFilename" xml:space="preserve">Шаблон є ім'ям файлу</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern.Pattern" xml:space="preserve">Спеціальний шаблон:</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern.Title" xml:space="preserve">Додати шаблон для відстеження до Git LFS</x:String>
<x:String x:Key="Text.GitLFS.Fetch" xml:space="preserve">Витягти</x:String>
<x:String x:Key="Text.GitLFS.Fetch.Tips" xml:space="preserve">Запустіть `git lfs fetch`, щоб завантажити об'єкти Git LFS. Це не оновлює робочу копію.</x:String>
<x:String x:Key="Text.GitLFS.Fetch.Title" xml:space="preserve">Витягти об'єкти LFS</x:String>
<x:String x:Key="Text.GitLFS.Install" xml:space="preserve">Встановити Git LFS hooks</x:String>
<x:String x:Key="Text.GitLFS.Locks" xml:space="preserve">Показати блокування</x:String>
<x:String x:Key="Text.GitLFS.Locks.Empty" xml:space="preserve">Немає заблокованих файлів</x:String>
<x:String x:Key="Text.GitLFS.Locks.Lock" xml:space="preserve">Заблокувати</x:String>
<x:String x:Key="Text.GitLFS.Locks.OnlyMine" xml:space="preserve">Показати лише мої блокування</x:String>
<x:String x:Key="Text.GitLFS.Locks.Title" xml:space="preserve">LFS блокування</x:String>
<x:String x:Key="Text.GitLFS.Locks.Unlock" xml:space="preserve">Розблокувати</x:String>
<x:String x:Key="Text.GitLFS.Locks.UnlockForce" xml:space="preserve">Примусово розблокувати</x:String>
<x:String x:Key="Text.GitLFS.Prune" xml:space="preserve">Принт</x:String>
<x:String x:Key="Text.GitLFS.Prune.Tips" xml:space="preserve">Запустіть `git lfs prune`, щоб видалити старі файли з локального сховища</x:String>
<x:String x:Key="Text.GitLFS.Pull" xml:space="preserve">Витягти</x:String>
<x:String x:Key="Text.GitLFS.Pull.Tips" xml:space="preserve">Запустіть `git lfs pull`, щоб завантажити всі файли Git LFS для поточної ref &amp; checkout</x:String>
<x:String x:Key="Text.GitLFS.Pull.Title" xml:space="preserve">Витягти об'єкти LFS</x:String>
<x:String x:Key="Text.GitLFS.Push" xml:space="preserve">Надіслати</x:String>
<x:String x:Key="Text.GitLFS.Push.Tips" xml:space="preserve">Надіслати чернетки великих файлів до кінця Git LFS</x:String>
<x:String x:Key="Text.GitLFS.Push.Title" xml:space="preserve">Надіслати об'єкти LFS</x:String>
<x:String x:Key="Text.GitLFS.Remote" xml:space="preserve">Віддалений:</x:String>
<x:String x:Key="Text.GitLFS.Track" xml:space="preserve">Відстежувати файли, названі '{0}'</x:String>
<x:String x:Key="Text.GitLFS.TrackByExtension" xml:space="preserve">Відстежувати всі *{0} файли</x:String>
<x:String x:Key="Text.Histories" xml:space="preserve">ІСТОРІЯ</x:String>
<x:String x:Key="Text.Histories.Header.Author" xml:space="preserve">АВТОР</x:String>
<x:String x:Key="Text.Histories.Header.AuthorTime" xml:space="preserve">ЧАС АВТОРА</x:String>
<x:String x:Key="Text.Histories.Header.GraphAndSubject" xml:space="preserve">ГРАФ ТА ТЕМА</x:String>
<x:String x:Key="Text.Histories.Header.SHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.Histories.Header.Time" xml:space="preserve">ЧАС КОМІТУ</x:String>
<x:String x:Key="Text.Histories.Selected" xml:space="preserve">ВИБРАНО {0} КОМІТІВ</x:String>
<x:String x:Key="Text.Histories.Tips" xml:space="preserve">Утримуйте 'Ctrl' або 'Shift' для вибору кількох комітів.</x:String>
<x:String x:Key="Text.Histories.Tips.MacOS" xml:space="preserve">Утримуйте ⌘ або ⇧ для вибору кількох комітів.</x:String>
<x:String x:Key="Text.Histories.Tips.Prefix" xml:space="preserve">ПОРАДИ:</x:String>
<x:String x:Key="Text.Hotkeys" xml:space="preserve">Гарячі клавіші</x:String>
<x:String x:Key="Text.Hotkeys.Global" xml:space="preserve">ГЛОБАЛЬНІ</x:String>
<x:String x:Key="Text.Hotkeys.Global.CancelPopup" xml:space="preserve">Скасувати поточне спливаюче вікно</x:String>
<x:String x:Key="Text.Hotkeys.Global.Clone" xml:space="preserve">Клонувати нове сховище</x:String>
<x:String x:Key="Text.Hotkeys.Global.CloseTab" xml:space="preserve">Закрити поточну вкладку</x:String>
<x:String x:Key="Text.Hotkeys.Global.GotoNextTab" xml:space="preserve">Перейти до наступної вкладки</x:String>
<x:String x:Key="Text.Hotkeys.Global.GotoPrevTab" xml:space="preserve">Перейти до попередньої вкладки</x:String>
<x:String x:Key="Text.Hotkeys.Global.NewTab" xml:space="preserve">Створити нову вкладку</x:String>
<x:String x:Key="Text.Hotkeys.Global.OpenPreferences" xml:space="preserve">Відкрити діалог Налаштування</x:String>
<x:String x:Key="Text.Hotkeys.Repo" xml:space="preserve">СХОВИЩЕ</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Commit" xml:space="preserve">Закомітити проіндексовані зміни</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CommitAndPush" xml:space="preserve">Закомітити та надіслати проіндексовані зміни</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CommitWithAutoStage" xml:space="preserve">Індексувати всі зміни та закомітити</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CreateBranchOnCommit" xml:space="preserve">Створити нову гілку на основі вибраного коміту</x:String>
<x:String x:Key="Text.Hotkeys.Repo.DiscardSelected" xml:space="preserve">Скасувати вибрані зміни</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Fetch" xml:space="preserve">Fetch, запускається без діалогу</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">Режим панелі керування (за замовчуванням)</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">Режим пошуку комітів</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Pull" xml:space="preserve">Pull, запускається без діалогу</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Push" xml:space="preserve">Push, запускається без діалогу</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Refresh" xml:space="preserve">Примусово перезавантажити це сховище</x:String>
<x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">Індексувати/Видалити з індексу вибрані зміни</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewChanges" xml:space="preserve">Перейти до 'Зміни'</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewHistories" xml:space="preserve">Перейти до 'Історія'</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewStashes" xml:space="preserve">Перейти до 'Схованки'</x:String>
<x:String x:Key="Text.Hotkeys.TextEditor" xml:space="preserve">ТЕКСТОВИЙ РЕДАКТОР</x:String>
<x:String x:Key="Text.Hotkeys.TextEditor.CloseSearch" xml:space="preserve">Закрити панель пошуку</x:String>
<x:String x:Key="Text.Hotkeys.TextEditor.GotoNextMatch" xml:space="preserve">Знайти наступний збіг</x:String>
<x:String x:Key="Text.Hotkeys.TextEditor.GotoPrevMatch" xml:space="preserve">Знайти попередній збіг</x:String>
<x:String x:Key="Text.Hotkeys.TextEditor.Search" xml:space="preserve">Відкрити панель пошуку</x:String>
<x:String x:Key="Text.Hunk.Discard" xml:space="preserve">Скасувати</x:String>
<x:String x:Key="Text.Hunk.Stage" xml:space="preserve">Індексувати</x:String>
<x:String x:Key="Text.Hunk.Unstage" xml:space="preserve">Видалити з індексу</x:String>
<x:String x:Key="Text.Init" xml:space="preserve">Ініціалізувати сховище</x:String>
<x:String x:Key="Text.Init.Path" xml:space="preserve">Шлях:</x:String>
<x:String x:Key="Text.InProgress.CherryPick" xml:space="preserve">Cherry-pick в процесі.</x:String>
<x:String x:Key="Text.InProgress.CherryPick.Head" xml:space="preserve">Обробка коміту</x:String>
<x:String x:Key="Text.InProgress.Merge" xml:space="preserve">Злиття в процесі.</x:String>
<x:String x:Key="Text.InProgress.Merge.Operating" xml:space="preserve">Виконується злиття</x:String>
<x:String x:Key="Text.InProgress.Rebase" xml:space="preserve">Перебазування в процесі.</x:String>
<x:String x:Key="Text.InProgress.Rebase.StoppedAt" xml:space="preserve">Зупинено на</x:String>
<x:String x:Key="Text.InProgress.Revert" xml:space="preserve">Скасування в процесі.</x:String>
<x:String x:Key="Text.InProgress.Revert.Head" xml:space="preserve">Скасування коміту</x:String>
<x:String x:Key="Text.InteractiveRebase" xml:space="preserve">Інтерактивне перебазування</x:String>
<x:String x:Key="Text.InteractiveRebase.On" xml:space="preserve">На:</x:String>
<x:String x:Key="Text.InteractiveRebase.Target" xml:space="preserve">Цільова гілка:</x:String>
<x:String x:Key="Text.IssueLinkCM.CopyLink" xml:space="preserve">Копіювати посилання</x:String>
<x:String x:Key="Text.IssueLinkCM.OpenInBrowser" xml:space="preserve">Відкрити в браузері</x:String>
<x:String x:Key="Text.Launcher.Error" xml:space="preserve">ПОМИЛКА</x:String>
<x:String x:Key="Text.Launcher.Info" xml:space="preserve">ПОВІДОМЛЕННЯ</x:String>
<x:String x:Key="Text.Merge" xml:space="preserve">Злиття гілки</x:String>
<x:String x:Key="Text.Merge.Into" xml:space="preserve">В:</x:String>
<x:String x:Key="Text.Merge.Mode" xml:space="preserve">Опція злиття:</x:String>
<x:String x:Key="Text.Merge.Source" xml:space="preserve">Джерело:</x:String>
<x:String x:Key="Text.MergeMultiple" xml:space="preserve">Злиття (Кілька)</x:String>
<x:String x:Key="Text.MergeMultiple.CommitChanges" xml:space="preserve">Закомітити всі зміни</x:String>
<x:String x:Key="Text.MergeMultiple.Strategy" xml:space="preserve">Стратегія:</x:String>
<x:String x:Key="Text.MergeMultiple.Targets" xml:space="preserve">Цілі:</x:String>
<x:String x:Key="Text.MoveRepositoryNode" xml:space="preserve">Перемістити вузол сховища</x:String>
<x:String x:Key="Text.MoveRepositoryNode.Target" xml:space="preserve">Виберіть батьківський вузол для:</x:String>
<x:String x:Key="Text.Name" xml:space="preserve">Назва:</x:String>
<x:String x:Key="Text.NotConfigured" xml:space="preserve">Git не налаштовано. Будь ласка, перейдіть до [Налаштування] та налаштуйте його.</x:String>
<x:String x:Key="Text.OpenAppDataDir" xml:space="preserve">Відкрити теку зберігання даних</x:String>
<x:String x:Key="Text.OpenWith" xml:space="preserve">Відкрити за допомогою...</x:String>
<x:String x:Key="Text.Optional" xml:space="preserve">Необов'язково.</x:String>
<x:String x:Key="Text.PageTabBar.New" xml:space="preserve">Створити нову вкладку</x:String>
<x:String x:Key="Text.PageTabBar.Tab.Bookmark" xml:space="preserve">Закладка</x:String>
<x:String x:Key="Text.PageTabBar.Tab.Close" xml:space="preserve">Закрити вкладку</x:String>
<x:String x:Key="Text.PageTabBar.Tab.CloseOther" xml:space="preserve">Закрити інші вкладки</x:String>
<x:String x:Key="Text.PageTabBar.Tab.CloseRight" xml:space="preserve">Закрити вкладки праворуч</x:String>
<x:String x:Key="Text.PageTabBar.Tab.CopyPath" xml:space="preserve">Копіювати шлях до сховища</x:String>
<x:String x:Key="Text.PageTabBar.Welcome.Title" xml:space="preserve">Сховища</x:String>
<x:String x:Key="Text.Paste" xml:space="preserve">Вставити</x:String>
<x:String x:Key="Text.Period.DaysAgo" xml:space="preserve">{0} днів тому</x:String>
<x:String x:Key="Text.Period.HourAgo" xml:space="preserve">годину тому</x:String>
<x:String x:Key="Text.Period.HoursAgo" xml:space="preserve">{0} годин тому</x:String>
<x:String x:Key="Text.Period.JustNow" xml:space="preserve">Щойно</x:String>
<x:String x:Key="Text.Period.LastMonth" xml:space="preserve">Минулого місяця</x:String>
<x:String x:Key="Text.Period.LastYear" xml:space="preserve">Минулого року</x:String>
<x:String x:Key="Text.Period.MinutesAgo" xml:space="preserve">{0} хвилин тому</x:String>
<x:String x:Key="Text.Period.MonthsAgo" xml:space="preserve">{0} місяців тому</x:String>
<x:String x:Key="Text.Period.YearsAgo" xml:space="preserve">{0} років тому</x:String>
<x:String x:Key="Text.Period.Yesterday" xml:space="preserve">Вчора</x:String>
<x:String x:Key="Text.Preferences" xml:space="preserve">Налаштування</x:String>
<x:String x:Key="Text.Preferences.AI" xml:space="preserve">AI</x:String>
<x:String x:Key="Text.Preferences.AI.AnalyzeDiffPrompt" xml:space="preserve">Промпт для аналізу різниці</x:String>
<x:String x:Key="Text.Preferences.AI.ApiKey" xml:space="preserve">Ключ API</x:String>
<x:String x:Key="Text.Preferences.AI.GenerateSubjectPrompt" xml:space="preserve">Промпт для генерації теми</x:String>
<x:String x:Key="Text.Preferences.AI.Model" xml:space="preserve">Модель</x:String>
<x:String x:Key="Text.Preferences.AI.Name" xml:space="preserve">Назва</x:String>
<x:String x:Key="Text.Preferences.AI.Server" xml:space="preserve">Сервер</x:String>
<x:String x:Key="Text.Preferences.AI.Streaming" xml:space="preserve">Увімкнути потокове відтворення</x:String>
<x:String x:Key="Text.Preferences.Appearance" xml:space="preserve">ВИГЛЯД</x:String>
<x:String x:Key="Text.Preferences.Appearance.DefaultFont" xml:space="preserve">Шрифт за замовчуванням</x:String>
<x:String x:Key="Text.Preferences.Appearance.EditorTabWidth" xml:space="preserve">Ширина табуляції в редакторі</x:String>
<x:String x:Key="Text.Preferences.Appearance.FontSize" xml:space="preserve">Розмір шрифту</x:String>
<x:String x:Key="Text.Preferences.Appearance.FontSize.Default" xml:space="preserve">За замовчуванням</x:String>
<x:String x:Key="Text.Preferences.Appearance.FontSize.Editor" xml:space="preserve">Редактор</x:String>
<x:String x:Key="Text.Preferences.Appearance.MonospaceFont" xml:space="preserve">Моноширинний шрифт</x:String>
<x:String x:Key="Text.Preferences.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">Використовувати моноширинний шрифт лише в текстовому редакторі</x:String>
<x:String x:Key="Text.Preferences.Appearance.Theme" xml:space="preserve">Тема</x:String>
<x:String x:Key="Text.Preferences.Appearance.ThemeOverrides" xml:space="preserve">Перевизначення теми</x:String>
<x:String x:Key="Text.Preferences.Appearance.UseFixedTabWidth" xml:space="preserve">Використовувати фіксовану ширину вкладки в заголовку</x:String>
<x:String x:Key="Text.Preferences.Appearance.UseNativeWindowFrame" xml:space="preserve">Використовувати системну рамку вікна</x:String>
<x:String x:Key="Text.Preferences.DiffMerge" xml:space="preserve">ІНСТРУМЕНТ DIFF/MERGE</x:String>
<x:String x:Key="Text.Preferences.DiffMerge.Path" xml:space="preserve">Шлях встановлення</x:String>
<x:String x:Key="Text.Preferences.DiffMerge.Path.Placeholder" xml:space="preserve">Введіть шлях до інструменту diff/merge</x:String>
<x:String x:Key="Text.Preferences.DiffMerge.Type" xml:space="preserve">Інструмент</x:String>
<x:String x:Key="Text.Preferences.General" xml:space="preserve">ЗАГАЛЬНІ</x:String>
<x:String x:Key="Text.Preferences.General.Check4UpdatesOnStartup" xml:space="preserve">Перевіряти оновлення при запуску</x:String>
<x:String x:Key="Text.Preferences.General.DateFormat" xml:space="preserve">Формат дати</x:String>
<x:String x:Key="Text.Preferences.General.Locale" xml:space="preserve">Мова</x:String>
<x:String x:Key="Text.Preferences.General.MaxHistoryCommits" xml:space="preserve">Кількість комітів в історії</x:String>
<x:String x:Key="Text.Preferences.General.ShowAuthorTime" xml:space="preserve">Показувати час автора замість часу коміту в графі</x:String>
<x:String x:Key="Text.Preferences.General.ShowChildren" xml:space="preserve">Показувати дочірні коміти в деталях</x:String>
<x:String x:Key="Text.Preferences.General.ShowTagsInGraph" xml:space="preserve">Показувати теги в графі комітів</x:String>
<x:String x:Key="Text.Preferences.General.SubjectGuideLength" xml:space="preserve">Довжина лінії-орієнтира для теми</x:String>
<x:String x:Key="Text.Preferences.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Preferences.Git.CRLF" xml:space="preserve">Увімкнути авто-CRLF</x:String>
<x:String x:Key="Text.Preferences.Git.DefaultCloneDir" xml:space="preserve">Тека клонування за замовчуванням</x:String>
<x:String x:Key="Text.Preferences.Git.Email" xml:space="preserve">Email користувача</x:String>
<x:String x:Key="Text.Preferences.Git.Email.Placeholder" xml:space="preserve">Глобальний email користувача git</x:String>
<x:String x:Key="Text.Preferences.Git.EnablePruneOnFetch" xml:space="preserve">Увімкнути --prune при fetch</x:String>
<x:String x:Key="Text.Preferences.Git.Invalid" xml:space="preserve">Git (&gt;= 2.23.0) є обов'язковим для цієї програми</x:String>
<x:String x:Key="Text.Preferences.Git.Path" xml:space="preserve">Шлях встановлення</x:String>
<x:String x:Key="Text.Preferences.Git.SSLVerify" xml:space="preserve">Увімкнути перевірку HTTP SSL</x:String>
<x:String x:Key="Text.Preferences.Git.User" xml:space="preserve">Ім'я користувача</x:String>
<x:String x:Key="Text.Preferences.Git.User.Placeholder" xml:space="preserve">Глобальне ім'я користувача git</x:String>
<x:String x:Key="Text.Preferences.Git.Version" xml:space="preserve">Версія Git</x:String>
<x:String x:Key="Text.Preferences.GPG" xml:space="preserve">ПІДПИС GPG</x:String>
<x:String x:Key="Text.Preferences.GPG.CommitEnabled" xml:space="preserve">Підпис GPG для комітів</x:String>
<x:String x:Key="Text.Preferences.GPG.Format" xml:space="preserve">Формат GPG</x:String>
<x:String x:Key="Text.Preferences.GPG.Path" xml:space="preserve">Шлях встановлення програми</x:String>
<x:String x:Key="Text.Preferences.GPG.Path.Placeholder" xml:space="preserve">Введіть шлях до встановленої програми GPG</x:String>
<x:String x:Key="Text.Preferences.GPG.TagEnabled" xml:space="preserve">Підпис GPG для тегів</x:String>
<x:String x:Key="Text.Preferences.GPG.UserKey" xml:space="preserve">Ключ підпису користувача</x:String>
<x:String x:Key="Text.Preferences.GPG.UserKey.Placeholder" xml:space="preserve">Ключ підпису GPG користувача</x:String>
<x:String x:Key="Text.Preferences.Integration" xml:space="preserve">ІНТЕГРАЦІЯ</x:String>
<x:String x:Key="Text.Preferences.Shell" xml:space="preserve">КОНСОЛЬ/ТЕРМІНАЛ</x:String>
<x:String x:Key="Text.Preferences.Shell.Path" xml:space="preserve">Шлях</x:String>
<x:String x:Key="Text.Preferences.Shell.Type" xml:space="preserve">Консоль/Термінал</x:String>
<x:String x:Key="Text.PruneRemote" xml:space="preserve">Prune для віддаленого сховища</x:String>
<x:String x:Key="Text.PruneRemote.Target" xml:space="preserve">Ціль:</x:String>
<x:String x:Key="Text.PruneWorktrees" xml:space="preserve">Prune для робочих дерев</x:String>
<x:String x:Key="Text.PruneWorktrees.Tip" xml:space="preserve">Видалити застарілу інформацію про робочі дерева в `$GIT_COMMON_DIR/worktrees`</x:String>
<x:String x:Key="Text.Pull" xml:space="preserve">Pull (Витягти)</x:String>
<x:String x:Key="Text.Pull.Branch" xml:space="preserve">Віддалена гілка:</x:String>
<x:String x:Key="Text.Pull.FetchAllBranches" xml:space="preserve">Отримати всі гілки</x:String>
<x:String x:Key="Text.Pull.Into" xml:space="preserve">В:</x:String>
<x:String x:Key="Text.Pull.LocalChanges" xml:space="preserve">Локальні зміни:</x:String>
<x:String x:Key="Text.Pull.LocalChanges.Discard" xml:space="preserve">Скасувати</x:String>
<x:String x:Key="Text.Pull.LocalChanges.StashAndReply" xml:space="preserve">Сховати та Застосувати</x:String>
<x:String x:Key="Text.Pull.NoTags" xml:space="preserve">Отримати без тегів</x:String>
<x:String x:Key="Text.Pull.Remote" xml:space="preserve">Віддалене сховище:</x:String>
<x:String x:Key="Text.Pull.Title" xml:space="preserve">Pull (Fetch &amp; Merge)</x:String>
<x:String x:Key="Text.Pull.UseRebase" xml:space="preserve">Використовувати rebase замість merge</x:String>
<x:String x:Key="Text.Push" xml:space="preserve">Push (Надіслати)</x:String>
<x:String x:Key="Text.Push.CheckSubmodules" xml:space="preserve">Переконатися, що підмодулі надіслано</x:String>
<x:String x:Key="Text.Push.Force" xml:space="preserve">Примусовий push</x:String>
<x:String x:Key="Text.Push.Local" xml:space="preserve">Локальна гілка:</x:String>
<x:String x:Key="Text.Push.Remote" xml:space="preserve">Віддалене сховище:</x:String>
<x:String x:Key="Text.Push.Title" xml:space="preserve">Надіслати зміни на віддалене сховище</x:String>
<x:String x:Key="Text.Push.To" xml:space="preserve">Віддалена гілка:</x:String>
<x:String x:Key="Text.Push.Tracking" xml:space="preserve">Встановити як відстежувану гілку</x:String>
<x:String x:Key="Text.Push.WithAllTags" xml:space="preserve">Надіслати всі теги</x:String>
<x:String x:Key="Text.PushTag" xml:space="preserve">Надіслати тег на віддалене сховище</x:String>
<x:String x:Key="Text.PushTag.PushAllRemotes" xml:space="preserve">Надіслати на всі віддалені сховища</x:String>
<x:String x:Key="Text.PushTag.Remote" xml:space="preserve">Віддалене сховище:</x:String>
<x:String x:Key="Text.PushTag.Tag" xml:space="preserve">Тег:</x:String>
<x:String x:Key="Text.Quit" xml:space="preserve">Вийти</x:String>
<x:String x:Key="Text.Rebase" xml:space="preserve">Перебазувати поточну гілку</x:String>
<x:String x:Key="Text.Rebase.AutoStash" xml:space="preserve">Сховати та застосувати локальні зміни</x:String>
<x:String x:Key="Text.Rebase.On" xml:space="preserve">На:</x:String>
<x:String x:Key="Text.Rebase.Target" xml:space="preserve">Перебазувати:</x:String>
<x:String x:Key="Text.RefetchAvatar" xml:space="preserve">Оновити</x:String>
<x:String x:Key="Text.Remote.AddTitle" xml:space="preserve">Додати віддалене сховище</x:String>
<x:String x:Key="Text.Remote.EditTitle" xml:space="preserve">Редагувати віддалене сховище</x:String>
<x:String x:Key="Text.Remote.Name" xml:space="preserve">Назва:</x:String>
<x:String x:Key="Text.Remote.Name.Placeholder" xml:space="preserve">Назва віддаленого сховища</x:String>
<x:String x:Key="Text.Remote.URL" xml:space="preserve">URL сховища:</x:String>
<x:String x:Key="Text.Remote.URL.Placeholder" xml:space="preserve">URL віддаленого git сховища</x:String>
<x:String x:Key="Text.RemoteCM.CopyURL" xml:space="preserve">Копіювати URL</x:String>
<x:String x:Key="Text.RemoteCM.Delete" xml:space="preserve">Видалити...</x:String>
<x:String x:Key="Text.RemoteCM.Edit" xml:space="preserve">Редагувати...</x:String>
<x:String x:Key="Text.RemoteCM.Fetch" xml:space="preserve">Fetch (Отримати)</x:String>
<x:String x:Key="Text.RemoteCM.OpenInBrowser" xml:space="preserve">Відкрити у браузері</x:String>
<x:String x:Key="Text.RemoteCM.Prune" xml:space="preserve">Prune (Очистити)</x:String>
<x:String x:Key="Text.RemoveWorktree" xml:space="preserve">Підтвердити видалення робочого дерева</x:String>
<x:String x:Key="Text.RemoveWorktree.Force" xml:space="preserve">Увімкнути опцію `--force`</x:String>
<x:String x:Key="Text.RemoveWorktree.Target" xml:space="preserve">Ціль:</x:String>
<x:String x:Key="Text.RenameBranch" xml:space="preserve">Перейменувати гілку</x:String>
<x:String x:Key="Text.RenameBranch.Name" xml:space="preserve">Нова назва:</x:String>
<x:String x:Key="Text.RenameBranch.Name.Placeholder" xml:space="preserve">Унікальна назва для цієї гілки</x:String>
<x:String x:Key="Text.RenameBranch.Target" xml:space="preserve">Гілка:</x:String>
<x:String x:Key="Text.Repository.Abort" xml:space="preserve">ПЕРЕРВАТИ</x:String>
<x:String x:Key="Text.Repository.AutoFetching" xml:space="preserve">Автоматичне отримання змін з віддалених сховищ...</x:String>
<x:String x:Key="Text.Repository.Clean" xml:space="preserve">Очистка (GC &amp; Prune)</x:String>
<x:String x:Key="Text.Repository.CleanTips" xml:space="preserve">Виконати команду `git gc` для цього сховища.</x:String>
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">Очистити все</x:String>
<x:String x:Key="Text.Repository.Configure" xml:space="preserve">Налаштувати це сховище</x:String>
<x:String x:Key="Text.Repository.Continue" xml:space="preserve">ПРОДОВЖИТИ</x:String>
<x:String x:Key="Text.Repository.CustomActions" xml:space="preserve">Спеціальні дії</x:String>
<x:String x:Key="Text.Repository.CustomActions.Empty" xml:space="preserve">Немає спеціальних дій</x:String>
<x:String x:Key="Text.Repository.EnableReflog" xml:space="preserve">Увімкнути опцію '--reflog'</x:String>
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">Відкрити у файловому менеджері</x:String>
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">Пошук гілок/тегів/підмодулів</x:String>
<x:String x:Key="Text.Repository.FilterCommits" xml:space="preserve">Видимість у графі</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Default" xml:space="preserve">Не встановлено</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Exclude" xml:space="preserve">Приховати в графі комітів</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Include" xml:space="preserve">Фільтрувати в графі комітів</x:String>
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">Увімкнути опцію '--first-parent'</x:String>
<x:String x:Key="Text.Repository.HistoriesLayout" xml:space="preserve">РОЗТАШУВАННЯ</x:String>
<x:String x:Key="Text.Repository.HistoriesLayout.Horizontal" xml:space="preserve">Горизонтальне</x:String>
<x:String x:Key="Text.Repository.HistoriesLayout.Vertical" xml:space="preserve">Вертикальне</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder" xml:space="preserve">ПОРЯДОК КОМІТІВ</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.ByDate" xml:space="preserve">За датою коміту</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.Topo" xml:space="preserve">Топологічний</x:String>
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">ЛОКАЛЬНІ ГІЛКИ</x:String>
<x:String x:Key="Text.Repository.NavigateToCurrentHead" xml:space="preserve">Перейти до HEAD</x:String>
<x:String x:Key="Text.Repository.NewBranch" xml:space="preserve">Створити гілку</x:String>
<x:String x:Key="Text.Repository.Notifications.Clear" xml:space="preserve">ОЧИСТИТИ СПОВІЩЕННЯ</x:String>
<x:String x:Key="Text.Repository.OnlyHighlightCurrentBranchInHistories" xml:space="preserve">Виділяти лише поточну гілку в графі</x:String>
<x:String x:Key="Text.Repository.OpenIn" xml:space="preserve">Відкрити в {0}</x:String>
<x:String x:Key="Text.Repository.OpenWithExternalTools" xml:space="preserve">Відкрити в зовнішніх інструментах</x:String>
<x:String x:Key="Text.Repository.Refresh" xml:space="preserve">Оновити</x:String>
<x:String x:Key="Text.Repository.Remotes" xml:space="preserve">ВІДДАЛЕНІ СХОВИЩА</x:String>
<x:String x:Key="Text.Repository.Remotes.Add" xml:space="preserve">ДОДАТИ ВІДДАЛЕНЕ СХОВИЩЕ</x:String>
<x:String x:Key="Text.Repository.Search" xml:space="preserve">Пошук коміту</x:String>
<x:String x:Key="Text.Repository.Search.ByAuthor" xml:space="preserve">Автор</x:String>
<x:String x:Key="Text.Repository.Search.ByCommitter" xml:space="preserve">Комітер</x:String>
<x:String x:Key="Text.Repository.Search.ByFile" xml:space="preserve">Файл</x:String>
<x:String x:Key="Text.Repository.Search.ByMessage" xml:space="preserve">Повідомлення</x:String>
<x:String x:Key="Text.Repository.Search.BySHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.Repository.Search.InCurrentBranch" xml:space="preserve">Поточна гілка</x:String>
<x:String x:Key="Text.Repository.ShowTagsAsTree" xml:space="preserve">Показати теги як дерево</x:String>
<x:String x:Key="Text.Repository.Skip" xml:space="preserve">ПРОПУСТИТИ</x:String>
<x:String x:Key="Text.Repository.Statistics" xml:space="preserve">Статистика</x:String>
<x:String x:Key="Text.Repository.Submodules" xml:space="preserve">ПІДМОДУЛІ</x:String>
<x:String x:Key="Text.Repository.Submodules.Add" xml:space="preserve">ДОДАТИ ПІДМОДУЛЬ</x:String>
<x:String x:Key="Text.Repository.Submodules.Update" xml:space="preserve">ОНОВИТИ ПІДМОДУЛЬ</x:String>
<x:String x:Key="Text.Repository.Tags" xml:space="preserve">ТЕГИ</x:String>
<x:String x:Key="Text.Repository.Tags.Add" xml:space="preserve">НОВИЙ ТЕГ</x:String>
<x:String x:Key="Text.Repository.Tags.OrderByCreatorDate" xml:space="preserve">За датою створення</x:String>
<x:String x:Key="Text.Repository.Tags.OrderByNameAsc" xml:space="preserve">За назвою (за зростанням)</x:String>
<x:String x:Key="Text.Repository.Tags.OrderByNameDes" xml:space="preserve">За назвою (за спаданням)</x:String>
<x:String x:Key="Text.Repository.Tags.Sort" xml:space="preserve">Сортувати</x:String>
<x:String x:Key="Text.Repository.Terminal" xml:space="preserve">Відкрити в терміналі</x:String>
<x:String x:Key="Text.Repository.UseRelativeTimeInHistories" xml:space="preserve">Використовувати відносний час в історії</x:String>
<x:String x:Key="Text.Repository.Worktrees" xml:space="preserve">РОБОЧІ ДЕРЕВА</x:String>
<x:String x:Key="Text.Repository.Worktrees.Add" xml:space="preserve">ДОДАТИ РОБОЧЕ ДЕРЕВО</x:String>
<x:String x:Key="Text.Repository.Worktrees.Prune" xml:space="preserve">PRUNE (ОЧИСТИТИ)</x:String>
<x:String x:Key="Text.RepositoryURL" xml:space="preserve">URL Git сховища</x:String>
<x:String x:Key="Text.Reset" xml:space="preserve">Скинути поточну гілку до ревізії</x:String>
<x:String x:Key="Text.Reset.Mode" xml:space="preserve">Режим скидання:</x:String>
<x:String x:Key="Text.Reset.MoveTo" xml:space="preserve">Перемістити до:</x:String>
<x:String x:Key="Text.Reset.Target" xml:space="preserve">Поточна гілка:</x:String>
<x:String x:Key="Text.RevealFile" xml:space="preserve">Показати у файловому менеджері</x:String>
<x:String x:Key="Text.Revert" xml:space="preserve">Revert (Скасувати коміт)</x:String>
<x:String x:Key="Text.Revert.Commit" xml:space="preserve">Коміт:</x:String>
<x:String x:Key="Text.Revert.CommitChanges" xml:space="preserve">Закомітити зміни скасування</x:String>
<x:String x:Key="Text.Reword" xml:space="preserve">Змінити повідомлення коміту</x:String>
<x:String x:Key="Text.Reword.Tip" xml:space="preserve">Використовуйте 'Shift+Enter' для введення нового рядка. 'Enter' - гаряча клавіша кнопки OK</x:String>
<x:String x:Key="Text.Running" xml:space="preserve">Виконується. Будь ласка, зачекайте...</x:String>
<x:String x:Key="Text.Save" xml:space="preserve">ЗБЕРЕГТИ</x:String>
<x:String x:Key="Text.SaveAs" xml:space="preserve">Зберегти як...</x:String>
<x:String x:Key="Text.SaveAsPatchSuccess" xml:space="preserve">Патч успішно збережено!</x:String>
<x:String x:Key="Text.ScanRepositories" xml:space="preserve">Сканувати сховища</x:String>
<x:String x:Key="Text.ScanRepositories.RootDir" xml:space="preserve">Коренева тека:</x:String>
<x:String x:Key="Text.SelfUpdate" xml:space="preserve">Перевірити оновлення...</x:String>
<x:String x:Key="Text.SelfUpdate.Available" xml:space="preserve">Доступна нова версія програми: </x:String>
<x:String x:Key="Text.SelfUpdate.Error" xml:space="preserve">Не вдалося перевірити оновлення!</x:String>
<x:String x:Key="Text.SelfUpdate.GotoDownload" xml:space="preserve">Завантажити</x:String>
<x:String x:Key="Text.SelfUpdate.IgnoreThisVersion" xml:space="preserve">Пропустити цю версію</x:String>
<x:String x:Key="Text.SelfUpdate.Title" xml:space="preserve">Оновлення програми</x:String>
<x:String x:Key="Text.SelfUpdate.UpToDate" xml:space="preserve">У вас встановлена остання версія.</x:String>
<x:String x:Key="Text.SetUpstream" xml:space="preserve">Встановити відстежувану гілку</x:String>
<x:String x:Key="Text.SetUpstream.Local" xml:space="preserve">Гілка:</x:String>
<x:String x:Key="Text.SetUpstream.Unset" xml:space="preserve">Скасувати upstream</x:String>
<x:String x:Key="Text.SetUpstream.Upstream" xml:space="preserve">Upstream:</x:String>
<x:String x:Key="Text.SHALinkCM.CopySHA" xml:space="preserve">Копіювати SHA</x:String>
<x:String x:Key="Text.SHALinkCM.NavigateTo" xml:space="preserve">Перейти до</x:String>
<x:String x:Key="Text.Squash" xml:space="preserve">Squash (Склеїти коміти)</x:String>
<x:String x:Key="Text.Squash.Into" xml:space="preserve">В:</x:String>
<x:String x:Key="Text.SSHKey" xml:space="preserve">Приватний ключ SSH:</x:String>
<x:String x:Key="Text.SSHKey.Placeholder" xml:space="preserve">Шлях до сховища приватного ключа SSH</x:String>
<x:String x:Key="Text.Start" xml:space="preserve">ПОЧАТИ</x:String>
<x:String x:Key="Text.Stash" xml:space="preserve">Stash (Сховати)</x:String>
<x:String x:Key="Text.Stash.AutoRestore" xml:space="preserve">Автоматично відновити після схову</x:String>
<x:String x:Key="Text.Stash.AutoRestore.Tip" xml:space="preserve">Ваші робочі файли залишаться без змін, але буде збережено схованку.</x:String>
<x:String x:Key="Text.Stash.IncludeUntracked" xml:space="preserve">Включити невідстежувані файли</x:String>
<x:String x:Key="Text.Stash.KeepIndex" xml:space="preserve">Зберегти проіндексовані файли</x:String>
<x:String x:Key="Text.Stash.Message" xml:space="preserve">Повідомлення:</x:String>
<x:String x:Key="Text.Stash.Message.Placeholder" xml:space="preserve">Необов'язково. Назва цієї схованки</x:String>
<x:String x:Key="Text.Stash.OnlyStagedChanges" xml:space="preserve">Лише проіндексовані зміни</x:String>
<x:String x:Key="Text.Stash.TipForSelectedFiles" xml:space="preserve">Будуть сховані як проіндексовані, так і не проіндексовані зміни вибраних файлів!!!</x:String>
<x:String x:Key="Text.Stash.Title" xml:space="preserve">Сховати локальні зміни</x:String>
<x:String x:Key="Text.StashCM.Apply" xml:space="preserve">Застосувати</x:String>
<x:String x:Key="Text.StashCM.Drop" xml:space="preserve">Видалити</x:String>
<x:String x:Key="Text.StashCM.SaveAsPatch" xml:space="preserve">Зберегти як патч...</x:String>
<x:String x:Key="Text.StashDropConfirm" xml:space="preserve">Видалити схованку</x:String>
<x:String x:Key="Text.StashDropConfirm.Label" xml:space="preserve">Видалити:</x:String>
<x:String x:Key="Text.Stashes" xml:space="preserve">СХОВАНКИ</x:String>
<x:String x:Key="Text.Stashes.Changes" xml:space="preserve">ЗМІНИ</x:String>
<x:String x:Key="Text.Stashes.Stashes" xml:space="preserve">СХОВАНКИ</x:String>
<x:String x:Key="Text.Statistics" xml:space="preserve">Статистика</x:String>
<x:String x:Key="Text.Statistics.CommitAmount" xml:space="preserve">КОМІТИ</x:String>
<x:String x:Key="Text.Statistics.Committer" xml:space="preserve">КОМІТЕР</x:String>
<x:String x:Key="Text.Statistics.Overview" xml:space="preserve">ОГЛЯД</x:String>
<x:String x:Key="Text.Statistics.ThisMonth" xml:space="preserve">МІСЯЦЬ</x:String>
<x:String x:Key="Text.Statistics.ThisWeek" xml:space="preserve">ТИЖДЕНЬ</x:String>
<x:String x:Key="Text.Statistics.TotalAuthors" xml:space="preserve">АВТОРІВ: </x:String>
<x:String x:Key="Text.Statistics.TotalCommits" xml:space="preserve">КОМІТІВ: </x:String>
<x:String x:Key="Text.Submodule" xml:space="preserve">ПІДМОДУЛІ</x:String>
<x:String x:Key="Text.Submodule.Add" xml:space="preserve">Додати підмодуль</x:String>
<x:String x:Key="Text.Submodule.CopyPath" xml:space="preserve">Копіювати відносний шлях</x:String>
<x:String x:Key="Text.Submodule.FetchNested" xml:space="preserve">Отримати вкладені підмодулі</x:String>
<x:String x:Key="Text.Submodule.Open" xml:space="preserve">Відкрити сховище підмодуля</x:String>
<x:String x:Key="Text.Submodule.RelativePath" xml:space="preserve">Відносний шлях:</x:String>
<x:String x:Key="Text.Submodule.RelativePath.Placeholder" xml:space="preserve">Відносна тека для зберігання цього модуля.</x:String>
<x:String x:Key="Text.Submodule.Remove" xml:space="preserve">Видалити підмодуль</x:String>
<x:String x:Key="Text.Sure" xml:space="preserve">OK</x:String>
<x:String x:Key="Text.TagCM.Copy" xml:space="preserve">Копіювати назву тегу</x:String>
<x:String x:Key="Text.TagCM.CopyMessage" xml:space="preserve">Копіювати повідомлення тегу</x:String>
<x:String x:Key="Text.TagCM.Delete" xml:space="preserve">Видалити ${0}$...</x:String>
<x:String x:Key="Text.TagCM.Merge" xml:space="preserve">Злиття ${0}$ в ${1}$...</x:String>
<x:String x:Key="Text.TagCM.Push" xml:space="preserve">Надіслати ${0}$...</x:String>
<x:String x:Key="Text.UpdateSubmodules" xml:space="preserve">Оновити підмодулі</x:String>
<x:String x:Key="Text.UpdateSubmodules.All" xml:space="preserve">Усі підмодулі</x:String>
<x:String x:Key="Text.UpdateSubmodules.Init" xml:space="preserve">Ініціалізувати за потреби</x:String>
<x:String x:Key="Text.UpdateSubmodules.Recursive" xml:space="preserve">Рекурсивно</x:String>
<x:String x:Key="Text.UpdateSubmodules.Target" xml:space="preserve">Підмодуль:</x:String>
<x:String x:Key="Text.UpdateSubmodules.UseRemote" xml:space="preserve">Використовувати опцію --remote</x:String>
<x:String x:Key="Text.URL" xml:space="preserve">URL:</x:String>
<x:String x:Key="Text.Warn" xml:space="preserve">Попередження</x:String>
<x:String x:Key="Text.Welcome" xml:space="preserve">Вітальна сторінка</x:String>
<x:String x:Key="Text.Welcome.AddRootFolder" xml:space="preserve">Створити групу</x:String>
<x:String x:Key="Text.Welcome.AddSubFolder" xml:space="preserve">Створити підгрупу</x:String>
<x:String x:Key="Text.Welcome.Clone" xml:space="preserve">Клонувати сховище</x:String>
<x:String x:Key="Text.Welcome.Delete" xml:space="preserve">Видалити</x:String>
<x:String x:Key="Text.Welcome.DragDropTip" xml:space="preserve">ПІДТРИМУЄТЬСЯ ПЕРЕТЯГУВАННЯ ТЕК. МОЖЛИВЕ ГРУПУВАННЯ.</x:String>
<x:String x:Key="Text.Welcome.Edit" xml:space="preserve">Редагувати</x:String>
<x:String x:Key="Text.Welcome.Move" xml:space="preserve">Перемістити до іншої групи</x:String>
<x:String x:Key="Text.Welcome.OpenAllInNode" xml:space="preserve">Відкрити всі сховища</x:String>
<x:String x:Key="Text.Welcome.OpenOrInit" xml:space="preserve">Відкрити сховище</x:String>
<x:String x:Key="Text.Welcome.OpenTerminal" xml:space="preserve">Відкрити термінал</x:String>
<x:String x:Key="Text.Welcome.ScanDefaultCloneDir" xml:space="preserve">Пересканувати сховища у теці клонування за замовчуванням</x:String>
<x:String x:Key="Text.Welcome.Search" xml:space="preserve">Пошук сховищ...</x:String>
<x:String x:Key="Text.Welcome.Sort" xml:space="preserve">Сортувати</x:String>
<x:String x:Key="Text.WorkingCopy" xml:space="preserve">ЛОКАЛЬНІ ЗМІНИ</x:String>
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore" xml:space="preserve">Git Ignore</x:String>
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.Extension" xml:space="preserve">Ігнорувати всі файли *{0}</x:String>
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.ExtensionInSameFolder" xml:space="preserve">Ігнорувати файли *{0} у цій же теці</x:String>
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.InSameFolder" xml:space="preserve">Ігнорувати файли у цій же теці</x:String>
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.SingleFile" xml:space="preserve">Ігнорувати лише цей файл</x:String>
<x:String x:Key="Text.WorkingCopy.Amend" xml:space="preserve">Amend (Доповнити)</x:String>
<x:String x:Key="Text.WorkingCopy.CanStageTip" xml:space="preserve">Тепер ви можете проіндексувати цей файл.</x:String>
<x:String x:Key="Text.WorkingCopy.Commit" xml:space="preserve">КОМІТ</x:String>
<x:String x:Key="Text.WorkingCopy.CommitAndPush" xml:space="preserve">КОМІТ ТА PUSH</x:String>
<x:String x:Key="Text.WorkingCopy.CommitMessageHelper" xml:space="preserve">Шаблон/Історії</x:String>
<x:String x:Key="Text.WorkingCopy.CommitTip" xml:space="preserve">Викликати подію кліку</x:String>
<x:String x:Key="Text.WorkingCopy.CommitToEdit" xml:space="preserve">Коміт (Редагувати)</x:String>
<x:String x:Key="Text.WorkingCopy.CommitWithAutoStage" xml:space="preserve">Індексувати всі зміни та закомітити</x:String>
<x:String x:Key="Text.WorkingCopy.ConfirmCommitWithFilter" xml:space="preserve">Ви проіндексували {0} файл(ів), але відображено лише {1} ({2} файлів відфільтровано). Продовжити?</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts" xml:space="preserve">ВИЯВЛЕНО КОНФЛІКТИ</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.OpenExternalMergeTool" xml:space="preserve">ВІДКРИТИ ЗОВНІШНІЙ ІНСТРУМЕНТ ЗЛИТТЯ</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts" xml:space="preserve">ВІДКРИТИ ВСІ КОНФЛІКТИ В ЗОВНІШНЬОМУ ІНСТРУМЕНТІ ЗЛИТТЯ</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.Resolved" xml:space="preserve">КОНФЛІКТИ ФАЙЛІВ ВИРІШЕНО</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.UseMine" xml:space="preserve">ВИКОРИСТАТИ МОЮ ВЕРСІЮ</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.UseTheirs" xml:space="preserve">ВИКОРИСТАТИ ЇХНЮ ВЕРСІЮ</x:String>
<x:String x:Key="Text.WorkingCopy.IncludeUntracked" xml:space="preserve">ВКЛЮЧИТИ НЕВІДСТЕЖУВАНІ ФАЙЛИ</x:String>
<x:String x:Key="Text.WorkingCopy.NoCommitHistories" xml:space="preserve">НЕМАЄ ОСТАННІХ ПОВІДОМЛЕНЬ</x:String>
<x:String x:Key="Text.WorkingCopy.NoCommitTemplates" xml:space="preserve">НЕМАЄ ШАБЛОНІВ КОМІТІВ</x:String>
<x:String x:Key="Text.WorkingCopy.ResolveTip" xml:space="preserve">Клацніть правою кнопкою миші на вибраних файлах та оберіть спосіб вирішення конфліктів.</x:String>
<x:String x:Key="Text.WorkingCopy.SignOff" xml:space="preserve">Підпис</x:String>
<x:String x:Key="Text.WorkingCopy.Staged" xml:space="preserve">ПРОІНДЕКСОВАНІ</x:String>
<x:String x:Key="Text.WorkingCopy.Staged.Unstage" xml:space="preserve">ВИДАЛИТИ З ІНДЕКСУ</x:String>
<x:String x:Key="Text.WorkingCopy.Staged.UnstageAll" xml:space="preserve">ВИДАЛИТИ ВСЕ З ІНДЕКСУ</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged" xml:space="preserve">НЕПРОІНДЕКСОВАНІ</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged.Stage" xml:space="preserve">ІНДЕКСУВАТИ</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged.StageAll" xml:space="preserve">ІНДЕКСУВАТИ ВСЕ</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged.ViewAssumeUnchaged" xml:space="preserve">ПЕРЕГЛЯНУТИ ФАЙЛИ, ЩО ВВАЖАЮТЬСЯ НЕЗМІНЕНИМИ</x:String>
<x:String x:Key="Text.WorkingCopy.UseCommitTemplate" xml:space="preserve">Шаблон: ${0}$</x:String>
<x:String x:Key="Text.Workspace" xml:space="preserve">РОБОЧИЙ ПРОСТІР: </x:String>
<x:String x:Key="Text.Workspace.Configure" xml:space="preserve">Налаштувати робочі простори...</x:String>
<x:String x:Key="Text.Worktree" xml:space="preserve">РОБОЧЕ ДЕРЕВО</x:String>
<x:String x:Key="Text.Worktree.CopyPath" xml:space="preserve">Копіювати шлях</x:String>
<x:String x:Key="Text.Worktree.Lock" xml:space="preserve">Заблокувати</x:String>
<x:String x:Key="Text.Worktree.Remove" xml:space="preserve">Видалити</x:String>
<x:String x:Key="Text.Worktree.Unlock" xml:space="preserve">Розблокувати</x:String>
</ResourceDictionary>

View file

@ -103,8 +103,11 @@
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">挑选(cherry-pick)...</x:String>
<x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">与当前HEAD比较</x:String>
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">与本地工作树比较</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">复制简要信息</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">复制提交指纹</x:String>
<x:String x:Key="Text.CommitCM.CopyAuthor" xml:space="preserve">作者</x:String>
<x:String x:Key="Text.CommitCM.CopyCommitter" xml:space="preserve">提交者</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">简要信息</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">提交指纹</x:String>
<x:String x:Key="Text.CommitCM.CopySubject" xml:space="preserve">主题</x:String>
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">自定义操作</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">交互式变基(rebase -i) ${0}$ 到此处</x:String>
<x:String x:Key="Text.CommitCM.Merge" xml:space="preserve">合并(merge)此提交至 ${0}$</x:String>
@ -136,6 +139,7 @@
<x:String x:Key="Text.CommitDetail.Info.SHA" xml:space="preserve">提交指纹</x:String>
<x:String x:Key="Text.CommitDetail.Info.WebLinks" xml:space="preserve">浏览器中查看</x:String>
<x:String x:Key="Text.CommitMessageTextBox.MessagePlaceholder" xml:space="preserve">详细描述</x:String>
<x:String x:Key="Text.CommitMessageTextBox.SubjectCount" xml:space="preserve">主题</x:String>
<x:String x:Key="Text.CommitMessageTextBox.SubjectPlaceholder" xml:space="preserve">填写提交信息主题</x:String>
<x:String x:Key="Text.Configure" xml:space="preserve">仓库配置</x:String>
<x:String x:Key="Text.Configure.CommitMessageTemplate" xml:space="preserve">提交信息模板</x:String>
@ -180,6 +184,7 @@
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">应用于本仓库的用户名</x:String>
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">工作区</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">颜色</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">名称</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">启动时恢复打开的仓库</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.Continue" xml:space="preserve">确认继续</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.NoLocalChanges" xml:space="preserve">提交未包含变更文件!是否继续(--allow-empty)</x:String>
@ -245,7 +250,7 @@
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">复制</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">文件权限已变化</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">首个差异</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">忽略空白符号变化</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">忽略空白符号变化和EOL</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">最后一个差异</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">LFS对象变更</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">下一个差异</x:String>
@ -460,7 +465,6 @@
<x:String x:Key="Text.Preferences.AI.Streaming" xml:space="preserve">启用流式输出</x:String>
<x:String x:Key="Text.Preferences.Appearance" xml:space="preserve">外观配置</x:String>
<x:String x:Key="Text.Preferences.Appearance.DefaultFont" xml:space="preserve">缺省字体</x:String>
<x:String x:Key="Text.Preferences.Appearance.EditorFontSize" xml:space="preserve">代码字体大小</x:String>
<x:String x:Key="Text.Preferences.Appearance.EditorTabWidth" xml:space="preserve">编辑器制表符宽度</x:String>
<x:String x:Key="Text.Preferences.Appearance.FontSize" xml:space="preserve">字体大小</x:String>
<x:String x:Key="Text.Preferences.Appearance.FontSize.Default" xml:space="preserve">默认</x:String>
@ -615,6 +619,7 @@
<x:String x:Key="Text.Repository.Tags.Sort" xml:space="preserve">排序</x:String>
<x:String x:Key="Text.Repository.Terminal" xml:space="preserve">在终端中打开</x:String>
<x:String x:Key="Text.Repository.UseRelativeTimeInHistories" xml:space="preserve">在提交列表中使用相对时间</x:String>
<x:String x:Key="Text.Repository.ViewLogs" xml:space="preserve">查看命令日志</x:String>
<x:String x:Key="Text.Repository.Worktrees" xml:space="preserve">工作树列表</x:String>
<x:String x:Key="Text.Repository.Worktrees.Add" xml:space="preserve">新增工作树</x:String>
<x:String x:Key="Text.Repository.Worktrees.Prune" xml:space="preserve">清理</x:String>
@ -700,6 +705,10 @@
<x:String x:Key="Text.UpdateSubmodules.Target" xml:space="preserve">子模块 </x:String>
<x:String x:Key="Text.UpdateSubmodules.UseRemote" xml:space="preserve">启用 '--remote'</x:String>
<x:String x:Key="Text.URL" xml:space="preserve">仓库地址 </x:String>
<x:String x:Key="Text.ViewLogs" xml:space="preserve">日志列表</x:String>
<x:String x:Key="Text.ViewLogs.Clear" xml:space="preserve">清空日志</x:String>
<x:String x:Key="Text.ViewLogs.CopyLog" xml:space="preserve">复制</x:String>
<x:String x:Key="Text.ViewLogs.Delete" xml:space="preserve">删除</x:String>
<x:String x:Key="Text.Warn" xml:space="preserve">警告</x:String>
<x:String x:Key="Text.Welcome" xml:space="preserve">起始页</x:String>
<x:String x:Key="Text.Welcome.AddRootFolder" xml:space="preserve">新建分组</x:String>

View file

@ -103,8 +103,11 @@
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">揀選 (cherry-pick)...</x:String>
<x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">與目前 HEAD 比較</x:String>
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">與本機工作區比較</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">複製摘要資訊</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">複製提交編號</x:String>
<x:String x:Key="Text.CommitCM.CopyAuthor" xml:space="preserve">作者</x:String>
<x:String x:Key="Text.CommitCM.CopyCommitter" xml:space="preserve">提交者</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">摘要資訊</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">提交編號</x:String>
<x:String x:Key="Text.CommitCM.CopySubject" xml:space="preserve">標題</x:String>
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">自訂動作</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">互動式重定基底 (rebase -i) ${0}$ 到此處</x:String>
<x:String x:Key="Text.CommitCM.Merge" xml:space="preserve">合併 (merge) 此提交到 ${0}$</x:String>
@ -136,6 +139,7 @@
<x:String x:Key="Text.CommitDetail.Info.SHA" xml:space="preserve">提交編號</x:String>
<x:String x:Key="Text.CommitDetail.Info.WebLinks" xml:space="preserve">在瀏覽器中檢視</x:String>
<x:String x:Key="Text.CommitMessageTextBox.MessagePlaceholder" xml:space="preserve">詳細描述</x:String>
<x:String x:Key="Text.CommitMessageTextBox.SubjectCount" xml:space="preserve">標題</x:String>
<x:String x:Key="Text.CommitMessageTextBox.SubjectPlaceholder" xml:space="preserve">填寫提交訊息標題</x:String>
<x:String x:Key="Text.Configure" xml:space="preserve">存放庫設定</x:String>
<x:String x:Key="Text.Configure.CommitMessageTemplate" xml:space="preserve">提交訊息範本</x:String>
@ -180,6 +184,7 @@
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">用於本存放庫的使用者名稱</x:String>
<x:String x:Key="Text.ConfigureWorkspace" xml:space="preserve">工作區</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Color" xml:space="preserve">顏色</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Name" xml:space="preserve">名稱</x:String>
<x:String x:Key="Text.ConfigureWorkspace.Restore" xml:space="preserve">啟動時還原上次開啟的存放庫</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.Continue" xml:space="preserve">确认继续</x:String>
<x:String x:Key="Text.ConfirmEmptyCommit.NoLocalChanges" xml:space="preserve">未包含任何檔案變更! 您是否仍要提交 (--allow-empty)?</x:String>
@ -245,7 +250,7 @@
<x:String x:Key="Text.Diff.Copy" xml:space="preserve">複製</x:String>
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">檔案權限已變更</x:String>
<x:String x:Key="Text.Diff.First" xml:space="preserve">第一個差異</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">忽略空白符號變化</x:String>
<x:String x:Key="Text.Diff.IgnoreWhitespace" xml:space="preserve">忽略空白符號變化和EOL</x:String>
<x:String x:Key="Text.Diff.Last" xml:space="preserve">最後一個差異</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">LFS 物件變更</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">下一個差異</x:String>
@ -614,6 +619,7 @@
<x:String x:Key="Text.Repository.Tags.Sort" xml:space="preserve">排序</x:String>
<x:String x:Key="Text.Repository.Terminal" xml:space="preserve">在終端機中開啟</x:String>
<x:String x:Key="Text.Repository.UseRelativeTimeInHistories" xml:space="preserve">在提交列表中使用相對時間</x:String>
<x:String x:Key="Text.Repository.ViewLogs" xml:space="preserve">檢視 GIT 指令的日誌</x:String>
<x:String x:Key="Text.Repository.Worktrees" xml:space="preserve">工作區列表</x:String>
<x:String x:Key="Text.Repository.Worktrees.Add" xml:space="preserve">新增工作區</x:String>
<x:String x:Key="Text.Repository.Worktrees.Prune" xml:space="preserve">清理</x:String>
@ -699,6 +705,10 @@
<x:String x:Key="Text.UpdateSubmodules.Target" xml:space="preserve">子模組:</x:String>
<x:String x:Key="Text.UpdateSubmodules.UseRemote" xml:space="preserve">啟用 [--remote] 選項</x:String>
<x:String x:Key="Text.URL" xml:space="preserve">存放庫網址:</x:String>
<x:String x:Key="Text.ViewLogs" xml:space="preserve">日誌清單</x:String>
<x:String x:Key="Text.ViewLogs.Clear" xml:space="preserve">清除所有日誌</x:String>
<x:String x:Key="Text.ViewLogs.CopyLog" xml:space="preserve">複製</x:String>
<x:String x:Key="Text.ViewLogs.Delete" xml:space="preserve">刪除</x:String>
<x:String x:Key="Text.Warn" xml:space="preserve">警告</x:String>
<x:String x:Key="Text.Welcome" xml:space="preserve">起始頁</x:String>
<x:String x:Key="Text.Welcome.AddRootFolder" xml:space="preserve">新增群組</x:String>

View file

@ -499,6 +499,12 @@
<Style Selector="Button.flat:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="Button.flat:disabled">
<Setter Property="Background" Value="{DynamicResource Brush.FlatButton.Background}"/>
</Style>
<Style Selector="Button.flat:disabled /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="Button.flat.primary">
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrush}"/>
<Setter Property="Background" Value="{DynamicResource AccentButtonBackground}"/>
@ -509,18 +515,15 @@
<Style Selector="Button.flat.primary:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="Button.flat.primary:disabled">
<Setter Property="Opacity" Value=".65"/>
</Style>
<Style Selector="Button.flat.primary TextBlock">
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForeground}"/>
</Style>
<Style Selector="Button.flat.primary ToolTip TextBlock">
<Setter Property="Foreground" Value="{DynamicResource Brush.FG1}"/>
</Style>
<Style Selector="Button.flat:disabled /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="Button.flat:disabled">
<Setter Property="Background" Value="{DynamicResource Brush.FlatButton.Background}"/>
</Style>
<Style Selector="SplitButton">
<Setter Property="MinHeight" Value="24"/>
@ -835,7 +838,13 @@
ContentTemplate="{TemplateBinding HeaderTemplate}"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
RecognizesAccessKey="False"/>
RecognizesAccessKey="False">
<ContentPresenter.DataTemplates>
<DataTemplate DataType="x:String">
<v:NameHighlightedTextBlock Text="{Binding}" VerticalAlignment="Center"/>
</DataTemplate>
</ContentPresenter.DataTemplates>
</ContentPresenter>
<TextBlock x:Name="PART_InputGestureText"
Grid.Column="2"

View file

@ -41,11 +41,11 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.2.7" />
<PackageReference Include="Avalonia.Desktop" Version="11.2.7" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.7" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.7" />
<PackageReference Include="Avalonia.Diagnostics" Version="11.2.7" Condition="'$(Configuration)' == 'Debug'" />
<PackageReference Include="Avalonia" Version="11.2.8" />
<PackageReference Include="Avalonia.Desktop" Version="11.2.8" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.8" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.8" />
<PackageReference Include="Avalonia.Diagnostics" Version="11.2.8" Condition="'$(Configuration)' == 'Debug'" />
<PackageReference Include="Avalonia.AvaloniaEdit" Version="11.2.0" />
<PackageReference Include="AvaloniaEdit.TextMate" Version="11.2.0" />
<PackageReference Include="Azure.AI.OpenAI" Version="2.2.0-beta.4" />

View file

@ -47,7 +47,6 @@ namespace SourceGit.ViewModels
public AddRemote(Repository repo)
{
_repo = repo;
View = new Views.AddRemote() { DataContext = this };
}
public static ValidationResult ValidateRemoteName(string name, ValidationContext ctx)
@ -93,15 +92,19 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = "Adding remote ...";
var log = _repo.CreateLog("Add Remote");
Use(log);
return Task.Run(() =>
{
var succ = new Commands.Remote(_repo.FullPath).Add(_name, _url);
var succ = new Commands.Remote(_repo.FullPath).Use(log).Add(_name, _url);
if (succ)
{
SetProgressDescription("Fetching from added remote ...");
new Commands.Config(_repo.FullPath).Set($"remote.{_name}.sshkey", _useSSH ? SSHKey : null);
new Commands.Fetch(_repo.FullPath, _name, false, false, SetProgressDescription).Exec();
new Commands.Config(_repo.FullPath).Use(log).Set($"remote.{_name}.sshkey", _useSSH ? SSHKey : null);
new Commands.Fetch(_repo.FullPath, _name, false, false).Use(log).Exec();
}
log.Complete();
CallUIThread(() =>
{
_repo.MarkFetched();

View file

@ -31,7 +31,6 @@ namespace SourceGit.ViewModels
public AddSubmodule(Repository repo)
{
_repo = repo;
View = new Views.AddSubmodule() { DataContext = this };
}
public static ValidationResult ValidateURL(string url, ValidationContext ctx)
@ -61,9 +60,14 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = "Adding submodule...";
var log = _repo.CreateLog("Add Submodule");
Use(log);
return Task.Run(() =>
{
var succ = new Commands.Submodule(_repo.FullPath).Add(_url, _relativePath, Recursive, SetProgressDescription);
var succ = new Commands.Submodule(_repo.FullPath).Use(log).Add(_url, _relativePath, Recursive);
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ;
});

View file

@ -78,8 +78,6 @@ namespace SourceGit.ViewModels
SelectedTrackingBranch = RemoteBranches[0];
else
SelectedTrackingBranch = string.Empty;
View = new Views.AddWorktree() { DataContext = this };
}
public static ValidationResult ValidateWorktreePath(string path, ValidationContext ctx)
@ -114,10 +112,15 @@ namespace SourceGit.ViewModels
var branchName = _selectedBranch;
var tracking = _setTrackingBranch ? SelectedTrackingBranch : string.Empty;
var log = _repo.CreateLog("Add Worktree");
Use(log);
return Task.Run(() =>
{
var succ = new Commands.Worktree(_repo.FullPath).Add(_path, branchName, _createNewBranch, tracking, SetProgressDescription);
var succ = new Commands.Worktree(_repo.FullPath).Use(log).Add(_path, branchName, _createNewBranch, tracking);
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ;
});

View file

@ -31,7 +31,6 @@ namespace SourceGit.ViewModels
_repo = repo;
SelectedWhiteSpaceMode = Models.ApplyWhiteSpaceMode.Supported[0];
View = new Views.Apply() { DataContext = this };
}
public static ValidationResult ValidatePatchFile(string file, ValidationContext _)
@ -47,9 +46,12 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = "Apply patch...";
var log = _repo.CreateLog("Apply Patch");
return Task.Run(() =>
{
var succ = new Commands.Apply(_repo.FullPath, _patchFile, _ignoreWhiteSpace, SelectedWhiteSpaceMode.Arg, null).Exec();
var succ = new Commands.Apply(_repo.FullPath, _patchFile, _ignoreWhiteSpace, SelectedWhiteSpaceMode.Arg, null).Use(log).Exec();
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ;
});

View file

@ -22,27 +22,28 @@ namespace SourceGit.ViewModels
set;
} = false;
public ApplyStash(string repo, Models.Stash stash)
public ApplyStash(Repository repo, Models.Stash stash)
{
_repo = repo;
Stash = stash;
View = new Views.ApplyStash() { DataContext = this };
}
public override Task<bool> Sure()
{
ProgressDescription = $"Applying stash: {Stash.Name}";
var log = _repo.CreateLog("Apply Stash");
return Task.Run(() =>
{
var succ = new Commands.Stash(_repo).Apply(Stash.Name, RestoreIndex);
var succ = new Commands.Stash(_repo.FullPath).Use(log).Apply(Stash.Name, RestoreIndex);
if (succ && DropAfterApply)
new Commands.Stash(_repo).Drop(Stash.Name);
new Commands.Stash(_repo.FullPath).Use(log).Drop(Stash.Name);
log.Complete();
return true;
});
}
private readonly string _repo;
private readonly Repository _repo;
}
}

View file

@ -25,7 +25,6 @@ namespace SourceGit.ViewModels
_revision = branch.Head;
_saveFile = $"archive-{Path.GetFileName(branch.Name)}.zip";
BasedOn = branch;
View = new Views.Archive() { DataContext = this };
}
public Archive(Repository repo, Models.Commit commit)
@ -34,7 +33,6 @@ namespace SourceGit.ViewModels
_revision = commit.SHA;
_saveFile = $"archive-{commit.SHA.Substring(0, 10)}.zip";
BasedOn = commit;
View = new Views.Archive() { DataContext = this };
}
public Archive(Repository repo, Models.Tag tag)
@ -43,7 +41,6 @@ namespace SourceGit.ViewModels
_revision = tag.SHA;
_saveFile = $"archive-{Path.GetFileName(tag.Name)}.zip";
BasedOn = tag;
View = new Views.Archive() { DataContext = this };
}
public override Task<bool> Sure()
@ -51,9 +48,14 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = "Archiving ...";
var log = _repo.CreateLog("Archive");
Use(log);
return Task.Run(() =>
{
var succ = new Commands.Archive(_repo.FullPath, _revision, _saveFile, SetProgressDescription).Exec();
var succ = new Commands.Archive(_repo.FullPath, _revision, _saveFile).Use(log).Exec();
log.Complete();
CallUIThread(() =>
{
_repo.SetWatcherEnabled(true);

View file

@ -9,18 +9,15 @@ namespace SourceGit.ViewModels
{
public AvaloniaList<string> Files { get; private set; }
public AssumeUnchangedManager(string repo)
public AssumeUnchangedManager(Repository repo)
{
_repo = repo;
Files = new AvaloniaList<string>();
Task.Run(() =>
{
var collect = new Commands.AssumeUnchanged(_repo).View();
Dispatcher.UIThread.Invoke(() =>
{
Files.AddRange(collect);
});
var collect = new Commands.QueryAssumeUnchangedFiles(_repo.FullPath).Result();
Dispatcher.UIThread.Invoke(() => Files.AddRange(collect));
});
}
@ -28,11 +25,13 @@ namespace SourceGit.ViewModels
{
if (!string.IsNullOrEmpty(file))
{
new Commands.AssumeUnchanged(_repo).Remove(file);
var log = _repo.CreateLog("Remove Assue Unchanged File");
new Commands.AssumeUnchanged(_repo.FullPath, file, false).Use(log).Exec();
log.Complete();
Files.Remove(file);
}
}
private readonly string _repo;
private readonly Repository _repo;
}
}

View file

@ -44,7 +44,7 @@ namespace SourceGit.ViewModels
public bool ShowUpstreamGoneTip
{
get => Backend is Models.Branch { IsUpsteamGone: true };
get => Backend is Models.Branch { IsUpstreamGone: true };
}
public string Tooltip

View file

@ -20,7 +20,6 @@ namespace SourceGit.ViewModels
_repo = repo;
Branch = branch;
DiscardLocalChanges = false;
View = new Views.Checkout() { DataContext = this };
}
public override Task<bool> Sure()
@ -28,6 +27,9 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = $"Checkout '{Branch}' ...";
var log = _repo.CreateLog($"Checkout '{Branch}'");
Use(log);
return Task.Run(() =>
{
var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result();
@ -36,15 +38,14 @@ namespace SourceGit.ViewModels
{
if (DiscardLocalChanges)
{
SetProgressDescription("Discard local changes ...");
Commands.Discard.All(_repo.FullPath, false);
Commands.Discard.All(_repo.FullPath, false, log);
}
else
{
SetProgressDescription("Stash local changes ...");
var succ = new Commands.Stash(_repo.FullPath).Push("CHECKOUT_AUTO_STASH");
var succ = new Commands.Stash(_repo.FullPath).Use(log).Push("CHECKOUT_AUTO_STASH");
if (!succ)
{
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return false;
}
@ -53,14 +54,11 @@ namespace SourceGit.ViewModels
}
}
SetProgressDescription("Checkout branch ...");
var rs = new Commands.Checkout(_repo.FullPath).Branch(Branch, SetProgressDescription);
var rs = new Commands.Checkout(_repo.FullPath).Use(log).Branch(Branch);
if (needPopStash)
{
SetProgressDescription("Re-apply local changes...");
rs = new Commands.Stash(_repo.FullPath).Pop("stash@{0}");
}
rs = new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}");
log.Complete();
CallUIThread(() =>
{

View file

@ -20,7 +20,6 @@ namespace SourceGit.ViewModels
_repo = repo;
Commit = commit;
DiscardLocalChanges = false;
View = new Views.CheckoutCommit() { DataContext = this };
}
public override Task<bool> Sure()
@ -28,6 +27,9 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = $"Checkout Commit '{Commit.SHA}' ...";
var log = _repo.CreateLog("Checkout Commit");
Use(log);
return Task.Run(() =>
{
var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result();
@ -36,15 +38,14 @@ namespace SourceGit.ViewModels
{
if (DiscardLocalChanges)
{
SetProgressDescription("Discard local changes ...");
Commands.Discard.All(_repo.FullPath, false);
Commands.Discard.All(_repo.FullPath, false, log);
}
else
{
SetProgressDescription("Stash local changes ...");
var succ = new Commands.Stash(_repo.FullPath).Push("CHECKOUT_AUTO_STASH");
var succ = new Commands.Stash(_repo.FullPath).Use(log).Push("CHECKOUT_AUTO_STASH");
if (!succ)
{
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return false;
}
@ -53,15 +54,11 @@ namespace SourceGit.ViewModels
}
}
SetProgressDescription("Checkout commit ...");
var rs = new Commands.Checkout(_repo.FullPath).Commit(Commit.SHA, SetProgressDescription);
var rs = new Commands.Checkout(_repo.FullPath).Use(log).Commit(Commit.SHA);
if (needPopStash)
{
SetProgressDescription("Re-apply local changes...");
rs = new Commands.Stash(_repo.FullPath).Pop("stash@{0}");
}
rs = new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}");
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return rs;
});

View file

@ -50,7 +50,6 @@ namespace SourceGit.ViewModels
MainlineForMergeCommit = 0;
AppendSourceToMessage = true;
AutoCommit = true;
View = new Views.CherryPick() { DataContext = this };
}
public CherryPick(Repository repo, Models.Commit merge, List<Models.Commit> parents)
@ -62,7 +61,6 @@ namespace SourceGit.ViewModels
MainlineForMergeCommit = 0;
AppendSourceToMessage = true;
AutoCommit = true;
View = new Views.CherryPick() { DataContext = this };
}
public override Task<bool> Sure()
@ -70,6 +68,9 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = $"Cherry-Pick commit(s) ...";
var log = _repo.CreateLog("Cherry-Pick");
Use(log);
return Task.Run(() =>
{
if (IsMergeCommit)
@ -79,7 +80,7 @@ namespace SourceGit.ViewModels
Targets[0].SHA,
!AutoCommit,
AppendSourceToMessage,
$"-m {MainlineForMergeCommit + 1}").Exec();
$"-m {MainlineForMergeCommit + 1}").Use(log).Exec();
}
else
{
@ -88,9 +89,10 @@ namespace SourceGit.ViewModels
string.Join(' ', Targets.ConvertAll(c => c.SHA)),
!AutoCommit,
AppendSourceToMessage,
string.Empty).Exec();
string.Empty).Use(log).Exec();
}
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return true;
});

View file

@ -7,7 +7,6 @@ namespace SourceGit.ViewModels
public Cleanup(Repository repo)
{
_repo = repo;
View = new Views.Cleanup() { DataContext = this };
}
public override Task<bool> Sure()
@ -15,9 +14,13 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = "Cleanup (GC & prune) ...";
var log = _repo.CreateLog("Cleanup (GC & prune)");
Use(log);
return Task.Run(() =>
{
new Commands.GC(_repo.FullPath, SetProgressDescription).Exec();
new Commands.GC(_repo.FullPath).Use(log).Exec();
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return true;
});

View file

@ -7,7 +7,6 @@ namespace SourceGit.ViewModels
public ClearStashes(Repository repo)
{
_repo = repo;
View = new Views.ClearStashes() { DataContext = this };
}
public override Task<bool> Sure()
@ -15,9 +14,13 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = "Clear all stashes...";
var log = _repo.CreateLog("Clear Stashes");
Use(log);
return Task.Run(() =>
{
new Commands.Stash(_repo.FullPath).Clear();
new Commands.Stash(_repo.FullPath).Use(log).Clear();
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return true;
});

View file

@ -62,7 +62,11 @@ namespace SourceGit.ViewModels
public Clone(string pageId)
{
_pageId = pageId;
View = new Views.Clone() { DataContext = this };
var activeWorkspace = Preferences.Instance.GetActiveWorkspace();
_parentFolder = activeWorkspace?.DefaultCloneDir;
if (string.IsNullOrEmpty(ParentFolder))
_parentFolder = Preferences.Instance.GitDefaultCloneDir;
Task.Run(async () =>
{
@ -70,9 +74,7 @@ namespace SourceGit.ViewModels
{
var text = await App.GetClipboardTextAsync();
if (Models.Remote.IsValidURL(text))
{
Dispatcher.UIThread.Invoke(() => Remote = text);
}
}
catch
{
@ -99,9 +101,13 @@ namespace SourceGit.ViewModels
{
ProgressDescription = "Clone ...";
// Create a temp log.
var log = new CommandLog("Clone");
Use(log);
return Task.Run(() =>
{
var cmd = new Commands.Clone(_pageId, _parentFolder, _remote, _local, _useSSH ? _sshKey : "", _extraArgs, SetProgressDescription);
var cmd = new Commands.Clone(_pageId, _parentFolder, _remote, _local, _useSSH ? _sshKey : "", _extraArgs).Use(log);
if (!cmd.Exec())
return false;
@ -138,12 +144,11 @@ namespace SourceGit.ViewModels
{
var submoduleList = new Commands.QuerySubmodules(path).Result();
foreach (var submodule in submoduleList)
{
var update = new Commands.Submodule(path);
update.Update(submodule.Path, true, true, false, SetProgressDescription);
}
new Commands.Submodule(path).Use(log).Update(submodule.Path, true, true, false);
}
log.Complete();
CallUIThread(() =>
{
var node = Preferences.Instance.FindOrAddNodeByRepositoryPath(path, null, true);
@ -170,7 +175,7 @@ namespace SourceGit.ViewModels
private string _remote = string.Empty;
private bool _useSSH = false;
private string _sshKey = string.Empty;
private string _parentFolder = Preferences.Instance.GitDefaultCloneDir;
private string _parentFolder = string.Empty;
private string _local = string.Empty;
private string _extraArgs = string.Empty;
}

View file

@ -0,0 +1,96 @@
using System;
using System.Text;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
{
public class CommandLog : ObservableObject, Models.ICommandLog
{
public string Name
{
get;
private set;
} = string.Empty;
public DateTime Time
{
get;
} = DateTime.Now;
public string TimeStr
{
get => Time.ToString("T");
}
public bool IsComplete
{
get;
private set;
} = false;
public string Content
{
get
{
return IsComplete ? _content : _builder.ToString();
}
}
public CommandLog(string name)
{
Name = name;
}
public void Register(Action<string> handler)
{
if (!IsComplete)
_onNewLineReceived += handler;
}
public void AppendLine(string line = null)
{
var newline = line ?? string.Empty;
Dispatcher.UIThread.Invoke(() =>
{
_builder.AppendLine(newline);
_onNewLineReceived?.Invoke(newline);
});
}
public void Complete()
{
IsComplete = true;
Dispatcher.UIThread.Invoke(() =>
{
_content = _builder.ToString();
_builder.Clear();
_builder = null;
OnPropertyChanged(nameof(IsComplete));
if (_onNewLineReceived != null)
{
var dumpHandlers = _onNewLineReceived.GetInvocationList();
foreach (var d in dumpHandlers)
_onNewLineReceived -= (Action<string>)d;
}
});
}
private string _content = string.Empty;
private StringBuilder _builder = new StringBuilder();
private event Action<string> _onNewLineReceived;
}
public static class CommandExtensions
{
public static T Use<T>(this T cmd, CommandLog log) where T : Commands.Command
{
cmd.Log = log;
return cmd;
}
}
}

View file

@ -391,7 +391,9 @@ namespace SourceGit.ViewModels
resetToThisRevision.Icon = App.CreateMenuIcon("Icons.File.Checkout");
resetToThisRevision.Click += (_, ev) =>
{
new Commands.Checkout(_repo.FullPath).FileWithRevision(change.Path, $"{_commit.SHA}");
var log = _repo.CreateLog($"Reset File to '{_commit.SHA}'");
new Commands.Checkout(_repo.FullPath).Use(log).FileWithRevision(change.Path, $"{_commit.SHA}");
log.Complete();
ev.Handled = true;
};
@ -401,10 +403,12 @@ namespace SourceGit.ViewModels
resetToFirstParent.IsEnabled = _commit.Parents.Count > 0;
resetToFirstParent.Click += (_, ev) =>
{
var log = _repo.CreateLog($"Reset File to '{_commit.SHA}~1'");
if (change.Index == Models.ChangeState.Renamed)
new Commands.Checkout(_repo.FullPath).FileWithRevision(change.OriginalPath, $"{_commit.SHA}~1");
new Commands.Checkout(_repo.FullPath).Use(log).FileWithRevision(change.OriginalPath, $"{_commit.SHA}~1");
new Commands.Checkout(_repo.FullPath).FileWithRevision(change.Path, $"{_commit.SHA}~1");
new Commands.Checkout(_repo.FullPath).Use(log).FileWithRevision(change.Path, $"{_commit.SHA}~1");
log.Complete();
ev.Handled = true;
};
@ -530,7 +534,9 @@ namespace SourceGit.ViewModels
resetToThisRevision.IsEnabled = File.Exists(fullPath);
resetToThisRevision.Click += (_, ev) =>
{
new Commands.Checkout(_repo.FullPath).FileWithRevision(file.Path, $"{_commit.SHA}");
var log = _repo.CreateLog($"Reset File to '{_commit.SHA}'");
new Commands.Checkout(_repo.FullPath).Use(log).FileWithRevision(file.Path, $"{_commit.SHA}");
log.Complete();
ev.Handled = true;
};
@ -542,7 +548,9 @@ namespace SourceGit.ViewModels
resetToFirstParent.IsEnabled = _commit.Parents.Count > 0 && fileIndex != Models.ChangeState.Renamed;
resetToFirstParent.Click += (_, ev) =>
{
new Commands.Checkout(_repo.FullPath).FileWithRevision(file.Path, $"{_commit.SHA}~1");
var log = _repo.CreateLog($"Reset File to '{_commit.SHA}~1'");
new Commands.Checkout(_repo.FullPath).Use(log).FileWithRevision(file.Path, $"{_commit.SHA}~1");
log.Complete();
ev.Handled = true;
};
@ -737,10 +745,12 @@ namespace SourceGit.ViewModels
{
lfsLock.Click += async (_, e) =>
{
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(_repo.Remotes[0].Name, path));
var log = _repo.CreateLog("Lock LFS file");
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(_repo.Remotes[0].Name, path, log));
if (succ)
App.SendNotification(_repo.FullPath, $"Lock file \"{path}\" successfully!");
log.Complete();
e.Handled = true;
};
}
@ -753,10 +763,12 @@ namespace SourceGit.ViewModels
lockRemote.Header = remoteName;
lockRemote.Click += async (_, e) =>
{
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(remoteName, path));
var log = _repo.CreateLog("Lock LFS file");
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(remoteName, path, log));
if (succ)
App.SendNotification(_repo.FullPath, $"Lock file \"{path}\" successfully!");
log.Complete();
e.Handled = true;
};
lfsLock.Items.Add(lockRemote);
@ -772,10 +784,12 @@ namespace SourceGit.ViewModels
{
lfsUnlock.Click += async (_, e) =>
{
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(_repo.Remotes[0].Name, path, false));
var log = _repo.CreateLog("Unlock LFS file");
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(_repo.Remotes[0].Name, path, false, log));
if (succ)
App.SendNotification(_repo.FullPath, $"Unlock file \"{path}\" successfully!");
log.Complete();
e.Handled = true;
};
}
@ -788,10 +802,12 @@ namespace SourceGit.ViewModels
unlockRemote.Header = remoteName;
unlockRemote.Click += async (_, e) =>
{
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(remoteName, path, false));
var log = _repo.CreateLog("Unlock LFS file");
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(remoteName, path, false, log));
if (succ)
App.SendNotification(_repo.FullPath, $"Unlock file \"{path}\" successfully!");
log.Complete();
e.Handled = true;
};
lfsUnlock.Items.Add(unlockRemote);

View file

@ -46,7 +46,7 @@
_wc = wc;
_change = change;
IsResolved = new Commands.IsConflictResolved(repo.FullPath, change).ReadToEnd().IsSuccess;
IsResolved = new Commands.IsConflictResolved(repo.FullPath, change).Result();
var context = wc.InProgressContext;
if (context is CherryPickInProgress cherryPick)

View file

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using System;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Text;
@ -46,9 +47,9 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _closedIssue, value);
}
public ConventionalCommitMessageBuilder(WorkingCopy wc)
public ConventionalCommitMessageBuilder(Action<string> onApply)
{
_wc = wc;
_onApply = onApply;
}
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode")]
@ -98,11 +99,11 @@ namespace SourceGit.ViewModels
builder.Append(_closedIssue);
}
_wc.CommitMessage = builder.ToString();
_onApply?.Invoke(builder.ToString());
return true;
}
private WorkingCopy _wc = null;
private Action<string> _onApply = null;
private Models.ConventionalCommitType _type = Models.ConventionalCommitType.Supported[0];
private string _scope = string.Empty;
private string _description = string.Empty;

View file

@ -48,7 +48,6 @@ namespace SourceGit.ViewModels
BasedOn = branch;
DiscardLocalChanges = false;
View = new Views.CreateBranch() { DataContext = this };
}
public CreateBranch(Repository repo, Models.Commit commit)
@ -58,7 +57,6 @@ namespace SourceGit.ViewModels
BasedOn = commit;
DiscardLocalChanges = false;
View = new Views.CreateBranch() { DataContext = this };
}
public CreateBranch(Repository repo, Models.Tag tag)
@ -68,7 +66,6 @@ namespace SourceGit.ViewModels
BasedOn = tag;
DiscardLocalChanges = false;
View = new Views.CreateBranch() { DataContext = this };
}
public static ValidationResult ValidateBranchName(string name, ValidationContext ctx)
@ -92,9 +89,12 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
var fixedName = FixName(_name);
var log = _repo.CreateLog($"Create Branch '{fixedName}'");
Use(log);
return Task.Run(() =>
{
var succ = false;
bool succ;
if (CheckoutAfterCreated && !_repo.IsBare)
{
var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result();
@ -103,15 +103,14 @@ namespace SourceGit.ViewModels
{
if (DiscardLocalChanges)
{
SetProgressDescription("Discard local changes...");
Commands.Discard.All(_repo.FullPath, false);
Commands.Discard.All(_repo.FullPath, false, log);
}
else
{
SetProgressDescription("Stash local changes");
succ = new Commands.Stash(_repo.FullPath).Push("CREATE_BRANCH_AUTO_STASH");
succ = new Commands.Stash(_repo.FullPath).Use(log).Push("CREATE_BRANCH_AUTO_STASH");
if (!succ)
{
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return false;
}
@ -120,21 +119,17 @@ namespace SourceGit.ViewModels
}
}
SetProgressDescription($"Create new branch '{fixedName}'");
succ = new Commands.Checkout(_repo.FullPath).Branch(fixedName, _baseOnRevision, SetProgressDescription);
succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(fixedName, _baseOnRevision);
if (needPopStash)
{
SetProgressDescription("Re-apply local changes...");
new Commands.Stash(_repo.FullPath).Pop("stash@{0}");
}
new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}");
}
else
{
SetProgressDescription($"Create new branch '{fixedName}'");
succ = Commands.Branch.Create(_repo.FullPath, fixedName, _baseOnRevision);
succ = Commands.Branch.Create(_repo.FullPath, fixedName, _baseOnRevision, log);
}
log.Complete();
CallUIThread(() =>
{
if (succ && CheckoutAfterCreated)

View file

@ -16,7 +16,6 @@ namespace SourceGit.ViewModels
public CreateGroup(RepositoryNode parent)
{
_parent = parent;
View = new Views.CreateGroup() { DataContext = this };
}
public override Task<bool> Sure()

View file

@ -52,7 +52,6 @@ namespace SourceGit.ViewModels
BasedOn = branch;
SignTag = new Commands.Config(repo.FullPath).Get("tag.gpgsign").Equals("true", StringComparison.OrdinalIgnoreCase);
View = new Views.CreateTag() { DataContext = this };
}
public CreateTag(Repository repo, Models.Commit commit)
@ -62,7 +61,6 @@ namespace SourceGit.ViewModels
BasedOn = commit;
SignTag = new Commands.Config(repo.FullPath).Get("tag.gpgsign").Equals("true", StringComparison.OrdinalIgnoreCase);
View = new Views.CreateTag() { DataContext = this };
}
public static ValidationResult ValidateTagName(string name, ValidationContext ctx)
@ -83,23 +81,24 @@ namespace SourceGit.ViewModels
ProgressDescription = "Create tag...";
var remotes = PushToRemotes ? _repo.Remotes : null;
var log = _repo.CreateLog("Create Tag");
Use(log);
return Task.Run(() =>
{
bool succ;
if (_annotated)
succ = Commands.Tag.Add(_repo.FullPath, _tagName, _basedOn, Message, SignTag);
succ = Commands.Tag.Add(_repo.FullPath, _tagName, _basedOn, Message, SignTag, log);
else
succ = Commands.Tag.Add(_repo.FullPath, _tagName, _basedOn);
succ = Commands.Tag.Add(_repo.FullPath, _tagName, _basedOn, log);
if (succ && remotes != null)
{
foreach (var remote in remotes)
{
SetProgressDescription($"Pushing tag to remote {remote.Name} ...");
new Commands.Push(_repo.FullPath, remote.Name, $"refs/tags/{_tagName}", false).Exec();
}
new Commands.Push(_repo.FullPath, remote.Name, $"refs/tags/{_tagName}", false).Use(log).Exec();
}
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ;
});

View file

@ -7,16 +7,14 @@ namespace SourceGit.ViewModels
public Models.Branch Target
{
get;
private set;
}
public Models.Branch TrackingRemoteBranch
{
get;
private set;
}
public object DeleteTrackingRemoteTip
public string DeleteTrackingRemoteTip
{
get;
private set;
@ -37,10 +35,8 @@ namespace SourceGit.ViewModels
{
TrackingRemoteBranch = repo.Branches.Find(x => x.FullName == branch.Upstream);
if (TrackingRemoteBranch != null)
DeleteTrackingRemoteTip = new Views.NameHighlightedTextBlock("DeleteBranch.WithTrackingRemote", TrackingRemoteBranch.FriendlyName);
DeleteTrackingRemoteTip = App.Text("DeleteBranch.WithTrackingRemote", TrackingRemoteBranch.FriendlyName);
}
View = new Views.DeleteBranch() { DataContext = this };
}
public override Task<bool> Sure()
@ -48,23 +44,25 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = "Deleting branch...";
var log = _repo.CreateLog("Delete Branch");
Use(log);
return Task.Run(() =>
{
if (Target.IsLocal)
{
Commands.Branch.DeleteLocal(_repo.FullPath, Target.Name);
Commands.Branch.DeleteLocal(_repo.FullPath, Target.Name, log);
if (_alsoDeleteTrackingRemote && TrackingRemoteBranch != null)
{
SetProgressDescription("Deleting remote-tracking branch...");
Commands.Branch.DeleteRemote(_repo.FullPath, TrackingRemoteBranch.Remote, TrackingRemoteBranch.Name);
}
Commands.Branch.DeleteRemote(_repo.FullPath, TrackingRemoteBranch.Remote, TrackingRemoteBranch.Name, log);
}
else
{
Commands.Branch.DeleteRemote(_repo.FullPath, Target.Remote, Target.Name);
Commands.Branch.DeleteRemote(_repo.FullPath, Target.Remote, Target.Name, log);
}
log.Complete();
CallUIThread(() =>
{
_repo.MarkBranchesDirtyManually();

View file

@ -15,7 +15,6 @@ namespace SourceGit.ViewModels
_repo = repo;
_isLocal = isLocal;
Targets = branches;
View = new Views.DeleteMultipleBranches() { DataContext = this };
}
public override Task<bool> Sure()
@ -23,25 +22,24 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = "Deleting multiple branches...";
var log = _repo.CreateLog("Delete Multiple Branches");
Use(log);
return Task.Run(() =>
{
if (_isLocal)
{
foreach (var target in Targets)
{
SetProgressDescription($"Deleting local branch : {target.Name}");
Commands.Branch.DeleteLocal(_repo.FullPath, target.Name);
}
Commands.Branch.DeleteLocal(_repo.FullPath, target.Name, log);
}
else
{
foreach (var target in Targets)
{
SetProgressDescription($"Deleting remote branch : {target.FriendlyName}");
Commands.Branch.DeleteRemote(_repo.FullPath, target.Remote, target.Name);
}
Commands.Branch.DeleteRemote(_repo.FullPath, target.Remote, target.Name, log);
}
log.Complete();
CallUIThread(() =>
{
_repo.MarkBranchesDirtyManually();

View file

@ -14,7 +14,6 @@ namespace SourceGit.ViewModels
{
_repo = repo;
Remote = remote;
View = new Views.DeleteRemote() { DataContext = this };
}
public override Task<bool> Sure()
@ -22,9 +21,14 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = "Deleting remote ...";
var log = _repo.CreateLog("Delete Remote");
Use(log);
return Task.Run(() =>
{
var succ = new Commands.Remote(_repo.FullPath).Delete(Remote.Name);
var succ = new Commands.Remote(_repo.FullPath).Use(log).Delete(Remote.Name);
log.Complete();
CallUIThread(() =>
{
_repo.MarkBranchesDirtyManually();

View file

@ -6,23 +6,19 @@ namespace SourceGit.ViewModels
{
public RepositoryNode Node
{
get => _node;
set => SetProperty(ref _node, value);
get;
}
public DeleteRepositoryNode(RepositoryNode node)
{
_node = node;
View = new Views.DeleteRepositoryNode() { DataContext = this };
Node = node;
}
public override Task<bool> Sure()
{
Preferences.Instance.RemoveNode(_node, true);
Preferences.Instance.RemoveNode(Node, true);
Welcome.Instance.Refresh();
return null;
}
private RepositoryNode _node = null;
}
}

View file

@ -4,7 +4,6 @@ namespace SourceGit.ViewModels
{
public class DeleteSubmodule : Popup
{
public string Submodule
{
get;
@ -15,7 +14,6 @@ namespace SourceGit.ViewModels
{
_repo = repo;
Submodule = submodule;
View = new Views.DeleteSubmodule() { DataContext = this };
}
public override Task<bool> Sure()
@ -23,9 +21,13 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = "Deleting submodule ...";
var log = _repo.CreateLog("Delete Submodule");
Use(log);
return Task.Run(() =>
{
var succ = new Commands.Submodule(_repo.FullPath).Delete(Submodule);
var succ = new Commands.Submodule(_repo.FullPath).Use(log).Delete(Submodule);
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ;
});

View file

@ -20,7 +20,6 @@ namespace SourceGit.ViewModels
{
_repo = repo;
Target = tag;
View = new Views.DeleteTag() { DataContext = this };
}
public override Task<bool> Sure()
@ -28,10 +27,21 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = $"Deleting tag '{Target.Name}' ...";
var remotes = PushToRemotes ? _repo.Remotes : null;
var remotes = PushToRemotes ? _repo.Remotes : [];
var log = _repo.CreateLog("Delete Tag");
Use(log);
return Task.Run(() =>
{
var succ = Commands.Tag.Delete(_repo.FullPath, Target.Name, remotes);
var succ = Commands.Tag.Delete(_repo.FullPath, Target.Name, log);
if (succ)
{
foreach (var r in remotes)
new Commands.Push(_repo.FullPath, r.Name, $"refs/tags/{Target.Name}", true).Use(log).Exec();
}
log.Complete();
CallUIThread(() =>
{
_repo.MarkTagsDirtyManually();

View file

@ -19,11 +19,15 @@ namespace SourceGit.ViewModels
public bool IgnoreWhitespace
{
get => _ignoreWhitespace;
get => Preferences.Instance.IgnoreWhitespaceChangesInDiff;
set
{
if (SetProperty(ref _ignoreWhitespace, value))
if (value != Preferences.Instance.IgnoreWhitespaceChangesInDiff)
{
Preferences.Instance.IgnoreWhitespaceChangesInDiff = value;
OnPropertyChanged();
LoadDiffContent();
}
}
}
@ -62,7 +66,6 @@ namespace SourceGit.ViewModels
_content = previous._content;
_fileModeChange = previous._fileModeChange;
_unifiedLines = previous._unifiedLines;
_ignoreWhitespace = previous._ignoreWhitespace;
_info = previous._info;
}
@ -114,8 +117,9 @@ namespace SourceGit.ViewModels
// There is no way to tell a git-diff to use "ALL lines of context",
// so instead we set a very high number for the "lines of context" parameter.
var numLines = Preferences.Instance.UseFullTextDiff ? 999999999 : _unifiedLines;
var latest = new Commands.Diff(_repo, _option, numLines, _ignoreWhitespace).Result();
var info = new Info(_option, numLines, _ignoreWhitespace, latest);
var ignoreWS = Preferences.Instance.IgnoreWhitespaceChangesInDiff;
var latest = new Commands.Diff(_repo, _option, numLines, ignoreWS).Result();
var info = new Info(_option, numLines, ignoreWS, latest);
if (_info != null && info.IsSame(_info))
return;
@ -287,7 +291,6 @@ namespace SourceGit.ViewModels
private string _fileModeChange = string.Empty;
private int _unifiedLines = 4;
private bool _isTextDiff = false;
private bool _ignoreWhitespace = false;
private object _content = null;
private Info _info = null;
}

View file

@ -40,9 +40,7 @@ namespace SourceGit.ViewModels
public Discard(Repository repo)
{
_repo = repo;
Mode = new DiscardAllMode();
View = new Views.Discard { DataContext = this };
}
public Discard(Repository repo, List<Models.Change> changes)
@ -56,8 +54,6 @@ namespace SourceGit.ViewModels
Mode = new DiscardSingleFile() { Path = _changes[0].Path };
else
Mode = new DiscardMultipleFiles() { Count = _changes.Count };
View = new Views.Discard() { DataContext = this };
}
public override Task<bool> Sure()
@ -65,12 +61,17 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = _changes == null ? "Discard all local changes ..." : $"Discard total {_changes.Count} changes ...";
var log = _repo.CreateLog("Discard all");
Use(log);
return Task.Run(() =>
{
if (Mode is DiscardAllMode all)
Commands.Discard.All(_repo.FullPath, all.IncludeIgnored);
Commands.Discard.All(_repo.FullPath, all.IncludeIgnored, log);
else
Commands.Discard.Changes(_repo.FullPath, _changes);
Commands.Discard.Changes(_repo.FullPath, _changes, log);
log.Complete();
CallUIThread(() =>
{

View file

@ -4,26 +4,29 @@ namespace SourceGit.ViewModels
{
public class DropStash : Popup
{
public Models.Stash Stash { get; private set; }
public Models.Stash Stash { get; }
public DropStash(string repo, Models.Stash stash)
public DropStash(Repository repo, Models.Stash stash)
{
_repo = repo;
Stash = stash;
View = new Views.DropStash() { DataContext = this };
}
public override Task<bool> Sure()
{
ProgressDescription = $"Dropping stash: {Stash.Name}";
var log = _repo.CreateLog("Drop Stash");
Use(log);
return Task.Run(() =>
{
new Commands.Stash(_repo).Drop(Stash.Name);
new Commands.Stash(_repo.FullPath).Use(log).Drop(Stash.Name);
log.Complete();
return true;
});
}
private readonly string _repo;
private readonly Repository _repo;
}
}

View file

@ -56,8 +56,6 @@ namespace SourceGit.ViewModels
{
SSHKey = new Commands.Config(repo.FullPath).Get($"remote.{remote.Name}.sshkey");
}
View = new Views.EditRemote() { DataContext = this };
}
public static ValidationResult ValidateRemoteName(string name, ValidationContext ctx)
@ -127,7 +125,6 @@ namespace SourceGit.ViewModels
if (pushURL != _url)
new Commands.Remote(_repo.FullPath).SetURL(_name, _url, true);
SetProgressDescription("Post processing ...");
new Commands.Config(_repo.FullPath).Set($"remote.{_name}.sshkey", _useSSH ? SSHKey : null);
CallUIThread(() => _repo.SetWatcherEnabled(true));

View file

@ -37,8 +37,6 @@ namespace SourceGit.ViewModels
_name = node.Name;
_isRepository = node.IsRepository;
_bookmark = node.Bookmark;
View = new Views.EditRepositoryNode() { DataContext = this };
}
public override Task<bool> Sure()

View file

@ -8,7 +8,6 @@ namespace SourceGit.ViewModels
public Models.CustomAction CustomAction
{
get;
private set;
}
public ExecuteCustomAction(Repository repo, Models.CustomAction action)
@ -16,7 +15,6 @@ namespace SourceGit.ViewModels
_repo = repo;
_args = action.Arguments.Replace("${REPO}", GetWorkdir());
CustomAction = action;
View = new Views.ExecuteCustomAction() { DataContext = this };
}
public ExecuteCustomAction(Repository repo, Models.CustomAction action, Models.Branch branch)
@ -24,7 +22,6 @@ namespace SourceGit.ViewModels
_repo = repo;
_args = action.Arguments.Replace("${REPO}", GetWorkdir()).Replace("${BRANCH}", branch.FriendlyName);
CustomAction = action;
View = new Views.ExecuteCustomAction() { DataContext = this };
}
public ExecuteCustomAction(Repository repo, Models.CustomAction action, Models.Commit commit)
@ -32,7 +29,6 @@ namespace SourceGit.ViewModels
_repo = repo;
_args = action.Arguments.Replace("${REPO}", GetWorkdir()).Replace("${SHA}", commit.SHA);
CustomAction = action;
View = new Views.ExecuteCustomAction() { DataContext = this };
}
public override Task<bool> Sure()
@ -43,7 +39,7 @@ namespace SourceGit.ViewModels
return Task.Run(() =>
{
if (CustomAction.WaitForExit)
Commands.ExecuteCustomAction.RunAndWait(_repo.FullPath, CustomAction.Executable, _args, SetProgressDescription);
Commands.ExecuteCustomAction.RunAndWait(_repo.FullPath, CustomAction.Executable, _args, output => CallUIThread(() => ProgressDescription = output));
else
Commands.ExecuteCustomAction.Run(_repo.FullPath, CustomAction.Executable, _args);
@ -58,6 +54,6 @@ namespace SourceGit.ViewModels
}
private readonly Repository _repo = null;
private string _args = string.Empty;
private readonly string _args;
}
}

View file

@ -7,13 +7,11 @@ namespace SourceGit.ViewModels
public Models.Branch Local
{
get;
private set;
}
public Models.Branch To
{
get;
private set;
}
public FastForwardWithoutCheckout(Repository repo, Models.Branch local, Models.Branch upstream)
@ -21,7 +19,6 @@ namespace SourceGit.ViewModels
_repo = repo;
Local = local;
To = upstream;
View = new Views.FastForwardWithoutCheckout() { DataContext = this };
}
public override Task<bool> Sure()
@ -29,10 +26,18 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = "Fast-Forward ...";
var log = _repo.CreateLog("Fast-Forward (No checkout)");
Use(log);
return Task.Run(() =>
{
new Commands.UpdateRef(_repo.FullPath, Local.FullName, To.FullName, SetProgressDescription).Exec();
CallUIThread(() => _repo.SetWatcherEnabled(true));
new Commands.UpdateRef(_repo.FullPath, Local.FullName, To.FullName).Use(log).Exec();
log.Complete();
CallUIThread(() =>
{
_repo.NavigateToCommit(To.Head);
_repo.SetWatcherEnabled(true);
});
return true;
});
}

View file

@ -34,14 +34,14 @@ namespace SourceGit.ViewModels
set => _repo.Settings.EnableForceOnFetch = value;
}
public Fetch(Repository repo, Models.Remote preferedRemote = null)
public Fetch(Repository repo, Models.Remote preferredRemote = null)
{
_repo = repo;
_fetchAllRemotes = preferedRemote == null;
_fetchAllRemotes = preferredRemote == null;
if (preferedRemote != null)
if (preferredRemote != null)
{
SelectedRemote = preferedRemote;
SelectedRemote = preferredRemote;
}
else if (!string.IsNullOrEmpty(_repo.Settings.DefaultRemote))
{
@ -55,8 +55,6 @@ namespace SourceGit.ViewModels
{
SelectedRemote = _repo.Remotes[0];
}
View = new Views.Fetch() { DataContext = this };
}
public override Task<bool> Sure()
@ -65,24 +63,26 @@ namespace SourceGit.ViewModels
var notags = _repo.Settings.FetchWithoutTags;
var force = _repo.Settings.EnableForceOnFetch;
var log = _repo.CreateLog("Fetch");
Use(log);
return Task.Run(() =>
{
if (FetchAllRemotes)
{
foreach (var remote in _repo.Remotes)
{
SetProgressDescription($"Fetching remote: {remote.Name}");
new Commands.Fetch(_repo.FullPath, remote.Name, notags, force, SetProgressDescription).Exec();
}
new Commands.Fetch(_repo.FullPath, remote.Name, notags, force).Use(log).Exec();
}
else
{
SetProgressDescription($"Fetching remote: {SelectedRemote.Name}");
new Commands.Fetch(_repo.FullPath, SelectedRemote.Name, notags, force, SetProgressDescription).Exec();
new Commands.Fetch(_repo.FullPath, SelectedRemote.Name, notags, force).Use(log).Exec();
}
log.Complete();
CallUIThread(() =>
{
_repo.NavigateToBranchDelayed(_repo.CurrentBranch?.Upstream);
_repo.MarkFetched();
_repo.SetWatcherEnabled(true);
});

View file

@ -7,13 +7,11 @@ namespace SourceGit.ViewModels
public Models.Branch Local
{
get;
private set;
}
public Models.Branch Upstream
{
get;
private set;
}
public FetchInto(Repository repo, Models.Branch local, Models.Branch upstream)
@ -21,7 +19,6 @@ namespace SourceGit.ViewModels
_repo = repo;
Local = local;
Upstream = upstream;
View = new Views.FetchInto() { DataContext = this };
}
public override Task<bool> Sure()
@ -29,10 +26,18 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = "Fast-Forward ...";
var log = _repo.CreateLog($"Fetch Into '{Local.FriendlyName}'");
Use(log);
return Task.Run(() =>
{
new Commands.Fetch(_repo.FullPath, Local, Upstream, SetProgressDescription).Exec();
CallUIThread(() => _repo.SetWatcherEnabled(true));
new Commands.Fetch(_repo.FullPath, Local, Upstream).Use(log).Exec();
log.Complete();
CallUIThread(() =>
{
_repo.NavigateToBranchDelayed(Upstream.FullName);
_repo.SetWatcherEnabled(true);
});
return true;
});
}

View file

@ -7,8 +7,7 @@ namespace SourceGit.ViewModels
public Models.Branch Branch
{
get;
set;
} = null;
}
public bool IsFeature => _type == "feature";
public bool IsRelease => _type == "release";
@ -25,19 +24,23 @@ namespace SourceGit.ViewModels
_repo = repo;
_type = type;
_prefix = prefix;
Branch = branch;
View = new Views.GitFlowFinish() { DataContext = this };
}
public override Task<bool> Sure()
{
_repo.SetWatcherEnabled(false);
var name = Branch.Name.StartsWith(_prefix) ? Branch.Name.Substring(_prefix.Length) : Branch.Name;
ProgressDescription = $"Git Flow - finishing {_type} {name} ...";
var log = _repo.CreateLog("Gitflow - Finish");
Use(log);
return Task.Run(() =>
{
var name = Branch.Name.StartsWith(_prefix) ? Branch.Name.Substring(_prefix.Length) : Branch.Name;
SetProgressDescription($"Git Flow - finishing {_type} {name} ...");
var succ = Commands.GitFlow.Finish(_repo.FullPath, _type, name, KeepBranch);
var succ = Commands.GitFlow.Finish(_repo.FullPath, _type, name, KeepBranch, log);
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ;
});

View file

@ -28,8 +28,6 @@ namespace SourceGit.ViewModels
_repo = repo;
_type = type;
_prefix = Commands.GitFlow.GetPrefix(repo.FullPath, type);
View = new Views.GitFlowStart() { DataContext = this };
}
public static ValidationResult ValidateBranchName(string name, ValidationContext ctx)
@ -50,10 +48,15 @@ namespace SourceGit.ViewModels
public override Task<bool> Sure()
{
_repo.SetWatcherEnabled(false);
ProgressDescription = $"Git Flow - starting {_type} {_name} ...";
var log = _repo.CreateLog("Gitflow - Start");
Use(log);
return Task.Run(() =>
{
SetProgressDescription($"Git Flow - starting {_type} {_name} ...");
var succ = Commands.GitFlow.Start(_repo.FullPath, _type, _name);
var succ = Commands.GitFlow.Start(_repo.FullPath, _type, _name, log);
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ;
});

Some files were not shown because too many files have changed in this diff Show more