Merge branch 'release/v8.25'

This commit is contained in:
leo 2024-08-12 10:13:16 +08:00
commit 2e7d742851
No known key found for this signature in database
72 changed files with 2083 additions and 771 deletions

View file

@ -15,6 +15,7 @@ Opensource Git GUI client.
* GIT commands with GUI * GIT commands with GUI
* Clone/Fetch/Pull/Push... * Clone/Fetch/Pull/Push...
* Merge/Rebase/Reset/Revert/Amend/Cherry-pick... * Merge/Rebase/Reset/Revert/Amend/Cherry-pick...
* Amend/Reword
* Interactive rebase (Basic) * Interactive rebase (Basic)
* Branches * Branches
* Remotes * Remotes
@ -30,8 +31,9 @@ Opensource Git GUI client.
* Revision Diffs * Revision Diffs
* Branch Diff * Branch Diff
* Image Diff - Side-By-Side/Swipe/Blend * Image Diff - Side-By-Side/Swipe/Blend
* GitFlow support * GitFlow
* Git LFS support * Git LFS
* Issue Link
> **Linux** only tested on **Debian 12** on both **X11** & **Wayland**. > **Linux** only tested on **Debian 12** on both **X11** & **Wayland**.

View file

@ -1 +1 @@
8.24 8.25

View file

@ -0,0 +1,26 @@
using System;
namespace SourceGit.Commands
{
public class CountLocalChangesWithoutUntracked : Command
{
public CountLocalChangesWithoutUntracked(string repo)
{
WorkingDirectory = repo;
Context = repo;
Args = "status -uno --ignore-submodules=dirty --porcelain";
}
public int Result()
{
var rs = ReadToEnd();
if (rs.IsSuccess)
{
var lines = rs.StdOut.Split('\n', StringSplitOptions.RemoveEmptyEntries);
return lines.Length;
}
return 0;
}
}
}

View file

@ -7,7 +7,8 @@ namespace SourceGit.Commands
{ {
private const string PREFIX_LOCAL = "refs/heads/"; private const string PREFIX_LOCAL = "refs/heads/";
private const string PREFIX_REMOTE = "refs/remotes/"; private const string PREFIX_REMOTE = "refs/remotes/";
private const string PREFIX_DETACHED = "(HEAD detached at"; private const string PREFIX_DETACHED_AT = "(HEAD detached at";
private const string PREFIX_DETACHED_FROM = "(HEAD detached from";
public QueryBranches(string repo) public QueryBranches(string repo)
{ {
@ -37,9 +38,9 @@ namespace SourceGit.Commands
if (refName.EndsWith("/HEAD", StringComparison.Ordinal)) if (refName.EndsWith("/HEAD", StringComparison.Ordinal))
return; return;
if (refName.StartsWith(PREFIX_DETACHED, StringComparison.Ordinal)) if (refName.StartsWith(PREFIX_DETACHED_AT, StringComparison.Ordinal) || refName.StartsWith(PREFIX_DETACHED_FROM, StringComparison.Ordinal))
{ {
branch.IsHead = true; branch.IsDetachedHead = true;
} }
if (refName.StartsWith(PREFIX_LOCAL, StringComparison.Ordinal)) if (refName.StartsWith(PREFIX_LOCAL, StringComparison.Ordinal))

View file

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace SourceGit.Commands namespace SourceGit.Commands
@ -9,6 +10,8 @@ namespace SourceGit.Commands
private static partial Regex REG_FORMAT1(); private static partial Regex REG_FORMAT1();
[GeneratedRegex(@"^[\-\+ ][0-9a-f]+\s(.*)$")] [GeneratedRegex(@"^[\-\+ ][0-9a-f]+\s(.*)$")]
private static partial Regex REG_FORMAT2(); private static partial Regex REG_FORMAT2();
[GeneratedRegex(@"^\s?[\w\?]{1,4}\s+(.+)$")]
private static partial Regex REG_FORMAT_STATUS();
public QuerySubmodules(string repo) public QuerySubmodules(string repo)
{ {
@ -17,28 +20,59 @@ namespace SourceGit.Commands
Args = "submodule status"; Args = "submodule status";
} }
public List<string> Result() public List<Models.Submodule> Result()
{ {
Exec(); var submodules = new List<Models.Submodule>();
return _submodules; var rs = ReadToEnd();
} if (!rs.IsSuccess)
return submodules;
protected override void OnReadline(string line) var builder = new StringBuilder();
var lines = rs.StdOut.Split('\n', System.StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{ {
var match = REG_FORMAT1().Match(line); var match = REG_FORMAT1().Match(line);
if (match.Success) if (match.Success)
{ {
_submodules.Add(match.Groups[1].Value); var path = match.Groups[1].Value;
return; builder.Append($"\"{path}\" ");
submodules.Add(new Models.Submodule() { Path = path });
continue;
} }
match = REG_FORMAT2().Match(line); match = REG_FORMAT2().Match(line);
if (match.Success) if (match.Success)
{ {
_submodules.Add(match.Groups[1].Value); var path = match.Groups[1].Value;
builder.Append($"\"{path}\" ");
submodules.Add(new Models.Submodule() { Path = path });
} }
} }
private readonly List<string> _submodules = new List<string>(); if (submodules.Count > 0)
{
Args = $"status -uno --porcelain -- {builder}";
rs = ReadToEnd();
if (!rs.IsSuccess)
return submodules;
var dirty = new HashSet<string>();
lines = rs.StdOut.Split('\n', System.StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var match = REG_FORMAT_STATUS().Match(line);
if (match.Success)
{
var path = match.Groups[1].Value;
dirty.Add(path);
}
}
foreach (var submodule in submodules)
submodule.IsDirty = dirty.Contains(submodule.Path);
}
return submodules;
}
} }
} }

View file

@ -34,6 +34,9 @@ namespace SourceGit.Models
if (!Directory.Exists(_storePath)) if (!Directory.Exists(_storePath))
Directory.CreateDirectory(_storePath); Directory.CreateDirectory(_storePath);
var icon = AssetLoader.Open(new Uri($"avares://SourceGit/Resources/Images/github.png", UriKind.RelativeOrAbsolute));
_resources.Add("noreply@github.com", new Bitmap(icon));
Task.Run(() => Task.Run(() =>
{ {
while (true) while (true)
@ -117,19 +120,11 @@ namespace SourceGit.Models
public static Bitmap Request(string email, bool forceRefetch) public static Bitmap Request(string email, bool forceRefetch)
{ {
if (email.Equals("noreply@github.com", StringComparison.Ordinal))
{
if (_githubEmailAvatar == null)
{
var icon = AssetLoader.Open(new Uri($"avares://SourceGit/Resources/Images/github.png", UriKind.RelativeOrAbsolute));
_githubEmailAvatar = new Bitmap(icon);
}
return _githubEmailAvatar;
}
if (forceRefetch) if (forceRefetch)
{ {
if (email.Equals("noreply@github.com", StringComparison.Ordinal))
return null;
if (_resources.ContainsKey(email)) if (_resources.ContainsKey(email))
_resources.Remove(email); _resources.Remove(email);
@ -198,6 +193,5 @@ namespace SourceGit.Models
[GeneratedRegex(@"^(?:(\d+)\+)?(.+?)@users\.noreply\.github\.com$")] [GeneratedRegex(@"^(?:(\d+)\+)?(.+?)@users\.noreply\.github\.com$")]
private static partial Regex REG_GITHUB_USER_EMAIL(); private static partial Regex REG_GITHUB_USER_EMAIL();
private static Bitmap _githubEmailAvatar = null;
} }
} }

View file

@ -28,10 +28,10 @@ namespace SourceGit.Models
public string Head { get; set; } public string Head { get; set; }
public bool IsLocal { get; set; } public bool IsLocal { get; set; }
public bool IsCurrent { get; set; } public bool IsCurrent { get; set; }
public bool IsDetachedHead { get; set; }
public string Upstream { get; set; } public string Upstream { get; set; }
public BranchTrackStatus TrackStatus { get; set; } public BranchTrackStatus TrackStatus { get; set; }
public string Remote { get; set; } public string Remote { get; set; }
public bool IsHead { get; set; }
public string FriendlyName => IsLocal ? Name : $"{Remote}/{Name}"; public string FriendlyName => IsLocal ? Name : $"{Remote}/{Name}";
} }

View file

@ -25,8 +25,6 @@ namespace SourceGit.Models
public bool HasDecorators => Decorators.Count > 0; public bool HasDecorators => Decorators.Count > 0;
public bool IsMerged { get; set; } = false; public bool IsMerged { get; set; } = false;
public bool CanPushToUpstream { get; set; } = false;
public bool CanPullFromUpstream { get; set; } = false;
public Thickness Margin { get; set; } = new Thickness(0); public Thickness Margin { get; set; } = new Thickness(0);
public string AuthorTimeStr => DateTime.UnixEpoch.AddSeconds(AuthorTime).ToLocalTime().ToString("yyyy/MM/dd HH:mm:ss"); public string AuthorTimeStr => DateTime.UnixEpoch.AddSeconds(AuthorTime).ToLocalTime().ToString("yyyy/MM/dd HH:mm:ss");

View file

@ -128,7 +128,7 @@ namespace SourceGit.Models
_penCount = colors.Count; _penCount = colors.Count;
} }
public static CommitGraph Parse(List<Commit> commits, HashSet<string> canPushCommits, HashSet<string> canPullCommits) public static CommitGraph Parse(List<Commit> commits)
{ {
double UNIT_WIDTH = 12; double UNIT_WIDTH = 12;
double HALF_WIDTH = 6; double HALF_WIDTH = 6;
@ -148,9 +148,6 @@ namespace SourceGit.Models
var isMerged = commit.IsMerged; var isMerged = commit.IsMerged;
var oldCount = unsolved.Count; var oldCount = unsolved.Count;
commit.CanPushToUpstream = canPushCommits.Remove(commit.SHA);
commit.CanPullFromUpstream = canPullCommits.Remove(commit.SHA);
// Update current y offset // Update current y offset
offsetY += UNIT_HEIGHT; offsetY += UNIT_HEIGHT;

View file

@ -0,0 +1,114 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.Models
{
public class IssueTrackerMatch
{
public int Start { get; set; } = 0;
public int Length { get; set; } = 0;
public string URL { get; set; } = "";
public bool Intersect(int start, int length)
{
if (start == Start)
return true;
if (start < Start)
return start + length > Start;
return start < Start + Length;
}
}
public class IssueTrackerRule : ObservableObject
{
public string Name
{
get => _name;
set => SetProperty(ref _name, value);
}
public string RegexString
{
get => _regexString;
set
{
if (SetProperty(ref _regexString, value))
{
try
{
_regex = null;
_regex = new Regex(_regexString, RegexOptions.Multiline);
}
catch
{
// Ignore errors.
}
}
OnPropertyChanged(nameof(IsRegexValid));
}
}
public bool IsRegexValid
{
get => _regex != null;
}
public string URLTemplate
{
get => _urlTemplate;
set => SetProperty(ref _urlTemplate, value);
}
public void Matches(List<IssueTrackerMatch> outs, string message)
{
if (_regex == null || string.IsNullOrEmpty(_urlTemplate))
return;
var matches = _regex.Matches(message);
for (var i = 0; i < matches.Count; i++)
{
var match = matches[i];
if (!match.Success)
continue;
var start = match.Index;
var len = match.Length;
var intersect = false;
foreach (var exist in outs)
{
if (exist.Intersect(start, len))
{
intersect = true;
break;
}
}
if (intersect)
continue;
var range = new IssueTrackerMatch();
range.Start = start;
range.Length = len;
range.URL = _urlTemplate;
for (var j = 1; j < match.Groups.Count; j++)
{
var group = match.Groups[j];
if (group.Success)
range.URL = range.URL.Replace($"${j}", group.Value);
}
outs.Add(range);
}
}
private string _name;
private string _regexString;
private string _urlTemplate;
private Regex _regex = null;
}
}

View file

@ -76,6 +76,12 @@ namespace SourceGit.Models
set; set;
} = new AvaloniaList<string>(); } = new AvaloniaList<string>();
public AvaloniaList<IssueTrackerRule> IssueTrackerRules
{
get;
set;
} = new AvaloniaList<IssueTrackerRule>();
public void PushCommitMessage(string message) public void PushCommitMessage(string message)
{ {
var existIdx = CommitMessages.IndexOf(message); var existIdx = CommitMessages.IndexOf(message);
@ -93,5 +99,50 @@ namespace SourceGit.Models
CommitMessages.Insert(0, message); CommitMessages.Insert(0, message);
} }
public IssueTrackerRule AddNewIssueTracker()
{
var rule = new IssueTrackerRule()
{
Name = "New Issue Tracker",
RegexString = "#(\\d+)",
URLTemplate = "https://xxx/$1",
};
IssueTrackerRules.Add(rule);
return rule;
}
public IssueTrackerRule AddGithubIssueTracker(string repoURL)
{
var rule = new IssueTrackerRule()
{
Name = "Github ISSUE",
RegexString = "#(\\d+)",
URLTemplate = string.IsNullOrEmpty(repoURL) ? "https://github.com/username/repository/issues/$1" : $"{repoURL}/issues/$1",
};
IssueTrackerRules.Add(rule);
return rule;
}
public IssueTrackerRule AddJiraIssueTracker()
{
var rule = new IssueTrackerRule()
{
Name = "Jira Tracker",
RegexString = "PROJ-(\\d+)",
URLTemplate = "https://jira.yourcompany.com/browse/PROJ-$1",
};
IssueTrackerRules.Add(rule);
return rule;
}
public void RemoveIssueTracker(IssueTrackerRule rule)
{
if (rule != null)
IssueTrackerRules.Remove(rule);
}
} }
} }

View file

@ -14,6 +14,7 @@ namespace SourceGit.Models
public class RevisionTextFile public class RevisionTextFile
{ {
public string FileName { get; set; }
public string Content { get; set; } public string Content { get; set; }
} }

8
src/Models/Submodule.cs Normal file
View file

@ -0,0 +1,8 @@
namespace SourceGit.Models
{
public class Submodule
{
public string Path { get; set; } = "";
public bool IsDirty { get; set; } = false;
}
}

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -70,6 +71,16 @@ namespace SourceGit.Models
} }
} }
public void SetSubmodules(List<Submodule> submodules)
{
lock (_lockSubmodule)
{
_submodules.Clear();
foreach (var submodule in submodules)
_submodules.Add(submodule.Path);
}
}
public void MarkBranchDirtyManually() public void MarkBranchDirtyManually()
{ {
_updateBranch = DateTime.Now.ToFileTime() - 1; _updateBranch = DateTime.Now.ToFileTime() - 1;
@ -168,9 +179,10 @@ namespace SourceGit.Models
return; return;
var name = e.Name.Replace("\\", "/"); var name = e.Name.Replace("\\", "/");
if (name.StartsWith("modules", StringComparison.Ordinal)) if (name.StartsWith("modules", StringComparison.Ordinal) && name.EndsWith("HEAD", StringComparison.Ordinal))
{ {
_updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime(); _updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime();
_updateWC = DateTime.Now.AddSeconds(1).ToFileTime();
} }
else if (name.StartsWith("refs/tags", StringComparison.Ordinal)) else if (name.StartsWith("refs/tags", StringComparison.Ordinal))
{ {
@ -186,6 +198,12 @@ namespace SourceGit.Models
(name.StartsWith("worktrees/", StringComparison.Ordinal) && name.EndsWith("/HEAD", StringComparison.Ordinal))) (name.StartsWith("worktrees/", StringComparison.Ordinal) && name.EndsWith("/HEAD", StringComparison.Ordinal)))
{ {
_updateBranch = DateTime.Now.AddSeconds(.5).ToFileTime(); _updateBranch = DateTime.Now.AddSeconds(.5).ToFileTime();
lock (_submodules)
{
if (_submodules.Count > 0)
_updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime();
}
} }
else if (name.StartsWith("objects/", StringComparison.Ordinal) || name.Equals("index", StringComparison.Ordinal)) else if (name.StartsWith("objects/", StringComparison.Ordinal) || name.Equals("index", StringComparison.Ordinal))
{ {
@ -201,6 +219,19 @@ namespace SourceGit.Models
var name = e.Name.Replace("\\", "/"); var name = e.Name.Replace("\\", "/");
if (name == ".git" || name.StartsWith(".git/", StringComparison.Ordinal)) if (name == ".git" || name.StartsWith(".git/", StringComparison.Ordinal))
return; return;
lock (_submodules)
{
foreach (var submodule in _submodules)
{
if (name.StartsWith(submodule, StringComparison.Ordinal))
{
_updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime();
return;
}
}
}
_updateWC = DateTime.Now.AddSeconds(1).ToFileTime(); _updateWC = DateTime.Now.AddSeconds(1).ToFileTime();
} }
@ -214,5 +245,8 @@ namespace SourceGit.Models
private long _updateSubmodules = 0; private long _updateSubmodules = 0;
private long _updateStashes = 0; private long _updateStashes = 0;
private long _updateTags = 0; private long _updateTags = 0;
private object _lockSubmodule = new object();
private List<string> _submodules = new List<string>();
} }
} }

View file

@ -52,6 +52,7 @@
<StreamGeometry x:Key="Icons.Info">M512 0C229 0 0 229 0 512s229 512 512 512 512-229 512-512S795 0 512 0zM512 928c-230 0-416-186-416-416S282 96 512 96s416 186 416 416S742 928 512 928zM538 343c47 0 83-38 83-78 0-32-21-61-62-61-55 0-82 45-82 77C475 320 498 343 538 343zM533 729c-8 0-11-10-3-40l43-166c16-61 11-100-22-100-39 0-131 40-211 108l16 27c25-17 68-35 78-35 8 0 7 10 0 36l-38 158c-23 89 1 110 34 110 33 0 118-30 196-110l-19-25C575 717 543 729 533 729z</StreamGeometry> <StreamGeometry x:Key="Icons.Info">M512 0C229 0 0 229 0 512s229 512 512 512 512-229 512-512S795 0 512 0zM512 928c-230 0-416-186-416-416S282 96 512 96s416 186 416 416S742 928 512 928zM538 343c47 0 83-38 83-78 0-32-21-61-62-61-55 0-82 45-82 77C475 320 498 343 538 343zM533 729c-8 0-11-10-3-40l43-166c16-61 11-100-22-100-39 0-131 40-211 108l16 27c25-17 68-35 78-35 8 0 7 10 0 36l-38 158c-23 89 1 110 34 110 33 0 118-30 196-110l-19-25C575 717 543 729 533 729z</StreamGeometry>
<StreamGeometry x:Key="Icons.Init">M412 66C326 132 271 233 271 347c0 17 1 34 4 50-41-48-98-79-162-83a444 444 0 00-46 196c0 207 142 382 337 439h2c19 0 34 15 34 33 0 11-6 21-14 26l1 14C183 973 0 763 0 511 0 272 166 70 393 7A35 35 0 01414 0c19 0 34 15 34 33a33 33 0 01-36 33zm200 893c86-66 141-168 141-282 0-17-1-34-4-50 41 48 98 79 162 83a444 444 0 0046-196c0-207-142-382-337-439h-2a33 33 0 01-34-33c0-11 6-21 14-26L596 0C841 51 1024 261 1024 513c0 239-166 441-393 504A35 35 0 01610 1024a33 33 0 01-34-33 33 33 0 0136-33zM512 704a192 192 0 110-384 192 192 0 010 384z</StreamGeometry> <StreamGeometry x:Key="Icons.Init">M412 66C326 132 271 233 271 347c0 17 1 34 4 50-41-48-98-79-162-83a444 444 0 00-46 196c0 207 142 382 337 439h2c19 0 34 15 34 33 0 11-6 21-14 26l1 14C183 973 0 763 0 511 0 272 166 70 393 7A35 35 0 01414 0c19 0 34 15 34 33a33 33 0 01-36 33zm200 893c86-66 141-168 141-282 0-17-1-34-4-50 41 48 98 79 162 83a444 444 0 0046-196c0-207-142-382-337-439h-2a33 33 0 01-34-33c0-11 6-21 14-26L596 0C841 51 1024 261 1024 513c0 239-166 441-393 504A35 35 0 01610 1024a33 33 0 01-34-33 33 33 0 0136-33zM512 704a192 192 0 110-384 192 192 0 010 384z</StreamGeometry>
<StreamGeometry x:Key="Icons.InteractiveRebase">M512 64A447 447 0 0064 512c0 248 200 448 448 448s448-200 448-448S760 64 512 64zM218 295h31c54 0 105 19 145 55 13 12 13 31 3 43a35 35 0 01-22 10 36 36 0 01-21-7 155 155 0 00-103-39h-31a32 32 0 01-31-31c0-18 13-31 30-31zm31 433h-31a32 32 0 01-31-31c0-16 13-31 31-31h31A154 154 0 00403 512 217 217 0 01620 295h75l-93-67a33 33 0 01-7-43 33 33 0 0143-7l205 148-205 148a29 29 0 01-18 6 32 32 0 01-31-31c0-10 4-19 13-25l93-67H620a154 154 0 00-154 154c0 122-97 220-217 220zm390 118a29 29 0 01-18 6 32 32 0 01-31-31c0-10 4-19 13-25l93-67h-75c-52 0-103-19-143-54-12-12-13-31-1-43a30 30 0 0142-3 151 151 0 00102 39h75L602 599a33 33 0 01-7-43 33 33 0 0143-7l205 148-203 151z</StreamGeometry> <StreamGeometry x:Key="Icons.InteractiveRebase">M512 64A447 447 0 0064 512c0 248 200 448 448 448s448-200 448-448S760 64 512 64zM218 295h31c54 0 105 19 145 55 13 12 13 31 3 43a35 35 0 01-22 10 36 36 0 01-21-7 155 155 0 00-103-39h-31a32 32 0 01-31-31c0-18 13-31 30-31zm31 433h-31a32 32 0 01-31-31c0-16 13-31 31-31h31A154 154 0 00403 512 217 217 0 01620 295h75l-93-67a33 33 0 01-7-43 33 33 0 0143-7l205 148-205 148a29 29 0 01-18 6 32 32 0 01-31-31c0-10 4-19 13-25l93-67H620a154 154 0 00-154 154c0 122-97 220-217 220zm390 118a29 29 0 01-18 6 32 32 0 01-31-31c0-10 4-19 13-25l93-67h-75c-52 0-103-19-143-54-12-12-13-31-1-43a30 30 0 0142-3 151 151 0 00102 39h75L602 599a33 33 0 01-7-43 33 33 0 0143-7l205 148-203 151z</StreamGeometry>
<StreamGeometry x:Key="Icons.Issue">M922 39H102A65 65 0 0039 106v609a65 65 0 0063 68h94v168a34 34 0 0019 31 30 30 0 0012 3 30 30 0 0022-10l182-192H922a65 65 0 0063-68V106A65 65 0 00922 39zM288 378h479a34 34 0 010 68H288a34 34 0 010-68zm0-135h479a34 34 0 010 68H288a34 34 0 010-68zm0 270h310a34 34 0 010 68H288a34 34 0 010-68z</StreamGeometry>
<StreamGeometry x:Key="Icons.Password">M640 96c-158 0-288 130-288 288 0 17 3 31 5 46L105 681 96 691V928h224v-96h96v-96h96v-95c38 18 82 31 128 31 158 0 288-130 288-288s-130-288-288-288zm0 64c123 0 224 101 224 224s-101 224-224 224a235 235 0 01-109-28l-8-4H448v96h-96v96H256v96H160v-146l253-254 12-11-3-17C419 417 416 400 416 384c0-123 101-224 224-224zm64 96a64 64 0 100 128 64 64 0 100-128z</StreamGeometry> <StreamGeometry x:Key="Icons.Password">M640 96c-158 0-288 130-288 288 0 17 3 31 5 46L105 681 96 691V928h224v-96h96v-96h96v-95c38 18 82 31 128 31 158 0 288-130 288-288s-130-288-288-288zm0 64c123 0 224 101 224 224s-101 224-224 224a235 235 0 01-109-28l-8-4H448v96h-96v96H256v96H160v-146l253-254 12-11-3-17C419 417 416 400 416 384c0-123 101-224 224-224zm64 96a64 64 0 100 128 64 64 0 100-128z</StreamGeometry>
<StreamGeometry x:Key="Icons.LayoutHorizontal">M875 117H149C109 117 75 151 75 192v640c0 41 34 75 75 75h725c41 0 75-34 75-75V192c0-41-34-75-75-75zM139 832V192c0-6 4-11 11-11h331v661H149c-6 0-11-4-11-11zm747 0c0 6-4 11-11 11H544v-661H875c6 0 11 4 11 11v640z</StreamGeometry> <StreamGeometry x:Key="Icons.LayoutHorizontal">M875 117H149C109 117 75 151 75 192v640c0 41 34 75 75 75h725c41 0 75-34 75-75V192c0-41-34-75-75-75zM139 832V192c0-6 4-11 11-11h331v661H149c-6 0-11-4-11-11zm747 0c0 6-4 11-11 11H544v-661H875c6 0 11 4 11 11v640z</StreamGeometry>
<StreamGeometry x:Key="Icons.LayoutVertical">M875 117H149C109 117 75 151 75 192v640c0 41 34 75 75 75h725c41 0 75-34 75-75V192c0-41-34-75-75-75zm-725 64h725c6 0 11 4 11 11v288h-747V192c0-6 4-11 11-11zm725 661H149c-6 0-11-4-11-11V544h747V832c0 6-4 11-11 11z</StreamGeometry> <StreamGeometry x:Key="Icons.LayoutVertical">M875 117H149C109 117 75 151 75 192v640c0 41 34 75 75 75h725c41 0 75-34 75-75V192c0-41-34-75-75-75zm-725 64h725c6 0 11 4 11 11v288h-747V192c0-6 4-11 11-11zm725 661H149c-6 0-11-4-11-11V544h747V832c0 6-4 11-11 11z</StreamGeometry>
@ -67,6 +68,8 @@
<StreamGeometry x:Key="Icons.MacOS.Maximize">M0 4 0 20 16 20 0 4M4 0 20 0 20 16 4 0z</StreamGeometry> <StreamGeometry x:Key="Icons.MacOS.Maximize">M0 4 0 20 16 20 0 4M4 0 20 0 20 16 4 0z</StreamGeometry>
<StreamGeometry x:Key="Icons.Menu">M192 192m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0ZM192 512m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0ZM192 832m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0ZM864 160H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32zM864 480H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32zM864 800H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32z</StreamGeometry> <StreamGeometry x:Key="Icons.Menu">M192 192m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0ZM192 512m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0ZM192 832m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0ZM864 160H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32zM864 480H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32zM864 800H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32z</StreamGeometry>
<StreamGeometry x:Key="Icons.Merge">M824 645V307c0-56-46-102-102-102h-102V102l-154 154 154 154V307h102v338c-46 20-82 67-82 123 0 72 61 133 133 133 72 0 133-61 133-133 0-56-36-102-82-123zm-51 195c-41 0-72-31-72-72s31-72 72-72c41 0 72 31 72 72s-31 72-72 72zM384 256c0-72-61-133-133-133-72 0-133 61-133 133 0 56 36 102 82 123v266C154 666 118 712 118 768c0 72 61 133 133 133 72 0 133-61 133-133 0-56-36-102-82-123V379C348 358 384 312 384 256zM323 768c0 41-31 72-72 72-41 0-72-31-72-72s31-72 72-72c41 0 72 31 72 72zM251 328c-41 0-72-31-72-72s31-72 72-72c41 0 72 31 72 72s-31 72-72 72z</StreamGeometry> <StreamGeometry x:Key="Icons.Merge">M824 645V307c0-56-46-102-102-102h-102V102l-154 154 154 154V307h102v338c-46 20-82 67-82 123 0 72 61 133 133 133 72 0 133-61 133-133 0-56-36-102-82-123zm-51 195c-41 0-72-31-72-72s31-72 72-72c41 0 72 31 72 72s-31 72-72 72zM384 256c0-72-61-133-133-133-72 0-133 61-133 133 0 56 36 102 82 123v266C154 666 118 712 118 768c0 72 61 133 133 133 72 0 133-61 133-133 0-56-36-102-82-123V379C348 358 384 312 384 256zM323 768c0 41-31 72-72 72-41 0-72-31-72-72s31-72 72-72c41 0 72 31 72 72zM251 328c-41 0-72-31-72-72s31-72 72-72c41 0 72 31 72 72s-31 72-72 72z</StreamGeometry>
<StreamGeometry x:Key="Icons.Modified">M896 64H128C96 64 64 96 64 128v768c0 32 32 64 64 64h768c32 0 64-32 64-64V128c0-32-32-64-64-64z m-64 736c0 16-17 32-32 32H224c-18 0-32-12-32-32V224c0-16 16-32 32-32h576c15 0 32 16 32 32v576zM512 384c-71 0-128 57-128 128s57 128 128 128 128-57 128-128-57-128-128-128z</StreamGeometry>
<StreamGeometry x:Key="Icons.Move">M299 811 299 725 384 725 384 811 299 811M469 811 469 725 555 725 555 811 469 811M640 811 640 725 725 725 725 811 640 811M299 640 299 555 384 555 384 640 299 640M469 640 469 555 555 555 555 640 469 640M640 640 640 555 725 555 725 640 640 640M299 469 299 384 384 384 384 469 299 469M469 469 469 384 555 384 555 469 469 469M640 469 640 384 725 384 725 469 640 469M299 299 299 213 384 213 384 299 299 299M469 299 469 213 555 213 555 299 469 299M640 299 640 213 725 213 725 299 640 299Z</StreamGeometry>
<StreamGeometry x:Key="Icons.OpenWith">M683 409v204L1024 308 683 0v191c-413 0-427 526-427 526c117-229 203-307 427-307zm85 492H102V327h153s38-63 114-122H51c-28 0-51 27-51 61v697c0 34 23 61 51 61h768c28 0 51-27 51-61V614l-102 100v187z</StreamGeometry> <StreamGeometry x:Key="Icons.OpenWith">M683 409v204L1024 308 683 0v191c-413 0-427 526-427 526c117-229 203-307 427-307zm85 492H102V327h153s38-63 114-122H51c-28 0-51 27-51 61v697c0 34 23 61 51 61h768c28 0 51-27 51-61V614l-102 100v187z</StreamGeometry>
<StreamGeometry x:Key="Icons.Paste">M544 85c49 0 90 37 95 85h75a96 96 0 0196 89L811 267a32 32 0 01-28 32L779 299a32 32 0 01-32-28L747 267a32 32 0 00-28-32L715 235h-91a96 96 0 01-80 42H395c-33 0-62-17-80-42L224 235a32 32 0 00-32 28L192 267v576c0 16 12 30 28 32l4 0h128a32 32 0 0132 28l0 4a32 32 0 01-32 32h-128a96 96 0 01-96-89L128 843V267a96 96 0 0189-96L224 171h75a96 96 0 0195-85h150zm256 256a96 96 0 0196 89l0 7v405a96 96 0 01-89 96L800 939h-277a96 96 0 01-96-89L427 843v-405a96 96 0 0189-96L523 341h277zm-256-192H395a32 32 0 000 64h150a32 32 0 100-64z</StreamGeometry> <StreamGeometry x:Key="Icons.Paste">M544 85c49 0 90 37 95 85h75a96 96 0 0196 89L811 267a32 32 0 01-28 32L779 299a32 32 0 01-32-28L747 267a32 32 0 00-28-32L715 235h-91a96 96 0 01-80 42H395c-33 0-62-17-80-42L224 235a32 32 0 00-32 28L192 267v576c0 16 12 30 28 32l4 0h128a32 32 0 0132 28l0 4a32 32 0 01-32 32h-128a96 96 0 01-96-89L128 843V267a96 96 0 0189-96L224 171h75a96 96 0 0195-85h150zm256 256a96 96 0 0196 89l0 7v405a96 96 0 01-89 96L800 939h-277a96 96 0 01-96-89L427 843v-405a96 96 0 0189-96L523 341h277zm-256-192H395a32 32 0 000 64h150a32 32 0 100-64z</StreamGeometry>
<StreamGeometry x:Key="Icons.Plus">m186 532 287 0 0 287c0 11 9 20 20 20s20-9 20-20l0-287 287 0c11 0 20-9 20-20s-9-20-20-20l-287 0 0-287c0-11-9-20-20-20s-20 9-20 20l0 287-287 0c-11 0-20 9-20 20s9 20 20 20z</StreamGeometry> <StreamGeometry x:Key="Icons.Plus">m186 532 287 0 0 287c0 11 9 20 20 20s20-9 20-20l0-287 287 0c11 0 20-9 20-20s-9-20-20-20l-287 0 0-287c0-11-9-20-20-20s-20 9-20 20l0 287-287 0c-11 0-20 9-20 20s9 20 20 20z</StreamGeometry>

