diff --git a/TRANSLATION.md b/TRANSLATION.md
index 1a9d00d1..08594b66 100644
--- a/TRANSLATION.md
+++ b/TRANSLATION.md
@@ -6,11 +6,18 @@ This document shows the translation status of each locale file in the repository
### 
-### 
+### 
Missing keys in de_DE.axaml
+- Text.BranchCM.ResetToSelectedCommit
+- Text.CommitDetail.Changes.Count
+- Text.CreateBranch.OverwriteExisting
+- Text.DeinitSubmodule
+- Text.DeinitSubmodule.Force
+- Text.DeinitSubmodule.Path
+- Text.Diff.Submodule.Deleted
- Text.GitFlow.FinishWithPush
- Text.GitFlow.FinishWithSquash
- Text.Hotkeys.Global.SwitchWorkspace
@@ -18,7 +25,12 @@ This document shows the translation status of each locale file in the repository
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.Launcher.Workspaces
- Text.Launcher.Pages
+- Text.Pull.RecurseSubmodules
- Text.Repository.ShowSubmodulesAsTree
+- Text.ResetWithoutCheckout
+- Text.ResetWithoutCheckout.MoveTo
+- Text.ResetWithoutCheckout.Target
+- Text.Submodule.Deinit
- Text.Submodule.Status
- Text.Submodule.Status.Modified
- Text.Submodule.Status.NotInited
@@ -28,19 +40,16 @@ This document shows the translation status of each locale file in the repository
-### 
+### 
Missing keys in es_ES.axaml
-- Text.Hotkeys.Global.SwitchWorkspace
-- Text.Hotkeys.Global.SwitchTab
-- Text.Launcher.Workspaces
-- Text.Launcher.Pages
+- Text.CreateBranch.OverwriteExisting
-### 
+### 
Missing keys in fr_FR.axaml
@@ -52,16 +61,23 @@ This document shows the translation status of each locale file in the repository
- Text.Bisect.Good
- Text.Bisect.Skip
- Text.Bisect.WaitingForRange
+- Text.BranchCM.ResetToSelectedCommit
- Text.Checkout.RecurseSubmodules
- Text.CommitCM.CopyAuthor
- Text.CommitCM.CopyCommitter
- Text.CommitCM.CopySubject
+- Text.CommitDetail.Changes.Count
- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.Git.PreferredMergeMode
- Text.ConfirmEmptyCommit.Continue
- Text.ConfirmEmptyCommit.NoLocalChanges
- Text.ConfirmEmptyCommit.StageAllThenCommit
- Text.ConfirmEmptyCommit.WithLocalChanges
+- Text.CreateBranch.OverwriteExisting
+- Text.DeinitSubmodule
+- Text.DeinitSubmodule.Force
+- Text.DeinitSubmodule.Path
+- Text.Diff.Submodule.Deleted
- Text.GitFlow.FinishWithPush
- Text.GitFlow.FinishWithSquash
- Text.Hotkeys.Global.SwitchWorkspace
@@ -70,6 +86,7 @@ This document shows the translation status of each locale file in the repository
- Text.Launcher.Workspaces
- Text.Launcher.Pages
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
+- Text.Pull.RecurseSubmodules
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
@@ -77,6 +94,10 @@ This document shows the translation status of each locale file in the repository
- Text.Repository.ShowSubmodulesAsTree
- Text.Repository.ViewLogs
- Text.Repository.Visit
+- Text.ResetWithoutCheckout
+- Text.ResetWithoutCheckout.MoveTo
+- Text.ResetWithoutCheckout.Target
+- Text.Submodule.Deinit
- Text.Submodule.Status
- Text.Submodule.Status.Modified
- Text.Submodule.Status.NotInited
@@ -95,19 +116,31 @@ This document shows the translation status of each locale file in the repository
-### 
+### 
Missing keys in it_IT.axaml
+- Text.BranchCM.ResetToSelectedCommit
+- Text.CommitDetail.Changes.Count
+- Text.CreateBranch.OverwriteExisting
+- Text.DeinitSubmodule
+- Text.DeinitSubmodule.Force
+- Text.DeinitSubmodule.Path
+- Text.Diff.Submodule.Deleted
- Text.Hotkeys.Global.SwitchWorkspace
- Text.Hotkeys.Global.SwitchTab
- Text.Launcher.Workspaces
- Text.Launcher.Pages
+- Text.Pull.RecurseSubmodules
+- Text.ResetWithoutCheckout
+- Text.ResetWithoutCheckout.MoveTo
+- Text.ResetWithoutCheckout.Target
+- Text.Submodule.Deinit
-### 
+### 
Missing keys in ja_JP.axaml
@@ -119,16 +152,23 @@ This document shows the translation status of each locale file in the repository
- Text.Bisect.Good
- Text.Bisect.Skip
- Text.Bisect.WaitingForRange
+- Text.BranchCM.ResetToSelectedCommit
- Text.Checkout.RecurseSubmodules
- Text.CommitCM.CopyAuthor
- Text.CommitCM.CopyCommitter
- Text.CommitCM.CopySubject
+- Text.CommitDetail.Changes.Count
- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.Git.PreferredMergeMode
- Text.ConfirmEmptyCommit.Continue
- Text.ConfirmEmptyCommit.NoLocalChanges
- Text.ConfirmEmptyCommit.StageAllThenCommit
- Text.ConfirmEmptyCommit.WithLocalChanges
+- Text.CreateBranch.OverwriteExisting
+- Text.DeinitSubmodule
+- Text.DeinitSubmodule.Force
+- Text.DeinitSubmodule.Path
+- Text.Diff.Submodule.Deleted
- Text.GitFlow.FinishWithPush
- Text.GitFlow.FinishWithSquash
- Text.Hotkeys.Global.SwitchWorkspace
@@ -137,6 +177,7 @@ This document shows the translation status of each locale file in the repository
- Text.Launcher.Workspaces
- Text.Launcher.Pages
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
+- Text.Pull.RecurseSubmodules
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
@@ -146,6 +187,10 @@ This document shows the translation status of each locale file in the repository
- Text.Repository.Tags.OrderByNameDes
- Text.Repository.ViewLogs
- Text.Repository.Visit
+- Text.ResetWithoutCheckout
+- Text.ResetWithoutCheckout.MoveTo
+- Text.ResetWithoutCheckout.Target
+- Text.Submodule.Deinit
- Text.Submodule.Status
- Text.Submodule.Status.Modified
- Text.Submodule.Status.NotInited
@@ -164,7 +209,7 @@ This document shows the translation status of each locale file in the repository
-### 
+### 
Missing keys in pt_BR.axaml
@@ -184,6 +229,7 @@ This document shows the translation status of each locale file in the repository
- Text.Bisect.WaitingForRange
- Text.BranchCM.CustomAction
- Text.BranchCM.MergeMultiBranches
+- Text.BranchCM.ResetToSelectedCommit
- Text.BranchUpstreamInvalid
- Text.Checkout.RecurseSubmodules
- Text.Clone.RecurseSubmodules
@@ -192,6 +238,7 @@ This document shows the translation status of each locale file in the repository
- Text.CommitCM.CopySubject
- Text.CommitCM.Merge
- Text.CommitCM.MergeMultiple
+- Text.CommitDetail.Changes.Count
- Text.CommitDetail.Files.Search
- Text.CommitDetail.Info.Children
- Text.CommitMessageTextBox.SubjectCount
@@ -206,11 +253,16 @@ This document shows the translation status of each locale file in the repository
- Text.ConfirmEmptyCommit.WithLocalChanges
- Text.CopyFullPath
- Text.CreateBranch.Name.WarnSpace
+- Text.CreateBranch.OverwriteExisting
+- Text.DeinitSubmodule
+- Text.DeinitSubmodule.Force
+- Text.DeinitSubmodule.Path
- Text.DeleteRepositoryNode.Path
- Text.DeleteRepositoryNode.TipForGroup
- Text.DeleteRepositoryNode.TipForRepository
- Text.Diff.First
- Text.Diff.Last
+- Text.Diff.Submodule.Deleted
- Text.Diff.UseBlockNavigation
- Text.Fetch.Force
- Text.FileCM.ResolveUsing
@@ -238,6 +290,7 @@ This document shows the translation status of each locale file in the repository
- Text.Preferences.General.ShowTagsInGraph
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Preferences.Git.SSLVerify
+- Text.Pull.RecurseSubmodules
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
@@ -258,6 +311,9 @@ This document shows the translation status of each locale file in the repository
- Text.Repository.UseRelativeTimeInHistories
- Text.Repository.ViewLogs
- Text.Repository.Visit
+- Text.ResetWithoutCheckout
+- Text.ResetWithoutCheckout.MoveTo
+- Text.ResetWithoutCheckout.Target
- Text.SetUpstream
- Text.SetUpstream.Local
- Text.SetUpstream.Unset
@@ -266,6 +322,7 @@ This document shows the translation status of each locale file in the repository
- Text.Stash.AutoRestore
- Text.Stash.AutoRestore.Tip
- Text.StashCM.SaveAsPatch
+- Text.Submodule.Deinit
- Text.Submodule.Status
- Text.Submodule.Status.Modified
- Text.Submodule.Status.NotInited
@@ -286,17 +343,9 @@ This document shows the translation status of each locale file in the repository
-### 
+### 
-
-Missing keys in ru_RU.axaml
-
-- Text.Hotkeys.Global.SwitchTab
-- Text.Launcher.Pages
-
-
-
-### 
+### 
Missing keys in ta_IN.axaml
@@ -308,16 +357,23 @@ This document shows the translation status of each locale file in the repository
- Text.Bisect.Good
- Text.Bisect.Skip
- Text.Bisect.WaitingForRange
+- Text.BranchCM.ResetToSelectedCommit
- Text.Checkout.RecurseSubmodules
- Text.CommitCM.CopyAuthor
- Text.CommitCM.CopyCommitter
- Text.CommitCM.CopySubject
+- Text.CommitDetail.Changes.Count
- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.Git.PreferredMergeMode
- Text.ConfirmEmptyCommit.Continue
- Text.ConfirmEmptyCommit.NoLocalChanges
- Text.ConfirmEmptyCommit.StageAllThenCommit
- Text.ConfirmEmptyCommit.WithLocalChanges
+- Text.CreateBranch.OverwriteExisting
+- Text.DeinitSubmodule
+- Text.DeinitSubmodule.Force
+- Text.DeinitSubmodule.Path
+- Text.Diff.Submodule.Deleted
- Text.GitFlow.FinishWithPush
- Text.GitFlow.FinishWithSquash
- Text.Hotkeys.Global.SwitchWorkspace
@@ -326,6 +382,7 @@ This document shows the translation status of each locale file in the repository
- Text.Launcher.Workspaces
- Text.Launcher.Pages
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
+- Text.Pull.RecurseSubmodules
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
@@ -333,6 +390,10 @@ This document shows the translation status of each locale file in the repository
- Text.Repository.ShowSubmodulesAsTree
- Text.Repository.ViewLogs
- Text.Repository.Visit
+- Text.ResetWithoutCheckout
+- Text.ResetWithoutCheckout.MoveTo
+- Text.ResetWithoutCheckout.Target
+- Text.Submodule.Deinit
- Text.Submodule.Status
- Text.Submodule.Status.Modified
- Text.Submodule.Status.NotInited
@@ -351,7 +412,7 @@ This document shows the translation status of each locale file in the repository
-### 
+### 
Missing keys in uk_UA.axaml
@@ -363,12 +424,19 @@ This document shows the translation status of each locale file in the repository
- Text.Bisect.Good
- Text.Bisect.Skip
- Text.Bisect.WaitingForRange
+- Text.BranchCM.ResetToSelectedCommit
- Text.Checkout.RecurseSubmodules
- Text.CommitCM.CopyAuthor
- Text.CommitCM.CopyCommitter
- Text.CommitCM.CopySubject
+- Text.CommitDetail.Changes.Count
- Text.CommitMessageTextBox.SubjectCount
- Text.ConfigureWorkspace.Name
+- Text.CreateBranch.OverwriteExisting
+- Text.DeinitSubmodule
+- Text.DeinitSubmodule.Force
+- Text.DeinitSubmodule.Path
+- Text.Diff.Submodule.Deleted
- Text.GitFlow.FinishWithPush
- Text.GitFlow.FinishWithSquash
- Text.Hotkeys.Global.SwitchWorkspace
@@ -377,6 +445,7 @@ This document shows the translation status of each locale file in the repository
- Text.Launcher.Workspaces
- Text.Launcher.Pages
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
+- Text.Pull.RecurseSubmodules
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
@@ -384,6 +453,10 @@ This document shows the translation status of each locale file in the repository
- Text.Repository.ShowSubmodulesAsTree
- Text.Repository.ViewLogs
- Text.Repository.Visit
+- Text.ResetWithoutCheckout
+- Text.ResetWithoutCheckout.MoveTo
+- Text.ResetWithoutCheckout.Target
+- Text.Submodule.Deinit
- Text.Submodule.Status
- Text.Submodule.Status.Modified
- Text.Submodule.Status.NotInited
diff --git a/VERSION b/VERSION
index 60bea9b2..ac98de3d 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2025.18
\ No newline at end of file
+2025.19
\ No newline at end of file
diff --git a/src/App.axaml.cs b/src/App.axaml.cs
index 45ab0b8c..0664ee25 100644
--- a/src/App.axaml.cs
+++ b/src/App.axaml.cs
@@ -548,7 +548,7 @@ namespace SourceGit
private void TryLaunchAsNormal(IClassicDesktopStyleApplicationLifetime desktop)
{
- Native.OS.SetupEnternalTools();
+ Native.OS.SetupExternalTools();
Models.AvatarManager.Instance.Start();
string startupRepo = null;
@@ -671,7 +671,16 @@ namespace SourceGit
prevChar = c;
}
- trimmed.Add(sb.ToString());
+ var name = sb.ToString();
+ var idx = name.IndexOf('#');
+ if (idx >= 0)
+ {
+ if (!name.Equals("fonts:Inter#Inter", StringComparison.Ordinal) &&
+ !name.Equals("fonts:SourceGit#JetBrains Mono", StringComparison.Ordinal))
+ continue;
+ }
+
+ trimmed.Add(name);
}
return trimmed.Count > 0 ? string.Join(',', trimmed) : string.Empty;
diff --git a/src/Commands/Branch.cs b/src/Commands/Branch.cs
index 9c396215..0d1b1f8f 100644
--- a/src/Commands/Branch.cs
+++ b/src/Commands/Branch.cs
@@ -1,4 +1,6 @@
-namespace SourceGit.Commands
+using System.Text;
+
+namespace SourceGit.Commands
{
public static class Branch
{
@@ -11,12 +13,20 @@
return cmd.ReadToEnd().StdOut.Trim();
}
- public static bool Create(string repo, string name, string basedOn, Models.ICommandLog log)
+ public static bool Create(string repo, string name, string basedOn, bool force, Models.ICommandLog log)
{
+ var builder = new StringBuilder();
+ builder.Append("branch ");
+ if (force)
+ builder.Append("-f ");
+ builder.Append(name);
+ builder.Append(" ");
+ builder.Append(basedOn);
+
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
- cmd.Args = $"branch {name} {basedOn}";
+ cmd.Args = builder.ToString();
cmd.Log = log;
return cmd.Exec();
}
diff --git a/src/Commands/Checkout.cs b/src/Commands/Checkout.cs
index 6f63ae60..aa386c2f 100644
--- a/src/Commands/Checkout.cs
+++ b/src/Commands/Checkout.cs
@@ -13,15 +13,28 @@ namespace SourceGit.Commands
public bool Branch(string branch, bool force)
{
- var option = force ? "--force" : string.Empty;
- Args = $"checkout {option} --progress {branch}";
+ var builder = new StringBuilder();
+ builder.Append("checkout --progress ");
+ if (force)
+ builder.Append("--force ");
+ builder.Append(branch);
+
+ Args = builder.ToString();
return Exec();
}
- public bool Branch(string branch, string basedOn, bool force)
+ public bool Branch(string branch, string basedOn, bool force, bool allowOverwrite)
{
- var option = force ? "--force" : string.Empty;
- Args = $"checkout --progress -b {branch} {basedOn}";
+ var builder = new StringBuilder();
+ builder.Append("checkout --progress ");
+ builder.Append(allowOverwrite ? "-B " : "-b ");
+ if (force)
+ builder.Append("--force ");
+ builder.Append(branch);
+ builder.Append(" ");
+ builder.Append(basedOn);
+
+ Args = builder.ToString();
return Exec();
}
diff --git a/src/Commands/Command.cs b/src/Commands/Command.cs
index 699cc120..9bfa1c15 100644
--- a/src/Commands/Command.cs
+++ b/src/Commands/Command.cs
@@ -36,44 +36,14 @@ namespace SourceGit.Commands
public bool Exec()
{
+ Log?.AppendLine($"$ git {Args}\n");
+
var start = CreateGitStartInfo();
var errs = new List();
var proc = new Process() { StartInfo = start };
- Log?.AppendLine($"$ git {Args}\n");
-
- proc.OutputDataReceived += (_, e) =>
- {
- if (e.Data == null)
- return;
-
- Log?.AppendLine(e.Data);
- };
-
- proc.ErrorDataReceived += (_, e) =>
- {
- if (string.IsNullOrEmpty(e.Data))
- {
- errs.Add(string.Empty);
- return;
- }
-
- Log?.AppendLine(e.Data);
-
- // Ignore progress messages
- if (e.Data.StartsWith("remote: Enumerating objects:", StringComparison.Ordinal))
- return;
- if (e.Data.StartsWith("remote: Counting objects:", StringComparison.Ordinal))
- return;
- if (e.Data.StartsWith("remote: Compressing objects:", StringComparison.Ordinal))
- return;
- if (e.Data.StartsWith("Filtering content:", StringComparison.Ordinal))
- return;
- if (REG_PROGRESS().IsMatch(e.Data))
- return;
-
- errs.Add(e.Data);
- };
+ proc.OutputDataReceived += (_, e) => HandleOutput(e.Data, errs);
+ proc.ErrorDataReceived += (_, e) => HandleOutput(e.Data, errs);
var dummy = null as Process;
var dummyProcLock = new object();
@@ -222,6 +192,28 @@ namespace SourceGit.Commands
return start;
}
+ private void HandleOutput(string line, List errs)
+ {
+ line = line ?? string.Empty;
+ Log?.AppendLine(line);
+
+ // Lines to hide in error message.
+ if (line.Length > 0)
+ {
+ if (line.StartsWith("remote: Enumerating objects:", StringComparison.Ordinal) ||
+ line.StartsWith("remote: Counting objects:", StringComparison.Ordinal) ||
+ line.StartsWith("remote: Compressing objects:", StringComparison.Ordinal) ||
+ line.StartsWith("Filtering content:", StringComparison.Ordinal) ||
+ line.StartsWith("hint:", StringComparison.Ordinal))
+ return;
+
+ if (REG_PROGRESS().IsMatch(line))
+ return;
+ }
+
+ errs.Add(line);
+ }
+
[GeneratedRegex(@"\d+%")]
private static partial Regex REG_PROGRESS();
}
diff --git a/src/Commands/ExecuteCustomAction.cs b/src/Commands/ExecuteCustomAction.cs
index 000c8fd1..e59bc068 100644
--- a/src/Commands/ExecuteCustomAction.cs
+++ b/src/Commands/ExecuteCustomAction.cs
@@ -27,7 +27,7 @@ namespace SourceGit.Commands
}
}
- public static void RunAndWait(string repo, string file, string args, Action outputHandler)
+ public static void RunAndWait(string repo, string file, string args, Models.ICommandLog log)
{
var start = new ProcessStartInfo();
start.FileName = file;
@@ -40,20 +40,22 @@ namespace SourceGit.Commands
start.StandardErrorEncoding = Encoding.UTF8;
start.WorkingDirectory = repo;
+ log?.AppendLine($"$ {file} {args}\n");
+
var proc = new Process() { StartInfo = start };
var builder = new StringBuilder();
proc.OutputDataReceived += (_, e) =>
{
if (e.Data != null)
- outputHandler?.Invoke(e.Data);
+ log?.AppendLine(e.Data);
};
proc.ErrorDataReceived += (_, e) =>
{
if (e.Data != null)
{
- outputHandler?.Invoke(e.Data);
+ log?.AppendLine(e.Data);
builder.AppendLine(e.Data);
}
};
diff --git a/src/Commands/GitFlow.cs b/src/Commands/GitFlow.cs
index e4fab235..1d33fa3a 100644
--- a/src/Commands/GitFlow.cs
+++ b/src/Commands/GitFlow.cs
@@ -1,53 +1,12 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
+using System.Text;
using Avalonia.Threading;
namespace SourceGit.Commands
{
public static class GitFlow
{
- public class BranchDetectResult
+ public static bool Init(string repo, string master, string develop, string feature, string release, string hotfix, string version, Models.ICommandLog log)
{
- public bool IsGitFlowBranch { get; set; } = false;
- public string Type { get; set; } = string.Empty;
- public string Prefix { get; set; } = string.Empty;
- }
-
- public static bool IsEnabled(string repo, List branches)
- {
- var localBrancheNames = new HashSet();
- foreach (var branch in branches)
- {
- if (branch.IsLocal)
- localBrancheNames.Add(branch.Name);
- }
-
- var config = new Config(repo).ListAll();
- if (!config.TryGetValue("gitflow.branch.master", out string master) || !localBrancheNames.Contains(master))
- return false;
-
- if (!config.TryGetValue("gitflow.branch.develop", out string develop) || !localBrancheNames.Contains(develop))
- return false;
-
- return config.ContainsKey("gitflow.prefix.feature") &&
- config.ContainsKey("gitflow.prefix.release") &&
- config.ContainsKey("gitflow.prefix.hotfix");
- }
-
- public static bool Init(string repo, List branches, string master, string develop, string feature, string release, string hotfix, string version, Models.ICommandLog log)
- {
- var current = branches.Find(x => x.IsCurrent);
-
- var masterBranch = branches.Find(x => x.Name == master);
- if (masterBranch == null && current != null)
- Branch.Create(repo, master, current.Head, log);
-
- var devBranch = branches.Find(x => x.Name == develop);
- if (devBranch == null && current != null)
- Branch.Create(repo, develop, current.Head, log);
-
var config = new Config(repo);
config.Set("gitflow.branch.master", master);
config.Set("gitflow.branch.develop", develop);
@@ -66,90 +25,53 @@ namespace SourceGit.Commands
return init.Exec();
}
- public static string GetPrefix(string repo, string type)
+ public static bool Start(string repo, Models.GitFlowBranchType type, string name, Models.ICommandLog log)
{
- return new Config(repo).Get($"gitflow.prefix.{type}");
- }
-
- public static BranchDetectResult DetectType(string repo, List branches, string branch)
- {
- var rs = new BranchDetectResult();
- var localBrancheNames = new HashSet();
- foreach (var b in branches)
- {
- if (b.IsLocal)
- localBrancheNames.Add(b.Name);
- }
-
- var config = new Config(repo).ListAll();
- if (!config.TryGetValue("gitflow.branch.master", out string master) || !localBrancheNames.Contains(master))
- return rs;
-
- if (!config.TryGetValue("gitflow.branch.develop", out string develop) || !localBrancheNames.Contains(develop))
- return rs;
-
- if (!config.TryGetValue("gitflow.prefix.feature", out var feature) ||
- !config.TryGetValue("gitflow.prefix.release", out var release) ||
- !config.TryGetValue("gitflow.prefix.hotfix", out var hotfix))
- return rs;
-
- if (branch.StartsWith(feature, StringComparison.Ordinal))
- {
- rs.IsGitFlowBranch = true;
- rs.Type = "feature";
- rs.Prefix = feature;
- }
- else if (branch.StartsWith(release, StringComparison.Ordinal))
- {
- rs.IsGitFlowBranch = true;
- rs.Type = "release";
- rs.Prefix = release;
- }
- else if (branch.StartsWith(hotfix, StringComparison.Ordinal))
- {
- rs.IsGitFlowBranch = true;
- rs.Type = "hotfix";
- rs.Prefix = hotfix;
- }
-
- return rs;
- }
-
- public static bool Start(string repo, string type, string name, Models.ICommandLog log)
- {
- if (!SUPPORTED_BRANCH_TYPES.Contains(type))
- {
- Dispatcher.UIThread.Post(() =>
- {
- App.RaiseException(repo, "Bad branch type!!!");
- });
-
- return false;
- }
-
var start = new Command();
start.WorkingDirectory = repo;
start.Context = repo;
- start.Args = $"flow {type} start {name}";
+
+ switch (type)
+ {
+ case Models.GitFlowBranchType.Feature:
+ start.Args = $"flow feature start {name}";
+ break;
+ case Models.GitFlowBranchType.Release:
+ start.Args = $"flow release start {name}";
+ break;
+ case Models.GitFlowBranchType.Hotfix:
+ start.Args = $"flow hotfix start {name}";
+ break;
+ default:
+ Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, "Bad git-flow branch type!!!"));
+ return false;
+ }
+
start.Log = log;
return start.Exec();
}
- public static bool Finish(string repo, string type, string name, bool squash, bool push, bool keepBranch, Models.ICommandLog log)
+ public static bool Finish(string repo, Models.GitFlowBranchType type, string name, bool squash, bool push, bool keepBranch, Models.ICommandLog log)
{
- if (!SUPPORTED_BRANCH_TYPES.Contains(type))
- {
- Dispatcher.UIThread.Post(() =>
- {
- App.RaiseException(repo, "Bad branch type!!!");
- });
-
- return false;
- }
-
var builder = new StringBuilder();
builder.Append("flow ");
- builder.Append(type);
+
+ switch (type)
+ {
+ case Models.GitFlowBranchType.Feature:
+ builder.Append("feature");
+ break;
+ case Models.GitFlowBranchType.Release:
+ builder.Append("release");
+ break;
+ case Models.GitFlowBranchType.Hotfix:
+ builder.Append("hotfix");
+ break;
+ default:
+ Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, "Bad git-flow branch type!!!"));
+ return false;
+ }
+
builder.Append(" finish ");
if (squash)
builder.Append("--squash ");
@@ -166,14 +88,5 @@ namespace SourceGit.Commands
finish.Log = log;
return finish.Exec();
}
-
- private static readonly List SUPPORTED_BRANCH_TYPES = new List()
- {
- "feature",
- "release",
- "bugfix",
- "hotfix",
- "support",
- };
}
}
diff --git a/src/Commands/IsBinary.cs b/src/Commands/IsBinary.cs
index de59b5a4..af8f54bb 100644
--- a/src/Commands/IsBinary.cs
+++ b/src/Commands/IsBinary.cs
@@ -11,7 +11,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
- Args = $"diff 4b825dc642cb6eb9a060e54bf8d69288fbee4904 {commit} --numstat -- \"{path}\"";
+ Args = $"diff {Models.Commit.EmptyTreeSHA1} {commit} --numstat -- \"{path}\"";
RaiseError = false;
}
diff --git a/src/Commands/Pull.cs b/src/Commands/Pull.cs
index 2695b16b..698fbfce 100644
--- a/src/Commands/Pull.cs
+++ b/src/Commands/Pull.cs
@@ -2,7 +2,7 @@
{
public class Pull : Command
{
- public Pull(string repo, string remote, string branch, bool useRebase, bool noTags)
+ public Pull(string repo, string remote, string branch, bool useRebase)
{
WorkingDirectory = repo;
Context = repo;
@@ -12,9 +12,6 @@
if (useRebase)
Args += "--rebase=true ";
- if (noTags)
- Args += "--no-tags ";
-
Args += $"{remote} {branch}";
}
}
diff --git a/src/Commands/QueryBranches.cs b/src/Commands/QueryBranches.cs
index 39794090..910e5fd2 100644
--- a/src/Commands/QueryBranches.cs
+++ b/src/Commands/QueryBranches.cs
@@ -27,7 +27,7 @@ namespace SourceGit.Commands
return branches;
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
- var remoteBranches = new HashSet();
+ var remoteHeads = new Dictionary();
foreach (var line in lines)
{
var b = ParseLine(line);
@@ -35,7 +35,7 @@ namespace SourceGit.Commands
{
branches.Add(b);
if (!b.IsLocal)
- remoteBranches.Add(b.FullName);
+ remoteHeads.Add(b.FullName, b.Head);
else
localBranchesCount++;
}
@@ -44,7 +44,22 @@ namespace SourceGit.Commands
foreach (var b in branches)
{
if (b.IsLocal && !string.IsNullOrEmpty(b.Upstream))
- b.IsUpstreamGone = !remoteBranches.Contains(b.Upstream);
+ {
+ if (remoteHeads.TryGetValue(b.Upstream, out var upstreamHead))
+ {
+ b.IsUpstreamGone = false;
+
+ if (b.TrackStatus == null)
+ b.TrackStatus = new QueryTrackStatus(WorkingDirectory, b.Head, upstreamHead).Result();
+ }
+ else
+ {
+ b.IsUpstreamGone = true;
+
+ if (b.TrackStatus == null)
+ b.TrackStatus = new Models.BranchTrackStatus();
+ }
+ }
}
return branches;
@@ -93,9 +108,10 @@ namespace SourceGit.Commands
branch.Upstream = parts[4];
branch.IsUpstreamGone = false;
- if (branch.IsLocal && !string.IsNullOrEmpty(parts[5]) && !parts[5].Equals("=", StringComparison.Ordinal))
- branch.TrackStatus = new QueryTrackStatus(WorkingDirectory, branch.Name, branch.Upstream).Result();
- else
+ if (!branch.IsLocal ||
+ string.IsNullOrEmpty(branch.Upstream) ||
+ string.IsNullOrEmpty(parts[5]) ||
+ parts[5].Equals("=", StringComparison.Ordinal))
branch.TrackStatus = new Models.BranchTrackStatus();
return branch;
diff --git a/src/Commands/QueryLocalChanges.cs b/src/Commands/QueryLocalChanges.cs
index 404f5be6..9abf433e 100644
--- a/src/Commands/QueryLocalChanges.cs
+++ b/src/Commands/QueryLocalChanges.cs
@@ -128,30 +128,16 @@ namespace SourceGit.Commands
change.Set(Models.ChangeState.Deleted, Models.ChangeState.Copied);
break;
case "DD":
- change.Set(Models.ChangeState.Deleted, Models.ChangeState.Deleted);
- break;
case "AU":
- change.Set(Models.ChangeState.Added, Models.ChangeState.Unmerged);
- break;
case "UD":
- change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Deleted);
- break;
case "UA":
- change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Added);
- break;
case "DU":
- change.Set(Models.ChangeState.Deleted, Models.ChangeState.Unmerged);
- break;
case "AA":
- change.Set(Models.ChangeState.Added, Models.ChangeState.Added);
- break;
case "UU":
- change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Unmerged);
+ change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
break;
case "??":
- change.Set(Models.ChangeState.Untracked, Models.ChangeState.Untracked);
- break;
- default:
+ change.Set(Models.ChangeState.None, Models.ChangeState.Untracked);
break;
}
diff --git a/src/Commands/QueryStagedChangesWithAmend.cs b/src/Commands/QueryStagedChangesWithAmend.cs
index 8f8456c9..b20c20dc 100644
--- a/src/Commands/QueryStagedChangesWithAmend.cs
+++ b/src/Commands/QueryStagedChangesWithAmend.cs
@@ -6,7 +6,7 @@ namespace SourceGit.Commands
{
public partial class QueryStagedChangesWithAmend : Command
{
- [GeneratedRegex(@"^:[\d]{6} ([\d]{6}) ([0-9a-f]{40}) [0-9a-f]{40} ([ACDMTUX])\d{0,6}\t(.*)$")]
+ [GeneratedRegex(@"^:[\d]{6} ([\d]{6}) ([0-9a-f]{40}) [0-9a-f]{40} ([ACDMT])\d{0,6}\t(.*)$")]
private static partial Regex REG_FORMAT1();
[GeneratedRegex(@"^:[\d]{6} ([\d]{6}) ([0-9a-f]{40}) [0-9a-f]{40} R\d{0,6}\t(.*\t.*)$")]
private static partial Regex REG_FORMAT2();
@@ -22,76 +22,71 @@ namespace SourceGit.Commands
public List Result()
{
var rs = ReadToEnd();
- if (rs.IsSuccess)
+ if (!rs.IsSuccess)
+ return [];
+
+ var changes = new List();
+ var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
+ foreach (var line in lines)
{
- var changes = new List();
- var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
- foreach (var line in lines)
+ var match = REG_FORMAT2().Match(line);
+ if (match.Success)
{
- var match = REG_FORMAT2().Match(line);
- if (match.Success)
+ var change = new Models.Change()
{
- var change = new Models.Change()
+ Path = match.Groups[3].Value,
+ DataForAmend = new Models.ChangeDataForAmend()
{
- Path = match.Groups[3].Value,
- DataForAmend = new Models.ChangeDataForAmend()
- {
- FileMode = match.Groups[1].Value,
- ObjectHash = match.Groups[2].Value,
- ParentSHA = _parent,
- },
- };
- change.Set(Models.ChangeState.Renamed);
- changes.Add(change);
- continue;
- }
-
- match = REG_FORMAT1().Match(line);
- if (match.Success)
- {
- var change = new Models.Change()
- {
- Path = match.Groups[4].Value,
- DataForAmend = new Models.ChangeDataForAmend()
- {
- FileMode = match.Groups[1].Value,
- ObjectHash = match.Groups[2].Value,
- ParentSHA = _parent,
- },
- };
-
- var type = match.Groups[3].Value;
- switch (type)
- {
- case "A":
- change.Set(Models.ChangeState.Added);
- break;
- case "C":
- change.Set(Models.ChangeState.Copied);
- break;
- case "D":
- change.Set(Models.ChangeState.Deleted);
- break;
- case "M":
- change.Set(Models.ChangeState.Modified);
- break;
- case "T":
- change.Set(Models.ChangeState.TypeChanged);
- break;
- case "U":
- change.Set(Models.ChangeState.Unmerged);
- break;
- }
- changes.Add(change);
- }
+ FileMode = match.Groups[1].Value,
+ ObjectHash = match.Groups[2].Value,
+ ParentSHA = _parent,
+ },
+ };
+ change.Set(Models.ChangeState.Renamed);
+ changes.Add(change);
+ continue;
}
- return changes;
+ match = REG_FORMAT1().Match(line);
+ if (match.Success)
+ {
+ var change = new Models.Change()
+ {
+ Path = match.Groups[4].Value,
+ DataForAmend = new Models.ChangeDataForAmend()
+ {
+ FileMode = match.Groups[1].Value,
+ ObjectHash = match.Groups[2].Value,
+ ParentSHA = _parent,
+ },
+ };
+
+ var type = match.Groups[3].Value;
+ switch (type)
+ {
+ case "A":
+ change.Set(Models.ChangeState.Added);
+ break;
+ case "C":
+ change.Set(Models.ChangeState.Copied);
+ break;
+ case "D":
+ change.Set(Models.ChangeState.Deleted);
+ break;
+ case "M":
+ change.Set(Models.ChangeState.Modified);
+ break;
+ case "T":
+ change.Set(Models.ChangeState.TypeChanged);
+ break;
+ }
+ changes.Add(change);
+ }
}
- return [];
+ return changes;
}
- private string _parent = string.Empty;
+ private readonly string _parent;
}
}
diff --git a/src/Commands/QuerySubmodules.cs b/src/Commands/QuerySubmodules.cs
index 86147f97..663c0ea0 100644
--- a/src/Commands/QuerySubmodules.cs
+++ b/src/Commands/QuerySubmodules.cs
@@ -112,7 +112,7 @@ namespace SourceGit.Commands
}
}
- Args = $"--no-optional-locks status -uno --porcelain -- {builder}";
+ Args = $"--no-optional-locks status --porcelain -- {builder}";
rs = ReadToEnd();
if (!rs.IsSuccess)
return submodules;
diff --git a/src/Commands/QueryUpdatableSubmodules.cs b/src/Commands/QueryUpdatableSubmodules.cs
new file mode 100644
index 00000000..03f4a24d
--- /dev/null
+++ b/src/Commands/QueryUpdatableSubmodules.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+
+namespace SourceGit.Commands
+{
+ public partial class QueryUpdatableSubmodules : Command
+ {
+ [GeneratedRegex(@"^([U\-\+ ])([0-9a-f]+)\s(.*?)(\s\(.*\))?$")]
+ private static partial Regex REG_FORMAT_STATUS();
+
+ public QueryUpdatableSubmodules(string repo)
+ {
+ WorkingDirectory = repo;
+ Context = repo;
+ Args = "submodule status";
+ }
+
+ public List Result()
+ {
+ var submodules = new List();
+ var rs = ReadToEnd();
+
+ var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
+ foreach (var line in lines)
+ {
+ var match = REG_FORMAT_STATUS().Match(line);
+ if (match.Success)
+ {
+ var stat = match.Groups[1].Value;
+ var path = match.Groups[3].Value;
+ if (!stat.StartsWith(' '))
+ submodules.Add(path);
+ }
+ }
+
+ return submodules;
+ }
+ }
+}
diff --git a/src/Commands/Submodule.cs b/src/Commands/Submodule.cs
index c8b676ea..025d035a 100644
--- a/src/Commands/Submodule.cs
+++ b/src/Commands/Submodule.cs
@@ -13,7 +13,7 @@ namespace SourceGit.Commands
public bool Add(string url, string relativePath, bool recursive)
{
- Args = $"submodule add {url} \"{relativePath}\"";
+ Args = $"-c protocol.file.allow=always submodule add \"{url}\" \"{relativePath}\"";
if (!Exec())
return false;
@@ -29,23 +29,7 @@ namespace SourceGit.Commands
}
}
- public bool Update(string module, bool init, bool recursive, bool useRemote)
- {
- Args = "submodule update";
-
- if (init)
- Args += " --init";
- if (recursive)
- Args += " --recursive";
- if (useRemote)
- Args += " --remote";
- if (!string.IsNullOrEmpty(module))
- Args += $" -- \"{module}\"";
-
- return Exec();
- }
-
- public bool Update(List modules, bool init, bool recursive, bool useRemote)
+ public bool Update(List modules, bool init, bool recursive, bool useRemote = false)
{
var builder = new StringBuilder();
builder.Append("submodule update");
@@ -60,20 +44,22 @@ namespace SourceGit.Commands
{
builder.Append(" --");
foreach (var module in modules)
- builder.Append($" \"{module.Path}\"");
+ builder.Append($" \"{module}\"");
}
Args = builder.ToString();
return Exec();
}
- public bool Delete(string relativePath)
+ public bool Deinit(string module, bool force)
{
- Args = $"submodule deinit -f \"{relativePath}\"";
- if (!Exec())
- return false;
+ Args = force ? $"submodule deinit -f -- \"{module}\"" : $"submodule deinit -- \"{module}\"";
+ return Exec();
+ }
- Args = $"rm -rf \"{relativePath}\"";
+ public bool Delete(string module)
+ {
+ Args = $"rm -rf \"{module}\"";
return Exec();
}
}
diff --git a/src/Commands/UpdateRef.cs b/src/Commands/UpdateRef.cs
deleted file mode 100644
index 1e7bb239..00000000
--- a/src/Commands/UpdateRef.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace SourceGit.Commands
-{
- public class UpdateRef : Command
- {
- public UpdateRef(string repo, string refName, string toRevision)
- {
- WorkingDirectory = repo;
- Context = repo;
- Args = $"update-ref {refName} {toRevision}";
- }
- }
-}
diff --git a/src/Converters/ListConverters.cs b/src/Converters/ListConverters.cs
index e0c5967e..6f3ae98b 100644
--- a/src/Converters/ListConverters.cs
+++ b/src/Converters/ListConverters.cs
@@ -7,6 +7,9 @@ namespace SourceGit.Converters
{
public static class ListConverters
{
+ public static readonly FuncValueConverter Count =
+ new FuncValueConverter(v => v == null ? "0" : $"{v.Count}");
+
public static readonly FuncValueConverter ToCount =
new FuncValueConverter(v => v == null ? "(0)" : $"({v.Count})");
diff --git a/src/Models/Change.cs b/src/Models/Change.cs
index 0c96ec95..7d772d3e 100644
--- a/src/Models/Change.cs
+++ b/src/Models/Change.cs
@@ -18,8 +18,8 @@ namespace SourceGit.Models
Deleted,
Renamed,
Copied,
- Unmerged,
- Untracked
+ Untracked,
+ Conflicted,
}
public class ChangeDataForAmend
@@ -36,20 +36,7 @@ namespace SourceGit.Models
public string Path { get; set; } = "";
public string OriginalPath { get; set; } = "";
public ChangeDataForAmend DataForAmend { get; set; } = null;
-
- public bool IsConflict
- {
- get
- {
- if (Index == ChangeState.Unmerged || WorkTree == ChangeState.Unmerged)
- return true;
- if (Index == ChangeState.Added && WorkTree == ChangeState.Added)
- return true;
- if (Index == ChangeState.Deleted && WorkTree == ChangeState.Deleted)
- return true;
- return false;
- }
- }
+ public bool IsConflicted => WorkTree == ChangeState.Conflicted;
public void Set(ChangeState index, ChangeState workTree = ChangeState.None)
{
@@ -77,6 +64,7 @@ namespace SourceGit.Models
if (Path[0] == '"')
Path = Path.Substring(1, Path.Length - 2);
+
if (!string.IsNullOrEmpty(OriginalPath) && OriginalPath[0] == '"')
OriginalPath = OriginalPath.Substring(1, OriginalPath.Length - 2);
}
diff --git a/src/Models/Commit.cs b/src/Models/Commit.cs
index ef5a34bc..d8eb8ab6 100644
--- a/src/Models/Commit.cs
+++ b/src/Models/Commit.cs
@@ -18,6 +18,9 @@ namespace SourceGit.Models
public class Commit
{
+ // As retrieved by: git mktree
public DiffOption(Commit commit, Change change)
{
- var baseRevision = commit.Parents.Count == 0 ? "4b825dc642cb6eb9a060e54bf8d69288fbee4904" : $"{commit.SHA}^";
+ var baseRevision = commit.Parents.Count == 0 ? Commit.EmptyTreeSHA1 : $"{commit.SHA}^";
_revisions.Add(baseRevision);
_revisions.Add(commit.SHA);
_path = change.Path;
@@ -79,7 +79,7 @@ namespace SourceGit.Models
///
public DiffOption(Commit commit, string file)
{
- var baseRevision = commit.Parents.Count == 0 ? "4b825dc642cb6eb9a060e54bf8d69288fbee4904" : $"{commit.SHA}^";
+ var baseRevision = commit.Parents.Count == 0 ? Commit.EmptyTreeSHA1 : $"{commit.SHA}^";
_revisions.Add(baseRevision);
_revisions.Add(commit.SHA);
_path = file;
@@ -124,6 +124,6 @@ namespace SourceGit.Models
private readonly string _path;
private readonly string _orgPath = string.Empty;
private readonly string _extra = string.Empty;
- private readonly List _revisions = new List();
+ private readonly List _revisions = [];
}
}
diff --git a/src/Models/GitFlow.cs b/src/Models/GitFlow.cs
new file mode 100644
index 00000000..5d26072b
--- /dev/null
+++ b/src/Models/GitFlow.cs
@@ -0,0 +1,46 @@
+namespace SourceGit.Models
+{
+ public enum GitFlowBranchType
+ {
+ None = 0,
+ Feature,
+ Release,
+ Hotfix,
+ }
+
+ public class GitFlow
+ {
+ public string Master { get; set; } = string.Empty;
+ public string Develop { get; set; } = string.Empty;
+ public string FeaturePrefix { get; set; } = string.Empty;
+ public string ReleasePrefix { get; set; } = string.Empty;
+ public string HotfixPrefix { get; set; } = string.Empty;
+
+ public bool IsValid
+ {
+ get
+ {
+ return !string.IsNullOrEmpty(Master) &&
+ !string.IsNullOrEmpty(Develop) &&
+ !string.IsNullOrEmpty(FeaturePrefix) &&
+ !string.IsNullOrEmpty(ReleasePrefix) &&
+ !string.IsNullOrEmpty(HotfixPrefix);
+ }
+ }
+
+ public string GetPrefix(GitFlowBranchType type)
+ {
+ switch (type)
+ {
+ case GitFlowBranchType.Feature:
+ return FeaturePrefix;
+ case GitFlowBranchType.Release:
+ return ReleasePrefix;
+ case GitFlowBranchType.Hotfix:
+ return HotfixPrefix;
+ default:
+ return string.Empty;
+ }
+ }
+ }
+}
diff --git a/src/Models/IRepository.cs b/src/Models/IRepository.cs
index 0224d81f..2fc7c612 100644
--- a/src/Models/IRepository.cs
+++ b/src/Models/IRepository.cs
@@ -2,6 +2,8 @@
{
public interface IRepository
{
+ bool MayHaveSubmodules();
+
void RefreshBranches();
void RefreshWorktrees();
void RefreshTags();
diff --git a/src/Models/Remote.cs b/src/Models/Remote.cs
index ec9b8f20..6e36cfb9 100644
--- a/src/Models/Remote.cs
+++ b/src/Models/Remote.cs
@@ -6,8 +6,10 @@ namespace SourceGit.Models
{
public partial class Remote
{
- [GeneratedRegex(@"^https?://([-a-zA-Z0-9:%._\+~#=]+@)?[-a-zA-Z0-9:%._\+~#=]{1,256}(\.[a-zA-Z0-9()]{1,6})?(:[0-9]{1,5})?\b(/[-a-zA-Z0-9()@:%_\+.~#?&=]+)+(\.git)?$")]
+ [GeneratedRegex(@"^https?://[^/]+/.+[^/\.]$")]
private static partial Regex REG_HTTPS();
+ [GeneratedRegex(@"^git://[^/]+/.+[^/\.]$")]
+ private static partial Regex REG_GIT();
[GeneratedRegex(@"^[\w\-]+@[\w\.\-]+(\:[0-9]+)?:([a-zA-z0-9~%][\w\-\./~%]*)?[a-zA-Z0-9](\.git)?$")]
private static partial Regex REG_SSH1();
[GeneratedRegex(@"^ssh://([\w\-]+@)?[\w\.\-]+(\:[0-9]+)?/([a-zA-z0-9~%][\w\-\./~%]*)?[a-zA-Z0-9](\.git)?$")]
@@ -18,6 +20,7 @@ namespace SourceGit.Models
private static readonly Regex[] URL_FORMATS = [
REG_HTTPS(),
+ REG_GIT(),
REG_SSH1(),
REG_SSH2(),
];
@@ -30,13 +33,10 @@ namespace SourceGit.Models
if (string.IsNullOrWhiteSpace(url))
return false;
- for (int i = 1; i < URL_FORMATS.Length; i++)
- {
- if (URL_FORMATS[i].IsMatch(url))
- return true;
- }
+ if (REG_SSH1().IsMatch(url))
+ return true;
- return false;
+ return REG_SSH2().IsMatch(url);
}
public static bool IsValidURL(string url)
@@ -50,7 +50,10 @@ namespace SourceGit.Models
return true;
}
- return url.EndsWith(".git", StringComparison.Ordinal) && Directory.Exists(url);
+ return url.StartsWith("file://", StringComparison.Ordinal) ||
+ url.StartsWith("./", StringComparison.Ordinal) ||
+ url.StartsWith("../", StringComparison.Ordinal) ||
+ Directory.Exists(url);
}
public bool TryGetVisitURL(out string url)
diff --git a/src/Models/RepositorySettings.cs b/src/Models/RepositorySettings.cs
index 9af032bb..34189073 100644
--- a/src/Models/RepositorySettings.cs
+++ b/src/Models/RepositorySettings.cs
@@ -80,18 +80,6 @@ namespace SourceGit.Models
set;
} = true;
- public bool FetchWithoutTagsOnPull
- {
- get;
- set;
- } = false;
-
- public bool FetchAllBranchesOnPull
- {
- get;
- set;
- } = true;
-
public bool CheckSubmodulesOnPush
{
get;
@@ -417,6 +405,7 @@ namespace SourceGit.Models
public void PushCommitMessage(string message)
{
+ message = message.Trim().ReplaceLineEndings("\n");
var existIdx = CommitMessages.IndexOf(message);
if (existIdx == 0)
return;
diff --git a/src/Models/Watcher.cs b/src/Models/Watcher.cs
index e930f412..928951ca 100644
--- a/src/Models/Watcher.cs
+++ b/src/Models/Watcher.cs
@@ -107,7 +107,6 @@ namespace SourceGit.Models
{
_updateBranch = 0;
_updateWC = 0;
- _updateSubmodules = 0;
if (_updateTags > 0)
{
@@ -115,10 +114,15 @@ namespace SourceGit.Models
Task.Run(_repo.RefreshTags);
}
+ if (_updateSubmodules > 0 || _repo.MayHaveSubmodules())
+ {
+ _updateSubmodules = 0;
+ Task.Run(_repo.RefreshSubmodules);
+ }
+
Task.Run(_repo.RefreshBranches);
Task.Run(_repo.RefreshCommits);
Task.Run(_repo.RefreshWorkingCopyChanges);
- Task.Run(_repo.RefreshSubmodules);
Task.Run(_repo.RefreshWorktrees);
}
@@ -150,14 +154,29 @@ namespace SourceGit.Models
private void OnRepositoryChanged(object o, FileSystemEventArgs e)
{
- if (string.IsNullOrEmpty(e.Name) || e.Name.EndsWith(".lock", StringComparison.Ordinal))
+ if (string.IsNullOrEmpty(e.Name))
return;
var name = e.Name.Replace("\\", "/");
- if (name.StartsWith("modules", StringComparison.Ordinal) && name.EndsWith("HEAD", StringComparison.Ordinal))
+ if (name.Contains("fsmonitor--daemon/", StringComparison.Ordinal) ||
+ name.EndsWith(".lock", StringComparison.Ordinal) ||
+ name.StartsWith("lfs/", StringComparison.Ordinal))
+ return;
+
+ if (name.StartsWith("modules", StringComparison.Ordinal))
{
- _updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime();
- _updateWC = DateTime.Now.AddSeconds(1).ToFileTime();
+ if (name.EndsWith("/HEAD", StringComparison.Ordinal) ||
+ name.EndsWith("/ORIG_HEAD", StringComparison.Ordinal))
+ {
+ _updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime();
+ _updateWC = DateTime.Now.AddSeconds(1).ToFileTime();
+ }
+ }
+ else if (name.Equals("MERGE_HEAD", StringComparison.Ordinal) ||
+ name.Equals("AUTO_MERGE", StringComparison.Ordinal))
+ {
+ if (_repo.MayHaveSubmodules())
+ _updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime();
}
else if (name.StartsWith("refs/tags", StringComparison.Ordinal))
{
@@ -187,9 +206,20 @@ namespace SourceGit.Models
return;
var name = e.Name.Replace("\\", "/");
- if (name == ".git" || name.StartsWith(".git/", StringComparison.Ordinal))
+ if (name.Equals(".git", StringComparison.Ordinal) ||
+ name.StartsWith(".git/", StringComparison.Ordinal) ||
+ name.EndsWith("/.git", StringComparison.Ordinal))
return;
+ if (name.StartsWith(".vs/", StringComparison.Ordinal))
+ return;
+
+ if (name.Equals(".gitmodules", StringComparison.Ordinal))
+ {
+ _updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime();
+ return;
+ }
+
lock (_lockSubmodule)
{
foreach (var submodule in _submodules)
diff --git a/src/Native/OS.cs b/src/Native/OS.cs
index 4c891283..ad6f8104 100644
--- a/src/Native/OS.cs
+++ b/src/Native/OS.cs
@@ -124,7 +124,7 @@ namespace SourceGit.Native
Directory.CreateDirectory(DataDir);
}
- public static void SetupEnternalTools()
+ public static void SetupExternalTools()
{
ExternalTools = _backend.FindExternalTools();
}
diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml
index 30750931..886a07cf 100644
--- a/src/Resources/Locales/de_DE.axaml
+++ b/src/Resources/Locales/de_DE.axaml
@@ -292,7 +292,6 @@
Ausgewähltes Repository bearbeiten
Führe benutzerdefinierte Aktion aus
Name der Aktion:
- Fast-Forward (ohne Auschecken)
Fetch
Alle Remotes fetchen
Aktiviere '--force' Option
@@ -527,12 +526,10 @@
Worktree Informationen in `$GIT_COMMON_DIR/worktrees` löschen
Pull
Remote-Branch:
- Alle Branches fetchen
Lokaler Branch:
Lokale Änderungen:
Verwerfen
Stashen & wieder anwenden
- Ohne Tags fetchen
Remote:
Pull (Fetch & Merge)
Rebase anstatt Merge verwenden
diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml
index bb259272..c12396ec 100644
--- a/src/Resources/Locales/en_US.axaml
+++ b/src/Resources/Locales/en_US.axaml
@@ -63,6 +63,7 @@
Push ${0}$
Rebase ${0}$ on ${1}$...
Rename ${0}$...
+ Reset ${0}$ to ${1}$...
Set Tracking Branch...
Branch Compare
Invalid upstream!
@@ -124,6 +125,7 @@
Squash into Parent
Squash Children into Here
CHANGES
+ changed file(s)
Search Changes...
FILES
LFS File
@@ -215,6 +217,7 @@
Enter branch name.
Spaces will be replaced with dashes.
Create Local Branch
+ Overwrite existing branch
Create Tag...
New Tag At:
GPG signing
@@ -229,6 +232,9 @@
lightweight
Hold Ctrl to start directly
Cut
+ De-initialize Submodule
+ Force de-init even if it contains local changes.
+ Submodule:
Delete Branch
Branch:
You are about to delete a remote branch!!!
@@ -264,6 +270,7 @@
Show hidden symbols
Side-By-Side Diff
SUBMODULE
+ DELETED
NEW
Swap
Syntax Highlighting
@@ -288,7 +295,6 @@
Edit Selected Repository
Run Custom Action
Action Name:
- Fast-Forward (without checkout)
Fetch
Fetch all remotes
Force override local refs
@@ -530,12 +536,11 @@
Prune worktree information in `$GIT_COMMON_DIR/worktrees`
Pull
Remote Branch:
- Fetch all branches
Into:
Local Changes:
Discard
Stash & Reapply
- Fetch without tags
+ Update all submodules
Remote:
Pull (Fetch & Merge)
Use rebase instead of merge
@@ -646,6 +651,9 @@
Reset Mode:
Move To:
Current Branch:
+ Reset Branch (Without Checkout)
+ Move To:
+ Branch:
Reveal in File Explorer
Revert Commit
Commit:
@@ -705,6 +713,7 @@
SUBMODULES
Add Submodule
Copy Relative Path
+ De-initialize Submodule
Fetch nested submodules
Open Submodule Repository
Relative Path:
diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml
index e2b16329..513eeb06 100644
--- a/src/Resources/Locales/es_ES.axaml
+++ b/src/Resources/Locales/es_ES.axaml
@@ -67,6 +67,7 @@
Push ${0}$
Rebase ${0}$ en ${1}$...
Renombrar ${0}$...
+ Resetear ${0}$ a ${1}$...
Establecer Rama de Seguimiento...
Comparar Ramas
¡Upstream inválido!
@@ -128,6 +129,7 @@
Squash en Parent
Squash Commits Hijos hasta Aquí
CAMBIOS
+ archivo(s) modificado(s)
Buscar Cambios...
ARCHIVOS
Archivo LFS
@@ -233,6 +235,9 @@
ligera
Mantenga Ctrl para iniciar directamente
Cortar
+ Desinicializar Submódulo
+ Forzar desinicialización incluso si contiene cambios locales.
+ Submódulo:
Eliminar Rama
Rama:
¡Estás a punto de eliminar una rama remota!
@@ -268,6 +273,7 @@
Mostrar símbolos ocultos
Diferencia Lado a Lado
SUBMÓDULO
+ BORRADO
NUEVO
Intercambiar
Resaltado de Sintaxis
@@ -292,7 +298,6 @@
Editar Repositorio Seleccionado
Ejecutar Acción Personalizada
Nombre de la Acción:
- Fast-Forward (sin checkout)
Fetch
Fetch todos los remotos
Utilizar opción '--force'
@@ -390,6 +395,8 @@
Ir a la página anterior
Crear nueva página
Abrir diálogo de preferencias
+ Cambiar espacio de trabajo activo
+ Cambiar página activa
REPOSITORIO
Commit cambios staged
Commit y push cambios staged
@@ -432,6 +439,8 @@
Abrir en el Navegador
ERROR
AVISO
+ Espacios de trabajo
+ Páginas
Merge Rama
En:
Opción de Merge:
@@ -530,12 +539,11 @@
Podar información de worktree en `$GIT_COMMON_DIR/worktrees`
Pull
Rama Remota:
- Fetch todas las ramas
En:
Cambios Locales:
Descartar
Stash & Reaplicar
- Fetch sin etiquetas
+ Actualizar todos los submódulos
Remoto:
Pull (Fetch & Merge)
Usar rebase en lugar de merge
@@ -646,6 +654,9 @@
Modo de Reset:
Mover a:
Rama Actual:
+ Resetear Rama (Sin hacer Checkout)
+ Mover A:
+ Rama:
Revelar en el Explorador de Archivos
Revertir Commit
Commit:
@@ -705,6 +716,7 @@
SUBMÓDULOS
Añadir Submódulo
Copiar Ruta Relativa
+ Desinicializar Submódulo
Fetch submódulos anidados
Abrir Repositorio del Submódulo
Ruta Relativa:
diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml
index 0529702d..0c3ab91b 100644
--- a/src/Resources/Locales/fr_FR.axaml
+++ b/src/Resources/Locales/fr_FR.axaml
@@ -275,7 +275,6 @@
Éditer le dépôt sélectionné
Lancer action personnalisée
Nom de l'action :
- Fast-Forward (sans récupération)
Fetch
Fetch toutes les branches distantes
Outrepasser les vérifications de refs
@@ -509,12 +508,10 @@
Élaguer les information de worktree dans `$GIT_COMMON_DIR/worktrees`
Pull
Branche distante :
- Fetch toutes les branches
Dans :
Changements locaux :
Rejeter
Stash & Réappliquer
- Fetch sans les tags
Dépôt distant :
Pull (Fetch & Merge)
Utiliser rebase au lieu de merge
diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml
index 05fee42b..23c31c6e 100644
--- a/src/Resources/Locales/it_IT.axaml
+++ b/src/Resources/Locales/it_IT.axaml
@@ -292,7 +292,6 @@
Modifica Repository Selezionato
Esegui Azione Personalizzata
Nome Azione:
- Avanzamento Veloce (senza verifica)
Recupera
Recupera da tutti i remoti
Forza la sovrascrittura dei riferimenti locali
@@ -530,12 +529,10 @@
Potatura delle informazioni di worktree in `$GIT_COMMON_DIR/worktrees`
Scarica
Branch Remoto:
- Recupera tutti i branch
In:
Modifiche Locali:
Scarta
Stasha e Riapplica
- Recupera senza tag
Remoto:
Scarica (Recupera e Unisci)
Riallineare anziché unire
diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml
index 48d55500..ca29b985 100644
--- a/src/Resources/Locales/ja_JP.axaml
+++ b/src/Resources/Locales/ja_JP.axaml
@@ -275,7 +275,6 @@
選択中のリポジトリを編集
カスタムアクションを実行
アクション名:
- (チェックアウトせずに)ブランチを早送りする
フェッチ
すべてのリモートをフェッチ
ローカル参照を強制的に上書き
@@ -509,12 +508,10 @@
`$GIT_DIR/worktrees` の作業ツリー情報を削除
プル
ブランチ:
- すべてのブランチをフェッチ
宛先:
ローカルの変更:
破棄
スタッシュして再適用
- タグなしでフェッチ
リモート:
プル (フェッチ & マージ)
マージの代わりにリベースを使用
diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml
index 2a693151..7ce861e9 100644
--- a/src/Resources/Locales/pt_BR.axaml
+++ b/src/Resources/Locales/pt_BR.axaml
@@ -249,7 +249,6 @@
Editar Repositório Selecionado
Executar ação customizada
Nome da ação:
- Fast-Forward (sem checkout)
Buscar
Buscar todos os remotos
Buscar sem tags
@@ -465,12 +464,10 @@
Podar informações de worktree em `$GIT_COMMON_DIR/worktrees`
Puxar
Branch Remoto:
- Buscar todos os branches
Para:
Alterações Locais:
Descartar
Guardar & Reaplicar
- Buscar sem tags
Remoto:
Puxar (Buscar & Mesclar)
Usar rebase em vez de merge
diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml
index 77a7ba4f..bc72fd65 100644
--- a/src/Resources/Locales/ru_RU.axaml
+++ b/src/Resources/Locales/ru_RU.axaml
@@ -67,6 +67,7 @@
Выложить ${0}$
Переместить ${0}$ на ${1}$...
Переименовать ${0}$...
+ Сбросить ${0}$ к ${1}$...
Отслеживать ветку...
Сравнение веток
Недопустимая основная ветка!
@@ -128,6 +129,7 @@
Объединить с предыдущей ревизией
Объединить все следующие ревизии с этим
ИЗМЕНЕНИЯ
+ изменённый(х) файл(ов)
Найти изменения....
ФАЙЛЫ
Файл LFS
@@ -219,6 +221,7 @@
Введите имя ветки.
Пробелы будут заменены на тире.
Создать локальную ветку
+ Перезаписать существующую ветку
Создать метку...
Новая метка у:
GPG подпись
@@ -233,6 +236,9 @@
Простой
Удерживайте Ctrl, чтобы сразу начать
Вырезать
+ Удалить подмодуль
+ Принудительно удалить даже если содержит локальные изменения.
+ Подмодуль:
Удалить ветку
Ветка:
Вы собираетесь удалить внешнюю ветку!!!
@@ -268,6 +274,7 @@
Показывать скрытые символы
Сравнение рядом
ПОДМОДУЛЬ
+ УДАЛЁН
НОВЫЙ
Обмен
Подсветка синтаксиса
@@ -292,7 +299,6 @@
Редактировать выбранный репозиторий
Выполнить пользовательское действие
Имя действия:
- Быстрая перемотка вперёд (без проверки)
Извлечь
Извлечь все внешние репозитории
Разрешить опцию (--force)
@@ -391,6 +397,7 @@
Создать новую вкладку
Открыть диалоговое окно настроек
Переключить активное рабочее место
+ Переключить активную страницу
РЕПОЗИТОРИЙ
Зафиксировать сформированные изменения
Зафиксировать и выложить сформированные изменения
@@ -434,6 +441,7 @@
ОШИБКА
УВЕДОМЛЕНИЕ
Рабочие места
+ Страницы
Влить ветку
В:
Опции слияния:
@@ -532,12 +540,11 @@
Информация об обрезке рабочего каталога в «$GIT_COMMON_DIR/worktrees»
Загрузить
Ветка внешнего репозитория:
- Извлечь все ветки
В:
Локальные изменения:
Отклонить
Отложить и применить повторно
- Загрузить без меток
+ Обновить все подмодули
Внешний репозиторий:
Загрузить (Получить и слить)
Использовать перемещение вместо слияния
@@ -648,6 +655,9 @@
Режим сброса:
Переместить в:
Текущая ветка:
+ Сброс ветки (без переключения)
+ Переместить в:
+ Ветка:
Открыть в файловом менеджере
Отменить ревизию
Ревизия:
@@ -707,6 +717,7 @@
ПОДМОДУЛИ
Добавить подмодули
Копировать относительный путь
+ Удалить подмодуль
Извлечение вложенных подмодулей
Открыть подмодуль репозитория
Каталог:
diff --git a/src/Resources/Locales/ta_IN.axaml b/src/Resources/Locales/ta_IN.axaml
index 02c138c6..71df97c0 100644
--- a/src/Resources/Locales/ta_IN.axaml
+++ b/src/Resources/Locales/ta_IN.axaml
@@ -275,7 +275,6 @@
தேர்ந்தெடுக்கப்பட்ட களஞ்சியத்தைத் திருத்து
தனிப்பயன் செயலை இயக்கு
செயல் பெயர்:
- வேகமாக முன்னோக்கி (சரிபார்க்காமல்)
பெறு
எல்லா தொலைகளையும் பெறு
உள்ளக குறிப்புகளை கட்டாயமாக மீறு
@@ -509,12 +508,10 @@
`$GIT_COMMON_DIR/பணிமரங்கள்` இதில் பணிமரம் தகவலை கத்தரி
இழு
தொலை கிளை:
- எல்லா கிளைகளையும் எடு
இதனுள்:
உள்ளக மாற்றங்கள்:
நிராகரி
பதுக்கிவை & மீண்டும் இடு
- குறிச்சொற்கள் இல்லாமல் பெறு
தொலை:
இழு (எடுத்து ஒன்றிணை)
ஒன்றிணை என்பதற்குப் பதிலாக மறுதளத்தைப் பயன்படுத்து
diff --git a/src/Resources/Locales/uk_UA.axaml b/src/Resources/Locales/uk_UA.axaml
index a3b63bde..297878a6 100644
--- a/src/Resources/Locales/uk_UA.axaml
+++ b/src/Resources/Locales/uk_UA.axaml
@@ -279,7 +279,6 @@
Редагувати вибраний репозиторій
Виконати спеціальну дію
Ім'я дії:
- Перемотати (без перемкнуття)
Витягти
Витягти всі віддалені сховища
Примусово перезаписати локальні refs
@@ -513,12 +512,10 @@
Видалити застарілу інформацію про робочі дерева в `$GIT_COMMON_DIR/worktrees`
Pull (Витягти)
Віддалена гілка:
- Отримати всі гілки
В:
Локальні зміни:
Скасувати
Сховати та Застосувати
- Отримати без тегів
Віддалене сховище:
Pull (Fetch & Merge)
Використовувати rebase замість merge
diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml
index 18569a14..00939656 100644
--- a/src/Resources/Locales/zh_CN.axaml
+++ b/src/Resources/Locales/zh_CN.axaml
@@ -65,8 +65,9 @@
拉回(pull) ${0}$
拉回(pull) ${0}$ 内容至 ${1}$...
推送(push)${0}$
- 变基(rebase) ${0}$ 分支至 ${1}$...
+ 变基(rebase) ${0}$ 至 ${1}$...
重命名 ${0}$...
+ 重置 ${0}$ 到 ${1}$...
切换上游分支 ...
分支比较
跟踪的上游分支不存在或已删除!
@@ -128,6 +129,7 @@
合并此提交到上一个提交
合并之后的提交到此处
变更对比
+ 个文件发生变更
查找变更...
文件列表
LFS文件
@@ -219,6 +221,7 @@
填写分支名称。
空格将被替换为'-'符号
创建本地分支
+ 允许重置已存在的分支
新建标签 ...
标签位于 :
使用GPG签名
@@ -233,6 +236,9 @@
轻量标签
按住Ctrl键点击将以默认参数运行
剪切
+ 取消初始化子模块
+ 强制取消,即使包含本地变更
+ 子模块 :
删除分支确认
分支名 :
您正在删除远程上的分支,请务必小心!!!
@@ -268,6 +274,7 @@
显示隐藏符号
分列对比
子模块
+ 删除
新增
交换比对双方
语法高亮
@@ -292,7 +299,6 @@
编辑仓库
执行自定义操作
自定义操作 :
- 快进(fast-forward,无需checkout)
拉取(fetch)
拉取所有的远程仓库
强制覆盖本地REFs
@@ -534,12 +540,11 @@
清理在`$GIT_COMMON_DIR/worktrees`中的无效工作树信息
拉回(pull)
拉取分支 :
- 拉取远程中的所有分支变更
本地分支 :
未提交更改 :
丢弃更改
贮藏并自动恢复
- 不拉取远程标签
+ 同时更新所有子模块
远程 :
拉回(拉取并合并)
使用变基方式合并分支
@@ -650,6 +655,9 @@
重置模式 :
提交 :
当前分支 :
+ 重置所选分支(非当前分支)
+ 重置点 :
+ 操作分支 :
在文件浏览器中查看
回滚操作确认
目标提交 :
@@ -709,6 +717,7 @@
子模块
添加子模块
复制路径
+ 取消初始化
拉取子孙模块
打开仓库
相对仓库路径 :
diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml
index ded99a14..026a41ed 100644
--- a/src/Resources/Locales/zh_TW.axaml
+++ b/src/Resources/Locales/zh_TW.axaml
@@ -67,6 +67,7 @@
推送 (push) ${0}$
重定基底 (rebase) ${0}$ 分支至 ${1}$...
重新命名 ${0}$...
+ 重設 ${0}$ 至 ${1}$...
切換上游分支...
分支比較
追蹤上游分支不存在或已刪除!
@@ -128,6 +129,7 @@
合併此提交到上一個提交
合併之後的提交到此處
變更對比
+ 個檔案已變更
搜尋變更...
檔案列表
LFS 檔案
@@ -219,6 +221,7 @@
輸入分支名稱。
空格將以英文破折號取代
建立本機分支
+ 允許覆寫現有分支
新增標籤...
標籤位於:
使用 GPG 簽章
@@ -233,6 +236,9 @@
輕量標籤
按住 Ctrl 鍵將直接以預設參數執行
剪下
+ 取消初始化子模組
+ 強制取消,即使它包含本地變更
+ 子模組 :
刪除分支確認
分支名稱:
您正在刪除遠端上的分支,請務必小心!
@@ -268,6 +274,7 @@
顯示隱藏符號
並排對比
子模組
+ 已刪除
新增
交換比對雙方
語法上色
@@ -292,7 +299,6 @@
編輯存放庫
執行自訂動作
自訂動作:
- 快進 (fast-forward,無需 checkout)
提取 (fetch)
提取所有的遠端存放庫
強制覆寫本機 REFs
@@ -534,12 +540,11 @@
清理在 `$GIT_COMMON_DIR/worktrees` 中的無效工作區資訊
拉取 (pull)
拉取分支:
- 拉取遠端中的所有分支
本機分支:
未提交變更:
捨棄變更
擱置變更並自動復原
- 不拉取遠端標籤
+ 同時更新所有子模組
遠端:
拉取 (提取並合併)
使用重定基底 (rebase) 合併分支
@@ -650,6 +655,9 @@
重設模式:
移至提交:
目前分支:
+ 重設選取的分支(非目前分支)
+ 重設位置 :
+ 選取分支 :
在檔案瀏覽器中檢視
復原操作確認
目標提交:
@@ -709,6 +717,7 @@
子模組
新增子模組
複製路徑
+ 取消初始化
提取子模組
開啟存放庫
相對存放庫路徑:
diff --git a/src/ViewModels/AddSubmodule.cs b/src/ViewModels/AddSubmodule.cs
index cf1bd8a3..82a1f62a 100644
--- a/src/ViewModels/AddSubmodule.cs
+++ b/src/ViewModels/AddSubmodule.cs
@@ -1,4 +1,5 @@
-using System.ComponentModel.DataAnnotations;
+using System;
+using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Threading.Tasks;
@@ -14,12 +15,10 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _url, value, true);
}
- [Required(ErrorMessage = "Reletive path is required!!!")]
- [CustomValidation(typeof(AddSubmodule), nameof(ValidateRelativePath))]
public string RelativePath
{
get => _relativePath;
- set => SetProperty(ref _relativePath, value, true);
+ set => SetProperty(ref _relativePath, value);
}
public bool Recursive
@@ -37,20 +36,6 @@ namespace SourceGit.ViewModels
{
if (!Models.Remote.IsValidURL(url))
return new ValidationResult("Invalid repository URL format");
- return ValidationResult.Success;
- }
-
- public static ValidationResult ValidateRelativePath(string path, ValidationContext ctx)
- {
- if (Path.Exists(path))
- {
- return new ValidationResult("Give path is exists already!");
- }
-
- if (Path.IsPathRooted(path))
- {
- return new ValidationResult("Path must be relative to this repository!");
- }
return ValidationResult.Success;
}
@@ -63,9 +48,20 @@ namespace SourceGit.ViewModels
var log = _repo.CreateLog("Add Submodule");
Use(log);
+ var relativePath = _relativePath;
+ if (string.IsNullOrEmpty(relativePath))
+ {
+ if (_url.EndsWith("/.git", StringComparison.Ordinal))
+ relativePath = Path.GetFileName(Path.GetDirectoryName(_url));
+ else if (_url.EndsWith(".git", StringComparison.Ordinal))
+ relativePath = Path.GetFileNameWithoutExtension(_url);
+ else
+ relativePath = Path.GetFileName(_url);
+ }
+
return Task.Run(() =>
{
- var succ = new Commands.Submodule(_repo.FullPath).Use(log).Add(_url, _relativePath, Recursive);
+ var succ = new Commands.Submodule(_repo.FullPath).Use(log).Add(_url, relativePath, Recursive);
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
diff --git a/src/ViewModels/Checkout.cs b/src/ViewModels/Checkout.cs
index d8e9b38a..630a97a5 100644
--- a/src/ViewModels/Checkout.cs
+++ b/src/ViewModels/Checkout.cs
@@ -17,8 +17,7 @@ namespace SourceGit.ViewModels
public bool IsRecurseSubmoduleVisible
{
- get;
- private set;
+ get => _repo.Submodules.Count > 0;
}
public bool RecurseSubmodules
@@ -32,7 +31,6 @@ namespace SourceGit.ViewModels
_repo = repo;
Branch = branch;
DiscardLocalChanges = false;
- IsRecurseSubmoduleVisible = repo.Submodules.Count > 0;
}
public override Task Sure()
@@ -76,9 +74,9 @@ namespace SourceGit.ViewModels
{
if (updateSubmodules)
{
- var submodules = new Commands.QuerySubmodules(_repo.FullPath).Result();
+ var submodules = new Commands.QueryUpdatableSubmodules(_repo.FullPath).Result();
if (submodules.Count > 0)
- new Commands.Submodule(_repo.FullPath).Use(log).Update(submodules, true, true, false);
+ new Commands.Submodule(_repo.FullPath).Use(log).Update(submodules, true, true);
}
if (needPopStash)
diff --git a/src/ViewModels/CheckoutCommit.cs b/src/ViewModels/CheckoutCommit.cs
index a8c5b8cf..c41fd2ce 100644
--- a/src/ViewModels/CheckoutCommit.cs
+++ b/src/ViewModels/CheckoutCommit.cs
@@ -17,8 +17,7 @@ namespace SourceGit.ViewModels
public bool IsRecurseSubmoduleVisible
{
- get;
- private set;
+ get => _repo.Submodules.Count > 0;
}
public bool RecurseSubmodules
@@ -32,7 +31,6 @@ namespace SourceGit.ViewModels
_repo = repo;
Commit = commit;
DiscardLocalChanges = false;
- IsRecurseSubmoduleVisible = repo.Submodules.Count > 0;
}
public override Task Sure()
@@ -76,9 +74,9 @@ namespace SourceGit.ViewModels
{
if (updateSubmodules)
{
- var submodules = new Commands.QuerySubmodules(_repo.FullPath).Result();
+ var submodules = new Commands.QueryUpdatableSubmodules(_repo.FullPath).Result();
if (submodules.Count > 0)
- new Commands.Submodule(_repo.FullPath).Use(log).Update(submodules, true, true, false);
+ new Commands.Submodule(_repo.FullPath).Use(log).Update(submodules, true, true);
}
if (needPop)
diff --git a/src/ViewModels/Clone.cs b/src/ViewModels/Clone.cs
index dd9cf86b..032551a2 100644
--- a/src/ViewModels/Clone.cs
+++ b/src/ViewModels/Clone.cs
@@ -140,9 +140,9 @@ namespace SourceGit.ViewModels
if (InitAndUpdateSubmodules)
{
- var submodules = new Commands.QuerySubmodules(path).Result();
+ var submodules = new Commands.QueryUpdatableSubmodules(path).Result();
if (submodules.Count > 0)
- new Commands.Submodule(path).Use(log).Update(submodules, true, true, false);
+ new Commands.Submodule(path).Use(log).Update(submodules, true, true);
}
log.Complete();
diff --git a/src/ViewModels/CommitDetail.cs b/src/ViewModels/CommitDetail.cs
index 3b411056..bd4f2284 100644
--- a/src/ViewModels/CommitDetail.cs
+++ b/src/ViewModels/CommitDetail.cs
@@ -15,7 +15,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
{
- public partial class CommitDetail : ObservableObject
+ public partial class CommitDetail : ObservableObject, IDisposable
{
public int ActivePageIndex
{
@@ -137,7 +137,7 @@ namespace SourceGit.ViewModels
WebLinks = Models.CommitLink.Get(repo.Remotes);
}
- public void Cleanup()
+ public void Dispose()
{
_repo = null;
_commit = null;
@@ -149,6 +149,7 @@ namespace SourceGit.ViewModels
_diffContext = null;
_viewRevisionFileContent = null;
_cancellationSource = null;
+ _requestingRevisionFiles = false;
_revisionFiles = null;
_revisionFileSearchSuggestion = null;
}
@@ -335,7 +336,7 @@ namespace SourceGit.ViewModels
options.DefaultExtension = ".patch";
options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }];
- var baseRevision = _commit.Parents.Count == 0 ? "4b825dc642cb6eb9a060e54bf8d69288fbee4904" : _commit.Parents[0];
+ var baseRevision = _commit.Parents.Count == 0 ? Models.Commit.EmptyTreeSHA1 : _commit.Parents[0];
var storageFile = await storageProvider.SaveFilePickerAsync(options);
if (storageFile != null)
{
@@ -546,6 +547,7 @@ namespace SourceGit.ViewModels
private void Refresh()
{
_changes = null;
+ _requestingRevisionFiles = false;
_revisionFiles = null;
SignInfo = null;
@@ -593,7 +595,7 @@ namespace SourceGit.ViewModels
Task.Run(() =>
{
- var parent = _commit.Parents.Count == 0 ? "4b825dc642cb6eb9a060e54bf8d69288fbee4904" : _commit.Parents[0];
+ var parent = _commit.Parents.Count == 0 ? Models.Commit.EmptyTreeSHA1 : _commit.Parents[0];
var cmd = new Commands.CompareRevisions(_repo.FullPath, parent, _commit.SHA) { CancellationToken = token };
var changes = cmd.Result();
var visible = changes;
@@ -812,16 +814,22 @@ namespace SourceGit.ViewModels
{
if (_revisionFiles == null)
{
+ if (_requestingRevisionFiles)
+ return;
+
var sha = Commit.SHA;
+ _requestingRevisionFiles = true;
Task.Run(() =>
{
var files = new Commands.QueryRevisionFileNames(_repo.FullPath, sha).Result();
Dispatcher.UIThread.Invoke(() =>
{
- if (sha == Commit.SHA)
+ if (sha == Commit.SHA && _requestingRevisionFiles)
{
_revisionFiles = files;
+ _requestingRevisionFiles = false;
+
if (!string.IsNullOrEmpty(_revisionFileSearchFilter))
CalcRevisionFileSearchSuggestion();
}
@@ -907,6 +915,7 @@ namespace SourceGit.ViewModels
private DiffContext _diffContext = null;
private object _viewRevisionFileContent = null;
private CancellationTokenSource _cancellationSource = null;
+ private bool _requestingRevisionFiles = false;
private List _revisionFiles = null;
private string _revisionFileSearchFilter = string.Empty;
private List _revisionFileSearchSuggestion = null;
diff --git a/src/ViewModels/Conflict.cs b/src/ViewModels/Conflict.cs
index 8c825081..add365a3 100644
--- a/src/ViewModels/Conflict.cs
+++ b/src/ViewModels/Conflict.cs
@@ -1,4 +1,6 @@
-namespace SourceGit.ViewModels
+using System;
+
+namespace SourceGit.ViewModels
{
public class ConflictSourceBranch
{
@@ -46,7 +48,8 @@
_wc = wc;
_change = change;
- IsResolved = new Commands.IsConflictResolved(repo.FullPath, change).Result();
+ var isSubmodule = repo.Submodules.Find(x => x.Path.Equals(change.Path, StringComparison.Ordinal)) != null;
+ IsResolved = !isSubmodule && new Commands.IsConflictResolved(repo.FullPath, change).Result();
var context = wc.InProgressContext;
if (context is CherryPickInProgress cherryPick)
diff --git a/src/ViewModels/CreateBranch.cs b/src/ViewModels/CreateBranch.cs
index 252802f4..e518e977 100644
--- a/src/ViewModels/CreateBranch.cs
+++ b/src/ViewModels/CreateBranch.cs
@@ -43,10 +43,19 @@ namespace SourceGit.ViewModels
get => _repo.IsBare;
}
+ public bool AllowOverwrite
+ {
+ get => _allowOverwrite;
+ set
+ {
+ if (SetProperty(ref _allowOverwrite, value))
+ ValidateProperty(_name, nameof(Name));
+ }
+ }
+
public bool IsRecurseSubmoduleVisible
{
- get;
- private set;
+ get => _repo.Submodules.Count > 0;
}
public bool RecurseSubmodules
@@ -67,7 +76,6 @@ namespace SourceGit.ViewModels
BasedOn = branch;
DiscardLocalChanges = false;
- IsRecurseSubmoduleVisible = repo.Submodules.Count > 0;
}
public CreateBranch(Repository repo, Models.Commit commit)
@@ -77,7 +85,6 @@ namespace SourceGit.ViewModels
BasedOn = commit;
DiscardLocalChanges = false;
- IsRecurseSubmoduleVisible = repo.Submodules.Count > 0;
}
public CreateBranch(Repository repo, Models.Tag tag)
@@ -87,23 +94,28 @@ namespace SourceGit.ViewModels
BasedOn = tag;
DiscardLocalChanges = false;
- IsRecurseSubmoduleVisible = repo.Submodules.Count > 0;
}
public static ValidationResult ValidateBranchName(string name, ValidationContext ctx)
{
- var creator = ctx.ObjectInstance as CreateBranch;
- if (creator == null)
- return new ValidationResult("Missing runtime context to create branch!");
-
- var fixedName = creator.FixName(name);
- foreach (var b in creator._repo.Branches)
+ if (ctx.ObjectInstance is CreateBranch creator)
{
- if (b.FriendlyName == fixedName)
- return new ValidationResult("A branch with same name already exists!");
- }
+ if (!creator._allowOverwrite)
+ {
+ var fixedName = creator.FixName(name);
+ foreach (var b in creator._repo.Branches)
+ {
+ if (b.FriendlyName == fixedName)
+ return new ValidationResult("A branch with same name already exists!");
+ }
+ }
- return ValidationResult.Success;
+ return ValidationResult.Success;
+ }
+ else
+ {
+ return new ValidationResult("Missing runtime context to create branch!");
+ }
}
public override Task Sure()
@@ -123,7 +135,7 @@ namespace SourceGit.ViewModels
var needPopStash = false;
if (DiscardLocalChanges)
{
- succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(fixedName, _baseOnRevision, true);
+ succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(fixedName, _baseOnRevision, true, _allowOverwrite);
}
else
{
@@ -141,16 +153,16 @@ namespace SourceGit.ViewModels
needPopStash = true;
}
- succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(fixedName, _baseOnRevision, false);
+ succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(fixedName, _baseOnRevision, false, _allowOverwrite);
}
if (succ)
{
if (updateSubmodules)
{
- var submodules = new Commands.QuerySubmodules(_repo.FullPath).Result();
+ var submodules = new Commands.QueryUpdatableSubmodules(_repo.FullPath).Result();
if (submodules.Count > 0)
- new Commands.Submodule(_repo.FullPath).Use(log).Update(submodules, true, true, false);
+ new Commands.Submodule(_repo.FullPath).Use(log).Update(submodules, true, true);
}
if (needPopStash)
@@ -159,7 +171,7 @@ namespace SourceGit.ViewModels
}
else
{
- succ = Commands.Branch.Create(_repo.FullPath, fixedName, _baseOnRevision, log);
+ succ = Commands.Branch.Create(_repo.FullPath, fixedName, _baseOnRevision, _allowOverwrite, log);
}
log.Complete();
@@ -205,5 +217,6 @@ namespace SourceGit.ViewModels
private readonly Repository _repo = null;
private string _name = null;
private readonly string _baseOnRevision = null;
+ private bool _allowOverwrite = false;
}
}
diff --git a/src/ViewModels/DeinitSubmodule.cs b/src/ViewModels/DeinitSubmodule.cs
new file mode 100644
index 00000000..a96a65d0
--- /dev/null
+++ b/src/ViewModels/DeinitSubmodule.cs
@@ -0,0 +1,45 @@
+using System.Threading.Tasks;
+
+namespace SourceGit.ViewModels
+{
+ public class DeinitSubmodule : Popup
+ {
+ public string Submodule
+ {
+ get;
+ private set;
+ }
+
+ public bool Force
+ {
+ get;
+ set;
+ }
+
+ public DeinitSubmodule(Repository repo, string submodule)
+ {
+ _repo = repo;
+ Submodule = submodule;
+ Force = false;
+ }
+
+ public override Task Sure()
+ {
+ _repo.SetWatcherEnabled(false);
+ ProgressDescription = "De-initialize Submodule";
+
+ var log = _repo.CreateLog("De-initialize Submodule");
+ Use(log);
+
+ return Task.Run(() =>
+ {
+ var succ = new Commands.Submodule(_repo.FullPath).Use(log).Deinit(Submodule, false);
+ log.Complete();
+ CallUIThread(() => _repo.SetWatcherEnabled(true));
+ return succ;
+ });
+ }
+
+ private Repository _repo;
+ }
+}
diff --git a/src/ViewModels/ExecuteCustomAction.cs b/src/ViewModels/ExecuteCustomAction.cs
index 52729e56..72570bf0 100644
--- a/src/ViewModels/ExecuteCustomAction.cs
+++ b/src/ViewModels/ExecuteCustomAction.cs
@@ -36,13 +36,17 @@ namespace SourceGit.ViewModels
_repo.SetWatcherEnabled(false);
ProgressDescription = "Run custom action ...";
+ var log = _repo.CreateLog(CustomAction.Name);
+ Use(log);
+
return Task.Run(() =>
{
if (CustomAction.WaitForExit)
- Commands.ExecuteCustomAction.RunAndWait(_repo.FullPath, CustomAction.Executable, _args, output => CallUIThread(() => ProgressDescription = output));
+ Commands.ExecuteCustomAction.RunAndWait(_repo.FullPath, CustomAction.Executable, _args, log);
else
Commands.ExecuteCustomAction.Run(_repo.FullPath, CustomAction.Executable, _args);
+ log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return true;
});
diff --git a/src/ViewModels/FastForwardWithoutCheckout.cs b/src/ViewModels/FastForwardWithoutCheckout.cs
deleted file mode 100644
index 53d69816..00000000
--- a/src/ViewModels/FastForwardWithoutCheckout.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using System.Threading.Tasks;
-
-namespace SourceGit.ViewModels
-{
- public class FastForwardWithoutCheckout : Popup
- {
- public Models.Branch Local
- {
- get;
- }
-
- public Models.Branch To
- {
- get;
- }
-
- public FastForwardWithoutCheckout(Repository repo, Models.Branch local, Models.Branch upstream)
- {
- _repo = repo;
- Local = local;
- To = upstream;
- }
-
- public override Task Sure()
- {
- _repo.SetWatcherEnabled(false);
- ProgressDescription = "Fast-Forward ...";
-
- var log = _repo.CreateLog("Fast-Forward (No checkout)");
- Use(log);
-
- return Task.Run(() =>
- {
- new Commands.UpdateRef(_repo.FullPath, Local.FullName, To.FullName).Use(log).Exec();
- log.Complete();
- CallUIThread(() =>
- {
- _repo.NavigateToCommit(To.Head);
- _repo.SetWatcherEnabled(true);
- });
- return true;
- });
- }
-
- private readonly Repository _repo = null;
- }
-}
diff --git a/src/ViewModels/Fetch.cs b/src/ViewModels/Fetch.cs
index fc92be81..b85b2b53 100644
--- a/src/ViewModels/Fetch.cs
+++ b/src/ViewModels/Fetch.cs
@@ -80,9 +80,16 @@ namespace SourceGit.ViewModels
log.Complete();
+ var upstream = _repo.CurrentBranch?.Upstream;
+ var upstreamHead = string.Empty;
+ if (!string.IsNullOrEmpty(upstream))
+ upstreamHead = new Commands.QueryRevisionByRefName(_repo.FullPath, upstream.Substring(13)).Result();
+
CallUIThread(() =>
{
- _repo.NavigateToBranchDelayed(_repo.CurrentBranch?.Upstream);
+ if (!string.IsNullOrEmpty(upstreamHead))
+ _repo.NavigateToCommitDelayed(upstreamHead);
+
_repo.MarkFetched();
_repo.SetWatcherEnabled(true);
});
diff --git a/src/ViewModels/FetchInto.cs b/src/ViewModels/FetchInto.cs
index eee87979..730c08b6 100644
--- a/src/ViewModels/FetchInto.cs
+++ b/src/ViewModels/FetchInto.cs
@@ -33,11 +33,14 @@ namespace SourceGit.ViewModels
{
new Commands.Fetch(_repo.FullPath, Local, Upstream).Use(log).Exec();
log.Complete();
+
+ var changedLocalBranchHead = new Commands.QueryRevisionByRefName(_repo.FullPath, Local.Name).Result();
CallUIThread(() =>
{
- _repo.NavigateToBranchDelayed(Upstream.FullName);
+ _repo.NavigateToCommitDelayed(changedLocalBranchHead);
_repo.SetWatcherEnabled(true);
});
+
return true;
});
}
diff --git a/src/ViewModels/GitFlowFinish.cs b/src/ViewModels/GitFlowFinish.cs
index d7ad5d31..bef4c2d9 100644
--- a/src/ViewModels/GitFlowFinish.cs
+++ b/src/ViewModels/GitFlowFinish.cs
@@ -9,9 +9,11 @@ namespace SourceGit.ViewModels
get;
}
- public bool IsFeature => _type == "feature";
- public bool IsRelease => _type == "release";
- public bool IsHotfix => _type == "hotfix";
+ public Models.GitFlowBranchType Type
+ {
+ get;
+ private set;
+ }
public bool Squash
{
@@ -31,27 +33,27 @@ namespace SourceGit.ViewModels
set;
} = false;
- public GitFlowFinish(Repository repo, Models.Branch branch, string type, string prefix)
+ public GitFlowFinish(Repository repo, Models.Branch branch, Models.GitFlowBranchType type)
{
_repo = repo;
- _type = type;
- _prefix = prefix;
Branch = branch;
+ Type = type;
}
public override Task Sure()
{
_repo.SetWatcherEnabled(false);
+ ProgressDescription = $"Git Flow - Finish {Branch.Name} ...";
- var name = Branch.Name.StartsWith(_prefix) ? Branch.Name.Substring(_prefix.Length) : Branch.Name;
- ProgressDescription = $"Git Flow - finishing {_type} {name} ...";
-
- var log = _repo.CreateLog("Gitflow - Finish");
+ var log = _repo.CreateLog("GitFlow - Finish");
Use(log);
+ var prefix = _repo.GitFlow.GetPrefix(Type);
+ var name = Branch.Name.StartsWith(prefix) ? Branch.Name.Substring(prefix.Length) : Branch.Name;
+
return Task.Run(() =>
{
- var succ = Commands.GitFlow.Finish(_repo.FullPath, _type, name, Squash, AutoPush, KeepBranch, log);
+ var succ = Commands.GitFlow.Finish(_repo.FullPath, Type, name, Squash, AutoPush, KeepBranch, log);
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ;
@@ -59,7 +61,5 @@ namespace SourceGit.ViewModels
}
private readonly Repository _repo;
- private readonly string _type;
- private readonly string _prefix;
}
}
diff --git a/src/ViewModels/GitFlowStart.cs b/src/ViewModels/GitFlowStart.cs
index 8e44984a..3ecba883 100644
--- a/src/ViewModels/GitFlowStart.cs
+++ b/src/ViewModels/GitFlowStart.cs
@@ -5,6 +5,18 @@ namespace SourceGit.ViewModels
{
public class GitFlowStart : Popup
{
+ public Models.GitFlowBranchType Type
+ {
+ get;
+ private set;
+ }
+
+ public string Prefix
+ {
+ get;
+ private set;
+ }
+
[Required(ErrorMessage = "Name is required!!!")]
[RegularExpression(@"^[\w\-/\.#]+$", ErrorMessage = "Bad branch name format!")]
[CustomValidation(typeof(GitFlowStart), nameof(ValidateBranchName))]
@@ -14,27 +26,19 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _name, value, true);
}
- public string Prefix
- {
- get => _prefix;
- }
-
- public bool IsFeature => _type == "feature";
- public bool IsRelease => _type == "release";
- public bool IsHotfix => _type == "hotfix";
-
- public GitFlowStart(Repository repo, string type)
+ public GitFlowStart(Repository repo, Models.GitFlowBranchType type)
{
_repo = repo;
- _type = type;
- _prefix = Commands.GitFlow.GetPrefix(repo.FullPath, type);
+
+ Type = type;
+ Prefix = _repo.GitFlow.GetPrefix(type);
}
public static ValidationResult ValidateBranchName(string name, ValidationContext ctx)
{
if (ctx.ObjectInstance is GitFlowStart starter)
{
- var check = $"{starter._prefix}{name}";
+ var check = $"{starter.Prefix}{name}";
foreach (var b in starter._repo.Branches)
{
if (b.FriendlyName == check)
@@ -48,14 +52,14 @@ namespace SourceGit.ViewModels
public override Task Sure()
{
_repo.SetWatcherEnabled(false);
- ProgressDescription = $"Git Flow - starting {_type} {_name} ...";
+ ProgressDescription = $"Git Flow - Start {Prefix}{_name} ...";
- var log = _repo.CreateLog("Gitflow - Start");
+ var log = _repo.CreateLog("GitFlow - Start");
Use(log);
return Task.Run(() =>
{
- var succ = Commands.GitFlow.Start(_repo.FullPath, _type, _name, log);
+ var succ = Commands.GitFlow.Start(_repo.FullPath, Type, _name, log);
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ;
@@ -63,8 +67,6 @@ namespace SourceGit.ViewModels
}
private readonly Repository _repo;
- private readonly string _type;
- private readonly string _prefix;
private string _name = null;
}
}
diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs
index f21d2636..2057a13f 100644
--- a/src/ViewModels/Histories.cs
+++ b/src/ViewModels/Histories.cs
@@ -12,7 +12,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
{
- public class Histories : ObservableObject
+ public class Histories : ObservableObject, IDisposable
{
public Repository Repo
{
@@ -57,7 +57,7 @@ namespace SourceGit.ViewModels
private set => SetProperty(ref _navigationId, value);
}
- public object DetailContext
+ public IDisposable DetailContext
{
get => _detailContext;
set => SetProperty(ref _detailContext, value);
@@ -98,23 +98,13 @@ namespace SourceGit.ViewModels
_repo = repo;
}
- public void Cleanup()
+ public void Dispose()
{
- Commits = new List();
-
+ Commits = [];
_repo = null;
_graph = null;
_autoSelectedCommit = null;
-
- if (_detailContext is CommitDetail cd)
- {
- cd.Cleanup();
- }
- else if (_detailContext is RevisionCompare rc)
- {
- rc.Cleanup();
- }
-
+ _detailContext?.Dispose();
_detailContext = null;
}
@@ -220,7 +210,7 @@ namespace SourceGit.ViewModels
else
{
_repo.SelectedSearchedCommit = null;
- DetailContext = commits.Count;
+ DetailContext = new Models.Count(commits.Count);
}
}
@@ -985,8 +975,8 @@ namespace SourceGit.ViewModels
if (!_repo.IsBare)
{
- var detect = Commands.GitFlow.DetectType(_repo.FullPath, _repo.Branches, current.Name);
- if (detect.IsGitFlowBranch)
+ var type = _repo.GetGitFlowType(current);
+ if (type != Models.GitFlowBranchType.None)
{
var finish = new MenuItem();
finish.Header = App.Text("BranchCM.Finish", current.Name);
@@ -994,7 +984,7 @@ namespace SourceGit.ViewModels
finish.Click += (_, e) =>
{
if (_repo.CanCreatePopup())
- _repo.ShowPopup(new GitFlowFinish(_repo, current, detect.Type, detect.Prefix));
+ _repo.ShowPopup(new GitFlowFinish(_repo, current, type));
e.Handled = true;
};
submenu.Items.Add(finish);
@@ -1073,8 +1063,8 @@ namespace SourceGit.ViewModels
if (!_repo.IsBare)
{
- var detect = Commands.GitFlow.DetectType(_repo.FullPath, _repo.Branches, branch.Name);
- if (detect.IsGitFlowBranch)
+ var type = _repo.GetGitFlowType(branch);
+ if (type != Models.GitFlowBranchType.None)
{
var finish = new MenuItem();
finish.Header = App.Text("BranchCM.Finish", branch.Name);
@@ -1082,7 +1072,7 @@ namespace SourceGit.ViewModels
finish.Click += (_, e) =>
{
if (_repo.CanCreatePopup())
- _repo.ShowPopup(new GitFlowFinish(_repo, branch, detect.Type, detect.Prefix));
+ _repo.ShowPopup(new GitFlowFinish(_repo, branch, type));
e.Handled = true;
};
submenu.Items.Add(finish);
@@ -1256,7 +1246,7 @@ namespace SourceGit.ViewModels
private Models.CommitGraph _graph = null;
private Models.Commit _autoSelectedCommit = null;
private long _navigationId = 0;
- private object _detailContext = null;
+ private IDisposable _detailContext = null;
private Models.Bisect _bisect = null;
diff --git a/src/ViewModels/InitGitFlow.cs b/src/ViewModels/InitGitFlow.cs
index 1672ef8e..dec587b0 100644
--- a/src/ViewModels/InitGitFlow.cs
+++ b/src/ViewModels/InitGitFlow.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@@ -109,9 +110,35 @@ namespace SourceGit.ViewModels
return Task.Run(() =>
{
- var succ = Commands.GitFlow.Init(
+ var succ = false;
+ var current = _repo.CurrentBranch;
+
+ var masterBranch = _repo.Branches.Find(x => x.IsLocal && x.Name.Equals(_master, StringComparison.Ordinal));
+ if (masterBranch == null)
+ {
+ succ = Commands.Branch.Create(_repo.FullPath, _master, current.Head, true, log);
+ if (!succ)
+ {
+ log.Complete();
+ CallUIThread(() => _repo.SetWatcherEnabled(true));
+ return false;
+ }
+ }
+
+ var developBranch = _repo.Branches.Find(x => x.IsLocal && x.Name.Equals(_develop, StringComparison.Ordinal));
+ if (developBranch == null)
+ {
+ succ = Commands.Branch.Create(_repo.FullPath, _develop, current.Head, true, log);
+ if (!succ)
+ {
+ log.Complete();
+ CallUIThread(() => _repo.SetWatcherEnabled(true));
+ return false;
+ }
+ }
+
+ succ = Commands.GitFlow.Init(
_repo.FullPath,
- _repo.Branches,
_master,
_develop,
_featurePrefix,
@@ -121,7 +148,23 @@ namespace SourceGit.ViewModels
log);
log.Complete();
- CallUIThread(() => _repo.SetWatcherEnabled(true));
+
+ CallUIThread(() =>
+ {
+ if (succ)
+ {
+ var gitflow = new Models.GitFlow();
+ gitflow.Master = _master;
+ gitflow.Develop = _develop;
+ gitflow.FeaturePrefix = _featurePrefix;
+ gitflow.ReleasePrefix = _releasePrefix;
+ gitflow.HotfixPrefix = _hotfixPrefix;
+ _repo.GitFlow = gitflow;
+ }
+
+ _repo.SetWatcherEnabled(true);
+ });
+
return succ;
});
}
diff --git a/src/ViewModels/InteractiveRebase.cs b/src/ViewModels/InteractiveRebase.cs
index 0e77eecf..1c4d4480 100644
--- a/src/ViewModels/InteractiveRebase.cs
+++ b/src/ViewModels/InteractiveRebase.cs
@@ -19,10 +19,23 @@ namespace SourceGit.ViewModels
private set;
}
+ public bool CanSquashOrFixup
+ {
+ get => _canSquashOrFixup;
+ set
+ {
+ if (SetProperty(ref _canSquashOrFixup, value))
+ {
+ if (_action == Models.InteractiveRebaseAction.Squash || _action == Models.InteractiveRebaseAction.Fixup)
+ Action = Models.InteractiveRebaseAction.Pick;
+ }
+ }
+ }
+
public Models.InteractiveRebaseAction Action
{
get => _action;
- private set => SetProperty(ref _action, value);
+ set => SetProperty(ref _action, value);
}
public string Subject
@@ -48,20 +61,17 @@ namespace SourceGit.ViewModels
}
}
- public InteractiveRebaseItem(Models.Commit c, string message)
+ public InteractiveRebaseItem(Models.Commit c, string message, bool canSquashOrFixup)
{
Commit = c;
FullMessage = message;
- }
-
- public void SetAction(object param)
- {
- Action = (Models.InteractiveRebaseAction)param;
+ CanSquashOrFixup = canSquashOrFixup;
}
private Models.InteractiveRebaseAction _action = Models.InteractiveRebaseAction.Pick;
private string _subject;
private string _fullMessage;
+ private bool _canSquashOrFixup = true;
}
public class InteractiveRebase : ObservableObject
@@ -88,7 +98,7 @@ namespace SourceGit.ViewModels
{
get;
private set;
- } = new AvaloniaList();
+ } = [];
public InteractiveRebaseItem SelectedItem
{
@@ -121,8 +131,11 @@ namespace SourceGit.ViewModels
var commits = new Commands.QueryCommitsForInteractiveRebase(repoPath, on.SHA).Result();
var list = new List();
- foreach (var c in commits)
- list.Add(new InteractiveRebaseItem(c.Commit, c.Message));
+ for (var i = 0; i < commits.Count; i++)
+ {
+ var c = commits[i];
+ list.Add(new InteractiveRebaseItem(c.Commit, c.Message, i < commits.Count - 1));
+ }
Dispatcher.UIThread.Invoke(() =>
{
@@ -141,6 +154,7 @@ namespace SourceGit.ViewModels
Items.RemoveAt(idx - 1);
Items.Insert(idx, prev);
SelectedItem = item;
+ UpdateItems();
}
}
@@ -153,9 +167,22 @@ namespace SourceGit.ViewModels
Items.RemoveAt(idx + 1);
Items.Insert(idx, next);
SelectedItem = item;
+ UpdateItems();
}
}
+ public void ChangeAction(InteractiveRebaseItem item, Models.InteractiveRebaseAction action)
+ {
+ if (!item.CanSquashOrFixup)
+ {
+ if (action == Models.InteractiveRebaseAction.Squash || action == Models.InteractiveRebaseAction.Fixup)
+ return;
+ }
+
+ item.Action = action;
+ UpdateItems();
+ }
+
public Task Start()
{
_repo.SetWatcherEnabled(false);
@@ -186,6 +213,27 @@ namespace SourceGit.ViewModels
});
}
+ private void UpdateItems()
+ {
+ if (Items.Count == 0)
+ return;
+
+ var hasValidParent = false;
+ for (var i = Items.Count - 1; i >= 0; i--)
+ {
+ var item = Items[i];
+ if (hasValidParent)
+ {
+ item.CanSquashOrFixup = true;
+ }
+ else
+ {
+ item.CanSquashOrFixup = false;
+ hasValidParent = item.Action != Models.InteractiveRebaseAction.Drop;
+ }
+ }
+ }
+
private Repository _repo = null;
private bool _isLoading = false;
private InteractiveRebaseItem _selectedItem = null;
diff --git a/src/ViewModels/Merge.cs b/src/ViewModels/Merge.cs
index d3d83836..2e276708 100644
--- a/src/ViewModels/Merge.cs
+++ b/src/ViewModels/Merge.cs
@@ -64,9 +64,10 @@ namespace SourceGit.ViewModels
new Commands.Merge(_repo.FullPath, _sourceName, Mode.Arg).Use(log).Exec();
log.Complete();
+ var head = new Commands.QueryRevisionByRefName(_repo.FullPath, "HEAD").Result();
CallUIThread(() =>
{
- _repo.NavigateToBranchDelayed(_repo.CurrentBranch?.FullName);
+ _repo.NavigateToCommitDelayed(head);
_repo.SetWatcherEnabled(true);
});
return true;
diff --git a/src/ViewModels/Popup.cs b/src/ViewModels/Popup.cs
index ec1e007c..b3fe7e23 100644
--- a/src/ViewModels/Popup.cs
+++ b/src/ViewModels/Popup.cs
@@ -48,7 +48,14 @@ namespace SourceGit.ViewModels
protected void Use(CommandLog log)
{
- log.Register(newline => ProgressDescription = newline.Trim());
+ log.Register(SetDescription);
+ }
+
+ private void SetDescription(string data)
+ {
+ var desc = data.Trim();
+ if (!string.IsNullOrEmpty(desc))
+ ProgressDescription = desc;
}
private bool _inProgress = false;
diff --git a/src/ViewModels/Pull.cs b/src/ViewModels/Pull.cs
index e13dad96..1b53949b 100644
--- a/src/ViewModels/Pull.cs
+++ b/src/ViewModels/Pull.cs
@@ -50,16 +50,15 @@ namespace SourceGit.ViewModels
set => _repo.Settings.PreferRebaseInsteadOfMerge = value;
}
- public bool FetchAllBranches
+ public bool IsRecurseSubmoduleVisible
{
- get => _repo.Settings.FetchAllBranchesOnPull;
- set => _repo.Settings.FetchAllBranchesOnPull = value;
+ get => _repo.Submodules.Count > 0;
}
- public bool NoTags
+ public bool RecurseSubmodules
{
- get => _repo.Settings.FetchWithoutTagsOnPull;
- set => _repo.Settings.FetchWithoutTagsOnPull = value;
+ get => _repo.Settings.UpdateSubmodulesOnCheckoutBranch;
+ set => _repo.Settings.UpdateSubmodulesOnCheckoutBranch = value;
}
public Pull(Repository repo, Models.Branch specifiedRemoteBranch)
@@ -119,6 +118,7 @@ namespace SourceGit.ViewModels
var log = _repo.CreateLog("Pull");
Use(log);
+ var updateSubmodules = IsRecurseSubmoduleVisible && RecurseSubmodules;
return Task.Run(() =>
{
var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result();
@@ -143,47 +143,31 @@ namespace SourceGit.ViewModels
}
}
- bool rs;
- if (FetchAllBranches)
+ bool rs = new Commands.Pull(
+ _repo.FullPath,
+ _selectedRemote.Name,
+ !string.IsNullOrEmpty(_current.Upstream) && _current.Upstream.Equals(_selectedBranch.FullName) ? string.Empty : _selectedBranch.Name,
+ UseRebase).Use(log).Exec();
+
+ if (rs)
{
- rs = new Commands.Fetch(
- _repo.FullPath,
- _selectedRemote.Name,
- NoTags,
- false).Use(log).Exec();
- if (!rs)
+ if (updateSubmodules)
{
- log.Complete();
- CallUIThread(() => _repo.SetWatcherEnabled(true));
- return false;
+ var submodules = new Commands.QueryUpdatableSubmodules(_repo.FullPath).Result();
+ if (submodules.Count > 0)
+ new Commands.Submodule(_repo.FullPath).Use(log).Update(submodules, true, true);
}
- _repo.MarkFetched();
-
- // Use merge/rebase instead of pull as fetch is done manually.
- if (UseRebase)
- rs = new Commands.Rebase(_repo.FullPath, _selectedBranch.FriendlyName, false).Use(log).Exec();
- else
- rs = new Commands.Merge(_repo.FullPath, _selectedBranch.FriendlyName, "").Use(log).Exec();
+ if (needPopStash)
+ new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}");
}
- else
- {
- rs = new Commands.Pull(
- _repo.FullPath,
- _selectedRemote.Name,
- _selectedBranch.Name,
- UseRebase,
- NoTags).Use(log).Exec();
- }
-
- if (rs && needPopStash)
- rs = new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}");
log.Complete();
+ var head = new Commands.QueryRevisionByRefName(_repo.FullPath, "HEAD").Result();
CallUIThread(() =>
{
- _repo.NavigateToBranchDelayed(_repo.CurrentBranch?.FullName);
+ _repo.NavigateToCommitDelayed(head);
_repo.SetWatcherEnabled(true);
});
diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs
index a3f63251..b02cf36a 100644
--- a/src/ViewModels/Repository.cs
+++ b/src/ViewModels/Repository.cs
@@ -51,6 +51,12 @@ namespace SourceGit.ViewModels
get => _settings;
}
+ public Models.GitFlow GitFlow
+ {
+ get;
+ set;
+ } = new Models.GitFlow();
+
public Models.FilterMode HistoriesFilterMode
{
get => _historiesFilterMode;
@@ -294,6 +300,7 @@ namespace SourceGit.ViewModels
SelectedSearchedCommit = null;
SearchCommitFilter = string.Empty;
MatchedFilesForSearching = null;
+ _requestingWorktreeFiles = false;
_worktreeFiles = null;
}
}
@@ -545,9 +552,9 @@ namespace SourceGit.ViewModels
_historiesFilterMode = Models.FilterMode.None;
_watcher?.Dispose();
- _histories.Cleanup();
- _workingCopy.Cleanup();
- _stashesPage.Cleanup();
+ _histories.Dispose();
+ _workingCopy.Dispose();
+ _stashesPage.Dispose();
_watcher = null;
_histories = null;
@@ -568,6 +575,7 @@ namespace SourceGit.ViewModels
_searchedCommits.Clear();
_selectedSearchedCommit = null;
+ _requestingWorktreeFiles = false;
_worktreeFiles = null;
_matchedFilesForSearching = null;
}
@@ -593,6 +601,28 @@ namespace SourceGit.ViewModels
GetOwnerPage()?.StartPopup(popup);
}
+ public bool IsGitFlowEnabled()
+ {
+ return GitFlow is { IsValid: true } &&
+ _branches.Find(x => x.IsLocal && x.Name.Equals(GitFlow.Master, StringComparison.Ordinal)) != null &&
+ _branches.Find(x => x.IsLocal && x.Name.Equals(GitFlow.Develop, StringComparison.Ordinal)) != null;
+ }
+
+ public Models.GitFlowBranchType GetGitFlowType(Models.Branch b)
+ {
+ if (!IsGitFlowEnabled())
+ return Models.GitFlowBranchType.None;
+
+ var name = b.Name;
+ if (name.StartsWith(GitFlow.FeaturePrefix, StringComparison.Ordinal))
+ return Models.GitFlowBranchType.Feature;
+ if (name.StartsWith(GitFlow.ReleasePrefix, StringComparison.Ordinal))
+ return Models.GitFlowBranchType.Release;
+ if (name.StartsWith(GitFlow.HotfixPrefix, StringComparison.Ordinal))
+ return Models.GitFlowBranchType.Hotfix;
+ return Models.GitFlowBranchType.None;
+ }
+
public CommandLog CreateLog(string name)
{
var log = new CommandLog(name);
@@ -602,19 +632,30 @@ namespace SourceGit.ViewModels
public void RefreshAll()
{
- Task.Run(() =>
- {
- var allowedSignersFile = new Commands.Config(_fullpath).Get("gpg.ssh.allowedSignersFile");
- _hasAllowedSignersFile = !string.IsNullOrEmpty(allowedSignersFile);
- });
-
+ Task.Run(RefreshCommits);
Task.Run(RefreshBranches);
Task.Run(RefreshTags);
- Task.Run(RefreshCommits);
Task.Run(RefreshSubmodules);
Task.Run(RefreshWorktrees);
Task.Run(RefreshWorkingCopyChanges);
Task.Run(RefreshStashes);
+
+ Task.Run(() =>
+ {
+ var config = new Commands.Config(_fullpath).ListAll();
+ _hasAllowedSignersFile = config.TryGetValue("gpg.ssh.allowedSignersFile", out var allowedSignersFile) && !string.IsNullOrEmpty(allowedSignersFile);
+
+ if (config.TryGetValue("gitflow.branch.master", out var masterName))
+ GitFlow.Master = masterName;
+ if (config.TryGetValue("gitflow.branch.develop", out var developName))
+ GitFlow.Develop = developName;
+ if (config.TryGetValue("gitflow.prefix.feature", out var featurePrefix))
+ GitFlow.FeaturePrefix = featurePrefix;
+ if (config.TryGetValue("gitflow.prefix.release", out var releasePrefix))
+ GitFlow.ReleasePrefix = releasePrefix;
+ if (config.TryGetValue("gitflow.prefix.hotfix", out var hotfixPrefix))
+ GitFlow.HotfixPrefix = hotfixPrefix;
+ });
}
public ContextMenu CreateContextMenuForExternalTools()
@@ -881,17 +922,17 @@ namespace SourceGit.ViewModels
}
}
+ public void NavigateToCommitDelayed(string sha)
+ {
+ _navigateToCommitDelayed = sha;
+ }
+
public void NavigateToCurrentHead()
{
if (_currentBranch != null)
NavigateToCommit(_currentBranch.Head);
}
- public void NavigateToBranchDelayed(string branch)
- {
- _navigateToBranchDelayed = branch;
- }
-
public void ClearHistoriesFilter()
{
_settings.HistoriesFilters.Clear();
@@ -1052,6 +1093,13 @@ namespace SourceGit.ViewModels
});
}
+ public bool MayHaveSubmodules()
+ {
+ var modulesFile = Path.Combine(_fullpath, ".gitmodules");
+ var info = new FileInfo(modulesFile);
+ return info.Exists && info.Length > 20;
+ }
+
public void RefreshBranches()
{
var branches = new Commands.QueryBranches(_fullpath).Result(out var localBranchesCount);
@@ -1141,27 +1189,64 @@ namespace SourceGit.ViewModels
BisectState = _histories.UpdateBisectInfo();
- if (!string.IsNullOrEmpty(_navigateToBranchDelayed))
- {
- var branch = _branches.Find(x => x.FullName == _navigateToBranchDelayed);
- if (branch != null)
- NavigateToCommit(branch.Head);
- }
+ if (!string.IsNullOrEmpty(_navigateToCommitDelayed))
+ NavigateToCommit(_navigateToCommitDelayed);
}
- _navigateToBranchDelayed = string.Empty;
+ _navigateToCommitDelayed = string.Empty;
});
}
public void RefreshSubmodules()
{
+ if (!MayHaveSubmodules())
+ {
+ if (_submodules.Count > 0)
+ {
+ Dispatcher.UIThread.Invoke(() =>
+ {
+ Submodules = [];
+ VisibleSubmodules = BuildVisibleSubmodules();
+ });
+ }
+
+ return;
+ }
+
var submodules = new Commands.QuerySubmodules(_fullpath).Result();
_watcher?.SetSubmodules(submodules);
Dispatcher.UIThread.Invoke(() =>
{
- Submodules = submodules;
- VisibleSubmodules = BuildVisibleSubmodules();
+ bool hasChanged = _submodules.Count != submodules.Count;
+ if (!hasChanged)
+ {
+ var old = new Dictionary();
+ foreach (var module in _submodules)
+ old.Add(module.Path, module);
+
+ foreach (var module in submodules)
+ {
+ if (!old.TryGetValue(module.Path, out var exist))
+ {
+ hasChanged = true;
+ break;
+ }
+
+ hasChanged = !exist.SHA.Equals(module.SHA, StringComparison.Ordinal) ||
+ !exist.URL.Equals(module.URL, StringComparison.Ordinal) ||
+ exist.Status != module.Status;
+
+ if (hasChanged)
+ break;
+ }
+ }
+
+ if (hasChanged)
+ {
+ Submodules = submodules;
+ VisibleSubmodules = BuildVisibleSubmodules();
+ }
});
}
@@ -1375,8 +1460,7 @@ namespace SourceGit.ViewModels
var menu = new ContextMenu();
menu.Placement = PlacementMode.BottomEdgeAlignedLeft;
- var isGitFlowEnabled = Commands.GitFlow.IsEnabled(_fullpath, _branches);
- if (isGitFlowEnabled)
+ if (IsGitFlowEnabled())
{
var startFeature = new MenuItem();
startFeature.Header = App.Text("GitFlow.StartFeature");
@@ -1384,7 +1468,7 @@ namespace SourceGit.ViewModels
startFeature.Click += (_, e) =>
{
if (CanCreatePopup())
- ShowPopup(new GitFlowStart(this, "feature"));
+ ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Feature));
e.Handled = true;
};
@@ -1394,7 +1478,7 @@ namespace SourceGit.ViewModels
startRelease.Click += (_, e) =>
{
if (CanCreatePopup())
- ShowPopup(new GitFlowStart(this, "release"));
+ ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Release));
e.Handled = true;
};
@@ -1404,7 +1488,7 @@ namespace SourceGit.ViewModels
startHotfix.Click += (_, e) =>
{
if (CanCreatePopup())
- ShowPopup(new GitFlowStart(this, "hotfix"));
+ ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Hotfix));
e.Handled = true;
};
@@ -1419,8 +1503,15 @@ namespace SourceGit.ViewModels
init.Icon = App.CreateMenuIcon("Icons.Init");
init.Click += (_, e) =>
{
- if (CanCreatePopup())
+ if (_currentBranch == null)
+ {
+ App.RaiseException(_fullpath, "Git flow init failed: No branch found!!!");
+ }
+ else if (CanCreatePopup())
+ {
ShowPopup(new InitGitFlow(this));
+ }
+
e.Handled = true;
};
menu.Items.Add(init);
@@ -1770,9 +1861,25 @@ namespace SourceGit.ViewModels
fastForward.Click += (_, e) =>
{
if (CanCreatePopup())
- ShowAndStartPopup(new FastForwardWithoutCheckout(this, branch, upstream));
+ ShowAndStartPopup(new ResetWithoutCheckout(this, branch, upstream));
e.Handled = true;
};
+ menu.Items.Add(fastForward);
+
+ var selectedCommit = (_histories?.DetailContext as CommitDetail)?.Commit;
+ if (selectedCommit != null && !selectedCommit.SHA.Equals(branch.Head, StringComparison.Ordinal))
+ {
+ var move = new MenuItem();
+ move.Header = App.Text("BranchCM.ResetToSelectedCommit", branch.Name, selectedCommit.SHA.Substring(0, 10));
+ move.Icon = App.CreateMenuIcon("Icons.Reset");
+ move.Click += (_, e) =>
+ {
+ if (CanCreatePopup())
+ ShowPopup(new ResetWithoutCheckout(this, branch, selectedCommit));
+ e.Handled = true;
+ };
+ menu.Items.Add(move);
+ }
var fetchInto = new MenuItem();
fetchInto.Header = App.Text("BranchCM.FetchInto", upstream.FriendlyName, branch.Name);
@@ -1785,7 +1892,6 @@ namespace SourceGit.ViewModels
e.Handled = true;
};
- menu.Items.Add(fastForward);
menu.Items.Add(new MenuItem() { Header = "-" });
menu.Items.Add(fetchInto);
}
@@ -1850,8 +1956,8 @@ namespace SourceGit.ViewModels
if (!IsBare)
{
- var detect = Commands.GitFlow.DetectType(_fullpath, _branches, branch.Name);
- if (detect.IsGitFlowBranch)
+ var type = GetGitFlowType(branch);
+ if (type != Models.GitFlowBranchType.None)
{
var finish = new MenuItem();
finish.Header = App.Text("BranchCM.Finish", branch.Name);
@@ -1859,7 +1965,7 @@ namespace SourceGit.ViewModels
finish.Click += (_, e) =>
{
if (CanCreatePopup())
- ShowPopup(new GitFlowFinish(this, branch, detect.Type, detect.Prefix));
+ ShowPopup(new GitFlowFinish(this, branch, type));
e.Handled = true;
};
menu.Items.Add(new MenuItem() { Header = "-" });
@@ -2370,12 +2476,14 @@ namespace SourceGit.ViewModels
ev.Handled = true;
};
- var copy = new MenuItem();
- copy.Header = App.Text("Submodule.CopyPath");
- copy.Icon = App.CreateMenuIcon("Icons.Copy");
- copy.Click += (_, ev) =>
+ var deinit = new MenuItem();
+ deinit.Header = App.Text("Submodule.Deinit");
+ deinit.Icon = App.CreateMenuIcon("Icons.Undo");
+ deinit.IsEnabled = submodule.Status != Models.SubmoduleStatus.NotInited;
+ deinit.Click += (_, ev) =>
{
- App.CopyText(submodule.Path);
+ if (CanCreatePopup())
+ ShowPopup(new DeinitSubmodule(this, submodule.Path));
ev.Handled = true;
};
@@ -2389,10 +2497,22 @@ namespace SourceGit.ViewModels
ev.Handled = true;
};
+ var copy = new MenuItem();
+ copy.Header = App.Text("Submodule.CopyPath");
+ copy.Icon = App.CreateMenuIcon("Icons.Copy");
+ copy.Click += (_, ev) =>
+ {
+ App.CopyText(submodule.Path);
+ ev.Handled = true;
+ };
+
var menu = new ContextMenu();
menu.Items.Add(open);
- menu.Items.Add(copy);
+ menu.Items.Add(new MenuItem() { Header = "-" });
+ menu.Items.Add(deinit);
menu.Items.Add(rm);
+ menu.Items.Add(new MenuItem() { Header = "-" });
+ menu.Items.Add(copy);
return menu;
}
@@ -2683,19 +2803,27 @@ namespace SourceGit.ViewModels
{
if (!IsSearchingCommitsByFilePath())
{
+ _requestingWorktreeFiles = false;
_worktreeFiles = null;
MatchedFilesForSearching = null;
GC.Collect();
return;
}
+ if (_requestingWorktreeFiles)
+ return;
+
+ _requestingWorktreeFiles = true;
+
Task.Run(() =>
{
_worktreeFiles = new Commands.QueryRevisionFileNames(_fullpath, "HEAD").Result();
Dispatcher.UIThread.Invoke(() =>
{
- if (IsSearchingCommitsByFilePath())
+ if (IsSearchingCommitsByFilePath() && _requestingWorktreeFiles)
CalcMatchedFilesForSearching();
+
+ _requestingWorktreeFiles = false;
});
});
}
@@ -2781,6 +2909,7 @@ namespace SourceGit.ViewModels
private string _searchCommitFilter = string.Empty;
private List _searchedCommits = new List();
private Models.Commit _selectedSearchedCommit = null;
+ private bool _requestingWorktreeFiles = false;
private List _worktreeFiles = null;
private List _matchedFilesForSearching = null;
@@ -2804,6 +2933,6 @@ namespace SourceGit.ViewModels
private Models.BisectState _bisectState = Models.BisectState.None;
private bool _isBisectCommandRunning = false;
- private string _navigateToBranchDelayed = string.Empty;
+ private string _navigateToCommitDelayed = string.Empty;
}
}
diff --git a/src/ViewModels/ResetWithoutCheckout.cs b/src/ViewModels/ResetWithoutCheckout.cs
new file mode 100644
index 00000000..3a9582ef
--- /dev/null
+++ b/src/ViewModels/ResetWithoutCheckout.cs
@@ -0,0 +1,53 @@
+using System.Threading.Tasks;
+
+namespace SourceGit.ViewModels
+{
+ public class ResetWithoutCheckout : Popup
+ {
+ public Models.Branch Target
+ {
+ get;
+ }
+
+ public object To
+ {
+ get;
+ }
+
+ public ResetWithoutCheckout(Repository repo, Models.Branch target, Models.Branch to)
+ {
+ _repo = repo;
+ _revision = to.Head;
+ Target = target;
+ To = to;
+ }
+
+ public ResetWithoutCheckout(Repository repo, Models.Branch target, Models.Commit to)
+ {
+ _repo = repo;
+ _revision = to.SHA;
+ Target = target;
+ To = to;
+ }
+
+ public override Task Sure()
+ {
+ _repo.SetWatcherEnabled(false);
+ ProgressDescription = $"Reset {Target.Name} to {_revision} ...";
+
+ var log = _repo.CreateLog($"Reset '{Target.Name}' to '{_revision}'");
+ Use(log);
+
+ return Task.Run(() =>
+ {
+ var succ = Commands.Branch.Create(_repo.FullPath, Target.Name, _revision, true, log);
+ log.Complete();
+ CallUIThread(() => _repo.SetWatcherEnabled(true));
+ return succ;
+ });
+ }
+
+ private readonly Repository _repo = null;
+ private readonly string _revision = string.Empty;
+ }
+}
diff --git a/src/ViewModels/RevisionCompare.cs b/src/ViewModels/RevisionCompare.cs
index 3b5717a6..1dad7593 100644
--- a/src/ViewModels/RevisionCompare.cs
+++ b/src/ViewModels/RevisionCompare.cs
@@ -10,7 +10,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
{
- public class RevisionCompare : ObservableObject
+ public class RevisionCompare : ObservableObject, IDisposable
{
public object StartPoint
{
@@ -83,7 +83,7 @@ namespace SourceGit.ViewModels
Task.Run(Refresh);
}
- public void Cleanup()
+ public void Dispose()
{
_repo = null;
_startPoint = null;
diff --git a/src/ViewModels/StashesPage.cs b/src/ViewModels/StashesPage.cs
index 87e36b86..b974d427 100644
--- a/src/ViewModels/StashesPage.cs
+++ b/src/ViewModels/StashesPage.cs
@@ -11,7 +11,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
{
- public class StashesPage : ObservableObject
+ public class StashesPage : ObservableObject, IDisposable
{
public List Stashes
{
@@ -69,7 +69,7 @@ namespace SourceGit.ViewModels
changes = new Commands.CompareRevisions(_repo.FullPath, $"{value.SHA}^", value.SHA).Result();
if (value.Parents.Count == 3)
{
- var untracked = new Commands.CompareRevisions(_repo.FullPath, "4b825dc642cb6eb9a060e54bf8d69288fbee4904", value.Parents[2]).Result();
+ var untracked = new Commands.CompareRevisions(_repo.FullPath, Models.Commit.EmptyTreeSHA1, value.Parents[2]).Result();
var needSort = changes.Count > 0;
foreach (var c in untracked)
@@ -107,7 +107,7 @@ namespace SourceGit.ViewModels
if (value == null)
DiffContext = null;
else if (value.Index == Models.ChangeState.Added && _selectedStash.Parents.Count == 3)
- DiffContext = new DiffContext(_repo.FullPath, new Models.DiffOption("4b825dc642cb6eb9a060e54bf8d69288fbee4904", _selectedStash.Parents[2], value), _diffContext);
+ DiffContext = new DiffContext(_repo.FullPath, new Models.DiffOption(Models.Commit.EmptyTreeSHA1, _selectedStash.Parents[2], value), _diffContext);
else
DiffContext = new DiffContext(_repo.FullPath, new Models.DiffOption(_selectedStash.Parents[0], _selectedStash.SHA, value), _diffContext);
}
@@ -125,14 +125,13 @@ namespace SourceGit.ViewModels
_repo = repo;
}
- public void Cleanup()
+ public void Dispose()
{
+ _stashes?.Clear();
+ _changes?.Clear();
+
_repo = null;
- if (_stashes != null)
- _stashes.Clear();
_selectedStash = null;
- if (_changes != null)
- _changes.Clear();
_selectedChange = null;
_diffContext = null;
}
@@ -183,7 +182,7 @@ namespace SourceGit.ViewModels
foreach (var c in _changes)
{
if (c.Index == Models.ChangeState.Added && _selectedStash.Parents.Count == 3)
- opts.Add(new Models.DiffOption("4b825dc642cb6eb9a060e54bf8d69288fbee4904", _selectedStash.Parents[2], c));
+ opts.Add(new Models.DiffOption(Models.Commit.EmptyTreeSHA1, _selectedStash.Parents[2], c));
else
opts.Add(new Models.DiffOption(_selectedStash.Parents[0], _selectedStash.SHA, c));
}
diff --git a/src/ViewModels/SubmoduleCollection.cs b/src/ViewModels/SubmoduleCollection.cs
index 4600496e..7def3ced 100644
--- a/src/ViewModels/SubmoduleCollection.cs
+++ b/src/ViewModels/SubmoduleCollection.cs
@@ -9,7 +9,7 @@ namespace SourceGit.ViewModels
{
public class SubmoduleTreeNode : ObservableObject
{
- public string FullPath { get; set; } = string.Empty;
+ public string FullPath { get; private set; } = string.Empty;
public int Depth { get; private set; } = 0;
public Models.Submodule Module { get; private set; } = null;
public List Children { get; private set; } = [];
diff --git a/src/ViewModels/TagCollection.cs b/src/ViewModels/TagCollection.cs
index ce9c9508..b6be1a0a 100644
--- a/src/ViewModels/TagCollection.cs
+++ b/src/ViewModels/TagCollection.cs
@@ -23,7 +23,7 @@ namespace SourceGit.ViewModels
public class TagTreeNode : ObservableObject
{
- public string FullPath { get; set; }
+ public string FullPath { get; private set; }
public int Depth { get; private set; } = 0;
public Models.Tag Tag { get; private set; } = null;
public TagTreeNodeToolTip ToolTip { get; private set; } = null;
diff --git a/src/ViewModels/UpdateSubmodules.cs b/src/ViewModels/UpdateSubmodules.cs
index c2f23133..df2d5565 100644
--- a/src/ViewModels/UpdateSubmodules.cs
+++ b/src/ViewModels/UpdateSubmodules.cs
@@ -65,14 +65,9 @@ namespace SourceGit.ViewModels
return Task.Run(() =>
{
- foreach (var submodule in targets)
- {
- new Commands.Submodule(_repo.FullPath).Use(log).Update(
- submodule,
- EnableInit,
- EnableRecursive,
- EnableRemote);
- }
+ new Commands.Submodule(_repo.FullPath)
+ .Use(log)
+ .Update(targets, EnableInit, EnableRecursive, EnableRemote);
log.Complete();
CallUIThread(() => _repo.SetWatcherEnabled(true));
diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs
index 762f1176..7c2d95f9 100644
--- a/src/ViewModels/WorkingCopy.cs
+++ b/src/ViewModels/WorkingCopy.cs
@@ -11,7 +11,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
{
- public class WorkingCopy : ObservableObject
+ public class WorkingCopy : ObservableObject, IDisposable
{
public bool IncludeUntracked
{
@@ -210,7 +210,7 @@ namespace SourceGit.ViewModels
_repo = repo;
}
- public void Cleanup()
+ public void Dispose()
{
_repo = null;
_inProgressContext = null;
@@ -244,7 +244,7 @@ namespace SourceGit.ViewModels
// Just force refresh selected changes.
Dispatcher.UIThread.Invoke(() =>
{
- HasUnsolvedConflicts = _cached.Find(x => x.IsConflict) != null;
+ HasUnsolvedConflicts = _cached.Find(x => x.IsConflicted) != null;
UpdateDetail();
UpdateInProgressState();
@@ -276,7 +276,7 @@ namespace SourceGit.ViewModels
if (c.WorkTree != Models.ChangeState.None)
{
unstaged.Add(c);
- hasConflict |= c.IsConflict;
+ hasConflict |= c.IsConflicted;
}
}
@@ -378,7 +378,7 @@ namespace SourceGit.ViewModels
foreach (var change in changes)
{
- if (!change.IsConflict)
+ if (!change.IsConflicted)
continue;
if (change.WorkTree == Models.ChangeState.Deleted)
@@ -420,7 +420,7 @@ namespace SourceGit.ViewModels
foreach (var change in changes)
{
- if (!change.IsConflict)
+ if (!change.IsConflicted)
continue;
if (change.Index == Models.ChangeState.Deleted)
@@ -547,17 +547,17 @@ namespace SourceGit.ViewModels
public void Commit()
{
- DoCommit(false, false, false);
+ DoCommit(false, false);
}
public void CommitWithAutoStage()
{
- DoCommit(true, false, false);
+ DoCommit(true, false);
}
public void CommitWithPush()
{
- DoCommit(false, true, false);
+ DoCommit(false, true);
}
public ContextMenu CreateContextMenuForUnstagedChanges()
@@ -594,7 +594,7 @@ namespace SourceGit.ViewModels
menu.Items.Add(openWith);
menu.Items.Add(new MenuItem() { Header = "-" });
- if (change.IsConflict)
+ if (change.IsConflicted)
{
var useTheirs = new MenuItem();
useTheirs.Icon = App.CreateMenuIcon("Icons.Incoming");
@@ -949,7 +949,7 @@ namespace SourceGit.ViewModels
var hasNonConflicts = false;
foreach (var change in _selectedUnstaged)
{
- if (change.IsConflict)
+ if (change.IsConflicted)
hasConflicts = true;
else
hasNonConflicts = true;
@@ -1528,14 +1528,13 @@ namespace SourceGit.ViewModels
if (_useAmend)
{
var head = new Commands.QuerySingleCommit(_repo.FullPath, "HEAD").Result();
- return new Commands.QueryStagedChangesWithAmend(_repo.FullPath, head.Parents.Count == 0 ? "4b825dc642cb6eb9a060e54bf8d69288fbee4904" : $"{head.SHA}^").Result();
+ return new Commands.QueryStagedChangesWithAmend(_repo.FullPath, head.Parents.Count == 0 ? Models.Commit.EmptyTreeSHA1 : $"{head.SHA}^").Result();
}
var rs = new List();
foreach (var c in _cached)
{
- if (c.Index != Models.ChangeState.None &&
- c.Index != Models.ChangeState.Untracked)
+ if (c.Index != Models.ChangeState.None)
rs.Add(c);
}
return rs;
@@ -1681,7 +1680,7 @@ namespace SourceGit.ViewModels
if (change == null)
DetailContext = null;
- else if (change.IsConflict && isUnstaged)
+ else if (change.IsConflicted)
DetailContext = new Conflict(_repo, this, change);
else
DetailContext = new DiffContext(_repo.FullPath, new Models.DiffOption(change, isUnstaged), _detailContext as DiffContext);
@@ -1763,14 +1762,17 @@ namespace SourceGit.ViewModels
{
if (old.Count != cur.Count)
return true;
-
- var oldSet = new HashSet();
+
+ var oldMap = new Dictionary();
foreach (var c in old)
- oldSet.Add($"{c.Path}\n{c.WorkTree}\n{c.Index}");
+ oldMap.Add(c.Path, c);
foreach (var c in cur)
{
- if (!oldSet.Contains($"{c.Path}\n{c.WorkTree}\n{c.Index}"))
+ if (!oldMap.TryGetValue(c.Path, out var o))
+ return true;
+
+ if (o.Index != c.Index || o.WorkTree != c.WorkTree)
return true;
}
diff --git a/src/Views/Blame.axaml.cs b/src/Views/Blame.axaml.cs
index 4342651e..00342b0b 100644
--- a/src/Views/Blame.axaml.cs
+++ b/src/Views/Blame.axaml.cs
@@ -296,8 +296,6 @@ namespace SourceGit.Views
TextArea.LeftMargins.Add(new CommitInfoMargin(this) { Margin = new Thickness(8, 0) });
TextArea.LeftMargins.Add(new VerticalSeparatorMargin(this));
TextArea.Caret.PositionChanged += OnTextAreaCaretPositionChanged;
- TextArea.LayoutUpdated += OnTextAreaLayoutUpdated;
- TextArea.PointerWheelChanged += OnTextAreaPointerWheelChanged;
TextArea.TextView.ContextRequested += OnTextViewContextRequested;
TextArea.TextView.VisualLinesChanged += OnTextViewVisualLinesChanged;
TextArea.TextView.Margin = new Thickness(4, 0);
@@ -341,8 +339,6 @@ namespace SourceGit.Views
TextArea.LeftMargins.Clear();
TextArea.Caret.PositionChanged -= OnTextAreaCaretPositionChanged;
- TextArea.LayoutUpdated -= OnTextAreaLayoutUpdated;
- TextArea.PointerWheelChanged -= OnTextAreaPointerWheelChanged;
TextArea.TextView.ContextRequested -= OnTextViewContextRequested;
TextArea.TextView.VisualLinesChanged -= OnTextViewVisualLinesChanged;
@@ -392,42 +388,21 @@ namespace SourceGit.Views
InvalidateVisual();
}
- private void OnTextAreaLayoutUpdated(object sender, EventArgs e)
- {
- if (TextArea.IsFocused)
- InvalidateVisual();
- }
-
- private void OnTextAreaPointerWheelChanged(object sender, PointerWheelEventArgs e)
- {
- if (!TextArea.IsFocused && !string.IsNullOrEmpty(_highlight))
- Focus();
- }
-
private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e)
{
var selected = SelectedText;
if (string.IsNullOrEmpty(selected))
return;
- var copy = new MenuItem() { Header = App.Text("Copy") };
+ var copy = new MenuItem();
+ copy.Header = App.Text("Copy");
+ copy.Icon = App.CreateMenuIcon("Icons.Copy");
copy.Click += (_, ev) =>
{
App.CopyText(selected);
ev.Handled = true;
};
- if (this.FindResource("Icons.Copy") is StreamGeometry geo)
- {
- copy.Icon = new Avalonia.Controls.Shapes.Path()
- {
- Width = 10,
- Height = 10,
- Stretch = Stretch.Fill,
- Data = geo,
- };
- }
-
var menu = new ContextMenu();
menu.Items.Add(copy);
menu.Open(TextArea.TextView);
@@ -445,6 +420,8 @@ namespace SourceGit.Views
break;
}
}
+
+ InvalidateVisual();
}
private TextMate.Installation _textMate = null;
diff --git a/src/Views/ChangeCollectionView.axaml b/src/Views/ChangeCollectionView.axaml
index 805028d0..36de5685 100644
--- a/src/Views/ChangeCollectionView.axaml
+++ b/src/Views/ChangeCollectionView.axaml
@@ -30,7 +30,8 @@
-
@@ -66,7 +67,8 @@
-
@@ -98,7 +100,8 @@
-
diff --git a/src/Views/ChangeCollectionView.axaml.cs b/src/Views/ChangeCollectionView.axaml.cs
index 6ef79861..00499fce 100644
--- a/src/Views/ChangeCollectionView.axaml.cs
+++ b/src/Views/ChangeCollectionView.axaml.cs
@@ -145,6 +145,7 @@ namespace SourceGit.Views
removeCount++;
}
+
tree.Rows.RemoveRange(idx + 1, removeCount);
}
}
@@ -209,6 +210,13 @@ namespace SourceGit.Views
return null;
}
+ public void TakeFocus()
+ {
+ var container = this.FindDescendantOfType();
+ if (container is { IsFocused: false })
+ container.Focus();
+ }
+
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
diff --git a/src/Views/ChangeStatusIcon.cs b/src/Views/ChangeStatusIcon.cs
index 7dbd0beb..c1185174 100644
--- a/src/Views/ChangeStatusIcon.cs
+++ b/src/Views/ChangeStatusIcon.cs
@@ -48,21 +48,16 @@ namespace SourceGit.Views
EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
},
new LinearGradientBrush
- {
- GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(238, 160, 14), 0), new GradientStop(Color.FromRgb(228, 172, 67), 1) },
- StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
- EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
- },
- new LinearGradientBrush
{
GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(47, 185, 47), 0), new GradientStop(Color.FromRgb(75, 189, 75), 1) },
StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
},
+ Brushes.OrangeRed,
];
- private static readonly string[] INDICATOR = ["?", "±", "T", "+", "−", "➜", "❏", "U", "★"];
- private static readonly string[] TIPS = ["Unknown", "Modified", "Type Changed", "Added", "Deleted", "Renamed", "Copied", "Unmerged", "Untracked"];
+ private static readonly string[] INDICATOR = ["?", "±", "T", "+", "−", "➜", "❏", "★", "!"];
+ private static readonly string[] TIPS = ["Unknown", "Modified", "Type Changed", "Added", "Deleted", "Renamed", "Copied", "Untracked", "Conflict"];
public static readonly StyledProperty IsUnstagedChangeProperty =
AvaloniaProperty.Register(nameof(IsUnstagedChange));
@@ -93,16 +88,8 @@ namespace SourceGit.Views
string indicator;
if (IsUnstagedChange)
{
- if (Change.IsConflict)
- {
- background = Brushes.OrangeRed;
- indicator = "!";
- }
- else
- {
- background = BACKGROUNDS[(int)Change.WorkTree];
- indicator = INDICATOR[(int)Change.WorkTree];
- }
+ background = BACKGROUNDS[(int)Change.WorkTree];
+ indicator = INDICATOR[(int)Change.WorkTree];
}
else
{
@@ -139,7 +126,7 @@ namespace SourceGit.Views
}
if (isUnstaged)
- ToolTip.SetTip(this, c.IsConflict ? "Conflict" : TIPS[(int)c.WorkTree]);
+ ToolTip.SetTip(this, TIPS[(int)c.WorkTree]);
else
ToolTip.SetTip(this, TIPS[(int)c.Index]);
diff --git a/src/Views/CommitChanges.axaml b/src/Views/CommitChanges.axaml
index 80f96c48..4dafee37 100644
--- a/src/Views/CommitChanges.axaml
+++ b/src/Views/CommitChanges.axaml
@@ -4,6 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
+ xmlns:c="using:SourceGit.Converters"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.CommitChanges"
x:DataType="vm:CommitDetail">
@@ -14,7 +15,7 @@
-
+
+
+
+
+
+
+
+
+
-
+
+
+
-
diff --git a/src/Views/DeinitSubmodule.axaml b/src/Views/DeinitSubmodule.axaml
new file mode 100644
index 00000000..d3e0b641
--- /dev/null
+++ b/src/Views/DeinitSubmodule.axaml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Views/FastForwardWithoutCheckout.axaml.cs b/src/Views/DeinitSubmodule.axaml.cs
similarity index 52%
rename from src/Views/FastForwardWithoutCheckout.axaml.cs
rename to src/Views/DeinitSubmodule.axaml.cs
index 0e3ba20d..18dd9944 100644
--- a/src/Views/FastForwardWithoutCheckout.axaml.cs
+++ b/src/Views/DeinitSubmodule.axaml.cs
@@ -2,9 +2,9 @@ using Avalonia.Controls;
namespace SourceGit.Views
{
- public partial class FastForwardWithoutCheckout : UserControl
+ public partial class DeinitSubmodule : UserControl
{
- public FastForwardWithoutCheckout()
+ public DeinitSubmodule()
{
InitializeComponent();
}
diff --git a/src/Views/DiffView.axaml b/src/Views/DiffView.axaml
index b6d1fd65..85da69d1 100644
--- a/src/Views/DiffView.axaml
+++ b/src/Views/DiffView.axaml
@@ -178,12 +178,12 @@
-
+
+ Text="{Binding Value, Converter={x:Static c:StringConverters.FormatByResourceKey}, ConverterParameter='Histories.Selected'}"/>
diff --git a/src/Views/Hotkeys.axaml b/src/Views/Hotkeys.axaml
index 5275f264..233c31a9 100644
--- a/src/Views/Hotkeys.axaml
+++ b/src/Views/Hotkeys.axaml
@@ -149,7 +149,7 @@
-
+
diff --git a/src/Views/InteractiveRebase.axaml b/src/Views/InteractiveRebase.axaml
index 0883c9dc..f9f69e88 100644
--- a/src/Views/InteractiveRebase.axaml
+++ b/src/Views/InteractiveRebase.axaml
@@ -107,7 +107,7 @@