diff --git a/README.md b/README.md
index 07cdc098..45d6bbf5 100644
--- a/README.md
+++ b/README.md
@@ -47,7 +47,7 @@
## Translation Status
-[](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md)
+[](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md)
## How to Use
diff --git a/TRANSLATION.md b/TRANSLATION.md
index c15fdcfb..508c0095 100644
--- a/TRANSLATION.md
+++ b/TRANSLATION.md
@@ -58,28 +58,12 @@
-### it_IT.axaml: 97.87%
+### it_IT.axaml: 100.0%
Missing Keys
-- Text.CommitDetail.Info.Children
-- Text.Configure.IssueTracker.AddSampleGitLabMergeRequest
-- Text.Configure.OpenAI.Preferred
-- Text.Configure.OpenAI.Preferred.Tip
-- Text.Fetch.Force
-- Text.Preference.General.ShowChildren
-- Text.Repository.FilterCommits
-- Text.Repository.FilterCommits.Default
-- Text.Repository.FilterCommits.Exclude
-- Text.Repository.FilterCommits.Include
-- Text.Repository.HistoriesOrder
-- Text.Repository.HistoriesOrder.ByDate
-- Text.Repository.HistoriesOrder.Topo
-- Text.SHALinkCM.CopySHA
-- Text.SHALinkCM.NavigateTo
-
### pt_BR.axaml: 99.29%
diff --git a/src/Commands/QueryCommitChildren.cs b/src/Commands/QueryCommitChildren.cs
index bef09abb..293de912 100644
--- a/src/Commands/QueryCommitChildren.cs
+++ b/src/Commands/QueryCommitChildren.cs
@@ -4,12 +4,14 @@ namespace SourceGit.Commands
{
public class QueryCommitChildren : Command
{
- public QueryCommitChildren(string repo, string commit, int max)
+ public QueryCommitChildren(string repo, string commit, int max, string filters)
{
WorkingDirectory = repo;
Context = repo;
_commit = commit;
- Args = $"rev-list -{max} --parents --branches --remotes ^{commit}";
+ if (string.IsNullOrEmpty(filters))
+ filters = "--branches --remotes --tags";
+ Args = $"rev-list -{max} --parents {filters} ^{commit}";
}
public IEnumerable Result()
diff --git a/src/Models/Filter.cs b/src/Models/Filter.cs
index 8d419800..af4569fa 100644
--- a/src/Models/Filter.cs
+++ b/src/Models/Filter.cs
@@ -20,11 +20,12 @@ namespace SourceGit.Models
public class Filter : ObservableObject
{
- public string Pattern
+ public string Pattern
{
get => _pattern;
set => SetProperty(ref _pattern, value);
}
+
public FilterType Type
{
get;
diff --git a/src/Models/RepositorySettings.cs b/src/Models/RepositorySettings.cs
index 586f52ec..5b3aa331 100644
--- a/src/Models/RepositorySettings.cs
+++ b/src/Models/RepositorySettings.cs
@@ -1,9 +1,8 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Text;
using Avalonia.Collections;
-using Avalonia.Threading;
namespace SourceGit.Models
{
@@ -153,22 +152,51 @@ namespace SourceGit.Models
set;
} = "---";
- public FilterMode GetHistoriesFilterMode(string pattern, FilterType type)
+ public Dictionary CollectHistoriesFilters()
{
+ var map = new Dictionary();
foreach (var filter in HistoriesFilters)
- {
- if (filter.Type != type)
- continue;
-
- if (filter.Pattern.Equals(pattern, StringComparison.Ordinal))
- return filter.Mode;
- }
-
- return FilterMode.None;
+ map.Add(filter.Pattern, filter.Mode);
+ return map;
}
public bool UpdateHistoriesFilter(string pattern, FilterType type, FilterMode mode)
{
+ // Clear all filters when there's a filter that has different mode.
+ if (mode != FilterMode.None)
+ {
+ var clear = false;
+ foreach (var filter in HistoriesFilters)
+ {
+ if (filter.Mode != mode)
+ {
+ clear = true;
+ break;
+ }
+ }
+
+ if (clear)
+ {
+ HistoriesFilters.Clear();
+ HistoriesFilters.Add(new Filter(pattern, type, mode));
+ return true;
+ }
+ }
+ else
+ {
+ for (int i = 0; i < HistoriesFilters.Count; i++)
+ {
+ var filter = HistoriesFilters[i];
+ if (filter.Type == type && filter.Pattern.Equals(pattern, StringComparison.Ordinal))
+ {
+ HistoriesFilters.RemoveAt(i);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
for (int i = 0; i < HistoriesFilters.Count; i++)
{
var filter = HistoriesFilters[i];
@@ -176,34 +204,33 @@ namespace SourceGit.Models
continue;
if (filter.Pattern.Equals(pattern, StringComparison.Ordinal))
- {
- if (mode == FilterMode.None)
- {
- HistoriesFilters.RemoveAt(i);
- return true;
- }
-
- if (mode != filter.Mode)
- {
- filter.Mode = mode;
- return true;
- }
- }
+ return false;
}
- if (mode != FilterMode.None)
+ HistoriesFilters.Add(new Filter(pattern, type, mode));
+ return true;
+ }
+
+ public void RemoveChildrenBranchFilters(string pattern)
+ {
+ var dirty = new List();
+ var prefix = $"{pattern}/";
+
+ foreach (var filter in HistoriesFilters)
{
- HistoriesFilters.Add(new Filter(pattern, type, mode));
- return true;
+ if (filter.Type == FilterType.Tag)
+ continue;
+
+ if (filter.Pattern.StartsWith(prefix, StringComparison.Ordinal))
+ dirty.Add(filter);
}
- return false;
+ foreach (var filter in dirty)
+ HistoriesFilters.Remove(filter);
}
public string BuildHistoriesFilter()
{
- var builder = new StringBuilder();
-
var excludedBranches = new List();
var excludedRemotes = new List();
var excludedTags = new List();
@@ -216,7 +243,7 @@ namespace SourceGit.Models
{
var name = filter.Pattern.Substring(11);
var b = $"{name.Substring(0, name.Length - 1)}[{name[^1]}]";
-
+
if (filter.Mode == FilterMode.Included)
includedBranches.Add(b);
else if (filter.Mode == FilterMode.Excluded)
@@ -258,14 +285,11 @@ namespace SourceGit.Models
}
}
- foreach (var b in excludedBranches)
- {
- builder.Append("--exclude=");
- builder.Append(b);
- builder.Append(' ');
- }
+ bool hasIncluded = includedBranches.Count > 0 || includedRemotes.Count > 0 || includedTags.Count > 0;
+ bool hasExcluded = excludedBranches.Count > 0 || excludedRemotes.Count > 0 || excludedTags.Count > 0;
- if (includedBranches.Count > 0)
+ var builder = new StringBuilder();
+ if (hasIncluded)
{
foreach (var b in includedBranches)
{
@@ -273,42 +297,14 @@ namespace SourceGit.Models
builder.Append(b);
builder.Append(' ');
}
- }
- else if (excludedBranches.Count > 0)
- {
- builder.Append("--branches ");
- }
- foreach (var r in excludedRemotes)
- {
- builder.Append("--exclude=");
- builder.Append(r);
- builder.Append(' ');
- }
-
- if (includedRemotes.Count > 0)
- {
foreach (var r in includedRemotes)
{
builder.Append("--remotes=");
builder.Append(r);
builder.Append(' ');
}
- }
- else if (excludedRemotes.Count > 0)
- {
- builder.Append("--remotes ");
- }
- foreach (var t in excludedTags)
- {
- builder.Append("--exclude=");
- builder.Append(t);
- builder.Append(' ');
- }
-
- if (includedTags.Count > 0)
- {
foreach (var t in includedTags)
{
builder.Append("--tags=");
@@ -316,8 +312,48 @@ namespace SourceGit.Models
builder.Append(' ');
}
}
- else if (excludedTags.Count > 0)
+ else if (hasExcluded)
{
+ if (excludedBranches.Count > 0)
+ {
+ foreach (var b in excludedBranches)
+ {
+ builder.Append("--exclude=");
+ builder.Append(b);
+ builder.Append(" --decorate-refs-exclude=refs/heads/");
+ builder.Append(b);
+ builder.Append(' ');
+ }
+ }
+
+ builder.Append("--exclude=HEA[D] --branches ");
+
+ if (excludedRemotes.Count > 0)
+ {
+ foreach (var r in excludedRemotes)
+ {
+ builder.Append("--exclude=");
+ builder.Append(r);
+ builder.Append(" --decorate-refs-exclude=refs/remotes/");
+ builder.Append(r);
+ builder.Append(' ');
+ }
+ }
+
+ builder.Append("--exclude=origin/HEA[D] --remotes ");
+
+ if (excludedTags.Count > 0)
+ {
+ foreach (var t in excludedTags)
+ {
+ builder.Append("--exclude=");
+ builder.Append(t);
+ builder.Append(" --decorate-refs-exclude=refs/tags/");
+ builder.Append(t);
+ builder.Append(' ');
+ }
+ }
+
builder.Append("--tags ");
}
diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml
index fd42b0f5..8a0ee04e 100644
--- a/src/Resources/Locales/en_US.axaml
+++ b/src/Resources/Locales/en_US.axaml
@@ -341,7 +341,7 @@
Remote:
Track files named '{0}'
Track all *{0} files
- HISTORY
+ Histories
Switch Horizontal/Vertical Layout
AUTHOR
AUTHOR TIME
@@ -453,7 +453,7 @@
Language
History Commits
Show author time instead of commit time in graph
- Show children in the commit details
+ Show children in the comment details
Subject Guide Length
GIT
Enable Auto CRLF
@@ -621,7 +621,7 @@
Pop
Drop Stash
Drop:
- STASHES
+ Stashes
CHANGES
STASHES
Statistics
@@ -668,7 +668,7 @@
Rescan Repositories in Default Clone Dir
Search Repositories...
Sort
- LOCAL CHANGES
+ Changes
Git Ignore
Ignore all *{0} files
Ignore *{0} files in the same folder
diff --git a/src/Resources/Styles.axaml b/src/Resources/Styles.axaml
index 6ea2af10..82970549 100644
--- a/src/Resources/Styles.axaml
+++ b/src/Resources/Styles.axaml
@@ -164,7 +164,6 @@
+
+
@@ -113,6 +119,12 @@
Margin="0,0,16,0"
PointerEntered="OnSHAPointerEntered"
PointerPressed="OnSHAPressed">
+
+
+
+
@@ -150,6 +162,12 @@
Margin="0,0,16,0"
PointerEntered="OnSHAPointerEntered"
PointerPressed="OnSHAPressed">
+
+
+
+
@@ -187,7 +205,13 @@
Message="{Binding #ThisControl.Message}"
IssueTrackerRules="{Binding #ThisControl.IssueTrackerRules}"
HorizontalAlignment="Stretch"
- TextWrapping="Wrap">
+ TextWrapping="Wrap">
+
+
+
+
diff --git a/src/Views/CreateBranch.axaml b/src/Views/CreateBranch.axaml
index caea0be4..3516c317 100644
--- a/src/Views/CreateBranch.axaml
+++ b/src/Views/CreateBranch.axaml
@@ -69,20 +69,21 @@
Margin="0,0,8,0"
Text="{DynamicResource Text.CreateBranch.LocalChanges}"/>
+
+
+
+
+ IsChecked="{Binding PreAction, Mode=TwoWay, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static m:DealWithLocalChanges.DoNothing}}"/>
+ IsChecked="{Binding PreAction, Mode=TwoWay, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static m:DealWithLocalChanges.StashAndReaply}}"/>
+ IsChecked="{Binding PreAction, Mode=TwoWay, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static m:DealWithLocalChanges.Discard}}"/>
-
-
-
-
-
-
-
-
-
-
+ Fill="{DynamicResource Brush.FG2}"
+ IsVisible="{Binding #ThisControl.Mode, Converter={x:Static ObjectConverters.Equal}, ConverterParameter={x:Static m:FilterMode.None}}"/>
();
@@ -57,199 +67,100 @@ namespace SourceGit.Views
if (button == null)
return;
+ var menu = new ContextMenu();
+ var mode = Models.FilterMode.None;
if (DataContext is Models.Tag tag)
{
- var mode = tag.FilterMode;
+ mode = tag.FilterMode;
- var none = new MenuItem();
- none.Icon = App.CreateMenuIcon("Icons.Eye");
- none.Header = "Default";
- none.IsEnabled = mode != Models.FilterMode.None;
- none.Click += (_, ev) =>
+ if (mode != Models.FilterMode.None)
{
- UpdateTagFilterMode(repo, tag, Models.FilterMode.None);
- ev.Handled = true;
- };
+ var unset = new MenuItem();
+ unset.Header = App.Text("Repository.FilterCommits.Default");
+ unset.Click += (_, ev) =>
+ {
+ repo.SetTagFilterMode(tag, Models.FilterMode.None);
+ ev.Handled = true;
+ };
+
+ menu.Items.Add(unset);
+ menu.Items.Add(new MenuItem() { Header = "-" });
+ }
var include = new MenuItem();
include.Icon = App.CreateMenuIcon("Icons.Filter");
- include.Header = "Filter";
+ include.Header = App.Text("Repository.FilterCommits.Include");
include.IsEnabled = mode != Models.FilterMode.Included;
include.Click += (_, ev) =>
{
- UpdateTagFilterMode(repo, tag, Models.FilterMode.Included);
+ repo.SetTagFilterMode(tag, Models.FilterMode.Included);
ev.Handled = true;
};
var exclude = new MenuItem();
exclude.Icon = App.CreateMenuIcon("Icons.EyeClose");
- exclude.Header = "Hide";
+ exclude.Header = App.Text("Repository.FilterCommits.Exclude");
exclude.IsEnabled = mode != Models.FilterMode.Excluded;
exclude.Click += (_, ev) =>
{
- UpdateTagFilterMode(repo, tag, Models.FilterMode.Excluded);
+ repo.SetTagFilterMode(tag, Models.FilterMode.Excluded);
ev.Handled = true;
};
- var menu = new ContextMenu();
- menu.Items.Add(none);
menu.Items.Add(include);
menu.Items.Add(exclude);
-
- if (mode == Models.FilterMode.None)
- {
- IsContextMenuOpening = true;
- menu.Closed += (_, _) => IsContextMenuOpening = false;
- }
-
- menu.Open(button);
}
else if (DataContext is ViewModels.BranchTreeNode node)
{
- var mode = node.FilterMode;
+ mode = node.FilterMode;
- var none = new MenuItem();
- none.Icon = App.CreateMenuIcon("Icons.Eye");
- none.Header = "Default";
- none.IsEnabled = mode != Models.FilterMode.None;
- none.Click += (_, ev) =>
+ if (mode != Models.FilterMode.None)
{
- UpdateBranchFilterMode(repo, node, Models.FilterMode.None);
- ev.Handled = true;
- };
+ var unset = new MenuItem();
+ unset.Header = App.Text("Repository.FilterCommits.Default");
+ unset.Click += (_, ev) =>
+ {
+ repo.SetBranchFilterMode(node, Models.FilterMode.None);
+ ev.Handled = true;
+ };
+
+ menu.Items.Add(unset);
+ menu.Items.Add(new MenuItem() { Header = "-" });
+ }
var include = new MenuItem();
include.Icon = App.CreateMenuIcon("Icons.Filter");
- include.Header = "Filter";
+ include.Header = App.Text("Repository.FilterCommits.Include");
include.IsEnabled = mode != Models.FilterMode.Included;
include.Click += (_, ev) =>
{
- UpdateBranchFilterMode(repo, node, Models.FilterMode.Included);
+ repo.SetBranchFilterMode(node, Models.FilterMode.Included);
ev.Handled = true;
};
var exclude = new MenuItem();
exclude.Icon = App.CreateMenuIcon("Icons.EyeClose");
- exclude.Header = "Hide";
+ exclude.Header = App.Text("Repository.FilterCommits.Exclude");
exclude.IsEnabled = mode != Models.FilterMode.Excluded;
exclude.Click += (_, ev) =>
{
- UpdateBranchFilterMode(repo, node, Models.FilterMode.Excluded);
+ repo.SetBranchFilterMode(node, Models.FilterMode.Excluded);
ev.Handled = true;
};
- var menu = new ContextMenu();
- menu.Items.Add(none);
menu.Items.Add(include);
menu.Items.Add(exclude);
-
- if (mode == Models.FilterMode.None)
- {
- IsContextMenuOpening = true;
- menu.Closed += (_, _) => IsContextMenuOpening = false;
- }
-
- menu.Open(button);
}
+ if (mode == Models.FilterMode.None)
+ {
+ IsContextMenuOpening = true;
+ menu.Closed += (_, _) => IsContextMenuOpening = false;
+ }
+
+ menu.Open(button);
e.Handled = true;
}
-
- private void UpdateTagFilterMode(ViewModels.Repository repo, Models.Tag tag, Models.FilterMode mode)
- {
- var changed = repo.Settings.UpdateHistoriesFilter(tag.Name, Models.FilterType.Tag, mode);
- if (changed)
- {
- tag.FilterMode = mode;
- Task.Run(repo.RefreshCommits);
- }
- }
-
- private void UpdateBranchFilterMode(ViewModels.Repository repo, ViewModels.BranchTreeNode node, Models.FilterMode mode)
- {
- var isLocal = node.Path.StartsWith("refs/heads/", StringComparison.Ordinal);
- var type = isLocal ? Models.FilterType.LocalBranch : Models.FilterType.RemoteBranch;
- var tree = isLocal ? repo.LocalBranchTrees : repo.RemoteBranchTrees;
-
- if (node.Backend is Models.Branch branch)
- {
- var changed = repo.Settings.UpdateHistoriesFilter(node.Path, type, mode);
- if (!changed)
- return;
-
- node.FilterMode = mode;
- }
- else
- {
- var changed = repo.Settings.UpdateHistoriesFilter(node.Path, isLocal ? Models.FilterType.LocalBranchFolder : Models.FilterType.RemoteBranchFolder, mode);
- if (!changed)
- return;
-
- node.FilterMode = mode;
- ResetChildrenBranchNodeFilterMode(repo, node, isLocal);
- }
-
- var parentType = isLocal ? Models.FilterType.LocalBranchFolder : Models.FilterType.RemoteBranchFolder;
- var cur = node;
- do
- {
- var lastSepIdx = cur.Path.LastIndexOf('/');
- if (lastSepIdx <= 0)
- break;
-
- var parentPath = cur.Path.Substring(0, lastSepIdx);
- var parent = FindParentNode(tree, parentPath);
- if (parent == null)
- break;
-
- repo.Settings.UpdateHistoriesFilter(parent.Path, parentType, Models.FilterMode.None);
- parent.FilterMode = Models.FilterMode.None;
- cur = parent;
- } while (true);
-
- Task.Run(repo.RefreshCommits);
- }
-
- private void ResetChildrenBranchNodeFilterMode(ViewModels.Repository repo, ViewModels.BranchTreeNode node, bool isLocal)
- {
- foreach (var child in node.Children)
- {
- child.FilterMode = Models.FilterMode.None;
-
- if (child.IsBranch)
- {
- var type = isLocal ? Models.FilterType.LocalBranch : Models.FilterType.RemoteBranch;
- repo.Settings.UpdateHistoriesFilter(child.Path, type, Models.FilterMode.None);
- }
- else
- {
- var type = isLocal ? Models.FilterType.LocalBranchFolder : Models.FilterType.RemoteBranchFolder;
- repo.Settings.UpdateHistoriesFilter(child.Path, type, Models.FilterMode.None);
- ResetChildrenBranchNodeFilterMode(repo, child, isLocal);
- }
- }
- }
-
- private ViewModels.BranchTreeNode FindParentNode(List nodes, string parent)
- {
- foreach (var node in nodes)
- {
- if (node.IsBranch)
- continue;
-
- if (node.Path.Equals(parent, StringComparison.Ordinal))
- return node;
-
- if (parent.StartsWith(node.Path, StringComparison.Ordinal))
- {
- var founded = FindParentNode(node.Children, parent);
- if (founded != null)
- return founded;
- }
- }
-
- return null;
- }
}
}
diff --git a/src/Views/Launcher.axaml.cs b/src/Views/Launcher.axaml.cs
index 4137579d..29d90e09 100644
--- a/src/Views/Launcher.axaml.cs
+++ b/src/Views/Launcher.axaml.cs
@@ -72,11 +72,6 @@ namespace SourceGit.Views
return _unhandledModifiers.HasFlag(modifier);
}
- public void ClearKeyModifier()
- {
- _unhandledModifiers = KeyModifiers.None;
- }
-
protected override void OnOpened(EventArgs e)
{
base.OnOpened(e);
diff --git a/src/Views/Pull.axaml b/src/Views/Pull.axaml
index f6aa245f..a23bb5d5 100644
--- a/src/Views/Pull.axaml
+++ b/src/Views/Pull.axaml
@@ -77,20 +77,21 @@
Margin="0,0,8,0"
Text="{DynamicResource Text.Pull.LocalChanges}"/>
+
+
+
+
+ IsChecked="{Binding PreAction, Mode=TwoWay, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static m:DealWithLocalChanges.DoNothing}}"/>
+ IsChecked="{Binding PreAction, Mode=TwoWay, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static m:DealWithLocalChanges.StashAndReaply}}"/>
+ IsChecked="{Binding PreAction, Mode=TwoWay, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static m:DealWithLocalChanges.Discard}}"/>
-
+
+
@@ -524,7 +531,7 @@
-
+
@@ -557,14 +564,6 @@
-
-