View file

@ -4,12 +4,12 @@
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
<x:String x:Key="Text.About" xml:space="preserve">Info</x:String> <x:String x:Key="Text.About" xml:space="preserve">Info</x:String>
<x:String x:Key="Text.About.Menu" xml:space="preserve">Über SourceGit</x:String> <x:String x:Key="Text.About.Menu" xml:space="preserve">Über SourceGit</x:String>
<x:String x:Key="Text.About.BuildWith" xml:space="preserve">• Erstellen mit </x:String> <x:String x:Key="Text.About.BuildWith" xml:space="preserve">• Erstellt mit </x:String>
<x:String x:Key="Text.About.Copyright" xml:space="preserve">© 2024 sourcegit-scm</x:String> <x:String x:Key="Text.About.Copyright" xml:space="preserve">© 2024 sourcegit-scm</x:String>
<x:String x:Key="Text.About.Editor" xml:space="preserve">• Text Editor von </x:String> <x:String x:Key="Text.About.Editor" xml:space="preserve">• Text Editor von </x:String>
<x:String x:Key="Text.About.Fonts" xml:space="preserve">• Monospace Schriftarten von </x:String> <x:String x:Key="Text.About.Fonts" xml:space="preserve">• Monospace-Schriftarten von </x:String>
<x:String x:Key="Text.About.SourceCode" xml:space="preserve">• Quelltext findenst du unter </x:String> <x:String x:Key="Text.About.SourceCode" xml:space="preserve">• Quelltext findest du unter </x:String>
<x:String x:Key="Text.About.SubTitle" xml:space="preserve">Opensource &amp; freier Git GUI Client</x:String> <x:String x:Key="Text.About.SubTitle" xml:space="preserve">Open Source &amp; freier Git GUI Client</x:String>
<x:String x:Key="Text.AddWorktree" xml:space="preserve">Worktree hinzufügen</x:String> <x:String x:Key="Text.AddWorktree" xml:space="preserve">Worktree hinzufügen</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout" xml:space="preserve">Was auschecken:</x:String> <x:String x:Key="Text.AddWorktree.WhatToCheckout" xml:space="preserve">Was auschecken:</x:String>
<x:String x:Key="Text.AddWorktree.WhatToCheckout.Existing" xml:space="preserve">Existierender Branch</x:String> <x:String x:Key="Text.AddWorktree.WhatToCheckout.Existing" xml:space="preserve">Existierender Branch</x:String>
@ -19,17 +19,17 @@
<x:String x:Key="Text.AddWorktree.Name" xml:space="preserve">Branch Name:</x:String> <x:String x:Key="Text.AddWorktree.Name" xml:space="preserve">Branch Name:</x:String>
<x:String x:Key="Text.AddWorktree.Name.Placeholder" xml:space="preserve">Optional. Standard ist der Zielordnername.</x:String> <x:String x:Key="Text.AddWorktree.Name.Placeholder" xml:space="preserve">Optional. Standard ist der Zielordnername.</x:String>
<x:String x:Key="Text.AddWorktree.Tracking" xml:space="preserve">Branch verfolgen:</x:String> <x:String x:Key="Text.AddWorktree.Tracking" xml:space="preserve">Branch verfolgen:</x:String>
<x:String x:Key="Text.AddWorktree.Tracking.Toggle" xml:space="preserve">Remote Branch verfolgen</x:String> <x:String x:Key="Text.AddWorktree.Tracking.Toggle" xml:space="preserve">Remote-Branch verfolgen</x:String>
<x:String x:Key="Text.Apply" xml:space="preserve">Patch</x:String> <x:String x:Key="Text.Apply" xml:space="preserve">Patch</x:String>
<x:String x:Key="Text.Apply.Error" xml:space="preserve">Fehler</x:String> <x:String x:Key="Text.Apply.Error" xml:space="preserve">Fehler</x:String>
<x:String x:Key="Text.Apply.Error.Desc" xml:space="preserve">Fehler werfen und anwenden des Patches verweigern</x:String> <x:String x:Key="Text.Apply.Error.Desc" xml:space="preserve">Fehler werfen und anwenden des Patches verweigern</x:String>
<x:String x:Key="Text.Apply.ErrorAll" xml:space="preserve">Alle Fehler</x:String> <x:String x:Key="Text.Apply.ErrorAll" xml:space="preserve">Alle Fehler</x:String>
<x:String x:Key="Text.Apply.ErrorAll.Desc" xml:space="preserve">Ähnlich wie 'Fehler', zeigt aber mehr an</x:String> <x:String x:Key="Text.Apply.ErrorAll.Desc" xml:space="preserve">Ähnlich wie 'Fehler', zeigt aber mehr an</x:String>
<x:String x:Key="Text.Apply.File" xml:space="preserve">Patch Datei:</x:String> <x:String x:Key="Text.Apply.File" xml:space="preserve">Patch-Datei:</x:String>
<x:String x:Key="Text.Apply.File.Placeholder" xml:space="preserve">Wählen Sie anzuwendende .patch Datei</x:String> <x:String x:Key="Text.Apply.File.Placeholder" xml:space="preserve">Wähle die anzuwendende .patch-Datei</x:String>
<x:String x:Key="Text.Apply.IgnoreWS" xml:space="preserve">Ignoriere Leerzeichenänderungen</x:String> <x:String x:Key="Text.Apply.IgnoreWS" xml:space="preserve">Ignoriere Leerzeichenänderungen</x:String>
<x:String x:Key="Text.Apply.NoWarn" xml:space="preserve">Keine Warnungen</x:String> <x:String x:Key="Text.Apply.NoWarn" xml:space="preserve">Keine Warnungen</x:String>
<x:String x:Key="Text.Apply.NoWarn.Desc" xml:space="preserve">Schaltet die Warnung vor überschüssigen Leerzeichen aus</x:String> <x:String x:Key="Text.Apply.NoWarn.Desc" xml:space="preserve">Schaltet die Warnung vor nachgestellte Leerzeichen aus</x:String>
<x:String x:Key="Text.Apply.Title" xml:space="preserve">Patch anwenden</x:String> <x:String x:Key="Text.Apply.Title" xml:space="preserve">Patch anwenden</x:String>
<x:String x:Key="Text.Apply.Warn" xml:space="preserve">Warnen</x:String> <x:String x:Key="Text.Apply.Warn" xml:space="preserve">Warnen</x:String>
<x:String x:Key="Text.Apply.Warn.Desc" xml:space="preserve">Gibt eine Warnung für ein paar solcher Fehler aus, aber wendet es an</x:String> <x:String x:Key="Text.Apply.Warn.Desc" xml:space="preserve">Gibt eine Warnung für ein paar solcher Fehler aus, aber wendet es an</x:String>
@ -38,15 +38,15 @@
<x:String x:Key="Text.Archive.File" xml:space="preserve">Speichere Archiv in:</x:String> <x:String x:Key="Text.Archive.File" xml:space="preserve">Speichere Archiv in:</x:String>
<x:String x:Key="Text.Archive.File.Placeholder" xml:space="preserve">Wähle Archivpfad aus</x:String> <x:String x:Key="Text.Archive.File.Placeholder" xml:space="preserve">Wähle Archivpfad aus</x:String>
<x:String x:Key="Text.Archive.Revision" xml:space="preserve">Revision:</x:String> <x:String x:Key="Text.Archive.Revision" xml:space="preserve">Revision:</x:String>
<x:String x:Key="Text.Archive.Title" xml:space="preserve">Archiv</x:String> <x:String x:Key="Text.Archive.Title" xml:space="preserve">Archiv erstellen</x:String>
<x:String x:Key="Text.Askpass" xml:space="preserve">SourceGit Askpass</x:String> <x:String x:Key="Text.Askpass" xml:space="preserve">SourceGit Askpass</x:String>
<x:String x:Key="Text.AssumeUnchanged" xml:space="preserve">UNVERÄNDERTE DATEIEN</x:String> <x:String x:Key="Text.AssumeUnchanged" xml:space="preserve">ALS UNVERÄNDERT ANGENOMMENE DATEIEN</x:String>
<x:String x:Key="Text.AssumeUnchanged.Empty" xml:space="preserve">KEINE UNVERÄNDERTEN DATEIEN GEFUNDEN</x:String> <x:String x:Key="Text.AssumeUnchanged.Empty" xml:space="preserve">KEINE UNVERÄNDERT ANGENOMMENEN DATEIEN GEFUNDEN</x:String>
<x:String x:Key="Text.AssumeUnchanged.Remove" xml:space="preserve">ENTFERNEN</x:String> <x:String x:Key="Text.AssumeUnchanged.Remove" xml:space="preserve">ENTFERNEN</x:String>
<x:String x:Key="Text.BinaryNotSupported" xml:space="preserve">BINÄRE DATEI NICHT UNTERSTÜTZT!!!</x:String> <x:String x:Key="Text.BinaryNotSupported" xml:space="preserve">BINÄRE DATEI NICHT UNTERSTÜTZT!!!</x:String>
<x:String x:Key="Text.Blame" xml:space="preserve">Blame</x:String> <x:String x:Key="Text.Blame" xml:space="preserve">Blame</x:String>
<x:String x:Key="Text.BlameTypeNotSupported" xml:space="preserve">BLAME WIRD BEI DIESER DATEI NICHT UNTERSTÜTZT!!!</x:String> <x:String x:Key="Text.BlameTypeNotSupported" xml:space="preserve">BLAME WIRD BEI DIESER DATEI NICHT UNTERSTÜTZT!!!</x:String>
<x:String x:Key="Text.BranchCM.Checkout" xml:space="preserve">Checkout ${0}$...</x:String> <x:String x:Key="Text.BranchCM.Checkout" xml:space="preserve">${0}$ auschecken...</x:String>
<x:String x:Key="Text.BranchCM.CompareWithBranch" xml:space="preserve">Mit Branch vergleichen</x:String> <x:String x:Key="Text.BranchCM.CompareWithBranch" xml:space="preserve">Mit Branch vergleichen</x:String>
<x:String x:Key="Text.BranchCM.CompareWithHead" xml:space="preserve">Mit HEAD vergleichen</x:String> <x:String x:Key="Text.BranchCM.CompareWithHead" xml:space="preserve">Mit HEAD vergleichen</x:String>
<x:String x:Key="Text.BranchCM.CompareWithWorktree" xml:space="preserve">Mit Worktree vergleichen</x:String> <x:String x:Key="Text.BranchCM.CompareWithWorktree" xml:space="preserve">Mit Worktree vergleichen</x:String>
@ -58,12 +58,12 @@
<x:String x:Key="Text.BranchCM.Finish" xml:space="preserve">Git Flow - Abschließen ${0}$</x:String> <x:String x:Key="Text.BranchCM.Finish" xml:space="preserve">Git Flow - Abschließen ${0}$</x:String>
<x:String x:Key="Text.BranchCM.Merge" xml:space="preserve">Merge ${0}$ in ${1}$ hinein...</x:String> <x:String x:Key="Text.BranchCM.Merge" xml:space="preserve">Merge ${0}$ in ${1}$ hinein...</x:String>
<x:String x:Key="Text.BranchCM.Pull" xml:space="preserve">Pull ${0}$</x:String> <x:String x:Key="Text.BranchCM.Pull" xml:space="preserve">Pull ${0}$</x:String>
<x:String x:Key="Text.BranchCM.PullInto" xml:space="preserve">Pulle ${0}$ in ${1}$ hinein...</x:String> <x:String x:Key="Text.BranchCM.PullInto" xml:space="preserve">Pull ${0}$ in ${1}$ hinein...</x:String>
<x:String x:Key="Text.BranchCM.Push" xml:space="preserve">Push ${0}$</x:String> <x:String x:Key="Text.BranchCM.Push" xml:space="preserve">Push ${0}$</x:String>
<x:String x:Key="Text.BranchCM.Rebase" xml:space="preserve">Rebase ${0}$ auf ${1}$...</x:String> <x:String x:Key="Text.BranchCM.Rebase" xml:space="preserve">Rebase ${0}$ auf ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.Rename" xml:space="preserve">Benenne ${0}$ um...</x:String> <x:String x:Key="Text.BranchCM.Rename" xml:space="preserve">Benenne ${0}$ um...</x:String>
<x:String x:Key="Text.BranchCM.Tracking" xml:space="preserve">Setze verfolgten Branch</x:String> <x:String x:Key="Text.BranchCM.Tracking" xml:space="preserve">Setze verfolgten Branch</x:String>
<x:String x:Key="Text.BranchCM.UnsetUpstream" xml:space="preserve">Upstream Verbindung löschen</x:String> <x:String x:Key="Text.BranchCM.UnsetUpstream" xml:space="preserve">Upstream Verfolgung aufheben</x:String>
<x:String x:Key="Text.BranchCompare" xml:space="preserve">Branch Vergleich</x:String> <x:String x:Key="Text.BranchCompare" xml:space="preserve">Branch Vergleich</x:String>
<x:String x:Key="Text.Bytes" xml:space="preserve">Bytes</x:String> <x:String x:Key="Text.Bytes" xml:space="preserve">Bytes</x:String>
<x:String x:Key="Text.Cancel" xml:space="preserve">ABBRECHEN</x:String> <x:String x:Key="Text.Cancel" xml:space="preserve">ABBRECHEN</x:String>
@ -71,15 +71,15 @@
<x:String x:Key="Text.ChangeDisplayMode.Grid" xml:space="preserve">Zeige als Datei- und Ordnerliste</x:String> <x:String x:Key="Text.ChangeDisplayMode.Grid" xml:space="preserve">Zeige als Datei- und Ordnerliste</x:String>
<x:String x:Key="Text.ChangeDisplayMode.List" xml:space="preserve">Zeige als Pfadliste</x:String> <x:String x:Key="Text.ChangeDisplayMode.List" xml:space="preserve">Zeige als Pfadliste</x:String>
<x:String x:Key="Text.ChangeDisplayMode.Tree" xml:space="preserve">Zeige als Dateisystembaum</x:String> <x:String x:Key="Text.ChangeDisplayMode.Tree" xml:space="preserve">Zeige als Dateisystembaum</x:String>
<x:String x:Key="Text.Checkout" xml:space="preserve">Checkout Branch</x:String> <x:String x:Key="Text.Checkout" xml:space="preserve">Branch auschecken</x:String>
<x:String x:Key="Text.Checkout.Commit" xml:space="preserve">Checkout Commit</x:String> <x:String x:Key="Text.Checkout.Commit" xml:space="preserve">Commit auschecken</x:String>
<x:String x:Key="Text.Checkout.Commit.Warning" xml:space="preserve">Warnung: Beim auschecken eines Commits wird dein HEAD detached sein</x:String> <x:String x:Key="Text.Checkout.Commit.Warning" xml:space="preserve">Warnung: Beim Auschecken eines Commits wird dein HEAD losgelöst (detached) sein!</x:String>
<x:String x:Key="Text.Checkout.Commit.Target" xml:space="preserve">Commit:</x:String> <x:String x:Key="Text.Checkout.Commit.Target" xml:space="preserve">Commit:</x:String>
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">Branch:</x:String> <x:String x:Key="Text.Checkout.Target" xml:space="preserve">Branch:</x:String>
<x:String x:Key="Text.Checkout.LocalChanges" xml:space="preserve">Lokale Änderungen:</x:String> <x:String x:Key="Text.Checkout.LocalChanges" xml:space="preserve">Lokale Änderungen:</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.Discard" xml:space="preserve">Verwerfen</x:String> <x:String x:Key="Text.Checkout.LocalChanges.Discard" xml:space="preserve">Verwerfen</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.DoNothing" xml:space="preserve">Nichts tun</x:String> <x:String x:Key="Text.Checkout.LocalChanges.DoNothing" xml:space="preserve">Nichts tun</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Stash &amp; wieder anwenden</x:String> <x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Stashen &amp; wieder anwenden</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">Diesen Commit cherry-picken</x:String> <x:String x:Key="Text.CherryPick" xml:space="preserve">Diesen Commit cherry-picken</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit:</x:String> <x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit:</x:String>
<x:String x:Key="Text.CherryPick.CommitChanges" xml:space="preserve">Alle Änderungen committen</x:String> <x:String x:Key="Text.CherryPick.CommitChanges" xml:space="preserve">Alle Änderungen committen</x:String>
@ -96,18 +96,18 @@
<x:String x:Key="Text.Close" xml:space="preserve">SCHLIESSEN</x:String> <x:String x:Key="Text.Close" xml:space="preserve">SCHLIESSEN</x:String>
<x:String x:Key="Text.CodeEditor" xml:space="preserve">Editor</x:String> <x:String x:Key="Text.CodeEditor" xml:space="preserve">Editor</x:String>
<x:String x:Key="Text.CommitCM.CherryPick" xml:space="preserve">Diesen Commit cherry-picken</x:String> <x:String x:Key="Text.CommitCM.CherryPick" xml:space="preserve">Diesen Commit cherry-picken</x:String>
<x:String x:Key="Text.CommitCM.Checkout" xml:space="preserve">Checkout Commit</x:String> <x:String x:Key="Text.CommitCM.Checkout" xml:space="preserve">Commit auschecken</x:String>
<x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">Mit HEAD vergleichen</x:String> <x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">Mit HEAD vergleichen</x:String>
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">Mit Worktree vergleichen</x:String> <x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">Mit Worktree vergleichen</x:String>
<x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Info kopieren</x:String> <x:String x:Key="Text.CommitCM.CopyInfo" xml:space="preserve">Info kopieren</x:String>
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">SHA kopieren</x:String> <x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">SHA kopieren</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">Interactives Rebase ${0}$ bis hier</x:String> <x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">Interactives Rebase von ${0}$ auf diesen Commit</x:String>
<x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">Rebase ${0}$ bis hier</x:String> <x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">Rebase von ${0}$ auf diesen Commit</x:String>
<x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">Reset ${0}$ bis hier</x:String> <x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">Reset ${0}$ auf diesen Commit</x:String>
<x:String x:Key="Text.CommitCM.Revert" xml:space="preserve">Commit rückgängig machen</x:String> <x:String x:Key="Text.CommitCM.Revert" xml:space="preserve">Commit rückgängig machen</x:String>
<x:String x:Key="Text.CommitCM.Reword" xml:space="preserve">Umformulieren</x:String> <x:String x:Key="Text.CommitCM.Reword" xml:space="preserve">Umformulieren</x:String>
<x:String x:Key="Text.CommitCM.SaveAsPatch" xml:space="preserve">Als Patch speichern...</x:String> <x:String x:Key="Text.CommitCM.SaveAsPatch" xml:space="preserve">Als Patch speichern...</x:String>
<x:String x:Key="Text.CommitCM.Squash" xml:space="preserve">Squash in den Parent</x:String> <x:String x:Key="Text.CommitCM.Squash" xml:space="preserve">Squash in den Vorgänger</x:String>
<x:String x:Key="Text.CommitDetail.Changes" xml:space="preserve">ÄNDERUNGEN</x:String> <x:String x:Key="Text.CommitDetail.Changes" xml:space="preserve">ÄNDERUNGEN</x:String>
<x:String x:Key="Text.CommitDetail.Changes.Search" xml:space="preserve">Änderungen durchsuchen...</x:String> <x:String x:Key="Text.CommitDetail.Changes.Search" xml:space="preserve">Änderungen durchsuchen...</x:String>
<x:String x:Key="Text.CommitDetail.Files" xml:space="preserve">DATEIEN</x:String> <x:String x:Key="Text.CommitDetail.Files" xml:space="preserve">DATEIEN</x:String>
@ -118,30 +118,39 @@
<x:String x:Key="Text.CommitDetail.Info.Changed" xml:space="preserve">GEÄNDERT</x:String> <x:String x:Key="Text.CommitDetail.Info.Changed" xml:space="preserve">GEÄNDERT</x:String>
<x:String x:Key="Text.CommitDetail.Info.Committer" xml:space="preserve">COMMITTER</x:String> <x:String x:Key="Text.CommitDetail.Info.Committer" xml:space="preserve">COMMITTER</x:String>
<x:String x:Key="Text.CommitDetail.Info.GotoChangesPage" xml:space="preserve">Zeigt nur die ersten 100 Änderungen. Alle Änderungen im ÄNDERUNGEN Tab.</x:String> <x:String x:Key="Text.CommitDetail.Info.GotoChangesPage" xml:space="preserve">Zeigt nur die ersten 100 Änderungen. Alle Änderungen im ÄNDERUNGEN Tab.</x:String>
<x:String x:Key="Text.CommitDetail.Info.Message" xml:space="preserve">NACHRICHT</x:String> <x:String x:Key="Text.CommitDetail.Info.Message" xml:space="preserve">COMMIT-NACHRICHT</x:String>
<x:String x:Key="Text.CommitDetail.Info.Parents" xml:space="preserve">PARENTS</x:String> <x:String x:Key="Text.CommitDetail.Info.Parents" xml:space="preserve">VORGÄNGER</x:String>
<x:String x:Key="Text.CommitDetail.Info.Refs" xml:space="preserve">REFS</x:String> <x:String x:Key="Text.CommitDetail.Info.Refs" xml:space="preserve">REFS</x:String>
<x:String x:Key="Text.CommitDetail.Info.SHA" xml:space="preserve">SHA</x:String> <x:String x:Key="Text.CommitDetail.Info.SHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.CommitMessageTextBox.SubjectPlaceholder" xml:space="preserve">Commit Nachricht</x:String> <x:String x:Key="Text.CommitMessageTextBox.SubjectPlaceholder" xml:space="preserve">Commit-Nachricht</x:String>
<x:String x:Key="Text.CommitMessageTextBox.MessagePlaceholder" xml:space="preserve">Beschreibung</x:String> <x:String x:Key="Text.CommitMessageTextBox.MessagePlaceholder" xml:space="preserve">Details</x:String>
<x:String x:Key="Text.Configure" xml:space="preserve">Repository konfigurieren</x:String> <x:String x:Key="Text.Configure" xml:space="preserve">Repository Einstellungen</x:String>
<x:String x:Key="Text.Configure.Email" xml:space="preserve">Email Adresse</x:String> <x:String x:Key="Text.Configure.Email" xml:space="preserve">Email Adresse</x:String>
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Email Adresse</x:String> <x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Email Adresse</x:String>
<x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">TICKETSYSTEM</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Beispiel für Github-Regel hinzufügen</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Beispiel für Jira-Regel hinzufügen</x:String>
<x:String x:Key="Text.Configure.IssueTracker.NewRule" xml:space="preserve">Neue Regel</x:String>
<x:String x:Key="Text.Configure.IssueTracker.Regex" xml:space="preserve">Ticketnummer Regex-Ausdruck:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">Name:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">Ergebnis-URL:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">Verwende bitte $1, $2 um auf Regex-Gruppenwerte zuzugreifen.</x:String>
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP Proxy</x:String> <x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP Proxy</x:String>
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP proxy für dieses Repository</x:String> <x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP Proxy für dieses Repository</x:String>
<x:String x:Key="Text.Configure.User" xml:space="preserve">Benutzername</x:String> <x:String x:Key="Text.Configure.User" xml:space="preserve">Benutzername</x:String>
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">Benutzername für dieses Repository</x:String> <x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">Benutzername für dieses Repository</x:String>
<x:String x:Key="Text.Copy" xml:space="preserve">Kopieren</x:String> <x:String x:Key="Text.Copy" xml:space="preserve">Kopieren</x:String>
<x:String x:Key="Text.CopyMessage" xml:space="preserve">NACHRICHT KOPIEREN</x:String> <x:String x:Key="Text.CopyMessage" xml:space="preserve">COMMIT-NACHRICHT KOPIEREN</x:String>
<x:String x:Key="Text.CopyPath" xml:space="preserve">Pfad kopieren</x:String> <x:String x:Key="Text.CopyPath" xml:space="preserve">Pfad kopieren</x:String>
<x:String x:Key="Text.CopyFileName" xml:space="preserve">Dateiename kopieren</x:String> <x:String x:Key="Text.CopyFileName" xml:space="preserve">Dateinamen kopieren</x:String>
<x:String x:Key="Text.CreateBranch" xml:space="preserve">Branch erstellen...</x:String> <x:String x:Key="Text.CreateBranch" xml:space="preserve">Branch erstellen...</x:String>
<x:String x:Key="Text.CreateBranch.BasedOn" xml:space="preserve">Basiert auf:</x:String> <x:String x:Key="Text.CreateBranch.BasedOn" xml:space="preserve">Basierend auf:</x:String>
<x:String x:Key="Text.CreateBranch.Checkout" xml:space="preserve">Erstellten Branch auschecken</x:String> <x:String x:Key="Text.CreateBranch.Checkout" xml:space="preserve">Erstellten Branch auschecken</x:String>
<x:String x:Key="Text.CreateBranch.LocalChanges" xml:space="preserve">Lokale Änderungen:</x:String> <x:String x:Key="Text.CreateBranch.LocalChanges" xml:space="preserve">Lokale Änderungen:</x:String>
<x:String x:Key="Text.CreateBranch.LocalChanges.Discard" xml:space="preserve">Verwerfen</x:String> <x:String x:Key="Text.CreateBranch.LocalChanges.Discard" xml:space="preserve">Verwerfen</x:String>
<x:String x:Key="Text.CreateBranch.LocalChanges.DoNothing" xml:space="preserve">Nichts tun</x:String> <x:String x:Key="Text.CreateBranch.LocalChanges.DoNothing" xml:space="preserve">Nichts tun</x:String>
<x:String x:Key="Text.CreateBranch.LocalChanges.StashAndReply" xml:space="preserve">Stash &amp; wieder anwenden</x:String> <x:String x:Key="Text.CreateBranch.LocalChanges.StashAndReply" xml:space="preserve">Stashen &amp; wieder anwenden</x:String>
<x:String x:Key="Text.CreateBranch.Name" xml:space="preserve">Neuer Branch-Name:</x:String> <x:String x:Key="Text.CreateBranch.Name" xml:space="preserve">Neuer Branch-Name:</x:String>
<x:String x:Key="Text.CreateBranch.Name.Placeholder" xml:space="preserve">Branch-Namen eingeben.</x:String> <x:String x:Key="Text.CreateBranch.Name.Placeholder" xml:space="preserve">Branch-Namen eingeben.</x:String>
<x:String x:Key="Text.CreateBranch.Title" xml:space="preserve">Lokalen Branch erstellen</x:String> <x:String x:Key="Text.CreateBranch.Title" xml:space="preserve">Lokalen Branch erstellen</x:String>
@ -181,7 +190,7 @@
<x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">Dateimodus geändert</x:String> <x:String x:Key="Text.Diff.FileModeChanged" xml:space="preserve">Dateimodus geändert</x:String>
<x:String x:Key="Text.Diff.LFS" xml:space="preserve">LFS OBJEKT ÄNDERUNG</x:String> <x:String x:Key="Text.Diff.LFS" xml:space="preserve">LFS OBJEKT ÄNDERUNG</x:String>
<x:String x:Key="Text.Diff.Next" xml:space="preserve">Nächste Änderung</x:String> <x:String x:Key="Text.Diff.Next" xml:space="preserve">Nächste Änderung</x:String>
<x:String x:Key="Text.Diff.NoChange" xml:space="preserve">KEINE ÄNDERUNG ODER NUR DATEI-ENDE ÄNDERUNGEN</x:String> <x:String x:Key="Text.Diff.NoChange" xml:space="preserve">KEINE ÄNDERUNG ODER NUR ZEILEN-ENDE ÄNDERUNGEN</x:String>
<x:String x:Key="Text.Diff.Prev" xml:space="preserve">Vorherige Änderung</x:String> <x:String x:Key="Text.Diff.Prev" xml:space="preserve">Vorherige Änderung</x:String>
<x:String x:Key="Text.Diff.SideBySide" xml:space="preserve">Nebeneinander</x:String> <x:String x:Key="Text.Diff.SideBySide" xml:space="preserve">Nebeneinander</x:String>
<x:String x:Key="Text.Diff.Submodule" xml:space="preserve">SUBMODUL</x:String> <x:String x:Key="Text.Diff.Submodule" xml:space="preserve">SUBMODUL</x:String>
@ -196,7 +205,7 @@
<x:String x:Key="Text.Diff.SwapCommits" xml:space="preserve">Seiten wechseln</x:String> <x:String x:Key="Text.Diff.SwapCommits" xml:space="preserve">Seiten wechseln</x:String>
<x:String x:Key="Text.DiffWithMerger" xml:space="preserve">Öffne in Merge Tool</x:String> <x:String x:Key="Text.DiffWithMerger" xml:space="preserve">Öffne in Merge Tool</x:String>
<x:String x:Key="Text.Discard" xml:space="preserve">Änderungen verwerfen</x:String> <x:String x:Key="Text.Discard" xml:space="preserve">Änderungen verwerfen</x:String>
<x:String x:Key="Text.Discard.All" xml:space="preserve">Alle Änderungen in der Working Copy.</x:String> <x:String x:Key="Text.Discard.All" xml:space="preserve">Alle Änderungen in der Arbeitskopie.</x:String>
<x:String x:Key="Text.Discard.Changes" xml:space="preserve">Änderungen:</x:String> <x:String x:Key="Text.Discard.Changes" xml:space="preserve">Änderungen:</x:String>
<x:String x:Key="Text.Discard.Total" xml:space="preserve">Insgesamt {0} Änderungen werden verworfen</x:String> <x:String x:Key="Text.Discard.Total" xml:space="preserve">Insgesamt {0} Änderungen werden verworfen</x:String>
<x:String x:Key="Text.Discard.Warning" xml:space="preserve">Du kannst das nicht rückgängig machen!!!</x:String> <x:String x:Key="Text.Discard.Warning" xml:space="preserve">Du kannst das nicht rückgängig machen!!!</x:String>
@ -205,13 +214,13 @@
<x:String x:Key="Text.EditRepositoryNode.Target" xml:space="preserve">Ziel:</x:String> <x:String x:Key="Text.EditRepositoryNode.Target" xml:space="preserve">Ziel:</x:String>
<x:String x:Key="Text.EditRepositoryNode.TitleForGroup" xml:space="preserve">Ausgewählte Gruppe bearbeiten</x:String> <x:String x:Key="Text.EditRepositoryNode.TitleForGroup" xml:space="preserve">Ausgewählte Gruppe bearbeiten</x:String>
<x:String x:Key="Text.EditRepositoryNode.TitleForRepository" xml:space="preserve">Ausgewähltes Repository bearbeiten</x:String> <x:String x:Key="Text.EditRepositoryNode.TitleForRepository" xml:space="preserve">Ausgewähltes Repository bearbeiten</x:String>
<x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">Fast-Forward (ohne Checkout)</x:String> <x:String x:Key="Text.FastForwardWithoutCheck" xml:space="preserve">Fast-Forward (ohne Auschecken)</x:String>
<x:String x:Key="Text.Fetch" xml:space="preserve">Fetch</x:String> <x:String x:Key="Text.Fetch" xml:space="preserve">Fetch</x:String>
<x:String x:Key="Text.Fetch.AllRemotes" xml:space="preserve">Alle Remotes fetchen</x:String> <x:String x:Key="Text.Fetch.AllRemotes" xml:space="preserve">Alle Remotes fetchen</x:String>
<x:String x:Key="Text.Fetch.NoTags" xml:space="preserve">Ohne Tags fetchen</x:String> <x:String x:Key="Text.Fetch.NoTags" xml:space="preserve">Ohne Tags fetchen</x:String>
<x:String x:Key="Text.Fetch.Prune" xml:space="preserve">Alle toten Branches entfernen</x:String> <x:String x:Key="Text.Fetch.Prune" xml:space="preserve">Alle toten remote Branches entfernen</x:String>
<x:String x:Key="Text.Fetch.Remote" xml:space="preserve">Remote:</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">Remote Änderungen fetchen</x:String> <x:String x:Key="Text.Fetch.Title" xml:space="preserve">Remote-Änderungen fetchen</x:String>
<x:String x:Key="Text.FileCM.AssumeUnchanged" xml:space="preserve">Als unverändert annehmen</x:String> <x:String x:Key="Text.FileCM.AssumeUnchanged" xml:space="preserve">Als unverändert annehmen</x:String>
<x:String x:Key="Text.FileCM.Discard" xml:space="preserve">Verwerfen...</x:String> <x:String x:Key="Text.FileCM.Discard" xml:space="preserve">Verwerfen...</x:String>
<x:String x:Key="Text.FileCM.DiscardMulti" xml:space="preserve">Verwerfe {0} Dateien...</x:String> <x:String x:Key="Text.FileCM.DiscardMulti" xml:space="preserve">Verwerfe {0} Dateien...</x:String>
@ -224,27 +233,27 @@
<x:String x:Key="Text.FileCM.Stash" xml:space="preserve">Stash...</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">{0} Dateien stashen...</x:String> <x:String x:Key="Text.FileCM.StashMulti" xml:space="preserve">{0} Dateien stashen...</x:String>
<x:String x:Key="Text.FileCM.Unstage" xml:space="preserve">Unstage</x:String> <x:String x:Key="Text.FileCM.Unstage" xml:space="preserve">Unstage</x:String>
<x:String x:Key="Text.FileCM.UnstageMulti" xml:space="preserve">{0} Dateien nicht mehr stashen</x:String> <x:String x:Key="Text.FileCM.UnstageMulti" xml:space="preserve">{0} Dateien unstagen</x:String>
<x:String x:Key="Text.FileCM.UnstageSelectedLines" xml:space="preserve">Änderungen in ausgewählten Zeilen stashen</x:String> <x:String x:Key="Text.FileCM.UnstageSelectedLines" xml:space="preserve">Änderungen in ausgewählten Zeilen unstagen</x:String>
<x:String x:Key="Text.FileCM.UseTheirs" xml:space="preserve">"Ihre" verwenden (checkout --theirs)</x:String> <x:String x:Key="Text.FileCM.UseTheirs" xml:space="preserve">"Ihre" verwenden (checkout --theirs)</x:String>
<x:String x:Key="Text.FileCM.UseMine" xml:space="preserve">"Meine" verwenden (checkout --ours)</x:String> <x:String x:Key="Text.FileCM.UseMine" xml:space="preserve">"Meine" verwenden (checkout --ours)</x:String>
<x:String x:Key="Text.FileHistory" xml:space="preserve">Datei Historie</x:String> <x:String x:Key="Text.FileHistory" xml:space="preserve">Datei Historie</x:String>
<x:String x:Key="Text.Filter" xml:space="preserve">FILTER</x:String> <x:String x:Key="Text.Filter" xml:space="preserve">FILTER</x:String>
<x:String x:Key="Text.GitFlow" xml:space="preserve">Git-Flow</x:String> <x:String x:Key="Text.GitFlow" xml:space="preserve">Git-Flow</x:String>
<x:String x:Key="Text.GitFlow.DevelopBranch" xml:space="preserve">Development Branch:</x:String> <x:String x:Key="Text.GitFlow.DevelopBranch" xml:space="preserve">Entwicklungs-Branch:</x:String>
<x:String x:Key="Text.GitFlow.Feature" xml:space="preserve">Feature:</x:String> <x:String x:Key="Text.GitFlow.Feature" xml:space="preserve">Feature:</x:String>
<x:String x:Key="Text.GitFlow.FeaturePrefix" xml:space="preserve">Feature Prefix:</x:String> <x:String x:Key="Text.GitFlow.FeaturePrefix" xml:space="preserve">Feature-Prefix:</x:String>
<x:String x:Key="Text.GitFlow.FinishFeature" xml:space="preserve">FLOW - Finish Feature</x:String> <x:String x:Key="Text.GitFlow.FinishFeature" xml:space="preserve">FLOW - Finish Feature</x:String>
<x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">FLOW - Finish Hotfix</x:String> <x:String x:Key="Text.GitFlow.FinishHotfix" xml:space="preserve">FLOW - Finish Hotfix</x:String>
<x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">FLOW - Finish Release</x:String> <x:String x:Key="Text.GitFlow.FinishRelease" xml:space="preserve">FLOW - Finish Release</x:String>
<x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">Ziel:</x:String> <x:String x:Key="Text.GitFlow.FinishTarget" xml:space="preserve">Ziel:</x:String>
<x:String x:Key="Text.GitFlow.Hotfix" xml:space="preserve">Hotfix:</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">Hotfix Prefix:</x:String> <x:String x:Key="Text.GitFlow.HotfixPrefix" xml:space="preserve">Hotfix-Prefix:</x:String>
<x:String x:Key="Text.GitFlow.Init" xml:space="preserve">Git-Flow initialisieren</x:String> <x:String x:Key="Text.GitFlow.Init" xml:space="preserve">Git-Flow initialisieren</x:String>
<x:String x:Key="Text.GitFlow.KeepBranchAfterFinish" xml:space="preserve">Branch behalten</x:String> <x:String x:Key="Text.GitFlow.KeepBranchAfterFinish" xml:space="preserve">Branch behalten</x:String>
<x:String x:Key="Text.GitFlow.ProductionBranch" xml:space="preserve">Production Branch:</x:String> <x:String x:Key="Text.GitFlow.ProductionBranch" xml:space="preserve">Produktions-Branch:</x:String>
<x:String x:Key="Text.GitFlow.Release" xml:space="preserve">Release:</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">Release Prefix:</x:String> <x:String x:Key="Text.GitFlow.ReleasePrefix" xml:space="preserve">Release-Prefix:</x:String>
<x:String x:Key="Text.GitFlow.StartFeature" xml:space="preserve">Feature starten...</x:String> <x:String x:Key="Text.GitFlow.StartFeature" xml:space="preserve">Feature starten...</x:String>
<x:String x:Key="Text.GitFlow.StartFeatureTitle" xml:space="preserve">FLOW - Feature starten</x:String> <x:String x:Key="Text.GitFlow.StartFeatureTitle" xml:space="preserve">FLOW - Feature starten</x:String>
<x:String x:Key="Text.GitFlow.StartHotfix" xml:space="preserve">Hotfix starten...</x:String> <x:String x:Key="Text.GitFlow.StartHotfix" xml:space="preserve">Hotfix starten...</x:String>
@ -252,17 +261,17 @@
<x:String x:Key="Text.GitFlow.StartPlaceholder" xml:space="preserve">Name eingeben</x:String> <x:String x:Key="Text.GitFlow.StartPlaceholder" xml:space="preserve">Name eingeben</x:String>
<x:String x:Key="Text.GitFlow.StartRelease" xml:space="preserve">Release starten...</x:String> <x:String x:Key="Text.GitFlow.StartRelease" xml:space="preserve">Release starten...</x:String>
<x:String x:Key="Text.GitFlow.StartReleaseTitle" xml:space="preserve">FLOW - Release starten</x:String> <x:String x:Key="Text.GitFlow.StartReleaseTitle" xml:space="preserve">FLOW - Release starten</x:String>
<x:String x:Key="Text.GitFlow.TagPrefix" xml:space="preserve">Versions-Tag Prefix:</x:String> <x:String x:Key="Text.GitFlow.TagPrefix" xml:space="preserve">Versions-Tag-Prefix:</x:String>
<x:String x:Key="Text.GitLFS" xml:space="preserve">Git LFS</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">Verfolgungsmuster hinzufügen...</x:String> <x:String x:Key="Text.GitLFS.AddTrackPattern" xml:space="preserve">Verfolgungsmuster hinzufügen...</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern.IsFilename" xml:space="preserve">Muster ist Dateiname</x:String> <x:String x:Key="Text.GitLFS.AddTrackPattern.IsFilename" xml:space="preserve">Muster ist ein Dateiname</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern.Pattern" xml:space="preserve">Eigenes Muster:</x:String> <x:String x:Key="Text.GitLFS.AddTrackPattern.Pattern" xml:space="preserve">Eigenes Muster:</x:String>
<x:String x:Key="Text.GitLFS.AddTrackPattern.Title" xml:space="preserve">Verfolgungsmuster zu Git LFS hinzufügen</x:String> <x:String x:Key="Text.GitLFS.AddTrackPattern.Title" xml:space="preserve">Verfolgungsmuster zu Git LFS hinzufügen</x:String>
<x:String x:Key="Text.GitLFS.Fetch" xml:space="preserve">Fetch</x:String> <x:String x:Key="Text.GitLFS.Fetch" xml:space="preserve">Fetch</x:String>
<x:String x:Key="Text.GitLFS.Fetch.Title" xml:space="preserve">LFS Objecte fetchen</x:String> <x:String x:Key="Text.GitLFS.Fetch.Title" xml:space="preserve">LFS Objekte fetchen</x:String>
<x:String x:Key="Text.GitLFS.Fetch.Tips" xml:space="preserve">Führt `git lfs fetch` aus um Git LFS Objekte herunterzuladen. Das aktualisiert nicht die Working Copy.</x:String> <x:String x:Key="Text.GitLFS.Fetch.Tips" xml:space="preserve">Führt `git lfs fetch` aus um Git LFS Objekte herunterzuladen. Das aktualisiert nicht die Arbeitskopie.</x:String>
<x:String x:Key="Text.GitLFS.Install" xml:space="preserve">Installiere Git LFS Hooks</x:String> <x:String x:Key="Text.GitLFS.Install" xml:space="preserve">Installiere Git LFS Hooks</x:String>
<x:String x:Key="Text.GitLFS.Locks" xml:space="preserve">Sperren zeigen</x:String> <x:String x:Key="Text.GitLFS.Locks" xml:space="preserve">Sperren anzeigen</x:String>
<x:String x:Key="Text.GitLFS.Locks.Empty" xml:space="preserve">Keine gesperrten Dateien</x:String> <x:String x:Key="Text.GitLFS.Locks.Empty" xml:space="preserve">Keine gesperrten Dateien</x:String>
<x:String x:Key="Text.GitLFS.Locks.Lock" xml:space="preserve">Sperre</x:String> <x:String x:Key="Text.GitLFS.Locks.Lock" xml:space="preserve">Sperre</x:String>
<x:String x:Key="Text.GitLFS.Locks.Title" xml:space="preserve">LFS Sperren</x:String> <x:String x:Key="Text.GitLFS.Locks.Title" xml:space="preserve">LFS Sperren</x:String>
@ -277,35 +286,35 @@
<x:String x:Key="Text.GitLFS.Push.Title" xml:space="preserve">LFS Objekte pushen</x:String> <x:String x:Key="Text.GitLFS.Push.Title" xml:space="preserve">LFS Objekte pushen</x:String>
<x:String x:Key="Text.GitLFS.Push.Tips" xml:space="preserve">Pushe große Dateien in der Warteschlange zum Git LFS Endpunkt</x:String> <x:String x:Key="Text.GitLFS.Push.Tips" xml:space="preserve">Pushe große Dateien in der Warteschlange zum Git LFS Endpunkt</x:String>
<x:String x:Key="Text.GitLFS.Remote" xml:space="preserve">Remote:</x:String> <x:String x:Key="Text.GitLFS.Remote" xml:space="preserve">Remote:</x:String>
<x:String x:Key="Text.GitLFS.Track" xml:space="preserve">Verfolge Dateien names '{0}'</x:String> <x:String x:Key="Text.GitLFS.Track" xml:space="preserve">Verfolge '{0}' benannte Dateien</x:String>
<x:String x:Key="Text.GitLFS.TrackByExtension" xml:space="preserve">Verfolge alle *{0} Dateien</x:String> <x:String x:Key="Text.GitLFS.TrackByExtension" xml:space="preserve">Verfolge alle *{0} Dateien</x:String>
<x:String x:Key="Text.Histories" xml:space="preserve">Historie</x:String> <x:String x:Key="Text.Histories" xml:space="preserve">Historien</x:String>
<x:String x:Key="Text.Histories.DisplayMode" xml:space="preserve">Wechsle zwischen horizontalem und vertikalem Layout</x:String> <x:String x:Key="Text.Histories.DisplayMode" xml:space="preserve">Wechsle zwischen horizontalem und vertikalem Layout</x:String>
<x:String x:Key="Text.Histories.GraphMode" xml:space="preserve">Wechsle zwischen Kurven- und Konturgraphenmodus</x:String> <x:String x:Key="Text.Histories.GraphMode" xml:space="preserve">Wechsle zwischen Kurven- und Konturgraphenmodus</x:String>
<x:String x:Key="Text.Histories.Header.Author" xml:space="preserve">AUTOR</x:String> <x:String x:Key="Text.Histories.Header.Author" xml:space="preserve">AUTOR</x:String>
<x:String x:Key="Text.Histories.Header.GraphAndSubject" xml:space="preserve">GRAPH &amp; SUBJEKT</x:String> <x:String x:Key="Text.Histories.Header.GraphAndSubject" xml:space="preserve">GRAPH &amp; COMMIT-NACHRICHT</x:String>
<x:String x:Key="Text.Histories.Header.SHA" xml:space="preserve">SHA</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">COMMIT ZEIT</x:String> <x:String x:Key="Text.Histories.Header.Time" xml:space="preserve">COMMIT ZEITPUNKT</x:String>
<x:String x:Key="Text.Histories.Search" xml:space="preserve">DURCHSUCHE SHA/SUBJEKT/AUTOR. DRÜCKE ZUM SUCHEN ENTER, ESC UM ABZUBRECHEN</x:String> <x:String x:Key="Text.Histories.Search" xml:space="preserve">DURCHSUCHE SHA/SUBJEKT/AUTOR. DRÜCKE ZUM SUCHEN ENTER, ESC UM ABZUBRECHEN</x:String>
<x:String x:Key="Text.Histories.SearchClear" xml:space="preserve">LÖSCHEN</x:String> <x:String x:Key="Text.Histories.SearchClear" xml:space="preserve">LÖSCHEN</x:String>
<x:String x:Key="Text.Histories.Selected" xml:space="preserve">{0} COMMITS AUSGEWÄHLT</x:String> <x:String x:Key="Text.Histories.Selected" xml:space="preserve">{0} COMMITS AUSGEWÄHLT</x:String>
<x:String x:Key="Text.Hotkeys" xml:space="preserve">Tastaturkürzel Referenz</x:String> <x:String x:Key="Text.Hotkeys" xml:space="preserve">Tastaturkürzel Referenz</x:String>
<x:String x:Key="Text.Hotkeys.Global" xml:space="preserve">GLOBAL</x:String> <x:String x:Key="Text.Hotkeys.Global" xml:space="preserve">GLOBAL</x:String>
<x:String x:Key="Text.Hotkeys.Global.CancelPopup" xml:space="preserve">Aktuelles Popup abbrechen</x:String> <x:String x:Key="Text.Hotkeys.Global.CancelPopup" xml:space="preserve">Aktuelles Popup schließen</x:String>
<x:String x:Key="Text.Hotkeys.Global.CloseTab" xml:space="preserve">Aktuelle Seite schließen</x:String> <x:String x:Key="Text.Hotkeys.Global.CloseTab" xml:space="preserve">Aktuellen Tab schließen</x:String>
<x:String x:Key="Text.Hotkeys.Global.GotoPrevTab" xml:space="preserve">Zu vorheriger Seite gehen</x:String> <x:String x:Key="Text.Hotkeys.Global.GotoPrevTab" xml:space="preserve">Zum vorherigen Tab wechseln</x:String>
<x:String x:Key="Text.Hotkeys.Global.GotoNextTab" xml:space="preserve">Zu nächster Seite gehen</x:String> <x:String x:Key="Text.Hotkeys.Global.GotoNextTab" xml:space="preserve">Zum nächsten Tab wechseln</x:String>
<x:String x:Key="Text.Hotkeys.Global.NewTab" xml:space="preserve">Neue Seite erstellen</x:String> <x:String x:Key="Text.Hotkeys.Global.NewTab" xml:space="preserve">Neuen Tab erstellen</x:String>
<x:String x:Key="Text.Hotkeys.Global.OpenPreference" xml:space="preserve">Einstellungen öffnen</x:String> <x:String x:Key="Text.Hotkeys.Global.OpenPreference" xml:space="preserve">Einstellungen öffnen</x:String>
<x:String x:Key="Text.Hotkeys.Repo" xml:space="preserve">REPOSITORY</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">Gestagte Änderungen committen</x:String> <x:String x:Key="Text.Hotkeys.Repo.Commit" xml:space="preserve">Gestagte Änderungen committen</x:String>
<x:String x:Key="Text.Hotkeys.Repo.CommitAndPush" xml:space="preserve">Gestagte Änderungen Committen und pushen</x:String> <x:String x:Key="Text.Hotkeys.Repo.CommitAndPush" xml:space="preserve">Gestagte Änderungen committen und pushen</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">Dashboard Modus (Standard)</x:String> <x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">Dashboard Modus (Standard)</x:String>
<x:String x:Key="Text.Hotkeys.Repo.Refresh" xml:space="preserve">Erzwinge Neuladen dieses Repositorys</x:String> <x:String x:Key="Text.Hotkeys.Repo.Refresh" xml:space="preserve">Erzwinge Neuladen des Repositorys</x:String>
<x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">Ausgewählte Änderungen stagen/unstagen</x:String> <x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">Ausgewählte Änderungen stagen/unstagen</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">Commit Suchmodus</x:String> <x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">Commit-Suchmodus</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewChanges" xml:space="preserve">Wechsle zu 'Änderungen'</x:String> <x:String x:Key="Text.Hotkeys.Repo.ViewChanges" xml:space="preserve">Wechsle zu 'Änderungen'</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewHistories" xml:space="preserve">Wechsle zu 'Historie'</x:String> <x:String x:Key="Text.Hotkeys.Repo.ViewHistories" xml:space="preserve">Wechsle zu 'Historien'</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewStashes" xml:space="preserve">Wechsle zu 'Stashes'</x:String> <x:String x:Key="Text.Hotkeys.Repo.ViewStashes" xml:space="preserve">Wechsle zu 'Stashes'</x:String>
<x:String x:Key="Text.Hotkeys.TextEditor" xml:space="preserve">TEXT EDITOR</x:String> <x:String x:Key="Text.Hotkeys.TextEditor" xml:space="preserve">TEXT EDITOR</x:String>
<x:String x:Key="Text.Hotkeys.TextEditor.CloseSearch" xml:space="preserve">Suchpanel schließen</x:String> <x:String x:Key="Text.Hotkeys.TextEditor.CloseSearch" xml:space="preserve">Suchpanel schließen</x:String>
@ -322,11 +331,11 @@
<x:String x:Key="Text.InProgress.Merge" xml:space="preserve">Merge request wird durchgeführt. Drücke 'Abbrechen' um den originalen HEAD wiederherzustellen.</x:String> <x:String x:Key="Text.InProgress.Merge" xml:space="preserve">Merge request wird durchgeführt. Drücke 'Abbrechen' um den originalen HEAD wiederherzustellen.</x:String>
<x:String x:Key="Text.InProgress.Rebase" xml:space="preserve">Rebase wird durchgeführt. Drücke 'Abbrechen' um den originalen HEAD wiederherzustellen.</x:String> <x:String x:Key="Text.InProgress.Rebase" xml:space="preserve">Rebase wird durchgeführt. Drücke 'Abbrechen' um den originalen HEAD wiederherzustellen.</x:String>
<x:String x:Key="Text.InProgress.Revert" xml:space="preserve">Revert wird durchgeführt. Drücke 'Abbrechen' um den originalen HEAD wiederherzustellen.</x:String> <x:String x:Key="Text.InProgress.Revert" xml:space="preserve">Revert wird durchgeführt. Drücke 'Abbrechen' um den originalen HEAD wiederherzustellen.</x:String>
<x:String x:Key="Text.InteractiveRebase" xml:space="preserve">Interactiver Rebase</x:String> <x:String x:Key="Text.InteractiveRebase" xml:space="preserve">Interaktiver Rebase</x:String>
<x:String x:Key="Text.InteractiveRebase.Target" xml:space="preserve">Ziel Branch:</x:String> <x:String x:Key="Text.InteractiveRebase.Target" xml:space="preserve">Ziel Branch:</x:String>
<x:String x:Key="Text.InteractiveRebase.On" xml:space="preserve">Auf:</x:String> <x:String x:Key="Text.InteractiveRebase.On" xml:space="preserve">Auf:</x:String>
<x:String x:Key="Text.InteractiveRebase.MoveUp" xml:space="preserve">Hinaufschieben</x:String> <x:String x:Key="Text.InteractiveRebase.MoveUp" xml:space="preserve">Hoch schieben</x:String>
<x:String x:Key="Text.InteractiveRebase.MoveDown" xml:space="preserve">Hinunterschieben</x:String> <x:String x:Key="Text.InteractiveRebase.MoveDown" xml:space="preserve">Runter schieben</x:String>
<x:String x:Key="Text.Launcher" xml:space="preserve">Source Git</x:String> <x:String x:Key="Text.Launcher" xml:space="preserve">Source Git</x:String>
<x:String x:Key="Text.Launcher.Error" xml:space="preserve">FEHLER</x:String> <x:String x:Key="Text.Launcher.Error" xml:space="preserve">FEHLER</x:String>
<x:String x:Key="Text.Launcher.Info" xml:space="preserve">INFO</x:String> <x:String x:Key="Text.Launcher.Info" xml:space="preserve">INFO</x:String>
@ -345,7 +354,7 @@
<x:String x:Key="Text.PageTabBar.Tab.Bookmark" xml:space="preserve">Lesezeichen</x:String> <x:String x:Key="Text.PageTabBar.Tab.Bookmark" xml:space="preserve">Lesezeichen</x:String>
<x:String x:Key="Text.PageTabBar.Tab.Close" xml:space="preserve">Tab schließen</x:String> <x:String x:Key="Text.PageTabBar.Tab.Close" xml:space="preserve">Tab schließen</x:String>
<x:String x:Key="Text.PageTabBar.Tab.CloseOther" xml:space="preserve">Schließe andere Tabs</x:String> <x:String x:Key="Text.PageTabBar.Tab.CloseOther" xml:space="preserve">Schließe andere Tabs</x:String>
<x:String x:Key="Text.PageTabBar.Tab.CloseRight" xml:space="preserve">Schließe Tabs rechts davon</x:String> <x:String x:Key="Text.PageTabBar.Tab.CloseRight" xml:space="preserve">Schließe Rechte Tabs</x:String>
<x:String x:Key="Text.PageTabBar.Tab.CopyPath" xml:space="preserve">Kopiere Repository-Pfad</x:String> <x:String x:Key="Text.PageTabBar.Tab.CopyPath" xml:space="preserve">Kopiere Repository-Pfad</x:String>
<x:String x:Key="Text.PageTabBar.Welcome.Title" xml:space="preserve">Repositories</x:String> <x:String x:Key="Text.PageTabBar.Welcome.Title" xml:space="preserve">Repositories</x:String>
<x:String x:Key="Text.Paste" xml:space="preserve">Einfügen</x:String> <x:String x:Key="Text.Paste" xml:space="preserve">Einfügen</x:String>
@ -359,27 +368,28 @@
<x:String x:Key="Text.Period.LastYear" xml:space="preserve">Leztes Jahr</x:String> <x:String x:Key="Text.Period.LastYear" xml:space="preserve">Leztes Jahr</x:String>
<x:String x:Key="Text.Period.YearsAgo" xml:space="preserve">Vor {0} Jahren</x:String> <x:String x:Key="Text.Period.YearsAgo" xml:space="preserve">Vor {0} Jahren</x:String>
<x:String x:Key="Text.Preference" xml:space="preserve">Einstellungen</x:String> <x:String x:Key="Text.Preference" xml:space="preserve">Einstellungen</x:String>
<x:String x:Key="Text.Preference.Appearance" xml:space="preserve">OBERFLÄCHE</x:String> <x:String x:Key="Text.Preference.Appearance" xml:space="preserve">ERSCHEINUNGSBILD</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Standardschriftart</x:String> <x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Standardschriftart</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">Standard Schriftgröße</x:String> <x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">Standardschriftgröße</x:String>
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Monospace Schriftart</x:String> <x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Monospace-Schriftart</x:String>
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">Verwende nur die Monospace-Schriftart im Text Editor</x:String>
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Design</x:String> <x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Design</x:String>
<x:String x:Key="Text.Preference.Appearance.ThemeOverrides" xml:space="preserve">Design Überbrückung</x:String> <x:String x:Key="Text.Preference.Appearance.ThemeOverrides" xml:space="preserve">Design-Anpassungen</x:String>
<x:String x:Key="Text.Preference.General" xml:space="preserve">ALLGEMEIN</x:String> <x:String x:Key="Text.Preference.General" xml:space="preserve">ALLGEMEIN</x:String>
<x:String x:Key="Text.Preference.General.AvatarServer" xml:space="preserve">Avatar Server</x:String> <x:String x:Key="Text.Preference.General.AvatarServer" xml:space="preserve">Avatar Server</x:String>
<x:String x:Key="Text.Preference.General.Check4UpdatesOnStartup" xml:space="preserve">Beim Starten nach Updates suchen</x:String> <x:String x:Key="Text.Preference.General.Check4UpdatesOnStartup" xml:space="preserve">Beim Starten nach Updates suchen</x:String>
<x:String x:Key="Text.Preference.General.Locale" xml:space="preserve">Sprache</x:String> <x:String x:Key="Text.Preference.General.Locale" xml:space="preserve">Sprache</x:String>
<x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">Commits Historie</x:String> <x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">Commit-Historie</x:String>
<x:String x:Key="Text.Preference.General.RestoreTabs" xml:space="preserve">Zuletzt geöffnete Tabs beim Starten wiederherstellen</x:String> <x:String x:Key="Text.Preference.General.RestoreTabs" xml:space="preserve">Zuletzt geöffnete Tabs beim Starten wiederherstellen</x:String>
<x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">Betreff Hilfslinienlänge</x:String> <x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">Commit-Nachricht Hinweislänge</x:String>
<x:String x:Key="Text.Preference.General.UseFixedTabWidth" xml:space="preserve">Fixe Tab-Breite in Titelleiste</x:String> <x:String x:Key="Text.Preference.General.UseFixedTabWidth" xml:space="preserve">Fixe Tab-Breite in Titelleiste</x:String>
<x:String x:Key="Text.Preference.General.VisibleDiffContextLines" xml:space="preserve">Sichtbare Vergleichskontextzeilen</x:String> <x:String x:Key="Text.Preference.General.VisibleDiffContextLines" xml:space="preserve">Sichtbare Vergleichskontextzeilen</x:String>
<x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT</x:String> <x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetch" xml:space="preserve">Remotes automatisch fetchen</x:String> <x:String x:Key="Text.Preference.Git.AutoFetch" xml:space="preserve">Remotes automatisch fetchen</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchInterval" xml:space="preserve">Auto-Fetch Interval</x:String> <x:String x:Key="Text.Preference.Git.AutoFetchInterval" xml:space="preserve">Auto-Fetch Intervall</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchIntervalSuffix" xml:space="preserve">Minute(n)</x:String> <x:String x:Key="Text.Preference.Git.AutoFetchIntervalSuffix" xml:space="preserve">Minute(n)</x:String>
<x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">Aktiviere Auto-CRLF</x:String> <x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">Aktiviere Auto-CRLF</x:String>
<x:String x:Key="Text.Preference.Git.DefaultCloneDir" xml:space="preserve">Standard Klon-Ordner</x:String> <x:String x:Key="Text.Preference.Git.DefaultCloneDir" xml:space="preserve">Clone Standardordner</x:String>
<x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">Benutzer Email</x:String> <x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">Benutzer Email</x:String>
<x:String x:Key="Text.Preference.Git.Email.Placeholder" xml:space="preserve">Globale Git Benutzer Email</x:String> <x:String x:Key="Text.Preference.Git.Email.Placeholder" xml:space="preserve">Globale Git Benutzer Email</x:String>
<x:String x:Key="Text.Preference.Git.Path" xml:space="preserve">Installationspfad</x:String> <x:String x:Key="Text.Preference.Git.Path" xml:space="preserve">Installationspfad</x:String>
@ -387,27 +397,27 @@
<x:String x:Key="Text.Preference.Git.User" xml:space="preserve">Benutzername</x:String> <x:String x:Key="Text.Preference.Git.User" xml:space="preserve">Benutzername</x:String>
<x:String x:Key="Text.Preference.Git.User.Placeholder" xml:space="preserve">Globaler Git Benutzername</x:String> <x:String x:Key="Text.Preference.Git.User.Placeholder" xml:space="preserve">Globaler Git Benutzername</x:String>
<x:String x:Key="Text.Preference.Git.Version" xml:space="preserve">Git Version</x:String> <x:String x:Key="Text.Preference.Git.Version" xml:space="preserve">Git Version</x:String>
<x:String x:Key="Text.Preference.Git.Invalid" xml:space="preserve">Git (>= 2.23.0) wird von dieser App benötigt</x:String> <x:String x:Key="Text.Preference.Git.Invalid" xml:space="preserve">Diese App setzt Git (>= 2.23.0) voraus</x:String>
<x:String x:Key="Text.Preference.GPG" xml:space="preserve">GPG SIGNIERUNG</x:String> <x:String x:Key="Text.Preference.GPG" xml:space="preserve">GPG SIGNIERUNG</x:String>
<x:String x:Key="Text.Preference.GPG.CommitEnabled" xml:space="preserve">Commit GPG Signierung</x:String> <x:String x:Key="Text.Preference.GPG.CommitEnabled" xml:space="preserve">Commit-Signierung</x:String>
<x:String x:Key="Text.Preference.GPG.TagEnabled" xml:space="preserve">Tag GPG Signierung</x:String> <x:String x:Key="Text.Preference.GPG.TagEnabled" xml:space="preserve">Tag-Signierung</x:String>
<x:String x:Key="Text.Preference.GPG.Format" xml:space="preserve">GPG Format</x:String> <x:String x:Key="Text.Preference.GPG.Format" xml:space="preserve">GPG Format</x:String>
<x:String x:Key="Text.Preference.GPG.Path" xml:space="preserve">Program Installspfad</x:String> <x:String x:Key="Text.Preference.GPG.Path" xml:space="preserve">GPG Installationspfad</x:String>
<x:String x:Key="Text.Preference.GPG.Path.Placeholder" xml:space="preserve">Gebe Installationspfad zu installiertem GPG Programm an</x:String> <x:String x:Key="Text.Preference.GPG.Path.Placeholder" xml:space="preserve">Gebe Installationspfad zu installiertem GPG Programm an</x:String>
<x:String x:Key="Text.Preference.GPG.UserKey" xml:space="preserve">Benutzer Signierungsschlüssel</x:String> <x:String x:Key="Text.Preference.GPG.UserKey" xml:space="preserve">Benutzer Signierungsschlüssel</x:String>
<x:String x:Key="Text.Preference.GPG.UserKey.Placeholder" xml:space="preserve">Benutzer GPG Signierungsschlüssel</x:String> <x:String x:Key="Text.Preference.GPG.UserKey.Placeholder" xml:space="preserve">GPG Benutzer Signierungsschlüssel</x:String>
<x:String x:Key="Text.Preference.DiffMerge" xml:space="preserve">DIFF/MERGE TOOL</x:String> <x:String x:Key="Text.Preference.DiffMerge" xml:space="preserve">DIFF/MERGE TOOL</x:String>
<x:String x:Key="Text.Preference.DiffMerge.Path" xml:space="preserve">Installspfad</x:String> <x:String x:Key="Text.Preference.DiffMerge.Path" xml:space="preserve">Installationspfad</x:String>
<x:String x:Key="Text.Preference.DiffMerge.Path.Placeholder" xml:space="preserve">Gebe Installationspfad von Diff/Merge Tool an</x:String> <x:String x:Key="Text.Preference.DiffMerge.Path.Placeholder" xml:space="preserve">Gebe Installationspfad zum Diff/Merge Tool an</x:String>
<x:String x:Key="Text.Preference.DiffMerge.Type" xml:space="preserve">Tool</x:String> <x:String x:Key="Text.Preference.DiffMerge.Type" xml:space="preserve">Tool</x:String>
<x:String x:Key="Text.PruneRemote" xml:space="preserve">Remote löschen</x:String> <x:String x:Key="Text.PruneRemote" xml:space="preserve">Remote löschen</x:String>
<x:String x:Key="Text.PruneRemote.Target" xml:space="preserve">Ziel:</x:String> <x:String x:Key="Text.PruneRemote.Target" xml:space="preserve">Ziel:</x:String>
<x:String x:Key="Text.PruneWorktrees" xml:space="preserve">Worktrees löschen</x:String> <x:String x:Key="Text.PruneWorktrees" xml:space="preserve">Worktrees löschen</x:String>
<x:String x:Key="Text.PruneWorktrees.Tip" xml:space="preserve">Worktree Informationen in `$GIT_DIR/worktrees` löschen</x:String> <x:String x:Key="Text.PruneWorktrees.Tip" xml:space="preserve">Worktree Informationen in `$GIT_DIR/worktrees` löschen</x:String>
<x:String x:Key="Text.Pull" xml:space="preserve">Pull</x:String> <x:String x:Key="Text.Pull" xml:space="preserve">Pull</x:String>
<x:String x:Key="Text.Pull.Branch" xml:space="preserve">Branch:</x:String> <x:String x:Key="Text.Pull.Branch" xml:space="preserve">Remote-Branch:</x:String>
<x:String x:Key="Text.Pull.FetchAllBranches" xml:space="preserve">Alle Branches fetchen</x:String> <x:String x:Key="Text.Pull.FetchAllBranches" xml:space="preserve">Alle Branches fetchen</x:String>
<x:String x:Key="Text.Pull.Into" xml:space="preserve">Ziel-Branch:</x:String> <x:String x:Key="Text.Pull.Into" xml:space="preserve">Lokaler Branch:</x:String>
<x:String x:Key="Text.Pull.LocalChanges" xml:space="preserve">Lokale Änderungen:</x:String> <x:String x:Key="Text.Pull.LocalChanges" xml:space="preserve">Lokale Änderungen:</x:String>
<x:String x:Key="Text.Pull.LocalChanges.Discard" xml:space="preserve">Verwerfen</x:String> <x:String x:Key="Text.Pull.LocalChanges.Discard" xml:space="preserve">Verwerfen</x:String>
<x:String x:Key="Text.Pull.LocalChanges.DoNothing" xml:space="preserve">Nichts tun</x:String> <x:String x:Key="Text.Pull.LocalChanges.DoNothing" xml:space="preserve">Nichts tun</x:String>
@ -415,14 +425,14 @@
<x:String x:Key="Text.Pull.NoTags" xml:space="preserve">Ohne Tags fetchen</x:String> <x:String x:Key="Text.Pull.NoTags" xml:space="preserve">Ohne Tags fetchen</x:String>
<x:String x:Key="Text.Pull.Remote" xml:space="preserve">Remote:</x:String> <x:String x:Key="Text.Pull.Remote" xml:space="preserve">Remote:</x:String>
<x:String x:Key="Text.Pull.Title" xml:space="preserve">Pull (Fetch &amp; Merge)</x:String> <x:String x:Key="Text.Pull.Title" xml:space="preserve">Pull (Fetch &amp; Merge)</x:String>
<x:String x:Key="Text.Pull.UseRebase" xml:space="preserve">Rebase anstatt Merge</x:String> <x:String x:Key="Text.Pull.UseRebase" xml:space="preserve">Rebase anstatt Merge verwenden</x:String>
<x:String x:Key="Text.Push" xml:space="preserve">Push</x:String> <x:String x:Key="Text.Push" xml:space="preserve">Push</x:String>
<x:String x:Key="Text.Push.Force" xml:space="preserve">Erzwinge Push</x:String> <x:String x:Key="Text.Push.Force" xml:space="preserve">Erzwinge Push</x:String>
<x:String x:Key="Text.Push.Local" xml:space="preserve">Lokaler Branch:</x:String> <x:String x:Key="Text.Push.Local" xml:space="preserve">Lokaler Branch:</x:String>
<x:String x:Key="Text.Push.Remote" xml:space="preserve">Remote:</x:String> <x:String x:Key="Text.Push.Remote" xml:space="preserve">Remote:</x:String>
<x:String x:Key="Text.Push.Title" xml:space="preserve">Änderungen zum Remote pushen</x:String> <x:String x:Key="Text.Push.Title" xml:space="preserve">Push</x:String>
<x:String x:Key="Text.Push.To" xml:space="preserve">Remote Branch:</x:String> <x:String x:Key="Text.Push.To" xml:space="preserve">Remote-Branch:</x:String>
<x:String x:Key="Text.Push.Tracking" xml:space="preserve">Als verfogender Branch konfigurieren</x:String> <x:String x:Key="Text.Push.Tracking" xml:space="preserve">Remote-Branch verfolgen</x:String>
<x:String x:Key="Text.Push.WithAllTags" xml:space="preserve">Alle Tags pushen</x:String> <x:String x:Key="Text.Push.WithAllTags" xml:space="preserve">Alle Tags pushen</x:String>
<x:String x:Key="Text.PushTag" xml:space="preserve">Tag zum Remote pushen</x:String> <x:String x:Key="Text.PushTag" xml:space="preserve">Tag zum Remote pushen</x:String>
<x:String x:Key="Text.PushTag.PushAllRemotes" xml:space="preserve">Zu allen Remotes pushen</x:String> <x:String x:Key="Text.PushTag.PushAllRemotes" xml:space="preserve">Zu allen Remotes pushen</x:String>
@ -445,7 +455,7 @@
<x:String x:Key="Text.RemoteCM.Edit" xml:space="preserve">Bearbeiten...</x:String> <x:String x:Key="Text.RemoteCM.Edit" xml:space="preserve">Bearbeiten...</x:String>
<x:String x:Key="Text.RemoteCM.Fetch" xml:space="preserve">Fetch</x:String> <x:String x:Key="Text.RemoteCM.Fetch" xml:space="preserve">Fetch</x:String>
<x:String x:Key="Text.RemoteCM.OpenInBrowser" xml:space="preserve">Im Browser öffnen</x:String> <x:String x:Key="Text.RemoteCM.OpenInBrowser" xml:space="preserve">Im Browser öffnen</x:String>
<x:String x:Key="Text.RemoteCM.Prune" xml:space="preserve">Aufräumen (Prune)</x:String> <x:String x:Key="Text.RemoteCM.Prune" xml:space="preserve">Prune</x:String>
<x:String x:Key="Text.RemoteCM.Prune.Target" xml:space="preserve">Ziel:</x:String> <x:String x:Key="Text.RemoteCM.Prune.Target" xml:space="preserve">Ziel:</x:String>
<x:String x:Key="Text.RemoveWorktree" xml:space="preserve">Bestätige das entfernen des Worktrees</x:String> <x:String x:Key="Text.RemoveWorktree" xml:space="preserve">Bestätige das entfernen des Worktrees</x:String>
<x:String x:Key="Text.RemoveWorktree.Force" xml:space="preserve">Aktiviere `--force` Option</x:String> <x:String x:Key="Text.RemoveWorktree.Force" xml:space="preserve">Aktiviere `--force` Option</x:String>
@ -458,9 +468,9 @@
<x:String x:Key="Text.Repository.Clean" xml:space="preserve">Aufräumen (GC &amp; Prune)</x:String> <x:String x:Key="Text.Repository.Clean" xml:space="preserve">Aufräumen (GC &amp; Prune)</x:String>
<x:String x:Key="Text.Repository.CleanTips" xml:space="preserve">Führt `git gc` auf diesem Repository aus.</x:String> <x:String x:Key="Text.Repository.CleanTips" xml:space="preserve">Führt `git gc` auf diesem Repository aus.</x:String>
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">Alles löschen</x:String> <x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">Alles löschen</x:String>
<x:String x:Key="Text.Repository.Configure" xml:space="preserve">Dieses Repository konfigureren</x:String> <x:String x:Key="Text.Repository.Configure" xml:space="preserve">Repository Einstellungen</x:String>
<x:String x:Key="Text.Repository.Continue" xml:space="preserve">WEITER</x:String> <x:String x:Key="Text.Repository.Continue" xml:space="preserve">WEITER</x:String>
<x:String x:Key="Text.Repository.Explore" xml:space="preserve">Repository im Datei-Browser öffnen</x:String> <x:String x:Key="Text.Repository.Explore" xml:space="preserve">Öffne im Datei-Browser</x:String>
<x:String x:Key="Text.Repository.FilterCommitPrefix" xml:space="preserve">GEFILTERT:</x:String> <x:String x:Key="Text.Repository.FilterCommitPrefix" xml:space="preserve">GEFILTERT:</x:String>
<x:String x:Key="Text.Repository.LocalBranches" xml:space="preserve">LOKALE BRANCHES</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.NavigateToCurrentHead" xml:space="preserve">Zum HEAD wechseln</x:String>
@ -470,14 +480,14 @@
<x:String x:Key="Text.Repository.Refresh" xml:space="preserve">Aktualisiern</x:String> <x:String x:Key="Text.Repository.Refresh" xml:space="preserve">Aktualisiern</x:String>
<x:String x:Key="Text.Repository.Remotes" xml:space="preserve">REMOTES</x:String> <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.Remotes.Add" xml:space="preserve">REMOTE HINZUFÜGEN</x:String>
<x:String x:Key="Text.Repository.Resolve" xml:space="preserve">AUFLÖSEN</x:String> <x:String x:Key="Text.Repository.Resolve" xml:space="preserve">LÖSEN</x:String>
<x:String x:Key="Text.Repository.Search" xml:space="preserve">Commit suchen</x:String> <x:String x:Key="Text.Repository.Search" xml:space="preserve">Commit suchen</x:String>
<x:String x:Key="Text.Repository.Search.By" xml:space="preserve">Suche über</x:String> <x:String x:Key="Text.Repository.Search.By" xml:space="preserve">Suche über</x:String>
<x:String x:Key="Text.Repository.Search.ByFile" xml:space="preserve">Datei</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">Nachricht</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.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.ByUser" xml:space="preserve">Autor &amp; Committer</x:String>
<x:String x:Key="Text.Repository.SearchBranchTag" xml:space="preserve">Duche Branches &amp; Tags</x:String> <x:String x:Key="Text.Repository.SearchBranchTag" xml:space="preserve">Suche Branches &amp; Tags</x:String>
<x:String x:Key="Text.Repository.Statistics" xml:space="preserve">Statistiken</x:String> <x:String x:Key="Text.Repository.Statistics" xml:space="preserve">Statistiken</x:String>
<x:String x:Key="Text.Repository.Submodules" xml:space="preserve">SUBMODULE</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">SUBMODUL HINZUFÜGEN</x:String> <x:String x:Key="Text.Repository.Submodules.Add" xml:space="preserve">SUBMODUL HINZUFÜGEN</x:String>
@ -487,19 +497,19 @@
<x:String x:Key="Text.Repository.Terminal" xml:space="preserve">Öffne im Terminal</x:String> <x:String x:Key="Text.Repository.Terminal" xml:space="preserve">Öffne im Terminal</x:String>
<x:String x:Key="Text.Repository.Worktrees" xml:space="preserve">WORKTREES</x:String> <x:String x:Key="Text.Repository.Worktrees" xml:space="preserve">WORKTREES</x:String>
<x:String x:Key="Text.Repository.Worktrees.Add" xml:space="preserve">WORKTREE HINZUFÜGEN</x:String> <x:String x:Key="Text.Repository.Worktrees.Add" xml:space="preserve">WORKTREE HINZUFÜGEN</x:String>
<x:String x:Key="Text.Repository.Worktrees.Prune" xml:space="preserve">AUFRÄUMEN (PRUNE)</x:String> <x:String x:Key="Text.Repository.Worktrees.Prune" xml:space="preserve">PRUNE</x:String>
<x:String x:Key="Text.RepositoryURL" xml:space="preserve">Git Repository URL</x:String> <x:String x:Key="Text.RepositoryURL" xml:space="preserve">Git Repository URL</x:String>
<x:String x:Key="Text.Reset" xml:space="preserve">Aktuellen Branch auf Revision zurücksetzen</x:String> <x:String x:Key="Text.Reset" xml:space="preserve">Aktuellen Branch auf Revision zurücksetzen</x:String>
<x:String x:Key="Text.Reset.Mode" xml:space="preserve">Rücksetzmodus:</x:String> <x:String x:Key="Text.Reset.Mode" xml:space="preserve">Rücksetzmodus:</x:String>
<x:String x:Key="Text.Reset.MoveTo" xml:space="preserve">Verschiebe zu:</x:String> <x:String x:Key="Text.Reset.MoveTo" xml:space="preserve">Verschiebe zu:</x:String>
<x:String x:Key="Text.Reset.Target" xml:space="preserve">Aktueller Branch:</x:String> <x:String x:Key="Text.Reset.Target" xml:space="preserve">Aktueller Branch:</x:String>
<x:String x:Key="Text.RevealFile" xml:space="preserve">Zeige im Datei Explorer</x:String> <x:String x:Key="Text.RevealFile" xml:space="preserve">Zeige im Datei-Explorer</x:String>
<x:String x:Key="Text.Revert" xml:space="preserve">Commit umkehren</x:String> <x:String x:Key="Text.Revert" xml:space="preserve">Commit rückgängig machen</x:String>
<x:String x:Key="Text.Revert.Commit" xml:space="preserve">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 Änderungen umkehren</x:String> <x:String x:Key="Text.Revert.CommitChanges" xml:space="preserve">Commit Änderungen rückgängig machen</x:String>
<x:String x:Key="Text.Reword" xml:space="preserve">Commit Nachricht umformulieren</x:String> <x:String x:Key="Text.Reword" xml:space="preserve">Commit Nachricht umformulieren</x:String>
<x:String x:Key="Text.Reword.Tip" xml:space="preserve">Verwende 'Shift+Enter' um eine neue Zeile einzufügen. 'Enter' ist das Kürzl für den OK Button</x:String> <x:String x:Key="Text.Reword.Tip" xml:space="preserve">Verwende 'Shift+Enter' um eine neue Zeile einzufügen. 'Enter' ist das Kürzel für den OK Button</x:String>
<x:String x:Key="Text.Running" xml:space="preserve">Läuft. Bitte warten...</x:String> <x:String x:Key="Text.Running" xml:space="preserve">Bitte warten...</x:String>
<x:String x:Key="Text.Save" xml:space="preserve">SPEICHERN</x:String> <x:String x:Key="Text.Save" xml:space="preserve">SPEICHERN</x:String>
<x:String x:Key="Text.SaveAs" xml:space="preserve">Speichern als...</x:String> <x:String x:Key="Text.SaveAs" xml:space="preserve">Speichern als...</x:String>
<x:String x:Key="Text.SaveAsPatchSuccess" xml:space="preserve">Patch wurde erfolgreich gespeichert!</x:String> <x:String x:Key="Text.SaveAsPatchSuccess" xml:space="preserve">Patch wurde erfolgreich gespeichert!</x:String>
@ -510,15 +520,15 @@
<x:String x:Key="Text.SelfUpdate.IgnoreThisVersion" xml:space="preserve">Diese Version überspringen</x:String> <x:String x:Key="Text.SelfUpdate.IgnoreThisVersion" xml:space="preserve">Diese Version überspringen</x:String>
<x:String x:Key="Text.SelfUpdate.Title" xml:space="preserve">Software Update</x:String> <x:String x:Key="Text.SelfUpdate.Title" xml:space="preserve">Software Update</x:String>
<x:String x:Key="Text.SelfUpdate.UpToDate" xml:space="preserve">Es sind momentan kein Updates verfügbar.</x:String> <x:String x:Key="Text.SelfUpdate.UpToDate" xml:space="preserve">Es sind momentan kein Updates verfügbar.</x:String>
<x:String x:Key="Text.Squash" xml:space="preserve">Squash HEAD In Parent</x:String> <x:String x:Key="Text.Squash" xml:space="preserve">Squash HEAD in Vorgänger</x:String>
<x:String x:Key="Text.SSHKey" xml:space="preserve">SSH privater Schlüssel:</x:String> <x:String x:Key="Text.SSHKey" xml:space="preserve">SSH privater Schlüssel:</x:String>
<x:String x:Key="Text.SSHKey.Placeholder" xml:space="preserve">Pfad zum privaten SSH Schlüssel</x:String> <x:String x:Key="Text.SSHKey.Placeholder" xml:space="preserve">Pfad zum privaten SSH Schlüssel</x:String>
<x:String x:Key="Text.Start" xml:space="preserve">START</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" xml:space="preserve">Stash</x:String>
<x:String x:Key="Text.Stash.IncludeUntracked" xml:space="preserve">Inklusive nicht-verfolgter Dateien</x:String> <x:String x:Key="Text.Stash.IncludeUntracked" xml:space="preserve">Inklusive nicht-verfolgter Dateien</x:String>
<x:String x:Key="Text.Stash.Message" xml:space="preserve">Nachricht:</x:String> <x:String x:Key="Text.Stash.Message" xml:space="preserve">Name:</x:String>
<x:String x:Key="Text.Stash.Message.Placeholder" xml:space="preserve">Optional. Name dieses Stashes</x:String> <x:String x:Key="Text.Stash.Message.Placeholder" xml:space="preserve">Optional. Name dieses Stashes</x:String>
<x:String x:Key="Text.Stash.Title" xml:space="preserve">Lokale Änderugen stashen</x:String> <x:String x:Key="Text.Stash.Title" xml:space="preserve">Lokale Änderungen stashen</x:String>
<x:String x:Key="Text.StashCM.Apply" xml:space="preserve">Anwenden</x:String> <x:String x:Key="Text.StashCM.Apply" xml:space="preserve">Anwenden</x:String>
<x:String x:Key="Text.StashCM.Drop" xml:space="preserve">Entfernen</x:String> <x:String x:Key="Text.StashCM.Drop" xml:space="preserve">Entfernen</x:String>
<x:String x:Key="Text.StashCM.Pop" xml:space="preserve">Anwenden und entfernen</x:String> <x:String x:Key="Text.StashCM.Pop" xml:space="preserve">Anwenden und entfernen</x:String>
@ -535,7 +545,7 @@
<x:String x:Key="Text.Statistics.ThisYear" xml:space="preserve">JAHR</x:String> <x:String x:Key="Text.Statistics.ThisYear" xml:space="preserve">JAHR</x:String>
<x:String x:Key="Text.Statistics.TotalCommits" xml:space="preserve">COMMITS: </x:String> <x:String x:Key="Text.Statistics.TotalCommits" xml:space="preserve">COMMITS: </x:String>
<x:String x:Key="Text.Statistics.TotalCommitters" xml:space="preserve">COMMITTERS: </x:String> <x:String x:Key="Text.Statistics.TotalCommitters" xml:space="preserve">COMMITTERS: </x:String>
<x:String x:Key="Text.Submodule" xml:space="preserve">SUBMODUL</x:String> <x:String x:Key="Text.Submodule" xml:space="preserve">SUBMODULE</x:String>
<x:String x:Key="Text.Submodule.Add" xml:space="preserve">Submodul hinzufügen</x:String> <x:String x:Key="Text.Submodule.Add" xml:space="preserve">Submodul hinzufügen</x:String>
<x:String x:Key="Text.Submodule.CopyPath" xml:space="preserve">Relativen Pfad kopieren</x:String> <x:String x:Key="Text.Submodule.CopyPath" xml:space="preserve">Relativen Pfad kopieren</x:String>
<x:String x:Key="Text.Submodule.FetchNested" xml:space="preserve">Untergeordnete Submodule fetchen</x:String> <x:String x:Key="Text.Submodule.FetchNested" xml:space="preserve">Untergeordnete Submodule fetchen</x:String>
@ -546,7 +556,7 @@
<x:String x:Key="Text.Sure" xml:space="preserve">OK</x:String> <x:String x:Key="Text.Sure" xml:space="preserve">OK</x:String>
<x:String x:Key="Text.TagCM.Copy" xml:space="preserve">Tag-Namen kopieren</x:String> <x:String x:Key="Text.TagCM.Copy" xml:space="preserve">Tag-Namen kopieren</x:String>
<x:String x:Key="Text.TagCM.Delete" xml:space="preserve">Lösche ${0}$...</x:String> <x:String x:Key="Text.TagCM.Delete" xml:space="preserve">Lösche ${0}$...</x:String>
<x:String x:Key="Text.TagCM.Push" xml:space="preserve">${0}$ pushen...</x:String> <x:String x:Key="Text.TagCM.Push" xml:space="preserve">Pushe ${0}$...</x:String>
<x:String x:Key="Text.URL" xml:space="preserve">URL:</x:String> <x:String x:Key="Text.URL" xml:space="preserve">URL:</x:String>
<x:String x:Key="Text.UpdateSubmodules" xml:space="preserve">Submodule aktualisieren</x:String> <x:String x:Key="Text.UpdateSubmodules" xml:space="preserve">Submodule aktualisieren</x:String>
<x:String x:Key="Text.UpdateSubmodules.All" xml:space="preserve">Alle Submodule</x:String> <x:String x:Key="Text.UpdateSubmodules.All" xml:space="preserve">Alle Submodule</x:String>
@ -555,11 +565,12 @@
<x:String x:Key="Text.UpdateSubmodules.Target" xml:space="preserve">Submodul:</x:String> <x:String x:Key="Text.UpdateSubmodules.Target" xml:space="preserve">Submodul:</x:String>
<x:String x:Key="Text.UpdateSubmodules.UseRemote" xml:space="preserve">Verwende `--remote` Option</x:String> <x:String x:Key="Text.UpdateSubmodules.UseRemote" xml:space="preserve">Verwende `--remote` Option</x:String>
<x:String x:Key="Text.Warn" xml:space="preserve">Warnung</x:String> <x:String x:Key="Text.Warn" xml:space="preserve">Warnung</x:String>
<x:String x:Key="Text.Welcome" xml:space="preserve">Willkommensseite</x:String>
<x:String x:Key="Text.Welcome.AddRootFolder" xml:space="preserve">Erstelle Gruppe</x:String> <x:String x:Key="Text.Welcome.AddRootFolder" xml:space="preserve">Erstelle Gruppe</x:String>
<x:String x:Key="Text.Welcome.AddSubFolder" xml:space="preserve">Erstelle Untergruppe</x:String> <x:String x:Key="Text.Welcome.AddSubFolder" xml:space="preserve">Erstelle Untergruppe</x:String>
<x:String x:Key="Text.Welcome.Clone" xml:space="preserve">Klone Repository</x:String> <x:String x:Key="Text.Welcome.Clone" xml:space="preserve">Klone Repository</x:String>
<x:String x:Key="Text.Welcome.Delete" xml:space="preserve">Lösche</x:String> <x:String x:Key="Text.Welcome.Delete" xml:space="preserve">Lösche</x:String>
<x:String x:Key="Text.Welcome.DragDropTip" xml:space="preserve">DRAG &amp; DROP VON ORDNER UNTERSTÜTZT. ANGEPASSTE GRUPPIERUNG UNTERSTÜTZT.</x:String> <x:String x:Key="Text.Welcome.DragDropTip" xml:space="preserve">DRAG &amp; DROP VON ORDNER UNTERSTÜTZT. BENUTZERDEFINIERTE GRUPPIERUNG UNTERSTÜTZT.</x:String>
<x:String x:Key="Text.Welcome.Edit" xml:space="preserve">Bearbeiten</x:String> <x:String x:Key="Text.Welcome.Edit" xml:space="preserve">Bearbeiten</x:String>
<x:String x:Key="Text.Welcome.OpenAllInNode" xml:space="preserve">Öffne alle Repositories</x:String> <x:String x:Key="Text.Welcome.OpenAllInNode" xml:space="preserve">Öffne alle Repositories</x:String>
<x:String x:Key="Text.Welcome.OpenOrInit" xml:space="preserve">Öffne Repository</x:String> <x:String x:Key="Text.Welcome.OpenOrInit" xml:space="preserve">Öffne Repository</x:String>
@ -581,20 +592,20 @@
<x:String x:Key="Text.WorkingCopy.CommitTip" xml:space="preserve">STRG + Enter</x:String> <x:String x:Key="Text.WorkingCopy.CommitTip" xml:space="preserve">STRG + Enter</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts" xml:space="preserve">KONFLIKTE ERKANNT</x:String> <x:String x:Key="Text.WorkingCopy.Conflicts" xml:space="preserve">KONFLIKTE ERKANNT</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.Resolved" xml:space="preserve">DATEI KONFLIKTE GELÖST</x:String> <x:String x:Key="Text.WorkingCopy.Conflicts.Resolved" xml:space="preserve">DATEI KONFLIKTE GELÖST</x:String>
<x:String x:Key="Text.WorkingCopy.HasCommitHistories" xml:space="preserve">LETZTE COMMIT NACHRICHTEN</x:String> <x:String x:Key="Text.WorkingCopy.HasCommitHistories" xml:space="preserve">LETZTE COMMIT-NACHRICHTEN</x:String>
<x:String x:Key="Text.WorkingCopy.IncludeUntracked" xml:space="preserve">NICHT-VERFOLGTE DATEIEN INKLUDIEREN</x:String> <x:String x:Key="Text.WorkingCopy.IncludeUntracked" xml:space="preserve">NICHT-VERFOLGTE DATEIEN INKLUDIEREN</x:String>
<x:String x:Key="Text.WorkingCopy.MessageHistories" xml:space="preserve">NACHRICHTEN HISTORIE</x:String> <x:String x:Key="Text.WorkingCopy.MessageHistories" xml:space="preserve">NACHRICHTEN HISTORIE</x:String>
<x:String x:Key="Text.WorkingCopy.NoCommitHistories" xml:space="preserve">KEINE BISHERIGEN COMMIT NACHRICHTEN</x:String> <x:String x:Key="Text.WorkingCopy.NoCommitHistories" xml:space="preserve">KEINE BISHERIGEN COMMIT-NACHRICHTEN</x:String>
<x:String x:Key="Text.WorkingCopy.Staged" xml:space="preserve">GESTAGED</x:String> <x:String x:Key="Text.WorkingCopy.Staged" xml:space="preserve">GESTAGED</x:String>
<x:String x:Key="Text.WorkingCopy.Staged.Unstage" xml:space="preserve">UNSTAGEN</x:String> <x:String x:Key="Text.WorkingCopy.Staged.Unstage" xml:space="preserve">UNSTAGEN</x:String>
<x:String x:Key="Text.WorkingCopy.Staged.UnstageAll" xml:space="preserve">ALLES UNSTAGEN</x:String> <x:String x:Key="Text.WorkingCopy.Staged.UnstageAll" xml:space="preserve">ALLES UNSTAGEN</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged" xml:space="preserve">UNSTAGED</x:String> <x:String x:Key="Text.WorkingCopy.Unstaged" xml:space="preserve">UNSTAGED</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged.Stage" xml:space="preserve">STAGEN</x:String> <x:String x:Key="Text.WorkingCopy.Unstaged.Stage" xml:space="preserve">STAGEN</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged.StageAll" xml:space="preserve">ALLES STAGEN</x:String> <x:String x:Key="Text.WorkingCopy.Unstaged.StageAll" xml:space="preserve">ALLES STAGEN</x:String>
<x:String x:Key="Text.WorkingCopy.Unstaged.ViewAssumeUnchaged" xml:space="preserve">UNVERÄNDERTE ANZEIGEN</x:String> <x:String x:Key="Text.WorkingCopy.Unstaged.ViewAssumeUnchaged" xml:space="preserve">ALS UNVERÄNDERT ANGENOMMENE ANZEIGEN</x:String>
<x:String x:Key="Text.WorkingCopy.ResolveTip" xml:space="preserve">Rechtsklick auf selektierte Dateien und wähle die Konfliktlösungen aus.</x:String> <x:String x:Key="Text.WorkingCopy.ResolveTip" xml:space="preserve">Rechtsklick auf selektierte Dateien und wähle die Konfliktlösungen aus.</x:String>
<x:String x:Key="Text.Worktree" xml:space="preserve">WORKTREE</x:String> <x:String x:Key="Text.Worktree" xml:space="preserve">WORKTREE</x:String>
<x:String x:Key="Text.Worktree.CopyPath" xml:space="preserve">Path kopieren</x:String> <x:String x:Key="Text.Worktree.CopyPath" xml:space="preserve">Pfad kopieren</x:String>
<x:String x:Key="Text.Worktree.Lock" xml:space="preserve">Sperren</x:String> <x:String x:Key="Text.Worktree.Lock" xml:space="preserve">Sperren</x:String>
<x:String x:Key="Text.Worktree.Remove" xml:space="preserve">Entfernen</x:String> <x:String x:Key="Text.Worktree.Remove" xml:space="preserve">Entfernen</x:String>
<x:String x:Key="Text.Worktree.Unlock" xml:space="preserve">Entsperren</x:String> <x:String x:Key="Text.Worktree.Unlock" xml:space="preserve">Entsperren</x:String>

