Merge branch 'release/v2025.04'

This commit is contained in:
leo 2025-02-10 10:05:23 +08:00
commit 7fc7c8fdb6
No known key found for this signature in database
83 changed files with 1829 additions and 913 deletions

View file

@ -47,7 +47,7 @@
## Translation Status
[![en_US](https://img.shields.io/badge/en__US-100%25-brightgreen)](TRANSLATION.md) [![de__DE](https://img.shields.io/badge/de__DE-100.00%25-brightgreen)](TRANSLATION.md) [![es__ES](https://img.shields.io/badge/es__ES-100.00%25-brightgreen)](TRANSLATION.md) [![fr__FR](https://img.shields.io/badge/fr__FR-94.69%25-yellow)](TRANSLATION.md) [![it__IT](https://img.shields.io/badge/it__IT-93.32%25-yellow)](TRANSLATION.md) [![pt__BR](https://img.shields.io/badge/pt__BR-94.41%25-yellow)](TRANSLATION.md) [![ru__RU](https://img.shields.io/badge/ru__RU-100.00%25-brightgreen)](TRANSLATION.md) [![zh__CN](https://img.shields.io/badge/zh__CN-100.00%25-brightgreen)](TRANSLATION.md) [![zh__TW](https://img.shields.io/badge/zh__TW-100.00%25-brightgreen)](TRANSLATION.md)
[![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen)](TRANSLATION.md) [![de__DE](https://img.shields.io/badge/de__DE-98.13%25-yellow)](TRANSLATION.md) [![es__ES](https://img.shields.io/badge/es__ES-98.13%25-yellow)](TRANSLATION.md) [![fr__FR](https://img.shields.io/badge/fr__FR-92.91%25-yellow)](TRANSLATION.md) [![it__IT](https://img.shields.io/badge/it__IT-98.40%25-yellow)](TRANSLATION.md) [![pt__BR](https://img.shields.io/badge/pt__BR-92.65%25-yellow)](TRANSLATION.md) [![ru__RU](https://img.shields.io/badge/ru__RU-98.13%25-yellow)](TRANSLATION.md) [![zh__CN](https://img.shields.io/badge/zh__CN-%E2%88%9A-brightgreen)](TRANSLATION.md) [![zh__TW](https://img.shields.io/badge/zh__TW-%E2%88%9A-brightgreen)](TRANSLATION.md)
> [!NOTE]
> You can find the missing keys in [TRANSLATION.md](TRANSLATION.md)
@ -136,11 +136,11 @@ This software supports using OpenAI or other AI service that has an OpenAI comap
For `OpenAI`:
* `Server` must be `https://api.openai.com/v1/chat/completions`
* `Server` must be `https://api.openai.com/v1`
For other AI service:
* The `Server` should fill in a URL equivalent to OpenAI's `https://api.openai.com/v1/chat/completions`. For example, when using `Ollama`, it should be `http://localhost:11434/v1/chat/completions` instead of `http://localhost:11434/api/generate`
* The `Server` should fill in a URL equivalent to OpenAI's `https://api.openai.com/v1`. For example, when using `Ollama`, it should be `http://localhost:11434/v1` instead of `http://localhost:11434/api/generate`
* The `API Key` is optional that depends on the service
## External Tools

View file

@ -1,29 +1,66 @@
### de_DE.axaml: 100.00%
### de_DE.axaml: 98.13%
<details>
<summary>Missing Keys</summary>
- Text.AIAssistant.Regen
- Text.AIAssistant.Use
- Text.ApplyStash
- Text.ApplyStash.DropAfterApply
- Text.ApplyStash.RestoreIndex
- Text.ApplyStash.Stash
- Text.Clone.RecurseSubmodules
- Text.CreateBranch.Name.WarnSpace
- Text.DeleteRepositoryNode.Path
- Text.DeleteRepositoryNode.TipForGroup
- Text.DeleteRepositoryNode.TipForRepository
- Text.Stash.AutoRestore
- Text.Stash.AutoRestore.Tip
- Text.WorkingCopy.SignOff
</details>
### es_ES.axaml: 100.00%
### es_ES.axaml: 98.13%
<details>
<summary>Missing Keys</summary>
- Text.AIAssistant.Regen
- Text.AIAssistant.Use
- Text.ApplyStash
- Text.ApplyStash.DropAfterApply
- Text.ApplyStash.RestoreIndex
- Text.ApplyStash.Stash
- Text.Clone.RecurseSubmodules
- Text.CreateBranch.Name.WarnSpace
- Text.DeleteRepositoryNode.Path
- Text.DeleteRepositoryNode.TipForGroup
- Text.DeleteRepositoryNode.TipForRepository
- Text.Stash.AutoRestore
- Text.Stash.AutoRestore.Tip
- Text.WorkingCopy.SignOff
</details>
### fr_FR.axaml: 94.69%
### fr_FR.axaml: 92.91%
<details>
<summary>Missing Keys</summary>
- Text.AIAssistant.Regen
- Text.AIAssistant.Use
- Text.ApplyStash
- Text.ApplyStash.DropAfterApply
- Text.ApplyStash.RestoreIndex
- Text.ApplyStash.Stash
- Text.Clone.RecurseSubmodules
- Text.CreateBranch.Name.WarnSpace
- Text.DeleteRepositoryNode.Path
- Text.DeleteRepositoryNode.TipForGroup
- Text.DeleteRepositoryNode.TipForRepository
- Text.InProgress.CherryPick.Head
- Text.InProgress.Merge.Operating
- Text.InProgress.Rebase.StoppedAt
@ -62,81 +99,58 @@
- Text.SetUpstream.Unset
- Text.SetUpstream.Upstream
- Text.SHALinkCM.NavigateTo
- Text.Stash.AutoRestore
- Text.Stash.AutoRestore.Tip
- Text.WorkingCopy.CommitToEdit
- Text.WorkingCopy.SignOff
</details>
### it_IT.axaml: 93.32%
<details>
<summary>Missing Keys</summary>
- Text.BranchCM.MergeMultiBranches
- Text.CommitCM.Merge
- Text.CommitCM.MergeMultiple
- Text.CommitDetail.Files.Search
- Text.CommitDetail.Info.Children
- Text.Configure.IssueTracker.AddSampleGiteeIssue
- Text.Configure.IssueTracker.AddSampleGiteePullRequest
- Text.Configure.IssueTracker.AddSampleGitLabMergeRequest
- Text.Configure.OpenAI.Preferred
- Text.Configure.OpenAI.Preferred.Tip
- Text.Diff.UseBlockNavigation
- Text.Fetch.Force
- Text.FileCM.ResolveUsing
- Text.InProgress.CherryPick.Head
- Text.InProgress.Merge.Operating
- Text.InProgress.Rebase.StoppedAt
- Text.InProgress.Revert.Head
- Text.Merge.Source
- Text.MergeMultiple
- Text.MergeMultiple.CommitChanges
- Text.MergeMultiple.Strategy
- Text.MergeMultiple.Targets
- Text.Preferences.General.DateFormat
- Text.Preferences.General.ShowChildren
- Text.Preferences.Git.SSLVerify
- Text.Repository.FilterCommits
- Text.Repository.FilterCommits.Default
- Text.Repository.FilterCommits.Exclude
- Text.Repository.FilterCommits.Include
- Text.Repository.HistoriesLayout
- Text.Repository.HistoriesLayout.Horizontal
- Text.Repository.HistoriesLayout.Vertical
- Text.Repository.HistoriesOrder
- Text.Repository.HistoriesOrder.ByDate
- Text.Repository.HistoriesOrder.Topo
- Text.Repository.OnlyHighlightCurrentBranchInHistories
- Text.Repository.Skip
- Text.Repository.Tags.OrderByCreatorDate
- Text.Repository.Tags.OrderByNameAsc
- Text.Repository.Tags.OrderByNameDes
- Text.Repository.Tags.Sort
- Text.Repository.UseRelativeTimeInHistories
- Text.SetUpstream
- Text.SetUpstream.Local
- Text.SetUpstream.Unset
- Text.SetUpstream.Upstream
- Text.SHALinkCM.CopySHA
- Text.SHALinkCM.NavigateTo
- Text.WorkingCopy.CommitToEdit
</details>
### pt_BR.axaml: 94.41%
### it_IT.axaml: 98.40%
<details>
<summary>Missing Keys</summary>
- Text.AIAssistant.Regen
- Text.AIAssistant.Use
- Text.ApplyStash
- Text.ApplyStash.DropAfterApply
- Text.ApplyStash.RestoreIndex
- Text.ApplyStash.Stash
- Text.Clone.RecurseSubmodules
- Text.DeleteRepositoryNode.Path
- Text.DeleteRepositoryNode.TipForGroup
- Text.DeleteRepositoryNode.TipForRepository
- Text.Stash.AutoRestore
- Text.Stash.AutoRestore.Tip
</details>
### pt_BR.axaml: 92.65%
<details>
<summary>Missing Keys</summary>
- Text.AIAssistant.Regen
- Text.AIAssistant.Use
- Text.ApplyStash
- Text.ApplyStash.DropAfterApply
- Text.ApplyStash.RestoreIndex
- Text.ApplyStash.Stash
- Text.BranchCM.MergeMultiBranches
- Text.Clone.RecurseSubmodules
- Text.CommitCM.Merge
- Text.CommitCM.MergeMultiple
- Text.CommitDetail.Files.Search
- Text.CommitDetail.Info.Children
- Text.Configure.IssueTracker.AddSampleGiteeIssue
- Text.Configure.IssueTracker.AddSampleGiteePullRequest
- Text.CreateBranch.Name.WarnSpace
- Text.DeleteRepositoryNode.Path
- Text.DeleteRepositoryNode.TipForGroup
- Text.DeleteRepositoryNode.TipForRepository
- Text.Diff.UseBlockNavigation
- Text.Fetch.Force
- Text.FileCM.ResolveUsing
@ -170,17 +184,33 @@
- Text.SetUpstream.Unset
- Text.SetUpstream.Upstream
- Text.SHALinkCM.NavigateTo
- Text.Stash.AutoRestore
- Text.Stash.AutoRestore.Tip
- Text.WorkingCopy.CommitToEdit
- Text.WorkingCopy.SignOff
</details>
### ru_RU.axaml: 100.00%
### ru_RU.axaml: 98.13%
<details>
<summary>Missing Keys</summary>
- Text.AIAssistant.Regen
- Text.AIAssistant.Use
- Text.ApplyStash
- Text.ApplyStash.DropAfterApply
- Text.ApplyStash.RestoreIndex
- Text.ApplyStash.Stash
- Text.Clone.RecurseSubmodules
- Text.CreateBranch.Name.WarnSpace
- Text.DeleteRepositoryNode.Path
- Text.DeleteRepositoryNode.TipForGroup
- Text.DeleteRepositoryNode.TipForRepository
- Text.Stash.AutoRestore
- Text.Stash.AutoRestore.Tip
- Text.WorkingCopy.SignOff
</details>

View file

@ -1 +1 @@
2025.03
2025.04

View file

@ -25,7 +25,7 @@ async function calculateTranslationRate() {
const files = (await fs.readdir(localesDir)).filter(file => file !== 'en_US.axaml' && file.endsWith('.axaml'));
// Add en_US badge first
badges.push(`[![en_US](https://img.shields.io/badge/en__US-100%25-brightgreen)](TRANSLATION.md)`);
badges.push(`[![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen)](TRANSLATION.md)`);
for (const file of files) {
const filePath = path.join(localesDir, file);
@ -40,9 +40,13 @@ async function calculateTranslationRate() {
// Add badges
const locale = file.replace('.axaml', '').replace('_', '__');
const badgeColor = translationRate === 100 ? 'brightgreen' : translationRate >= 75 ? 'yellow' : 'red';
if (translationRate === 100) {
badges.push(`[![${locale}](https://img.shields.io/badge/${locale}-%E2%88%9A-brightgreen)](TRANSLATION.md)`);
} else {
const badgeColor = translationRate >= 75 ? 'yellow' : 'red';
badges.push(`[![${locale}](https://img.shields.io/badge/${locale}-${translationRate.toFixed(2)}%25-${badgeColor})](TRANSLATION.md)`);
}
}
console.log(translationRates.join('\n\n'));

View file

@ -46,8 +46,6 @@ namespace SourceGit
[JsonSerializable(typeof(Models.ExternalToolPaths))]
[JsonSerializable(typeof(Models.InteractiveRebaseJobCollection))]
[JsonSerializable(typeof(Models.JetBrainsState))]
[JsonSerializable(typeof(Models.OpenAIChatRequest))]
[JsonSerializable(typeof(Models.OpenAIChatResponse))]
[JsonSerializable(typeof(Models.ThemeOverrides))]
[JsonSerializable(typeof(Models.Version))]
[JsonSerializable(typeof(Models.RepositorySettings))]

View file

@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Avalonia;
@ -332,17 +334,16 @@ namespace SourceGit
builder.Append($"Crash::: {ex.GetType().FullName}: {ex.Message}\n\n");
builder.Append("----------------------------\n");
builder.Append($"Version: {Assembly.GetExecutingAssembly().GetName().Version}\n");
builder.Append($"OS: {Environment.OSVersion.ToString()}\n");
builder.Append($"OS: {Environment.OSVersion}\n");
builder.Append($"Framework: {AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName}\n");
builder.Append($"Source: {ex.Source}\n");
builder.Append($"Thread Name: {Thread.CurrentThread.Name ?? "Unnamed"}\n");
builder.Append($"User: {Environment.UserName}\n");
builder.Append($"App Start Time: {Process.GetCurrentProcess().StartTime}\n");
builder.Append($"Exception Time: {DateTime.Now}\n");
builder.Append($"Memory Usage: {Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024} MB\n");
builder.Append($"---------------------------\n\n");
builder.Append(ex.StackTrace);
while (ex.InnerException != null)
{
ex = ex.InnerException;
builder.Append($"\n\nInnerException::: {ex.GetType().FullName}: {ex.Message}\n");
builder.Append(ex.StackTrace);
}
builder.Append(ex);
var time = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
var file = Path.Combine(Native.OS.DataDir, $"crash_{time}.log");

View file

@ -12,7 +12,7 @@ namespace SourceGit.Commands
WorkingDirectory = path;
TraitErrorAsOutput = true;
SSHKey = sshKey;
Args = "clone --progress --verbose --recurse-submodules ";
Args = "clone --progress --verbose ";
if (!string.IsNullOrEmpty(extraArgs))
Args += $"{extraArgs} ";

View file

@ -18,6 +18,15 @@ namespace SourceGit.Commands
Args = $"diff --name-status {based} {end}";
}
public CompareRevisions(string repo, string start, string end, string path)
{
WorkingDirectory = repo;
Context = repo;
var based = string.IsNullOrEmpty(start) ? "-R" : start;
Args = $"diff --name-status {based} {end} -- \"{path}\"";
}
public List<Models.Change> Result()
{
Exec();

View file

@ -4,7 +4,7 @@ namespace SourceGit.Commands
{
public class Fetch : Command
{
public Fetch(string repo, string remote, bool noTags, bool prune, bool force, Action<string> outputHandler)
public Fetch(string repo, string remote, bool noTags, bool force, Action<string> outputHandler)
{
_outputHandler = outputHandler;
WorkingDirectory = repo;
@ -21,9 +21,6 @@ namespace SourceGit.Commands
if (force)
Args += "--force ";
if (prune)
Args += "--prune ";
Args += remote;
}

View file

@ -1,8 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Avalonia.Threading;
namespace SourceGit.Commands
{
/// <summary>
@ -20,82 +23,134 @@ namespace SourceGit.Commands
}
}
public GenerateCommitMessage(Models.OpenAIService service, string repo, List<Models.Change> changes, CancellationToken cancelToken, Action<string> onProgress)
public GenerateCommitMessage(Models.OpenAIService service, string repo, List<Models.Change> changes, CancellationToken cancelToken, Action<string> onResponse)
{
_service = service;
_repo = repo;
_changes = changes;
_cancelToken = cancelToken;
_onProgress = onProgress;
_onResponse = onResponse;
}
public string Result()
public void Exec()
{
try
{
var summarybuilder = new StringBuilder();
var bodyBuilder = new StringBuilder();
var responseBuilder = new StringBuilder();
var summaryBuilder = new StringBuilder();
foreach (var change in _changes)
{
if (_cancelToken.IsCancellationRequested)
return "";
return;
_onProgress?.Invoke($"Analyzing {change.Path}...");
responseBuilder.Append("- ");
summaryBuilder.Append("- ");
var summary = GenerateChangeSummary(change);
summarybuilder.Append("- ");
summarybuilder.Append(summary);
summarybuilder.Append("(file: ");
summarybuilder.Append(change.Path);
summarybuilder.Append(")");
summarybuilder.AppendLine();
var rs = new GetDiffContent(_repo, new Models.DiffOption(change, false)).ReadToEnd();
if (rs.IsSuccess)
{
var hasFirstValidChar = false;
var thinkingBuffer = new StringBuilder();
_service.Chat(
_service.AnalyzeDiffPrompt,
$"Here is the `git diff` output: {rs.StdOut}",
_cancelToken,
update =>
ProcessChatResponse(update, ref hasFirstValidChar, thinkingBuffer,
(responseBuilder, text =>
_onResponse?.Invoke(
$"Waiting for pre-file analyzing to completed...\n\n{text}")),
(summaryBuilder, null)));
}
bodyBuilder.Append("- ");
bodyBuilder.Append(summary);
bodyBuilder.AppendLine();
responseBuilder.Append("\n");
summaryBuilder.Append("(file: ");
summaryBuilder.Append(change.Path);
summaryBuilder.Append(")\n");
}
if (_cancelToken.IsCancellationRequested)
return "";
return;
_onProgress?.Invoke($"Generating commit message...");
var body = bodyBuilder.ToString();
var subject = GenerateSubject(summarybuilder.ToString());
return string.Format("{0}\n\n{1}", subject, body);
var responseBody = responseBuilder.ToString();
var subjectBuilder = new StringBuilder();
var hasSubjectFirstValidChar = false;
var subjectThinkingBuffer = new StringBuilder();
_service.Chat(
_service.GenerateSubjectPrompt,
$"Here are the summaries changes:\n{summaryBuilder}",
_cancelToken,
update =>
ProcessChatResponse(update, ref hasSubjectFirstValidChar, subjectThinkingBuffer,
(subjectBuilder, text => _onResponse?.Invoke($"{text}\n\n{responseBody}"))));
}
catch (Exception e)
{
App.RaiseException(_repo, $"Failed to generate commit message: {e}");
return "";
Dispatcher.UIThread.Post(() => App.RaiseException(_repo, $"Failed to generate commit message: {e}"));
}
}
private string GenerateChangeSummary(Models.Change change)
private void ProcessChatResponse(
string update,
ref bool hasFirstValidChar,
StringBuilder thinkingBuffer,
params (StringBuilder builder, Action<string> callback)[] outputs)
{
var rs = new GetDiffContent(_repo, new Models.DiffOption(change, false)).ReadToEnd();
var diff = rs.IsSuccess ? rs.StdOut : "unknown change";
var rsp = _service.Chat(_service.AnalyzeDiffPrompt, $"Here is the `git diff` output: {diff}", _cancelToken);
if (rsp != null && rsp.Choices.Count > 0)
return rsp.Choices[0].Message.Content;
return string.Empty;
if (!hasFirstValidChar)
{
update = update.TrimStart();
if (string.IsNullOrEmpty(update))
return;
if (update.StartsWith("<", StringComparison.Ordinal))
thinkingBuffer.Append(update);
hasFirstValidChar = true;
}
private string GenerateSubject(string summary)
{
var rsp = _service.Chat(_service.GenerateSubjectPrompt, $"Here are the summaries changes:\n{summary}", _cancelToken);
if (rsp != null && rsp.Choices.Count > 0)
return rsp.Choices[0].Message.Content;
if (thinkingBuffer.Length > 0)
thinkingBuffer.Append(update);
return string.Empty;
if (thinkingBuffer.Length > 15)
{
var match = REG_COT.Match(thinkingBuffer.ToString());
if (match.Success)
{
update = REG_COT.Replace(thinkingBuffer.ToString(), "").TrimStart();
if (update.Length > 0)
{
foreach (var output in outputs)
output.builder.Append(update);
thinkingBuffer.Clear();
}
return;
}
match = REG_THINK_START.Match(thinkingBuffer.ToString());
if (!match.Success)
{
foreach (var output in outputs)
output.builder.Append(thinkingBuffer);
thinkingBuffer.Clear();
return;
}
}
if (thinkingBuffer.Length == 0)
{
foreach (var output in outputs)
{
output.builder.Append(update);
output.callback?.Invoke(output.builder.ToString());
}
}
}
private Models.OpenAIService _service;
private string _repo;
private List<Models.Change> _changes;
private CancellationToken _cancelToken;
private Action<string> _onProgress;
private Action<string> _onResponse;
private static readonly Regex REG_COT = new(@"^<(think|thought|thinking|thought_chain)>(.*?)</\1>", RegexOptions.Singleline);
private static readonly Regex REG_THINK_START = new(@"^<(think|thought|thinking|thought_chain)>", RegexOptions.Singleline);
}
}

View file

@ -4,7 +4,7 @@ namespace SourceGit.Commands
{
public class Pull : Command
{
public Pull(string repo, string remote, string branch, bool useRebase, bool noTags, bool prune, Action<string> outputHandler)
public Pull(string repo, string remote, string branch, bool useRebase, bool noTags, Action<string> outputHandler)
{
_outputHandler = outputHandler;
WorkingDirectory = repo;
@ -17,8 +17,6 @@ namespace SourceGit.Commands
Args += "--rebase ";
if (noTags)
Args += "--no-tags ";
if (prune)
Args += "--prune ";
Args += $"{remote} {branch}";
}

View file

@ -18,9 +18,13 @@ namespace SourceGit.Commands
{
string search = onlyCurrentBranch ? string.Empty : "--branches --remotes ";
if (method == Models.CommitSearchMethod.ByUser)
if (method == Models.CommitSearchMethod.ByAuthor)
{
search += $"-i --author=\"{filter}\" --committer=\"{filter}\"";
search += $"-i --author=\"{filter}\"";
}
else if (method == Models.CommitSearchMethod.ByCommitter)
{
search += $"-i --committer=\"{filter}\"";
}
else if (method == Models.CommitSearchMethod.ByFile)
{

View file

@ -24,8 +24,6 @@ namespace SourceGit.Commands
{
var submodules = new List<Models.Submodule>();
var rs = ReadToEnd();
if (!rs.IsSuccess)
return submodules;
var builder = new StringBuilder();
var lines = rs.StdOut.Split('\n', System.StringSplitOptions.RemoveEmptyEntries);

View file

@ -30,7 +30,7 @@ namespace SourceGit.Commands
public bool Push(string message, List<Models.Change> changes, bool keepIndex)
{
var builder = new StringBuilder();
builder.Append("stash push ");
builder.Append("stash push --include-untracked ");
if (keepIndex)
builder.Append("--keep-index ");
builder.Append("-m \"");
@ -47,7 +47,7 @@ namespace SourceGit.Commands
public bool Push(string message, string pathspecFromFile, bool keepIndex)
{
var builder = new StringBuilder();
builder.Append("stash push --pathspec-from-file=\"");
builder.Append("stash push --include-untracked --pathspec-from-file=\"");
builder.Append(pathspecFromFile);
builder.Append("\" ");
if (keepIndex)
@ -73,21 +73,22 @@ namespace SourceGit.Commands
return Exec();
}
public bool Apply(string name)
public bool Apply(string name, bool restoreIndex)
{
Args = $"stash apply --index -q {name}";
var opts = restoreIndex ? "--index" : string.Empty;
Args = $"stash apply -q {opts} \"{name}\"";
return Exec();
}
public bool Pop(string name)
{
Args = $"stash pop --index -q {name}";
Args = $"stash pop -q \"{name}\"";
return Exec();
}
public bool Drop(string name)
{
Args = $"stash drop -q {name}";
Args = $"stash drop -q \"{name}\"";
return Exec();
}

View file

@ -73,6 +73,8 @@ namespace SourceGit.Commands
if (!string.IsNullOrEmpty(tracking))
Args += tracking;
else if (!string.IsNullOrEmpty(name) && !createNew)
Args += name;
_outputHandler = outputHandler;
return Exec();

View file

@ -78,5 +78,8 @@ namespace SourceGit.Converters
return v.Substring(13);
return v;
});
public static readonly FuncValueConverter<string, bool> ContainsSpaces =
new FuncValueConverter<string, bool>(v => v != null && v.Contains(' '));
}
}

View file

@ -8,7 +8,8 @@ namespace SourceGit.Models
{
public enum CommitSearchMethod
{
ByUser,
ByAuthor,
ByCommitter,
ByMessage,
ByFile,
}

View file

@ -1,81 +1,13 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.ClientModel;
using System.Threading;
using Azure.AI.OpenAI;
using CommunityToolkit.Mvvm.ComponentModel;
using OpenAI;
using OpenAI.Chat;
namespace SourceGit.Models
{
public class OpenAIChatMessage
{
[JsonPropertyName("role")]
public string Role
{
get;
set;
}
[JsonPropertyName("content")]
public string Content
{
get;
set;
}
}
public class OpenAIChatChoice
{
[JsonPropertyName("index")]
public int Index
{
get;
set;
}
[JsonPropertyName("message")]
public OpenAIChatMessage Message
{
get;
set;
}
}
public class OpenAIChatResponse
{
[JsonPropertyName("choices")]
public List<OpenAIChatChoice> Choices
{
get;
set;
} = [];
}
public class OpenAIChatRequest
{
[JsonPropertyName("model")]
public string Model
{
get;
set;
}
[JsonPropertyName("messages")]
public List<OpenAIChatMessage> Messages
{
get;
set;
} = [];
public void AddMessage(string role, string content)
{
Messages.Add(new OpenAIChatMessage { Role = role, Content = content });
}
}
public class OpenAIService : ObservableObject
{
public string Name
@ -87,7 +19,15 @@ namespace SourceGit.Models
public string Server
{
get => _server;
set => SetProperty(ref _server, value);
set
{
// migrate old server value
if (!string.IsNullOrEmpty(value) && value.EndsWith("/chat/completions", StringComparison.Ordinal))
{
value = value.Substring(0, value.Length - "/chat/completions".Length);
}
SetProperty(ref _server, value);
}
}
public string ApiKey
@ -147,44 +87,38 @@ namespace SourceGit.Models
""";
}
public OpenAIChatResponse Chat(string prompt, string question, CancellationToken cancellation)
{
var chat = new OpenAIChatRequest() { Model = Model };
chat.AddMessage("user", prompt);
chat.AddMessage("user", question);
var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(60) };
if (!string.IsNullOrEmpty(ApiKey))
public void Chat(string prompt, string question, CancellationToken cancellation, Action<string> onUpdate)
{
Uri server = new(Server);
ApiKeyCredential key = new(ApiKey);
ChatClient client = null;
if (Server.Contains("openai.azure.com/", StringComparison.Ordinal))
client.DefaultRequestHeaders.Add("api-key", ApiKey);
{
var azure = new AzureOpenAIClient(server, key);
client = azure.GetChatClient(Model);
}
else
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {ApiKey}");
{
var openai = new OpenAIClient(key, new() { Endpoint = server });
client = openai.GetChatClient(Model);
}
var req = new StringContent(JsonSerializer.Serialize(chat, JsonCodeGen.Default.OpenAIChatRequest), Encoding.UTF8, "application/json");
try
{
var task = client.PostAsync(Server, req, cancellation);
task.Wait(cancellation);
var updates = client.CompleteChatStreaming([
_model.Equals("o1-mini", StringComparison.Ordinal) ? new UserChatMessage(prompt) : new SystemChatMessage(prompt),
new UserChatMessage(question),
], null, cancellation);
var rsp = task.Result;
var reader = rsp.Content.ReadAsStringAsync(cancellation);
reader.Wait(cancellation);
var body = reader.Result;
if (!rsp.IsSuccessStatusCode)
foreach (var update in updates)
{
throw new Exception($"AI service returns error code {rsp.StatusCode}. Body: {body ?? string.Empty}");
if (update.ContentUpdate.Count > 0)
onUpdate.Invoke(update.ContentUpdate[0].Text);
}
return JsonSerializer.Deserialize(reader.Result, JsonCodeGen.Default.OpenAIChatResponse);
}
catch
{
if (cancellation.IsCancellationRequested)
return null;
if (!cancellation.IsCancellationRequested)
throw;
}
}

View file

@ -10,10 +10,10 @@ namespace SourceGit.Models
private static partial Regex REG_HTTPS();
[GeneratedRegex(@"^[\w\-]+@[\w\.\-]+(\:[0-9]+)?:[\w\-/~%]+/[\w\-\.%]+(\.git)?$")]
private static partial Regex REG_SSH1();
[GeneratedRegex(@"^ssh://([\w\-]+@)?[\w\.\-]+(\:[0-9]+)?/[\w\-/~]+/[\w\-\.]+(\.git)?$")]
[GeneratedRegex(@"^ssh://([\w\-]+@)?[\w\.\-]+(\:[0-9]+)?/[\w\-/~%]+/[\w\-\.%]+(\.git)?$")]
private static partial Regex REG_SSH2();
[GeneratedRegex(@"^git@([\w\.\-]+):([\w\-/~]+/[\w\-\.]+)\.git$")]
[GeneratedRegex(@"^git@([\w\.\-]+):([\w\-/~%]+/[\w\-\.%]+)\.git$")]
private static partial Regex REG_TO_VISIT_URL_CAPTURE();
private static readonly Regex[] URL_FORMATS = [

View file

@ -56,12 +56,6 @@ namespace SourceGit.Models
set;
} = DealWithLocalChanges.DoNothing;
public bool EnablePruneOnFetch
{
get;
set;
} = false;
public bool EnableForceOnFetch
{
get;
@ -188,6 +182,12 @@ namespace SourceGit.Models
set;
} = false;
public bool AutoRestoreAfterStash
{
get;
set;
} = false;
public string PreferedOpenAIService
{
get;

View file

@ -42,6 +42,7 @@ namespace SourceGit.Models
new ShellOrTerminal("mac-terminal", "Terminal", ""),
new ShellOrTerminal("iterm2", "iTerm", ""),
new ShellOrTerminal("warp", "Warp", ""),
new ShellOrTerminal("ghostty", "Ghostty", "")
};
}
else

View file

@ -313,7 +313,7 @@ namespace SourceGit.Models
private static bool IsNameChar(char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
// (?) notice or log if variable is not found

View file

@ -44,6 +44,8 @@ namespace SourceGit.Native
return "iTerm";
case "warp":
return "Warp";
case "ghostty":
return "Ghostty";
}
return string.Empty;

View file

@ -25,7 +25,8 @@ namespace SourceGit.Native
void OpenWithDefaultEditor(string file);
}
public static string DataDir {
public static string DataDir
{
get;
private set;
} = string.Empty;
@ -61,12 +62,14 @@ namespace SourceGit.Native
private set;
} = new Version(0, 0, 0);
public static string ShellOrTerminal {
public static string ShellOrTerminal
{
get;
set;
} = string.Empty;
public static List<Models.ExternalTool> ExternalTools {
public static List<Models.ExternalTool> ExternalTools
{
get;
set;
} = [];

View file

@ -152,7 +152,7 @@ namespace SourceGit.Native
public void OpenBrowser(string url)
{
var info = new ProcessStartInfo("cmd", $"/c start {url}");
var info = new ProcessStartInfo("cmd", $"/c start \"\" \"{url}\"");
info.CreateNoWindow = true;
Process.Start(info);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View file

@ -160,8 +160,6 @@
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">Remotes automatisch fetchen</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">Minute(n)</x:String>
<x:String x:Key="Text.Configure.Git.DefaultRemote" xml:space="preserve">Standard Remote</x:String>
<x:String x:Key="Text.Configure.Git.EnablePruneOnFetch" xml:space="preserve">Aktivere --prune beim fetchen</x:String>
<x:String x:Key="Text.Configure.Git.EnableSignOff" xml:space="preserve">Aktiviere --signoff für Commits</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">TICKETSYSTEM</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteeIssue" xml:space="preserve">Beispiel für Gitee Issue Regel einfügen</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteePullRequest" xml:space="preserve">Beispiel für Gitee Pull Request Regel einfügen</x:String>
@ -478,6 +476,7 @@
<x:String x:Key="Text.Preferences.Git.DefaultCloneDir" xml:space="preserve">Klon Standardordner</x:String>
<x:String x:Key="Text.Preferences.Git.Email" xml:space="preserve">Benutzer Email</x:String>
<x:String x:Key="Text.Preferences.Git.Email.Placeholder" xml:space="preserve">Globale Git Benutzer Email</x:String>
<x:String x:Key="Text.Preferences.Git.EnablePruneOnFetch" xml:space="preserve">Aktivere --prune beim fetchen</x:String>
<x:String x:Key="Text.Preferences.Git.Path" xml:space="preserve">Installationspfad</x:String>
<x:String x:Key="Text.Preferences.Git.SSLVerify" xml:space="preserve">Aktiviere HTTP SSL Verifizierung</x:String>
<x:String x:Key="Text.Preferences.Git.User" xml:space="preserve">Benutzername</x:String>
@ -570,8 +569,8 @@
<x:String x:Key="Text.Repository.HistoriesLayout.Horizontal" xml:space="preserve">Horizontal</x:String>
<x:String x:Key="Text.Repository.HistoriesLayout.Vertical" xml:space="preserve">Vertikal</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder" xml:space="preserve">COMMIT SORTIERUNG</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.ByDate" xml:space="preserve">Commit Zeitpunkt (--date-order)</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.Topo" xml:space="preserve">Topologie (--topo-order)</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.ByDate" xml:space="preserve">Commit Zeitpunkt</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.Topo" xml:space="preserve">Topologie</x:String>
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">LOKALE BRANCHES</x:String>
<x:String x:Key="Text.Repository.NavigateToCurrentHead" xml:space="preserve">Zum HEAD wechseln</x:String>
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">Aktiviere '--first-parent' Option</x:String>
@ -583,10 +582,11 @@
<x:String x:Key="Text.Repository.Remotes" xml:space="preserve">REMOTES</x:String>
<x:String x:Key="Text.Repository.Remotes.Add" xml:space="preserve">REMOTE HINZUFÜGEN</x:String>
<x:String x:Key="Text.Repository.Search" xml:space="preserve">Commit suchen</x:String>
<x:String x:Key="Text.Repository.Search.ByAuthor" xml:space="preserve">Autor</x:String>
<x:String x:Key="Text.Repository.Search.ByCommitter" xml:space="preserve">Committer</x:String>
<x:String x:Key="Text.Repository.Search.ByFile" xml:space="preserve">Dateiname</x:String>
<x:String x:Key="Text.Repository.Search.ByMessage" xml:space="preserve">Commit-Nachricht</x:String>
<x:String x:Key="Text.Repository.Search.BySHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.Repository.Search.ByUser" xml:space="preserve">Autor &amp; Committer</x:String>
<x:String x:Key="Text.Repository.Search.InCurrentBranch" xml:space="preserve">Aktueller Branch</x:String>
<x:String x:Key="Text.Repository.ShowTagsAsTree" xml:space="preserve">Zeige Tags als Baum</x:String>
<x:String x:Key="Text.Repository.Skip" xml:space="preserve">ÜBERSPRINGEN</x:String>

View file

@ -19,7 +19,9 @@
<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.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>
<x:String x:Key="Text.AIAssistant.Use" xml:space="preserve">APPLY AS COMMIT MESSAGE</x:String>
<x:String x:Key="Text.Apply" xml:space="preserve">Patch</x:String>
<x:String x:Key="Text.Apply.Error" xml:space="preserve">Error</x:String>
<x:String x:Key="Text.Apply.Error.Desc" xml:space="preserve">Raise errors and refuses to apply the patch</x:String>
@ -34,6 +36,10 @@
<x:String x:Key="Text.Apply.Warn" xml:space="preserve">Warn</x:String>
<x:String x:Key="Text.Apply.Warn.Desc" xml:space="preserve">Outputs warnings for a few such errors, but applies</x:String>
<x:String x:Key="Text.Apply.WS" xml:space="preserve">Whitespace:</x:String>
<x:String x:Key="Text.ApplyStash" xml:space="preserve">Apply Stash</x:String>
<x:String x:Key="Text.ApplyStash.DropAfterApply" xml:space="preserve">Delete after applying</x:String>
<x:String x:Key="Text.ApplyStash.RestoreIndex" xml:space="preserve">Reinstate the index's changes</x:String>
<x:String x:Key="Text.ApplyStash.Stash" xml:space="preserve">Stash:</x:String>
<x:String x:Key="Text.Archive" xml:space="preserve">Archive...</x:String>
<x:String x:Key="Text.Archive.File" xml:space="preserve">Save Archive To:</x:String>
<x:String x:Key="Text.Archive.File.Placeholder" xml:space="preserve">Select archive file path</x:String>
@ -97,6 +103,7 @@
<x:String x:Key="Text.Clone.LocalName" xml:space="preserve">Local Name:</x:String>
<x:String x:Key="Text.Clone.LocalName.Placeholder" xml:space="preserve">Repository name. Optional.</x:String>
<x:String x:Key="Text.Clone.ParentFolder" xml:space="preserve">Parent Folder:</x:String>
<x:String x:Key="Text.Clone.RecurseSubmodules" xml:space="preserve">Initialize &amp; update submodules</x:String>
<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>
@ -157,8 +164,6 @@
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">Fetch remotes automatically</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">Minute(s)</x:String>
<x:String x:Key="Text.Configure.Git.DefaultRemote" xml:space="preserve">Default Remote</x:String>
<x:String x:Key="Text.Configure.Git.EnablePruneOnFetch" xml:space="preserve">Enable --prune on fetch</x:String>
<x:String x:Key="Text.Configure.Git.EnableSignOff" xml:space="preserve">Enable --signoff for commit</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ISSUE TRACKER</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>
@ -201,6 +206,7 @@
<x:String x:Key="Text.CreateBranch.LocalChanges.StashAndReply" xml:space="preserve">Stash &amp; Reapply</x:String>
<x:String x:Key="Text.CreateBranch.Name" xml:space="preserve">New Branch Name:</x:String>
<x:String x:Key="Text.CreateBranch.Name.Placeholder" xml:space="preserve">Enter branch name.</x:String>
<x:String x:Key="Text.CreateBranch.Name.WarnSpace" xml:space="preserve">Spaces will be replaced with dashes.</x:String>
<x:String x:Key="Text.CreateBranch.Title" xml:space="preserve">Create Local Branch</x:String>
<x:String x:Key="Text.CreateTag" xml:space="preserve">Create Tag...</x:String>
<x:String x:Key="Text.CreateTag.BasedOn" xml:space="preserve">New Tag At:</x:String>
@ -224,8 +230,11 @@
<x:String x:Key="Text.DeleteMultiBranch.Tip" xml:space="preserve">You are trying to delete multiple branches at one time. Be sure to double-check before taking action!</x:String>
<x:String x:Key="Text.DeleteRemote" xml:space="preserve">Delete Remote</x:String>
<x:String x:Key="Text.DeleteRemote.Remote" xml:space="preserve">Remote:</x:String>
<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.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>
@ -273,7 +282,7 @@
<x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">Fast-Forward (without checkout)</x:String>
<x:String x:Key="Text.Fetch" xml:space="preserve">Fetch</x:String>
<x:String x:Key="Text.Fetch.AllRemotes" xml:space="preserve">Fetch all remotes</x:String>
<x:String x:Key="Text.Fetch.Force" xml:space="preserve">Override refs check</x:String>
<x:String x:Key="Text.Fetch.Force" xml:space="preserve">Force override local refs</x:String>
<x:String x:Key="Text.Fetch.NoTags" xml:space="preserve">Fetch without tags</x:String>
<x:String x:Key="Text.Fetch.Remote" xml:space="preserve">Remote:</x:String>
<x:String x:Key="Text.Fetch.Title" xml:space="preserve">Fetch Remote Changes</x:String>
@ -475,6 +484,7 @@
<x:String x:Key="Text.Preferences.Git.DefaultCloneDir" xml:space="preserve">Default Clone Dir</x:String>
<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.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>
@ -567,8 +577,8 @@
<x:String x:Key="Text.Repository.HistoriesLayout.Horizontal" xml:space="preserve">Horizontal</x:String>
<x:String x:Key="Text.Repository.HistoriesLayout.Vertical" xml:space="preserve">Vertical</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder" xml:space="preserve">COMMITS ORDER</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.ByDate" xml:space="preserve">Commit Date (--date-order)</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.Topo" xml:space="preserve">Topologically (--topo-order)</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.ByDate" xml:space="preserve">Commit Date</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.Topo" xml:space="preserve">Topologically</x:String>
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">LOCAL BRANCHES</x:String>
<x:String x:Key="Text.Repository.NavigateToCurrentHead" xml:space="preserve">Navigate to HEAD</x:String>
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">Enable '--first-parent' Option</x:String>
@ -580,10 +590,11 @@
<x:String x:Key="Text.Repository.Remotes" xml:space="preserve">REMOTES</x:String>
<x:String x:Key="Text.Repository.Remotes.Add" xml:space="preserve">ADD REMOTE</x:String>
<x:String x:Key="Text.Repository.Search" xml:space="preserve">Search Commit</x:String>
<x:String x:Key="Text.Repository.Search.ByAuthor" xml:space="preserve">Author</x:String>
<x:String x:Key="Text.Repository.Search.ByCommitter" xml:space="preserve">Committer</x:String>
<x:String x:Key="Text.Repository.Search.ByFile" xml:space="preserve">File</x:String>
<x:String x:Key="Text.Repository.Search.ByMessage" xml:space="preserve">Message</x:String>
<x:String x:Key="Text.Repository.Search.BySHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.Repository.Search.ByUser" xml:space="preserve">Author &amp; Committer</x:String>
<x:String x:Key="Text.Repository.Search.InCurrentBranch" xml:space="preserve">Current Branch</x:String>
<x:String x:Key="Text.Repository.ShowTagsAsTree" xml:space="preserve">Show Tags as Tree</x:String>
<x:String x:Key="Text.Repository.Skip" xml:space="preserve">SKIP</x:String>
@ -638,6 +649,8 @@
<x:String x:Key="Text.SSHKey.Placeholder" xml:space="preserve">Private SSH key store path</x:String>
<x:String x:Key="Text.Start" xml:space="preserve">START</x:String>
<x:String x:Key="Text.Stash" xml:space="preserve">Stash</x:String>
<x:String x:Key="Text.Stash.AutoRestore" xml:space="preserve">Auto-restore after stashing</x:String>
<x:String x:Key="Text.Stash.AutoRestore.Tip" xml:space="preserve">Your working files remain unchanged, but a stash is saved.</x:String>
<x:String x:Key="Text.Stash.IncludeUntracked" xml:space="preserve">Include untracked files</x:String>
<x:String x:Key="Text.Stash.KeepIndex" xml:space="preserve">Keep staged files</x:String>
<x:String x:Key="Text.Stash.Message" xml:space="preserve">Message:</x:String>
@ -717,6 +730,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.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>
<x:String x:Key="Text.WorkingCopy.Staged.UnstageAll" xml:space="preserve">UNSTAGE ALL</x:String>

View file

@ -160,8 +160,6 @@
<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.EnablePruneOnFetch" xml:space="preserve">Habilitar --prune para fetch</x:String>
<x:String x:Key="Text.Configure.Git.EnableSignOff" xml:space="preserve">Habilitar --signoff para commit</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">SEGUIMIENTO DE INCIDENCIAS</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteeIssue" xml:space="preserve">Añadir Regla de Ejemplo para Incidencias de Gitee</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteePullRequest" xml:space="preserve">Añadir Regla de Ejemplo para Pull Requests de Gitee</x:String>
@ -479,6 +477,7 @@
<x:String x:Key="Text.Preferences.Git.DefaultCloneDir" xml:space="preserve">Directorio de clonado por defecto</x:String>
<x:String x:Key="Text.Preferences.Git.Email" xml:space="preserve">Email de usuario</x:String>
<x:String x:Key="Text.Preferences.Git.Email.Placeholder" xml:space="preserve">Email global del usuario git</x:String>
<x:String x:Key="Text.Preferences.Git.EnablePruneOnFetch" xml:space="preserve">Habilitar --prune para fetch</x:String>
<x:String x:Key="Text.Preferences.Git.Path" xml:space="preserve">Ruta de instalación</x:String>
<x:String x:Key="Text.Preferences.Git.SSLVerify" xml:space="preserve">Habilitar verificación HTTP SSL</x:String>
<x:String x:Key="Text.Preferences.Git.User" xml:space="preserve">Nombre de usuario</x:String>
@ -571,8 +570,8 @@
<x:String x:Key="Text.Repository.HistoriesLayout.Horizontal" xml:space="preserve">Horizontal</x:String>
<x:String x:Key="Text.Repository.HistoriesLayout.Vertical" xml:space="preserve">Vertical</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder" xml:space="preserve">ORDEN DE COMMITS</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.ByDate" xml:space="preserve">Fecha de Commit (--date-order)</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.Topo" xml:space="preserve">Topológicamente (--topo-order)</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.ByDate" xml:space="preserve">Fecha de Commit</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.Topo" xml:space="preserve">Topológicamente</x:String>
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">RAMAS LOCALES</x:String>
<x:String x:Key="Text.Repository.NavigateToCurrentHead" xml:space="preserve">Navegar a HEAD</x:String>
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">Habilitar Opción '--first-parent'</x:String>
@ -584,10 +583,11 @@
<x:String x:Key="Text.Repository.Remotes" xml:space="preserve">REMOTOS</x:String>
<x:String x:Key="Text.Repository.Remotes.Add" xml:space="preserve">AÑADIR REMOTO</x:String>
<x:String x:Key="Text.Repository.Search" xml:space="preserve">Buscar Commit</x:String>
<x:String x:Key="Text.Repository.Search.ByAuthor" xml:space="preserve">Autor</x:String>
<x:String x:Key="Text.Repository.Search.ByCommitter" xml:space="preserve">Committer</x:String>
<x:String x:Key="Text.Repository.Search.ByFile" xml:space="preserve">Archivo</x:String>
<x:String x:Key="Text.Repository.Search.ByMessage" xml:space="preserve">Mensaje</x:String>
<x:String x:Key="Text.Repository.Search.BySHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.Repository.Search.ByUser" xml:space="preserve">Autor &amp; Committer</x:String>
<x:String x:Key="Text.Repository.Search.InCurrentBranch" xml:space="preserve">Rama Actual</x:String>
<x:String x:Key="Text.Repository.ShowTagsAsTree" xml:space="preserve">Mostrar Etiquetas como Árbol</x:String>
<x:String x:Key="Text.Repository.Skip" xml:space="preserve">OMITIR</x:String>
@ -707,7 +707,7 @@
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.ExtensionInSameFolder" xml:space="preserve">Ignorar archivos *{0} en la misma carpeta</x:String>
<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 (Amend)</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.Commit" xml:space="preserve">COMMIT</x:String>
<x:String x:Key="Text.WorkingCopy.CommitAndPush" xml:space="preserve">COMMIT &amp; PUSH</x:String>

View file

@ -161,8 +161,6 @@
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">Fetch les dépôts distants automatiquement</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">minute(s)</x:String>
<x:String x:Key="Text.Configure.Git.DefaultRemote" xml:space="preserve">Dépôt par défaut</x:String>
<x:String x:Key="Text.Configure.Git.EnablePruneOnFetch" xml:space="preserve">Activer --prune pour fetch</x:String>
<x:String x:Key="Text.Configure.Git.EnableSignOff" xml:space="preserve">Activer --signoff pour commit</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">SUIVI DES PROBLÈMES</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteeIssue" xml:space="preserve">Ajouter une règle d'exemple Gitee</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteePullRequest" xml:space="preserve">Ajouter une règle d'exemple pour Pull Request Gitee</x:String>
@ -467,6 +465,7 @@
<x:String x:Key="Text.Preferences.Git.DefaultCloneDir" xml:space="preserve">Répertoire de clônage par défaut</x:String>
<x:String x:Key="Text.Preferences.Git.Email" xml:space="preserve">E-mail utilsateur</x:String>
<x:String x:Key="Text.Preferences.Git.Email.Placeholder" xml:space="preserve">E-mail utilsateur global</x:String>
<x:String x:Key="Text.Preferences.Git.EnablePruneOnFetch" xml:space="preserve">Activer --prune pour fetch</x:String>
<x:String x:Key="Text.Preferences.Git.Path" xml:space="preserve">Chemin d'installation</x:String>
<x:String x:Key="Text.Preferences.Git.User" xml:space="preserve">Nom d'utilisateur</x:String>
<x:String x:Key="Text.Preferences.Git.User.Placeholder" xml:space="preserve">Nom d'utilisateur global</x:String>
@ -560,10 +559,11 @@
<x:String x:Key="Text.Repository.Remotes" xml:space="preserve">DEPOTS DISTANTS</x:String>
<x:String x:Key="Text.Repository.Remotes.Add" xml:space="preserve">AJOUTER DEPOT DISTANT</x:String>
<x:String x:Key="Text.Repository.Search" xml:space="preserve">Rechercher un commit</x:String>
<x:String x:Key="Text.Repository.Search.ByAuthor" xml:space="preserve">Auteur</x:String>
<x:String x:Key="Text.Repository.Search.ByCommitter" xml:space="preserve">Committer</x:String>
<x:String x:Key="Text.Repository.Search.ByFile" xml:space="preserve">Fichier</x:String>
<x:String x:Key="Text.Repository.Search.ByMessage" xml:space="preserve">Message</x:String>
<x:String x:Key="Text.Repository.Search.BySHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.Repository.Search.ByUser" xml:space="preserve">Auteur &amp; Committer</x:String>
<x:String x:Key="Text.Repository.Search.InCurrentBranch" xml:space="preserve">Branche actuelle</x:String>
<x:String x:Key="Text.Repository.ShowTagsAsTree" xml:space="preserve">Voir les Tags en tant qu'arbre</x:String>
<x:String x:Key="Text.Repository.Statistics" xml:space="preserve">Statistiques</x:String>

View file

@ -12,7 +12,7 @@
<x:String x:Key="Text.About.SourceCode" xml:space="preserve">• Il codice sorgente è disponibile su </x:String>
<x:String x:Key="Text.About.SubTitle" xml:space="preserve">Client GUI Git open source e gratuito</x:String>
<x:String x:Key="Text.AddWorktree" xml:space="preserve">Aggiungi Worktree</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout" xml:space="preserve">Cosa fare il checkout:</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout" xml:space="preserve">Di cosa fare il checkout:</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.Existing" xml:space="preserve">Branch esistente</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.CreateNew" xml:space="preserve">Crea nuovo branch</x:String>
<x:String x:Key="Text.AddWorktree.Location" xml:space="preserve">Posizione:</x:String>
@ -60,8 +60,9 @@
<x:String x:Key="Text.BranchCM.FetchInto" xml:space="preserve">Recupera ${0}$ in ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.Finish" xml:space="preserve">Git Flow - Completa ${0}$</x:String>
<x:String x:Key="Text.BranchCM.Merge" xml:space="preserve">Unisci ${0}$ in ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.Pull" xml:space="preserve">Recupera ${0}$</x:String>
<x:String x:Key="Text.BranchCM.PullInto" xml:space="preserve">Recupera ${0}$ in ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.MergeMultiBranches" xml:space="preserve">Unisci i {0} branch selezionati in quello corrente</x:String>
<x:String x:Key="Text.BranchCM.Pull" xml:space="preserve">Scarica ${0}$</x:String>
<x:String x:Key="Text.BranchCM.PullInto" xml:space="preserve">Scarica ${0}$ in ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.Push" xml:space="preserve">Invia ${0}$</x:String>
<x:String x:Key="Text.BranchCM.Rebase" xml:space="preserve">Riallinea ${0}$ su ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.Rename" xml:space="preserve">Rinomina ${0}$...</x:String>
@ -73,7 +74,7 @@
<x:String x:Key="Text.ChangeCM.CheckoutFirstParentRevision" xml:space="preserve">Ripristina la Revisione Padre</x:String>
<x:String x:Key="Text.ChangeCM.GenerateCommitMessage" xml:space="preserve">Genera messaggio di commit</x:String>
<x:String x:Key="Text.ChangeDisplayMode" xml:space="preserve">CAMBIA MODALITÀ DI VISUALIZZAZIONE</x:String>
<x:String x:Key="Text.ChangeDisplayMode.Grid" xml:space="preserve">Mostra come elenco di file e directory</x:String>
<x:String x:Key="Text.ChangeDisplayMode.Grid" xml:space="preserve">Mostra come elenco di file e cartelle</x:String>
<x:String x:Key="Text.ChangeDisplayMode.List" xml:space="preserve">Mostra come elenco di percorsi</x:String>
<x:String x:Key="Text.ChangeDisplayMode.Tree" xml:space="preserve">Mostra come albero del filesystem</x:String>
<x:String x:Key="Text.Checkout" xml:space="preserve">Checkout Branch</x:String>
@ -84,13 +85,13 @@
<x:String x:Key="Text.Checkout.LocalChanges" xml:space="preserve">Modifiche Locali:</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.Discard" xml:space="preserve">Scarta</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.DoNothing" xml:space="preserve">Non fare nulla</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Stash e Ripristina</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Stasha e Ripristina</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">Aggiungi sorgente al messaggio di commit</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit(s):</x:String>
<x:String x:Key="Text.CherryPick.CommitChanges" xml:space="preserve">Conferma tutte le modifiche</x:String>
<x:String x:Key="Text.CherryPick.Mainline" xml:space="preserve">Mainline:</x:String>
<x:String x:Key="Text.CherryPick.Mainline.Tips" xml:space="preserve">Di solito non è possibile cherry-pick su una fusione perché non si sa quale lato della fusione deve essere considerato il mainline. Questa opzione consente di riprodurre la modifica relativa al genitore specificato.</x:String>
<x:String x:Key="Text.CherryPick.Mainline.Tips" xml:space="preserve">Di solito non è possibile fare cherry-pick sdi una unione perché non si sa quale lato deve essere considerato il mainline. Questa opzione consente di riprodurre la modifica relativa al genitore specificato.</x:String>
<x:String x:Key="Text.ClearStashes" xml:space="preserve">Cancella Stash</x:String>
<x:String x:Key="Text.ClearStashes.Message" xml:space="preserve">Stai per cancellare tutti gli stash. Sei sicuro di voler continuare?</x:String>
<x:String x:Key="Text.Clone" xml:space="preserve">Clona Repository Remoto</x:String>
@ -110,22 +111,26 @@
<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.CustomAction" xml:space="preserve">Azione Personalizzata</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">Rebase Interattivo ${0}$ fino a Qui</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>
<x:String x:Key="Text.CommitCM.MergeMultiple" xml:space="preserve">Unisci ...</x:String>
<x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">Riallinea ${0}$ fino a Qui</x:String>
<x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">Ripristina ${0}$ fino a Qui</x:String>
<x:String x:Key="Text.CommitCM.Revert" xml:space="preserve">Annulla Commit</x:String>
<x:String x:Key="Text.CommitCM.Reword" xml:space="preserve">Modifica</x:String>
<x:String x:Key="Text.CommitCM.SaveAsPatch" xml:space="preserve">Salva come Patch...</x:String>
<x:String x:Key="Text.CommitCM.Squash" xml:space="preserve">Unisci al Genitore</x:String>
<x:String x:Key="Text.CommitCM.SquashCommitsSinceThis" xml:space="preserve">Unisci Commit Figli fino a Qui</x:String>
<x:String x:Key="Text.CommitCM.Squash" xml:space="preserve">Compatta nel Genitore</x:String>
<x:String x:Key="Text.CommitCM.SquashCommitsSinceThis" xml:space="preserve">Compatta Commit Figli fino a Qui</x:String>
<x:String x:Key="Text.CommitDetail.Changes" xml:space="preserve">MODIFICHE</x:String>
<x:String x:Key="Text.CommitDetail.Changes.Search" xml:space="preserve">Cerca Modifiche...</x:String>
<x:String x:Key="Text.CommitDetail.Files" xml:space="preserve">FILE</x:String>
<x:String x:Key="Text.CommitDetail.Files.LFS" xml:space="preserve">File LFS</x:String>
<x:String x:Key="Text.CommitDetail.Files.Search" xml:space="preserve">Cerca File...</x:String>
<x:String x:Key="Text.CommitDetail.Files.Submodule" xml:space="preserve">Sottomodulo</x:String>
<x:String x:Key="Text.CommitDetail.Info" xml:space="preserve">INFORMAZIONI</x:String>
<x:String x:Key="Text.CommitDetail.Info.Author" xml:space="preserve">AUTORE</x:String>
<x:String x:Key="Text.CommitDetail.Info.Changed" xml:space="preserve">MODIFICATO</x:String>
<x:String x:Key="Text.CommitDetail.Info.Children" xml:space="preserve">FIGLI</x:String>
<x:String x:Key="Text.CommitDetail.Info.Committer" xml:space="preserve">CHI HA COMMITTATO</x:String>
<x:String x:Key="Text.CommitDetail.Info.ContainsIn" xml:space="preserve">Controlla i riferimenti che contengono questo commit</x:String>
<x:String x:Key="Text.CommitDetail.Info.ContainsIn.Title" xml:space="preserve">IL COMMIT È CONTENUTO DA</x:String>
@ -155,21 +160,21 @@
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">Recupera automaticamente i remoti</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">Minuto/i</x:String>
<x:String x:Key="Text.Configure.Git.DefaultRemote" xml:space="preserve">Remoto Predefinito</x:String>
<x:String x:Key="Text.Configure.Git.EnablePruneOnFetch" xml:space="preserve">Abilita --prune durante il fetch</x:String>
<x:String x:Key="Text.Configure.Git.EnableSignOff" xml:space="preserve">Abilita --signoff per i commit</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">TRACCIAMENTO ISSUE</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Aggiungi Regola Esempio per GitHub</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Aggiungi Regola Esempio per Jira</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGitLabIssue" xml:space="preserve">Aggiungi Regola Esempio per Issue GitLab</x:String>
<x:String x:Key="Tracker.AddSampleGitLabMergeRequest" xml:space="preserve">Aggiungi Regola Esempio per Merge Request GitLab</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteeIssue" xml:space="preserve">Aggiungi una regola di esempio per un Issue Gitee</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteePullRequest" xml:space="preserve">Aggiungi una regola di esempio per un Pull Request Gitee</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Aggiungi una regola di esempio per GitHub</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Aggiungi una regola di esempio per Jira</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGitLabIssue" xml:space="preserve">Aggiungi una regola di esempio per Issue GitLab</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGitLabMergeRequest" xml:space="preserve">Aggiungi una regola di esempio per una Merge Request GitLab</x:String>
<x:String x:Key="Text.Configure.IssueTracker.NewRule" xml:space="preserve">Nuova Regola</x:String>
<x:String x:Key="Text.Configure.IssueTracker.Regex" xml:space="preserve">Espressione Regex Issue:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">Nome Regola:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">URL Risultato:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">Utilizza $1, $2 per accedere ai valori dei gruppi regex.</x:String>
<x:String x:Key="Text.Configure.OpenAI" xml:space="preserve">AI</x:String>
<x:String x:Key="Text.Configure.OpenAI.Prefered" xml:space="preserve">Servizio Preferito:</x:String>
<x:String x:Key="Text.Configure.OpenAI.Prefered.Tip" xml:space="preserve">Se il 'Servizio Preferito' è impostato, SourceGit utilizzerà solo quello per questo repository. In caso contrario, se sono disponibili più servizi, verrà mostrato un menu contestuale per sceglierne uno.</x:String>
<x:String x:Key="Text.Configure.OpenAI.Preferred" xml:space="preserve">Servizio preferito:</x:String>
<x:String x:Key="Text.Configure.OpenAI.Preferred.Tip" xml:space="preserve">Se il 'Servizio Preferito' é impostato, SourceGit utilizzerà solo quello per questo repository. Altrimenti, se ci sono più servizi disponibili, verrà mostrato un menu contestuale per sceglierne uno.</x:String>
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">Proxy HTTP</x:String>
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">Proxy HTTP usato da questo repository</x:String>
<x:String x:Key="Text.Configure.User" xml:space="preserve">Nome Utente</x:String>
@ -194,9 +199,10 @@
<x:String x:Key="Text.CreateBranch.LocalChanges" xml:space="preserve">Modifiche Locali:</x:String>
<x:String x:Key="Text.CreateBranch.LocalChanges.Discard" xml:space="preserve">Scarta</x:String>
<x:String x:Key="Text.CreateBranch.LocalChanges.DoNothing" xml:space="preserve">Non Fare Nulla</x:String>
<x:String x:Key="Text.CreateBranch.LocalChanges.StashAndReply" xml:space="preserve">Stash e Ripristina</x:String>
<x:String x:Key="Text.CreateBranch.LocalChanges.StashAndReply" xml:space="preserve">Stasha e Ripristina</x:String>
<x:String x:Key="Text.CreateBranch.Name" xml:space="preserve">Nome Nuovo Branch:</x:String>
<x:String x:Key="Text.CreateBranch.Name.Placeholder" xml:space="preserve">Inserisci il nome del branch.</x:String>
<x:String x:Key="Text.CreateBranch.Name.WarnSpace" xml:space="preserve">Gli spazi verranno rimpiazzati con dei trattini.</x:String>
<x:String x:Key="Text.CreateBranch.Title" xml:space="preserve">Crea Branch Locale</x:String>
<x:String x:Key="Text.CreateTag" xml:space="preserve">Crea Tag...</x:String>
<x:String x:Key="Text.CreateTag.BasedOn" xml:space="preserve">Nuovo Tag Su:</x:String>
@ -238,6 +244,7 @@
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Differenza Successiva</x:String>
<x:String x:Key="Text.Diff.NoChange" xml:space="preserve">NESSUNA MODIFICA O SOLO CAMBIAMENTI DI FINE LINEA</x:String>
<x:String x:Key="Text.Diff.Prev" xml:space="preserve">Differenza Precedente</x:String>
<x:String x:Key="Text.Diff.UseBlockNavigation" xml:space="preserve">Abilita la navigazione a blocchi</x:String>
<x:String x:Key="Text.Diff.SaveAsPatch" xml:space="preserve">Salva come Patch</x:String>
<x:String x:Key="Text.Diff.ShowHiddenSymbols" xml:space="preserve">Mostra Simboli Nascosti</x:String>
<x:String x:Key="Text.Diff.SideBySide" xml:space="preserve">Diff Affiancato</x:String>
@ -268,6 +275,7 @@
<x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">Avanzamento Veloce (senza verifica)</x:String>
<x:String x:Key="Text.Fetch" xml:space="preserve">Recupera</x:String>
<x:String x:Key="Text.Fetch.AllRemotes" xml:space="preserve">Recupera da tutti i remoti</x:String>
<x:String x:Key="Text.Fetch.Force" xml:space="preserve">Forza la sovrascrittura dei riferimenti locali</x:String>
<x:String x:Key="Text.Fetch.NoTags" xml:space="preserve">Recupera senza tag</x:String>
<x:String x:Key="Text.Fetch.Remote" xml:space="preserve">Remoto:</x:String>
<x:String x:Key="Text.Fetch.Title" xml:space="preserve">Recupera Modifiche Remote</x:String>
@ -276,15 +284,16 @@
<x:String x:Key="Text.FileCM.DiscardMulti" xml:space="preserve">Scarta {0} file...</x:String>
<x:String x:Key="Text.FileCM.DiscardSelectedLines" xml:space="preserve">Scarta Modifiche nelle Righe Selezionate</x:String>
<x:String x:Key="Text.FileCM.OpenWithExternalMerger" xml:space="preserve">Apri Strumento di Merge Esterno</x:String>
<x:String x:Key="Text.FileCM.ResolveUsing" xml:space="preserve">Risolvi Usando ${0}$</x:String>
<x:String x:Key="Text.FileCM.SaveAsPatch" xml:space="preserve">Salva come Patch...</x:String>
<x:String x:Key="Text.FileCM.Stage" xml:space="preserve">Staging</x:String>
<x:String x:Key="Text.FileCM.StageMulti" xml:space="preserve">Staging {0} file</x:String>
<x:String x:Key="Text.FileCM.StageSelectedLines" xml:space="preserve">Staging Modifiche nelle Righe Selezionate</x:String>
<x:String x:Key="Text.FileCM.Stash" xml:space="preserve">Stash...</x:String>
<x:String x:Key="Text.FileCM.StashMulti" xml:space="preserve">Stash {0} file...</x:String>
<x:String x:Key="Text.FileCM.Unstage" xml:space="preserve">Rimuovi dallo Staging</x:String>
<x:String x:Key="Text.FileCM.UnstageMulti" xml:space="preserve">Rimuovi dallo Staging {0} file</x:String>
<x:String x:Key="Text.FileCM.UnstageSelectedLines" xml:space="preserve">Rimuovi dallo Staging Modifiche nelle Righe Selezionate</x:String>
<x:String x:Key="Text.FileCM.Stage" xml:space="preserve">Stage</x:String>
<x:String x:Key="Text.FileCM.StageMulti" xml:space="preserve">Stage di {0} file</x:String>
<x:String x:Key="Text.FileCM.StageSelectedLines" xml:space="preserve">Stage delle Modifiche nelle Righe Selezionate</x:String>
<x:String x:Key="Text.FileCM.Stash" xml:space="preserve">Stasha...</x:String>
<x:String x:Key="Text.FileCM.StashMulti" xml:space="preserve">Stasha {0} file...</x:String>
<x:String x:Key="Text.FileCM.Unstage" xml:space="preserve">Rimuovi da Stage</x:String>
<x:String x:Key="Text.FileCM.UnstageMulti" xml:space="preserve">Rimuovi da Stage {0} file</x:String>
<x:String x:Key="Text.FileCM.UnstageSelectedLines" xml:space="preserve">Rimuovi le Righe Selezionate da Stage</x:String>
<x:String x:Key="Text.FileCM.UseTheirs" xml:space="preserve">Usa Il Loro (checkout --theirs)</x:String>
<x:String x:Key="Text.FileCM.UseMine" xml:space="preserve">Usa Il Mio (checkout --ours)</x:String>
<x:String x:Key="Text.FileHistory" xml:space="preserve">Cronologia File</x:String>
@ -297,22 +306,22 @@
<x:String x:Key="Text.GitFlow.FeaturePrefix" xml:space="preserve">Prefisso Feature:</x:String>
<x:String x:Key="Text.GitFlow.FinishFeature" xml:space="preserve">FLOW - Completa Feature</x:String>
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">FLOW - Completa Hotfix</x:String>
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">FLOW - Completa Release</x:String>
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">FLOW - Completa Rilascio</x:String>
<x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">Target:</x:String>
<x:String x:Key="Text.GitFlow.Hotfix" xml:space="preserve">Hotfix:</x:String>
<x:String x:Key="Text.GitFlow.HotfixPrefix" xml:space="preserve">Prefisso Hotfix:</x:String>
<x:String x:Key="Text.GitFlow.Init" xml:space="preserve">Inizializza Git-Flow</x:String>
<x:String x:Key="Text.GitFlow.KeepBranchAfterFinish" xml:space="preserve">Mantieni branch</x:String>
<x:String x:Key="Text.GitFlow.ProductionBranch" xml:space="preserve">Branch di Produzione:</x:String>
<x:String x:Key="Text.GitFlow.Release" xml:space="preserve">Release:</x:String>
<x:String x:Key="Text.GitFlow.ReleasePrefix" xml:space="preserve">Prefisso Release:</x:String>
<x:String x:Key="Text.GitFlow.Release" xml:space="preserve">Rilascio:</x:String>
<x:String x:Key="Text.GitFlow.ReleasePrefix" xml:space="preserve">Prefisso Rilascio:</x:String>
<x:String x:Key="Text.GitFlow.StartFeature" xml:space="preserve">Inizia Feature...</x:String>
<x:String x:Key="Text.GitFlow.StartFeatureTitle" xml:space="preserve">FLOW - Inizia Feature</x:String>
<x:String x:Key="Text.GitFlow.StartHotfix" xml:space="preserve">Inizia Hotfix...</x:String>
<x:String x:Key="Text.GitFlow.StartHotfixTitle" xml:space="preserve">FLOW - Inizia Hotfix</x:String>
<x:String x:Key="Text.GitFlow.StartPlaceholder" xml:space="preserve">Inserisci nome</x:String>
<x:String x:Key="Text.GitFlow.StartRelease" xml:space="preserve">Inizia Release...</x:String>
<x:String x:Key="Text.GitFlow.StartReleaseTitle" xml:space="preserve">FLOW - Inizia Release</x:String>
<x:String x:Key="Text.GitFlow.StartRelease" xml:space="preserve">Inizia Rilascio...</x:String>
<x:String x:Key="Text.GitFlow.StartReleaseTitle" xml:space="preserve">FLOW - Inizia Rilascio</x:String>
<x:String x:Key="Text.GitFlow.TagPrefix" xml:space="preserve">Prefisso Tag Versione:</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">Aggiungi Modello di Tracciamento...</x:String>
@ -323,28 +332,28 @@
<x:String x:Key="Text.GitLFS.Fetch.Title" xml:space="preserve">Recupera Oggetti LFS</x:String>
<x:String x:Key="Text.GitLFS.Fetch.Tips" xml:space="preserve">Esegui `git lfs fetch` per scaricare gli oggetti Git LFS. Questo non aggiorna la copia di lavoro.</x:String>
<x:String x:Key="Text.GitLFS.Install" xml:space="preserve">Installa hook di Git LFS</x:String>
<x:String x:Key="Text.GitLFS.Locks" xml:space="preserve">Mostra Bloccaggi</x:String>
<x:String x:Key="Text.GitLFS.Locks" xml:space="preserve">Mostra Blocchi</x:String>
<x:String x:Key="Text.GitLFS.Locks.Empty" xml:space="preserve">Nessun File Bloccato</x:String>
<x:String x:Key="Text.GitLFS.Locks.Lock" xml:space="preserve">Blocca</x:String>
<x:String x:Key="Text.GitLFS.Locks.OnlyMine" xml:space="preserve">Mostra solo i miei bloccaggi</x:String>
<x:String x:Key="Text.GitLFS.Locks.Title" xml:space="preserve">Bloccaggi LFS</x:String>
<x:String x:Key="Text.GitLFS.Locks.OnlyMine" xml:space="preserve">Mostra solo i miei blocchi</x:String>
<x:String x:Key="Text.GitLFS.Locks.Title" xml:space="preserve">Blocchi LFS</x:String>
<x:String x:Key="Text.GitLFS.Locks.Unlock" xml:space="preserve">Sblocca</x:String>
<x:String x:Key="Text.GitLFS.Locks.UnlockForce" xml:space="preserve">Forza Sblocco</x:String>
<x:String x:Key="Text.GitLFS.Prune" xml:space="preserve">Elimina</x:String>
<x:String x:Key="Text.GitLFS.Prune.Tips" xml:space="preserve">Esegui `git lfs prune` per eliminare vecchi file LFS dallo storage locale</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 Oggetti LFS</x:String>
<x:String x:Key="Text.GitLFS.Pull" xml:space="preserve">Scarica</x:String>
<x:String x:Key="Text.GitLFS.Pull.Title" xml:space="preserve">Scarica Oggetti LFS</x:String>
<x:String x:Key="Text.GitLFS.Pull.Tips" xml:space="preserve">Esegui `git lfs pull` per scaricare tutti i file LFS per il ref corrente e fare il checkout</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 Oggetti LFS</x:String>
<x:String x:Key="Text.GitLFS.Push" xml:space="preserve">Invia</x:String>
<x:String x:Key="Text.GitLFS.Push.Title" xml:space="preserve">Invia Oggetti LFS</x:String>
<x:String x:Key="Text.GitLFS.Push.Tips" xml:space="preserve">Invia grandi file in coda al punto finale di Git LFS</x:String>
<x:String x:Key="Text.GitLFS.Remote" xml:space="preserve">Remoto:</x:String>
<x:String x:Key="Text.GitLFS.Track" xml:space="preserve">Traccia file con nome '{0}'</x:String>
<x:String x:Key="Text.GitLFS.TrackByExtension" xml:space="preserve">Traccia tutti i file *{0}</x:String>
<x:String x:Key="Text.Histories" xml:space="preserve">Storico</x:String>
<x:String x:Key="Text.Histories" xml:space="preserve">STORICO</x:String>
<x:String x:Key="Text.Histories.Header.Author" xml:space="preserve">AUTORE</x:String>
<x:String x:Key="Text.Histories.Header.AuthorTime" xml:space="preserve">ORA AUTORE</x:String>
<x:String x:Key="Text.Histories.Header.GraphAndSubject" xml:space="preserve">GRAFICO &amp; OGGETTO</x:String>
<x:String x:Key="Text.Histories.Header.GraphAndSubject" xml:space="preserve">GRAFICO E OGGETTO</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">ORA COMMIT</x:String>
<x:String x:Key="Text.Histories.Selected" xml:space="preserve">{0} COMMIT SELEZIONATI</x:String>
@ -359,19 +368,19 @@
<x:String x:Key="Text.Hotkeys.Global.GotoPrevTab" xml:space="preserve">Vai alla pagina precedente</x:String>
<x:String x:Key="Text.Hotkeys.Global.GotoNextTab" xml:space="preserve">Vai alla pagina successiva</x:String>
<x:String x:Key="Text.Hotkeys.Global.NewTab" xml:space="preserve">Crea una nuova pagina</x:String>
<x:String x:Key="Text.Hotkeys.Global.OpenPreferences" xml:space="preserve">Apri la finestra di preferenze</x:String>
<x:String x:Key="Text.Hotkeys.Global.OpenPreferences" xml:space="preserve">Apri la finestra delle preferenze</x:String>
<x:String x:Key="Text.Hotkeys.Repo" xml:space="preserve">REPOSITORY</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Commit" xml:space="preserve">Conferma le modifiche in fase</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CommitAndPush" xml:space="preserve">Conferma e invia le modifiche in fase</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CommitWithAutoStage" xml:space="preserve">Aggiungi tutte le modifiche e conferma</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Commit" xml:space="preserve">Committa le modifiche in tsage</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CommitAndPush" xml:space="preserve">Committa e invia le modifiche in stage</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CommitWithAutoStage" xml:space="preserve">Fai lo stage di tutte le modifiche e committa</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CreateBranchOnCommit" xml:space="preserve">Crea un nuovo branch dal commit selezionato</x:String>
<x:String x:Key="Text.Hotkeys.Repo.DiscardSelected" xml:space="preserve">Scarta le modifiche selezionate</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Fetch" xml:space="preserve">Recupera, avvia direttamente</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">Modalità Dashboard (Predefinita)</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Pull" xml:space="preserve">Recupera e integra, avvia direttamente</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Pull" xml:space="preserve">Scarica, avvia direttamente</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Push" xml:space="preserve">Invia, avvia direttamente</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Refresh" xml:space="preserve">Forza il ricaricamento di questo repository</x:String>
<x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">Aggiungi/Rimuovi le modifiche selezionate</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Refresh" xml:space="preserve">Forza l'aggiornamento di questo repository</x:String>
<x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">Aggiungi/Rimuovi da stage le modifiche selezionate</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">Modalità ricerca commit</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewChanges" xml:space="preserve">Passa a 'Modifiche'</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewHistories" xml:space="preserve">Passa a 'Storico'</x:String>
@ -381,16 +390,20 @@
<x:String x:Key="Text.Hotkeys.TextEditor.GotoNextMatch" xml:space="preserve">Trova il prossimo risultato</x:String>
<x:String x:Key="Text.Hotkeys.TextEditor.GotoPrevMatch" xml:space="preserve">Trova il risultato precedente</x:String>
<x:String x:Key="Text.Hotkeys.TextEditor.Search" xml:space="preserve">Apri il pannello di ricerca</x:String>
<x:String x:Key="Text.Hunk.Stage" xml:space="preserve">Aggiungi</x:String>
<x:String x:Key="Text.Hunk.Stage" xml:space="preserve">Aggiungi in stage</x:String>
<x:String x:Key="Text.Hunk.Unstage" xml:space="preserve">Rimuovi</x:String>
<x:String x:Key="Text.Hunk.Discard" xml:space="preserve">Scarta</x:String>
<x:String x:Key="Text.Init" xml:space="preserve">Inizializza Repository</x:String>
<x:String x:Key="Text.Init.Path" xml:space="preserve">Percorso:</x:String>
<x:String x:Key="Text.InProgress.CherryPick" xml:space="preserve">Cherry-Pick in corso.</x:String>
<x:String x:Key="Text.InProgress.Merge" xml:space="preserve">Richiesta di merge in corso.</x:String>
<x:String x:Key="Text.InProgress.Rebase" xml:space="preserve">Rebase in corso.</x:String>
<x:String x:Key="Text.InProgress.Revert" xml:space="preserve">Revert in corso.</x:String>
<x:String x:Key="Text.InteractiveRebase" xml:space="preserve">Rebase Interattivo</x:String>
<x:String x:Key="Text.InProgress.CherryPick.Head" xml:space="preserve">Elaborando il commit</x:String>
<x:String x:Key="Text.InProgress.Merge" xml:space="preserve">Unione in corso.</x:String>
<x:String x:Key="Text.InProgress.Merge.Operating" xml:space="preserve">Unendo</x:String>
<x:String x:Key="Text.InProgress.Rebase" xml:space="preserve">Riallineamento in corso.</x:String>
<x:String x:Key="Text.InProgress.Rebase.StoppedAt" xml:space="preserve">Interrotto a</x:String>
<x:String x:Key="Text.InProgress.Revert" xml:space="preserve">Ripristino in corso.</x:String>
<x:String x:Key="Text.InProgress.Revert.Head" xml:space="preserve">Ripristinando il commit</x:String>
<x:String x:Key="Text.InteractiveRebase" xml:space="preserve">Riallinea Interattivamente</x:String>
<x:String x:Key="Text.InteractiveRebase.Target" xml:space="preserve">Branch di destinazione:</x:String>
<x:String x:Key="Text.InteractiveRebase.On" xml:space="preserve">Su:</x:String>
<x:String x:Key="Text.IssueLinkCM.OpenInBrowser" xml:space="preserve">Apri nel Browser</x:String>
@ -399,11 +412,16 @@
<x:String x:Key="Text.Launcher.Info" xml:space="preserve">AVVISO</x:String>
<x:String x:Key="Text.Merge" xml:space="preserve">Unisci Branch</x:String>
<x:String x:Key="Text.Merge.Into" xml:space="preserve">In:</x:String>
<x:String x:Key="Text.Merge.Mode" xml:space="preserve">Opzione di Merge:</x:String>
<x:String x:Key="Text.Merge.Mode" xml:space="preserve">Opzione di Unione:</x:String>
<x:String x:Key="Text.Merge.Source" xml:space="preserve">Sorgente:</x:String>
<x:String x:Key="Text.MergeMultiple" xml:space="preserve">Unione (multipla)</x:String>
<x:String x:Key="Text.MergeMultiple.CommitChanges" xml:space="preserve">Commit di tutte le modifiche</x:String>
<x:String x:Key="Text.MergeMultiple.Strategy" xml:space="preserve">Strategia:</x:String>
<x:String x:Key="Text.MergeMultiple.Targets" xml:space="preserve">Obiettivi:</x:String>
<x:String x:Key="Text.MoveRepositoryNode" xml:space="preserve">Sposta Nodo Repository</x:String>
<x:String x:Key="Text.MoveRepositoryNode.Target" xml:space="preserve">Seleziona nodo padre per:</x:String>
<x:String x:Key="Text.Name" xml:space="preserve">Nome:</x:String>
<x:String x:Key="Text.NotConfigured" xml:space="preserve">Git NON è configurato. Vai su [Preferenze] e configurarlo prima.</x:String>
<x:String x:Key="Text.NotConfigured" xml:space="preserve">Git NON è configurato. Prima vai su [Preferenze] per configurarlo.</x:String>
<x:String x:Key="Text.OpenAppDataDir" xml:space="preserve">Apri Cartella Dati App</x:String>
<x:String x:Key="Text.OpenWith" xml:space="preserve">Apri con...</x:String>
<x:String x:Key="Text.Optional" xml:space="preserve">Opzionale.</x:String>
@ -428,7 +446,7 @@
<x:String x:Key="Text.Preferences.AI" xml:space="preserve">AI</x:String>
<x:String x:Key="Text.Preferences.AI.AnalyzeDiffPrompt" xml:space="preserve">Analizza il Prompt Differenza</x:String>
<x:String x:Key="Text.Preferences.AI.ApiKey" xml:space="preserve">Chiave API</x:String>
<x:String x:Key="Text.Preferences.AI.GenerateSubjectPrompt" xml:space="preserve">Genera Prompt Soggetto</x:String>
<x:String x:Key="Text.Preferences.AI.GenerateSubjectPrompt" xml:space="preserve">Genera Prompt Oggetto</x:String>
<x:String x:Key="Text.Preferences.AI.Model" xml:space="preserve">Modello</x:String>
<x:String x:Key="Text.Preferences.AI.Name" xml:space="preserve">Nome</x:String>
<x:String x:Key="Text.Preferences.AI.Server" xml:space="preserve">Server</x:String>
@ -449,20 +467,24 @@
<x:String x:Key="Text.Preferences.DiffMerge.Type" xml:space="preserve">Strumento</x:String>
<x:String x:Key="Text.Preferences.General" xml:space="preserve">GENERALE</x:String>
<x:String x:Key="Text.Preferences.General.Check4UpdatesOnStartup" xml:space="preserve">Controlla aggiornamenti all'avvio</x:String>
<x:String x:Key="Text.Preferences.General.DateFormat" xml:space="preserve">Formato data</x:String>
<x:String x:Key="Text.Preferences.General.Locale" xml:space="preserve">Lingua</x:String>
<x:String x:Key="Text.Preferences.General.MaxHistoryCommits" xml:space="preserve">Numero massimo di commit nella cronologia</x:String>
<x:String x:Key="Text.Preferences.General.ShowAuthorTime" xml:space="preserve">Mostra l'orario dell'autore anziché quello del commit nel grafico</x:String>
<x:String x:Key="Text.Preferences.General.SubjectGuideLength" xml:space="preserve">Lunghezza Guida Soggetto</x:String>
<x:String x:Key="Text.Preferences.General.ShowAuthorTime" xml:space="preserve">Mostra nel grafico l'orario dell'autore anziché quello del commit</x:String>
<x:String x:Key="Text.Preferences.General.ShowChildren" xml:space="preserve">Mostra i figli nei dettagli del commit</x:String>
<x:String x:Key="Text.Preferences.General.SubjectGuideLength" xml:space="preserve">Lunghezza Guida Oggetto</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">Abilita Auto CRLF</x:String>
<x:String x:Key="Text.Preferences.Git.DefaultCloneDir" xml:space="preserve">Cartella predefinita per cloni</x:String>
<x:String x:Key="Text.Preferences.Git.Email" xml:space="preserve">Email Utente</x:String>
<x:String x:Key="Text.Preferences.Git.Email.Placeholder" xml:space="preserve">Email globale utente Git</x:String>
<x:String x:Key="Text.Preferences.Git.Email.Placeholder" xml:space="preserve">Email utente Git globale</x:String>
<x:String x:Key="Text.Preferences.Git.EnablePruneOnFetch" xml:space="preserve">Abilita --prune durante il fetch</x:String>
<x:String x:Key="Text.Preferences.Git.Path" xml:space="preserve">Percorso Installazione</x:String>
<x:String x:Key="Text.Preferences.Git.User" xml:space="preserve">Nome Utente</x:String>
<x:String x:Key="Text.Preferences.Git.User.Placeholder" xml:space="preserve">Nome globale utente Git</x:String>
<x:String x:Key="Text.Preferences.Git.User.Placeholder" xml:space="preserve">Nome utente Git globale</x:String>
<x:String x:Key="Text.Preferences.Git.Version" xml:space="preserve">Versione di Git</x:String>
<x:String x:Key="Text.Preferences.Git.Invalid" xml:space="preserve">Git (&gt;= 2.23.0) è richiesto da questa applicazione</x:String>
<x:String x:Key="Text.Preferences.Git.Invalid" xml:space="preserve">Questa applicazione richiede Git (&gt;= 2.23.0)</x:String>
<x:String x:Key="Text.Preferences.Git.SSLVerify" xml:space="preserve">Abilita la verifica HTTP SSL</x:String>
<x:String x:Key="Text.Preferences.GPG" xml:space="preserve">FIRMA GPG</x:String>
<x:String x:Key="Text.Preferences.GPG.CommitEnabled" xml:space="preserve">Firma GPG per commit</x:String>
<x:String x:Key="Text.Preferences.GPG.TagEnabled" xml:space="preserve">Firma GPG per tag</x:String>
@ -479,21 +501,21 @@
<x:String x:Key="Text.PruneRemote.Target" xml:space="preserve">Destinazione:</x:String>
<x:String x:Key="Text.PruneWorktrees" xml:space="preserve">Potatura Worktrees</x:String>
<x:String x:Key="Text.PruneWorktrees.Tip" xml:space="preserve">Potatura delle informazioni di worktree in `$GIT_DIR/worktrees`</x:String>
<x:String x:Key="Text.Pull" xml:space="preserve">Pull</x:String>
<x:String x:Key="Text.Pull" xml:space="preserve">Scarica</x:String>
<x:String x:Key="Text.Pull.Branch" xml:space="preserve">Branch Remoto:</x:String>
<x:String x:Key="Text.Pull.FetchAllBranches" xml:space="preserve">Recupera tutti i branch</x:String>
<x:String x:Key="Text.Pull.Into" xml:space="preserve">In:</x:String>
<x:String x:Key="Text.Pull.LocalChanges" xml:space="preserve">Modifiche Locali:</x:String>
<x:String x:Key="Text.Pull.LocalChanges.Discard" xml:space="preserve">Scarta</x:String>
<x:String x:Key="Text.Pull.LocalChanges.DoNothing" xml:space="preserve">Non fare nulla</x:String>
<x:String x:Key="Text.Pull.LocalChanges.StashAndReply" xml:space="preserve">Accantona e Riapplica</x:String>
<x:String x:Key="Text.Pull.LocalChanges.StashAndReply" xml:space="preserve">Stasha e Riapplica</x:String>
<x:String x:Key="Text.Pull.NoTags" xml:space="preserve">Recupera senza tag</x:String>
<x:String x:Key="Text.Pull.Remote" xml:space="preserve">Remoto:</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">Usa rebase anziché 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">Assicurati che i submoduli siano stati spinti</x:String>
<x:String x:Key="Text.Push.Force" xml:space="preserve">Forza il push</x:String>
<x:String x:Key="Text.Pull.Title" xml:space="preserve">Scarica (Recupera e Unisci)</x:String>
<x:String x:Key="Text.Pull.UseRebase" xml:space="preserve">Riallineare anziché unire</x:String>
<x:String x:Key="Text.Push" xml:space="preserve">Invia</x:String>
<x:String x:Key="Text.Push.CheckSubmodules" xml:space="preserve">Assicurati che i sottomoduli siano stati inviati</x:String>
<x:String x:Key="Text.Push.Force" xml:space="preserve">Forza l'invio</x:String>
<x:String x:Key="Text.Push.Local" xml:space="preserve">Branch Locale:</x:String>
<x:String x:Key="Text.Push.Remote" xml:space="preserve">Remoto:</x:String>
<x:String x:Key="Text.Push.Title" xml:space="preserve">Invia modifiche al remoto</x:String>
@ -505,10 +527,10 @@
<x:String x:Key="Text.PushTag.Remote" xml:space="preserve">Remoto:</x:String>
<x:String x:Key="Text.PushTag.Tag" xml:space="preserve">Tag:</x:String>
<x:String x:Key="Text.Quit" xml:space="preserve">Esci</x:String>
<x:String x:Key="Text.Rebase" xml:space="preserve">Rebase Branch Corrente</x:String>
<x:String x:Key="Text.Rebase.AutoStash" xml:space="preserve">Accantona &amp; Riapplica modifiche locali</x:String>
<x:String x:Key="Text.Rebase" xml:space="preserve">Riallinea Branch Corrente</x:String>
<x:String x:Key="Text.Rebase.AutoStash" xml:space="preserve">Stasha e Riapplica modifiche locali</x:String>
<x:String x:Key="Text.Rebase.On" xml:space="preserve">Su:</x:String>
<x:String x:Key="Text.Rebase.Target" xml:space="preserve">Rebase:</x:String>
<x:String x:Key="Text.Rebase.Target" xml:space="preserve">Riallinea:</x:String>
<x:String x:Key="Text.RefetchAvatar" xml:space="preserve">Aggiorna</x:String>
<x:String x:Key="Text.Remote.AddTitle" xml:space="preserve">Aggiungi Remoto</x:String>
<x:String x:Key="Text.Remote.EditTitle" xml:space="preserve">Modifica Remoto</x:String>
@ -531,7 +553,7 @@
<x:String x:Key="Text.RenameBranch.Target" xml:space="preserve">Branch:</x:String>
<x:String x:Key="Text.Repository.Abort" xml:space="preserve">ANNULLA</x:String>
<x:String x:Key="Text.Repository.AutoFetching" xml:space="preserve">Recupero automatico delle modifiche dai remoti...</x:String>
<x:String x:Key="Text.Repository.Clean" xml:space="preserve">Pulizia (GC &amp; Potatura)</x:String>
<x:String x:Key="Text.Repository.Clean" xml:space="preserve">Pulizia (GC e Potatura)</x:String>
<x:String x:Key="Text.Repository.CleanTips" xml:space="preserve">Esegui il comando `git gc` per questo repository.</x:String>
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">Cancella tutto</x:String>
<x:String x:Key="Text.Repository.Configure" xml:space="preserve">Configura questo repository</x:String>
@ -539,32 +561,50 @@
<x:String x:Key="Text.Repository.CustomActions" xml:space="preserve">Azioni Personalizzate</x:String>
<x:String x:Key="Text.Repository.CustomActions.Empty" xml:space="preserve">Nessuna Azione Personalizzata</x:String>
<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 nel Browser File</x:String>
<x:String x:Key="Text.Repository.Filter" xml:space="preserve">Cerca Branch/Tag/Submodule</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>
<x:String x:Key="Text.Repository.FilterCommits.Include" xml:space="preserve">Filtra nel grafico dei commit</x:String>
<x:String x:Key="Text.Repository.HistoriesLayout" xml:space="preserve">LAYOUT</x:String>
<x:String x:Key="Text.Repository.HistoriesLayout.Horizontal" xml:space="preserve">Orizzontale</x:String>
<x:String x:Key="Text.Repository.HistoriesLayout.Vertical" xml:space="preserve">Verticale</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder" xml:space="preserve">Ordine dei commit</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.ByDate" xml:space="preserve">Per data del commit</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.Topo" xml:space="preserve">Topologicamente</x:String>
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">BRANCH LOCALI</x:String>
<x:String x:Key="Text.Repository.NavigateToCurrentHead" xml:space="preserve">Vai a HEAD</x:String>
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">Abilita opzione '--first-parent'</x:String>
<x:String x:Key="Text.Repository.NewBranch" xml:space="preserve">Crea Branch</x:String>
<x:String x:Key="Text.Repository.OnlyHighlightCurrentBranchInHistories" xml:space="preserve">Evidenzia nel grafico solo il branch corrente</x:String>
<x:String x:Key="Text.Repository.OpenIn" xml:space="preserve">Apri in {0}</x:String>
<x:String x:Key="Text.Repository.OpenWithExternalTools" xml:space="preserve">Apri in Strumenti Esterni</x:String>
<x:String x:Key="Text.Repository.Refresh" xml:space="preserve">Aggiorna</x:String>
<x:String x:Key="Text.Repository.Remotes" xml:space="preserve">REMOTI</x:String>
<x:String x:Key="Text.Repository.Remotes.Add" xml:space="preserve">AGGIUNGI REMOTO</x:String>
<x:String x:Key="Text.Repository.Search" xml:space="preserve">Cerca Commit</x:String>
<x:String x:Key="Text.Repository.Search.ByAuthor" xml:space="preserve">Autore</x:String>
<x:String x:Key="Text.Repository.Search.ByCommitter" xml:space="preserve">Committente</x:String>
<x:String x:Key="Text.Repository.Search.ByFile" xml:space="preserve">File</x:String>
<x:String x:Key="Text.Repository.Search.ByMessage" xml:space="preserve">Messaggio</x:String>
<x:String x:Key="Text.Repository.Search.BySHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.Repository.Search.ByUser" xml:space="preserve">Autore &amp; Committente</x:String>
<x:String x:Key="Text.Repository.Search.InCurrentBranch" xml:space="preserve">Branch Corrente</x:String>
<x:String x:Key="Text.Repository.ShowTagsAsTree" xml:space="preserve">Mostra Tag come Albero</x:String>
<x:String x:Key="Text.Repository.Skip" xml:space="preserve">SALTA</x:String>
<x:String x:Key="Text.Repository.Statistics" xml:space="preserve">Statistiche</x:String>
<x:String x:Key="Text.Repository.Submodules" xml:space="preserve">SUBMODULE</x:String>
<x:String x:Key="Text.Repository.Submodules.Add" xml:space="preserve">AGGIUNGI SUBMODULE</x:String>
<x:String x:Key="Text.Repository.Submodules.Update" xml:space="preserve">AGGIORNA SUBMODULE</x:String>
<x:String x:Key="Text.Repository.Submodules" xml:space="preserve">SOTTOMODULI</x:String>
<x:String x:Key="Text.Repository.Submodules.Add" xml:space="preserve">AGGIUNGI SOTTOMODULI</x:String>
<x:String x:Key="Text.Repository.Submodules.Update" xml:space="preserve">AGGIORNA SOTTOMODULI</x:String>
<x:String x:Key="Text.Repository.Tags" xml:space="preserve">TAG</x:String>
<x:String x:Key="Text.Repository.Tags.Add" xml:space="preserve">NUOVO TAG</x:String>
<x:String x:Key="Text.Repository.Tags.OrderByCreatorDate" xml:space="preserve">Per data di creazione</x:String>
<x:String x:Key="Text.Repository.Tags.OrderByNameAsc" xml:space="preserve">Per nome (ascendente)</x:String>
<x:String x:Key="Text.Repository.Tags.OrderByNameDes" xml:space="preserve">Per nome (discendente)</x:String>
<x:String x:Key="Text.Repository.Tags.Sort" xml:space="preserve">Ordina</x:String>
<x:String x:Key="Text.Repository.Terminal" xml:space="preserve">Apri nel Terminale</x:String>
<x:String x:Key="Text.Repository.UseRelativeTimeInHistories" xml:space="preserve">Usa tempo relativo nello storico</x:String>
<x:String x:Key="Text.Repository.Worktrees" xml:space="preserve">WORKTREE</x:String>
<x:String x:Key="Text.Repository.Worktrees.Add" xml:space="preserve">AGGIUNGI WORKTREE</x:String>
<x:String x:Key="Text.Repository.Worktrees.Prune" xml:space="preserve">POTATURA</x:String>
@ -573,10 +613,10 @@
<x:String x:Key="Text.Reset.Mode" xml:space="preserve">Modalità Reset:</x:String>
<x:String x:Key="Text.Reset.MoveTo" xml:space="preserve">Sposta a:</x:String>
<x:String x:Key="Text.Reset.Target" xml:space="preserve">Branch Corrente:</x:String>
<x:String x:Key="Text.RevealFile" xml:space="preserve">Mostra nel File Explorer</x:String>
<x:String x:Key="Text.Revert" xml:space="preserve">Revert Commit</x:String>
<x:String x:Key="Text.RevealFile" xml:space="preserve">Mostra nell'Esplora File</x:String>
<x:String x:Key="Text.Revert" xml:space="preserve">Ripristina Commit</x:String>
<x:String x:Key="Text.Revert.Commit" xml:space="preserve">Commit:</x:String>
<x:String x:Key="Text.Revert.CommitChanges" xml:space="preserve">Commit delle modifiche di revert</x:String>
<x:String x:Key="Text.Revert.CommitChanges" xml:space="preserve">Commit delle modifiche di ripristino</x:String>
<x:String x:Key="Text.Reword" xml:space="preserve">Modifica Messaggio di Commit</x:String>
<x:String x:Key="Text.Reword.Tip" xml:space="preserve">Usa 'Shift+Enter' per inserire una nuova riga. 'Enter' è il tasto rapido per il pulsante OK</x:String>
<x:String x:Key="Text.Running" xml:space="preserve">In esecuzione. Attendere...</x:String>
@ -592,27 +632,33 @@
<x:String x:Key="Text.SelfUpdate.IgnoreThisVersion" xml:space="preserve">Salta questa versione</x:String>
<x:String x:Key="Text.SelfUpdate.Title" xml:space="preserve">Aggiornamento Software</x:String>
<x:String x:Key="Text.SelfUpdate.UpToDate" xml:space="preserve">Non ci sono aggiornamenti disponibili.</x:String>
<x:String x:Key="Text.Squash" xml:space="preserve">Squash Commit</x:String>
<x:String x:Key="Text.SetUpstream" xml:space="preserve">Imposta il Branch </x:String>
<x:String x:Key="Text.SetUpstream.Local" xml:space="preserve">Branch:</x:String>
<x:String x:Key="Text.SetUpstream.Unset" xml:space="preserve">Rimuovi 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">Copia SHA</x:String>
<x:String x:Key="Text.SHALinkCM.NavigateTo" xml:space="preserve">Vai a</x:String>
<x:String x:Key="Text.Squash" xml:space="preserve">Compatta Commit</x:String>
<x:String x:Key="Text.Squash.Into" xml:space="preserve">In:</x:String>
<x:String x:Key="Text.SSHKey" xml:space="preserve">Chiave Privata SSH:</x:String>
<x:String x:Key="Text.SSHKey.Placeholder" xml:space="preserve">Percorso per la chiave SSH privata</x:String>
<x:String x:Key="Text.Start" xml:space="preserve">AVVIA</x:String>
<x:String x:Key="Text.Stash" xml:space="preserve">Accantona</x:String>
<x:String x:Key="Text.Stash" xml:space="preserve">Stasha</x:String>
<x:String x:Key="Text.Stash.IncludeUntracked" xml:space="preserve">Includi file non tracciati</x:String>
<x:String x:Key="Text.Stash.KeepIndex" xml:space="preserve">Mantieni file indicizzati</x:String>
<x:String x:Key="Text.Stash.KeepIndex" xml:space="preserve">Mantieni file in stage</x:String>
<x:String x:Key="Text.Stash.Message" xml:space="preserve">Messaggio:</x:String>
<x:String x:Key="Text.Stash.Message.Placeholder" xml:space="preserve">Opzionale. Nome di questo accantonamento</x:String>
<x:String x:Key="Text.Stash.OnlyStagedChanges" xml:space="preserve">Solo modifiche indicizzate</x:String>
<x:String x:Key="Text.Stash.TipForSelectedFiles" xml:space="preserve">Sia le modifiche indicizzate che quelle non indicizzate dei file selezionati saranno accantonate!!!</x:String>
<x:String x:Key="Text.Stash.Title" xml:space="preserve">Accantona Modifiche Locali</x:String>
<x:String x:Key="Text.Stash.Message.Placeholder" xml:space="preserve">Opzionale. Nome di questo stash</x:String>
<x:String x:Key="Text.Stash.OnlyStagedChanges" xml:space="preserve">Solo modifiche in stage</x:String>
<x:String x:Key="Text.Stash.TipForSelectedFiles" xml:space="preserve">Sia le modifiche in stage che quelle non in stage dei file selezionati saranno stashate!!!</x:String>
<x:String x:Key="Text.Stash.Title" xml:space="preserve">Stasha Modifiche Locali</x:String>
<x:String x:Key="Text.StashCM.Apply" xml:space="preserve">Applica</x:String>
<x:String x:Key="Text.StashCM.Drop" xml:space="preserve">Elimina</x:String>
<x:String x:Key="Text.StashCM.Pop" xml:space="preserve">Estrai</x:String>
<x:String x:Key="Text.StashDropConfirm" xml:space="preserve">Elimina Accantonamento</x:String>
<x:String x:Key="Text.StashDropConfirm" xml:space="preserve">Elimina Stash</x:String>
<x:String x:Key="Text.StashDropConfirm.Label" xml:space="preserve">Elimina:</x:String>
<x:String x:Key="Text.Stashes" xml:space="preserve">Accantonamenti</x:String>
<x:String x:Key="Text.Stashes" xml:space="preserve">STASH</x:String>
<x:String x:Key="Text.Stashes.Changes" xml:space="preserve">MODIFICHE</x:String>
<x:String x:Key="Text.Stashes.Stashes" xml:space="preserve">ACCANTONAMENTI</x:String>
<x:String x:Key="Text.Stashes.Stashes" xml:space="preserve">STASH</x:String>
<x:String x:Key="Text.Statistics" xml:space="preserve">Statistiche</x:String>
<x:String x:Key="Text.Statistics.CommitAmount" xml:space="preserve">COMMIT</x:String>
<x:String x:Key="Text.Statistics.Committer" xml:space="preserve">COMMITTER</x:String>
@ -621,14 +667,14 @@
<x:String x:Key="Text.Statistics.TotalCommits" xml:space="preserve">COMMIT:</x:String>
<x:String x:Key="Text.Statistics.TotalAuthors" xml:space="preserve">AUTORI:</x:String>
<x:String x:Key="Text.Statistics.Overview" xml:space="preserve">PANORAMICA</x:String>
<x:String x:Key="Text.Submodule" xml:space="preserve">SUBMODULE</x:String>
<x:String x:Key="Text.Submodule.Add" xml:space="preserve">Aggiungi Submodule</x:String>
<x:String x:Key="Text.Submodule" xml:space="preserve">SOTTOMODULI</x:String>
<x:String x:Key="Text.Submodule.Add" xml:space="preserve">Aggiungi Sottomodulo</x:String>
<x:String x:Key="Text.Submodule.CopyPath" xml:space="preserve">Copia Percorso Relativo</x:String>
<x:String x:Key="Text.Submodule.FetchNested" xml:space="preserve">Recupera submodule annidati</x:String>
<x:String x:Key="Text.Submodule.Open" xml:space="preserve">Apri Repository Submodule</x:String>
<x:String x:Key="Text.Submodule.FetchNested" xml:space="preserve">Recupera sottomoduli annidati</x:String>
<x:String x:Key="Text.Submodule.Open" xml:space="preserve">Apri Repository del Sottomodulo</x:String>
<x:String x:Key="Text.Submodule.RelativePath" xml:space="preserve">Percorso Relativo:</x:String>
<x:String x:Key="Text.Submodule.RelativePath.Placeholder" xml:space="preserve">Cartella relativa per memorizzare questo modulo.</x:String>
<x:String x:Key="Text.Submodule.Remove" xml:space="preserve">Elimina Submodule</x:String>
<x:String x:Key="Text.Submodule.Remove" xml:space="preserve">Elimina Sottomodulo</x:String>
<x:String x:Key="Text.Sure" xml:space="preserve">OK</x:String>
<x:String x:Key="Text.TagCM.Copy" xml:space="preserve">Copia Nome Tag</x:String>
<x:String x:Key="Text.TagCM.CopyMessage" xml:space="preserve">Copia Messaggio Tag</x:String>
@ -636,11 +682,11 @@
<x:String x:Key="Text.TagCM.Merge" xml:space="preserve">Unisci ${0}$ in ${1}$...</x:String>
<x:String x:Key="Text.TagCM.Push" xml:space="preserve">Invia ${0}$...</x:String>
<x:String x:Key="Text.URL" xml:space="preserve">URL:</x:String>
<x:String x:Key="Text.UpdateSubmodules" xml:space="preserve">Aggiorna Submodule</x:String>
<x:String x:Key="Text.UpdateSubmodules.All" xml:space="preserve">Tutti i submodule</x:String>
<x:String x:Key="Text.UpdateSubmodules" xml:space="preserve">Aggiorna Sottomoduli</x:String>
<x:String x:Key="Text.UpdateSubmodules.All" xml:space="preserve">Tutti i sottomoduli</x:String>
<x:String x:Key="Text.UpdateSubmodules.Init" xml:space="preserve">Inizializza se necessario</x:String>
<x:String x:Key="Text.UpdateSubmodules.Recursive" xml:space="preserve">Ricorsivamente</x:String>
<x:String x:Key="Text.UpdateSubmodules.Target" xml:space="preserve">Submodule:</x:String>
<x:String x:Key="Text.UpdateSubmodules.Target" xml:space="preserve">Sottomodulo:</x:String>
<x:String x:Key="Text.UpdateSubmodules.UseRemote" xml:space="preserve">Usa opzione --remote</x:String>
<x:String x:Key="Text.Warn" xml:space="preserve">Avviso</x:String>
<x:String x:Key="Text.Welcome" xml:space="preserve">Pagina di Benvenuto</x:String>
@ -648,7 +694,7 @@
<x:String x:Key="Text.Welcome.AddSubFolder" xml:space="preserve">Crea Sottogruppo</x:String>
<x:String x:Key="Text.Welcome.Clone" xml:space="preserve">Clona Repository</x:String>
<x:String x:Key="Text.Welcome.Delete" xml:space="preserve">Elimina</x:String>
<x:String x:Key="Text.Welcome.DragDropTip" xml:space="preserve">TRASCINA &amp; RILASCIA CARTELLA SUPPORTATO. RAGGRUPPAMENTI PERSONALIZZATI SUPPORTATI.</x:String>
<x:String x:Key="Text.Welcome.DragDropTip" xml:space="preserve">TRASCINA E RILASCIA CARTELLA SUPPORTATO. RAGGRUPPAMENTI PERSONALIZZATI SUPPORTATI.</x:String>
<x:String x:Key="Text.Welcome.Edit" xml:space="preserve">Modifica</x:String>
<x:String x:Key="Text.Welcome.Move" xml:space="preserve">Sposta in un Altro Gruppo</x:String>
<x:String x:Key="Text.Welcome.OpenAllInNode" xml:space="preserve">Apri Tutti i Repository</x:String>
@ -657,34 +703,36 @@
<x:String x:Key="Text.Welcome.ScanDefaultCloneDir" xml:space="preserve">Riscansiona Repository nella Cartella Clone Predefinita</x:String>
<x:String x:Key="Text.Welcome.Search" xml:space="preserve">Cerca Repository...</x:String>
<x:String x:Key="Text.Welcome.Sort" xml:space="preserve">Ordina</x:String>
<x:String x:Key="Text.WorkingCopy" xml:space="preserve">Modifiche</x:String>
<x:String x:Key="Text.WorkingCopy" xml:space="preserve">MODIFICHE LOCALI</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">Ignora tutti i file *{0}</x:String>
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.ExtensionInSameFolder" xml:space="preserve">Ignora i file *{0} nella stessa cartella</x:String>
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.InSameFolder" xml:space="preserve">Ignora i file nella stessa cartella</x:String>
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.SingleFile" xml:space="preserve">Ignora solo questo file</x:String>
<x:String x:Key="Text.WorkingCopy.Amend" xml:space="preserve">Modifica</x:String>
<x:String x:Key="Text.WorkingCopy.CanStageTip" xml:space="preserve">Puoi indicizzare questo file ora.</x:String>
<x:String x:Key="Text.WorkingCopy.CanStageTip" xml:space="preserve">Puoi aggiungere in stage questo file ora.</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.CommitAndPush" xml:space="preserve">COMMIT E INVIA</x:String>
<x:String x:Key="Text.WorkingCopy.CommitMessageHelper" xml:space="preserve">Template/Storico</x:String>
<x:String x:Key="Text.WorkingCopy.CommitTip" xml:space="preserve">Attiva evento click</x:String>
<x:String x:Key="Text.WorkingCopy.CommitWithAutoStage" xml:space="preserve">Indica tutte le modifiche e fai il commit</x:String>
<x:String x:Key="Text.WorkingCopy.ConfirmCommitWithoutFiles" xml:space="preserve">Commit vuoto rilevato! Vuoi continuare (--allow-empty)?</x:String>
<x:String x:Key="Text.WorkingCopy.CommitToEdit" xml:space="preserve">Commit (Modifica)</x:String>
<x:String x:Key="Text.WorkingCopy.CommitWithAutoStage" xml:space="preserve">Stage di tutte le modifiche e fai il commit</x:String>
<x:String x:Key="Text.WorkingCopy.ConfirmCommitWithoutFiles" xml:space="preserve">Trovato un commit vuoto! Vuoi continuare (--allow-empty)?</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts" xml:space="preserve">CONFLITTI RILEVATI</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.Resolved" xml:space="preserve">CONFLITTI NEI FILE RISOLTI</x:String>
<x:String x:Key="Text.WorkingCopy.IncludeUntracked" xml:space="preserve">INCLUDI FILE NON TRACCIATI</x:String>
<x:String x:Key="Text.WorkingCopy.NoCommitHistories" xml:space="preserve">NESSUN MESSAGGIO RECENTE INSERITO</x:String>
<x:String x:Key="Text.WorkingCopy.NoCommitTemplates" xml:space="preserve">NESSUN TEMPLATE DI COMMIT</x:String>
<x:String x:Key="Text.WorkingCopy.Staged" xml:space="preserve">INDICIZZATI</x:String>
<x:String x:Key="Text.WorkingCopy.Staged.Unstage" xml:space="preserve">RIMUOVI DALL'INDICIZZAZIONE</x:String>
<x:String x:Key="Text.WorkingCopy.Staged.UnstageAll" xml:space="preserve">RIMUOVI TUTTO DALL'INDICIZZAZIONE</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged" xml:space="preserve">NON INDICIZZATI</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged.Stage" xml:space="preserve">INDICIZZA</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged.StageAll" xml:space="preserve">INDICIZZA TUTTO</x:String>
<x:String x:Key="Text.WorkingCopy.Staged" xml:space="preserve">IN STAGE</x:String>
<x:String x:Key="Text.WorkingCopy.Staged.Unstage" xml:space="preserve">RIMUOVI DA STAGE</x:String>
<x:String x:Key="Text.WorkingCopy.Staged.UnstageAll" xml:space="preserve">RIMUOVI TUTTO DA STAGE</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged" xml:space="preserve">NON IN STAGE</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged.Stage" xml:space="preserve">FAI LO STAGE</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged.StageAll" xml:space="preserve">FAI LO STAGE DI TUTTO</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged.ViewAssumeUnchaged" xml:space="preserve">VISUALIZZA COME NON MODIFICATO</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">Clicca con il tasto destro sul file(i) selezionato, quindi scegli come risolvere i conflitti.</x:String>
<x:String x:Key="Text.WorkingCopy.ResolveTip" xml:space="preserve">Clicca con il tasto destro sul(i) file selezionato, quindi scegli come risolvere i conflitti.</x:String>
<x:String x:Key="Text.WorkingCopy.SignOff" xml:space="preserve">SignOff</x:String>
<x:String x:Key="Text.Workspace" xml:space="preserve">WORKSPACE:</x:String>
<x:String x:Key="Text.Workspace.Configure" xml:space="preserve">Configura Workspaces...</x:String>
<x:String x:Key="Text.Worktree" xml:space="preserve">WORKTREE</x:String>

View file

@ -180,8 +180,6 @@
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">Buscar remotos automaticamente</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 padrão</x:String>
<x:String x:Key="Text.Configure.Git.EnablePruneOnFetch" xml:space="preserve">Habilita --prune ao buscar</x:String>
<x:String x:Key="Text.Configure.Git.EnableSignOff" xml:space="preserve">Habilita --signoff para commits</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">RASTREADOR DE PROBLEMAS</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Adicionar Regra de Exemplo do Github</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Adicionar Regra de Exemplo do Jira</x:String>
@ -481,6 +479,7 @@
<x:String x:Key="Text.Preferences.Git.DefaultCloneDir" xml:space="preserve">Diretório de Clone Padrão</x:String>
<x:String x:Key="Text.Preferences.Git.Email" xml:space="preserve">Email do Usuário</x:String>
<x:String x:Key="Text.Preferences.Git.Email.Placeholder" xml:space="preserve">Email global do usuário git</x:String>
<x:String x:Key="Text.Preferences.Git.EnablePruneOnFetch" xml:space="preserve">Habilita --prune ao buscar</x:String>
<x:String x:Key="Text.Preferences.Git.Path" xml:space="preserve">Caminho de Instalação</x:String>
<x:String x:Key="Text.Preferences.Git.User" xml:space="preserve">Nome do Usuário</x:String>
<x:String x:Key="Text.Preferences.Git.User.Placeholder" xml:space="preserve">Nome global do usuário git</x:String>
@ -567,8 +566,8 @@
<x:String x:Key="Text.Repository.FilterCommits.Default" xml:space="preserve">Desfazer</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Exclude" xml:space="preserve">Esconder no gráfico de commit</x:String>
<x:String x:Key="Text.Repository.FilterCommits.Include" xml:space="preserve">Incluir no gráfico de commit</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.ByDate" xml:space="preserve">Data do Commit (--date-order)</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.Topo" xml:space="preserve">Topologicamente (--topo-order)</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.ByDate" xml:space="preserve">Data do Commit</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.Topo" xml:space="preserve">Topologicamente</x:String>
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">BRANCHES LOCAIS</x:String>
<x:String x:Key="Text.Repository.NavigateToCurrentHead" xml:space="preserve">Navegar para HEAD</x:String>
<x:String x:Key="Text.Repository.FirstParentFilterToggle" xml:space="preserve">Habilitar opção '--first-parent'</x:String>
@ -579,10 +578,11 @@
<x:String x:Key="Text.Repository.Remotes" xml:space="preserve">REMOTOS</x:String>
<x:String x:Key="Text.Repository.Remotes.Add" xml:space="preserve">ADICIONAR REMOTO</x:String>
<x:String x:Key="Text.Repository.Search" xml:space="preserve">Pesquisar Commit</x:String>
<x:String x:Key="Text.Repository.Search.ByAuthor" xml:space="preserve">Autor</x:String>
<x:String x:Key="Text.Repository.Search.ByCommitter" xml:space="preserve">Committer</x:String>
<x:String x:Key="Text.Repository.Search.ByFile" xml:space="preserve">Arquivo</x:String>
<x:String x:Key="Text.Repository.Search.ByMessage" xml:space="preserve">Mensagem</x:String>
<x:String x:Key="Text.Repository.Search.BySHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.Repository.Search.ByUser" xml:space="preserve">Autor &amp; Committer</x:String>
<x:String x:Key="Text.Repository.Search.InCurrentBranch" xml:space="preserve">Branch Atual</x:String>
<x:String x:Key="Text.Repository.ShowTagsAsTree" xml:space="preserve">Exibir Tags como Árvore</x:String>
<x:String x:Key="Text.Repository.Statistics" xml:space="preserve">Estatísticas</x:String>

View file

@ -159,9 +159,7 @@
<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.EnableSignOff" xml:space="preserve">Разрешить '--signoff' для ревизии</x:String>
<x:String x:Key="Text.Configure.Git.DefaultRemote" xml:space="preserve">Внешний репозиторий по умолчанию</x:String>
<x:String x:Key="Text.Configure.Git.EnablePruneOnFetch" xml:space="preserve">Разрешить '--prune' при скачивании</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ОТСЛЕЖИВАНИЕ ПРОБЛЕМ</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteeIssue" xml:space="preserve">Добавить пример правила для тем в Gitee</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteePullRequest" xml:space="preserve">Добавить пример правила запроса скачивания из Gitee</x:String>
@ -479,6 +477,7 @@
<x:String x:Key="Text.Preferences.Git.DefaultCloneDir" xml:space="preserve">Каталог клонирования по умолчанию</x:String>
<x:String x:Key="Text.Preferences.Git.Email" xml:space="preserve">Электроная почта пользователя</x:String>
<x:String x:Key="Text.Preferences.Git.Email.Placeholder" xml:space="preserve">Общая электроная почта пользователя git</x:String>
<x:String x:Key="Text.Preferences.Git.EnablePruneOnFetch" xml:space="preserve">Разрешить '--prune' при скачивании</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>
@ -572,8 +571,8 @@
<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">Дата ревизии (--date-order)</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.Topo" xml:space="preserve">Топологически (--topo-order)</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.FirstParentFilterToggle" xml:space="preserve">Включить опцию --first-parent</x:String>
@ -585,10 +584,11 @@
<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.ByUser" xml:space="preserve">Автор и исполнитель</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>

View file

@ -22,7 +22,9 @@
<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.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">应用补丁(apply)</x:String>
<x:String x:Key="Text.Apply.Error" xml:space="preserve">错误</x:String>
<x:String x:Key="Text.Apply.Error.Desc" xml:space="preserve">输出错误,并终止应用补丁</x:String>
@ -37,6 +39,10 @@
<x:String x:Key="Text.Apply.Warn" xml:space="preserve">警告</x:String>
<x:String x:Key="Text.Apply.Warn.Desc" 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">存档(archive) ...</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>
@ -100,6 +106,7 @@
<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">远程仓库 </x:String>
<x:String x:Key="Text.Close" xml:space="preserve">关闭</x:String>
<x:String x:Key="Text.CodeEditor" xml:space="preserve">提交信息编辑器</x:String>
@ -160,8 +167,6 @@
<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.EnableSignOff" xml:space="preserve">提交信息追加署名 (--signoff)</x:String>
<x:String x:Key="Text.Configure.Git.EnablePruneOnFetch" xml:space="preserve">拉取更新时启用修剪(--prune</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ISSUE追踪</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteeIssue" xml:space="preserve">新增匹配Gitee议题规则</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteePullRequest" xml:space="preserve">新增匹配Gitee合并请求规则</x:String>
@ -204,6 +209,7 @@
<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>
@ -227,8 +233,11 @@
<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.TitleForGroup" xml:space="preserve">删除分组确认</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.TipForRepository" 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>
@ -276,7 +285,7 @@
<x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">快进(fast-forward无需checkout)</x:String>
<x:String x:Key="Text.Fetch" xml:space="preserve">拉取(fetch)</x:String>
<x:String x:Key="Text.Fetch.AllRemotes" xml:space="preserve">拉取所有的远程仓库</x:String>
<x:String x:Key="Text.Fetch.Force" xml:space="preserve">覆盖REF检查</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>
@ -479,6 +488,7 @@
<x:String x:Key="Text.Preferences.Git.DefaultCloneDir" xml:space="preserve">默认克隆路径</x:String>
<x:String x:Key="Text.Preferences.Git.Email" xml:space="preserve">邮箱</x:String>
<x:String x:Key="Text.Preferences.Git.Email.Placeholder" xml:space="preserve">默认GIT用户邮箱</x:String>
<x:String x:Key="Text.Preferences.Git.EnablePruneOnFetch" xml:space="preserve">拉取更新时启用修剪(--prune</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>
@ -571,8 +581,8 @@
<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">按提交时间 (--date-order)</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.Topo" xml:space="preserve">按拓扑排序 (--topo-order)</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.FirstParentFilterToggle" xml:space="preserve">启用 --first-parent 过滤选项</x:String>
@ -584,10 +594,11 @@
<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">提交指纹</x:String>
<x:String x:Key="Text.Repository.Search.ByUser" xml:space="preserve">作者及提交者</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>
@ -642,6 +653,8 @@
<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>
@ -707,7 +720,7 @@
<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.Amend" xml:space="preserve">修补</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">提交并推送</x:String>
@ -721,6 +734,7 @@
<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.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>

View file

@ -22,7 +22,9 @@
<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.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">套用修補檔 (apply patch)</x:String>
<x:String x:Key="Text.Apply.Error" xml:space="preserve">錯誤</x:String>
<x:String x:Key="Text.Apply.Error.Desc" xml:space="preserve">輸出錯誤,並中止套用修補檔</x:String>
@ -37,6 +39,10 @@
<x:String x:Key="Text.Apply.Warn" xml:space="preserve">警告</x:String>
<x:String x:Key="Text.Apply.Warn.Desc" 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">封存 (archive)...</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>
@ -100,6 +106,7 @@
<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">遠端存放庫:</x:String>
<x:String x:Key="Text.Close" xml:space="preserve">關閉</x:String>
<x:String x:Key="Text.CodeEditor" xml:space="preserve">提交訊息編輯器</x:String>
@ -160,8 +167,6 @@
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">啟用定時自動提取 (fetch) 遠端更新</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.EnableSignOff" xml:space="preserve">提交訊息追加署名 (--signoff)</x:String>
<x:String x:Key="Text.Configure.Git.EnablePruneOnFetch" xml:space="preserve">拉取變更時進行清理 (--prune)</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">Issue 追蹤</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteeIssue" xml:space="preserve">新增符合 Gitee 議題規則</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGiteePullRequest" xml:space="preserve">新增符合 Gitee 合併請求規則</x:String>
@ -204,6 +209,7 @@
<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>
@ -227,8 +233,11 @@
<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.TitleForGroup" xml:space="preserve">刪除群組確認</x:String>
<x:String x:Key="Text.DeleteRepositoryNode.TipForRepository" 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>
@ -276,7 +285,7 @@
<x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">快進 (fast-forward無需 checkout)</x:String>
<x:String x:Key="Text.Fetch" xml:space="preserve">提取 (fetch)</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.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>
@ -478,6 +487,7 @@
<x:String x:Key="Text.Preferences.Git.DefaultCloneDir" xml:space="preserve">預設複製 (clone) 路徑</x:String>
<x:String x:Key="Text.Preferences.Git.Email" xml:space="preserve">電子郵件</x:String>
<x:String x:Key="Text.Preferences.Git.Email.Placeholder" xml:space="preserve">預設 Git 使用者電子郵件</x:String>
<x:String x:Key="Text.Preferences.Git.EnablePruneOnFetch" xml:space="preserve">拉取變更時進行清理 (--prune)</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>
@ -570,8 +580,8 @@
<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">依提交時間排序 (--date-order)</x:String>
<x:String x:Key="Text.Repository.HistoriesOrder.Topo" xml:space="preserve">依拓撲排序 (--topo-order)</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.FirstParentFilterToggle" xml:space="preserve">啟用 [--first-parent] 選項</x:String>
@ -583,10 +593,11 @@
<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">提交編號</x:String>
<x:String x:Key="Text.Repository.Search.ByUser" xml:space="preserve">作者及提交者</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>
@ -641,6 +652,8 @@
<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>
@ -706,7 +719,7 @@
<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.Amend" xml:space="preserve">修補</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">提交並推送</x:String>
@ -720,6 +733,7 @@
<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.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>

View file

@ -2,6 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="using:SourceGit"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
xmlns:c="using:SourceGit.Converters"
xmlns:ae="using:AvaloniaEdit"
xmlns:aee="using:AvaloniaEdit.Editing"
@ -844,7 +845,19 @@
HorizontalAlignment="Right"
VerticalAlignment="Center"
Foreground="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForeground}"
FontSize="11"/>
FontSize="11"
IsVisible="{TemplateBinding (v:MenuItemExtension.Command), Converter={x:Static StringConverters.IsNullOrEmpty}}"/>
<TextBlock x:Name="PART_CommandTip"
Grid.Column="2"
Classes="CaptionTextBlockStyle"
Margin="{DynamicResource MenuInputGestureTextMargin}"
Text="{TemplateBinding (v:MenuItemExtension.Command)}"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Foreground="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForeground}"
FontSize="11"
IsVisible="{TemplateBinding (v:MenuItemExtension.Command), Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
<Path Name="PART_ChevronPath"
Width="6"

View file

@ -48,8 +48,10 @@
<PackageReference Include="Avalonia.Diagnostics" Version="11.2.3" Condition="'$(Configuration)' == 'Debug'" />
<PackageReference Include="Avalonia.AvaloniaEdit" Version="11.1.0" />
<PackageReference Include="AvaloniaEdit.TextMate" Version="11.1.0" />
<PackageReference Include="Azure.AI.OpenAI" Version="2.2.0-beta.1" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.3.2" />
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" Version="2.0.0-rc5" />
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" Version="2.0.0-rc5.1" />
<PackageReference Include="OpenAI" Version="2.2.0-beta.1" />
<PackageReference Include="TextMateSharp" Version="1.0.65" />
<PackageReference Include="TextMateSharp.Grammars" Version="1.0.65" />
</ItemGroup>

View file

@ -100,7 +100,7 @@ namespace SourceGit.ViewModels
{
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, false, SetProgressDescription).Exec();
new Commands.Fetch(_repo.FullPath, _name, false, false, SetProgressDescription).Exec();
}
CallUIThread(() =>
{

View file

@ -12,7 +12,7 @@ namespace SourceGit.ViewModels
public string Path
{
get => _path;
set => SetProperty(ref _path, value);
set => SetProperty(ref _path, value, true);
}
public bool CreateNewBranch

View file

@ -0,0 +1,48 @@
using System.Threading.Tasks;
namespace SourceGit.ViewModels
{
public class ApplyStash : Popup
{
public Models.Stash Stash
{
get;
private set;
}
public bool RestoreIndex
{
get;
set;
} = true;
public bool DropAfterApply
{
get;
set;
} = false;
public ApplyStash(string repo, Models.Stash stash)
{
_repo = repo;
Stash = stash;
View = new Views.ApplyStash() { DataContext = this };
}
public override Task<bool> Sure()
{
ProgressDescription = $"Applying stash: {Stash.Name}";
return Task.Run(() =>
{
var succ = new Commands.Stash(_repo).Apply(Stash.Name, RestoreIndex);
if (succ && DropAfterApply)
new Commands.Stash(_repo).Drop(Stash.Name);
return true;
});
}
private readonly string _repo;
}
}

View file

@ -53,6 +53,12 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _extraArgs, value);
}
public bool InitAndUpdateSubmodules
{
get;
set;
} = true;
public Clone(string pageId)
{
_pageId = pageId;
@ -127,6 +133,17 @@ namespace SourceGit.ViewModels
config.Set("remote.origin.sshkey", _sshKey);
}
// individually update submodule (if any)
if (InitAndUpdateSubmodules)
{
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);
}
}
CallUIThread(() =>
{
var node = Preferences.Instance.FindOrAddNodeByRepositoryPath(path, null, true);

View file

@ -6,7 +6,7 @@ namespace SourceGit.ViewModels
public class CreateBranch : Popup
{
[Required(ErrorMessage = "Branch name is required!")]
[RegularExpression(@"^[\w\-/\.#]+$", ErrorMessage = "Bad branch name format!")]
[RegularExpression(@"^[\w \-/\.#]+$", ErrorMessage = "Bad branch name format!")]
[CustomValidation(typeof(CreateBranch), nameof(ValidateBranchName))]
public string Name
{
@ -74,9 +74,10 @@ namespace SourceGit.ViewModels
if (creator == null)
return new ValidationResult("Missing runtime context to create branch!");
var fixedName = creator.FixName(name);
foreach (var b in creator._repo.Branches)
{
if (b.FriendlyName == name)
if (b.FriendlyName == fixedName)
return new ValidationResult("A branch with same name already exists!");
}
@ -86,6 +87,8 @@ namespace SourceGit.ViewModels
public override Task<bool> Sure()
{
_repo.SetWatcherEnabled(false);
var fixedName = FixName(_name);
return Task.Run(() =>
{
var succ = false;
@ -114,8 +117,8 @@ namespace SourceGit.ViewModels
}
}
SetProgressDescription($"Create new branch '{_name}'");
succ = new Commands.Checkout(_repo.FullPath).Branch(_name, _baseOnRevision, SetProgressDescription);
SetProgressDescription($"Create new branch '{fixedName}'");
succ = new Commands.Checkout(_repo.FullPath).Branch(fixedName, _baseOnRevision, SetProgressDescription);
if (needPopStash)
{
@ -125,15 +128,15 @@ namespace SourceGit.ViewModels
}
else
{
SetProgressDescription($"Create new branch '{_name}'");
succ = Commands.Branch.Create(_repo.FullPath, _name, _baseOnRevision);
SetProgressDescription($"Create new branch '{fixedName}'");
succ = Commands.Branch.Create(_repo.FullPath, fixedName, _baseOnRevision);
}
CallUIThread(() =>
{
if (succ && CheckoutAfterCreated)
{
var fake = new Models.Branch() { IsLocal = true, FullName = $"refs/heads/{_name}" };
var fake = new Models.Branch() { IsLocal = true, FullName = $"refs/heads/{fixedName}" };
if (BasedOn is Models.Branch based && !based.IsLocal)
fake.Upstream = based.FullName;
@ -153,6 +156,15 @@ namespace SourceGit.ViewModels
});
}
private string FixName(string name)
{
if (!name.Contains(' '))
return name;
var parts = name.Split(' ', System.StringSplitOptions.RemoveEmptyEntries);
return string.Join("-", parts);
}
private readonly Repository _repo = null;
private string _name = null;
private readonly string _baseOnRevision = null;

View file

@ -47,7 +47,6 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
var notags = _repo.Settings.FetchWithoutTags;
var prune = _repo.Settings.EnablePruneOnFetch;
var force = _repo.Settings.EnableForceOnFetch;
return Task.Run(() =>
{
@ -56,13 +55,13 @@ namespace SourceGit.ViewModels
foreach (var remote in _repo.Remotes)
{
SetProgressDescription($"Fetching remote: {remote.Name}");
new Commands.Fetch(_repo.FullPath, remote.Name, notags, prune, force, SetProgressDescription).Exec();
new Commands.Fetch(_repo.FullPath, remote.Name, notags, force, SetProgressDescription).Exec();
}
}
else
{
SetProgressDescription($"Fetching remote: {SelectedRemote.Name}");
new Commands.Fetch(_repo.FullPath, SelectedRemote.Name, notags, prune, force, SetProgressDescription).Exec();
new Commands.Fetch(_repo.FullPath, SelectedRemote.Name, notags, force, SetProgressDescription).Exec();
}
CallUIThread(() =>

View file

@ -4,6 +4,7 @@ using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Avalonia.Collections;
using Avalonia.Media.Imaging;
using Avalonia.Threading;
@ -17,36 +18,14 @@ namespace SourceGit.ViewModels
public object Content { get; set; } = content;
}
public partial class FileHistories : ObservableObject
public partial class FileHistoriesSingleRevision : ObservableObject
{
public bool IsLoading
public bool IsDiffMode
{
get => _isLoading;
private set => SetProperty(ref _isLoading, value);
}
public List<Models.Commit> Commits
{
get => _commits;
set => SetProperty(ref _commits, value);
}
public Models.Commit SelectedCommit
{
get => _selectedCommit;
get => _isDiffMode;
set
{
if (SetProperty(ref _selectedCommit, value))
RefreshViewContent();
}
}
public bool IsViewContent
{
get => _isViewContent;
set
{
if (SetProperty(ref _isViewContent, value))
if (SetProperty(ref _isDiffMode, value))
RefreshViewContent();
}
}
@ -54,55 +33,36 @@ namespace SourceGit.ViewModels
public object ViewContent
{
get => _viewContent;
private set => SetProperty(ref _viewContent, value);
set => SetProperty(ref _viewContent, value);
}
public FileHistories(Repository repo, string file, string commit = null)
public FileHistoriesSingleRevision(Repository repo, string file, Models.Commit revision, bool prevIsDiffMode)
{
_repo = repo;
_file = file;
_revision = revision;
_isDiffMode = prevIsDiffMode;
_viewContent = null;
Task.Run(() =>
{
var based = commit ?? string.Empty;
var commits = new Commands.QueryCommits(_repo.FullPath, $"--date-order -n 10000 {based} -- \"{file}\"", false).Result();
Dispatcher.UIThread.Invoke(() =>
{
IsLoading = false;
Commits = commits;
if (commits.Count > 0)
SelectedCommit = commits[0];
});
});
}
public void NavigateToCommit(Models.Commit commit)
{
_repo.NavigateToCommit(commit.SHA);
RefreshViewContent();
}
public void ResetToSelectedRevision()
{
new Commands.Checkout(_repo.FullPath).FileWithRevision(_file, $"{_selectedCommit.SHA}");
new Commands.Checkout(_repo.FullPath).FileWithRevision(_file, $"{_revision.SHA}");
}
private void RefreshViewContent()
{
if (_selectedCommit == null)
{
ViewContent = null;
return;
}
if (_isViewContent)
SetViewContentAsRevisionFile();
else
if (_isDiffMode)
SetViewContentAsDiff();
else
SetViewContentAsRevisionFile();
}
private void SetViewContentAsRevisionFile()
{
var objs = new Commands.QueryRevisionObjects(_repo.FullPath, _selectedCommit.SHA, _file).Result();
var objs = new Commands.QueryRevisionObjects(_repo.FullPath, _revision.SHA, _file).Result();
if (objs.Count == 0)
{
ViewContent = new FileHistoriesRevisionFile(_file, null);
@ -115,13 +75,13 @@ namespace SourceGit.ViewModels
case Models.ObjectType.Blob:
Task.Run(() =>
{
var isBinary = new Commands.IsBinary(_repo.FullPath, _selectedCommit.SHA, _file).Result();
var isBinary = new Commands.IsBinary(_repo.FullPath, _revision.SHA, _file).Result();
if (isBinary)
{
var ext = Path.GetExtension(_file);
if (IMG_EXTS.Contains(ext))
{
var stream = Commands.QueryFileContent.Run(_repo.FullPath, _selectedCommit.SHA, _file);
var stream = Commands.QueryFileContent.Run(_repo.FullPath, _revision.SHA, _file);
var fileSize = stream.Length;
var bitmap = fileSize > 0 ? new Bitmap(stream) : null;
var imageType = Path.GetExtension(_file).TrimStart('.').ToUpper(CultureInfo.CurrentCulture);
@ -130,7 +90,7 @@ namespace SourceGit.ViewModels
}
else
{
var size = new Commands.QueryFileSize(_repo.FullPath, _file, _selectedCommit.SHA).Result();
var size = new Commands.QueryFileSize(_repo.FullPath, _file, _revision.SHA).Result();
var binaryFile = new Models.RevisionBinaryFile() { Size = size };
Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, binaryFile));
}
@ -138,7 +98,7 @@ namespace SourceGit.ViewModels
return;
}
var contentStream = Commands.QueryFileContent.Run(_repo.FullPath, _selectedCommit.SHA, _file);
var contentStream = Commands.QueryFileContent.Run(_repo.FullPath, _revision.SHA, _file);
var content = new StreamReader(contentStream).ReadToEnd();
var matchLFS = REG_LFS_FORMAT().Match(content);
if (matchLFS.Success)
@ -181,7 +141,7 @@ namespace SourceGit.ViewModels
private void SetViewContentAsDiff()
{
var option = new Models.DiffOption(_selectedCommit, _file);
var option = new Models.DiffOption(_revision, _file);
ViewContent = new DiffContext(_repo.FullPath, option, _viewContent as DiffContext);
}
@ -193,12 +153,155 @@ namespace SourceGit.ViewModels
".ico", ".bmp", ".jpg", ".png", ".jpeg", ".webp"
};
private Repository _repo = null;
private string _file = null;
private Models.Commit _revision = null;
private bool _isDiffMode = true;
private object _viewContent = null;
}
public class FileHistoriesCompareRevisions : ObservableObject
{
public Models.Commit StartPoint
{
get => _startPoint;
set => SetProperty(ref _startPoint, value);
}
public Models.Commit EndPoint
{
get => _endPoint;
set => SetProperty(ref _endPoint, value);
}
public DiffContext ViewContent
{
get => _viewContent;
set => SetProperty(ref _viewContent, value);
}
public FileHistoriesCompareRevisions(Repository repo, string file, Models.Commit start, Models.Commit end)
{
_repo = repo;
_file = file;
_startPoint = start;
_endPoint = end;
RefreshViewContent();
}
public void Swap()
{
(StartPoint, EndPoint) = (_endPoint, _startPoint);
RefreshViewContent();
}
public Task<bool> SaveAsPatch(string saveTo)
{
return Task.Run(() =>
{
Commands.SaveChangesAsPatch.ProcessRevisionCompareChanges(_repo.FullPath, _changes, _startPoint.SHA, _endPoint.SHA, saveTo);
return true;
});
}
private void RefreshViewContent()
{
Task.Run(() =>
{
_changes = new Commands.CompareRevisions(_repo.FullPath, _startPoint.SHA, _endPoint.SHA, _file).Result();
if (_changes.Count == 0)
{
Dispatcher.UIThread.Invoke(() => ViewContent = null);
return;
}
var option = new Models.DiffOption(_startPoint.SHA, _endPoint.SHA, _changes[0]);
Dispatcher.UIThread.Invoke(() => ViewContent = new DiffContext(_repo.FullPath, option, _viewContent));
});
}
private Repository _repo = null;
private string _file = null;
private Models.Commit _startPoint = null;
private Models.Commit _endPoint = null;
private List<Models.Change> _changes = [];
private DiffContext _viewContent = null;
}
public class FileHistories : ObservableObject
{
public bool IsLoading
{
get => _isLoading;
private set => SetProperty(ref _isLoading, value);
}
public List<Models.Commit> Commits
{
get => _commits;
set => SetProperty(ref _commits, value);
}
public AvaloniaList<Models.Commit> SelectedCommits
{
get;
set;
} = [];
public object ViewContent
{
get => _viewContent;
private set => SetProperty(ref _viewContent, value);
}
public FileHistories(Repository repo, string file, string commit = null)
{
_repo = repo;
_file = file;
Task.Run(() =>
{
var based = commit ?? string.Empty;
var commits = new Commands.QueryCommits(_repo.FullPath, $"--date-order -n 10000 {based} -- \"{file}\"", false).Result();
Dispatcher.UIThread.Invoke(() =>
{
IsLoading = false;
Commits = commits;
if (Commits.Count > 0)
SelectedCommits.Add(Commits[0]);
});
});
SelectedCommits.CollectionChanged += (_, _) =>
{
if (_viewContent is FileHistoriesSingleRevision singleRevision)
_prevIsDiffMode = singleRevision.IsDiffMode;
switch (SelectedCommits.Count)
{
case 1:
ViewContent = new FileHistoriesSingleRevision(_repo, _file, SelectedCommits[0], _prevIsDiffMode);
break;
case 2:
ViewContent = new FileHistoriesCompareRevisions(_repo, _file, SelectedCommits[0], SelectedCommits[1]);
break;
default:
ViewContent = SelectedCommits.Count;
break;
}
};
}
public void NavigateToCommit(Models.Commit commit)
{
_repo.NavigateToCommit(commit.SHA);
}
private readonly Repository _repo = null;
private readonly string _file = null;
private bool _isLoading = true;
private bool _prevIsDiffMode = true;
private List<Models.Commit> _commits = null;
private Models.Commit _selectedCommit = null;
private bool _isViewContent = false;
private object _viewContent = null;
}
}

View file

@ -107,8 +107,12 @@ namespace SourceGit.ViewModels
{
_gitDir = repo.GitDir;
var stoppedSHA = File.ReadAllText(Path.Combine(repo.GitDir, "rebase-merge", "stopped-sha")).Trim();
var stoppedSHAPath = Path.Combine(repo.GitDir, "rebase-merge", "stopped-sha");
if (File.Exists(stoppedSHAPath))
{
var stoppedSHA = File.ReadAllText(stoppedSHAPath).Trim();
StoppedAt = new Commands.QuerySingleCommit(repo.FullPath, stoppedSHA).Result() ?? new Models.Commit() { SHA = stoppedSHA };
}
var ontoSHA = File.ReadAllText(Path.Combine(repo.GitDir, "rebase-merge", "onto")).Trim();
Onto = new Commands.QuerySingleCommit(repo.FullPath, ontoSHA).Result() ?? new Models.Commit() { SHA = ontoSHA };

View file

@ -59,6 +59,8 @@ namespace SourceGit.ViewModels
public void StartPopup(Popup popup)
{
Popup = popup;
if (popup.CanStartDirectly())
ProcessPopup();
}

View file

@ -61,9 +61,9 @@ namespace SourceGit.ViewModels
return Task.Run(() =>
{
var succ = new Commands.Merge(_repo.FullPath, _sourceName, SelectedMode.Arg, SetProgressDescription).Exec();
new Commands.Merge(_repo.FullPath, _sourceName, SelectedMode.Arg, SetProgressDescription).Exec();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ;
return true;
});
}

View file

@ -37,6 +37,11 @@ namespace SourceGit.ViewModels
return !HasErrors;
}
public virtual bool CanStartDirectly()
{
return true;
}
public virtual Task<bool> Sure()
{
return null;

View file

@ -151,7 +151,6 @@ namespace SourceGit.ViewModels
_repo.FullPath,
_selectedRemote.Name,
NoTags,
_repo.Settings.EnablePruneOnFetch,
false,
SetProgressDescription).Exec();
@ -184,7 +183,6 @@ namespace SourceGit.ViewModels
_selectedBranch.Name,
UseRebase,
NoTags,
_repo.Settings.EnablePruneOnFetch,
SetProgressDescription).Exec();
}

View file

@ -152,6 +152,11 @@ namespace SourceGit.ViewModels
View = new Views.Push() { DataContext = this };
}
public override bool CanStartDirectly()
{
return !string.IsNullOrEmpty(_selectedRemoteBranch?.Head);
}
public override Task<bool> Sure()
{
_repo.SetWatcherEnabled(false);

View file

@ -733,12 +733,15 @@ namespace SourceGit.ViewModels
visible.Add(commit);
break;
case 1:
visible = new Commands.QueryCommits(_fullpath, _searchCommitFilter, Models.CommitSearchMethod.ByUser, _onlySearchCommitsInCurrentBranch).Result();
visible = new Commands.QueryCommits(_fullpath, _searchCommitFilter, Models.CommitSearchMethod.ByAuthor, _onlySearchCommitsInCurrentBranch).Result();
break;
case 2:
visible = new Commands.QueryCommits(_fullpath, _searchCommitFilter, Models.CommitSearchMethod.ByMessage, _onlySearchCommitsInCurrentBranch).Result();
visible = new Commands.QueryCommits(_fullpath, _searchCommitFilter, Models.CommitSearchMethod.ByCommitter, _onlySearchCommitsInCurrentBranch).Result();
break;
case 3:
visible = new Commands.QueryCommits(_fullpath, _searchCommitFilter, Models.CommitSearchMethod.ByMessage, _onlySearchCommitsInCurrentBranch).Result();
break;
case 4:
visible = new Commands.QueryCommits(_fullpath, _searchCommitFilter, Models.CommitSearchMethod.ByFile, _onlySearchCommitsInCurrentBranch).Result();
break;
}
@ -936,7 +939,7 @@ namespace SourceGit.ViewModels
RemoteBranchTrees = builder.Remotes;
if (_workingCopy != null)
_workingCopy.CanCommitWithPush = _currentBranch != null && !string.IsNullOrEmpty(_currentBranch.Upstream);
_workingCopy.HasRemotes = remotes.Count > 0;
});
}
@ -1196,6 +1199,25 @@ namespace SourceGit.ViewModels
App.GetLauncer()?.OpenRepositoryInTab(node, null);
}
public AvaloniaList<Models.OpenAIService> GetPreferedOpenAIServices()
{
var services = Preferences.Instance.OpenAIServices;
if (services == null || services.Count == 0)
return [];
if (services.Count == 1)
return services;
var prefered = _settings.PreferedOpenAIService;
foreach (var service in services)
{
if (service.Name.Equals(prefered, StringComparison.Ordinal))
return [service];
}
return services;
}
public ContextMenu CreateContextMenuForGitFlow()
{
var menu = new ContextMenu();
@ -2358,7 +2380,7 @@ namespace SourceGit.ViewModels
Dispatcher.UIThread.Invoke(() => IsAutoFetching = true);
foreach (var remote in remotes)
new Commands.Fetch(_fullpath, remote, false, _settings.EnablePruneOnFetch, false, null) { RaiseError = false }.Exec();
new Commands.Fetch(_fullpath, remote, false, false, null) { RaiseError = false }.Exec();
_lastFetchTime = DateTime.Now;
Dispatcher.UIThread.Invoke(() => IsAutoFetching = false);
}
@ -2382,7 +2404,7 @@ namespace SourceGit.ViewModels
private bool _isSearching = false;
private bool _isSearchLoadingVisible = false;
private bool _isSearchCommitSuggestionOpen = false;
private int _searchCommitFilterType = 2;
private int _searchCommitFilterType = 3;
private bool _onlySearchCommitsInCurrentBranch = false;
private string _searchCommitFilter = string.Empty;
private List<Models.Commit> _searchedCommits = new List<Models.Commit>();

View file

@ -60,18 +60,6 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _httpProxy, value);
}
public bool EnableSignOffForCommit
{
get => _repo.Settings.EnableSignOffForCommit;
set => _repo.Settings.EnableSignOffForCommit = value;
}
public bool EnablePruneOnFetch
{
get => _repo.Settings.EnablePruneOnFetch;
set => _repo.Settings.EnablePruneOnFetch = value;
}
public bool EnableAutoFetch
{
get => _repo.Settings.EnableAutoFetch;

View file

@ -36,6 +36,12 @@ namespace SourceGit.ViewModels
set => _repo.Settings.KeepIndexWhenStash = value;
}
public bool AutoRestore
{
get => _repo.Settings.AutoRestoreAfterStash;
set => _repo.Settings.AutoRestoreAfterStash = value;
}
public StashChanges(Repository repo, List<Models.Change> changes, bool hasSelectedFiles)
{
_repo = repo;
@ -84,6 +90,9 @@ namespace SourceGit.ViewModels
succ = StashWithChanges(_changes);
}
if (AutoRestore && succ)
succ = new Commands.Stash(_repo.FullPath).Apply("stash@{0}", true);
CallUIThread(() =>
{
_repo.MarkWorkingCopyDirtyManually();

View file

@ -141,15 +141,9 @@ namespace SourceGit.ViewModels
apply.Header = App.Text("StashCM.Apply");
apply.Click += (_, ev) =>
{
Task.Run(() => new Commands.Stash(_repo.FullPath).Apply(stash.Name));
ev.Handled = true;
};
if (_repo.CanCreatePopup())
_repo.ShowPopup(new ApplyStash(_repo.FullPath, stash));
var pop = new MenuItem();
pop.Header = App.Text("StashCM.Pop");
pop.Click += (_, ev) =>
{
Task.Run(() => new Commands.Stash(_repo.FullPath).Pop(stash.Name));
ev.Handled = true;
};
@ -165,7 +159,6 @@ namespace SourceGit.ViewModels
var menu = new ContextMenu();
menu.Items.Add(apply);
menu.Items.Add(pop);
menu.Items.Add(drop);
return menu;
}

View file

@ -56,25 +56,24 @@ namespace SourceGit.ViewModels
{
_repo.SetWatcherEnabled(false);
string target = string.Empty;
List<string> targets;
if (_updateAll)
{
ProgressDescription = "Updating submodules ...";
}
targets = Submodules;
else
{
target = SelectedSubmodule;
ProgressDescription = $"Updating submodule {target} ...";
}
targets = [SelectedSubmodule];
return Task.Run(() =>
{
foreach (var submodule in targets)
{
ProgressDescription = $"Updating submodule {submodule} ...";
new Commands.Submodule(_repo.FullPath).Update(
target,
submodule,
EnableInit,
EnableRecursive,
EnableRemote,
SetProgressDescription);
}
CallUIThread(() => _repo.SetWatcherEnabled(true));
return true;

View file

@ -26,10 +26,10 @@ namespace SourceGit.ViewModels
}
}
public bool CanCommitWithPush
public bool HasRemotes
{
get => _canCommitWithPush;
set => SetProperty(ref _canCommitWithPush, value);
get => _hasRemotes;
set => SetProperty(ref _hasRemotes, value);
}
public bool HasUnsolvedConflicts
@ -62,6 +62,12 @@ namespace SourceGit.ViewModels
private set => SetProperty(ref _isCommitting, value);
}
public bool EnableSignOff
{
get => _repo.Settings.EnableSignOffForCommit;
set => _repo.Settings.EnableSignOffForCommit = value;
}
public bool UseAmend
{
get => _useAmend;
@ -93,12 +99,34 @@ namespace SourceGit.ViewModels
}
}
public string UnstagedFilter
{
get => _unstagedFilter;
set
{
if (SetProperty(ref _unstagedFilter, value))
{
if (_isLoadingData)
return;
VisibleUnstaged = GetVisibleUnstagedChanges();
SelectedUnstaged = [];
}
}
}
public List<Models.Change> Unstaged
{
get => _unstaged;
private set => SetProperty(ref _unstaged, value);
}
public List<Models.Change> VisibleUnstaged
{
get => _visibleUnstaged;
private set => SetProperty(ref _visibleUnstaged, value);
}
public List<Models.Change> Staged
{
get => _staged;
@ -185,8 +213,9 @@ namespace SourceGit.ViewModels
_selectedStaged.Clear();
OnPropertyChanged(nameof(SelectedStaged));
_visibleUnstaged.Clear();
_unstaged.Clear();
OnPropertyChanged(nameof(Unstaged));
OnPropertyChanged(nameof(VisibleUnstaged));
_staged.Clear();
OnPropertyChanged(nameof(Staged));
@ -212,7 +241,7 @@ namespace SourceGit.ViewModels
var inProgress = null as InProgressContext;
if (File.Exists(Path.Combine(_repo.GitDir, "CHERRY_PICK_HEAD")))
inProgress = new CherryPickInProgress(_repo);
else if (File.Exists(Path.Combine(_repo.GitDir, "REBASE_HEAD")) && Directory.Exists(Path.Combine(_repo.GitDir, "rebase-merge")))
else if (Directory.Exists(Path.Combine(_repo.GitDir, "rebase-merge")) || Directory.Exists(Path.Combine(_repo.GitDir, "rebase-apply")))
inProgress = new RebaseInProgress(_repo);
else if (File.Exists(Path.Combine(_repo.GitDir, "REVERT_HEAD")))
inProgress = new RevertInProgress(_repo);
@ -243,7 +272,6 @@ namespace SourceGit.ViewModels
}
var unstaged = new List<Models.Change>();
var selectedUnstaged = new List<Models.Change>();
var hasConflict = false;
foreach (var c in changes)
{
@ -251,11 +279,18 @@ namespace SourceGit.ViewModels
{
unstaged.Add(c);
hasConflict |= c.IsConflit;
}
}
_unstaged = unstaged;
var visibleUnstaged = GetVisibleUnstagedChanges();
var selectedUnstaged = new List<Models.Change>();
foreach (var c in visibleUnstaged)
{
if (lastSelectedUnstaged.Contains(c.Path))
selectedUnstaged.Add(c);
}
}
var staged = GetStagedChanges();
var selectedStaged = new List<Models.Change>();
@ -269,7 +304,7 @@ namespace SourceGit.ViewModels
{
_isLoadingData = true;
HasUnsolvedConflicts = hasConflict;
Unstaged = unstaged;
VisibleUnstaged = visibleUnstaged;
Staged = staged;
SelectedUnstaged = selectedUnstaged;
SelectedStaged = selectedStaged;
@ -285,7 +320,7 @@ namespace SourceGit.ViewModels
var inProgress = null as InProgressContext;
if (File.Exists(Path.Combine(_repo.GitDir, "CHERRY_PICK_HEAD")))
inProgress = new CherryPickInProgress(_repo);
else if (File.Exists(Path.Combine(_repo.GitDir, "REBASE_HEAD")) && Directory.Exists(Path.Combine(_repo.GitDir, "rebase-merge")))
else if (Directory.Exists(Path.Combine(_repo.GitDir, "rebase-merge")) || Directory.Exists(Path.Combine(_repo.GitDir, "rebase-apply")))
inProgress = new RebaseInProgress(_repo);
else if (File.Exists(Path.Combine(_repo.GitDir, "REVERT_HEAD")))
inProgress = new RevertInProgress(_repo);
@ -330,46 +365,7 @@ namespace SourceGit.ViewModels
public void StageAll()
{
StageChanges(_unstaged, null);
}
public async void StageChanges(List<Models.Change> changes, Models.Change next)
{
if (_unstaged.Count == 0 || changes.Count == 0)
return;
// Use `_selectedUnstaged` instead of `SelectedUnstaged` to avoid UI refresh.
_selectedUnstaged = next != null ? [next] : [];
IsStaging = true;
_repo.SetWatcherEnabled(false);
if (changes.Count == _unstaged.Count)
{
await Task.Run(() => new Commands.Add(_repo.FullPath, _repo.IncludeUntracked).Exec());
}
else if (Native.OS.GitVersion >= Models.GitVersions.ADD_WITH_PATHSPECFILE)
{
var paths = new List<string>();
foreach (var c in changes)
paths.Add(c.Path);
var tmpFile = Path.GetTempFileName();
File.WriteAllLines(tmpFile, paths);
await Task.Run(() => new Commands.Add(_repo.FullPath, tmpFile).Exec());
File.Delete(tmpFile);
}
else
{
for (int i = 0; i < changes.Count; i += 10)
{
var count = Math.Min(10, changes.Count - i);
var step = changes.GetRange(i, count);
await Task.Run(() => new Commands.Add(_repo.FullPath, step).Exec());
}
}
_repo.MarkWorkingCopyDirtyManually();
_repo.SetWatcherEnabled(true);
IsStaging = false;
StageChanges(_visibleUnstaged, null);
}
public void UnstageSelected(Models.Change next)
@ -382,47 +378,15 @@ namespace SourceGit.ViewModels
UnstageChanges(_staged, null);
}
public async void UnstageChanges(List<Models.Change> changes, Models.Change next)
{
if (_staged.Count == 0 || changes.Count == 0)
return;
// Use `_selectedStaged` instead of `SelectedStaged` to avoid UI refresh.
_selectedStaged = next != null ? [next] : [];
IsUnstaging = true;
_repo.SetWatcherEnabled(false);
if (_useAmend)
{
await Task.Run(() => new Commands.UnstageChangesForAmend(_repo.FullPath, changes).Exec());
}
else if (changes.Count == _staged.Count)
{
await Task.Run(() => new Commands.Reset(_repo.FullPath).Exec());
}
else
{
for (int i = 0; i < changes.Count; i += 10)
{
var count = Math.Min(10, changes.Count - i);
var step = changes.GetRange(i, count);
await Task.Run(() => new Commands.Reset(_repo.FullPath, step).Exec());
}
}
_repo.MarkWorkingCopyDirtyManually();
_repo.SetWatcherEnabled(true);
IsUnstaging = false;
}
public void Discard(List<Models.Change> changes)
{
if (_repo.CanCreatePopup())
{
if (changes.Count == _unstaged.Count && _staged.Count == 0)
_repo.ShowPopup(new Discard(_repo));
else
_repo.ShowPopup(new Discard(_repo, changes));
}
public void ClearUnstagedFilter()
{
UnstagedFilter = string.Empty;
}
public async void UseTheirs(List<Models.Change> changes)
@ -1067,7 +1031,7 @@ namespace SourceGit.ViewModels
var menu = new ContextMenu();
var ai = null as MenuItem;
var services = GetPreferedOpenAIServices();
var services = _repo.GetPreferedOpenAIServices();
if (services.Count > 0)
{
ai = new MenuItem();
@ -1078,7 +1042,7 @@ namespace SourceGit.ViewModels
{
ai.Click += (_, e) =>
{
var dialog = new Views.AIAssistant(services[0], _repo.FullPath, _selectedStaged, generated => CommitMessage = generated);
var dialog = new Views.AIAssistant(services[0], _repo.FullPath, this, _selectedStaged);
App.OpenDialog(dialog);
e.Handled = true;
};
@ -1093,7 +1057,7 @@ namespace SourceGit.ViewModels
item.Header = service.Name;
item.Click += (_, e) =>
{
var dialog = new Views.AIAssistant(dup, _repo.FullPath, _selectedStaged, generated => CommitMessage = generated);
var dialog = new Views.AIAssistant(dup, _repo.FullPath, this, _selectedStaged);
App.OpenDialog(dialog);
e.Handled = true;
};
@ -1458,7 +1422,7 @@ namespace SourceGit.ViewModels
return null;
}
var services = GetPreferedOpenAIServices();
var services = _repo.GetPreferedOpenAIServices();
if (services.Count == 0)
{
App.RaiseException(_repo.FullPath, "Bad configuration for OpenAI");
@ -1467,7 +1431,7 @@ namespace SourceGit.ViewModels
if (services.Count == 1)
{
var dialog = new Views.AIAssistant(services[0], _repo.FullPath, _staged, generated => CommitMessage = generated);
var dialog = new Views.AIAssistant(services[0], _repo.FullPath, this, _staged);
App.OpenDialog(dialog);
return null;
}
@ -1483,7 +1447,7 @@ namespace SourceGit.ViewModels
item.Header = service.Name;
item.Click += (_, e) =>
{
var dialog = new Views.AIAssistant(dup, _repo.FullPath, _staged, generated => CommitMessage = generated);
var dialog = new Views.AIAssistant(dup, _repo.FullPath, this, _staged);
App.OpenDialog(dialog);
e.Handled = true;
};
@ -1495,6 +1459,22 @@ namespace SourceGit.ViewModels
}
}
private List<Models.Change> GetVisibleUnstagedChanges()
{
if (string.IsNullOrEmpty(_unstagedFilter))
return _unstaged;
var visible = new List<Models.Change>();
foreach (var c in _unstaged)
{
if (c.Path.Contains(_unstagedFilter, StringComparison.OrdinalIgnoreCase))
visible.Add(c);
}
return visible;
}
private List<Models.Change> GetStagedChanges()
{
if (_useAmend)
@ -1510,6 +1490,77 @@ namespace SourceGit.ViewModels
return rs;
}
private async void StageChanges(List<Models.Change> changes, Models.Change next)
{
if (changes.Count == 0)
return;
// Use `_selectedUnstaged` instead of `SelectedUnstaged` to avoid UI refresh.
_selectedUnstaged = next != null ? [next] : [];
IsStaging = true;
_repo.SetWatcherEnabled(false);
if (changes.Count == _unstaged.Count)
{
await Task.Run(() => new Commands.Add(_repo.FullPath, _repo.IncludeUntracked).Exec());
}
else if (Native.OS.GitVersion >= Models.GitVersions.ADD_WITH_PATHSPECFILE)
{
var paths = new List<string>();
foreach (var c in changes)
paths.Add(c.Path);
var tmpFile = Path.GetTempFileName();
File.WriteAllLines(tmpFile, paths);
await Task.Run(() => new Commands.Add(_repo.FullPath, tmpFile).Exec());
File.Delete(tmpFile);
}
else
{
for (int i = 0; i < changes.Count; i += 10)
{
var count = Math.Min(10, changes.Count - i);
var step = changes.GetRange(i, count);
await Task.Run(() => new Commands.Add(_repo.FullPath, step).Exec());
}
}
_repo.MarkWorkingCopyDirtyManually();
_repo.SetWatcherEnabled(true);
IsStaging = false;
}
private async void UnstageChanges(List<Models.Change> changes, Models.Change next)
{
if (changes.Count == 0)
return;
// Use `_selectedStaged` instead of `SelectedStaged` to avoid UI refresh.
_selectedStaged = next != null ? [next] : [];
IsUnstaging = true;
_repo.SetWatcherEnabled(false);
if (_useAmend)
{
await Task.Run(() => new Commands.UnstageChangesForAmend(_repo.FullPath, changes).Exec());
}
else if (changes.Count == _staged.Count)
{
await Task.Run(() => new Commands.Reset(_repo.FullPath).Exec());
}
else
{
for (int i = 0; i < changes.Count; i += 10)
{
var count = Math.Min(10, changes.Count - i);
var step = changes.GetRange(i, count);
await Task.Run(() => new Commands.Reset(_repo.FullPath, step).Exec());
}
}
_repo.MarkWorkingCopyDirtyManually();
_repo.SetWatcherEnabled(true);
IsUnstaging = false;
}
private void SetDetail(Models.Change change, bool isUnstaged)
{
if (_isLoadingData)
@ -1599,39 +1650,22 @@ namespace SourceGit.ViewModels
return false;
}
private IList<Models.OpenAIService> GetPreferedOpenAIServices()
{
var services = Preferences.Instance.OpenAIServices;
if (services == null || services.Count == 0)
return [];
if (services.Count == 1)
return services;
var prefered = _repo.Settings.PreferedOpenAIService;
foreach (var service in services)
{
if (service.Name.Equals(prefered, StringComparison.Ordinal))
return [service];
}
return services;
}
private Repository _repo = null;
private bool _isLoadingData = false;
private bool _isStaging = false;
private bool _isUnstaging = false;
private bool _isCommitting = false;
private bool _useAmend = false;
private bool _canCommitWithPush = false;
private bool _hasRemotes = false;
private List<Models.Change> _cached = [];
private List<Models.Change> _unstaged = [];
private List<Models.Change> _visibleUnstaged = [];
private List<Models.Change> _staged = [];
private List<Models.Change> _selectedUnstaged = [];
private List<Models.Change> _selectedStaged = [];
private int _count = 0;
private object _detailContext = null;
private string _unstagedFilter = string.Empty;
private string _commitMessage = string.Empty;
private bool _hasUnsolvedConflicts = false;

View file

@ -10,7 +10,7 @@
x:Name="ThisControl"
Icon="/App.ico"
Title="{DynamicResource Text.AIAssistant}"
Width="400" SizeToContent="Height"
Width="520" SizeToContent="Height"
CanResize="False"
WindowStartupLocation="CenterOwner">
<Grid RowDefinitions="Auto,Auto,Auto">
@ -36,18 +36,33 @@
IsVisible="{OnPlatform True, macOS=False}"/>
</Grid>
<!-- Animated Icon -->
<v:LoadingIcon Grid.Row="1"
Width="24" Height="24"
Margin="0,16,0,0"/>
<!-- AI response -->
<v:AIResponseView Grid.Row="1"
x:Name="TxtResponse"
Margin="8"
Height="320"
BorderThickness="1"
BorderBrush="{DynamicResource Brush.Border2}"
Background="{DynamicResource Brush.Contents}"/>
<!-- Message -->
<TextBlock Grid.Row="2"
x:Name="ProgressMessage"
Margin="16"
FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
HorizontalAlignment="Center"
Text="Generating commit message... Please wait!"
TextTrimming="CharacterEllipsis"/>
<!-- Options -->
<Border Grid.Row="2" Margin="0,0,0,8">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<v:LoadingIcon x:Name="IconInProgress" Width="14" Height="14" Margin="0,0,8,0"/>
<Button Classes="flat"
x:Name="BtnGenerateCommitMessage"
Height="28"
Margin="0,0,8,0"
Padding="12,0"
Content="{DynamicResource Text.AIAssistant.Use}"
Click="OnGenerateCommitMessage"/>
<Button Classes="flat"
x:Name="BtnRegenerate"
Height="28"
Padding="12,0"
Content="{DynamicResource Text.AIAssistant.Regen}"
Click="OnRegen"/>
</StackPanel>
</Border>
</Grid>
</v:ChromelessWindow>

View file

@ -2,27 +2,111 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Threading;
using AvaloniaEdit;
using AvaloniaEdit.Document;
using AvaloniaEdit.Editing;
using AvaloniaEdit.TextMate;
namespace SourceGit.Views
{
public class AIResponseView : TextEditor
{
protected override Type StyleKeyOverride => typeof(TextEditor);
public AIResponseView() : base(new TextArea(), new TextDocument())
{
IsReadOnly = true;
ShowLineNumbers = false;
WordWrap = true;
HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled;
VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
TextArea.TextView.Margin = new Thickness(4, 0);
TextArea.TextView.Options.EnableHyperlinks = false;
TextArea.TextView.Options.EnableEmailHyperlinks = false;
}
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
TextArea.TextView.ContextRequested += OnTextViewContextRequested;
if (_textMate == null)
{
_textMate = Models.TextMateHelper.CreateForEditor(this);
Models.TextMateHelper.SetGrammarByFileName(_textMate, "README.md");
}
}
protected override void OnUnloaded(RoutedEventArgs e)
{
base.OnUnloaded(e);
TextArea.TextView.ContextRequested -= OnTextViewContextRequested;
if (_textMate != null)
{
_textMate.Dispose();
_textMate = null;
}
GC.Collect();
}
private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e)
{
var selected = SelectedText;
if (string.IsNullOrEmpty(selected))
return;
var copy = new MenuItem() { Header = App.Text("Copy") };
copy.Click += (_, ev) =>
{
App.CopyText(selected);
ev.Handled = true;
};
if (this.FindResource("Icons.Copy") is Geometry geo)
{
copy.Icon = new Avalonia.Controls.Shapes.Path()
{
Width = 10,
Height = 10,
Stretch = Stretch.Uniform,
Data = geo,
};
}
var menu = new ContextMenu();
menu.Items.Add(copy);
menu.Open(TextArea.TextView);
e.Handled = true;
}
private TextMate.Installation _textMate = null;
}
public partial class AIAssistant : ChromelessWindow
{
public AIAssistant()
{
_cancel = new CancellationTokenSource();
InitializeComponent();
}
public AIAssistant(Models.OpenAIService service, string repo, List<Models.Change> changes, Action<string> onDone)
public AIAssistant(Models.OpenAIService service, string repo, ViewModels.WorkingCopy wc, List<Models.Change> changes)
{
_service = service;
_repo = repo;
_wc = wc;
_changes = changes;
_onDone = onDone;
_cancel = new CancellationTokenSource();
InitializeComponent();
}
@ -30,39 +114,63 @@ namespace SourceGit.Views
protected override void OnOpened(EventArgs e)
{
base.OnOpened(e);
if (string.IsNullOrEmpty(_repo))
return;
Task.Run(() =>
{
var message = new Commands.GenerateCommitMessage(_service, _repo, _changes, _cancel.Token, SetDescription).Result();
if (_cancel.IsCancellationRequested)
return;
Dispatcher.UIThread.Invoke(() =>
{
_onDone?.Invoke(message);
Close();
});
}, _cancel.Token);
Generate();
}
protected override void OnClosing(WindowClosingEventArgs e)
{
base.OnClosing(e);
_cancel.Cancel();
_cancel?.Cancel();
}
private void SetDescription(string message)
private void OnGenerateCommitMessage(object sender, RoutedEventArgs e)
{
Dispatcher.UIThread.Invoke(() => ProgressMessage.Text = message);
if (_wc != null)
_wc.CommitMessage = TxtResponse.Text;
Close();
}
private void OnRegen(object sender, RoutedEventArgs e)
{
TxtResponse.Text = string.Empty;
Generate();
e.Handled = true;
}
private void Generate()
{
if (_repo == null)
return;
IconInProgress.IsVisible = true;
BtnGenerateCommitMessage.IsEnabled = false;
BtnRegenerate.IsEnabled = false;
_cancel = new CancellationTokenSource();
Task.Run(() =>
{
new Commands.GenerateCommitMessage(_service, _repo, _changes, _cancel.Token, message =>
{
Dispatcher.UIThread.Invoke(() => TxtResponse.Text = message);
}).Exec();
if (!_cancel.IsCancellationRequested)
{
Dispatcher.UIThread.Invoke(() =>
{
IconInProgress.IsVisible = false;
BtnGenerateCommitMessage.IsEnabled = true;
BtnRegenerate.IsEnabled = true;
});
}
}, _cancel.Token);
}
private Models.OpenAIService _service;
private string _repo;
private ViewModels.WorkingCopy _wc;
private List<Models.Change> _changes;
private Action<string> _onDone;
private CancellationTokenSource _cancel;
}
}

View file

@ -0,0 +1,38 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:c="using:SourceGit.Converters"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.ApplyStash"
x:DataType="vm:ApplyStash">
<StackPanel Orientation="Vertical" Margin="8,0,0,0">
<TextBlock FontSize="18"
Classes="bold"
Text="{DynamicResource Text.ApplyStash}"/>
<Grid Margin="0,16,8,0" RowDefinitions="32,32,32" ColumnDefinitions="100,*">
<TextBlock Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
Text="{DynamicResource Text.ApplyStash.Stash}"/>
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
<Path Width="12" Height="12" Margin="2,0,8,0"
HorizontalAlignment="Left" VerticalAlignment="Center"
Data="{StaticResource Icons.Stashes}"/>
<TextBlock VerticalAlignment="Center" Classes="primary" Text="{Binding Stash.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange"/>
<TextBlock VerticalAlignment="Center" Text="{Binding Stash.Message}" Margin="8,0,0,0"/>
</StackPanel>
<CheckBox Grid.Row="1" Grid.Column="1"
Content="{DynamicResource Text.ApplyStash.RestoreIndex}"
IsChecked="{Binding RestoreIndex, Mode=TwoWay}"
ToolTip.Tip="--index"/>
<CheckBox Grid.Row="2" Grid.Column="1"
Content="{DynamicResource Text.ApplyStash.DropAfterApply}"
IsChecked="{Binding DropAfterApply, Mode=TwoWay}"/>
</Grid>
</StackPanel>
</UserControl>

View file

@ -0,0 +1,13 @@
using Avalonia.Controls;
namespace SourceGit.Views
{
public partial class ApplyStash : UserControl
{
public ApplyStash()
{
InitializeComponent();
}
}
}

View file

@ -10,7 +10,7 @@
<StackPanel Orientation="Vertical" Margin="8,0,0,0">
<TextBlock Classes="bold" FontSize="18" Text="{DynamicResource Text.Clone}"/>
<Grid Margin="8,16,0,0" RowDefinitions="32,Auto,32,32,32" ColumnDefinitions="Auto,*">
<Grid Margin="8,16,0,0" RowDefinitions="32,Auto,32,32,32,32" ColumnDefinitions="Auto,*">
<TextBlock Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Right"
Margin="0,0,8,0"
@ -75,6 +75,11 @@
CornerRadius="3"
Watermark="{DynamicResource Text.Clone.AdditionalParam.Placeholder}"
Text="{Binding ExtraArgs, Mode=TwoWay}"/>
<CheckBox Grid.Row="5" Grid.Column="1"
Content="{DynamicResource Text.Clone.RecurseSubmodules}"
IsChecked="{Binding InitAndUpdateSubmodules, Mode=TwoWay}"
ToolTip.Tip="--recurse-submodules"/>
</Grid>
</StackPanel>
</UserControl>

View file

@ -15,7 +15,7 @@ namespace SourceGit.Views
{
public partial class CommitMessagePresenter : SelectableTextBlock
{
[GeneratedRegex(@"\b([0-9a-fA-F]{10,40})\b")]
[GeneratedRegex(@"\b([0-9a-fA-F]{6,40})\b")]
private static partial Regex REG_SHA_FORMAT();
public static readonly StyledProperty<string> MessageProperty =
@ -172,8 +172,11 @@ namespace SourceGit.Views
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
var point = e.GetCurrentPoint(this);
if (_lastHover != null)
{
var link = _lastHover.Link;
e.Pointer.Capture(null);
if (_lastHover.IsCommitSHA)
@ -181,9 +184,6 @@ namespace SourceGit.Views
var parentView = this.FindAncestorOfType<CommitBaseInfo>();
if (parentView is { DataContext: ViewModels.CommitDetail detail })
{
var point = e.GetCurrentPoint(this);
var link = _lastHover.Link;
if (point.Properties.IsLeftButtonPressed)
{
detail.NavigateTo(_lastHover.Link);
@ -217,9 +217,6 @@ namespace SourceGit.Views
}
else
{
var point = e.GetCurrentPoint(this);
var link = _lastHover.Link;
if (point.Properties.IsLeftButtonPressed)
{
Native.OS.OpenBrowser(link);
@ -255,6 +252,49 @@ namespace SourceGit.Views
return;
}
if (point.Properties.IsLeftButtonPressed && e.ClickCount == 3)
{
var text = Inlines?.Text;
if (string.IsNullOrEmpty(text))
{
e.Handled = true;
return;
}
var position = e.GetPosition(this) - new Point(Padding.Left, Padding.Top);
var x = Math.Min(Math.Max(position.X, 0), Math.Max(TextLayout.WidthIncludingTrailingWhitespace, 0));
var y = Math.Min(Math.Max(position.Y, 0), Math.Max(TextLayout.Height, 0));
position = new Point(x, y);
var textPos = TextLayout.HitTestPoint(position).TextPosition;
var lineStart = 0;
var lineEnd = text.IndexOf('\n', lineStart);
if (lineEnd <= 0)
{
lineEnd = text.Length;
}
else
{
while (lineEnd < textPos)
{
lineStart = lineEnd + 1;
lineEnd = text.IndexOf('\n', lineStart);
if (lineEnd == -1)
{
lineEnd = text.Length;
break;
}
}
}
SetCurrentValue(SelectionStartProperty, lineStart);
SetCurrentValue(SelectionEndProperty, lineEnd);
e.Pointer.Capture(this);
e.Handled = true;
return;
}
base.OnPointerPressed(e);
}

View file

@ -20,6 +20,7 @@
<RowDefinition Height="32"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0"
@ -63,13 +64,19 @@
Text="{Binding Name, Mode=TwoWay}"
Watermark="{DynamicResource Text.CreateBranch.Name.Placeholder}"
v:AutoFocusBehaviour.IsEnabled="True"/>
<StackPanel Grid.Row="2" Grid.Column="1"
Orientation="Horizontal"
IsVisible="{Binding Name, Converter={x:Static c:StringConverters.ContainsSpaces}}">
<Path Width="10" Height="10" Data="{StaticResource Icons.Error}" Fill="DarkOrange"/>
<TextBlock Classes="small" Text="{DynamicResource Text.CreateBranch.Name.WarnSpace}" Margin="4,0,0,0"/>
</StackPanel>
<TextBlock Grid.Row="2" Grid.Column="0"
<TextBlock Grid.Row="3" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
Text="{DynamicResource Text.CreateBranch.LocalChanges}"
IsVisible="{Binding !IsBareRepository}"/>
<Border Grid.Row="2" Grid.Column="1" MinHeight="32" IsVisible="{Binding !IsBareRepository}">
<Border Grid.Row="3" Grid.Column="1" MinHeight="32" IsVisible="{Binding !IsBareRepository}">
<WrapPanel Orientation="Horizontal" VerticalAlignment="Center">
<RadioButton Content="{DynamicResource Text.CreateBranch.LocalChanges.DoNothing}"
x:Name="RadioDoNothing"
@ -88,7 +95,7 @@
</WrapPanel>
</Border>
<CheckBox Grid.Row="3" Grid.Column="1"
<CheckBox Grid.Row="4" Grid.Column="1"
Content="{DynamicResource Text.CreateBranch.Checkout}"
IsChecked="{Binding CheckoutAfterCreated, Mode=TwoWay}"
IsVisible="{Binding !IsBareRepository}"/>

View file

@ -17,12 +17,12 @@
Text="{DynamicResource Text.DeleteRepositoryNode.TitleForRepository}"
IsVisible="{Binding Node.IsRepository}"/>
<Grid Margin="0,16,8,0" Height="28" ColumnDefinitions="120,*">
<TextBlock Grid.Column="0"
<Grid Margin="0,16,8,0" RowDefinitions="32,Auto,32" ColumnDefinitions="120,*">
<TextBlock Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
Text="{DynamicResource Text.DeleteRepositoryNode.Target}"/>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
<Path Width="12" Height="12" Margin="0,0,8,0"
Fill="{Binding Node.Bookmark, Converter={x:Static c:IntConverters.ToBookmarkBrush}}"
HorizontalAlignment="Left" VerticalAlignment="Center"
@ -35,8 +35,32 @@
IsVisible="{Binding !Node.IsRepository}"/>
<TextBlock VerticalAlignment="Center" Text="{Binding Node.Name}"/>
<TextBlock Margin="8,0" HorizontalAlignment="Right" VerticalAlignment="Center" Foreground="{DynamicResource Brush.FG2}" Text="{Binding Node.Id}" IsVisible="{Binding Node.IsRepository}"/>
</StackPanel>
<TextBlock Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
Text="{DynamicResource Text.DeleteRepositoryNode.Path}"
IsVisible="{Binding Node.IsRepository}"/>
<StackPanel Grid.Row="1" Grid.Column="1" Height="32" Orientation="Horizontal" IsVisible="{Binding Node.IsRepository}">
<Path Width="12" Height="12"
Margin="0,0,8,0"
Fill="{DynamicResource Brush.FG1}"
HorizontalAlignment="Left" VerticalAlignment="Center"
Data="{StaticResource Icons.Folder}"/>
<TextBlock Text="{Binding Node.Id}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</StackPanel>
<Grid Grid.Row="2" Grid.Column="1">
<TextBlock Text="{DynamicResource Text.DeleteRepositoryNode.TipForRepository}"
TextWrapping="Wrap"
Foreground="{DynamicResource Brush.FG2}"
IsVisible="{Binding Node.IsRepository}"/>
<TextBlock Text="{DynamicResource Text.DeleteRepositoryNode.TipForGroup}"
TextWrapping="Wrap"
Foreground="{DynamicResource Brush.FG2}"
IsVisible="{Binding !Node.IsRepository}"/>
</Grid>
</Grid>
</StackPanel>
</UserControl>

View file

@ -129,6 +129,7 @@
<ToggleButton Classes="line_path"
Width="28"
IsChecked="{Binding IgnoreWhitespace, Mode=TwoWay}"
IsVisible="{Binding IsTextDiff}"
ToolTip.Tip="{DynamicResource Text.Diff.IgnoreWhitespace}">
<Path Width="14" Height="14" Stretch="Uniform" Data="{StaticResource Icons.Whitespace}"/>
</ToggleButton>

View file

@ -56,8 +56,8 @@
Margin="8,4,4,8"
BorderBrush="{DynamicResource Brush.Border2}"
ItemsSource="{Binding Commits}"
SelectedItem="{Binding SelectedCommit, Mode=TwoWay}"
SelectionMode="Single"
SelectedItems="{Binding SelectedCommits, Mode=TwoWay}"
SelectionMode="Multiple"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.Styles>
@ -107,22 +107,20 @@
BorderThickness="1,0,0,0"
BorderBrush="{DynamicResource Brush.Border0}"/>
<v:LoadingIcon Grid.Column="2"
Width="48" Height="48"
HorizontalAlignment="Center" VerticalAlignment="Center"
IsVisible="{Binding IsLoading}"/>
<Grid Grid.Column="2" RowDefinitions="Auto,*,Auto" IsVisible="{Binding !IsLoading}">
<ContentControl Grid.Column="2" Content="{Binding ViewContent}">
<ContentControl.DataTemplates>
<DataTemplate DataType="vm:FileHistoriesSingleRevision">
<Grid RowDefinitions="Auto,*,Auto">
<StackPanel Grid.Row="0" Margin="0,8" Height="28" HorizontalAlignment="Center" Orientation="Horizontal">
<RadioButton Classes="switch_button"
GroupName="SearchGroup"
IsChecked="{Binding !IsViewContent, Mode=OneWay}">
IsChecked="{Binding IsDiffMode, Mode=OneWay}">
<TextBlock Margin="16,0" Text="{DynamicResource Text.FileHistory.FileChange}" FontWeight="Bold"/>
</RadioButton>
<RadioButton Classes="switch_button"
GroupName="SearchGroup"
IsChecked="{Binding IsViewContent, Mode=TwoWay}">
IsChecked="{Binding !IsDiffMode, Mode=TwoWay}">
<TextBlock Margin="16,0" Text="{DynamicResource Text.FileHistory.FileContent}" FontWeight="Bold"/>
</RadioButton>
</StackPanel>
@ -164,6 +162,77 @@
Content="{DynamicResource Text.ChangeCM.CheckoutThisRevision}"
Click="OnResetToSelectedRevision"/>
</Grid>
</DataTemplate>
<DataTemplate DataType="vm:FileHistoriesCompareRevisions">
<Grid RowDefinitions="Auto,*">
<Grid Grid.Row="0" Margin="4,6" ColumnDefinitions="*,32,*,Auto">
<Grid.DataTemplates>
<DataTemplate DataType="m:Commit">
<Grid RowDefinitions="Auto,*">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto,Auto,Auto">
<v:Avatar Width="16" Height="16" VerticalAlignment="Center" IsHitTestVisible="False" User="{Binding Author}"/>
<TextBlock Grid.Column="1" Classes="primary" Text="{Binding Author.Name}" Margin="8,0,0,0"/>
<Border Grid.Column="2" Background="{DynamicResource Brush.Accent}" CornerRadius="4" IsVisible="{Binding IsCurrentHead}">
<TextBlock Text="HEAD" Classes="primary" Margin="4,0" Foreground="#FFDDDDDD"/>
</Border>
<TextBlock Grid.Column="3" Classes="primary" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0" TextDecorations="Underline" Cursor="Hand" PointerPressed="OnPressCommitSHA" />
<TextBlock Grid.Column="4" Classes="primary" Text="{Binding CommitterTimeStr}" Foreground="{DynamicResource Brush.FG2}" Margin="8,0,0,0"/>
</Grid>
<TextBlock Grid.Row="1" Classes="primary" Text="{Binding Subject}" VerticalAlignment="Bottom"/>
</Grid>
</DataTemplate>
</Grid.DataTemplates>
<Border Grid.Column="0" BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="1" Background="{DynamicResource Brush.Contents}" CornerRadius="4" Padding="4">
<ContentControl Content="{Binding StartPoint}"/>
</Border>
<Button Grid.Column="1" Classes="icon_button" Command="{Binding Swap}" HorizontalAlignment="Center" ToolTip.Tip="{DynamicResource Text.Diff.SwapCommits}">
<Path Width="16" Height="16" Data="{DynamicResource Icons.Compare}"/>
</Button>
<Border Grid.Column="2" BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="1" Background="{DynamicResource Brush.Contents}" CornerRadius="4" Padding="4">
<ContentControl Content="{Binding EndPoint}"/>
</Border>
<Button Grid.Column="3" Classes="icon_button" Width="32" Click="OnSaveAsPatch" ToolTip.Tip="{DynamicResource Text.Diff.SaveAsPatch}">
<Path Width="16" Height="16" Data="{DynamicResource Icons.Diff}"/>
</Button>
</Grid>
<ContentControl Grid.Row="1" Margin="4,4,8,8" Content="{Binding ViewContent}">
<ContentControl.DataTemplates>
<DataTemplate DataType="vm:DiffContext">
<v:DiffView/>
</DataTemplate>
</ContentControl.DataTemplates>
</ContentControl>
</Grid>
</DataTemplate>
<DataTemplate DataType="x:Int32">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<Path Width="128" Height="128"
Data="{StaticResource Icons.Detail}"
HorizontalAlignment="Center"
Fill="{DynamicResource Brush.FG2}"/>
<TextBlock HorizontalAlignment="Center"
Margin="0,16"
FontSize="24" FontWeight="Bold"
Foreground="{DynamicResource Brush.FG2}"
Text="{Binding Converter={x:Static c:StringConverters.FormatByResourceKey}, ConverterParameter='Histories.Selected'}"/>
</StackPanel>
</DataTemplate>
</ContentControl.DataTemplates>
</ContentControl>
<v:LoadingIcon Grid.Column="2"
Width="48" Height="48"
HorizontalAlignment="Center" VerticalAlignment="Center"
IsVisible="{Binding IsLoading}"/>
</Grid>
<Border Grid.Row="1" x:Name="NotifyDonePanel" Background="Transparent" IsVisible="False" PointerPressed="OnCloseNotifyPanel">

View file

@ -1,6 +1,7 @@
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
namespace SourceGit.Views
{
@ -22,11 +23,11 @@ namespace SourceGit.Views
e.Handled = true;
}
private void OnResetToSelectedRevision(object _, RoutedEventArgs e)
private void OnResetToSelectedRevision(object sender, RoutedEventArgs e)
{
if (DataContext is ViewModels.FileHistories vm)
if (sender is Button { DataContext: ViewModels.FileHistoriesSingleRevision single })
{
vm.ResetToSelectedRevision();
single.ResetToSelectedRevision();
NotifyDonePanel.IsVisible = true;
}
@ -38,5 +39,23 @@ namespace SourceGit.Views
NotifyDonePanel.IsVisible = false;
e.Handled = true;
}
private async void OnSaveAsPatch(object sender, RoutedEventArgs e)
{
if (sender is Button { DataContext: ViewModels.FileHistoriesCompareRevisions compare })
{
var options = new FilePickerSaveOptions();
options.Title = App.Text("FileCM.SaveAsPatch");
options.DefaultExtension = ".patch";
options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }];
var storageFile = await this.StorageProvider.SaveFilePickerAsync(options);
if (storageFile != null)
await compare.SaveAsPatch(storageFile.Path.LocalPath);
NotifyDonePanel.IsVisible = true;
e.Handled = true;
}
}
}
}

View file

@ -92,6 +92,20 @@ namespace SourceGit.Views
return availableSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
if (Image is { } image)
{
var imageSize = image.Size;
var scaleW = finalSize.Width / imageSize.Width;
var scaleH = finalSize.Height / imageSize.Height;
var scale = Math.Min(scaleW, scaleH);
return new Size(scale * imageSize.Width, scale * imageSize.Height);
}
return base.ArrangeOverride(finalSize);
}
}
public class ImageSwipeControl : ImageContainer

View file

@ -146,7 +146,8 @@ namespace SourceGit.Views
return;
}
if (e.Key == Key.Q) {
if (e.Key == Key.Q)
{
App.Quit(0);
e.Handled = true;
return;

View file

@ -7,7 +7,7 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.LauncherTabBar"
x:DataType="vm:Launcher">
<Grid ColumnDefinitions="Auto,*,Auto">
<Grid ColumnDefinitions="Auto,*,Auto,Auto">
<RepeatButton x:Name="LeftScrollIndicator" Grid.Column="0" Classes="icon_button" Width="18" Height="30" Click="ScrollTabsLeft">
<Path Width="8" Height="14" Stretch="Fill" Data="{StaticResource Icons.TriangleLeft}"/>
</RepeatButton>
@ -96,7 +96,8 @@
</ListBox.ItemTemplate>
</ListBox>
<Button Classes="icon_button"
<Button x:Name="InnerNewTabBtn"
Classes="icon_button"
Width="16" Height="16"
Margin="8,0"
Command="{Binding AddNewTab}">
@ -115,5 +116,21 @@
<RepeatButton x:Name="RightScrollIndicator" Grid.Column="2" Classes="icon_button" Width="18" Height="30" Click="ScrollTabsRight">
<Path Width="8" Height="14" Stretch="Fill" Data="{StaticResource Icons.TriangleRight}"/>
</RepeatButton>
<Button x:Name="OuterNewTabBtn"
Grid.Column="3"
Classes="icon_button"
Width="16" Height="16"
Margin="8,0"
Command="{Binding AddNewTab}">
<ToolTip.Tip>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="{DynamicResource Text.PageTabBar.New}" VerticalAlignment="Center"/>
<TextBlock Margin="16,0,0,0" Text="{OnPlatform Ctrl+T, macOS=⌘+T}" Opacity=".6" FontSize="11" VerticalAlignment="Center"/>
</StackPanel>
</ToolTip.Tip>
<Path Width="12" Height="12" Data="{StaticResource Icons.Plus}"/>
</Button>
</Grid>
</UserControl>

View file

@ -43,6 +43,9 @@ namespace SourceGit.Views
if (containerEndX < startX || containerEndX > endX)
continue;
if (OuterNewTabBtn.IsVisible && i == count - 1)
break;
var separatorX = containerEndX - startX + LauncherTabsScroller.Bounds.X;
context.DrawLine(separatorPen, new Point(separatorX, separatorY), new Point(separatorX, separatorY + 20));
}
@ -88,7 +91,7 @@ namespace SourceGit.Views
x = drawRightX - 6;
}
if (drawRightX < LauncherTabsScroller.Bounds.Right)
if (drawRightX <= LauncherTabsScroller.Bounds.Right)
{
ctx.LineTo(new Point(x, y));
x = drawRightX;
@ -146,11 +149,15 @@ namespace SourceGit.Views
LeftScrollIndicator.IsEnabled = LauncherTabsScroller.Offset.X > 0;
RightScrollIndicator.IsVisible = true;
RightScrollIndicator.IsEnabled = LauncherTabsScroller.Offset.X < LauncherTabsScroller.Extent.Width - LauncherTabsScroller.Viewport.Width;
InnerNewTabBtn.IsVisible = false;
OuterNewTabBtn.IsVisible = true;
}
else
{
LeftScrollIndicator.IsVisible = false;
RightScrollIndicator.IsVisible = false;
InnerNewTabBtn.IsVisible = true;
OuterNewTabBtn.IsVisible = false;
}
InvalidateVisual();

View file

@ -0,0 +1,12 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Data;
namespace SourceGit.Views
{
public class MenuItemExtension : AvaloniaObject
{
public static readonly AttachedProperty<string> CommandProperty =
AvaloniaProperty.RegisterAttached<MenuItemExtension, MenuItem, string>("Command", string.Empty, false, BindingMode.OneWay);
}
}

View file

@ -255,7 +255,7 @@
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Preferences.Git}"/>
</TabItem.Header>
<Grid Margin="8" RowDefinitions="32,32,32,32,32,32" ColumnDefinitions="Auto,*">
<Grid Margin="8" RowDefinitions="32,32,32,32,32,32,32" ColumnDefinitions="Auto,*">
<TextBlock Grid.Row="0" Grid.Column="0"
Text="{DynamicResource Text.Preferences.Git.Path}"
HorizontalAlignment="Right"
@ -329,6 +329,11 @@
</ComboBox>
<CheckBox Grid.Row="5" Grid.Column="1"
Height="32"
Content="{DynamicResource Text.Preferences.Git.EnablePruneOnFetch}"
IsChecked="{Binding #ThisControl.EnablePruneOnFetch, Mode=TwoWay}"/>
<CheckBox Grid.Row="6" Grid.Column="1"
Height="32"
Content="{DynamicResource Text.Preferences.Git.SSLVerify}"
IsChecked="{Binding #ThisControl.EnableHTTPSSLVerify, Mode=TwoWay}"/>

View file

@ -28,6 +28,12 @@ namespace SourceGit.Views
set;
} = null;
public bool EnablePruneOnFetch
{
get;
set;
}
public static readonly StyledProperty<string> GitVersionProperty =
AvaloniaProperty.Register<Preferences, string>(nameof(GitVersion));
@ -114,6 +120,8 @@ namespace SourceGit.Views
GPGUserKey = signingKey;
if (config.TryGetValue("core.autocrlf", out var crlf))
CRLFMode = Models.CRLFMode.Supported.Find(x => x.Value == crlf);
if (config.TryGetValue("fetch.prune", out var pruneOnFetch))
EnablePruneOnFetch = (pruneOnFetch == "true");
if (config.TryGetValue("commit.gpgsign", out var gpgCommitSign))
EnableGPGCommitSigning = (gpgCommitSign == "true");
if (config.TryGetValue("tag.gpgsign", out var gpgTagSign))
@ -157,6 +165,7 @@ namespace SourceGit.Views
SetIfChanged(config, "user.email", DefaultEmail, "");
SetIfChanged(config, "user.signingkey", GPGUserKey, "");
SetIfChanged(config, "core.autocrlf", CRLFMode != null ? CRLFMode.Value : null, null);
SetIfChanged(config, "fetch.prune", EnablePruneOnFetch ? "true" : "false", "false");
SetIfChanged(config, "commit.gpgsign", EnableGPGCommitSigning ? "true" : "false", "false");
SetIfChanged(config, "tag.gpgsign", EnableGPGTagSigning ? "true" : "false", "false");
SetIfChanged(config, "http.sslverify", EnableHTTPSSLVerify ? "" : "false", "");

View file

@ -479,7 +479,8 @@
SelectedIndex="{Binding SearchCommitFilterType, Mode=TwoWay}">
<ComboBox.Items>
<TextBlock Text="{DynamicResource Text.Repository.Search.BySHA}" FontSize="12"/>
<TextBlock Text="{DynamicResource Text.Repository.Search.ByUser}" FontSize="12"/>
<TextBlock Text="{DynamicResource Text.Repository.Search.ByAuthor}" FontSize="12"/>
<TextBlock Text="{DynamicResource Text.Repository.Search.ByCommitter}" FontSize="12"/>
<TextBlock Text="{DynamicResource Text.Repository.Search.ByMessage}" FontSize="12"/>
<TextBlock Text="{DynamicResource Text.Repository.Search.ByFile}" FontSize="12"/>
</ComboBox.Items>
@ -597,11 +598,18 @@
<Grid ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" Orientation="Horizontal">
<TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.Rebase}"/>
<TextBlock FontWeight="Bold" Margin="4,0,0,0" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.Rebase.StoppedAt}"/>
<TextBlock FontWeight="Bold" Margin="4,0,0,0" Foreground="DarkOrange" Text="{Binding StoppedAt.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" ToolTip.Tip="{Binding StoppedAt}"/>
<TextBlock FontWeight="Bold" Margin="4,0,0,0" Foreground="{DynamicResource Brush.ConflictForeground}"
Text="{DynamicResource Text.InProgress.Rebase.StoppedAt}"
IsVisible="{Binding StoppedAt, Converter={x:Static ObjectConverters.IsNotNull}}" />
<TextBlock FontWeight="Bold" Margin="4,0,0,0" Foreground="DarkOrange"
Text="{Binding StoppedAt.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}"
IsVisible="{Binding StoppedAt, Converter={x:Static ObjectConverters.IsNotNull}}"
ToolTip.Tip="{Binding StoppedAt}" />
</StackPanel>
<Button Grid.Column="1" Classes="flat" FontWeight="Regular" BorderThickness="0" Content="{DynamicResource Text.Repository.Skip}" Padding="8,2" Click="OnSkipInProgress"/>
<Button Grid.Column="1" Classes="flat" FontWeight="Regular" BorderThickness="0"
Content="{DynamicResource Text.Repository.Skip}" Padding="8,2" Click="OnSkipInProgress"
IsVisible="{Binding StoppedAt, Converter={x:Static ObjectConverters.IsNotNull}}" />
</Grid>
</DataTemplate>

View file

@ -434,6 +434,7 @@ namespace SourceGit.Views
var dateOrder = new MenuItem();
dateOrder.Header = App.Text("Repository.HistoriesOrder.ByDate");
dateOrder.SetValue(MenuItemExtension.CommandProperty, "--date-order");
if (!repo.EnableTopoOrderInHistories)
dateOrder.Icon = App.CreateMenuIcon("Icons.Check");
dateOrder.Click += (_, ev) =>
@ -444,6 +445,7 @@ namespace SourceGit.Views
var topoOrder = new MenuItem();
topoOrder.Header = App.Text("Repository.HistoriesOrder.Topo");
topoOrder.SetValue(MenuItemExtension.CommandProperty, "--top-order");
if (repo.EnableTopoOrderInHistories)
topoOrder.Icon = App.CreateMenuIcon("Icons.Check");
topoOrder.Click += (_, ev) =>

View file

@ -45,7 +45,7 @@
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Configure.Git}"/>
</TabItem.Header>
<Grid Margin="16,4,16,8" RowDefinitions="32,32,32,32,32,32,32,32,32,32" ColumnDefinitions="Auto,*">
<Grid Margin="16,4,16,8" RowDefinitions="32,32,32,32,32,32,32,32" ColumnDefinitions="Auto,*">
<TextBlock Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
@ -117,18 +117,10 @@
IsChecked="{Binding GPGCommitSigningEnabled, Mode=TwoWay}"/>
<CheckBox Grid.Row="6" Grid.Column="1"
Content="{DynamicResource Text.Configure.Git.EnableSignOff}"
IsChecked="{Binding EnableSignOffForCommit, Mode=TwoWay}"/>
<CheckBox Grid.Row="7" Grid.Column="1"
Content="{DynamicResource Text.Preferences.GPG.TagEnabled}"
IsChecked="{Binding GPGTagSigningEnabled, Mode=TwoWay}"/>
<CheckBox Grid.Row="8" Grid.Column="1"
Content="{DynamicResource Text.Configure.Git.EnablePruneOnFetch}"
IsChecked="{Binding EnablePruneOnFetch, Mode=TwoWay}"/>
<StackPanel Grid.Row="9" Grid.Column="1" Orientation="Horizontal">
<StackPanel Grid.Row="7" Grid.Column="1" Orientation="Horizontal">
<CheckBox x:Name="AutoFetchCheckBox"
Content="{DynamicResource Text.Configure.Git.AutoFetch}"
IsChecked="{Binding EnableAutoFetch, Mode=TwoWay}"/>

View file

@ -1,7 +1,117 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Avalonia.Media;
using AvaloniaEdit;
using AvaloniaEdit.Document;
using AvaloniaEdit.Editing;
using AvaloniaEdit.TextMate;
namespace SourceGit.Views
{
public class RevisionTextFileView : TextEditor
{
protected override Type StyleKeyOverride => typeof(TextEditor);
public RevisionTextFileView() : base(new TextArea(), new TextDocument())
{
IsReadOnly = true;
ShowLineNumbers = true;
WordWrap = false;
HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
TextArea.LeftMargins[0].Margin = new Thickness(8, 0);
TextArea.TextView.Margin = new Thickness(4, 0);
TextArea.TextView.Options.EnableHyperlinks = false;
TextArea.TextView.Options.EnableEmailHyperlinks = false;
}
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
TextArea.TextView.ContextRequested += OnTextViewContextRequested;
UpdateTextMate();
}
protected override void OnUnloaded(RoutedEventArgs e)
{
base.OnUnloaded(e);
TextArea.TextView.ContextRequested -= OnTextViewContextRequested;
if (_textMate != null)
{
_textMate.Dispose();
_textMate = null;
}
GC.Collect();
}
protected override void OnDataContextChanged(EventArgs e)
{
base.OnDataContextChanged(e);
if (DataContext is Models.RevisionTextFile source)
{
UpdateTextMate();
Text = source.Content;
}
else
{
Text = string.Empty;
}
}
private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e)
{
var selected = SelectedText;
if (string.IsNullOrEmpty(selected))
return;
var copy = new MenuItem() { Header = App.Text("Copy") };
copy.Click += (_, ev) =>
{
App.CopyText(selected);
ev.Handled = true;
};
if (this.FindResource("Icons.Copy") is Geometry geo)
{
copy.Icon = new Avalonia.Controls.Shapes.Path()
{
Width = 10,
Height = 10,
Stretch = Stretch.Uniform,
Data = geo,
};
}
var menu = new ContextMenu();
menu.Items.Add(copy);
menu.Open(TextArea.TextView);
e.Handled = true;
}
private void UpdateTextMate()
{
if (_textMate == null)
_textMate = Models.TextMateHelper.CreateForEditor(this);
if (DataContext is Models.RevisionTextFile file)
Models.TextMateHelper.SetGrammarByFileName(_textMate, file.FileName);
}
private TextMate.Installation _textMate = null;
}
public partial class RevisionFileContentViewer : UserControl
{
public RevisionFileContentViewer()

View file

@ -1,118 +1,8 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;
using AvaloniaEdit;
using AvaloniaEdit.Document;
using AvaloniaEdit.Editing;
using AvaloniaEdit.TextMate;
namespace SourceGit.Views
{
public class RevisionTextFileView : TextEditor
{
protected override Type StyleKeyOverride => typeof(TextEditor);
public RevisionTextFileView() : base(new TextArea(), new TextDocument())
{
IsReadOnly = true;
ShowLineNumbers = true;
WordWrap = false;
HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
TextArea.LeftMargins[0].Margin = new Thickness(8, 0);
TextArea.TextView.Margin = new Thickness(4, 0);
TextArea.TextView.Options.EnableHyperlinks = false;
TextArea.TextView.Options.EnableEmailHyperlinks = false;
}
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
TextArea.TextView.ContextRequested += OnTextViewContextRequested;
UpdateTextMate();
}
protected override void OnUnloaded(RoutedEventArgs e)
{
base.OnUnloaded(e);
TextArea.TextView.ContextRequested -= OnTextViewContextRequested;
if (_textMate != null)
{
_textMate.Dispose();
_textMate = null;
}
GC.Collect();
}
protected override void OnDataContextChanged(EventArgs e)
{
base.OnDataContextChanged(e);
if (DataContext is Models.RevisionTextFile source)
{
UpdateTextMate();
Text = source.Content;
}
else
{
Text = string.Empty;
}
}
private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e)
{
var selected = SelectedText;
if (string.IsNullOrEmpty(selected))
return;
var copy = new MenuItem() { Header = App.Text("Copy") };
copy.Click += (_, ev) =>
{
App.CopyText(selected);
ev.Handled = true;
};
if (this.FindResource("Icons.Copy") is Geometry geo)
{
copy.Icon = new Avalonia.Controls.Shapes.Path()
{
Width = 10,
Height = 10,
Stretch = Stretch.Uniform,
Data = geo,
};
}
var menu = new ContextMenu();
menu.Items.Add(copy);
menu.Open(TextArea.TextView);
e.Handled = true;
}
private void UpdateTextMate()
{
if (_textMate == null)
_textMate = Models.TextMateHelper.CreateForEditor(this);
if (DataContext is Models.RevisionTextFile file)
Models.TextMateHelper.SetGrammarByFileName(_textMate, file.FileName);
}
private TextMate.Installation _textMate = null;
}
public partial class RevisionFiles : UserControl
{
public RevisionFiles()

View file

@ -11,7 +11,7 @@
<TextBlock FontSize="18"
Classes="bold"
Text="{DynamicResource Text.Stash.Title}"/>
<Grid Margin="8,16,0,0" RowDefinitions="32,Auto,Auto,32,Auto" ColumnDefinitions="120,*">
<Grid Margin="8,16,0,0" RowDefinitions="32,Auto,Auto,32,Auto,Auto" ColumnDefinitions="120,*">
<TextBlock Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Right"
Margin="8,0"
@ -43,7 +43,13 @@
IsChecked="{Binding KeepIndex, Mode=TwoWay}"
ToolTip.Tip="--keep-index"/>
<TextBlock Grid.Row="4" Grid.Column="1"
<CheckBox Grid.Row="4" Grid.Column="1"
Height="32"
Content="{DynamicResource Text.Stash.AutoRestore}"
IsChecked="{Binding AutoRestore, Mode=TwoWay}"
ToolTip.Tip="{DynamicResource Text.Stash.AutoRestore.Tip}"/>
<TextBlock Grid.Row="5" Grid.Column="1"
Margin="0,4,0,0"
Text="{DynamicResource Text.Stash.TipForSelectedFiles}"
TextWrapping="Wrap"

View file

@ -669,6 +669,8 @@ namespace SourceGit.Views
TextArea.TextView.PointerWheelChanged += OnTextViewPointerWheelChanged;
TextArea.TextView.VisualLinesChanged += OnTextViewVisualLinesChanged;
TextArea.AddHandler(KeyDownEvent, OnTextAreaKeyDown, RoutingStrategies.Tunnel);
UpdateTextMate();
OnTextViewVisualLinesChanged(null, null);
}
@ -677,6 +679,8 @@ namespace SourceGit.Views
{
base.OnUnloaded(e);
TextArea.RemoveHandler(KeyDownEvent, OnTextAreaKeyDown);
TextArea.TextView.ContextRequested -= OnTextViewContextRequested;
TextArea.TextView.PointerEntered -= OnTextViewPointerChanged;
TextArea.TextView.PointerMoved -= OnTextViewPointerChanged;
@ -732,6 +736,21 @@ namespace SourceGit.Views
}
}
private void OnTextAreaKeyDown(object sender, KeyEventArgs e)
{
if (e.KeyModifiers.Equals(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control))
{
if (e.Key == Key.C)
{
CopyWithoutIndicators();
e.Handled = true;
}
}
if (!e.Handled)
base.OnKeyDown(e);
}
private void OnBlockNavigationPropertyChanged(object _1, PropertyChangedEventArgs _2)
{
TextArea?.TextView?.Redraw();
@ -748,7 +767,7 @@ namespace SourceGit.Views
copy.Icon = App.CreateMenuIcon("Icons.Copy");
copy.Click += (_, ev) =>
{
App.CopyText(SelectedText);
CopyWithoutIndicators();
ev.Handled = true;
};
@ -941,6 +960,59 @@ namespace SourceGit.Views
}
}
private void CopyWithoutIndicators()
{
var selection = TextArea.Selection;
if (selection.IsEmpty)
{
App.CopyText(string.Empty);
return;
}
var lines = GetLines();
var startIdx = Math.Min(selection.StartPosition.Line - 1, lines.Count - 1);
var endIdx = Math.Min(selection.EndPosition.Line - 1, lines.Count - 1);
if (startIdx == endIdx)
{
var line = lines[startIdx];
if (line.Type == Models.TextDiffLineType.Indicator ||
line.Type == Models.TextDiffLineType.None)
{
App.CopyText(string.Empty);
return;
}
App.CopyText(SelectedText);
return;
}
var builder = new StringBuilder();
for (var i = startIdx; i <= endIdx; i++)
{
var line = lines[i];
if (line.Type == Models.TextDiffLineType.Indicator ||
line.Type == Models.TextDiffLineType.None)
continue;
if (i == startIdx && selection.StartPosition.Column > 1)
{
builder.AppendLine(line.Content.Substring(selection.StartPosition.Column - 1));
continue;
}
if (i == endIdx && selection.EndPosition.Column < line.Content.Length)
{
builder.AppendLine(line.Content.Substring(0, selection.EndPosition.Column));
continue;
}
builder.AppendLine(line.Content);
}
App.CopyText(builder.ToString());
}
private TextMate.Installation _textMate = null;
private TextLocation _lastSelectStart = TextLocation.Empty;
private TextLocation _lastSelectEnd = TextLocation.Empty;

View file

@ -25,7 +25,7 @@
</Grid.RowDefinitions>
<!-- Unstaged -->
<Grid Grid.Row="0" RowDefinitions="28,*">
<Grid Grid.Row="0" RowDefinitions="28,36,*">
<!-- Unstaged Toolbar -->
<Border Grid.Row="0" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}">
<Grid ColumnDefinitions="Auto,Auto,Auto,Auto,*,Auto,Auto,Auto,Auto,Auto">
@ -75,15 +75,47 @@
</Grid>
</Border>
<!-- Unstaged Filter -->
<Border Grid.Row="1" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}">
<TextBox Height="24"
Margin="4,0"
BorderThickness="1"
CornerRadius="12"
Text="{Binding UnstagedFilter, Mode=TwoWay}"
BorderBrush="{DynamicResource Brush.Border2}"
VerticalContentAlignment="Center">
<TextBox.InnerLeftContent>
<Path Width="14" Height="14"
Margin="6,0,0,0"
Fill="{DynamicResource Brush.FG2}"
Data="{StaticResource Icons.Search}"/>
</TextBox.InnerLeftContent>
<TextBox.InnerRightContent>
<Button Classes="icon_button"
Width="16"
Margin="0,0,6,0"
Command="{Binding ClearUnstagedFilter}"
IsVisible="{Binding UnstagedFilter, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
HorizontalAlignment="Right">
<Path Width="14" Height="14"
Margin="0,1,0,0"
Fill="{DynamicResource Brush.FG1}"
Data="{StaticResource Icons.Clear}"/>
</Button>
</TextBox.InnerRightContent>
</TextBox>
</Border>
<!-- Unstaged Changes -->
<v:ChangeCollectionView Grid.Row="1"
<v:ChangeCollectionView Grid.Row="2"
x:Name="UnstagedChangesView"
Focusable="True"
IsUnstagedChange="True"
SelectionMode="Multiple"
Background="{DynamicResource Brush.Contents}"
ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=UnstagedChangeViewMode}"
Changes="{Binding Unstaged}"
Changes="{Binding VisibleUnstaged}"
SelectedChanges="{Binding SelectedUnstaged, Mode=TwoWay}"
ContextRequested="OnUnstagedContextRequested"
ChangeDoubleTapped="OnUnstagedChangeDoubleTapped"
@ -258,7 +290,7 @@
<v:CommitMessageTextBox Grid.Row="2" Text="{Binding CommitMessage, Mode=TwoWay}"/>
<!-- Commit Options -->
<Grid Grid.Row="3" Margin="0,6,0,0" ColumnDefinitions="Auto,Auto,Auto,Auto,*,Auto,Auto,Auto,Auto">
<Grid Grid.Row="3" Margin="0,6,0,0" ColumnDefinitions="Auto,Auto,Auto,Auto,Auto,*,Auto,Auto,Auto">
<Button Grid.Column="0"
Classes="icon_button"
Margin="4,0,0,0" Padding="0"
@ -293,10 +325,26 @@
Height="24"
Margin="8,0,0,0"
HorizontalAlignment="Left"
IsChecked="{Binding UseAmend, Mode=TwoWay}"
Content="{DynamicResource Text.WorkingCopy.Amend}"/>
IsChecked="{Binding EnableSignOff, Mode=TwoWay}"
Content="{DynamicResource Text.WorkingCopy.SignOff}"
ToolTip.Tip="--signoff"
ToolTip.Placement="Top"
ToolTip.VerticalOffset="0"/>
<v:LoadingIcon Grid.Column="5" Width="18" Height="18" IsVisible="{Binding IsCommitting}"/>
<CheckBox Grid.Column="4"
Height="24"
Margin="12,0,0,0"
HorizontalAlignment="Left"
IsChecked="{Binding UseAmend, Mode=TwoWay}"
Content="{DynamicResource Text.WorkingCopy.Amend}"
ToolTip.Tip="--amend"
ToolTip.Placement="Top"
ToolTip.VerticalOffset="0"/>
<v:LoadingIcon Grid.Column="5"
Width="18" Height="18"
HorizontalAlignment="Right"
IsVisible="{Binding IsCommitting}"/>
<SplitButton Grid.Column="6"
Content="{DynamicResource Text.Repository.Continue}"
@ -358,8 +406,8 @@
ToolTip.VerticalOffset="0">
<Button.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.And}">
<Binding Path="HasRemotes"/>
<Binding Path="UseAmend" Converter="{x:Static BoolConverters.Not}"/>
<Binding Path="CanCommitWithPush"/>
<Binding Path="InProgressContext" Converter="{x:Static ObjectConverters.IsNull}"/>
</MultiBinding>
</Button.IsVisible>