diff --git a/README.md b/README.md
index d63886ed..aacf222e 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
* Supports Windows/macOS/Linux
* Opensource/Free
* Fast
-* Deutsch/English/Español/Français/Italiano/Português/Русский/简体中文/繁體中文
+* Deutsch/English/Español/Français/Italiano/Português/Русский/简体中文/繁體中文/日本語
* Built-in light/dark themes
* Customize theme
* Visual commit graph
diff --git a/TRANSLATION.md b/TRANSLATION.md
index a96f0fc6..b344e6a3 100644
--- a/TRANSLATION.md
+++ b/TRANSLATION.md
@@ -6,13 +6,15 @@ This document shows the translation status of each locale file in the repository
### 
-### 
+### 
Missing keys in de_DE.axaml
- Text.BranchUpstreamInvalid
- Text.Configure.CustomAction.WaitForExit
+- Text.Configure.IssueTracker.AddSampleAzure
+- Text.CopyFullPath
- Text.Diff.First
- Text.Diff.Last
- Text.Preferences.AI.Streaming
@@ -22,27 +24,31 @@ This document shows the translation status of each locale file in the repository
-### 
-
-
-Missing keys in es_ES.axaml
-
-- Text.Preferences.General.ShowTagsInGraph
-
-
+### 
### 
-### 
+### 
Missing keys in it_IT.axaml
+- Text.CopyFullPath
- Text.Preferences.General.ShowTagsInGraph
-### 
+### 
+
+
+Missing keys in ja_JP.axaml
+
+- Text.Repository.FilterCommits
+- Text.Repository.Tags.OrderByNameDes
+
+
+
+### 
Missing keys in pt_BR.axaml
@@ -65,6 +71,7 @@ This document shows the translation status of each locale file in the repository
- Text.Configure.CustomAction.WaitForExit
- Text.Configure.IssueTracker.AddSampleGiteeIssue
- Text.Configure.IssueTracker.AddSampleGiteePullRequest
+- Text.CopyFullPath
- Text.CreateBranch.Name.WarnSpace
- Text.DeleteRepositoryNode.Path
- Text.DeleteRepositoryNode.TipForGroup
diff --git a/VERSION b/VERSION
index e78345d1..8283ecf3 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2025.10
\ No newline at end of file
+2025.12
\ No newline at end of file
diff --git a/build/resources/deb/DEBIAN/control b/build/resources/deb/DEBIAN/control
index f553db8b..71786b43 100755
--- a/build/resources/deb/DEBIAN/control
+++ b/build/resources/deb/DEBIAN/control
@@ -1,7 +1,8 @@
Package: sourcegit
-Version: 8.23
+Version: 2025.10
Priority: optional
Depends: libx11-6, libice6, libsm6, libicu | libicu76 | libicu74 | libicu72 | libicu71 | libicu70 | libicu69 | libicu68 | libicu67 | libicu66 | libicu65 | libicu63 | libicu60 | libicu57 | libicu55 | libicu52, xdg-utils
Architecture: amd64
+Installed-Size: 60440
Maintainer: longshuang@msn.cn
Description: Open-source & Free Git GUI Client
diff --git a/build/scripts/package.linux.sh b/build/scripts/package.linux.sh
index 5abb058b..1b4adbdc 100755
--- a/build/scripts/package.linux.sh
+++ b/build/scripts/package.linux.sh
@@ -56,8 +56,15 @@ cp -f SourceGit/* resources/deb/opt/sourcegit
ln -rsf resources/deb/opt/sourcegit/sourcegit resources/deb/usr/bin
cp -r resources/_common/applications resources/deb/usr/share
cp -r resources/_common/icons resources/deb/usr/share
-sed -i -e "s/^Version:.*/Version: $VERSION/" -e "s/^Architecture:.*/Architecture: $arch/" resources/deb/DEBIAN/control
-dpkg-deb --root-owner-group --build resources/deb "sourcegit_$VERSION-1_$arch.deb"
+# Calculate installed size in KB
+installed_size=$(du -sk resources/deb | cut -f1)
+# Update the control file
+sed -i -e "s/^Version:.*/Version: $VERSION/" \
+ -e "s/^Architecture:.*/Architecture: $arch/" \
+ -e "s/^Installed-Size:.*/Installed-Size: $installed_size/" \
+ resources/deb/DEBIAN/control
+# Build deb package with gzip compression
+dpkg-deb -Zgzip --root-owner-group --build resources/deb "sourcegit_$VERSION-1_$arch.deb"
rpmbuild -bb --target="$target" resources/rpm/SPECS/build.spec --define "_topdir $(pwd)/resources/rpm" --define "_version $VERSION"
mv "resources/rpm/RPMS/$target/sourcegit-$VERSION-1.$target.rpm" ./
diff --git a/src/App.Commands.cs b/src/App.Commands.cs
index 85a75829..3733587a 100644
--- a/src/App.Commands.cs
+++ b/src/App.Commands.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Windows.Input;
using Avalonia.Controls;
@@ -37,16 +37,15 @@ namespace SourceGit
}
}
- public static readonly Command OpenPreferencesCommand = new Command(_ => OpenDialog(new Views.Preferences()));
- public static readonly Command OpenHotkeysCommand = new Command(_ => OpenDialog(new Views.Hotkeys()));
- public static readonly Command OpenAppDataDirCommand = new Command(_ => Native.OS.OpenInFileManager(Native.OS.DataDir));
- public static readonly Command OpenAboutCommand = new Command(_ => OpenDialog(new Views.About()));
- public static readonly Command CheckForUpdateCommand = new Command(_ => (Current as App)?.Check4Update(true));
- public static readonly Command QuitCommand = new Command(_ => Quit(0));
- public static readonly Command CopyTextBlockCommand = new Command(p =>
+ public static readonly Command OpenPreferencesCommand = new(_ => OpenDialog(new Views.Preferences()));
+ public static readonly Command OpenHotkeysCommand = new(_ => OpenDialog(new Views.Hotkeys()));
+ public static readonly Command OpenAppDataDirCommand = new(_ => Native.OS.OpenInFileManager(Native.OS.DataDir));
+ public static readonly Command OpenAboutCommand = new(_ => OpenDialog(new Views.About()));
+ public static readonly Command CheckForUpdateCommand = new(_ => (Current as App)?.Check4Update(true));
+ public static readonly Command QuitCommand = new(_ => Quit(0));
+ public static readonly Command CopyTextBlockCommand = new(p =>
{
- var textBlock = p as TextBlock;
- if (textBlock == null)
+ if (p is not TextBlock textBlock)
return;
if (textBlock.Inlines is { Count: > 0 } inlines)
diff --git a/src/App.axaml b/src/App.axaml
index 76d4baa8..fdfa8e07 100644
--- a/src/App.axaml
+++ b/src/App.axaml
@@ -20,6 +20,7 @@
+
diff --git a/src/App.axaml.cs b/src/App.axaml.cs
index af5e6177..f6a5fb22 100644
--- a/src/App.axaml.cs
+++ b/src/App.axaml.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -37,7 +37,6 @@ namespace SourceGit
TaskScheduler.UnobservedTaskException += (_, e) =>
{
- LogException(e.Exception);
e.SetObserved();
};
@@ -284,10 +283,12 @@ namespace SourceGit
public static Avalonia.Controls.Shapes.Path CreateMenuIcon(string key)
{
- var icon = new Avalonia.Controls.Shapes.Path();
- icon.Width = 12;
- icon.Height = 12;
- icon.Stretch = Stretch.Uniform;
+ var icon = new Avalonia.Controls.Shapes.Path
+ {
+ Width = 12,
+ Height = 12,
+ Stretch = Stretch.Uniform
+ };
var geo = Current?.FindResource(key) as StreamGeometry;
if (geo != null)
@@ -430,7 +431,7 @@ namespace SourceGit
if (!File.Exists(doneFile))
return true;
- var done = File.ReadAllText(doneFile).Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
+ var done = File.ReadAllText(doneFile).Split(['\n', '\r'], StringSplitOptions.RemoveEmptyEntries);
if (done.Length > collection.Jobs.Count)
return true;
@@ -560,8 +561,22 @@ namespace SourceGit
foreach (var part in parts)
{
var t = part.Trim();
- if (!string.IsNullOrEmpty(t))
- trimmed.Add(t);
+ if (string.IsNullOrEmpty(t))
+ continue;
+
+ // Collapse multiple spaces into single space
+ var prevChar = '\0';
+ var sb = new StringBuilder();
+
+ foreach (var c in t)
+ {
+ if (c == ' ' && prevChar == ' ')
+ continue;
+ sb.Append(c);
+ prevChar = c;
+ }
+
+ trimmed.Add(sb.ToString());
}
return trimmed.Count > 0 ? string.Join(',', trimmed) : string.Empty;
diff --git a/src/Commands/CompareRevisions.cs b/src/Commands/CompareRevisions.cs
index e311a88e..c3206767 100644
--- a/src/Commands/CompareRevisions.cs
+++ b/src/Commands/CompareRevisions.cs
@@ -6,8 +6,10 @@ namespace SourceGit.Commands
{
public partial class CompareRevisions : Command
{
- [GeneratedRegex(@"^([MADRC])\s+(.+)$")]
+ [GeneratedRegex(@"^([MADC])\s+(.+)$")]
private static partial Regex REG_FORMAT();
+ [GeneratedRegex(@"^R[0-9]{0,4}\s+(.+)$")]
+ private static partial Regex REG_RENAME_FORMAT();
public CompareRevisions(string repo, string start, string end)
{
@@ -38,7 +40,17 @@ namespace SourceGit.Commands
{
var match = REG_FORMAT().Match(line);
if (!match.Success)
+ {
+ match = REG_RENAME_FORMAT().Match(line);
+ if (match.Success)
+ {
+ var renamed = new Models.Change() { Path = match.Groups[1].Value };
+ renamed.Set(Models.ChangeState.Renamed);
+ _changes.Add(renamed);
+ }
+
return;
+ }
var change = new Models.Change() { Path = match.Groups[2].Value };
var status = match.Groups[1].Value;
@@ -57,10 +69,6 @@ namespace SourceGit.Commands
change.Set(Models.ChangeState.Deleted);
_changes.Add(change);
break;
- case 'R':
- change.Set(Models.ChangeState.Renamed);
- _changes.Add(change);
- break;
case 'C':
change.Set(Models.ChangeState.Copied);
_changes.Add(change);
diff --git a/src/Commands/QueryStashChanges.cs b/src/Commands/QueryStashChanges.cs
index 7fc27ea3..92240569 100644
--- a/src/Commands/QueryStashChanges.cs
+++ b/src/Commands/QueryStashChanges.cs
@@ -9,8 +9,10 @@ namespace SourceGit.Commands
///
public partial class QueryStashChanges : Command
{
- [GeneratedRegex(@"^([MADRC])\s+(.+)$")]
+ [GeneratedRegex(@"^([MADC])\s+(.+)$")]
private static partial Regex REG_FORMAT();
+ [GeneratedRegex(@"^R[0-9]{0,4}\s+(.+)$")]
+ private static partial Regex REG_RENAME_FORMAT();
public QueryStashChanges(string repo, string stash)
{
@@ -31,7 +33,17 @@ namespace SourceGit.Commands
{
var match = REG_FORMAT().Match(line);
if (!match.Success)
+ {
+ match = REG_RENAME_FORMAT().Match(line);
+ if (match.Success)
+ {
+ var renamed = new Models.Change() { Path = match.Groups[1].Value };
+ renamed.Set(Models.ChangeState.Renamed);
+ outs.Add(renamed);
+ }
+
continue;
+ }
var change = new Models.Change() { Path = match.Groups[2].Value };
var status = match.Groups[1].Value;
@@ -50,10 +62,6 @@ namespace SourceGit.Commands
change.Set(Models.ChangeState.Deleted);
outs.Add(change);
break;
- case 'R':
- change.Set(Models.ChangeState.Renamed);
- outs.Add(change);
- break;
case 'C':
change.Set(Models.ChangeState.Copied);
outs.Add(change);
diff --git a/src/Commands/Stash.cs b/src/Commands/Stash.cs
index 7acfdf38..7d1a269b 100644
--- a/src/Commands/Stash.cs
+++ b/src/Commands/Stash.cs
@@ -82,7 +82,7 @@ namespace SourceGit.Commands
public bool Pop(string name)
{
- Args = $"stash pop -q \"{name}\"";
+ Args = $"stash pop -q --index \"{name}\"";
return Exec();
}
diff --git a/src/Converters/DoubleConverters.cs b/src/Converters/DoubleConverters.cs
index 5b7c0a03..c9bd9890 100644
--- a/src/Converters/DoubleConverters.cs
+++ b/src/Converters/DoubleConverters.cs
@@ -4,16 +4,12 @@ namespace SourceGit.Converters
{
public static class DoubleConverters
{
- public static readonly FuncValueConverter Increase =
- new FuncValueConverter(v => v + 1.0);
+ public static readonly FuncValueConverter Increase = new(v => v + 1.0);
- public static readonly FuncValueConverter Decrease =
- new FuncValueConverter(v => v - 1.0);
+ public static readonly FuncValueConverter Decrease = new(v => v - 1.0);
- public static readonly FuncValueConverter ToPercentage =
- new FuncValueConverter(v => (v * 100).ToString("F3") + "%");
+ public static readonly FuncValueConverter ToPercentage = new(v => $"{v * 100:F3}%");
- public static readonly FuncValueConverter OneMinusToPercentage =
- new FuncValueConverter(v => ((1.0 - v) * 100).ToString("F3") + "%");
+ public static readonly FuncValueConverter OneMinusToPercentage = new(v => $"{(1.0 - v) * 100:F3}%");
}
}
diff --git a/src/Converters/FilterModeConverters.cs b/src/Converters/FilterModeConverters.cs
index c486af5e..12ca1c9b 100644
--- a/src/Converters/FilterModeConverters.cs
+++ b/src/Converters/FilterModeConverters.cs
@@ -6,17 +6,14 @@ namespace SourceGit.Converters
public static class FilterModeConverters
{
public static readonly FuncValueConverter ToBorderBrush =
- new FuncValueConverter(v =>
+ new(v =>
{
- switch (v)
+ return v switch
{
- case Models.FilterMode.Included:
- return Brushes.Green;
- case Models.FilterMode.Excluded:
- return Brushes.Red;
- default:
- return Brushes.Transparent;
- }
+ Models.FilterMode.Included => Brushes.Green,
+ Models.FilterMode.Excluded => Brushes.Red,
+ _ => Brushes.Transparent,
+ };
});
}
}
diff --git a/src/Converters/IntConverters.cs b/src/Converters/IntConverters.cs
index f21c5d24..c2542b2a 100644
--- a/src/Converters/IntConverters.cs
+++ b/src/Converters/IntConverters.cs
@@ -7,32 +7,24 @@ namespace SourceGit.Converters
{
public static class IntConverters
{
- public static readonly FuncValueConverter IsGreaterThanZero =
- new FuncValueConverter(v => v > 0);
+ public static readonly FuncValueConverter IsGreaterThanZero = new(v => v > 0);
- public static readonly FuncValueConverter IsGreaterThanFour =
- new FuncValueConverter(v => v > 4);
+ public static readonly FuncValueConverter IsGreaterThanFour = new(v => v > 4);
- public static readonly FuncValueConverter IsZero =
- new FuncValueConverter(v => v == 0);
+ public static readonly FuncValueConverter IsZero = new(v => v == 0);
- public static readonly FuncValueConverter IsOne =
- new FuncValueConverter(v => v == 1);
+ public static readonly FuncValueConverter IsOne = new(v => v == 1);
- public static readonly FuncValueConverter IsNotOne =
- new FuncValueConverter(v => v != 1);
+ public static readonly FuncValueConverter IsNotOne = new(v => v != 1);
- public static readonly FuncValueConverter IsSubjectLengthBad =
- new FuncValueConverter(v => v > ViewModels.Preferences.Instance.SubjectGuideLength);
+ public static readonly FuncValueConverter IsSubjectLengthBad = new(v => v > ViewModels.Preferences.Instance.SubjectGuideLength);
- public static readonly FuncValueConverter IsSubjectLengthGood =
- new FuncValueConverter(v => v <= ViewModels.Preferences.Instance.SubjectGuideLength);
+ public static readonly FuncValueConverter IsSubjectLengthGood = new(v => v <= ViewModels.Preferences.Instance.SubjectGuideLength);
- public static readonly FuncValueConverter ToTreeMargin =
- new FuncValueConverter(v => new Thickness(v * 16, 0, 0, 0));
+ public static readonly FuncValueConverter ToTreeMargin = new(v => new Thickness(v * 16, 0, 0, 0));
public static readonly FuncValueConverter ToBookmarkBrush =
- new FuncValueConverter(bookmark =>
+ new(bookmark =>
{
if (bookmark == 0)
return Application.Current?.FindResource("Brush.FG1") as IBrush;
diff --git a/src/Converters/InteractiveRebaseActionConverters.cs b/src/Converters/InteractiveRebaseActionConverters.cs
index dbd183bd..7478e3d0 100644
--- a/src/Converters/InteractiveRebaseActionConverters.cs
+++ b/src/Converters/InteractiveRebaseActionConverters.cs
@@ -6,46 +6,34 @@ namespace SourceGit.Converters
public static class InteractiveRebaseActionConverters
{
public static readonly FuncValueConverter ToIconBrush =
- new FuncValueConverter(v =>
+ new(v =>
{
- switch (v)
+ return v switch
{
- case Models.InteractiveRebaseAction.Pick:
- return Brushes.Green;
- case Models.InteractiveRebaseAction.Edit:
- return Brushes.Orange;
- case Models.InteractiveRebaseAction.Reword:
- return Brushes.Orange;
- case Models.InteractiveRebaseAction.Squash:
- return Brushes.LightGray;
- case Models.InteractiveRebaseAction.Fixup:
- return Brushes.LightGray;
- default:
- return Brushes.Red;
- }
+ Models.InteractiveRebaseAction.Pick => Brushes.Green,
+ Models.InteractiveRebaseAction.Edit => Brushes.Orange,
+ Models.InteractiveRebaseAction.Reword => Brushes.Orange,
+ Models.InteractiveRebaseAction.Squash => Brushes.LightGray,
+ Models.InteractiveRebaseAction.Fixup => Brushes.LightGray,
+ _ => Brushes.Red,
+ };
});
public static readonly FuncValueConverter ToName =
- new FuncValueConverter(v =>
+ new(v =>
{
- switch (v)
+ return v switch
{
- case Models.InteractiveRebaseAction.Pick:
- return "Pick";
- case Models.InteractiveRebaseAction.Edit:
- return "Edit";
- case Models.InteractiveRebaseAction.Reword:
- return "Reword";
- case Models.InteractiveRebaseAction.Squash:
- return "Squash";
- case Models.InteractiveRebaseAction.Fixup:
- return "Fixup";
- default:
- return "Drop";
- }
+ Models.InteractiveRebaseAction.Pick => "Pick",
+ Models.InteractiveRebaseAction.Edit => "Edit",
+ Models.InteractiveRebaseAction.Reword => "Reword",
+ Models.InteractiveRebaseAction.Squash => "Squash",
+ Models.InteractiveRebaseAction.Fixup => "Fixup",
+ _ => "Drop",
+ };
});
public static readonly FuncValueConverter CanEditMessage =
- new FuncValueConverter(v => v == Models.InteractiveRebaseAction.Reword || v == Models.InteractiveRebaseAction.Squash);
+ new(v => v == Models.InteractiveRebaseAction.Reword || v == Models.InteractiveRebaseAction.Squash);
}
}
diff --git a/src/Converters/ListConverters.cs b/src/Converters/ListConverters.cs
index 81cac8b7..9c379e6b 100644
--- a/src/Converters/ListConverters.cs
+++ b/src/Converters/ListConverters.cs
@@ -8,18 +8,18 @@ namespace SourceGit.Converters
public static class ListConverters
{
public static readonly FuncValueConverter ToCount =
- new FuncValueConverter(v => v == null ? " (0)" : $" ({v.Count})");
+ new(v => v == null ? " (0)" : $" ({v.Count})");
public static readonly FuncValueConverter IsNullOrEmpty =
- new FuncValueConverter(v => v == null || v.Count == 0);
+ new(v => v == null || v.Count == 0);
public static readonly FuncValueConverter IsNotNullOrEmpty =
- new FuncValueConverter(v => v != null && v.Count > 0);
+ new(v => v != null && v.Count > 0);
public static readonly FuncValueConverter, List> Top100Changes =
- new FuncValueConverter, List>(v => (v == null || v.Count < 100) ? v : v.GetRange(0, 100));
+ new(v => (v == null || v.Count < 100) ? v : v.GetRange(0, 100));
public static readonly FuncValueConverter IsOnlyTop100Shows =
- new FuncValueConverter(v => v != null && v.Count > 100);
+ new(v => v != null && v.Count > 100);
}
}
diff --git a/src/Converters/PathConverters.cs b/src/Converters/PathConverters.cs
index dd7cfa49..bd945304 100644
--- a/src/Converters/PathConverters.cs
+++ b/src/Converters/PathConverters.cs
@@ -22,7 +22,7 @@ namespace SourceGit.Converters
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length;
if (v.StartsWith(home, StringComparison.Ordinal))
- return "~" + v.Substring(prefixLen);
+ return $"~{v.AsSpan()[prefixLen..]}";
return v;
});
diff --git a/src/Converters/StringConverters.cs b/src/Converters/StringConverters.cs
index 5e4608c5..f90e18a4 100644
--- a/src/Converters/StringConverters.cs
+++ b/src/Converters/StringConverters.cs
@@ -21,7 +21,7 @@ namespace SourceGit.Converters
}
}
- public static readonly ToLocaleConverter ToLocale = new ToLocaleConverter();
+ public static readonly ToLocaleConverter ToLocale = new();
public class ToThemeConverter : IValueConverter
{
@@ -46,7 +46,7 @@ namespace SourceGit.Converters
}
}
- public static readonly ToThemeConverter ToTheme = new ToThemeConverter();
+ public static readonly ToThemeConverter ToTheme = new();
public class FormatByResourceKeyConverter : IValueConverter
{
@@ -62,24 +62,24 @@ namespace SourceGit.Converters
}
}
- public static readonly FormatByResourceKeyConverter FormatByResourceKey = new FormatByResourceKeyConverter();
+ public static readonly FormatByResourceKeyConverter FormatByResourceKey = new();
public static readonly FuncValueConverter ToShortSHA =
- new FuncValueConverter(v => v == null ? string.Empty : (v.Length > 10 ? v.Substring(0, 10) : v));
+ new(v => v == null ? string.Empty : (v.Length > 10 ? v.Substring(0, 10) : v));
public static readonly FuncValueConverter TrimRefsPrefix =
- new FuncValueConverter(v =>
+ new(v =>
{
if (v == null)
return string.Empty;
if (v.StartsWith("refs/heads/", StringComparison.Ordinal))
- return v.Substring(11);
+ return v[11..];
if (v.StartsWith("refs/remotes/", StringComparison.Ordinal))
- return v.Substring(13);
+ return v[13..];
return v;
});
public static readonly FuncValueConverter ContainsSpaces =
- new FuncValueConverter(v => v != null && v.Contains(' '));
+ new(v => v != null && v.Contains(' '));
}
}
diff --git a/src/Models/DateTimeFormat.cs b/src/Models/DateTimeFormat.cs
index 4e71a74f..4e8aa550 100644
--- a/src/Models/DateTimeFormat.cs
+++ b/src/Models/DateTimeFormat.cs
@@ -32,17 +32,17 @@ namespace SourceGit.Models
public static readonly List Supported = new List
{
- new DateTimeFormat("yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss"),
- new DateTimeFormat("yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss"),
- new DateTimeFormat("yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss"),
- new DateTimeFormat("MM/dd/yyyy", "MM/dd/yyyy HH:mm:ss"),
- new DateTimeFormat("MM.dd.yyyy", "MM.dd.yyyy HH:mm:ss"),
- new DateTimeFormat("MM-dd-yyyy", "MM-dd-yyyy HH:mm:ss"),
- new DateTimeFormat("dd/MM/yyyy", "dd/MM/yyyy HH:mm:ss"),
- new DateTimeFormat("dd.MM.yyyy", "dd.MM.yyyy HH:mm:ss"),
- new DateTimeFormat("dd-MM-yyyy", "dd-MM-yyyy HH:mm:ss"),
- new DateTimeFormat("MMM d yyyy", "MMM d yyyy HH:mm:ss"),
- new DateTimeFormat("d MMM yyyy", "d MMM yyyy HH:mm:ss"),
+ new DateTimeFormat("yyyy/MM/dd", "yyyy/MM/dd, HH:mm:ss"),
+ new DateTimeFormat("yyyy.MM.dd", "yyyy.MM.dd, HH:mm:ss"),
+ new DateTimeFormat("yyyy-MM-dd", "yyyy-MM-dd, HH:mm:ss"),
+ new DateTimeFormat("MM/dd/yyyy", "MM/dd/yyyy, HH:mm:ss"),
+ new DateTimeFormat("MM.dd.yyyy", "MM.dd.yyyy, HH:mm:ss"),
+ new DateTimeFormat("MM-dd-yyyy", "MM-dd-yyyy, HH:mm:ss"),
+ new DateTimeFormat("dd/MM/yyyy", "dd/MM/yyyy, HH:mm:ss"),
+ new DateTimeFormat("dd.MM.yyyy", "dd.MM.yyyy, HH:mm:ss"),
+ new DateTimeFormat("dd-MM-yyyy", "dd-MM-yyyy, HH:mm:ss"),
+ new DateTimeFormat("MMM d yyyy", "MMM d yyyy, HH:mm:ss"),
+ new DateTimeFormat("d MMM yyyy", "d MMM yyyy, HH:mm:ss"),
};
private static readonly DateTime _example = new DateTime(2025, 1, 31, 8, 0, 0, DateTimeKind.Local);
diff --git a/src/Models/Locales.cs b/src/Models/Locales.cs
index d5e1534c..802e88ef 100644
--- a/src/Models/Locales.cs
+++ b/src/Models/Locales.cs
@@ -17,6 +17,7 @@ namespace SourceGit.Models
new Locale("Русский", "ru_RU"),
new Locale("简体中文", "zh_CN"),
new Locale("繁體中文", "zh_TW"),
+ new Locale("日本語", "ja_JP"),
};
public Locale(string name, string key)
diff --git a/src/Native/OS.cs b/src/Native/OS.cs
index f11d1e7f..320b5208 100644
--- a/src/Native/OS.cs
+++ b/src/Native/OS.cs
@@ -162,6 +162,15 @@ namespace SourceGit.Native
_backend.OpenWithDefaultEditor(file);
}
+ public static string GetAbsPath(string root, string sub)
+ {
+ var fullpath = Path.Combine(root, sub);
+ if (OperatingSystem.IsWindows())
+ return fullpath.Replace('/', '\\');
+
+ return fullpath;
+ }
+
private static void UpdateGitVersion()
{
if (string.IsNullOrEmpty(_gitExecutable) || !File.Exists(_gitExecutable))
diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml
index 7144ef43..bbfe4545 100644
--- a/src/Resources/Locales/de_DE.axaml
+++ b/src/Resources/Locales/de_DE.axaml
@@ -186,7 +186,6 @@
Kopieren
Kopiere gesamten Text
Pfad kopieren
- Dateinamen kopieren
Branch erstellen...
Basierend auf:
Erstellten Branch auschecken
@@ -650,7 +649,6 @@
Lokale Änderungen stashen
Anwenden
Entfernen
- Anwenden und entfernen
Stash entfernen
Entfernen:
Stashes
diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml
index f24d6c65..61140173 100644
--- a/src/Resources/Locales/en_US.axaml
+++ b/src/Resources/Locales/en_US.axaml
@@ -160,6 +160,7 @@
Add Sample GitLab Issue Rule
Add Sample GitLab Merge Request Rule
Add Sample Jira Rule
+ Add Sample Azure DevOps Rule
New Rule
Issue Regex Expression:
Rule Name:
@@ -185,7 +186,7 @@
Copy
Copy All Text
Copy Path
- Copy File Name
+ Copy Full Path
Create Branch...
Based On:
Check out the created branch
@@ -654,7 +655,6 @@
Stash Local Changes
Apply
Drop
- Pop
Save as Patch...
Drop Stash
Drop:
@@ -719,6 +719,7 @@
Trigger click event
Commit (Edit)
Stage all changes and commit
+ You have staged {0} file(s) but only {1} file(s) displayed ({2} files are filtered out). Do you want to continue?
Empty commit detected! Do you want to continue (--allow-empty)?
CONFLICTS DETECTED
FILE CONFLICTS ARE RESOLVED
diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml
index e7e953e5..8b4c350f 100644
--- a/src/Resources/Locales/es_ES.axaml
+++ b/src/Resources/Locales/es_ES.axaml
@@ -161,6 +161,7 @@
Añadir Regla de Ejemplo para Pull Requests de Gitee
Añadir Regla de Ejemplo para Github
Añadir Regla de Ejemplo para Jira
+ Añadir Regla de Ejemplo para Azure DevOps
Añadir Regla de Ejemplo para Incidencias de GitLab
Añadir Regla de Ejemplo para Merge Requests de GitLab
Nueva Regla
@@ -188,7 +189,7 @@
Copiar
Copiar Todo el Texto
Copiar Ruta
- Copiar Nombre del Archivo
+ Copiar Ruta Completa
Crear Rama...
Basado En:
Checkout de la rama creada
@@ -475,6 +476,7 @@
Commits en el historial
Mostrar hora del autor en lugar de la hora del commit en el gráfico
Mostrar hijos en los detalles de commit
+ Mostrar etiquetas en el gráfico de commit
Longitud de la guía del asunto
GIT
Habilitar Auto CRLF
@@ -604,7 +606,7 @@
Por Fecha de Creación
Por Nombre (Ascendiente)
Por Nombre (Descendiente)
- Sort
+ Ordenar
Abrir en Terminal
Usar tiempo relativo en las historias
WORKTREES
@@ -657,7 +659,6 @@
Stash Cambios Locales
Aplicar
Eliminar
- Pop
Guardar como Parche...
Eliminar Stash
Eliminar:
diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml
index 19c0859c..bf238aa2 100644
--- a/src/Resources/Locales/fr_FR.axaml
+++ b/src/Resources/Locales/fr_FR.axaml
@@ -16,13 +16,19 @@
Suivre la branche :
Suivi de la branche distante
Assistant IA
+ RE-GÉNERER
Utiliser l'IA pour générer un message de commit
+ APPLIQUER COMME MESSAGE DE COMMIT
Appliquer
Fichier de patch :
Selectionner le fichier .patch à appliquer
Ignorer les changements d'espaces blancs
Appliquer le patch
Espaces blancs :
+ Appliquer le Stash
+ Supprimer après application
+ Rétablir les changements de l'index
+ Stash:
Archiver...
Enregistrer l'archive sous :
Sélectionnez le chemin du fichier d'archive
@@ -39,6 +45,7 @@
Comparer avec HEAD
Comparer avec le worktree
Copier le nom de la branche
+ Action personnalisée
Supprimer ${0}$...
Supprimer {0} branches sélectionnées
Rejeter tous les changements
@@ -54,6 +61,7 @@
Renommer ${0}$...
Définir la branche de suivi...
Comparer les branches
+ Branche amont invalide !
Octets
ANNULER
Réinitialiser à la révision parente
@@ -92,6 +100,7 @@
Récupérer ce commit
Cherry-Pick ce commit
Cherry-Pick ...
+ Checkout Commit
Comparer avec HEAD
Comparer avec le worktree
Copier les informations
@@ -150,9 +159,10 @@
Ajouter une règle d'exemple Gitee
Ajouter une règle d'exemple pour Pull Request Gitee
Ajouter une règle d'exemple Github
- Ajouter une règle d'exemple Jira
Ajouter une règle d'exemple pour Incidents GitLab
Ajouter une règle d'exemple pour Merge Request GitLab
+ Ajouter une règle d'exemple Jira
+ Ajouter une règle d'exemple Azure DevOps
Nouvelle règle
Issue Regex Expression:
Nom de règle :
@@ -177,8 +187,8 @@
Type de Changement :
Copier
Copier tout le texte
- Copier le nom de fichier
Copier le chemin
+ Copier le chemin complet
Créer une branche...
Basé sur :
Récupérer la branche créée
@@ -187,6 +197,7 @@
Stash & Réappliquer
Nom de la nouvelle branche :
Entrez le nom de la branche.
+ Les espaces seront remplacés par des tirets.
Créer une branche locale
Créer un tag...
Nouveau tag à :
@@ -583,13 +594,20 @@
Passer cette version
Mise à jour du logiciel
Il n'y a pas de mise à jour pour le moment.
+ Définir la branche de suivi
+ Branche :
+ Escamoter la branche amont
+ Branche amont:
Copier le SHA
- Squash Commits
+ Aller à
+ Squash les commits
Dans :
Clé privée SSH :
Chemin du magasin de clés privées SSH
START
Stash
+ Auto-restauration après le stash
+ Vos fichiers de travail sont inchangés, mais un stash a été sauvegardé.
Inclure les fichiers non-suivis
Garder les fichiers indexés
Message :
@@ -599,7 +617,7 @@
Stash les changements locaux
Appliquer
Effacer
- Extraire
+ Sauver comme Patch...
Effacer le Stash
Effacer :
Stashes
diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml
index d002dfef..85038d9e 100644
--- a/src/Resources/Locales/it_IT.axaml
+++ b/src/Resources/Locales/it_IT.axaml
@@ -161,6 +161,7 @@
Aggiungi una regola di esempio per un Pull Request Gitee
Aggiungi una regola di esempio per GitHub
Aggiungi una regola di esempio per Jira
+ Aggiungi una regola di esempio per Azure DevOps
Aggiungi una regola di esempio per Issue GitLab
Aggiungi una regola di esempio per una Merge Request GitLab
Nuova Regola
@@ -188,7 +189,6 @@
Copia
Copia Tutto il Testo
Copia Percorso
- Copia Nome File
Crea Branch...
Basato Su:
Checkout del Branch Creato
@@ -658,7 +658,6 @@
Stasha Modifiche Locali
Applica
Elimina
- Estrai
Salva come Patch...
Elimina Stash
Elimina:
diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml
new file mode 100644
index 00000000..21255221
--- /dev/null
+++ b/src/Resources/Locales/ja_JP.axaml
@@ -0,0 +1,747 @@
+
+
+
+
+ 概要
+ SourceGitについて
+ オープンソース & フリーなGit GUIクライアント
+ ワークツリーを追加
+ チェックアウトする内容:
+ 既存のブランチ
+ 新しいブランチを作成
+ 場所:
+ ワークツリーのパスを入力してください。相対パスも使用することができます。
+ ブランチの名前:
+ 任意。デフォルトでは宛先フォルダ名が使用されます。
+ 追跡するブランチ:
+ 追跡中のリモートブランチ
+ OpenAI アシスタント
+ 再生成
+ OpenAIを使用してコミットメッセージを生成
+ コミットメッセージとして適用
+ 適用
+ パッチファイル:
+ 適用する .patchファイルを選択
+ 空白文字の変更を無視
+ パッチを適用
+ 空白文字:
+ スタッシュを適用
+ 適用後に削除
+ インデックスの変更を復元
+ スタッシュ:
+ アーカイブ...
+ アーカイブの保存先:
+ アーカイブファイルのパスを選択
+ リビジョン:
+ アーカイブ
+ SourceGit Askpass
+ 変更されていないとみなされるファイル
+ 変更されていないとみなされるファイルはありません
+ 削除
+ バイナリファイルはサポートされていません!!!
+ Blame
+ BLAMEではこのファイルはサポートされていません!!!
+ ${0}$ をチェックアウトする...
+ HEADと比較
+ ワークツリーと比較
+ ブランチ名をコピー
+ カスタムアクション
+ ${0}$を削除...
+ 選択中の{0}個のブランチを削除
+ すべての変更を破棄
+ ${0}$ へ早送りする
+ ${0}$ から ${1}$ へフェッチする
+ Git Flow - Finish ${0}$
+ ${0}$ を ${1}$ にマージする...
+ 選択中の{0}個のブランチを現在のブランチにマージする
+ ${0}$ をプルする
+ ${0}$ を ${1}$ にプルする...
+ ${0}$ をプッシュする
+ ${0}$ を ${1}$ でリベースする...
+ ${0}$ をリネームする...
+ トラッキングブランチを設定...
+ ブランチの比較
+ 無効な上流ブランチ!
+ バイト
+ キャンセル
+ このリビジョンにリセット
+ 親リビジョンにリセット
+ コミットメッセージを生成
+ 変更表示の切り替え
+ ファイルとディレクトリのリストを表示
+ パスのリストを表示
+ ファイルシステムのツリーを表示
+ ブランチをチェックアウト
+ コミットをチェックアウト
+ 警告: コミットをチェックアウトするとHEADが切断されます
+ コミット:
+ ブランチ:
+ ローカルの変更:
+ 破棄
+ スタッシュして再適用
+ チェリーピック
+ ソースをコミットメッセージに追加
+ コミット(複数可):
+ すべての変更をコミット
+ メインライン:
+ 通常、マージをチェリーピックすることはできません。どちらのマージ元をメインラインとして扱うべきかが分からないためです。このオプションを使用すると、指定した親に対して変更を再適用する形でチェリーピックを実行できます。
+ スタッシュをクリア
+ すべてのスタッシュをクリアします。続行しますか?
+ リモートリポジトリをクローン
+ 追加の引数:
+ リポジトリをクローンする際の追加パラメータ(任意)。
+ ローカル名:
+ リポジトリの名前(任意)。
+ 親フォルダ:
+ サブモジュールを初期化して更新
+ リポジトリのURL:
+ 閉じる
+ エディタ
+ このコミットをチェリーピック
+ チェリーピック...
+ コミットをチェックアウト
+ HEADと比較
+ ワークツリーと比較
+ 情報をコピー
+ SHAをコピー
+ カスタムアクション
+ ${0}$ ブランチをここにインタラクティブリベース
+ ${0}$ にマージ
+ マージ...
+ ${0}$ をここにリベース
+ ${0}$ ブランチをここにリセット
+ コミットを戻す
+ 書き直す
+ パッチとして保存...
+ 親にスカッシュ
+ 子コミットをここにスカッシュ
+ 変更
+ 変更を検索...
+ ファイル
+ LFSファイル
+ ファイルを検索...
+ サブモジュール
+ コミットの情報
+ 著者
+ 変更
+ 子
+ コミッター
+ このコミットを含む参照を確認
+ コミットが含まれるか確認
+ 最初の100件の変更のみが表示されています。すべての変更は'変更'タブで確認できます。
+ メッセージ
+ 親
+ 参照
+ SHA
+ ブラウザで開く
+ コミットのタイトルを入力
+ 説明
+ リポジトリの設定
+ コミットテンプレート
+ テンプレート名:
+ テンプレート内容:
+ カスタムアクション
+ 引数:
+ ${REPO} - リポジトリのパス; ${BRANCH} - 選択中のブランチ; ${SHA} - 選択中のコミットのSHA
+ 実行ファイル:
+ 名前:
+ スコープ:
+ ブランチ
+ コミット
+ リポジトリ
+ アクションの終了を待機
+ Eメールアドレス
+ Eメールアドレス
+ GIT
+ 自動的にリモートからフェッチ 間隔:
+ 分(s)
+ リモートの初期値
+ ISSUEトラッカー
+ サンプルのGitee Issueルールを追加
+ サンプルのGiteeプルリクエストルールを追加
+ サンプルのGithubルールを追加
+ サンプルのGitLab Issueルールを追加
+ サンプルのGitLabマージリクエストルールを追加
+ サンプルのJiraルールを追加
+ サンプルのAzure DevOpsルールを追加
+ 新しいルール
+ Issueの正規表現:
+ ルール名:
+ リザルトURL:
+ 正規表現のグループ値に$1, $2を使用してください。
+ AI
+ 優先するサービス:
+ 優先するサービスが設定されている場合、SourceGitはこのリポジトリでのみそれを使用します。そうでない場合で複数サービスが利用できる場合は、そのうちの1つを選択するためのコンテキストメニューが表示されます。
+ HTTP プロキシ
+ このリポジトリで使用するHTTPプロキシ
+ ユーザー名
+ このリポジトリにおけるユーザー名
+ ワークスペース
+ 色
+ 起動時にタブを復元
+ Conventional Commitヘルパー
+ 破壊的変更:
+ 閉じたIssue:
+ 詳細な変更:
+ スコープ:
+ 短い説明:
+ 変更の種類:
+ コピー
+ すべてのテキストをコピー
+ パスをコピー
+ 絶対パスをコピー
+ ブランチを作成...
+ 派生元:
+ 作成したブランチにチェックアウト
+ ローカルの変更:
+ 破棄
+ スタッシュして再適用
+ 新しいブランチの名前:
+ ブランチの名前を入力
+ スペースはダッシュに置き換えられます。
+ ローカルブランチを作成
+ タグを作成...
+ 付与されるコミット:
+ GPG署名を使用
+ タグメッセージ:
+ 任意。
+ タグの名前:
+ 推奨フォーマット: v1.0.0-alpha
+ 作成後にすべてのリモートにプッシュ
+ 新しいタグを作成
+ 種類:
+ 注釈付き
+ 軽量
+ Ctrlキーを押しながらクリックで実行
+ 切り取り
+ ブランチを削除
+ ブランチ:
+ リモートブランチを削除しようとしています!!!
+ もしリモートブランチを削除する場合、${0}$も削除します。
+ 複数のブランチを削除
+ 一度に複数のブランチを削除しようとしています! 操作を行う前に再度確認してください!
+ リモートを削除
+ リモート:
+ パス:
+ 対象:
+ すべての子ノードがリストから削除されます。
+ グループを削除
+ これはリストからのみ削除され、ディスクには保存されません!
+ リポジトリを削除
+ サブモジュールを削除
+ サブモジュールのパス:
+ タグを削除
+ タグ:
+ リモートリポジトリから削除
+ バイナリの差分
+ NEW
+ OLD
+ コピー
+ ファイルモードが変更されました
+ 先頭の差分
+ 空白の変更を無視
+ 最後の差分
+ LFSオブジェクトの変更
+ 次の差分
+ 変更がない、もしくはEOLの変更のみ
+ 前の差分
+ パッチとして保存
+ 隠されたシンボルを表示
+ 差分の分割表示
+ サブモジュール
+ 新規
+ スワップ
+ シンタックスハイライト
+ 行の折り返し
+ ブロックナビゲーションを有効化
+ マージツールで開く
+ すべての行を表示
+ 表示する行数を減らす
+ 表示する行数を増やす
+ ファイルを選択すると、変更内容が表示されます
+ マージツールで開く
+ 変更を破棄
+ ワーキングディレクトリのすべての変更を破棄
+ 変更:
+ 無視したファイルを含める
+ {0}個の変更を破棄します。
+ この操作を元に戻すことはできません!!!
+ ブックマーク:
+ 新しい名前:
+ 対象:
+ 選択中のグループを編集
+ 選択中のリポジトリを編集
+ カスタムアクションを実行
+ アクション名:
+ (チェックアウトせずに)ブランチを早送りする
+ フェッチ
+ すべてのリモートをフェッチ
+ ローカル参照を強制的に上書き
+ タグなしでフェッチ
+ リモート:
+ リモートの変更をフェッチ
+ 変更されていないとみなされる
+ 破棄...
+ {0}個のファイルを破棄...
+ 選択された行の変更を破棄
+ 外部マージツールで開く
+ ${0}$ を使用して解決
+ パッチとして保存...
+ ステージ
+ {0}個のファイルをステージ...
+ 選択された行の変更をステージ
+ スタッシュ...
+ {0}個のファイルをスタッシュ...
+ アンステージ
+ {0}個のファイルをアンステージ...
+ 選択された行の変更をアンステージ
+ 相手の変更を使用 (checkout --theirs)
+ 自分の変更を使用 (checkout --ours)
+ ファイルの履歴
+ コンテンツ
+ 変更
+ Git-Flow
+ 開発ブランチ:
+ Feature:
+ Feature プレフィックス:
+ FLOW - Finish Feature
+ FLOW - Finish Hotfix
+ FLOW - Finish Release
+ 対象:
+ Hotfix:
+ Hotfix プレフィックス:
+ Git-Flowを初期化
+ ブランチを保持
+ プロダクション ブランチ:
+ Release:
+ Release プレフィックス:
+ Start Feature...
+ FLOW - Start Feature
+ Start Hotfix...
+ FLOW - Start Hotfix
+ 名前を入力
+ Start Release...
+ FLOW - Start Release
+ Versionタグ プレフィックス:
+ Git LFS
+ トラックパターンを追加...
+ パターンをファイル名として扱う
+ カスタム パターン:
+ Git LFSにトラックパターンを追加
+ フェッチ
+ LFSオブジェクトをフェッチ
+ `git lfs fetch`を実行して、Git LFSオブジェクトをダウンロードします。ワーキングコピーは更新されません。
+ Git LFSフックをインストール
+ ロックを表示
+ ロックされているファイルはありません
+ ロック
+ 私のロックのみ表示
+ LFSロック
+ ロック解除
+ 強制的にロック解除
+ 削除
+ `git lfs prune`を実行して、ローカルの保存領域から古いLFSファイルを削除します。
+ プル
+ LFSオブジェクトをプル
+ `git lfs pull`を実行して、現在の参照とチェックアウトのすべてのGit LFSファイルをダウンロードします。
+ プッシュ
+ LFSオブジェクトをプッシュ
+ キュー内の大容量ファイルをGit LFSエンドポイントにプッシュします。
+ リモート:
+ {0}という名前のファイルをトラック
+ すべての*{0}ファイルをトラック
+ 履歴
+ 著者
+ 著者時間
+ グラフ & コミットのタイトル
+ SHA
+ 日時
+ {0} コミットを選択しました
+ 'Ctrl'キーまたは'Shift'キーを押すと、複数のコミットを選択できます。
+ ⌘ または ⇧ キーを押して複数のコミットを選択します。
+ TIPS:
+ キーボードショートカットを確認
+ 総合
+ 現在のポップアップをキャンセル
+ 新しくリポジトリをクローン
+ 現在のページを閉じる
+ 前のページに移動
+ 次のページに移動
+ 新しいページを作成
+ 設定ダイアログを開く
+ リポジトリ
+ ステージ済みの変更をコミット
+ ステージ済みの変更をコミットしてプッシュ
+ 全ての変更をステージしてコミット
+ 選択中のコミットから新たなブランチを作成
+ 選択した変更を破棄
+ 直接フェッチを実行
+ ダッシュボードモード (初期値)
+ 直接プルを実行
+ 直接プッシュを実行
+ 現在のリポジトリを強制的に再読み込み
+ 選択中の変更をステージ/アンステージ
+ コミット検索モード
+ '変更'に切り替える
+ '履歴'に切り替える
+ 'スタッシュ'に切り替える
+ テキストエディタ
+ 検索パネルを閉じる
+ 次のマッチを検索
+ 前のマッチを検索
+ 検索パネルを開く
+ ステージ
+ アンステージ
+ 破棄
+ リポジトリの初期化
+ パス:
+ チェリーピックが進行中です。'中止'を押すと元のHEADが復元されます。
+ コミットを処理中
+ マージリクエストが進行中です。'中止'を押すと元のHEADが復元されます。
+ マージ中
+ リベースが進行中です。'中止'を押すと元のHEADが復元されます。
+ 停止しました
+ 元に戻す処理が進行中です。'中止'を押すと元のHEADが復元されます。
+ コミットを元に戻しています
+ インタラクティブ リベース
+ 対象のブランチ:
+ On:
+ ブラウザで開く
+ リンクをコピー
+ エラー
+ 通知
+ ブランチのマージ
+ 宛先:
+ マージオプション:
+ ソースブランチ:
+ マージ (複数)
+ すべての変更をコミット
+ マージ戦略:
+ 対象:
+ リポジトリノードの移動
+ 親ノードを選択:
+ 名前:
+ Gitが設定されていません。まず[設定]に移動して設定を行ってください。
+ アプリケーションデータのディレクトリを開く
+ 外部ツールで開く...
+ 任意。
+ 新しいページを開く
+ ブックマーク
+ タブを閉じる
+ 他のタブを閉じる
+ 右のタブを閉じる
+ リポジトリパスをコピー
+ リポジトリ
+ 貼り付け
+ たった今
+ {0} 分前
+ 1 時間前
+ {0} 時間前
+ 昨日
+ {0} 日前
+ 先月
+ {0} ヶ月前
+ 昨年
+ {0} 年前
+ 設定
+ AI
+ 差分分析プロンプト
+ APIキー
+ タイトル生成プロンプト
+ モデル
+ 名前
+ サーバー
+ ストリーミングを有効化
+ 外観
+ デフォルトのフォント
+ エディタのタブ幅
+ フォントサイズ
+ デフォルト
+ エディタ
+ 等幅フォント
+ テキストエディタでは等幅フォントのみを使用する
+ テーマ
+ テーマの上書き
+ タイトルバーの固定タブ幅を使用
+ ネイティブウィンドウフレームを使用
+ 差分/マージ ツール
+ インストール パス
+ 差分/マージ ツールのパスを入力
+ ツール
+ 総合
+ 起動時にアップデートを確認
+ 日時のフォーマット
+ 言語
+ コミット履歴
+ グラフにコミット時間の代わりに著者の時間を表示する
+ コミット詳細に子コミットを表示
+ コミットグラフにタグを表示
+ コミットタイトル枠の大きさ
+ GIT
+ 自動CRLFを有効化
+ デフォルトのクローンディレクトリ
+ ユーザー Eメールアドレス
+ グローバルgitのEメールアドレス
+ フェッチ時に--pruneを有効化
+ インストール パス
+ HTTP SSL 検証を有効にする
+ ユーザー名
+ グローバルのgitユーザー名
+ Gitバージョン
+ Git (>= 2.23.0) はこのアプリで必要です
+ GPG 署名
+ コミットにGPG署名を行う
+ タグにGPG署名を行う
+ GPGフォーマット
+ プログラムのインストールパス
+ インストールされたgpgプログラムのパスを入力
+ ユーザー署名キー
+ ユーザーのGPG署名キー
+ 統合
+ シェル/ターミナル
+ シェル/ターミナル
+ パス
+ リモートを削除
+ 対象:
+ 作業ツリーを削除
+ `$GIT_DIR/worktrees` の作業ツリー情報を削除
+ プル
+ ブランチ:
+ すべてのブランチをフェッチ
+ 宛先:
+ ローカルの変更:
+ 破棄
+ スタッシュして再適用
+ タグなしでフェッチ
+ リモート:
+ プル (フェッチ & マージ)
+ マージの代わりにリベースを使用
+ プッシュ
+ サブモジュールがプッシュされていることを確認
+ 強制的にプッシュ
+ ローカル ブランチ:
+ リモート:
+ 変更をリモートにプッシュ
+ リモート ブランチ:
+ 追跡ブランチとして設定
+ すべてのタグをプッシュ
+ リモートにタグをプッシュ
+ すべてのリモートにプッシュ
+ リモート:
+ タグ:
+ 終了
+ 現在のブランチをリベース
+ ローカルの変更をスタッシュして再適用
+ On:
+ リベース:
+ 更新
+ リモートを追加
+ リモートを編集
+ 名前:
+ リモートの名前
+ リポジトリのURL:
+ リモートのgitリポジトリのURL
+ URLをコピー
+ 削除...
+ 編集...
+ フェッチ
+ ブラウザで開く
+ 削除
+ ワークツリーの削除を確認
+ `--force` オプションを有効化
+ 対象:
+ ブランチの名前を編集
+ 新しい名前:
+ このブランチにつける一意な名前
+ ブランチ:
+ 中止
+ リモートから変更を自動取得中...
+ クリーンアップ(GC & Prune)
+ このリポジトリに対して`git gc`コマンドを実行します。
+ すべてのフィルターをクリア
+ リポジトリの設定
+ 続ける
+ カスタムアクション
+ カスタムアクションがありません
+ `--reflog` オプションを有効化
+ ファイルブラウザーで開く
+ ブランチ/タグ/サブモジュールを検索
+ 解除
+ コミットグラフで非表示
+ コミットグラフでフィルター
+ `--first-parent` オプションを有効化
+ レイアウト
+ 水平
+ 垂直
+ コミットの並び順
+ 日時
+ トポロジカルソート
+ ローカル ブランチ
+ HEADに移動
+ ブランチを作成
+ 通知をクリア
+ グラフで現在のブランチを強調表示
+ {0} で開く
+ 外部ツールで開く
+ 更新
+ リモート
+ リモートを追加
+ コミットを検索
+ 著者
+ コミッター
+ ファイル
+ メッセージ
+ SHA
+ 現在のブランチ
+ タグをツリーとして表示
+ スキップ
+ 統計
+ サブモジュール
+ サブモジュールを追加
+ サブモジュールを更新
+ タグ
+ 新しいタグを作成
+ 作成者日時
+ 名前 (昇順)
+ 名前 (降順)
+ ソート
+ ターミナルで開く
+ 履歴に相対時間を使用
+ ワークツリー
+ ワークツリーを追加
+ 削除
+ GitリポジトリのURL
+ 現在のブランチをリビジョンにリセット
+ リセットモード:
+ 移動先:
+ 現在のブランチ:
+ ファイルエクスプローラーで表示
+ コミットを戻す
+ コミット:
+ コミットの変更を戻す
+ コミットメッセージを書き直す
+ 改行には'Shift+Enter'キーを使用します。 'Enter"はOKボタンのホットキーとして機能します。
+ 実行中です。しばらくお待ちください...
+ 保存
+ 名前を付けて保存...
+ パッチが正常に保存されました!
+ リポジトリをスキャン
+ ルートディレクトリ:
+ 更新を確認
+ 新しいバージョンのソフトウェアが利用可能です:
+ 更新の確認に失敗しました!
+ ダウンロード
+ このバージョンをスキップ
+ ソフトウェアの更新
+ 利用可能なアップデートはありません
+ トラッキングブランチを設定
+ ブランチ:
+ 上流ブランチを解除
+ 上流ブランチ:
+ SHAをコピー
+ Go to
+ スカッシュコミット
+ 宛先:
+ SSH プライベートキー:
+ プライベートSSHキーストアのパス
+ スタート
+ スタッシュ
+ スタッシュ後に自動で復元
+ 作業ファイルは変更されず、スタッシュが保存されます。
+ 追跡されていないファイルを含める
+ ステージされたファイルを保持
+ メッセージ:
+ オプション. このスタッシュの名前を入力
+ ステージされた変更のみ
+ 選択したファイルの、ステージされた変更とステージされていない変更の両方がスタッシュされます!!!
+ ローカルの変更をスタッシュ
+ 適用
+ 破棄
+ パッチとして保存
+ スタッシュを破棄
+ 破棄:
+ スタッシュ
+ 変更
+ スタッシュ
+ 統計
+ コミット
+ コミッター
+ 月間
+ 週間
+ コミット:
+ 著者:
+ 概要
+ サブモジュール
+ サブモジュールを追加
+ 相対パスをコピー
+ ネストされたサブモジュールを取得する
+ サブモジュールのリポジトリを開く
+ 相対パス:
+ このモジュールを保存するフォルダの相対パス
+ サブモジュールを削除
+ OK
+ タグ名をコピー
+ タグメッセージをコピー
+ ${0}$ を削除...
+ ${0}$ を ${1}$ にマージ...
+ ${0}$ をプッシュ...
+ URL:
+ サブモジュールを更新
+ すべてのサブモジュール
+ 必要に応じて初期化
+ 再帰的に更新
+ サブモジュール:
+ --remoteオプションを使用
+ 警告
+ ようこそ
+ グループを作成
+ サブグループを作成
+ リポジトリをクローンする
+ 削除
+ ドラッグ & ドロップでフォルダを追加できます. グループを作成したり、変更したりできます。
+ 編集
+ 別のグループに移動
+ すべてのリポジトリを開く
+ リポジトリを開く
+ ターミナルを開く
+ デフォルトのクローンディレクトリ内のリポジトリを再スキャン
+ リポジトリを検索...
+ ソート
+ 変更
+ Git Ignore
+ すべての*{0}ファイルを無視
+ 同じフォルダ内の*{0}ファイルを無視
+ 同じフォルダ内のファイルを無視
+ このファイルのみを無視
+ Amend
+ このファイルを今すぐステージできます。
+ コミット
+ コミットしてプッシュ
+ メッセージのテンプレート/履歴
+ クリックイベントをトリガー
+ コミット (Edit)
+ すべての変更をステージしてコミット
+ 空のコミットが検出されました。続行しますか? (--allow-empty)
+ 競合が検出されました
+ ファイルの競合は解決されました
+ 追跡されていないファイルを含める
+ 最近の入力メッセージはありません
+ コミットテンプレートはありません
+ サインオフ
+ ステージしたファイル
+ ステージを取り消し
+ すべてステージを取り消し
+ 未ステージのファイル
+ ステージへ移動
+ すべてステージへ移動
+ 変更されていないとみなしたものを表示
+ テンプレート: ${0}$
+ 選択したファイルを右クリックし、競合を解決する操作を選択してください。
+ ワークスペース:
+ ワークスペースを設定...
+ ワークツリー
+ パスをコピー
+ ロック
+ 削除
+ ロック解除
+
diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml
index e811cf3e..4ee6cdbc 100644
--- a/src/Resources/Locales/pt_BR.axaml
+++ b/src/Resources/Locales/pt_BR.axaml
@@ -168,6 +168,7 @@
RASTREADOR DE PROBLEMAS
Adicionar Regra de Exemplo do Github
Adicionar Regra de Exemplo do Jira
+ Adicionar Regra de Exemplo do Azure DevOps
Adicionar Regra de Exemplo do GitLab
Adicionar regra de exemplo de Merge Request do GitLab
Nova Regra
@@ -195,7 +196,6 @@
Copiar
Copiar todo o texto
Copiar Caminho
- Copiar Nome do Arquivo
Criar Branch...
Baseado Em:
Checar o branch criado
@@ -619,7 +619,6 @@
Guardar Alterações Locais
Aplicar
Descartar
- Pop
Descartar Stash
Descartar:
Stashes
diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml
index 707c9ed9..2ea274d1 100644
--- a/src/Resources/Locales/ru_RU.axaml
+++ b/src/Resources/Locales/ru_RU.axaml
@@ -161,6 +161,7 @@
Добавить пример правила запроса скачивания из Gitea
Добавить пример правила для Git
Добавить пример правила Jira
+ Добавить пример правила Azure DevOps
Добавить пример правила выдачи GitLab
Добавить пример правила запроса на слияние в GitLab
Новое правило
@@ -189,7 +190,7 @@
Копировать
Копировать весь текст
Копировать путь
- Копировать имя файла
+ Копировать полный путь
Создать ветку...
Основан на:
Проверить созданную ветку
@@ -212,7 +213,7 @@
Вид:
С примечаниями
Простой
- Удерживайте Ctrl, чтобы начать сразу
+ Удерживайте Ctrl, чтобы сразу начать
Вырезать
Удалить ветку
Ветка:
@@ -330,7 +331,7 @@
Добавить шаблон отслеживания в LFS Git
Извлечь
Извлечь объекты LFS
- Запустить «git lfs fetch», чтобы загрузить объекты LFS Git. При этом рабочая копия не обновляется.
+ Запустить (git lfs fetch), чтобы загрузить объекты LFS Git. При этом рабочая копия не обновляется.
Установить перехват LFS Git
Показывать блокировки
Нет заблокированных файлов
@@ -340,10 +341,10 @@
Разблокировать
Принудительно разблокировать
Обрезать
- Запустить «git lfs prune», чтобы удалить старые файлы LFS из локального хранилища
+ Запустить (git lfs prune), чтобы удалить старые файлы LFS из локального хранилища
Забрать
Забрать объекты LFS
- Запустить «git lfs pull», чтобы загрузить все файлы LFS Git для текущей ссылки и проверить
+ Запустить (git lfs pull), чтобы загрузить все файлы LFS Git для текущей ссылки и проверить
Выложить
Выложить объекты LFS
Отправляйте большие файлы, помещенные в очередь, в конечную точку LFS Git
@@ -557,7 +558,7 @@
Отказ
Автоматическое извлечение изменений с внешних репозиторий...
Очистить (Сбор мусора и удаление)
- Запустить команду «git gc» для данного репозитория.
+ Запустить команду (git gc) для данного репозитория.
Очистить всё
Настройка репозитория
ПРОДОЛЖИТЬ
@@ -659,7 +660,6 @@
Отложить локальные изменения
Принять
Отбросить
- Применить
Сохранить как заплатку...
Отбросить тайник
Отбросить:
diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml
index 93d08bd0..fec5c780 100644
--- a/src/Resources/Locales/zh_CN.axaml
+++ b/src/Resources/Locales/zh_CN.axaml
@@ -157,6 +157,7 @@
分钟
默认远程
ISSUE追踪
+ 新增匹配Azure DevOps规则
新增匹配Gitee议题规则
新增匹配Gitee合并请求规则
新增匹配Github Issue规则
@@ -188,7 +189,7 @@
复制
复制全部文本
复制路径
- 复制文件名
+ 复制完整路径
新建分支 ...
新分支基于 :
完成后切换到新分支
@@ -658,7 +659,6 @@
贮藏本地变更
应用(apply)
删除(drop)
- 应用并删除(pop)
另存为补丁...
丢弃贮藏确认
丢弃贮藏 :
@@ -723,6 +723,7 @@
触发点击事件
提交(修改原始提交)
自动暂存所有变更并提交
+ 当前有 {0} 个文件在暂存区中,但仅显示了 {1} 个文件({2} 个文件被过滤掉了),是否继续提交?
提交未包含变更文件!是否继续(--allow-empty)?
检测到冲突
文件冲突已解决
diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml
index d5a7a77c..66bcc33a 100644
--- a/src/Resources/Locales/zh_TW.axaml
+++ b/src/Resources/Locales/zh_TW.axaml
@@ -157,6 +157,7 @@
分鐘
預設遠端存放庫
Issue 追蹤
+ 新增符合 Azure DevOps 規則
新增符合 Gitee 議題規則
新增符合 Gitee 合併請求規則
新增符合 GitHub Issue 規則
@@ -188,7 +189,7 @@
複製
複製全部內容
複製路徑
- 複製檔案名稱
+ 複製完整路徑
新增分支...
新分支基於:
完成後切換到新分支
@@ -657,7 +658,6 @@
擱置本機變更
套用 (apply)
刪除 (drop)
- 套用並刪除 (pop)
另存為修補檔 (patch)...
捨棄擱置變更確認
捨棄擱置變更:
@@ -722,6 +722,7 @@
觸發點擊事件
提交 (修改原始提交)
自動暫存全部變更並提交
+ 您已暫存 {0} 檔案,但只顯示 {1} 檔案 ({2} 檔案被篩選器隱藏)。您要繼續嗎?
未包含任何檔案變更! 您是否仍要提交 (--allow-empty)?
檢測到衝突
檔案衝突已解決
diff --git a/src/SourceGit.csproj b/src/SourceGit.csproj
index 3578d59f..852c9e34 100644
--- a/src/SourceGit.csproj
+++ b/src/SourceGit.csproj
@@ -41,17 +41,17 @@
-
-
-
-
-
+
+
+
+
+
-
+
-
+
diff --git a/src/ViewModels/BranchCompare.cs b/src/ViewModels/BranchCompare.cs
index b3c0009c..4edb978c 100644
--- a/src/ViewModels/BranchCompare.cs
+++ b/src/ViewModels/BranchCompare.cs
@@ -163,15 +163,15 @@ namespace SourceGit.ViewModels
};
menu.Items.Add(copyPath);
- var copyFileName = new MenuItem();
- copyFileName.Header = App.Text("CopyFileName");
- copyFileName.Icon = App.CreateMenuIcon("Icons.Copy");
- copyFileName.Click += (_, e) =>
+ var copyFullPath = new MenuItem();
+ copyFullPath.Header = App.Text("CopyFullPath");
+ copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
+ copyFullPath.Click += (_, e) =>
{
- App.CopyText(Path.GetFileName(change.Path));
+ App.CopyText(Native.OS.GetAbsPath(_repo, change.Path));
e.Handled = true;
};
- menu.Items.Add(copyFileName);
+ menu.Items.Add(copyFullPath);
return menu;
}
diff --git a/src/ViewModels/CommitDetail.cs b/src/ViewModels/CommitDetail.cs
index 34ac8308..d04e674b 100644
--- a/src/ViewModels/CommitDetail.cs
+++ b/src/ViewModels/CommitDetail.cs
@@ -425,17 +425,17 @@ namespace SourceGit.ViewModels
ev.Handled = true;
};
- var copyFileName = new MenuItem();
- copyFileName.Header = App.Text("CopyFileName");
- copyFileName.Icon = App.CreateMenuIcon("Icons.Copy");
- copyFileName.Click += (_, e) =>
+ var copyFullPath = new MenuItem();
+ copyFullPath.Header = App.Text("CopyFullPath");
+ copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
+ copyFullPath.Click += (_, e) =>
{
- App.CopyText(Path.GetFileName(change.Path));
+ App.CopyText(Native.OS.GetAbsPath(_repo.FullPath, change.Path));
e.Handled = true;
};
menu.Items.Add(copyPath);
- menu.Items.Add(copyFileName);
+ menu.Items.Add(copyFullPath);
return menu;
}
@@ -562,17 +562,17 @@ namespace SourceGit.ViewModels
ev.Handled = true;
};
- var copyFileName = new MenuItem();
- copyFileName.Header = App.Text("CopyFileName");
- copyFileName.Icon = App.CreateMenuIcon("Icons.Copy");
- copyFileName.Click += (_, e) =>
+ var copyFullPath = new MenuItem();
+ copyFullPath.Header = App.Text("CopyFullPath");
+ copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
+ copyFullPath.Click += (_, e) =>
{
- App.CopyText(Path.GetFileName(file.Path));
+ App.CopyText(Native.OS.GetAbsPath(_repo.FullPath, file.Path));
e.Handled = true;
};
menu.Items.Add(copyPath);
- menu.Items.Add(copyFileName);
+ menu.Items.Add(copyFullPath);
return menu;
}
diff --git a/src/ViewModels/ConfirmCommit.cs b/src/ViewModels/ConfirmCommit.cs
new file mode 100644
index 00000000..cea56948
--- /dev/null
+++ b/src/ViewModels/ConfirmCommit.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace SourceGit.ViewModels
+{
+ public class ConfirmCommit
+ {
+ public string Message
+ {
+ get;
+ private set;
+ }
+
+ public ConfirmCommit(string message, Action onSure)
+ {
+ Message = message;
+ _onSure = onSure;
+ }
+
+ public void Continue()
+ {
+ _onSure?.Invoke();
+ }
+
+ private Action _onSure;
+ }
+}
diff --git a/src/ViewModels/ConfirmCommitWithoutFiles.cs b/src/ViewModels/ConfirmCommitWithoutFiles.cs
deleted file mode 100644
index 3249fba8..00000000
--- a/src/ViewModels/ConfirmCommitWithoutFiles.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-namespace SourceGit.ViewModels
-{
- public class ConfirmCommitWithoutFiles
- {
- public ConfirmCommitWithoutFiles(WorkingCopy wc, bool autoPush)
- {
- _wc = wc;
- _autoPush = autoPush;
- }
-
- public void Continue()
- {
- _wc.CommitWithoutFiles(_autoPush);
- }
-
- private readonly WorkingCopy _wc;
- private bool _autoPush;
- }
-}
diff --git a/src/ViewModels/Launcher.cs b/src/ViewModels/Launcher.cs
index 06479394..8df914fb 100644
--- a/src/ViewModels/Launcher.cs
+++ b/src/ViewModels/Launcher.cs
@@ -48,7 +48,7 @@ namespace SourceGit.ViewModels
{
_ignoreIndexChange = true;
- Pages = new AvaloniaList();
+ Pages = [];
AddNewTab();
var pref = Preferences.Instance;
@@ -205,8 +205,7 @@ namespace SourceGit.ViewModels
return;
}
- if (page == null)
- page = _activePage;
+ page ??= _activePage;
var removeIdx = Pages.IndexOf(page);
var activeIdx = Pages.IndexOf(_activePage);
@@ -239,7 +238,7 @@ namespace SourceGit.ViewModels
CloseRepositoryInTab(one);
}
- Pages = new AvaloniaList { ActivePage };
+ Pages = [ActivePage];
ActiveWorkspace.ActiveIdx = 0;
OnPropertyChanged(nameof(Pages));
@@ -275,22 +274,16 @@ namespace SourceGit.ViewModels
if (!Path.Exists(node.Id))
{
- var ctx = page == null ? ActivePage.Node.Id : page.Node.Id;
- App.RaiseException(ctx, "Repository does NOT exists any more. Please remove it.");
+ App.RaiseException(node.Id, "Repository does NOT exists any more. Please remove it.");
return;
}
var isBare = new Commands.IsBareRepository(node.Id).Result();
- var gitDir = node.Id;
- if (!isBare)
+ var gitDir = isBare ? node.Id : GetRepositoryGitDir(node.Id);
+ if (string.IsNullOrEmpty(gitDir))
{
- gitDir = new Commands.QueryGitDir(node.Id).Result();
- if (string.IsNullOrEmpty(gitDir))
- {
- var ctx = page == null ? ActivePage.Node.Id : page.Node.Id;
- App.RaiseException(ctx, "Given path is not a valid git repository!");
- return;
- }
+ App.RaiseException(node.Id, "Given path is not a valid git repository!");
+ return;
}
var repo = new Repository(isBare, node.Id, gitDir);
@@ -366,9 +359,11 @@ namespace SourceGit.ViewModels
var icon = App.CreateMenuIcon(workspace.IsActive ? "Icons.Check" : "Icons.Workspace");
icon.Fill = workspace.Brush;
- var item = new MenuItem();
- item.Header = workspace.Name;
- item.Icon = icon;
+ var item = new MenuItem
+ {
+ Header = workspace.Name,
+ Icon = icon
+ };
item.Click += (_, e) =>
{
if (!workspace.IsActive)
@@ -382,8 +377,10 @@ namespace SourceGit.ViewModels
menu.Items.Add(new MenuItem() { Header = "-" });
- var configure = new MenuItem();
- configure.Header = App.Text("Workspace.Configure");
+ var configure = new MenuItem
+ {
+ Header = App.Text("Workspace.Configure")
+ };
configure.Click += (_, e) =>
{
App.OpenDialog(new Views.ConfigureWorkspace() { DataContext = new ConfigureWorkspace() });
@@ -400,9 +397,11 @@ namespace SourceGit.ViewModels
return null;
var menu = new ContextMenu();
- var close = new MenuItem();
- close.Header = App.Text("PageTabBar.Tab.Close");
- close.InputGesture = KeyGesture.Parse(OperatingSystem.IsMacOS() ? "⌘+W" : "Ctrl+W");
+ var close = new MenuItem
+ {
+ Header = App.Text("PageTabBar.Tab.Close"),
+ InputGesture = KeyGesture.Parse(OperatingSystem.IsMacOS() ? "⌘+W" : "Ctrl+W")
+ };
close.Click += (_, e) =>
{
CloseTab(page);
@@ -410,8 +409,10 @@ namespace SourceGit.ViewModels
};
menu.Items.Add(close);
- var closeOthers = new MenuItem();
- closeOthers.Header = App.Text("PageTabBar.Tab.CloseOther");
+ var closeOthers = new MenuItem
+ {
+ Header = App.Text("PageTabBar.Tab.CloseOther")
+ };
closeOthers.Click += (_, e) =>
{
CloseOtherTabs();
@@ -419,8 +420,10 @@ namespace SourceGit.ViewModels
};
menu.Items.Add(closeOthers);
- var closeRight = new MenuItem();
- closeRight.Header = App.Text("PageTabBar.Tab.CloseRight");
+ var closeRight = new MenuItem
+ {
+ Header = App.Text("PageTabBar.Tab.CloseRight")
+ };
closeRight.Click += (_, e) =>
{
CloseRightTabs();
@@ -430,9 +433,11 @@ namespace SourceGit.ViewModels
if (page.Node.IsRepository)
{
- var bookmark = new MenuItem();
- bookmark.Header = App.Text("PageTabBar.Tab.Bookmark");
- bookmark.Icon = App.CreateMenuIcon("Icons.Bookmark");
+ var bookmark = new MenuItem
+ {
+ Header = App.Text("PageTabBar.Tab.Bookmark"),
+ Icon = App.CreateMenuIcon("Icons.Bookmark")
+ };
for (int i = 0; i < Models.Bookmarks.Supported.Count; i++)
{
@@ -442,8 +447,10 @@ namespace SourceGit.ViewModels
icon.Fill = Models.Bookmarks.Brushes[i];
var dupIdx = i;
- var setter = new MenuItem();
- setter.Header = icon;
+ var setter = new MenuItem
+ {
+ Header = icon
+ };
setter.Click += (_, e) =>
{
page.Node.Bookmark = dupIdx;
@@ -454,9 +461,11 @@ namespace SourceGit.ViewModels
menu.Items.Add(new MenuItem() { Header = "-" });
menu.Items.Add(bookmark);
- var copyPath = new MenuItem();
- copyPath.Header = App.Text("PageTabBar.Tab.CopyPath");
- copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
+ var copyPath = new MenuItem
+ {
+ Header = App.Text("PageTabBar.Tab.CopyPath"),
+ Icon = App.CreateMenuIcon("Icons.Copy")
+ };
copyPath.Click += (_, e) =>
{
page.CopyPath();
@@ -469,6 +478,37 @@ namespace SourceGit.ViewModels
return menu;
}
+ private string GetRepositoryGitDir(string repo)
+ {
+ var fullpath = Path.Combine(repo, ".git");
+ if (Directory.Exists(fullpath))
+ {
+ if (Directory.Exists(Path.Combine(fullpath, "refs")) &&
+ Directory.Exists(Path.Combine(fullpath, "objects")) &&
+ File.Exists(Path.Combine(fullpath, "HEAD")))
+ return fullpath;
+
+ return null;
+ }
+
+ if (File.Exists(fullpath))
+ {
+ var redirect = File.ReadAllText(fullpath).Trim();
+ if (redirect.StartsWith("gitdir: ", StringComparison.Ordinal))
+ redirect = redirect.Substring(8);
+
+ if (!Path.IsPathRooted(redirect))
+ redirect = Path.GetFullPath(Path.Combine(repo, redirect));
+
+ if (Directory.Exists(redirect))
+ return redirect;
+
+ return null;
+ }
+
+ return new Commands.QueryGitDir(repo).Result();
+ }
+
private void SwitchWorkspace(Workspace to)
{
foreach (var one in Pages)
diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs
index 6ea41e04..6b1e439e 100644
--- a/src/ViewModels/Repository.cs
+++ b/src/ViewModels/Repository.cs
@@ -2513,30 +2513,37 @@ namespace SourceGit.ViewModels
private void AutoFetchImpl(object sender)
{
- if (!_settings.EnableAutoFetch || _isAutoFetching)
- return;
-
- var lockFile = Path.Combine(_gitDir, "index.lock");
- if (File.Exists(lockFile))
- return;
-
- var now = DateTime.Now;
- var desire = _lastFetchTime.AddMinutes(_settings.AutoFetchInterval);
- if (desire > now)
- return;
-
- var remotes = new List();
- lock (_lockRemotes)
+ try
{
- foreach (var remote in _remotes)
- remotes.Add(remote.Name);
- }
+ if (!_settings.EnableAutoFetch || _isAutoFetching)
+ return;
- Dispatcher.UIThread.Invoke(() => IsAutoFetching = true);
- foreach (var remote in remotes)
- new Commands.Fetch(_fullpath, remote, false, false, null) { RaiseError = false }.Exec();
- _lastFetchTime = DateTime.Now;
- Dispatcher.UIThread.Invoke(() => IsAutoFetching = false);
+ var lockFile = Path.Combine(_gitDir, "index.lock");
+ if (File.Exists(lockFile))
+ return;
+
+ var now = DateTime.Now;
+ var desire = _lastFetchTime.AddMinutes(_settings.AutoFetchInterval);
+ if (desire > now)
+ return;
+
+ var remotes = new List();
+ lock (_lockRemotes)
+ {
+ foreach (var remote in _remotes)
+ remotes.Add(remote.Name);
+ }
+
+ Dispatcher.UIThread.Invoke(() => IsAutoFetching = true);
+ foreach (var remote in remotes)
+ new Commands.Fetch(_fullpath, remote, false, false, null) { RaiseError = false }.Exec();
+ _lastFetchTime = DateTime.Now;
+ Dispatcher.UIThread.Invoke(() => IsAutoFetching = false);
+ }
+ catch
+ {
+ // DO nothing, but prevent `System.AggregateException`
+ }
}
private string _fullpath = string.Empty;
diff --git a/src/ViewModels/RepositoryConfigure.cs b/src/ViewModels/RepositoryConfigure.cs
index cf23b6d8..3f590758 100644
--- a/src/ViewModels/RepositoryConfigure.cs
+++ b/src/ViewModels/RepositoryConfigure.cs
@@ -203,6 +203,11 @@ namespace SourceGit.ViewModels
SelectedIssueTrackerRule = _repo.Settings.AddIssueTracker("Jira Tracker", "PROJ-(\\d+)", "https://jira.yourcompany.com/browse/PROJ-$1");
}
+ public void AddSampleAzureWorkItemTracker()
+ {
+ SelectedIssueTrackerRule = _repo.Settings.AddIssueTracker("Azure DevOps Tracker", "#(\\d+)", "https://dev.azure.com/yourcompany/workspace/_workitems/edit/$1");
+ }
+
public void AddSampleGitLabIssueTracker()
{
var link = "https://gitlab.com/username/repository/-/issues/$1";
diff --git a/src/ViewModels/RevisionCompare.cs b/src/ViewModels/RevisionCompare.cs
index 77a408e0..3b5717a6 100644
--- a/src/ViewModels/RevisionCompare.cs
+++ b/src/ViewModels/RevisionCompare.cs
@@ -183,15 +183,15 @@ namespace SourceGit.ViewModels
};
menu.Items.Add(copyPath);
- var copyFileName = new MenuItem();
- copyFileName.Header = App.Text("CopyFileName");
- copyFileName.Icon = App.CreateMenuIcon("Icons.Copy");
- copyFileName.Click += (_, e) =>
+ var copyFullPath = new MenuItem();
+ copyFullPath.Header = App.Text("CopyFullPath");
+ copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
+ copyFullPath.Click += (_, e) =>
{
- App.CopyText(Path.GetFileName(change.Path));
+ App.CopyText(Native.OS.GetAbsPath(_repo, change.Path));
e.Handled = true;
};
- menu.Items.Add(copyFileName);
+ menu.Items.Add(copyFullPath);
return menu;
}
diff --git a/src/ViewModels/StashesPage.cs b/src/ViewModels/StashesPage.cs
index 77ed5551..e69d9bb5 100644
--- a/src/ViewModels/StashesPage.cs
+++ b/src/ViewModels/StashesPage.cs
@@ -251,12 +251,12 @@ namespace SourceGit.ViewModels
ev.Handled = true;
};
- var copyFileName = new MenuItem();
- copyFileName.Header = App.Text("CopyFileName");
- copyFileName.Icon = App.CreateMenuIcon("Icons.Copy");
- copyFileName.Click += (_, e) =>
+ var copyFullPath = new MenuItem();
+ copyFullPath.Header = App.Text("CopyFullPath");
+ copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
+ copyFullPath.Click += (_, e) =>
{
- App.CopyText(Path.GetFileName(change.Path));
+ App.CopyText(Native.OS.GetAbsPath(_repo.FullPath, change.Path));
e.Handled = true;
};
@@ -267,7 +267,7 @@ namespace SourceGit.ViewModels
menu.Items.Add(resetToThisRevision);
menu.Items.Add(new MenuItem { Header = "-" });
menu.Items.Add(copyPath);
- menu.Items.Add(copyFileName);
+ menu.Items.Add(copyFullPath);
return menu;
}
diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs
index f9ddb288..a0933ea3 100644
--- a/src/ViewModels/WorkingCopy.cs
+++ b/src/ViewModels/WorkingCopy.cs
@@ -99,17 +99,18 @@ namespace SourceGit.ViewModels
}
}
- public string UnstagedFilter
+ public string Filter
{
- get => _unstagedFilter;
+ get => _filter;
set
{
- if (SetProperty(ref _unstagedFilter, value))
+ if (SetProperty(ref _filter, value))
{
if (_isLoadingData)
return;
- VisibleUnstaged = GetVisibleUnstagedChanges(_unstaged);
+ VisibleUnstaged = GetVisibleChanges(_unstaged);
+ VisibleStaged = GetVisibleChanges(_staged);
SelectedUnstaged = [];
}
}
@@ -133,6 +134,12 @@ namespace SourceGit.ViewModels
private set => SetProperty(ref _staged, value);
}
+ public List VisibleStaged
+ {
+ get => _visibleStaged;
+ private set => SetProperty(ref _visibleStaged, value);
+ }
+
public List SelectedUnstaged
{
get => _selectedUnstaged;
@@ -216,6 +223,9 @@ namespace SourceGit.ViewModels
_visibleUnstaged.Clear();
OnPropertyChanged(nameof(VisibleUnstaged));
+ _visibleStaged.Clear();
+ OnPropertyChanged(nameof(VisibleStaged));
+
_unstaged.Clear();
OnPropertyChanged(nameof(Unstaged));
@@ -269,7 +279,7 @@ namespace SourceGit.ViewModels
}
}
- var visibleUnstaged = GetVisibleUnstagedChanges(unstaged);
+ var visibleUnstaged = GetVisibleChanges(unstaged);
var selectedUnstaged = new List();
foreach (var c in visibleUnstaged)
{
@@ -278,8 +288,10 @@ namespace SourceGit.ViewModels
}
var staged = GetStagedChanges();
+
+ var visibleStaged = GetVisibleChanges(staged);
var selectedStaged = new List();
- foreach (var c in staged)
+ foreach (var c in visibleStaged)
{
if (lastSelectedStaged.Contains(c.Path))
selectedStaged.Add(c);
@@ -290,6 +302,7 @@ namespace SourceGit.ViewModels
_isLoadingData = true;
HasUnsolvedConflicts = hasConflict;
VisibleUnstaged = visibleUnstaged;
+ VisibleStaged = visibleStaged;
Unstaged = unstaged;
Staged = staged;
SelectedUnstaged = selectedUnstaged;
@@ -337,7 +350,7 @@ namespace SourceGit.ViewModels
public void UnstageAll()
{
- UnstageChanges(_staged, null);
+ UnstageChanges(_visibleStaged, null);
}
public void Discard(List changes)
@@ -346,9 +359,9 @@ namespace SourceGit.ViewModels
_repo.ShowPopup(new Discard(_repo, changes));
}
- public void ClearUnstagedFilter()
+ public void ClearFilter()
{
- UnstagedFilter = string.Empty;
+ Filter = string.Empty;
}
public async void UseTheirs(List changes)
@@ -538,11 +551,6 @@ namespace SourceGit.ViewModels
DoCommit(false, true, false);
}
- public void CommitWithoutFiles(bool autoPush)
- {
- DoCommit(false, autoPush, true);
- }
-
public ContextMenu CreateContextMenuForUnstagedChanges()
{
if (_selectedUnstaged == null || _selectedUnstaged.Count == 0)
@@ -903,15 +911,15 @@ namespace SourceGit.ViewModels
};
menu.Items.Add(copy);
- var copyFileName = new MenuItem();
- copyFileName.Header = App.Text("CopyFileName");
- copyFileName.Icon = App.CreateMenuIcon("Icons.Copy");
- copyFileName.Click += (_, e) =>
+ var copyFullPath = new MenuItem();
+ copyFullPath.Header = App.Text("CopyFullPath");
+ copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
+ copyFullPath.Click += (_, e) =>
{
- App.CopyText(Path.GetFileName(change.Path));
+ App.CopyText(Native.OS.GetAbsPath(_repo.FullPath, change.Path));
e.Handled = true;
};
- menu.Items.Add(copyFileName);
+ menu.Items.Add(copyFullPath);
}
else
{
@@ -1270,17 +1278,17 @@ namespace SourceGit.ViewModels
e.Handled = true;
};
- var copyFileName = new MenuItem();
- copyFileName.Header = App.Text("CopyFileName");
- copyFileName.Icon = App.CreateMenuIcon("Icons.Copy");
- copyFileName.Click += (_, e) =>
+ var copyFullPath = new MenuItem();
+ copyFullPath.Header = App.Text("CopyFullPath");
+ copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
+ copyFullPath.Click += (_, e) =>
{
- App.CopyText(Path.GetFileName(change.Path));
+ App.CopyText(Native.OS.GetAbsPath(_repo.FullPath, change.Path));
e.Handled = true;
};
menu.Items.Add(copyPath);
- menu.Items.Add(copyFileName);
+ menu.Items.Add(copyFullPath);
}
else
{
@@ -1472,16 +1480,16 @@ namespace SourceGit.ViewModels
return menu;
}
- private List GetVisibleUnstagedChanges(List unstaged)
+ private List GetVisibleChanges(List changes)
{
- if (string.IsNullOrEmpty(_unstagedFilter))
- return unstaged;
+ if (string.IsNullOrEmpty(_filter))
+ return changes;
var visible = new List();
- foreach (var c in unstaged)
+ foreach (var c in changes)
{
- if (c.Path.Contains(_unstagedFilter, StringComparison.OrdinalIgnoreCase))
+ if (c.Path.Contains(_filter, StringComparison.OrdinalIgnoreCase))
visible.Add(c);
}
@@ -1599,7 +1607,8 @@ namespace SourceGit.ViewModels
private async void UnstageChanges(List changes, Models.Change next)
{
- if (changes.Count == 0)
+ var count = changes.Count;
+ if (count == 0)
return;
// Use `_selectedStaged` instead of `SelectedStaged` to avoid UI refresh.
@@ -1611,16 +1620,15 @@ namespace SourceGit.ViewModels
{
await Task.Run(() => new Commands.UnstageChangesForAmend(_repo.FullPath, changes).Exec());
}
- else if (changes.Count == _staged.Count)
+ else if (count == _staged.Count)
{
await Task.Run(() => new Commands.Reset(_repo.FullPath).Exec());
}
else
{
- for (int i = 0; i < changes.Count; i += 10)
+ for (int i = 0; i < count; i += 10)
{
- var count = Math.Min(10, changes.Count - i);
- var step = changes.GetRange(i, count);
+ var step = changes.GetRange(i, Math.Min(10, count - i));
await Task.Run(() => new Commands.Reset(_repo.FullPath, step).Exec());
}
}
@@ -1642,7 +1650,7 @@ namespace SourceGit.ViewModels
DetailContext = new DiffContext(_repo.FullPath, new Models.DiffOption(change, isUnstaged), _detailContext as DiffContext);
}
- private void DoCommit(bool autoStage, bool autoPush, bool allowEmpty)
+ private void DoCommit(bool autoStage, bool autoPush, bool allowEmpty = false, bool confirmWithFilter = false)
{
if (!_repo.CanCreatePopup())
{
@@ -1650,6 +1658,20 @@ namespace SourceGit.ViewModels
return;
}
+ if (!string.IsNullOrEmpty(_filter) && _staged.Count > _visibleStaged.Count && !confirmWithFilter)
+ {
+ var confirmMessage = App.Text("WorkingCopy.ConfirmCommitWithFilter", _staged.Count, _visibleStaged.Count, _staged.Count - _visibleStaged.Count);
+ App.OpenDialog(new Views.ConfirmCommit()
+ {
+ DataContext = new ConfirmCommit(confirmMessage, () =>
+ {
+ DoCommit(autoStage, autoPush, allowEmpty, true);
+ })
+ });
+
+ return;
+ }
+
if (string.IsNullOrWhiteSpace(_commitMessage))
{
App.RaiseException(_repo.FullPath, "Commit without message is NOT allowed!");
@@ -1660,9 +1682,13 @@ namespace SourceGit.ViewModels
{
if ((autoStage && _count == 0) || (!autoStage && _staged.Count == 0))
{
- App.OpenDialog(new Views.ConfirmCommitWithoutFiles()
+ var confirmMessage = App.Text("WorkingCopy.ConfirmCommitWithoutFiles");
+ App.OpenDialog(new Views.ConfirmCommit()
{
- DataContext = new ConfirmCommitWithoutFiles(this, autoPush)
+ DataContext = new ConfirmCommit(confirmMessage, () =>
+ {
+ DoCommit(autoStage, autoPush, true, confirmWithFilter);
+ })
});
return;
@@ -1729,11 +1755,12 @@ namespace SourceGit.ViewModels
private List _unstaged = [];
private List _visibleUnstaged = [];
private List _staged = [];
+ private List _visibleStaged = [];
private List _selectedUnstaged = [];
private List _selectedStaged = [];
private int _count = 0;
private object _detailContext = null;
- private string _unstagedFilter = string.Empty;
+ private string _filter = string.Empty;
private string _commitMessage = string.Empty;
private bool _hasUnsolvedConflicts = false;
diff --git a/src/Views/ConfirmCommitWithoutFiles.axaml b/src/Views/ConfirmCommit.axaml
similarity index 92%
rename from src/Views/ConfirmCommitWithoutFiles.axaml
rename to src/Views/ConfirmCommit.axaml
index 4c9fd1c8..77bbdb30 100644
--- a/src/Views/ConfirmCommitWithoutFiles.axaml
+++ b/src/Views/ConfirmCommit.axaml
@@ -5,8 +5,8 @@
xmlns:v="using:SourceGit.Views"
xmlns:vm="using:SourceGit.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
- x:Class="SourceGit.Views.ConfirmCommitWithoutFiles"
- x:DataType="vm:ConfirmCommitWithoutFiles"
+ x:Class="SourceGit.Views.ConfirmCommit"
+ x:DataType="vm:ConfirmCommit"
x:Name="ThisControl"
Icon="/App.ico"
Title="{DynamicResource Text.Warn}"
@@ -38,7 +38,7 @@
-
+
diff --git a/src/Views/ConfirmCommitWithoutFiles.axaml.cs b/src/Views/ConfirmCommit.axaml.cs
similarity index 57%
rename from src/Views/ConfirmCommitWithoutFiles.axaml.cs
rename to src/Views/ConfirmCommit.axaml.cs
index 342600fc..1cf770cb 100644
--- a/src/Views/ConfirmCommitWithoutFiles.axaml.cs
+++ b/src/Views/ConfirmCommit.axaml.cs
@@ -2,20 +2,16 @@ using Avalonia.Interactivity;
namespace SourceGit.Views
{
- public partial class ConfirmCommitWithoutFiles : ChromelessWindow
+ public partial class ConfirmCommit : ChromelessWindow
{
- public ConfirmCommitWithoutFiles()
+ public ConfirmCommit()
{
InitializeComponent();
}
private void Sure(object _1, RoutedEventArgs _2)
{
- if (DataContext is ViewModels.ConfirmCommitWithoutFiles vm)
- {
- vm.Continue();
- }
-
+ (DataContext as ViewModels.ConfirmCommit)?.Continue();
Close();
}
diff --git a/src/Views/Histories.axaml b/src/Views/Histories.axaml
index 4fd8909d..96340d1e 100644
--- a/src/Views/Histories.axaml
+++ b/src/Views/Histories.axaml
@@ -195,7 +195,7 @@
-
+
+
diff --git a/src/Views/WorkingCopy.axaml b/src/Views/WorkingCopy.axaml
index 4d79135d..94dd0c30 100644
--- a/src/Views/WorkingCopy.axaml
+++ b/src/Views/WorkingCopy.axaml
@@ -19,13 +19,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -75,40 +108,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -155,15 +156,16 @@
ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=StagedChangeViewMode, Mode=TwoWay}"/>
-
+