View file

@ -124,6 +124,15 @@
<x:String x:Key="Text.Configure" xml:space="preserve">Repository Configure</x:String> <x:String x:Key="Text.Configure" xml:space="preserve">Repository Configure</x:String>
<x:String x:Key="Text.Configure.Email" xml:space="preserve">Email Address</x:String> <x:String x:Key="Text.Configure.Email" xml:space="preserve">Email Address</x:String>
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Email address</x:String> <x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Email address</x:String>
<x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ISSUE TRACKER</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Add Sample Github Rule</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Add Sample Jira Rule</x:String>
<x:String x:Key="Text.Configure.IssueTracker.NewRule" xml:space="preserve">New Rule</x:String>
<x:String x:Key="Text.Configure.IssueTracker.Regex" xml:space="preserve">Issue Regex Expression:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">Rule Name:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">Result URL:</x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">Please use $1, $2 to access regex groups values.</x:String>
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP Proxy</x:String> <x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP Proxy</x:String>
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP proxy used by this repository</x:String> <x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP proxy used by this repository</x:String>
<x:String x:Key="Text.Configure.User" xml:space="preserve">User Name</x:String> <x:String x:Key="Text.Configure.User" xml:space="preserve">User Name</x:String>
@ -476,6 +485,7 @@
<x:String x:Key="Text.Repository.Search.BySHA" xml:space="preserve">SHA</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.ByUser" xml:space="preserve">Author &amp; Committer</x:String>
<x:String x:Key="Text.Repository.SearchBranchTag" xml:space="preserve">Search Branches &amp; Tags</x:String> <x:String x:Key="Text.Repository.SearchBranchTag" xml:space="preserve">Search Branches &amp; Tags</x:String>
<x:String x:Key="Text.Repository.ShowTagsAsTree" xml:space="preserve">Show Tags as Tree</x:String>
<x:String x:Key="Text.Repository.Statistics" xml:space="preserve">Statistics</x:String> <x:String x:Key="Text.Repository.Statistics" xml:space="preserve">Statistics</x:String>
<x:String x:Key="Text.Repository.Submodules" xml:space="preserve">SUBMODULES</x:String> <x:String x:Key="Text.Repository.Submodules" xml:space="preserve">SUBMODULES</x:String>
<x:String x:Key="Text.Repository.Submodules.Add" xml:space="preserve">ADD SUBMODULE</x:String> <x:String x:Key="Text.Repository.Submodules.Add" xml:space="preserve">ADD SUBMODULE</x:String>

View file

@ -127,6 +127,15 @@
<x:String x:Key="Text.Configure" xml:space="preserve">仓库配置</x:String> <x:String x:Key="Text.Configure" xml:space="preserve">仓库配置</x:String>
<x:String x:Key="Text.Configure.Email" xml:space="preserve">电子邮箱</x:String> <x:String x:Key="Text.Configure.Email" xml:space="preserve">电子邮箱</x:String>
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">邮箱地址</x:String> <x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">邮箱地址</x:String>
<x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT配置</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ISSUE追踪</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">新增匹配Github Issue规则</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">新增匹配Jira规则</x:String>
<x:String x:Key="Text.Configure.IssueTracker.NewRule" xml:space="preserve">新增自定义规则</x:String>
<x:String x:Key="Text.Configure.IssueTracker.Regex" xml:space="preserve">匹配ISSUE的正则表达式 </x:String>
<x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">规则名 </x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">为ISSUE生成的URL链接 </x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">可在URL中使用$1$2等变量填入正则表达式匹配的内容</x:String>
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP代理</x:String> <x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP代理</x:String>
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP网络代理</x:String> <x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP网络代理</x:String>
<x:String x:Key="Text.Configure.User" xml:space="preserve">用户名</x:String> <x:String x:Key="Text.Configure.User" xml:space="preserve">用户名</x:String>
@ -478,6 +487,7 @@
<x:String x:Key="Text.Repository.Search.BySHA" 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.ByUser" xml:space="preserve">作者及提交者</x:String>
<x:String x:Key="Text.Repository.SearchBranchTag" xml:space="preserve">快速查找分支、标签</x:String> <x:String x:Key="Text.Repository.SearchBranchTag" xml:space="preserve">快速查找分支、标签</x:String>
<x:String x:Key="Text.Repository.ShowTagsAsTree" xml:space="preserve">以树型结构展示</x:String>
<x:String x:Key="Text.Repository.Statistics" xml:space="preserve">提交统计</x:String> <x:String x:Key="Text.Repository.Statistics" xml:space="preserve">提交统计</x:String>
<x:String x:Key="Text.Repository.Submodules" xml:space="preserve">子模块列表</x:String> <x:String x:Key="Text.Repository.Submodules" xml:space="preserve">子模块列表</x:String>
<x:String x:Key="Text.Repository.Submodules.Add" xml:space="preserve">添加子模块</x:String> <x:String x:Key="Text.Repository.Submodules.Add" xml:space="preserve">添加子模块</x:String>

View file

@ -127,6 +127,15 @@
<x:String x:Key="Text.Configure" xml:space="preserve">倉庫配置</x:String> <x:String x:Key="Text.Configure" xml:space="preserve">倉庫配置</x:String>
<x:String x:Key="Text.Configure.Email" xml:space="preserve">電子郵箱</x:String> <x:String x:Key="Text.Configure.Email" xml:space="preserve">電子郵箱</x:String>
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">郵箱地址</x:String> <x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">郵箱地址</x:String>
<x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT配置</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ISSUE追蹤</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">新增匹配Github Issue規則</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">新增匹配Jira規則</x:String>
<x:String x:Key="Text.Configure.IssueTracker.NewRule" xml:space="preserve">新增自定義規則</x:String>
<x:String x:Key="Text.Configure.IssueTracker.Regex" xml:space="preserve">匹配ISSUE的正則表達式 </x:String>
<x:String x:Key="Text.Configure.IssueTracker.RuleName" xml:space="preserve">規則名 </x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate" xml:space="preserve">為ISSUE生成的URL連結 </x:String>
<x:String x:Key="Text.Configure.IssueTracker.URLTemplate.Tip" xml:space="preserve">可在URL中使用$1$2等變數填入正則表示式匹配的內容</x:String>
<x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP代理</x:String> <x:String x:Key="Text.Configure.Proxy" xml:space="preserve">HTTP代理</x:String>
<x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP網路代理</x:String> <x:String x:Key="Text.Configure.Proxy.Placeholder" xml:space="preserve">HTTP網路代理</x:String>
<x:String x:Key="Text.Configure.User" xml:space="preserve">使用者名稱</x:String> <x:String x:Key="Text.Configure.User" xml:space="preserve">使用者名稱</x:String>
@ -478,6 +487,7 @@
<x:String x:Key="Text.Repository.Search.BySHA" 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.ByUser" xml:space="preserve">作者及提交者</x:String>
<x:String x:Key="Text.Repository.SearchBranchTag" xml:space="preserve">快速查找分支、標籤</x:String> <x:String x:Key="Text.Repository.SearchBranchTag" xml:space="preserve">快速查找分支、標籤</x:String>
<x:String x:Key="Text.Repository.ShowTagsAsTree" xml:space="preserve">以樹型結構展示</x:String>
<x:String x:Key="Text.Repository.Statistics" xml:space="preserve">提交統計</x:String> <x:String x:Key="Text.Repository.Statistics" xml:space="preserve">提交統計</x:String>
<x:String x:Key="Text.Repository.Submodules" xml:space="preserve">子模組列表</x:String> <x:String x:Key="Text.Repository.Submodules" xml:space="preserve">子模組列表</x:String>
<x:String x:Key="Text.Repository.Submodules.Add" xml:space="preserve">新增子模組</x:String> <x:String x:Key="Text.Repository.Submodules.Add" xml:space="preserve">新增子模組</x:String>

View file

@ -164,6 +164,7 @@
<Setter Property="Foreground" Value="{DynamicResource Brush.FG1}"/> <Setter Property="Foreground" Value="{DynamicResource Brush.FG1}"/>
<Setter Property="Background" Value="{DynamicResource Brush.Popup}"/> <Setter Property="Background" Value="{DynamicResource Brush.Popup}"/>
<Setter Property="VerticalOffset" Value="-8"/> <Setter Property="VerticalOffset" Value="-8"/>
<Setter Property="TextBlock.TextDecorations" Value=""/>
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate> <ControlTemplate>
<Grid Effect="drop-shadow(0 0 8 #80000000)"> <Grid Effect="drop-shadow(0 0 8 #80000000)">
@ -276,6 +277,13 @@
<Setter Property="FontWeight" Value="Bold"/> <Setter Property="FontWeight" Value="Bold"/>
<Setter Property="HorizontalAlignment" Value="Right"/> <Setter Property="HorizontalAlignment" Value="Right"/>
</Style> </Style>
<Style Selector="TextBlock.issue_link">
<Setter Property="Foreground" Value="{DynamicResource Brush.Link}"/>
<Setter Property="Cursor" Value="Hand"/>
</Style>
<Style Selector="TextBlock.issue_link:pointerover">
<Setter Property="TextDecorations" Value="Underline"/>
</Style>
<Style Selector="SelectableTextBlock"> <Style Selector="SelectableTextBlock">
<Setter Property="HorizontalAlignment" Value="Left"/> <Setter Property="HorizontalAlignment" Value="Left"/>
@ -1249,6 +1257,38 @@
<Setter Property="Opacity" Value="1"/> <Setter Property="Opacity" Value="1"/>
</Style> </Style>
<Style Selector="ToggleButton.tag_display_mode">
<Setter Property="Margin" Value="0" />
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<ControlTemplate>
<Border Background="Transparent"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
HorizontalAlignment="Left"
VerticalAlignment="Center">
<Path x:Name="ChevronPath"
Width="11" Height="11"
Margin="0,1,0,0"
Data="{StaticResource Icons.Tree}"
Fill="{DynamicResource Brush.FG1}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Opacity="0.65"/>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:checked /template/ Path#ChevronPath">
<Setter Property="Fill" Value="{DynamicResource Brush.Accent}" />
</Style>
<Style Selector="^:pointerover /template/ Path#ChevronPath">
<Setter Property="Fill" Value="{DynamicResource Brush.Accent}" />
<Setter Property="Opacity" Value="1"/>
</Style>
</Style>
<Style Selector="Slider"> <Style Selector="Slider">
<Style.Resources> <Style.Resources>
<Thickness x:Key="SliderTopHeaderMargin">0,0,0,4</Thickness> <Thickness x:Key="SliderTopHeaderMargin">0,0,0,4</Thickness>

View file

@ -32,6 +32,7 @@
<Color x:Key="Color.Diff.DeletedBG">#80FF9797</Color> <Color x:Key="Color.Diff.DeletedBG">#80FF9797</Color>
<Color x:Key="Color.Diff.AddedHighlight">#A7E1A7</Color> <Color x:Key="Color.Diff.AddedHighlight">#A7E1A7</Color>
<Color x:Key="Color.Diff.DeletedHighlight">#F19B9D</Color> <Color x:Key="Color.Diff.DeletedHighlight">#F19B9D</Color>
<Color x:Key="Color.Link">#0000EE</Color>
</ResourceDictionary> </ResourceDictionary>
<ResourceDictionary x:Key="Dark"> <ResourceDictionary x:Key="Dark">
@ -65,6 +66,7 @@
<Color x:Key="Color.Diff.DeletedBG">#C0633F3E</Color> <Color x:Key="Color.Diff.DeletedBG">#C0633F3E</Color>
<Color x:Key="Color.Diff.AddedHighlight">#A0308D3C</Color> <Color x:Key="Color.Diff.AddedHighlight">#A0308D3C</Color>
<Color x:Key="Color.Diff.DeletedHighlight">#A09F4247</Color> <Color x:Key="Color.Diff.DeletedHighlight">#A09F4247</Color>
<Color x:Key="Color.Link">#4DAAFC</Color>
</ResourceDictionary> </ResourceDictionary>
</ResourceDictionary.ThemeDictionaries> </ResourceDictionary.ThemeDictionaries>
@ -100,4 +102,5 @@
<SolidColorBrush x:Key="Brush.Diff.DeletedBG" Color="{DynamicResource Color.Diff.DeletedBG}"/> <SolidColorBrush x:Key="Brush.Diff.DeletedBG" Color="{DynamicResource Color.Diff.DeletedBG}"/>
<SolidColorBrush x:Key="Brush.Diff.AddedHighlight" Color="{DynamicResource Color.Diff.AddedHighlight}"/> <SolidColorBrush x:Key="Brush.Diff.AddedHighlight" Color="{DynamicResource Color.Diff.AddedHighlight}"/>
<SolidColorBrush x:Key="Brush.Diff.DeletedHighlight" Color="{DynamicResource Color.Diff.DeletedHighlight}"/> <SolidColorBrush x:Key="Brush.Diff.DeletedHighlight" Color="{DynamicResource Color.Diff.DeletedHighlight}"/>
<SolidColorBrush x:Key="Brush.Link" Color="{DynamicResource Color.Link}"/>
</ResourceDictionary> </ResourceDictionary>

View file

@ -37,15 +37,15 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="11.1.1" /> <PackageReference Include="Avalonia" Version="11.0.13" />
<PackageReference Include="Avalonia.Desktop" Version="11.1.1" /> <PackageReference Include="Avalonia.Desktop" Version="11.0.13" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.1.1" /> <PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.13" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.1.1" /> <PackageReference Include="Avalonia.Controls.DataGrid" Version="11.0.13" />
<PackageReference Include="Avalonia.AvaloniaEdit" Version="11.0.6" /> <PackageReference Include="Avalonia.Diagnostics" Version="11.0.13" Condition="'$(Configuration)' == 'Debug'" />
<PackageReference Include="Avalonia.Diagnostics" Version="11.1.1" Condition="'$(Configuration)' == 'Debug'" /> <PackageReference Include="Avalonia.AvaloniaEdit" Version="11.1.0" />
<PackageReference Include="AvaloniaEdit.TextMate" Version="11.0.6" /> <PackageReference Include="AvaloniaEdit.TextMate" Version="11.1.0" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" /> <PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageReference Include="TextMateSharp.Grammars" Version="1.0.56" /> <PackageReference Include="TextMateSharp.Grammars" Version="1.0.60" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -53,7 +53,7 @@
<TrimmerRootAssembly Include="Avalonia.Themes.Fluent" /> <TrimmerRootAssembly Include="Avalonia.Themes.Fluent" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Release'"> <ItemGroup Condition="$([MSBuild]::IsOSPlatform('OSX'))">
<LinkerArg Include="-mmacosx-version-min=11.0" Condition="$([MSBuild]::IsOSPlatform('OSX'))"/> <LinkerArg Include="-mmacosx-version-min=11.0" Condition="'$(Configuration)' == 'Release'"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -189,7 +189,7 @@ namespace SourceGit.ViewModels
{ {
nodes.Sort((l, r) => nodes.Sort((l, r) =>
{ {
if (l.Backend is Models.Branch { IsHead: true }) if (l.Backend is Models.Branch { IsDetachedHead: true })
return -1; return -1;
if (l.Backend is Models.Branch) if (l.Backend is Models.Branch)

View file

@ -28,22 +28,16 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false); _repo.SetWatcherEnabled(false);
ProgressDescription = $"Checkout '{Branch}' ..."; ProgressDescription = $"Checkout '{Branch}' ...";
var hasLocalChanges = _repo.WorkingCopyChangesCount > 0;
return Task.Run(() => return Task.Run(() =>
{ {
var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result();
var needPopStash = false; var needPopStash = false;
if (hasLocalChanges) if (changes > 0)
{ {
if (PreAction == Models.DealWithLocalChanges.StashAndReaply) if (PreAction == Models.DealWithLocalChanges.StashAndReaply)
{
SetProgressDescription("Adding untracked changes ...");
var succ = new Commands.Add(_repo.FullPath).Exec();
if (succ)
{ {
SetProgressDescription("Stash local changes ..."); SetProgressDescription("Stash local changes ...");
succ = new Commands.Stash(_repo.FullPath).Push("CHECKOUT_AUTO_STASH"); var succ = new Commands.Stash(_repo.FullPath).Push("CHECKOUT_AUTO_STASH");
}
if (!succ) if (!succ)
{ {
CallUIThread(() => _repo.SetWatcherEnabled(true)); CallUIThread(() => _repo.SetWatcherEnabled(true));
@ -65,11 +59,7 @@ namespace SourceGit.ViewModels
if (needPopStash) if (needPopStash)
{ {
SetProgressDescription("Re-apply local changes..."); SetProgressDescription("Re-apply local changes...");
rs = new Commands.Stash(_repo.FullPath).Apply("stash@{0}"); rs = new Commands.Stash(_repo.FullPath).Pop("stash@{0}");
if (rs)
{
rs = new Commands.Stash(_repo.FullPath).Drop("stash@{0}");
}
} }
CallUIThread(() => _repo.SetWatcherEnabled(true)); CallUIThread(() => _repo.SetWatcherEnabled(true));

View file

@ -10,11 +10,6 @@ namespace SourceGit.ViewModels
private set; private set;
} }
public bool HasLocalChanges
{
get => _repo.WorkingCopyChangesCount > 0;
}
public bool AutoStash public bool AutoStash
{ {
get => _autoStash; get => _autoStash;
@ -35,19 +30,14 @@ namespace SourceGit.ViewModels
return Task.Run(() => return Task.Run(() =>
{ {
var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result();
var needPopStash = false; var needPopStash = false;
if (HasLocalChanges) if (changes > 0)
{ {
if (AutoStash) if (AutoStash)
{
SetProgressDescription("Adding untracked changes ...");
var succ = new Commands.Add(_repo.FullPath).Exec();
if (succ)
{ {
SetProgressDescription("Stash local changes ..."); SetProgressDescription("Stash local changes ...");
succ = new Commands.Stash(_repo.FullPath).Push("CHECKOUT_AUTO_STASH"); var succ = new Commands.Stash(_repo.FullPath).Push("CHECKOUT_AUTO_STASH");
}
if (!succ) if (!succ)
{ {
CallUIThread(() => _repo.SetWatcherEnabled(true)); CallUIThread(() => _repo.SetWatcherEnabled(true));
@ -69,11 +59,7 @@ namespace SourceGit.ViewModels
if (needPopStash) if (needPopStash)
{ {
SetProgressDescription("Re-apply local changes..."); SetProgressDescription("Re-apply local changes...");
rs = new Commands.Stash(_repo.FullPath).Apply("stash@{0}"); rs = new Commands.Stash(_repo.FullPath).Pop("stash@{0}");
if (rs)
{
rs = new Commands.Stash(_repo.FullPath).Drop("stash@{0}");
}
} }
CallUIThread(() => _repo.SetWatcherEnabled(true)); CallUIThread(() => _repo.SetWatcherEnabled(true));

View file

@ -4,6 +4,7 @@ using System.IO;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Collections;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using Avalonia.Platform.Storage; using Avalonia.Platform.Storage;
@ -88,9 +89,15 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _viewRevisionFileContent, value); set => SetProperty(ref _viewRevisionFileContent, value);
} }
public CommitDetail(string repo) public AvaloniaList<Models.IssueTrackerRule> IssueTrackerRules
{
get => _issueTrackerRules;
}
public CommitDetail(string repo, AvaloniaList<Models.IssueTrackerRule> issueTrackerRules)
{ {
_repo = repo; _repo = repo;
_issueTrackerRules = issueTrackerRules;
} }
public void Cleanup() public void Cleanup()
@ -176,7 +183,7 @@ namespace SourceGit.ViewModels
} }
else else
{ {
var txt = new Models.RevisionTextFile() { Content = content }; var txt = new Models.RevisionTextFile() { FileName = file.Path, Content = content };
Dispatcher.UIThread.Invoke(() => ViewRevisionFileContent = txt); Dispatcher.UIThread.Invoke(() => ViewRevisionFileContent = txt);
} }
}); });
@ -242,7 +249,7 @@ namespace SourceGit.ViewModels
history.Icon = App.CreateMenuIcon("Icons.Histories"); history.Icon = App.CreateMenuIcon("Icons.Histories");
history.Click += (_, ev) => history.Click += (_, ev) =>
{ {
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path) }; var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path, _issueTrackerRules) };
window.Show(); window.Show();
ev.Handled = true; ev.Handled = true;
}; };
@ -305,7 +312,7 @@ namespace SourceGit.ViewModels
history.Icon = App.CreateMenuIcon("Icons.Histories"); history.Icon = App.CreateMenuIcon("Icons.Histories");
history.Click += (_, ev) => history.Click += (_, ev) =>
{ {
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, file.Path) }; var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, file.Path, _issueTrackerRules) };
window.Show(); window.Show();
ev.Handled = true; ev.Handled = true;
}; };
@ -457,6 +464,7 @@ namespace SourceGit.ViewModels
}; };
private string _repo; private string _repo;
private AvaloniaList<Models.IssueTrackerRule> _issueTrackerRules = null;
private int _activePageIndex = 0; private int _activePageIndex = 0;
private Models.Commit _commit = null; private Models.Commit _commit = null;
private string _fullMessage = string.Empty; private string _fullMessage = string.Empty;

View file

@ -35,7 +35,7 @@ namespace SourceGit.ViewModels
public CreateBranch(Repository repo, Models.Branch branch) public CreateBranch(Repository repo, Models.Branch branch)
{ {
_repo = repo; _repo = repo;
_baseOnRevision = branch.FullName; _baseOnRevision = branch.IsDetachedHead ? branch.Head : branch.FullName;
if (!branch.IsLocal && repo.Branches.Find(x => x.IsLocal && x.Name == branch.Name) == null) if (!branch.IsLocal && repo.Branches.Find(x => x.IsLocal && x.Name == branch.Name) == null)
{ {
@ -86,19 +86,14 @@ namespace SourceGit.ViewModels
{ {
if (CheckoutAfterCreated) if (CheckoutAfterCreated)
{ {
bool needPopStash = false; var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result();
if (_repo.WorkingCopyChangesCount > 0) var needPopStash = false;
if (changes > 0)
{ {
if (PreAction == Models.DealWithLocalChanges.StashAndReaply) if (PreAction == Models.DealWithLocalChanges.StashAndReaply)
{
SetProgressDescription("Adding untracked changes...");
var succ = new Commands.Add(_repo.FullPath).Exec();
if (succ)
{ {
SetProgressDescription("Stash local changes"); SetProgressDescription("Stash local changes");
succ = new Commands.Stash(_repo.FullPath).Push("CREATE_BRANCH_AUTO_STASH"); var succ = new Commands.Stash(_repo.FullPath).Push("CREATE_BRANCH_AUTO_STASH");
}
if (!succ) if (!succ)
{ {
CallUIThread(() => _repo.SetWatcherEnabled(true)); CallUIThread(() => _repo.SetWatcherEnabled(true));

View file

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Collections;
using Avalonia.Threading; using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
@ -54,11 +54,11 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _detailContext, value); set => SetProperty(ref _detailContext, value);
} }
public FileHistories(string repo, string file) public FileHistories(string repo, string file, AvaloniaList<Models.IssueTrackerRule> issueTrackerRules)
{ {
_repo = repo; _repo = repo;
_file = file; _file = file;
_detailContext = new CommitDetail(repo); _detailContext = new CommitDetail(repo, issueTrackerRules);
Task.Run(() => Task.Run(() =>
{ {

View file

@ -1,7 +1,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Collections;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Platform.Storage; using Avalonia.Platform.Storage;
using Avalonia.VisualTree; using Avalonia.VisualTree;
@ -55,6 +55,11 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _detailContext, value); set => SetProperty(ref _detailContext, value);
} }
public AvaloniaList<Models.IssueTrackerRule> IssueTrackerRules
{
get => _repo.Settings.IssueTrackerRules;
}
public Histories(Repository repo) public Histories(Repository repo)
{ {
_repo = repo; _repo = repo;
@ -94,7 +99,7 @@ namespace SourceGit.ViewModels
} }
else else
{ {
var commitDetail = new CommitDetail(_repo.FullPath); var commitDetail = new CommitDetail(_repo.FullPath, _repo.Settings.IssueTrackerRules);
commitDetail.Commit = commit; commitDetail.Commit = commit;
DetailContext = commitDetail; DetailContext = commitDetail;
} }
@ -122,7 +127,7 @@ namespace SourceGit.ViewModels
} }
else else
{ {
var commitDetail = new CommitDetail(_repo.FullPath); var commitDetail = new CommitDetail(_repo.FullPath, _repo.Settings.IssueTrackerRules);
commitDetail.Commit = commit; commitDetail.Commit = commit;
DetailContext = commitDetail; DetailContext = commitDetail;
} }

View file

@ -114,7 +114,7 @@ namespace SourceGit.ViewModels
Current = current; Current = current;
On = on; On = on;
IsLoading = true; IsLoading = true;
DetailContext = new CommitDetail(repoPath); DetailContext = new CommitDetail(repoPath, repo.Settings.IssueTrackerRules);
Task.Run(() => Task.Run(() =>
{ {

View file

@ -177,6 +177,12 @@ namespace SourceGit.ViewModels
set; set;
} = string.Empty; } = string.Empty;
public bool ShowTagsAsTree
{
get => _showTagsAsTree;
set => SetProperty(ref _showTagsAsTree, value);
}
public bool UseTwoColumnsLayoutInHistories public bool UseTwoColumnsLayoutInHistories
{ {
get => _useTwoColumnsLayoutInHistories; get => _useTwoColumnsLayoutInHistories;
@ -520,6 +526,7 @@ namespace SourceGit.ViewModels
private bool _useFixedTabWidth = true; private bool _useFixedTabWidth = true;
private bool _check4UpdatesOnStartup = true; private bool _check4UpdatesOnStartup = true;
private bool _showTagsAsTree = false;
private bool _useTwoColumnsLayoutInHistories = false; private bool _useTwoColumnsLayoutInHistories = false;
private bool _displayTimeAsPeriodInHistories = false; private bool _displayTimeAsPeriodInHistories = false;
private bool _useSideBySideDiff = false; private bool _useSideBySideDiff = false;

View file

@ -21,16 +21,7 @@ namespace SourceGit.ViewModels
set set
{ {
if (SetProperty(ref _selectedRemote, value)) if (SetProperty(ref _selectedRemote, value))
{ PostRemoteSelected();
var branches = new List<Models.Branch>();
foreach (var branch in _repo.Branches)
{
if (branch.Remote == value.Name)
branches.Add(branch);
}
RemoteBranches = branches;
SelectedBranch = branches.Count > 0 ? branches[0] : null;
}
} }
} }
@ -80,46 +71,35 @@ namespace SourceGit.ViewModels
{ {
_selectedRemote = repo.Remotes.Find(x => x.Name == specifiedRemoteBranch.Remote); _selectedRemote = repo.Remotes.Find(x => x.Name == specifiedRemoteBranch.Remote);
_selectedBranch = specifiedRemoteBranch; _selectedBranch = specifiedRemoteBranch;
var branches = new List<Models.Branch>();
foreach (var branch in _repo.Branches)
{
if (branch.Remote == specifiedRemoteBranch.Remote)
branches.Add(branch);
}
_remoteBranches = branches;
HasSpecifiedRemoteBranch = true; HasSpecifiedRemoteBranch = true;
} }
else else
{ {
var autoSelectedRemote = null as Models.Remote;
if (!string.IsNullOrEmpty(_current.Upstream)) if (!string.IsNullOrEmpty(_current.Upstream))
{ {
foreach (var branch in repo.Branches) var remoteNameEndIdx = _current.Upstream.IndexOf('/', 13);
if (remoteNameEndIdx > 0)
{ {
if (!branch.IsLocal && _current.Upstream == branch.FullName) var remoteName = _current.Upstream.Substring(13, remoteNameEndIdx - 13);
{ autoSelectedRemote = _repo.Remotes.Find(x => x.Name == remoteName);
_selectedRemote = repo.Remotes.Find(x => x.Name == branch.Remote);
_selectedBranch = branch;
break;
}
} }
} }
_selectedRemote = autoSelectedRemote ?? repo.Remotes[0];
PostRemoteSelected();
HasSpecifiedRemoteBranch = false; HasSpecifiedRemoteBranch = false;
} }
// Make sure remote is exists.
if (_selectedRemote == null)
{
_selectedRemote = repo.Remotes[0];
_selectedBranch = null;
HasSpecifiedRemoteBranch = false;
}
_remoteBranches = new List<Models.Branch>();
foreach (var branch in _repo.Branches)
{
if (branch.Remote == _selectedRemote.Name)
_remoteBranches.Add(branch);
}
if (_selectedBranch == null && _remoteBranches.Count > 0)
{
_selectedBranch = _remoteBranches[0];
}
View = new Views.Pull() { DataContext = this }; View = new Views.Pull() { DataContext = this };
} }
@ -129,19 +109,14 @@ namespace SourceGit.ViewModels
return Task.Run(() => return Task.Run(() =>
{ {
var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result();
var needPopStash = false; var needPopStash = false;
if (_repo.WorkingCopyChangesCount > 0) if (changes > 0)
{ {
if (PreAction == Models.DealWithLocalChanges.StashAndReaply) if (PreAction == Models.DealWithLocalChanges.StashAndReaply)
{
SetProgressDescription("Adding untracked changes...");
var succ = new Commands.Add(_repo.FullPath).Exec();
if (succ)
{ {
SetProgressDescription("Stash local changes..."); SetProgressDescription("Stash local changes...");
succ = new Commands.Stash(_repo.FullPath).Push("PULL_AUTO_STASH"); var succ = new Commands.Stash(_repo.FullPath).Push("PULL_AUTO_STASH");
}
if (!succ) if (!succ)
{ {
CallUIThread(() => _repo.SetWatcherEnabled(true)); CallUIThread(() => _repo.SetWatcherEnabled(true));
@ -194,6 +169,50 @@ namespace SourceGit.ViewModels
}); });
} }
private void PostRemoteSelected()
{
var remoteName = _selectedRemote.Name;
var branches = new List<Models.Branch>();
foreach (var branch in _repo.Branches)
{
if (branch.Remote == remoteName)
branches.Add(branch);
}
RemoteBranches = branches;
var autoSelectedBranch = false;
if (!string.IsNullOrEmpty(_current.Upstream) &&
_current.Upstream.StartsWith($"refs/remotes/{remoteName}/", System.StringComparison.Ordinal))
{
foreach (var branch in branches)
{
if (_current.Upstream == branch.FullName)
{
SelectedBranch = branch;
autoSelectedBranch = true;
break;
}
}
}
if (!autoSelectedBranch)
{
foreach (var branch in branches)
{
if (_current.Name == branch.Name)
{
SelectedBranch = branch;
autoSelectedBranch = true;
break;
}
}
}
if (!autoSelectedBranch)
SelectedBranch = branches.Count > 0 ? branches[0] : null;
}
private readonly Repository _repo = null; private readonly Repository _repo = null;
private readonly Models.Branch _current = null; private readonly Models.Branch _current = null;
private Models.Remote _selectedRemote = null; private Models.Remote _selectedRemote = null;

View file

@ -49,9 +49,9 @@ namespace SourceGit.ViewModels
return Task.Run(() => return Task.Run(() =>
{ {
var succ = new Commands.Rebase(_repo.FullPath, _revision, AutoStash).Exec(); new Commands.Rebase(_repo.FullPath, _revision, AutoStash).Exec();
CallUIThread(() => _repo.SetWatcherEnabled(true)); CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ; return true;
}); });
} }

View file

@ -136,7 +136,7 @@ namespace SourceGit.ViewModels
private set => SetProperty(ref _visibleTags, value); private set => SetProperty(ref _visibleTags, value);
} }
public List<string> Submodules public List<Models.Submodule> Submodules
{ {
get => _submodules; get => _submodules;
private set => SetProperty(ref _submodules, value); private set => SetProperty(ref _submodules, value);
@ -746,23 +746,11 @@ namespace SourceGit.ViewModels
} }
else else
{ {
limits += "--branches --remotes --tags"; limits += "--exclude=refs/stash --all";
}
var canPushCommits = new HashSet<string>();
var canPullCommits = new HashSet<string>();
var currentBranch = _branches.Find(x => x.IsCurrent);
if (currentBranch != null)
{
foreach (var sha in currentBranch.TrackStatus.Ahead)
canPushCommits.Add(sha);
foreach (var sha in currentBranch.TrackStatus.Behind)
canPullCommits.Add(sha);
} }
var commits = new Commands.QueryCommits(_fullpath, limits).Result(); var commits = new Commands.QueryCommits(_fullpath, limits).Result();
var graph = Models.CommitGraph.Parse(commits, canPushCommits, canPullCommits); var graph = Models.CommitGraph.Parse(commits);
Dispatcher.UIThread.Invoke(() => Dispatcher.UIThread.Invoke(() =>
{ {
@ -778,6 +766,9 @@ namespace SourceGit.ViewModels
public void RefreshSubmodules() public void RefreshSubmodules()
{ {
var submodules = new Commands.QuerySubmodules(_fullpath).Result(); var submodules = new Commands.QuerySubmodules(_fullpath).Result();
if (_watcher != null)
_watcher.SetSubmodules(submodules);
Dispatcher.UIThread.Invoke(() => Submodules = submodules); Dispatcher.UIThread.Invoke(() => Submodules = submodules);
} }
@ -1992,7 +1983,7 @@ namespace SourceGit.ViewModels
private List<Models.Worktree> _worktrees = new List<Models.Worktree>(); private List<Models.Worktree> _worktrees = new List<Models.Worktree>();
private List<Models.Tag> _tags = new List<Models.Tag>(); private List<Models.Tag> _tags = new List<Models.Tag>();
private List<Models.Tag> _visibleTags = new List<Models.Tag>(); private List<Models.Tag> _visibleTags = new List<Models.Tag>();
private List<string> _submodules = new List<string>(); private List<Models.Submodule> _submodules = new List<Models.Submodule>();
private bool _includeUntracked = true; private bool _includeUntracked = true;
private InProgressContext _inProgressContext = null; private InProgressContext _inProgressContext = null;

View file

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Collections;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels namespace SourceGit.ViewModels
@ -41,6 +42,17 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _httpProxy, value); set => SetProperty(ref _httpProxy, value);
} }
public AvaloniaList<Models.IssueTrackerRule> IssueTrackerRules
{
get => _repo.Settings.IssueTrackerRules;
}
public Models.IssueTrackerRule SelectedIssueTrackerRule
{
get => _selectedIssueTrackerRule;
set => SetProperty(ref _selectedIssueTrackerRule, value);
}
public RepositoryConfigure(Repository repo) public RepositoryConfigure(Repository repo)
{ {
_repo = repo; _repo = repo;
@ -65,6 +77,39 @@ namespace SourceGit.ViewModels
HttpProxy = string.Empty; HttpProxy = string.Empty;
} }
public void AddSampleGithubIssueTracker()
{
foreach (var remote in _repo.Remotes)
{
if (remote.URL.Contains("github.com", System.StringComparison.Ordinal))
{
if (remote.TryGetVisitURL(out string url))
{
SelectedIssueTrackerRule = _repo.Settings.AddGithubIssueTracker(url);
return;
}
}
}
SelectedIssueTrackerRule = _repo.Settings.AddGithubIssueTracker(null);
}
public void AddSampleJiraIssueTracker()
{
SelectedIssueTrackerRule = _repo.Settings.AddJiraIssueTracker();
}
public void NewIssueTracker()
{
SelectedIssueTrackerRule = _repo.Settings.AddNewIssueTracker();
}
public void RemoveSelectedIssueTracker()
{
_repo.Settings.RemoveIssueTracker(_selectedIssueTrackerRule);
SelectedIssueTrackerRule = null;
}
public void Save() public void Save()
{ {
SetIfChanged("user.name", UserName); SetIfChanged("user.name", UserName);
@ -96,5 +141,6 @@ namespace SourceGit.ViewModels
private readonly Repository _repo = null; private readonly Repository _repo = null;
private readonly Dictionary<string, string> _cached = null; private readonly Dictionary<string, string> _cached = null;
private string _httpProxy; private string _httpProxy;
private Models.IssueTrackerRule _selectedIssueTrackerRule = null;
} }
} }

View file

@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using Avalonia.Collections;
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
{
public class TagTreeNode : ObservableObject
{
public string FullPath { get; set; }
public int Depth { get; private set; } = 0;
public Models.Tag Tag { get; private set; } = null;
public List<TagTreeNode> Children { get; private set; } = [];
public bool IsFolder
{
get => Tag == null;
}
public bool IsFiltered
{
get => Tag?.IsFiltered ?? false;
set
{
if (Tag != null)
Tag.IsFiltered = value;
}
}
public bool IsExpanded
{
get => _isExpanded;
set => SetProperty(ref _isExpanded, value);
}
public TagTreeNode(Models.Tag t, int depth)
{
FullPath = t.Name;
Depth = depth;
Tag = t;
IsExpanded = false;
}
public TagTreeNode(string path, bool isExpanded, int depth)
{
FullPath = path;
Depth = depth;
IsExpanded = isExpanded;
}
public static List<TagTreeNode> Build(IList<Models.Tag> tags, HashSet<string> expaneded)
{
var nodes = new List<TagTreeNode>();
var folders = new Dictionary<string, TagTreeNode>();
foreach (var tag in tags)
{
var sepIdx = tag.Name.IndexOf('/', StringComparison.Ordinal);
if (sepIdx == -1)
{
nodes.Add(new TagTreeNode(tag, 0));
}
else
{
TagTreeNode lastFolder = null;
int depth = 0;
while (sepIdx != -1)
{
var folder = tag.Name.Substring(0, sepIdx);
if (folders.TryGetValue(folder, out var value))
{
lastFolder = value;
}
else if (lastFolder == null)
{
lastFolder = new TagTreeNode(folder, expaneded.Contains(folder), depth);
folders.Add(folder, lastFolder);
InsertFolder(nodes, lastFolder);
}
else
{
var cur = new TagTreeNode(folder, expaneded.Contains(folder), depth);
folders.Add(folder, cur);
InsertFolder(lastFolder.Children, cur);
lastFolder = cur;
}
depth++;
sepIdx = tag.Name.IndexOf('/', sepIdx + 1);
}
lastFolder?.Children.Add(new TagTreeNode(tag, depth));
}
}
folders.Clear();
return nodes;
}
private static void InsertFolder(List<TagTreeNode> collection, TagTreeNode subFolder)
{
for (int i = 0; i < collection.Count; i++)
{
if (!collection[i].IsFolder)
{
collection.Insert(i, subFolder);
return;
}
}
collection.Add(subFolder);
}
private bool _isExpanded = true;
}
public class TagCollectionAsList
{
public AvaloniaList<Models.Tag> Tags
{
get;
set;
} = [];
}
public class TagCollectionAsTree
{
public List<TagTreeNode> Tree
{
get;
set;
} = [];
public AvaloniaList<TagTreeNode> Rows
{
get;
set;
} = [];
}
}

View file

@ -7,8 +7,9 @@ namespace SourceGit.ViewModels
{ {
public List<string> Submodules public List<string> Submodules
{ {
get => _repo.Submodules; get;
} private set;
} = new List<string>();
public string SelectedSubmodule public string SelectedSubmodule
{ {
@ -43,7 +44,11 @@ namespace SourceGit.ViewModels
public UpdateSubmodules(Repository repo) public UpdateSubmodules(Repository repo)
{ {
_repo = repo; _repo = repo;
SelectedSubmodule = repo.Submodules.Count > 0 ? repo.Submodules[0] : string.Empty;
foreach (var submodule in _repo.Submodules)
Submodules.Add(submodule.Path);
SelectedSubmodule = Submodules.Count > 0 ? Submodules[0] : string.Empty;
View = new Views.UpdateSubmodules() { DataContext = this }; View = new Views.UpdateSubmodules() { DataContext = this };
} }

View file

@ -135,7 +135,7 @@ namespace SourceGit.ViewModels
if (value == null || value.Count == 0) if (value == null || value.Count == 0)
{ {
if (_selectedStaged == null || _selectedStaged.Count == 0) if (_selectedStaged == null || _selectedStaged.Count == 0)
SetDetail(null); SetDetail(null, true);
} }
else else
{ {
@ -143,9 +143,9 @@ namespace SourceGit.ViewModels
SelectedStaged = []; SelectedStaged = [];
if (value.Count == 1) if (value.Count == 1)
SetDetail(value[0]); SetDetail(value[0], true);
else else
SetDetail(null); SetDetail(null, true);
} }
} }
} }
@ -161,7 +161,7 @@ namespace SourceGit.ViewModels
if (value == null || value.Count == 0) if (value == null || value.Count == 0)
{ {
if (_selectedUnstaged == null || _selectedUnstaged.Count == 0) if (_selectedUnstaged == null || _selectedUnstaged.Count == 0)
SetDetail(null); SetDetail(null, false);
} }
else else
{ {
@ -169,9 +169,9 @@ namespace SourceGit.ViewModels
SelectedUnstaged = []; SelectedUnstaged = [];
if (value.Count == 1) if (value.Count == 1)
SetDetail(value[0]); SetDetail(value[0], false);
else else
SetDetail(null); SetDetail(null, false);
} }
} }
} }
@ -218,7 +218,24 @@ namespace SourceGit.ViewModels
public bool SetData(List<Models.Change> changes) public bool SetData(List<Models.Change> changes)
{ {
if (!IsChanged(_cached, changes))
{
// Just force refresh selected changes.
Dispatcher.UIThread.Invoke(() =>
{
if (_selectedUnstaged.Count == 1)
SetDetail(_selectedUnstaged[0], true);
else if (_selectedStaged.Count == 1)
SetDetail(_selectedStaged[0], false);
else
SetDetail(null, false);
});
return _cached.Find(x => x.IsConflit) != null;
}
_cached = changes; _cached = changes;
_count = _cached.Count;
var unstaged = new List<Models.Change>(); var unstaged = new List<Models.Change>();
var staged = new List<Models.Change>(); var staged = new List<Models.Change>();
@ -227,12 +244,12 @@ namespace SourceGit.ViewModels
var lastSelectedUnstaged = new HashSet<string>(); var lastSelectedUnstaged = new HashSet<string>();
var lastSelectedStaged = new HashSet<string>(); var lastSelectedStaged = new HashSet<string>();
if (_selectedUnstaged != null) if (_selectedUnstaged != null && _selectedUnstaged.Count > 0)
{ {
foreach (var c in _selectedUnstaged) foreach (var c in _selectedUnstaged)
lastSelectedUnstaged.Add(c.Path); lastSelectedUnstaged.Add(c.Path);
} }
else if (_selectedStaged != null) else if (_selectedStaged != null && _selectedStaged.Count > 0)
{ {
foreach (var c in _selectedStaged) foreach (var c in _selectedStaged)
lastSelectedStaged.Add(c.Path); lastSelectedStaged.Add(c.Path);
@ -258,21 +275,21 @@ namespace SourceGit.ViewModels
selectedStaged.Add(c); selectedStaged.Add(c);
} }
_count = changes.Count;
Dispatcher.UIThread.Invoke(() => Dispatcher.UIThread.Invoke(() =>
{ {
_isLoadingData = true; _isLoadingData = true;
Unstaged = unstaged; Unstaged = unstaged;
Staged = staged; Staged = staged;
SelectedUnstaged = selectedUnstaged;
SelectedStaged = selectedStaged;
_isLoadingData = false; _isLoadingData = false;
if (selectedUnstaged.Count > 0) if (selectedUnstaged.Count == 1)
SelectedUnstaged = selectedUnstaged; SetDetail(selectedUnstaged[0], true);
else if (selectedStaged.Count > 0) else if (selectedStaged.Count == 1)
SelectedStaged = selectedStaged; SetDetail(selectedStaged[0], false);
else else
SetDetail(null); SetDetail(null, false);
// Try to load merge message from MERGE_MSG // Try to load merge message from MERGE_MSG
if (string.IsNullOrEmpty(_commitMessage)) if (string.IsNullOrEmpty(_commitMessage))
@ -317,7 +334,6 @@ namespace SourceGit.ViewModels
if (_unstaged.Count == 0 || changes.Count == 0) if (_unstaged.Count == 0 || changes.Count == 0)
return; return;
SetDetail(null);
IsStaging = true; IsStaging = true;
_repo.SetWatcherEnabled(false); _repo.SetWatcherEnabled(false);
if (changes.Count == _unstaged.Count) if (changes.Count == _unstaged.Count)
@ -355,7 +371,6 @@ namespace SourceGit.ViewModels
if (_staged.Count == 0 || changes.Count == 0) if (_staged.Count == 0 || changes.Count == 0)
return; return;
SetDetail(null);
IsUnstaging = true; IsUnstaging = true;
_repo.SetWatcherEnabled(false); _repo.SetWatcherEnabled(false);
if (_useAmend) if (_useAmend)
@ -541,7 +556,7 @@ namespace SourceGit.ViewModels
history.Icon = App.CreateMenuIcon("Icons.Histories"); history.Icon = App.CreateMenuIcon("Icons.Histories");
history.Click += (_, e) => history.Click += (_, e) =>
{ {
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo.FullPath, change.Path) }; var window = new Views.FileHistories() { DataContext = new FileHistories(_repo.FullPath, change.Path, _repo.Settings.IssueTrackerRules) };
window.Show(); window.Show();
e.Handled = true; e.Handled = true;
}; };
@ -1155,12 +1170,11 @@ namespace SourceGit.ViewModels
} }
} }
private void SetDetail(Models.Change change) private void SetDetail(Models.Change change, bool isUnstaged)
{ {
if (_isLoadingData) if (_isLoadingData)
return; return;
var isUnstaged = _selectedUnstaged != null && _selectedUnstaged.Count > 0;
if (change == null) if (change == null)
DetailContext = null; DetailContext = null;
else if (change.IsConflit && isUnstaged) else if (change.IsConflit && isUnstaged)
@ -1225,28 +1239,34 @@ namespace SourceGit.ViewModels
return; return;
} }
if (_count == 0)
{
App.RaiseException(_repo.FullPath, "No files added to commit!");
return;
}
if (!AutoStageBeforeCommit && _staged.Count == 0)
{
App.RaiseException(_repo.FullPath, "No files added to commit!");
return;
}
if (string.IsNullOrWhiteSpace(_commitMessage)) if (string.IsNullOrWhiteSpace(_commitMessage))
{ {
App.RaiseException(_repo.FullPath, "Commit without message is NOT allowed!"); App.RaiseException(_repo.FullPath, "Commit without message is NOT allowed!");
return; return;
} }
_repo.Settings.PushCommitMessage(_commitMessage); if (!_useAmend)
{
if (AutoStageBeforeCommit)
{
if (_count == 0)
{
App.RaiseException(_repo.FullPath, "No files added to commit!");
return;
}
}
else
{
if (_staged.Count == 0)
{
App.RaiseException(_repo.FullPath, "No files added to commit!");
return;
}
}
}
SetDetail(null);
IsCommitting = true; IsCommitting = true;
_repo.Settings.PushCommitMessage(_commitMessage);
_repo.SetWatcherEnabled(false); _repo.SetWatcherEnabled(false);
var autoStage = AutoStageBeforeCommit; var autoStage = AutoStageBeforeCommit;
@ -1257,6 +1277,7 @@ namespace SourceGit.ViewModels
{ {
if (succ) if (succ)
{ {
SelectedStaged = [];
CommitMessage = string.Empty; CommitMessage = string.Empty;
UseAmend = false; UseAmend = false;
@ -1273,6 +1294,24 @@ namespace SourceGit.ViewModels
}); });
} }
private bool IsChanged(List<Models.Change> old, List<Models.Change> cur)
{
if (old.Count != cur.Count)
return true;
var oldSet = new HashSet<string>();
foreach (var c in old)
oldSet.Add($"{c.Path}\n{c.WorkTree}\n{c.Index}");
foreach (var c in cur)
{
if (!oldSet.Contains($"{c.Path}\n{c.WorkTree}\n{c.Index}"))
return true;
}
return false;
}
private Repository _repo = null; private Repository _repo = null;
private bool _isLoadingData = false; private bool _isLoadingData = false;
private bool _isStaging = false; private bool _isStaging = false;

View file

@ -39,10 +39,7 @@ namespace SourceGit.Views
refetch.Click += (_, _) => refetch.Click += (_, _) =>
{ {
if (User != null) if (User != null)
{
Models.AvatarManager.Request(User.Email, true); Models.AvatarManager.Request(User.Email, true);
InvalidateVisual();
}
}; };
ContextMenu = new ContextMenu(); ContextMenu = new ContextMenu();

View file

@ -24,9 +24,7 @@
Background="{DynamicResource Brush.TitleBar}" Background="{DynamicResource Brush.TitleBar}"
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border2}"
DoubleTapped="MaximizeOrRestoreWindow" DoubleTapped="MaximizeOrRestoreWindow"
PointerPressed="BeginMoveWindow" PointerPressed="BeginMoveWindow"/>
PointerMoved="MoveWindow"
PointerReleased="EndMoveWindow"/>
<!-- Caption Buttons (macOS) --> <!-- Caption Buttons (macOS) -->
<Border Grid.Column="0" IsVisible="{OnPlatform False, macOS=True}"> <Border Grid.Column="0" IsVisible="{OnPlatform False, macOS=True}">

View file

@ -330,8 +330,6 @@ namespace SourceGit.Views
private void MaximizeOrRestoreWindow(object _, TappedEventArgs e) private void MaximizeOrRestoreWindow(object _, TappedEventArgs e)
{ {
_pressedTitleBar = false;
if (WindowState == WindowState.Maximized) if (WindowState == WindowState.Maximized)
WindowState = WindowState.Normal; WindowState = WindowState.Normal;
else else
@ -342,34 +340,10 @@ namespace SourceGit.Views
private void BeginMoveWindow(object _, PointerPressedEventArgs e) private void BeginMoveWindow(object _, PointerPressedEventArgs e)
{ {
if (e.ClickCount != 2) if (e.ClickCount == 1)
_pressedTitleBar = true; BeginMoveDrag(e);
}
private void MoveWindow(object _, PointerEventArgs e) e.Handled = true;
{
if (!_pressedTitleBar || e.Source == null)
return;
var visual = (Visual)e.Source;
if (visual == null)
return;
#pragma warning disable CS0618
BeginMoveDrag(new PointerPressedEventArgs(
e.Source,
e.Pointer,
visual,
e.GetPosition(visual),
e.Timestamp,
new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.LeftButtonPressed),
e.KeyModifiers));
#pragma warning restore CS0618
}
private void EndMoveWindow(object _1, PointerReleasedEventArgs _2)
{
_pressedTitleBar = false;
} }
protected override void OnClosed(EventArgs e) protected override void OnClosed(EventArgs e)
@ -377,7 +351,5 @@ namespace SourceGit.Views
base.OnClosed(e); base.OnClosed(e);
GC.Collect(); GC.Collect();
} }
private bool _pressedTitleBar = false;
} }
} }

View file

@ -26,9 +26,7 @@
Background="{DynamicResource Brush.TitleBar}" Background="{DynamicResource Brush.TitleBar}"
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border2}"
DoubleTapped="MaximizeOrRestoreWindow" DoubleTapped="MaximizeOrRestoreWindow"
PointerPressed="BeginMoveWindow" PointerPressed="BeginMoveWindow"/>
PointerMoved="MoveWindow"
PointerReleased="EndMoveWindow"/>
<!-- Caption Buttons (macOS) --> <!-- Caption Buttons (macOS) -->
<Border Grid.Column="0" IsVisible="{OnPlatform False, macOS=True}"> <Border Grid.Column="0" IsVisible="{OnPlatform False, macOS=True}">

View file

@ -1,4 +1,3 @@
using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
@ -13,8 +12,6 @@ namespace SourceGit.Views
private void MaximizeOrRestoreWindow(object _, TappedEventArgs e) private void MaximizeOrRestoreWindow(object _, TappedEventArgs e)
{ {
_pressedTitleBar = false;
if (WindowState == WindowState.Maximized) if (WindowState == WindowState.Maximized)
WindowState = WindowState.Normal; WindowState = WindowState.Normal;
else else
@ -25,34 +22,10 @@ namespace SourceGit.Views
private void BeginMoveWindow(object _, PointerPressedEventArgs e) private void BeginMoveWindow(object _, PointerPressedEventArgs e)
{ {
if (e.ClickCount != 2) if (e.ClickCount == 1)
_pressedTitleBar = true; BeginMoveDrag(e);
}
private void MoveWindow(object _, PointerEventArgs e) e.Handled = true;
{
if (!_pressedTitleBar || e.Source == null)
return;
var visual = (Visual)e.Source;
if (visual == null)
return;
#pragma warning disable CS0618
BeginMoveDrag(new PointerPressedEventArgs(
e.Source,
e.Pointer,
visual,
e.GetPosition(visual),
e.Timestamp,
new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.LeftButtonPressed),
e.KeyModifiers));
#pragma warning restore CS0618
}
private void EndMoveWindow(object _1, PointerReleasedEventArgs _2)
{
_pressedTitleBar = false;
} }
private void OnChangeContextRequested(object sender, ContextRequestedEventArgs e) private void OnChangeContextRequested(object sender, ContextRequestedEventArgs e)
@ -73,7 +46,5 @@ namespace SourceGit.Views
e.Handled = true; e.Handled = true;
} }
private bool _pressedTitleBar = false;
} }
} }

View file

@ -23,6 +23,7 @@
<DataGrid.Styles> <DataGrid.Styles>
<Style Selector="DataGridRow" x:DataType="vm:BranchTreeNode"> <Style Selector="DataGridRow" x:DataType="vm:BranchTreeNode">
<Setter Property="CornerRadius" Value="{Binding CornerRadius}" /> <Setter Property="CornerRadius" Value="{Binding CornerRadius}" />
<Setter Property="Height" Value="24"/>
</Style> </Style>
<Style Selector="DataGridRow /template/ Border#RowBorder"> <Style Selector="DataGridRow /template/ Border#RowBorder">

View file

@ -11,31 +11,31 @@ namespace SourceGit.Views
InitializeComponent(); InitializeComponent();
} }
private void MinimizeWindow(object _1, RoutedEventArgs _2) private void MinimizeWindow(object _, RoutedEventArgs e)
{ {
var window = this.FindAncestorOfType<Window>(); var window = this.FindAncestorOfType<Window>();
if (window != null) if (window != null)
{
window.WindowState = WindowState.Minimized; window.WindowState = WindowState.Minimized;
}
e.Handled = true;
} }
private void MaximizeOrRestoreWindow(object _1, RoutedEventArgs _2) private void MaximizeOrRestoreWindow(object _, RoutedEventArgs e)
{ {
var window = this.FindAncestorOfType<Window>(); var window = this.FindAncestorOfType<Window>();
if (window != null) if (window != null)
{
window.WindowState = window.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; window.WindowState = window.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
}
e.Handled = true;
} }
private void CloseWindow(object _1, RoutedEventArgs _2) private void CloseWindow(object _, RoutedEventArgs e)
{ {
var window = this.FindAncestorOfType<Window>(); var window = this.FindAncestorOfType<Window>();
if (window != null) if (window != null)
{
window.Close(); window.Close();
}
e.Handled = true;
} }
} }
} }

View file

@ -11,31 +11,31 @@ namespace SourceGit.Views
InitializeComponent(); InitializeComponent();
} }
private void MinimizeWindow(object _1, RoutedEventArgs _2) private void MinimizeWindow(object _, RoutedEventArgs e)
{ {
var window = this.FindAncestorOfType<Window>(); var window = this.FindAncestorOfType<Window>();
if (window != null) if (window != null)
{
window.WindowState = WindowState.Minimized; window.WindowState = WindowState.Minimized;
}
e.Handled = true;
} }
private void MaximizeOrRestoreWindow(object _1, RoutedEventArgs _2) private void MaximizeOrRestoreWindow(object _, RoutedEventArgs e)
{ {
var window = this.FindAncestorOfType<Window>(); var window = this.FindAncestorOfType<Window>();
if (window != null) if (window != null)
{
window.WindowState = window.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; window.WindowState = window.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
}
e.Handled = true;
} }
private void CloseWindow(object _1, RoutedEventArgs _2) private void CloseWindow(object _, RoutedEventArgs e)
{ {
var window = this.FindAncestorOfType<Window>(); var window = this.FindAncestorOfType<Window>();
if (window != null) if (window != null)
{
window.Close(); window.Close();
}
e.Handled = true;
} }
} }
} }

View file

@ -26,9 +26,8 @@
<TextBlock Grid.Row="1" Grid.Column="0" <TextBlock Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center" HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0" Margin="0,0,8,0"
Text="{DynamicResource Text.Checkout.LocalChanges}" Text="{DynamicResource Text.Checkout.LocalChanges}"/>
IsVisible="{Binding HasLocalChanges}"/> <StackPanel Grid.Row="1" Grid.Column="1" Height="32" Orientation="Horizontal">
<StackPanel Grid.Row="1" Grid.Column="1" Height="32" Orientation="Horizontal" IsVisible="{Binding HasLocalChanges}">
<RadioButton Content="{DynamicResource Text.Checkout.LocalChanges.StashAndReply}" <RadioButton Content="{DynamicResource Text.Checkout.LocalChanges.StashAndReply}"
GroupName="LocalChanges" GroupName="LocalChanges"
IsChecked="{Binding AutoStash, Mode=TwoWay}" /> IsChecked="{Binding AutoStash, Mode=TwoWay}" />

View file

@ -92,7 +92,12 @@
<!-- Messages --> <!-- Messages -->
<TextBlock Grid.Row="3" Grid.Column="0" Classes="info_label" Text="{DynamicResource Text.CommitDetail.Info.Message}" VerticalAlignment="Top" Margin="0,4,0,0" /> <TextBlock Grid.Row="3" Grid.Column="0" Classes="info_label" Text="{DynamicResource Text.CommitDetail.Info.Message}" VerticalAlignment="Top" Margin="0,4,0,0" />
<SelectableTextBlock Grid.Row="3" Grid.Column="1" Margin="12,5,8,0" Classes="primary" Text="{Binding #ThisControl.Message}" TextWrapping="Wrap"/> <v:CommitMessagePresenter Grid.Row="3" Grid.Column="1"
Margin="12,5,8,0"
Classes="primary"
Message="{Binding #ThisControl.Message}"
IssueTrackerRules="{Binding #ThisControl.IssueTrackerRules}"
TextWrapping="Wrap"/>
</Grid> </Grid>
</StackPanel> </StackPanel>
</DataTemplate> </DataTemplate>

View file

@ -1,4 +1,5 @@
using Avalonia; using Avalonia;
using Avalonia.Collections;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
@ -24,6 +25,15 @@ namespace SourceGit.Views
set => SetValue(MessageProperty, value); set => SetValue(MessageProperty, value);
} }
public static readonly StyledProperty<AvaloniaList<Models.IssueTrackerRule>> IssueTrackerRulesProperty =
AvaloniaProperty.Register<CommitBaseInfo, AvaloniaList<Models.IssueTrackerRule>>(nameof(IssueTrackerRules));
public AvaloniaList<Models.IssueTrackerRule> IssueTrackerRules
{
get => GetValue(IssueTrackerRulesProperty);
set => SetValue(IssueTrackerRulesProperty, value);
}
public CommitBaseInfo() public CommitBaseInfo()
{ {
InitializeComponent(); InitializeComponent();

View file

@ -19,7 +19,9 @@
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"> <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<!-- Base Information --> <!-- Base Information -->
<v:CommitBaseInfo Content="{Binding Commit}" Message="{Binding FullMessage}"/> <v:CommitBaseInfo Content="{Binding Commit}"
Message="{Binding FullMessage}"
IssueTrackerRules="{Binding IssueTrackerRules}"/>
<!-- Line --> <!-- Line -->
<Rectangle Height=".65" Margin="8" Fill="{DynamicResource Brush.Border2}"/> <Rectangle Height=".65" Margin="8" Fill="{DynamicResource Brush.Border2}"/>

View file

@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using Avalonia;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Documents;
using Avalonia.Input;
namespace SourceGit.Views
{
public class CommitMessagePresenter : SelectableTextBlock
{
public static readonly StyledProperty<string> MessageProperty =
AvaloniaProperty.Register<CommitMessagePresenter, string>(nameof(Message));
public string Message
{
get => GetValue(MessageProperty);
set => SetValue(MessageProperty, value);
}
public static readonly StyledProperty<AvaloniaList<Models.IssueTrackerRule>> IssueTrackerRulesProperty =
AvaloniaProperty.Register<CommitMessagePresenter, AvaloniaList<Models.IssueTrackerRule>>(nameof(IssueTrackerRules));
public AvaloniaList<Models.IssueTrackerRule> IssueTrackerRules
{
get => GetValue(IssueTrackerRulesProperty);
set => SetValue(IssueTrackerRulesProperty, value);
}
protected override Type StyleKeyOverride => typeof(SelectableTextBlock);
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == MessageProperty || change.Property == IssueTrackerRulesProperty)
{
Inlines.Clear();
var message = Message;
if (string.IsNullOrEmpty(message))
return;
var rules = IssueTrackerRules;
if (rules == null || rules.Count == 0)
{
Inlines.Add(new Run(message));
return;
}
var matches = new List<Models.IssueTrackerMatch>();
foreach (var rule in rules)
rule.Matches(matches, message);
if (matches.Count == 0)
{
Inlines.Add(new Run(message));
return;
}
matches.Sort((l, r) => l.Start - r.Start);
int pos = 0;
foreach (var match in matches)
{
if (match.Start > pos)
Inlines.Add(new Run(message.Substring(pos, match.Start - pos)));
var link = new TextBlock();
link.SetValue(TextProperty, message.Substring(match.Start, match.Length));
link.SetValue(ToolTip.TipProperty, match.URL);
link.Classes.Add("issue_link");
link.PointerPressed += OnLinkPointerPressed;
Inlines.Add(link);
pos = match.Start + match.Length;
}
if (pos < message.Length)
Inlines.Add(new Run(message.Substring(pos)));
}
}
private void OnLinkPointerPressed(object sender, PointerPressedEventArgs e)
{
if (sender is TextBlock text)
{
var tooltip = text.GetValue(ToolTip.TipProperty) as string;
if (!string.IsNullOrEmpty(tooltip))
Native.OS.OpenBrowser(tooltip);
e.Handled = true;
}
}
}
}

View file

@ -158,7 +158,7 @@ namespace SourceGit.Views
IsTag = decorator.Type == Models.DecoratorType.Tag, IsTag = decorator.Type == Models.DecoratorType.Tag,
}; };
var geo = null as StreamGeometry; StreamGeometry geo;
switch (decorator.Type) switch (decorator.Type)
{ {
case Models.DecoratorType.CurrentBranchHead: case Models.DecoratorType.CurrentBranchHead:
@ -176,7 +176,7 @@ namespace SourceGit.Views
break; break;
} }
var drawGeo = geo.Clone(); var drawGeo = geo!.Clone();
var iconBounds = drawGeo.Bounds; var iconBounds = drawGeo.Bounds;
var translation = Matrix.CreateTranslation(-(Vector)iconBounds.Position); var translation = Matrix.CreateTranslation(-(Vector)iconBounds.Position);
var scale = Math.Min(8.0 / iconBounds.Width, 8.0 / iconBounds.Height); var scale = Math.Min(8.0 / iconBounds.Width, 8.0 / iconBounds.Height);

View file

@ -26,9 +26,7 @@
Background="{DynamicResource Brush.TitleBar}" Background="{DynamicResource Brush.TitleBar}"
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"
DoubleTapped="MaximizeOrRestoreWindow" DoubleTapped="MaximizeOrRestoreWindow"
PointerPressed="BeginMoveWindow" PointerPressed="BeginMoveWindow"/>
PointerMoved="MoveWindow"
PointerReleased="EndMoveWindow"/>
<!-- Caption Buttons (macOS) --> <!-- Caption Buttons (macOS) -->
<Border Grid.Column="0" IsVisible="{OnPlatform False, macOS=True}"> <Border Grid.Column="0" IsVisible="{OnPlatform False, macOS=True}">

View file

@ -1,4 +1,3 @@
using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
@ -13,8 +12,6 @@ namespace SourceGit.Views
private void MaximizeOrRestoreWindow(object _, TappedEventArgs e) private void MaximizeOrRestoreWindow(object _, TappedEventArgs e)
{ {
_pressedTitleBar = false;
if (WindowState == WindowState.Maximized) if (WindowState == WindowState.Maximized)
WindowState = WindowState.Normal; WindowState = WindowState.Normal;
else else
@ -25,36 +22,10 @@ namespace SourceGit.Views
private void BeginMoveWindow(object _, PointerPressedEventArgs e) private void BeginMoveWindow(object _, PointerPressedEventArgs e)
{ {
if (e.ClickCount != 2) if (e.ClickCount == 1)
_pressedTitleBar = true; BeginMoveDrag(e);
}
private void MoveWindow(object _, PointerEventArgs e) e.Handled = true;
{ }
if (!_pressedTitleBar || e.Source == null)
return;
var visual = (Visual)e.Source;
if (visual == null)
return;
#pragma warning disable CS0618
BeginMoveDrag(new PointerPressedEventArgs(
e.Source,
e.Pointer,
visual,
e.GetPosition(visual),
e.Timestamp,
new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.LeftButtonPressed),
e.KeyModifiers));
#pragma warning restore CS0618
}
private void EndMoveWindow(object _1, PointerReleasedEventArgs _2)
{
_pressedTitleBar = false;
}
private bool _pressedTitleBar = false;
} }
} }

View file

@ -27,10 +27,12 @@
ColumnHeaderHeight="24" ColumnHeaderHeight="24"
HorizontalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
ClipboardCopyMode="None"
LayoutUpdated="OnCommitDataGridLayoutUpdated" LayoutUpdated="OnCommitDataGridLayoutUpdated"
SelectionChanged="OnCommitDataGridSelectionChanged" SelectionChanged="OnCommitDataGridSelectionChanged"
ContextRequested="OnCommitDataGridContextRequested" ContextRequested="OnCommitDataGridContextRequested"
DoubleTapped="OnCommitDataGridDoubleTapped"> DoubleTapped="OnCommitDataGridDoubleTapped"
KeyDown="OnCommitDataGridKeyDown">
<DataGrid.Styles> <DataGrid.Styles>
<Style Selector="DataGridColumnHeader"> <Style Selector="DataGridColumnHeader">
<Setter Property="MinHeight" Value="24"/> <Setter Property="MinHeight" Value="24"/>
@ -60,15 +62,10 @@
<DataTemplate x:DataType="{x:Type m:Commit}"> <DataTemplate x:DataType="{x:Type m:Commit}">
<Border Margin="{Binding Margin}"> <Border Margin="{Binding Margin}">
<StackPanel Orientation="Horizontal" Margin="2,0,0,0"> <StackPanel Orientation="Horizontal" Margin="2,0,0,0">
<Ellipse Width="5" Height="5" <v:CommitStatusIndicator CurrentBranch="{Binding $parent[v:Histories].CurrentBranch}"
Margin="0,0,4,0" AheadBrush="{DynamicResource Brush.Accent}"
Fill="{DynamicResource Brush.Accent}" BehindBrush="{DynamicResource Brush.FG1}"
IsVisible="{Binding CanPushToUpstream}"/> VerticalAlignment="Center"/>
<Ellipse Width="5" Height="5"
Margin="0,0,4,0"
Fill="{DynamicResource Brush.FG1}"
IsVisible="{Binding CanPullFromUpstream}"/>
<v:CommitRefsPresenter IsVisible="{Binding HasDecorators}" <v:CommitRefsPresenter IsVisible="{Binding HasDecorators}"
IconBackground="{DynamicResource Brush.DecoratorIconBG}" IconBackground="{DynamicResource Brush.DecoratorIconBG}"
@ -80,8 +77,9 @@
FontSize="10" FontSize="10"
VerticalAlignment="Center"/> VerticalAlignment="Center"/>
<TextBlock Classes="primary" <v:CommitSubjectPresenter Classes="primary"
Text="{Binding Subject}" Subject="{Binding Subject}"
IssueTrackerRules="{Binding $parent[v:Histories].IssueTrackerRules}"
Opacity="{Binding Opacity}" Opacity="{Binding Opacity}"
FontWeight="{Binding FontWeight}"/> FontWeight="{Binding FontWeight}"/>
</StackPanel> </StackPanel>

View file

@ -1,7 +1,11 @@
using System; using System;
using System.Collections.Generic;
using System.Text;
using Avalonia; using Avalonia;
using Avalonia.Collections;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Documents;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
@ -70,6 +74,175 @@ namespace SourceGit.Views
} }
} }
public class CommitStatusIndicator : Control
{
public static readonly StyledProperty<Models.Branch> CurrentBranchProperty =
AvaloniaProperty.Register<CommitStatusIndicator, Models.Branch>(nameof(CurrentBranch));
public Models.Branch CurrentBranch
{
get => GetValue(CurrentBranchProperty);
set => SetValue(CurrentBranchProperty, value);
}
public static readonly StyledProperty<IBrush> AheadBrushProperty =
AvaloniaProperty.Register<CommitStatusIndicator, IBrush>(nameof(AheadBrush));
public IBrush AheadBrush
{
get => GetValue(AheadBrushProperty);
set => SetValue(AheadBrushProperty, value);
}
public static readonly StyledProperty<IBrush> BehindBrushProperty =
AvaloniaProperty.Register<CommitStatusIndicator, IBrush>(nameof(BehindBrush));
public IBrush BehindBrush
{
get => GetValue(BehindBrushProperty);
set => SetValue(BehindBrushProperty, value);
}
enum Status
{
Normal,
Ahead,
Behind,
}
public override void Render(DrawingContext context)
{
if (_status == Status.Normal)
return;
context.DrawEllipse(_status == Status.Ahead ? AheadBrush : BehindBrush, null, new Rect(0, 0, 5, 5));
}
protected override Size MeasureOverride(Size availableSize)
{
if (DataContext is Models.Commit commit && CurrentBranch is not null)
{
var sha = commit.SHA;
var track = CurrentBranch.TrackStatus;
if (track.Ahead.Contains(sha))
_status = Status.Ahead;
else if (track.Behind.Contains(sha))
_status = Status.Behind;
else
_status = Status.Normal;
}
else
{
_status = Status.Normal;
}
return _status == Status.Normal ? new Size(0, 0) : new Size(9, 5);
}
protected override void OnDataContextChanged(EventArgs e)
{
base.OnDataContextChanged(e);
InvalidateMeasure();
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == CurrentBranchProperty)
InvalidateMeasure();
}
private Status _status = Status.Normal;
}
public class CommitSubjectPresenter : TextBlock
{
public static readonly StyledProperty<string> SubjectProperty =
AvaloniaProperty.Register<CommitSubjectPresenter, string>(nameof(Subject));
public string Subject
{
get => GetValue(SubjectProperty);
set => SetValue(SubjectProperty, value);
}
public static readonly StyledProperty<AvaloniaList<Models.IssueTrackerRule>> IssueTrackerRulesProperty =
AvaloniaProperty.Register<CommitSubjectPresenter, AvaloniaList<Models.IssueTrackerRule>>(nameof(IssueTrackerRules));
public AvaloniaList<Models.IssueTrackerRule> IssueTrackerRules
{
get => GetValue(IssueTrackerRulesProperty);
set => SetValue(IssueTrackerRulesProperty, value);
}
protected override Type StyleKeyOverride => typeof(TextBlock);
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == SubjectProperty || change.Property == IssueTrackerRulesProperty)
{
Inlines.Clear();
var subject = Subject;
if (string.IsNullOrEmpty(subject))
return;
var rules = IssueTrackerRules;
if (rules == null || rules.Count == 0)
{
Inlines.Add(new Run(subject));
return;
}
var matches = new List<Models.IssueTrackerMatch>();
foreach (var rule in rules)
rule.Matches(matches, subject);
if (matches.Count == 0)
{
Inlines.Add(new Run(subject));
return;
}
matches.Sort((l, r) => l.Start - r.Start);
int pos = 0;
foreach (var match in matches)
{
if (match.Start > pos)
Inlines.Add(new Run(subject.Substring(pos, match.Start - pos)));
var link = new TextBlock();
link.SetValue(TextProperty, subject.Substring(match.Start, match.Length));
link.SetValue(ToolTip.TipProperty, match.URL);
link.Classes.Add("issue_link");
link.PointerPressed += OnLinkPointerPressed;
Inlines.Add(link);
pos = match.Start + match.Length;
}
if (pos < subject.Length)
Inlines.Add(new Run(subject.Substring(pos)));
}
}
private void OnLinkPointerPressed(object sender, PointerPressedEventArgs e)
{
if (sender is TextBlock text)
{
var tooltip = text.GetValue(ToolTip.TipProperty) as string;
if (!string.IsNullOrEmpty(tooltip))
Native.OS.OpenBrowser(tooltip);
e.Handled = true;
}
}
}
public class CommitTimeTextBlock : TextBlock public class CommitTimeTextBlock : TextBlock
{ {
public static readonly StyledProperty<bool> ShowAsDateTimeProperty = public static readonly StyledProperty<bool> ShowAsDateTimeProperty =
@ -359,6 +532,15 @@ namespace SourceGit.Views
public partial class Histories : UserControl public partial class Histories : UserControl
{ {
public static readonly StyledProperty<Models.Branch> CurrentBranchProperty =
AvaloniaProperty.Register<Histories, Models.Branch>(nameof(CurrentBranch));
public Models.Branch CurrentBranch
{
get => GetValue(CurrentBranchProperty);
set => SetValue(CurrentBranchProperty, value);
}
public static readonly StyledProperty<long> NavigationIdProperty = public static readonly StyledProperty<long> NavigationIdProperty =
AvaloniaProperty.Register<Histories, long>(nameof(NavigationId)); AvaloniaProperty.Register<Histories, long>(nameof(NavigationId));
@ -368,6 +550,16 @@ namespace SourceGit.Views
set => SetValue(NavigationIdProperty, value); set => SetValue(NavigationIdProperty, value);
} }
public AvaloniaList<Models.IssueTrackerRule> IssueTrackerRules
{
get
{
if (DataContext is ViewModels.Histories histories)
return histories.IssueTrackerRules;
return null;
}
}
static Histories() static Histories()
{ {
NavigationIdProperty.Changed.AddClassHandler<Histories>((h, _) => NavigationIdProperty.Changed.AddClassHandler<Histories>((h, _) =>
@ -419,5 +611,24 @@ namespace SourceGit.Views
} }
e.Handled = true; e.Handled = true;
} }
private void OnCommitDataGridKeyDown(object sender, KeyEventArgs e)
{
if (sender is DataGrid grid &&
grid.SelectedItems is { Count: > 0 } selected &&
e.Key == Key.C &&
e.KeyModifiers.HasFlag(KeyModifiers.Control))
{
var builder = new StringBuilder();
foreach (var item in selected)
{
if (item is Models.Commit commit)
builder.AppendLine($"{commit.SHA.Substring(0, 10)} - {commit.Subject}");
}
App.CopyText(builder.ToString());
e.Handled = true;
}
}
} }
} }

View file

@ -73,7 +73,6 @@
CanUserReorderColumns="False" CanUserReorderColumns="False"
CanUserResizeColumns="False" CanUserResizeColumns="False"
CanUserSortColumns="False" CanUserSortColumns="False"
DragDrop.AllowDrop="True"
IsReadOnly="True" IsReadOnly="True"
HeadersVisibility="None" HeadersVisibility="None"
Focusable="False" Focusable="False"
@ -82,6 +81,19 @@
VerticalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
KeyDown="OnDataGridKeyDown"> KeyDown="OnDataGridKeyDown">
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTemplateColumn Width="16" Header="DragHandler">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type vm:InteractiveRebaseItem}">
<Border Background="Transparent"
Margin="4,0,0,0"
Loaded="OnSetupRowHeaderDragDrop"
PointerPressed="OnRowHeaderPointerPressed">
<Path Width="14" Height="14" Data="{StaticResource Icons.Move}" Fill="{DynamicResource Brush.FG2}"/>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Option"> <DataGridTemplateColumn Header="Option">
<DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type vm:InteractiveRebaseItem}"> <DataTemplate x:DataType="{x:Type vm:InteractiveRebaseItem}">

View file

@ -21,6 +21,55 @@ namespace SourceGit.Views
Close(); Close();
} }
private void OnSetupRowHeaderDragDrop(object sender, RoutedEventArgs e)
{
if (sender is Border border)
{
DragDrop.SetAllowDrop(border, true);
border.AddHandler(DragDrop.DragOverEvent, OnRowHeaderDragOver);
}
}
private void OnRowHeaderPointerPressed(object sender, PointerPressedEventArgs e)
{
if (sender is Border border && border.DataContext is ViewModels.InteractiveRebaseItem item)
{
var data = new DataObject();
data.Set("InteractiveRebaseItem", item);
DragDrop.DoDragDrop(e, data, DragDropEffects.Move | DragDropEffects.Copy | DragDropEffects.Link);
}
}
private void OnRowHeaderDragOver(object sender, DragEventArgs e)
{
if (DataContext is ViewModels.InteractiveRebase vm &&
e.Data.Get("InteractiveRebaseItem") is ViewModels.InteractiveRebaseItem src &&
sender is Border { DataContext: ViewModels.InteractiveRebaseItem dst } border &&
src != dst)
{
e.DragEffects = DragDropEffects.Move | DragDropEffects.Copy | DragDropEffects.Link;
var p = e.GetPosition(border);
if (p.Y > border.Bounds.Height * 0.33 && p.Y < border.Bounds.Height * 0.67)
{
var srcIdx = vm.Items.IndexOf(src);
var dstIdx = vm.Items.IndexOf(dst);
if (srcIdx < dstIdx)
{
for (var i = srcIdx; i < dstIdx; i++)
vm.MoveItemDown(src);
}
else
{
for (var i = srcIdx; i > dstIdx; i--)
vm.MoveItemUp(src);
}
}
e.Handled = true;
}
}
private void OnMoveItemUp(object sender, RoutedEventArgs e) private void OnMoveItemUp(object sender, RoutedEventArgs e)
{ {
if (sender is Control control && DataContext is ViewModels.InteractiveRebase vm) if (sender is Control control && DataContext is ViewModels.InteractiveRebase vm)

View file

@ -25,9 +25,7 @@
Background="{DynamicResource Brush.TitleBar}" Background="{DynamicResource Brush.TitleBar}"
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"
DoubleTapped="OnTitleBarDoubleTapped" DoubleTapped="OnTitleBarDoubleTapped"
PointerPressed="BeginMoveWindow" PointerPressed="BeginMoveWindow"/>
PointerMoved="MoveWindow"
PointerReleased="EndMoveWindow"/>
<!-- Caption Buttons (macOS) --> <!-- Caption Buttons (macOS) -->
<Border Grid.Column="0" VerticalAlignment="Stretch" Margin="2,0,8,3" IsVisible="{OnPlatform False, macOS=True}"> <Border Grid.Column="0" VerticalAlignment="Stretch" Margin="2,0,8,3" IsVisible="{OnPlatform False, macOS=True}">

View file

@ -163,8 +163,6 @@ namespace SourceGit.Views
private void OnTitleBarDoubleTapped(object _, TappedEventArgs e) private void OnTitleBarDoubleTapped(object _, TappedEventArgs e)
{ {
_pressedTitleBar = false;
if (WindowState == WindowState.Maximized) if (WindowState == WindowState.Maximized)
WindowState = WindowState.Normal; WindowState = WindowState.Normal;
else else
@ -175,36 +173,10 @@ namespace SourceGit.Views
private void BeginMoveWindow(object _, PointerPressedEventArgs e) private void BeginMoveWindow(object _, PointerPressedEventArgs e)
{ {
if (e.ClickCount != 2) if (e.ClickCount == 1)
_pressedTitleBar = true; BeginMoveDrag(e);
}
private void MoveWindow(object _, PointerEventArgs e) e.Handled = true;
{ }
if (!_pressedTitleBar || e.Source == null)
return;
var visual = (Visual)e.Source;
if (visual == null)
return;
#pragma warning disable CS0618
BeginMoveDrag(new PointerPressedEventArgs(
e.Source,
e.Pointer,
visual,
e.GetPosition(visual),
e.Timestamp,
new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.LeftButtonPressed),
e.KeyModifiers));
#pragma warning restore CS0618
}
private void EndMoveWindow(object _1, PointerReleasedEventArgs _2)
{
_pressedTitleBar = false;
}
private bool _pressedTitleBar = false;
} }
} }

View file

@ -64,16 +64,16 @@
IsHitTestVisible="False"/> IsHitTestVisible="False"/>
<TextBlock Grid.Column="1" <TextBlock Grid.Column="1"
Classes="primary" Classes="primary"
FontSize="12"
HorizontalAlignment="Stretch" VerticalAlignment="Center" HorizontalAlignment="Stretch" VerticalAlignment="Center"
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
TextAlignment="Center" TextAlignment="Center"
Text="{Binding Node.Name}" Text="{Binding Node.Name}"
IsVisible="{Binding Node.IsRepository}" IsVisible="{Binding Node.IsRepository}"
IsHitTestVisible="False"/> IsHitTestVisible="False"/>
<TextBlock Grid.Column="1" <TextBlock Grid.Column="1"
Classes="primary" Classes="primary"
FontSize="12"
HorizontalAlignment="Stretch" VerticalAlignment="Center" HorizontalAlignment="Stretch" VerticalAlignment="Center"
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
TextAlignment="Center" TextAlignment="Center"
Text="{DynamicResource Text.PageTabBar.Welcome.Title}" Text="{DynamicResource Text.PageTabBar.Welcome.Title}"
IsVisible="{Binding !Node.IsRepository}" IsVisible="{Binding !Node.IsRepository}"

View file

@ -211,7 +211,7 @@
HorizontalAlignment="Right" HorizontalAlignment="Right"
Margin="0,0,16,0"/> Margin="0,0,16,0"/>
<NumericUpDown Grid.Row="3" Grid.Column="1" <NumericUpDown Grid.Row="3" Grid.Column="1"
Minimum="10" Maximum="16" Increment="0.5" Minimum="10" Maximum="18" Increment="0.5"
Height="28" Height="28"
Padding="4" Padding="4"
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}"

View file

@ -188,92 +188,35 @@
<!-- Tags --> <!-- Tags -->
<ToggleButton Grid.Row="4" Classes="group_expander" IsChecked="{Binding IsTagGroupExpanded, Mode=TwoWay}"> <ToggleButton Grid.Row="4" Classes="group_expander" IsChecked="{Binding IsTagGroupExpanded, Mode=TwoWay}">
<Grid ColumnDefinitions="Auto,*,Auto"> <Grid ColumnDefinitions="Auto,*,Auto,Auto">
<TextBlock Grid.Column="0" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.Tags}"/> <TextBlock Grid.Column="0" Classes="group_header_label" Margin="0" Text="{DynamicResource Text.Repository.Tags}"/>
<TextBlock Grid.Column="1" Text="{Binding Tags, Converter={x:Static c:ListConverters.ToCount}}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold"/> <TextBlock Grid.Column="1" Text="{Binding Tags, Converter={x:Static c:ListConverters.ToCount}}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold"/>
<Button Grid.Column="2" Classes="icon_button" Width="14" Margin="8,0" Command="{Binding CreateNewTag}" ToolTip.Tip="{DynamicResource Text.Repository.Tags.Add}"> <ToggleButton Grid.Column="2"
Classes="tag_display_mode"
Width="14"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowTagsAsTree, Mode=TwoWay}"
ToolTip.Tip="{DynamicResource Text.Repository.ShowTagsAsTree}"/>
<Button Grid.Column="3"
Classes="icon_button"
Width="14"
Margin="8,0"
Command="{Binding CreateNewTag}"
ToolTip.Tip="{DynamicResource Text.Repository.Tags.Add}">
<Path Width="12" Height="12" Data="{StaticResource Icons.Tag.Add}"/> <Path Width="12" Height="12" Data="{StaticResource Icons.Tag.Add}"/>
</Button> </Button>
</Grid> </Grid>
</ToggleButton> </ToggleButton>
<DataGrid Grid.Row="5" <v:TagsView Grid.Row="5"
x:Name="TagsList" x:Name="TagsList"
Height="0" Height="0"
Margin="8,0,4,0" Margin="8,0,4,0"
Background="Transparent" Background="Transparent"
ItemsSource="{Binding VisibleTags}" ShowTagsAsTree="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowTagsAsTree, Mode=OneWay}"
SelectionMode="Single" Tags="{Binding VisibleTags}"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
CanUserSortColumns="False"
IsReadOnly="True"
HeadersVisibility="None"
Focusable="False" Focusable="False"
RowHeight="24"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto"
IsVisible="{Binding IsTagGroupExpanded, Mode=OneWay}" IsVisible="{Binding IsTagGroupExpanded, Mode=OneWay}"
SelectionChanged="OnTagDataGridSelectionChanged" SelectionChanged="OnTagsSelectionChanged"
ContextRequested="OnTagContextRequested" RowsChanged="OnTagsRowsChanged"/>
PropertyChanged="OnLeftSidebarDataGridPropertyChanged">
<DataGrid.Styles>
<Style Selector="DataGridRow">
<Setter Property="CornerRadius" Value="4" />
</Style>
<Style Selector="DataGridRow /template/ Border#RowBorder">
<Setter Property="ClipToBounds" Value="True" />
</Style>
<Style Selector="Grid.repository_leftpanel DataGridRow:pointerover /template/ Rectangle#BackgroundRectangle">
<Setter Property="Fill" Value="{DynamicResource Brush.AccentHovered}" />
<Setter Property="Opacity" Value=".5"/>
</Style>
<Style Selector="Grid.repository_leftpanel DataGridRow:selected /template/ Rectangle#BackgroundRectangle">
<Setter Property="Fill" Value="{DynamicResource Brush.AccentHovered}" />
<Setter Property="Opacity" Value="1"/>
</Style>
<Style Selector="Grid.repository_leftpanel:focus-within DataGridRow:selected /template/ Rectangle#BackgroundRectangle">
<Setter Property="Fill" Value="{DynamicResource Brush.Accent}" />
<Setter Property="Opacity" Value=".65"/>
</Style>
<Style Selector="Grid.repository_leftpanel:focus-within DataGridRow:selected:pointerover /template/ Rectangle#BackgroundRectangle">
<Setter Property="Fill" Value="{DynamicResource Brush.Accent}" />
<Setter Property="Opacity" Value=".8"/>
</Style>
</DataGrid.Styles>
<DataGrid.Columns>
<DataGridTemplateColumn Header="ICON">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type m:Tag}">
<Path Width="10" Height="10" Margin="8,0" Data="{StaticResource Icons.Tag}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="*" Header="NAME">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type m:Tag}">
<TextBlock Text="{Binding Name}" Classes="primary" TextTrimming="CharacterEllipsis" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="FILTER">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type m:Tag}">
<ToggleButton Classes="filter"
Margin="0,0,8,0"
Background="Transparent"
IsCheckedChanged="OnTagFilterIsCheckedChanged"
IsChecked="{Binding IsFiltered}"
ToolTip.Tip="{DynamicResource Text.Filter}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<!-- Submodules --> <!-- Submodules -->
<ToggleButton Grid.Row="6" Classes="group_expander" IsChecked="{Binding IsSubmoduleGroupExpanded, Mode=TwoWay}"> <ToggleButton Grid.Row="6" Classes="group_expander" IsChecked="{Binding IsSubmoduleGroupExpanded, Mode=TwoWay}">
@ -312,7 +255,7 @@
IsReadOnly="True" IsReadOnly="True"
HeadersVisibility="None" HeadersVisibility="None"
Focusable="False" Focusable="False"
RowHeight="26" RowHeight="24"
HorizontalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
ContextRequested="OnSubmoduleContextRequested" ContextRequested="OnSubmoduleContextRequested"
@ -322,6 +265,7 @@
<DataGrid.Styles> <DataGrid.Styles>
<Style Selector="DataGridRow"> <Style Selector="DataGridRow">
<Setter Property="CornerRadius" Value="4" /> <Setter Property="CornerRadius" Value="4" />
<Setter Property="Height" Value="24"/>
</Style> </Style>
<Style Selector="DataGridRow /template/ Border#RowBorder"> <Style Selector="DataGridRow /template/ Border#RowBorder">
@ -349,9 +293,14 @@
<DataGridTemplateColumn Width="*" Header="NAME"> <DataGridTemplateColumn Width="*" Header="NAME">
<DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellTemplate>
<DataTemplate> <DataTemplate>
<Border Padding="0,0,4,0"> <Grid Background="Transparent" Margin="0,0,4,0" ColumnDefinitions="*,8">
<TextBlock Text="{Binding}" ClipToBounds="True" Classes="primary" TextTrimming="CharacterEllipsis"/> <TextBlock Grid.Column="0" Text="{Binding Path}" ClipToBounds="True" Classes="primary" TextTrimming="CharacterEllipsis"/>
</Border> <Path Grid.Column="1"
Width="8" Height="8"
Fill="Goldenrod"
Data="{StaticResource Icons.Modified}"
IsVisible="{Binding IsDirty}"/>
</Grid>
</DataTemplate> </DataTemplate>
</DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn> </DataGridTemplateColumn>
@ -395,7 +344,7 @@
IsReadOnly="True" IsReadOnly="True"
HeadersVisibility="None" HeadersVisibility="None"
Focusable="False" Focusable="False"
RowHeight="26" RowHeight="24"
HorizontalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
ContextRequested="OnWorktreeContextRequested" ContextRequested="OnWorktreeContextRequested"
@ -405,6 +354,7 @@
<DataGrid.Styles> <DataGrid.Styles>
<Style Selector="DataGridRow"> <Style Selector="DataGridRow">
<Setter Property="CornerRadius" Value="4"/> <Setter Property="CornerRadius" Value="4"/>
<Setter Property="Height" Value="24"/>
</Style> </Style>
<Style Selector="DataGridRow /template/ Border#RowBorder"> <Style Selector="DataGridRow /template/ Border#RowBorder">
@ -720,7 +670,8 @@
<ContentControl Grid.Row="2" Content="{Binding SelectedView}"> <ContentControl Grid.Row="2" Content="{Binding SelectedView}">
<ContentControl.DataTemplates> <ContentControl.DataTemplates>
<DataTemplate DataType="vm:Histories"> <DataTemplate DataType="vm:Histories">
<v:Histories NavigationId="{Binding NavigationId}"/> <v:Histories CurrentBranch="{Binding $parent[v:Repository].((vm:Repository)DataContext).CurrentBranch}"
NavigationId="{Binding NavigationId}"/>
</DataTemplate> </DataTemplate>
<DataTemplate DataType="vm:WorkingCopy"> <DataTemplate DataType="vm:WorkingCopy">

View file

@ -2,7 +2,6 @@ using System;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
@ -30,6 +29,9 @@ namespace SourceGit.Views
private void OnSearchKeyDown(object _, KeyEventArgs e) private void OnSearchKeyDown(object _, KeyEventArgs e)
{ {
var repo = DataContext as ViewModels.Repository; var repo = DataContext as ViewModels.Repository;
if (repo == null)
return;
if (e.Key == Key.Enter) if (e.Key == Key.Enter)
{ {
if (!string.IsNullOrWhiteSpace(repo.SearchCommitFilter)) if (!string.IsNullOrWhiteSpace(repo.SearchCommitFilter))
@ -45,7 +47,6 @@ namespace SourceGit.Views
SearchSuggestionBox.SelectedIndex = 0; SearchSuggestionBox.SelectedIndex = 0;
} }
e.Handled = true; e.Handled = true;
} }
else if (e.Key == Key.Escape) else if (e.Key == Key.Escape)
@ -79,53 +80,32 @@ namespace SourceGit.Views
private void OnLocalBranchTreeSelectionChanged(object _1, RoutedEventArgs _2) private void OnLocalBranchTreeSelectionChanged(object _1, RoutedEventArgs _2)
{ {
RemoteBranchTree.UnselectAll(); RemoteBranchTree.UnselectAll();
TagsList.SelectedItem = null; TagsList.UnselectAll();
} }
private void OnRemoteBranchTreeSelectionChanged(object _1, RoutedEventArgs _2) private void OnRemoteBranchTreeSelectionChanged(object _1, RoutedEventArgs _2)
{ {
LocalBranchTree.UnselectAll(); LocalBranchTree.UnselectAll();
TagsList.SelectedItem = null; TagsList.UnselectAll();
} }
private void OnTagDataGridSelectionChanged(object sender, SelectionChangedEventArgs _) private void OnTagsRowsChanged(object _, RoutedEventArgs e)
{ {
if (sender is DataGrid { SelectedItem: Models.Tag tag }) UpdateLeftSidebarLayout();
e.Handled = true;
}
private void OnTagsSelectionChanged(object _1, RoutedEventArgs _2)
{ {
LocalBranchTree.UnselectAll(); LocalBranchTree.UnselectAll();
RemoteBranchTree.UnselectAll(); RemoteBranchTree.UnselectAll();
if (DataContext is ViewModels.Repository repo)
repo.NavigateToCommit(tag.SHA);
}
}
private void OnTagContextRequested(object sender, ContextRequestedEventArgs e)
{
if (sender is DataGrid { SelectedItem: Models.Tag tag } grid && DataContext is ViewModels.Repository repo)
{
var menu = repo.CreateContextMenuForTag(tag);
grid.OpenContextMenu(menu);
}
e.Handled = true;
}
private void OnTagFilterIsCheckedChanged(object sender, RoutedEventArgs e)
{
if (sender is ToggleButton { DataContext: Models.Tag tag } toggle && DataContext is ViewModels.Repository repo)
{
repo.UpdateFilter(tag.Name, toggle.IsChecked == true);
}
e.Handled = true;
} }
private void OnSubmoduleContextRequested(object sender, ContextRequestedEventArgs e) private void OnSubmoduleContextRequested(object sender, ContextRequestedEventArgs e)
{ {
if (sender is DataGrid { SelectedItem: string submodule } grid && DataContext is ViewModels.Repository repo) if (sender is DataGrid { SelectedItem: Models.Submodule submodule } grid && DataContext is ViewModels.Repository repo)
{ {
var menu = repo.CreateContextMenuForSubmodule(submodule); var menu = repo.CreateContextMenuForSubmodule(submodule.Path);
grid.OpenContextMenu(menu); grid.OpenContextMenu(menu);
} }
@ -134,9 +114,9 @@ namespace SourceGit.Views
private void OnDoubleTappedSubmodule(object sender, TappedEventArgs e) private void OnDoubleTappedSubmodule(object sender, TappedEventArgs e)
{ {
if (sender is DataGrid { SelectedItem: string submodule } && DataContext is ViewModels.Repository repo) if (sender is DataGrid { SelectedItem: Models.Submodule submodule } && DataContext is ViewModels.Repository repo)
{ {
repo.OpenSubmodule(submodule); repo.OpenSubmodule(submodule.Path);
} }
e.Handled = true; e.Handled = true;
@ -188,7 +168,7 @@ namespace SourceGit.Views
var localBranchRows = vm.IsLocalBranchGroupExpanded ? LocalBranchTree.Rows.Count : 0; var localBranchRows = vm.IsLocalBranchGroupExpanded ? LocalBranchTree.Rows.Count : 0;
var remoteBranchRows = vm.IsRemoteGroupExpanded ? RemoteBranchTree.Rows.Count : 0; var remoteBranchRows = vm.IsRemoteGroupExpanded ? RemoteBranchTree.Rows.Count : 0;
var desiredBranches = (localBranchRows + remoteBranchRows) * 24.0; var desiredBranches = (localBranchRows + remoteBranchRows) * 24.0;
var desiredTag = vm.IsTagGroupExpanded ? TagsList.RowHeight * vm.VisibleTags.Count : 0; var desiredTag = vm.IsTagGroupExpanded ? 24.0 * TagsList.Rows : 0;
var desiredSubmodule = vm.IsSubmoduleGroupExpanded ? SubmoduleList.RowHeight * vm.Submodules.Count : 0; var desiredSubmodule = vm.IsSubmoduleGroupExpanded ? SubmoduleList.RowHeight * vm.Submodules.Count : 0;
var desiredWorktree = vm.IsWorktreeGroupExpanded ? WorktreeList.RowHeight * vm.Worktrees.Count : 0; var desiredWorktree = vm.IsWorktreeGroupExpanded ? WorktreeList.RowHeight * vm.Worktrees.Count : 0;
var desiredOthers = desiredTag + desiredSubmodule + desiredWorktree; var desiredOthers = desiredTag + desiredSubmodule + desiredWorktree;
@ -295,9 +275,12 @@ namespace SourceGit.Views
} }
} }
private void OnSearchSuggestionBoxKeyDown(object sender, KeyEventArgs e) private void OnSearchSuggestionBoxKeyDown(object _, KeyEventArgs e)
{ {
var repo = DataContext as ViewModels.Repository; var repo = DataContext as ViewModels.Repository;
if (repo == null)
return;
if (e.Key == Key.Escape) if (e.Key == Key.Escape)
{ {
repo.IsSearchCommitSuggestionOpen = false; repo.IsSearchCommitSuggestionOpen = false;
@ -317,6 +300,9 @@ namespace SourceGit.Views
private void OnSearchSuggestionDoubleTapped(object sender, TappedEventArgs e) private void OnSearchSuggestionDoubleTapped(object sender, TappedEventArgs e)
{ {
var repo = DataContext as ViewModels.Repository; var repo = DataContext as ViewModels.Repository;
if (repo == null)
return;
var content = (sender as StackPanel)?.DataContext as string; var content = (sender as StackPanel)?.DataContext as string;
if (!string.IsNullOrEmpty(content)) if (!string.IsNullOrEmpty(content))
{ {

View file

@ -2,6 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:m="using:SourceGit.Models"
xmlns:vm="using:SourceGit.ViewModels" xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views" xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
@ -47,7 +48,13 @@
</Grid> </Grid>
<!-- Body --> <!-- Body -->
<Grid Grid.Row="1" Margin="16,8,16,0" RowDefinitions="32,32,32,32,32,32" ColumnDefinitions="Auto,*"> <TabControl Grid.Row="1">
<TabItem>
<TabItem.Header>
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Configure.Git}"/>
</TabItem.Header>
<Grid Margin="16,4,16,8" RowDefinitions="32,32,32,32,32,32" ColumnDefinitions="Auto,*">
<TextBlock Grid.Row="0" Grid.Column="0" <TextBlock Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center" HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0" Margin="0,0,8,0"
@ -103,23 +110,105 @@
Content="{DynamicResource Text.Preference.GPG.TagEnabled}" Content="{DynamicResource Text.Preference.GPG.TagEnabled}"
IsChecked="{Binding GPGTagSigningEnabled, Mode=TwoWay}"/> IsChecked="{Binding GPGTagSigningEnabled, Mode=TwoWay}"/>
</Grid> </Grid>
</TabItem>
<!-- Options --> <TabItem>
<StackPanel Grid.Row="2" <TabItem.Header>
Margin="8,4,8,8" <TextBlock Classes="tab_header" Text="{DynamicResource Text.Configure.IssueTracker}"/>
Height="32" </TabItem.Header>
Orientation="Horizontal"
HorizontalAlignment="Center"> <Grid ColumnDefinitions="200,*" Height="250" Margin="0,8,0,16">
<Button Classes="flat primary" <Border Grid.Column="0"
Width="80" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}"
Content="{DynamicResource Text.Sure}" Background="{DynamicResource Brush.Contents}">
Click="SaveAndClose" <Grid RowDefinitions="*,1,Auto">
HotKey="Enter"/> <ListBox Grid.Row="0"
<Button Classes="flat" Background="Transparent"
Width="80" ItemsSource="{Binding IssueTrackerRules}"
Margin="8,0,0,0" SelectedItem="{Binding SelectedIssueTrackerRule, Mode=TwoWay}"
Content="{DynamicResource Text.Cancel}" SelectionMode="Single">
Click="CloseWindow"/> <ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="MinHeight" Value="0"/>
<Setter Property="Height" Value="26"/>
<Setter Property="Padding" Value="4,2"/>
</Style>
</ListBox.Styles>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate DataType="m:IssueTrackerRule">
<TextBlock Grid.Column="1" Text="{Binding Name}" Margin="8,0" TextTrimming="CharacterEllipsis"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Rectangle Grid.Row="1" Height="1" Fill="{DynamicResource Brush.Border2}" HorizontalAlignment="Stretch" VerticalAlignment="Bottom"/>
<StackPanel Grid.Row="2" Orientation="Horizontal" Background="{DynamicResource Brush.ToolBar}">
<Button Classes="icon_button">
<Button.Flyout>
<MenuFlyout Placement="BottomEdgeAlignedLeft">
<MenuItem Header="{DynamicResource Text.Configure.IssueTracker.NewRule}" Command="{Binding NewIssueTracker}"/>
<MenuItem Header="-"/>
<MenuItem Header="{DynamicResource Text.Configure.IssueTracker.AddSampleGithub}" Command="{Binding AddSampleGithubIssueTracker}"/>
<MenuItem Header="{DynamicResource Text.Configure.IssueTracker.AddSampleJira}" Command="{Binding AddSampleJiraIssueTracker}"/>
</MenuFlyout>
</Button.Flyout>
<Path Width="14" Height="14" Data="{StaticResource Icons.Plus}"/>
</Button>
<Rectangle Width="1" Fill="{DynamicResource Brush.Border2}" HorizontalAlignment="Left" VerticalAlignment="Stretch"/>
<Button Classes="icon_button" Command="{Binding RemoveSelectedIssueTracker}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Window.Minimize}"/>
</Button>
<Rectangle Width="1" Fill="{DynamicResource Brush.Border2}" HorizontalAlignment="Left" VerticalAlignment="Stretch"/>
</StackPanel> </StackPanel>
</Grid> </Grid>
</Border>
<ContentControl Grid.Column="1" Margin="16,0,0,0">
<ContentControl.Content>
<Binding Path="SelectedIssueTrackerRule">
<Binding.TargetNullValue>
<Path Width="64" Height="64"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Fill="{DynamicResource Brush.FG2}"
Data="{StaticResource Icons.Issue}"/>
</Binding.TargetNullValue>
</Binding>
</ContentControl.Content>
<ContentControl.DataTemplates>
<DataTemplate DataType="m:IssueTrackerRule">
<Grid RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<TextBlock Grid.Row="0" Text="{DynamicResource Text.Configure.IssueTracker.RuleName}"/>
<TextBox Grid.Row="1" Margin="0,4,0,0" CornerRadius="3" Height="28" Text="{Binding Name, Mode=TwoWay}"/>
<TextBlock Grid.Row="2" Margin="0,12,0,0" Text="{DynamicResource Text.Configure.IssueTracker.Regex}"/>
<TextBox Grid.Row="3" Margin="0,4,0,0" CornerRadius="3" Height="28" Text="{Binding RegexString, Mode=TwoWay}">
<TextBox.InnerRightContent>
<Path Margin="4,0" Width="12" Height="12" Data="{StaticResource Icons.Error}" Fill="OrangeRed" IsVisible="{Binding !IsRegexValid}"/>
</TextBox.InnerRightContent>
</TextBox>
<TextBlock Grid.Row="4" Margin="0,12,0,0" Text="{DynamicResource Text.Configure.IssueTracker.URLTemplate}"/>
<TextBox Grid.Row="5" Margin="0,4,0,0" CornerRadius="3" Height="28" Text="{Binding URLTemplate, Mode=TwoWay}"/>
<TextBlock Grid.Row="6" Margin="0,2,0,0" Text="{DynamicResource Text.Configure.IssueTracker.URLTemplate.Tip}" Foreground="{DynamicResource Brush.FG2}"/>
</Grid>
</DataTemplate>
</ContentControl.DataTemplates>
</ContentControl>
</Grid>
</TabItem>
</TabControl>
</Grid>
</v:ChromelessWindow> </v:ChromelessWindow>

View file

@ -16,11 +16,6 @@ namespace SourceGit.Views
} }
private void CloseWindow(object _1, RoutedEventArgs _2) private void CloseWindow(object _1, RoutedEventArgs _2)
{
Close();
}
private void SaveAndClose(object _1, RoutedEventArgs _2)
{ {
(DataContext as ViewModels.RepositoryConfigure)?.Save(); (DataContext as ViewModels.RepositoryConfigure)?.Save();
Close(); Close();

View file

@ -9,6 +9,7 @@ using Avalonia.Media;
using AvaloniaEdit; using AvaloniaEdit;
using AvaloniaEdit.Document; using AvaloniaEdit.Document;
using AvaloniaEdit.Editing; using AvaloniaEdit.Editing;
using AvaloniaEdit.TextMate;
namespace SourceGit.Views namespace SourceGit.Views
{ {
@ -35,6 +36,7 @@ namespace SourceGit.Views
base.OnLoaded(e); base.OnLoaded(e);
TextArea.TextView.ContextRequested += OnTextViewContextRequested; TextArea.TextView.ContextRequested += OnTextViewContextRequested;
UpdateTextMate();
} }
protected override void OnUnloaded(RoutedEventArgs e) protected override void OnUnloaded(RoutedEventArgs e)
@ -42,6 +44,13 @@ namespace SourceGit.Views
base.OnUnloaded(e); base.OnUnloaded(e);
TextArea.TextView.ContextRequested -= OnTextViewContextRequested; TextArea.TextView.ContextRequested -= OnTextViewContextRequested;
if (_textMate != null)
{
_textMate.Dispose();
_textMate = null;
}
GC.Collect(); GC.Collect();
} }
@ -50,10 +59,15 @@ namespace SourceGit.Views
base.OnDataContextChanged(e); base.OnDataContextChanged(e);
if (DataContext is Models.RevisionTextFile source) if (DataContext is Models.RevisionTextFile source)
{
UpdateTextMate();
Text = source.Content; Text = source.Content;
}
else else
{
Text = string.Empty; Text = string.Empty;
} }
}
private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e) private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e)
{ {
@ -85,6 +99,17 @@ namespace SourceGit.Views
TextArea.TextView.OpenContextMenu(menu); TextArea.TextView.OpenContextMenu(menu);
e.Handled = true; 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 partial class RevisionFiles : UserControl

View file

@ -55,7 +55,11 @@
SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}" SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
Background="Transparent"> Background="Transparent"
BorderThickness="1"
BorderBrush="{DynamicResource Brush.Border2}"
CornerRadius="14"
Padding="3,0">
<ListBox.ItemsPanel> <ListBox.ItemsPanel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/> <StackPanel Orientation="Horizontal"/>
@ -64,6 +68,7 @@
<ListBox.Styles> <ListBox.Styles>
<Style Selector="ListBoxItem"> <Style Selector="ListBoxItem">
<Setter Property="Height" Value="28"/>
<Setter Property="Padding" Value="0"/> <Setter Property="Padding" Value="0"/>
<Setter Property="Background" Value="Transparent"/> <Setter Property="Background" Value="Transparent"/>
</Style> </Style>
@ -77,12 +82,15 @@
</Style> </Style>
<Style Selector="ListBoxItem Border.switcher_bg"> <Style Selector="ListBoxItem Border.switcher_bg">
<Setter Property="BorderBrush" Value="{DynamicResource Brush.Border2}"/> <Setter Property="Height" Value="22"/>
<Setter Property="CornerRadius" Value="11"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Padding" Value="16,0"/>
</Style> </Style>
<Style Selector="ListBoxItem:selected Border.switcher_bg"> <Style Selector="ListBoxItem:selected Border.switcher_bg">
<Setter Property="Background" Value="{DynamicResource Brush.Accent}"/> <Setter Property="Background" Value="{DynamicResource Brush.Accent}"/>
<Setter Property="BorderBrush" Value="{DynamicResource Brush.Accent}"/>
</Style> </Style>
<Style Selector="TextBlock.view_mode_switcher"> <Style Selector="TextBlock.view_mode_switcher">
@ -90,25 +98,29 @@
<Setter Property="Foreground" Value="{DynamicResource Brush.FG2}"/> <Setter Property="Foreground" Value="{DynamicResource Brush.FG2}"/>
</Style> </Style>
<Style Selector="ListBoxItem:pointerover TextBlock.view_mode_switcher">
<Setter Property="Foreground" Value="{DynamicResource Brush.FG1}"/>
</Style>
<Style Selector="ListBoxItem:selected TextBlock.view_mode_switcher"> <Style Selector="ListBoxItem:selected TextBlock.view_mode_switcher">
<Setter Property="Foreground" Value="White"/> <Setter Property="Foreground" Value="White"/>
</Style> </Style>
</ListBox.Styles> </ListBox.Styles>
<ListBoxItem> <ListBoxItem>
<Border Classes="switcher_bg" Height="28" Padding="16,0" BorderThickness="1,1,0,1" CornerRadius="14,0,0,14"> <Border Classes="switcher_bg">
<TextBlock Classes="view_mode_switcher" Text="{DynamicResource Text.Statistics.ThisYear}"/> <TextBlock Classes="view_mode_switcher" Text="{DynamicResource Text.Statistics.ThisYear}"/>
</Border> </Border>
</ListBoxItem> </ListBoxItem>
<ListBoxItem> <ListBoxItem>
<Border Classes="switcher_bg" Height="28" Padding="16,0" BorderThickness="1"> <Border Classes="switcher_bg">
<TextBlock Classes="view_mode_switcher" Text="{DynamicResource Text.Statistics.ThisMonth}"/> <TextBlock Classes="view_mode_switcher" Text="{DynamicResource Text.Statistics.ThisMonth}"/>
</Border> </Border>
</ListBoxItem> </ListBoxItem>
<ListBoxItem> <ListBoxItem>
<Border Classes="switcher_bg" Height="28" Padding="16,0" BorderThickness="0,1,1,1" CornerRadius="0,14,14,0"> <Border Classes="switcher_bg">
<TextBlock Classes="view_mode_switcher" Text="{DynamicResource Text.Statistics.ThisWeek}"/> <TextBlock Classes="view_mode_switcher" Text="{DynamicResource Text.Statistics.ThisWeek}"/>
</Border> </Border>
</ListBoxItem> </ListBoxItem>

103
src/Views/TagsView.axaml Normal file
View file

@ -0,0 +1,103 @@
<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:m="using:SourceGit.Models"
xmlns:v="using:SourceGit.Views"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:c="using:SourceGit.Converters"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.TagsView">
<UserControl.Styles>
<Style Selector="ListBox">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ItemsPanel">
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</Setter>
</Style>
<Style Selector="ListBoxItem">
<Setter Property="Height" Value="24"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="CornerRadius" Value="4"/>
</Style>
</UserControl.Styles>
<UserControl.DataTemplates>
<DataTemplate DataType="vm:TagCollectionAsTree">
<ListBox ItemsSource="{Binding Rows}"
SelectionMode="Single"
SelectionChanged="OnRowSelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate DataType="vm:TagTreeNode">
<Grid ColumnDefinitions="16,Auto,*,Auto"
Margin="{Binding Depth, Converter={x:Static c:IntConverters.ToTreeMargin}}"
Background="Transparent"
ContextRequested="OnRowContextRequested"
DoubleTapped="OnDoubleTappedNode">
<v:TagTreeNodeToggleButton Grid.Column="0"
Classes="tree_expander"
Focusable="False"
HorizontalAlignment="Center"
IsChecked="{Binding IsExpanded, Mode=OneWay}"
IsVisible="{Binding IsFolder}"/>
<v:TagTreeNodeIcon Grid.Column="1"
Node="{Binding .}"
IsExpanded="{Binding IsExpanded, Mode=OneWay}"/>
<TextBlock Grid.Column="2"
Classes="primary"
Text="{Binding FullPath, Converter={x:Static c:PathConverters.PureFileName}}"
Margin="8,0,0,0"/>
<ToggleButton Grid.Column="3"
Classes="filter"
Margin="0,0,8,0"
Background="Transparent"
IsCheckedChanged="OnToggleFilter"
IsChecked="{Binding IsFiltered}"
ToolTip.Tip="{DynamicResource Text.Filter}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
<DataTemplate DataType="vm:TagCollectionAsList">
<ListBox ItemsSource="{Binding Tags}"
SelectionMode="Single"
SelectionChanged="OnRowSelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate DataType="m:Tag">
<Grid ColumnDefinitions="Auto,*,Auto" Background="Transparent" ContextRequested="OnRowContextRequested">
<Path Grid.Column="0"
Width="10" Height="10"
Margin="8,0,0,0"
Data="{StaticResource Icons.Tag}"/>
<TextBlock Grid.Column="1"
Classes="primary"
Text="{Binding Name}"
Margin="8,0,0,0"/>
<ToggleButton Grid.Column="2"
Classes="filter"
Margin="0,0,8,0"
Background="Transparent"
IsCheckedChanged="OnToggleFilter"
IsChecked="{Binding IsFiltered}"
ToolTip.Tip="{DynamicResource Text.Filter}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</UserControl.DataTemplates>
</UserControl>

324
src/Views/TagsView.axaml.cs Normal file
View file

@ -0,0 +1,324 @@
using System;
using System.Collections.Generic;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.VisualTree;
namespace SourceGit.Views
{
public class TagTreeNodeToggleButton : ToggleButton
{
protected override Type StyleKeyOverride => typeof(ToggleButton);
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed &&
DataContext is ViewModels.TagTreeNode { IsFolder: true } node)
{
var view = this.FindAncestorOfType<TagsView>();
view?.ToggleNodeIsExpanded(node);
}
e.Handled = true;
}
}
public class TagTreeNodeIcon : UserControl
{
public static readonly StyledProperty<ViewModels.TagTreeNode> NodeProperty =
AvaloniaProperty.Register<TagTreeNodeIcon, ViewModels.TagTreeNode>(nameof(Node));
public ViewModels.TagTreeNode Node
{
get => GetValue(NodeProperty);
set => SetValue(NodeProperty, value);
}
public static readonly StyledProperty<bool> IsExpandedProperty =
AvaloniaProperty.Register<TagTreeNodeIcon, bool>(nameof(IsExpanded));
public bool IsExpanded
{
get => GetValue(IsExpandedProperty);
set => SetValue(IsExpandedProperty, value);
}
static TagTreeNodeIcon()
{
NodeProperty.Changed.AddClassHandler<TagTreeNodeIcon>((icon, _) => icon.UpdateContent());
IsExpandedProperty.Changed.AddClassHandler<TagTreeNodeIcon>((icon, _) => icon.UpdateContent());
}
private void UpdateContent()
{
var node = Node;
if (node == null)
{
Content = null;
return;
}
if (node.Tag != null)
CreateContent(new Thickness(0, 2, 0, 0), "Icons.Tag");
else if (node.IsExpanded)
CreateContent(new Thickness(0, 2, 0, 0), "Icons.Folder.Open");
else
CreateContent(new Thickness(0, 2, 0, 0), "Icons.Folder");
}
private void CreateContent(Thickness margin, string iconKey)
{
var geo = this.FindResource(iconKey) as StreamGeometry;
if (geo == null)
return;
Content = new Avalonia.Controls.Shapes.Path()
{
Width = 12,
Height = 12,
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Center,
Margin = margin,
Data = geo,
};
}
}
public partial class TagsView : UserControl
{
public static readonly StyledProperty<bool> ShowTagsAsTreeProperty =
AvaloniaProperty.Register<TagsView, bool>(nameof(ShowTagsAsTree));
public bool ShowTagsAsTree
{
get => GetValue(ShowTagsAsTreeProperty);
set => SetValue(ShowTagsAsTreeProperty, value);
}
public static readonly StyledProperty<List<Models.Tag>> TagsProperty =
AvaloniaProperty.Register<TagsView, List<Models.Tag>>(nameof(Tags));
public List<Models.Tag> Tags
{
get => GetValue(TagsProperty);
set => SetValue(TagsProperty, value);
}
public static readonly RoutedEvent<RoutedEventArgs> SelectionChangedEvent =
RoutedEvent.Register<TagsView, RoutedEventArgs>(nameof(SelectionChanged), RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
public event EventHandler<RoutedEventArgs> SelectionChanged
{
add { AddHandler(SelectionChangedEvent, value); }
remove { RemoveHandler(SelectionChangedEvent, value); }
}
public static readonly RoutedEvent<RoutedEventArgs> RowsChangedEvent =
RoutedEvent.Register<TagsView, RoutedEventArgs>(nameof(RowsChanged), RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
public event EventHandler<RoutedEventArgs> RowsChanged
{
add { AddHandler(RowsChangedEvent, value); }
remove { RemoveHandler(RowsChangedEvent, value); }
}
public int Rows
{
get;
private set;
}
public TagsView()
{
InitializeComponent();
}
public void UnselectAll()
{
var list = this.FindDescendantOfType<ListBox>();
if (list != null)
list.SelectedItem = null;
}
public void ToggleNodeIsExpanded(ViewModels.TagTreeNode node)
{
if (Content is ViewModels.TagCollectionAsTree tree)
{
node.IsExpanded = !node.IsExpanded;
var depth = node.Depth;
var idx = tree.Rows.IndexOf(node);
if (idx == -1)
return;
if (node.IsExpanded)
{
var subrows = new List<ViewModels.TagTreeNode>();
MakeTreeRows(subrows, node.Children);
tree.Rows.InsertRange(idx + 1, subrows);
}
else
{
var removeCount = 0;
for (int i = idx + 1; i < tree.Rows.Count; i++)
{
var row = tree.Rows[i];
if (row.Depth <= depth)
break;
removeCount++;
}
tree.Rows.RemoveRange(idx + 1, removeCount);
}
Rows = tree.Rows.Count;
RaiseEvent(new RoutedEventArgs(RowsChangedEvent));
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == ShowTagsAsTreeProperty || change.Property == TagsProperty)
{
UpdateDataSource();
RaiseEvent(new RoutedEventArgs(RowsChangedEvent));
}
else if (change.Property == IsVisibleProperty)
{
RaiseEvent(new RoutedEventArgs(RowsChangedEvent));
}
}
private void OnDoubleTappedNode(object sender, TappedEventArgs e)
{
if (sender is Grid { DataContext: ViewModels.TagTreeNode node })
{
if (node.IsFolder)
ToggleNodeIsExpanded(node);
}
e.Handled = true;
}
private void OnRowContextRequested(object sender, ContextRequestedEventArgs e)
{
var control = sender as Control;
if (control == null)
return;
Models.Tag selected;
if (control.DataContext is ViewModels.TagTreeNode node)
selected = node.Tag;
else if (control.DataContext is Models.Tag tag)
selected = tag;
else
selected = null;
if (selected != null && DataContext is ViewModels.Repository repo)
{
var menu = repo.CreateContextMenuForTag(selected);
control.OpenContextMenu(menu);
}
e.Handled = true;
}
private void OnRowSelectionChanged(object sender, SelectionChangedEventArgs _)
{
var selected = (sender as ListBox)?.SelectedItem;
var selectedTag = null as Models.Tag;
if (selected is ViewModels.TagTreeNode node)
selectedTag = node.Tag;
else if (selected is Models.Tag tag)
selectedTag = tag;
if (selectedTag != null && DataContext is ViewModels.Repository repo)
{
RaiseEvent(new RoutedEventArgs(SelectionChangedEvent));
repo.NavigateToCommit(selectedTag.SHA);
}
}
private void OnToggleFilter(object sender, RoutedEventArgs e)
{
if (sender is ToggleButton toggle && DataContext is ViewModels.Repository repo)
{
var target = null as Models.Tag;
if (toggle.DataContext is ViewModels.TagTreeNode node)
target = node.Tag;
else if (toggle.DataContext is Models.Tag tag)
target = tag;
if (target != null)
repo.UpdateFilter(target.Name, toggle.IsChecked == true);
}
e.Handled = true;
}
private void MakeTreeRows(List<ViewModels.TagTreeNode> rows, List<ViewModels.TagTreeNode> nodes)
{
foreach (var node in nodes)
{
rows.Add(node);
if (!node.IsExpanded || !node.IsFolder)
continue;
MakeTreeRows(rows, node.Children);
}
}
private void UpdateDataSource()
{
var tags = Tags;
if (tags == null || tags.Count == 0)
{
Content = null;
return;
}
if (ShowTagsAsTree)
{
var oldExpanded = new HashSet<string>();
if (Content is ViewModels.TagCollectionAsTree oldTree)
{
foreach (var row in oldTree.Rows)
{
if (row.IsFolder && row.IsExpanded)
oldExpanded.Add(row.FullPath);
}
}
var tree = new ViewModels.TagCollectionAsTree();
tree.Tree = ViewModels.TagTreeNode.Build(tags, oldExpanded);
var rows = new List<ViewModels.TagTreeNode>();
MakeTreeRows(rows, tree.Tree);
tree.Rows.AddRange(rows);
Content = tree;
Rows = rows.Count;
}
else
{
var list = new ViewModels.TagCollectionAsList();
list.Tags.AddRange(tags);
Content = list;
Rows = tags.Count;
}
RaiseEvent(new RoutedEventArgs(RowsChangedEvent));
}
}
}

View file

@ -1085,7 +1085,7 @@ namespace SourceGit.Views
return; return;
} }
var top = chunk.Y + 16; var top = chunk.Y + (chunk.Height >= 36 ? 16 : 4);
var right = (chunk.Combined || !chunk.IsOldSide) ? 16 : v.Bounds.Width * 0.5f + 16; var right = (chunk.Combined || !chunk.IsOldSide) ? 16 : v.Bounds.Width * 0.5f + 16;
v.Popup.Margin = new Thickness(0, top, right, 0); v.Popup.Margin = new Thickness(0, top, right, 0);
v.Popup.IsVisible = true; v.Popup.IsVisible = true;
@ -1147,17 +1147,6 @@ namespace SourceGit.Views
if (!selection.HasChanges) if (!selection.HasChanges)
return; return;
if (!selection.HasLeftChanges)
{
var workcopyView = this.FindAncestorOfType<WorkingCopy>();
if (workcopyView == null)
return;
var workcopy = workcopyView.DataContext as ViewModels.WorkingCopy;
workcopy?.StageChanges(new List<Models.Change> { change });
}
else
{
var repoView = this.FindAncestorOfType<Repository>(); var repoView = this.FindAncestorOfType<Repository>();
if (repoView == null) if (repoView == null)
return; return;
@ -1168,6 +1157,12 @@ namespace SourceGit.Views
repo.SetWatcherEnabled(false); repo.SetWatcherEnabled(false);
if (!selection.HasLeftChanges)
{
new Commands.Add(repo.FullPath, [change]).Exec();
}
else
{
var tmpFile = Path.GetTempFileName(); var tmpFile = Path.GetTempFileName();
if (change.WorkTree == Models.ChangeState.Untracked) if (change.WorkTree == Models.ChangeState.Untracked)
{ {
@ -1186,11 +1181,11 @@ namespace SourceGit.Views
new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--cache --index").Exec(); new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--cache --index").Exec();
File.Delete(tmpFile); File.Delete(tmpFile);
}
repo.MarkWorkingCopyDirtyManually(); repo.MarkWorkingCopyDirtyManually();
repo.SetWatcherEnabled(true); repo.SetWatcherEnabled(true);
} }
}
private void OnUnstageChunk(object sender, RoutedEventArgs e) private void OnUnstageChunk(object sender, RoutedEventArgs e)
{ {
@ -1210,17 +1205,6 @@ namespace SourceGit.Views
if (!selection.HasChanges) if (!selection.HasChanges)
return; return;
if (!selection.HasLeftChanges)
{
var workcopyView = this.FindAncestorOfType<WorkingCopy>();
if (workcopyView == null)
return;
var workcopy = workcopyView.DataContext as ViewModels.WorkingCopy;
workcopy?.UnstageChanges(new List<Models.Change> { change });
}
else
{
var repoView = this.FindAncestorOfType<Repository>(); var repoView = this.FindAncestorOfType<Repository>();
if (repoView == null) if (repoView == null)
return; return;
@ -1231,6 +1215,15 @@ namespace SourceGit.Views
repo.SetWatcherEnabled(false); repo.SetWatcherEnabled(false);
if (!selection.HasLeftChanges)
{
if (change.DataForAmend != null)
new Commands.UnstageChangesForAmend(repo.FullPath, [change]).Exec();
else
new Commands.Reset(repo.FullPath, [change]).Exec();
}
else
{
var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result(); var treeGuid = new Commands.QueryStagedFileBlobGuid(diff.Repo, change.Path).Result();
var tmpFile = Path.GetTempFileName(); var tmpFile = Path.GetTempFileName();
if (change.Index == Models.ChangeState.Added) if (change.Index == Models.ChangeState.Added)
@ -1242,11 +1235,11 @@ namespace SourceGit.Views
new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--cache --index --reverse").Exec(); new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--cache --index --reverse").Exec();
File.Delete(tmpFile); File.Delete(tmpFile);
}
repo.MarkWorkingCopyDirtyManually(); repo.MarkWorkingCopyDirtyManually();
repo.SetWatcherEnabled(true); repo.SetWatcherEnabled(true);
} }
}
private void OnDiscardChunk(object sender, RoutedEventArgs e) private void OnDiscardChunk(object sender, RoutedEventArgs e)
{ {
@ -1266,17 +1259,6 @@ namespace SourceGit.Views
if (!selection.HasChanges) if (!selection.HasChanges)
return; return;
if (!selection.HasLeftChanges)
{
var workcopyView = this.FindAncestorOfType<WorkingCopy>();
if (workcopyView == null)
return;
var workcopy = workcopyView.DataContext as ViewModels.WorkingCopy;
workcopy?.Discard(new List<Models.Change> { change });
}
else
{
var repoView = this.FindAncestorOfType<Repository>(); var repoView = this.FindAncestorOfType<Repository>();
if (repoView == null) if (repoView == null)
return; return;
@ -1287,6 +1269,12 @@ namespace SourceGit.Views
repo.SetWatcherEnabled(false); repo.SetWatcherEnabled(false);
if (!selection.HasLeftChanges)
{
Commands.Discard.Changes(repo.FullPath, [change]);
}
else
{
var tmpFile = Path.GetTempFileName(); var tmpFile = Path.GetTempFileName();
if (change.Index == Models.ChangeState.Added) if (change.Index == Models.ChangeState.Added)
{ {
@ -1305,10 +1293,10 @@ namespace SourceGit.Views
new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--reverse").Exec(); new Commands.Apply(diff.Repo, tmpFile, true, "nowarn", "--reverse").Exec();
File.Delete(tmpFile); File.Delete(tmpFile);
}
repo.MarkWorkingCopyDirtyManually(); repo.MarkWorkingCopyDirtyManually();
repo.SetWatcherEnabled(true); repo.SetWatcherEnabled(true);
} }
} }
} }
}

View file

@ -55,7 +55,7 @@ namespace SourceGit.Views
} }
var normalizedPath = root.Replace("\\", "/"); var normalizedPath = root.Replace("\\", "/");
var node = ViewModels.Preference.Instance.FindOrAddNodeByRepositoryPath(normalizedPath, parent, true); var node = ViewModels.Preference.Instance.FindOrAddNodeByRepositoryPath(normalizedPath, parent, false);
var launcher = this.FindAncestorOfType<Launcher>()?.DataContext as ViewModels.Launcher; var launcher = this.FindAncestorOfType<Launcher>()?.DataContext as ViewModels.Launcher;
launcher?.OpenRepositoryInTab(node, launcher.ActivePage); launcher?.OpenRepositoryInTab(node, launcher.ActivePage);
} }