diff --git a/src/Models/Change.cs b/src/Models/Change.cs
index 2ad448add..9420559cd 100644
--- a/src/Models/Change.cs
+++ b/src/Models/Change.cs
@@ -7,6 +7,12 @@ public enum ChangeViewMode
Tree,
}
+ public enum ChangeSortMode
+ {
+ Path,
+ Status,
+ }
+
public enum ChangeState
{
None,
@@ -79,6 +85,48 @@ public void Set(ChangeState index, ChangeState workTree = ChangeState.None)
OriginalPath = OriginalPath.Substring(1, OriginalPath.Length - 2);
}
+ ///
+ /// Gets the sort priority for a change based on its status, used for sorting changes by status.
+ /// Lower numbers indicate higher priority (appear first in sorted lists).
+ ///
+ /// The change object to get priority for
+ /// True if sorting in unstaged context, false for staged context
+ /// Priority value where lower numbers appear first
+ public static int GetStatusSortPriority(Change change, bool isUnstagedContext)
+ {
+ if (change == null) return int.MaxValue;
+
+ if (isUnstagedContext)
+ {
+ // For unstaged context, only consider WorkTree state
+ return change.WorkTree switch
+ {
+ ChangeState.Conflicted => 1, // Conflicts first - most urgent
+ ChangeState.Modified => 2,
+ ChangeState.TypeChanged => 3,
+ ChangeState.Deleted => 4, // Missing files
+ ChangeState.Renamed => 5,
+ ChangeState.Copied => 6,
+ ChangeState.Untracked => 7, // New files last
+ _ => 10
+ };
+ }
+ else
+ {
+ // For staged context, only consider Index state
+ return change.Index switch
+ {
+ ChangeState.Modified => 1,
+ ChangeState.TypeChanged => 2,
+ ChangeState.Renamed => 3,
+ ChangeState.Copied => 4,
+ ChangeState.Added => 5,
+ ChangeState.Deleted => 6,
+ _ => 10
+ };
+ }
+ }
+
private static readonly string[] TYPE_DESCS =
[
"Unknown",
diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml
index bb78b8e7c..67d08fc52 100644
--- a/src/Resources/Locales/de_DE.axaml
+++ b/src/Resources/Locales/de_DE.axaml
@@ -87,6 +87,8 @@
Zeige als Datei- und Ordnerliste
Zeige als Pfadliste
Zeige als Dateisystembaum
+ Nach Pfad sortieren
+ Nach Status sortieren
Ändere URL des Submoduls
Submodule:
URL:
diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml
index 655f6e976..1c882266c 100644
--- a/src/Resources/Locales/en_US.axaml
+++ b/src/Resources/Locales/en_US.axaml
@@ -83,6 +83,8 @@
Show as File and Dir List
Show as Path List
Show as Filesystem Tree
+ Sort by Path
+ Sort by Status
Change Submodule's URL
Submodule:
URL:
diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml
index 4ef06eae9..a8bb15041 100644
--- a/src/Resources/Locales/es_ES.axaml
+++ b/src/Resources/Locales/es_ES.axaml
@@ -87,6 +87,8 @@
Mostrar como Lista de Archivos y Directorios
Mostrar como Lista de Rutas
Mostrar como Árbol de Sistema de Archivos
+ Ordenar por ruta
+ Ordenar por estado
Cambiar la URL del Submódulo
Submódulo:
URL:
diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml
index 919dfeac8..731314fad 100644
--- a/src/Resources/Locales/fr_FR.axaml
+++ b/src/Resources/Locales/fr_FR.axaml
@@ -70,6 +70,8 @@
Afficher comme liste de dossiers/fichiers
Afficher comme liste de chemins
Afficher comme arborescence
+ Trier par chemin
+ Trier par statut
Récupérer la branche
Récupérer ce commit
Commit :
diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml
index c12e3e53c..7bf68de21 100644
--- a/src/Resources/Locales/it_IT.axaml
+++ b/src/Resources/Locales/it_IT.axaml
@@ -77,6 +77,8 @@
Mostra come elenco di file e cartelle
Mostra come elenco di percorsi
Mostra come albero del filesystem
+ Ordina per percorso
+ Ordina per stato
Checkout Branch
Checkout Commit
Commit:
diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml
index 32c41f216..e45bef786 100644
--- a/src/Resources/Locales/ja_JP.axaml
+++ b/src/Resources/Locales/ja_JP.axaml
@@ -69,6 +69,8 @@
ファイルとディレクトリのリストを表示
パスのリストを表示
ファイルシステムのツリーを表示
+ パスで並び替え
+ ステータスで並び替え
ブランチをチェックアウト
コミットをチェックアウト
コミット:
diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml
index 3fbac432f..cf4481598 100644
--- a/src/Resources/Locales/pt_BR.axaml
+++ b/src/Resources/Locales/pt_BR.axaml
@@ -61,6 +61,8 @@
Exibir como Lista de Arquivos e Diretórios
Exibir como Lista de Caminhos
Exibir como Árvore de Sistema de Arquivos
+ Ordenar por caminho
+ Ordenar por status
Checkout Branch
Checkout Commit
Commit:
diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml
index 413b99e32..0e5b83357 100644
--- a/src/Resources/Locales/ru_RU.axaml
+++ b/src/Resources/Locales/ru_RU.axaml
@@ -87,6 +87,8 @@
Показывать в виде списка файлов и каталогов
Показывать в виде списка путей
Показывать в виде дерева файловой системы
+ Сортировать по пути
+ Сортировать по статусу
Изменить URL-адрес подмодуля
Подмодуль:
URL-адрес:
diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml
index 711ab12f3..418184113 100644
--- a/src/Resources/Locales/zh_CN.axaml
+++ b/src/Resources/Locales/zh_CN.axaml
@@ -87,6 +87,8 @@
文件名+路径列表模式
全路径列表模式
文件目录树形结构模式
+ 按路径排序
+ 按状态排序
修改子模块远程地址
子模块 :
远程地址 :
diff --git a/src/ViewModels/ChangeTreeNode.cs b/src/ViewModels/ChangeTreeNode.cs
index 4d71a153b..72efc8287 100644
--- a/src/ViewModels/ChangeTreeNode.cs
+++ b/src/ViewModels/ChangeTreeNode.cs
@@ -47,7 +47,7 @@ public ChangeTreeNode(string path, bool isExpanded, int depth)
IsExpanded = isExpanded;
}
- public static List Build(IList changes, HashSet folded)
+ public static List Build(IList changes, HashSet folded, Models.ChangeSortMode sortMode = Models.ChangeSortMode.Path, bool isUnstagedContext = false)
{
var nodes = new List();
var folders = new Dictionary();
@@ -93,7 +93,7 @@ public static List Build(IList changes, HashSet collection, ChangeTreeNode
collection.Add(subFolder);
}
- private static void Sort(List nodes)
+ private static void Sort(List nodes, Models.ChangeSortMode sortMode, bool isUnstagedContext)
{
foreach (var node in nodes)
{
if (node.IsFolder)
- Sort(node.Children);
+ Sort(node.Children, sortMode, isUnstagedContext);
}
- nodes.Sort((l, r) =>
+ if (sortMode == Models.ChangeSortMode.Status)
{
- if (l.IsFolder == r.IsFolder)
+ nodes.Sort((l, r) =>
+ {
+ // Sort folders first
+ if (l.IsFolder != r.IsFolder)
+ return l.IsFolder ? -1 : 1;
+
+ // If both are folders, sort by path
+ if (l.IsFolder && r.IsFolder)
+ return Models.NumericSort.Compare(l.FullPath, r.FullPath);
+
+ // For files, sort by status first
+ var leftPriority = Models.Change.GetStatusSortPriority(l.Change, isUnstagedContext);
+ var rightPriority = Models.Change.GetStatusSortPriority(r.Change, isUnstagedContext);
+
+ // First sort by status priority
+ var statusComparison = leftPriority.CompareTo(rightPriority);
+ if (statusComparison != 0)
+ return statusComparison;
+
+ // If status priorities are equal, sort by path as secondary sort
+ // Use the same sorting logic as the path-only sort for consistency
return Models.NumericSort.Compare(l.FullPath, r.FullPath);
- return l.IsFolder ? -1 : 1;
- });
+ });
+ }
+ else
+ {
+ nodes.Sort((l, r) =>
+ {
+ if (l.IsFolder == r.IsFolder)
+ return Models.NumericSort.Compare(l.FullPath, r.FullPath);
+ return l.IsFolder ? -1 : 1;
+ });
+ }
}
private bool _isExpanded = true;
diff --git a/src/ViewModels/Preferences.cs b/src/ViewModels/Preferences.cs
index 05be06010..0a2a975d9 100644
--- a/src/ViewModels/Preferences.cs
+++ b/src/ViewModels/Preferences.cs
@@ -291,6 +291,30 @@ public Models.ChangeViewMode StashChangeViewMode
set => SetProperty(ref _stashChangeViewMode, value);
}
+ public Models.ChangeSortMode UnstagedChangeSortMode
+ {
+ get => _unstagedChangeSortMode;
+ set => SetProperty(ref _unstagedChangeSortMode, value);
+ }
+
+ public Models.ChangeSortMode StagedChangeSortMode
+ {
+ get => _stagedChangeSortMode;
+ set => SetProperty(ref _stagedChangeSortMode, value);
+ }
+
+ public Models.ChangeSortMode CommitChangeSortMode
+ {
+ get => _commitChangeSortMode;
+ set => SetProperty(ref _commitChangeSortMode, value);
+ }
+
+ public Models.ChangeSortMode StashChangeSortMode
+ {
+ get => _stashChangeSortMode;
+ set => SetProperty(ref _stashChangeSortMode, value);
+ }
+
public string GitInstallPath
{
get => Native.OS.GitExecutable;
@@ -715,6 +739,11 @@ private bool RemoveInvalidRepositoriesRecursive(List collection)
private Models.ChangeViewMode _commitChangeViewMode = Models.ChangeViewMode.List;
private Models.ChangeViewMode _stashChangeViewMode = Models.ChangeViewMode.List;
+ private Models.ChangeSortMode _unstagedChangeSortMode = Models.ChangeSortMode.Path;
+ private Models.ChangeSortMode _stagedChangeSortMode = Models.ChangeSortMode.Path;
+ private Models.ChangeSortMode _commitChangeSortMode = Models.ChangeSortMode.Path;
+ private Models.ChangeSortMode _stashChangeSortMode = Models.ChangeSortMode.Path;
+
private string _gitDefaultCloneDir = string.Empty;
private int _shellOrTerminal = -1;
diff --git a/src/Views/BranchCompare.axaml b/src/Views/BranchCompare.axaml
index b80fefb5d..b77347b0b 100644
--- a/src/Views/BranchCompare.axaml
+++ b/src/Views/BranchCompare.axaml
@@ -119,12 +119,14 @@
+ ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=CommitChangeViewMode, Mode=TwoWay}"
+ SortMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=CommitChangeSortMode, Mode=TwoWay}"/>
diff --git a/src/Views/ChangeCollectionView.axaml.cs b/src/Views/ChangeCollectionView.axaml.cs
index 8b9f90586..df2d55a1a 100644
--- a/src/Views/ChangeCollectionView.axaml.cs
+++ b/src/Views/ChangeCollectionView.axaml.cs
@@ -109,6 +109,15 @@ public Models.ChangeViewMode ViewMode
set => SetValue(ViewModeProperty, value);
}
+ public static readonly StyledProperty SortModeProperty =
+ AvaloniaProperty.Register(nameof(SortMode), Models.ChangeSortMode.Path);
+
+ public Models.ChangeSortMode SortMode
+ {
+ get => GetValue(SortModeProperty);
+ set => SetValue(SortModeProperty, value);
+ }
+
public static readonly StyledProperty> ChangesProperty =
AvaloniaProperty.Register>(nameof(Changes));
@@ -250,6 +259,8 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
if (change.Property == ViewModeProperty)
UpdateDataSource(true);
+ else if (change.Property == SortModeProperty)
+ UpdateDataSource(true);
else if (change.Property == ChangesProperty)
UpdateDataSource(false);
else if (change.Property == SelectedChangesProperty)
@@ -384,7 +395,7 @@ private void UpdateDataSource(bool onlyViewModeChange)
}
var tree = new ViewModels.ChangeCollectionAsTree();
- tree.Tree = ViewModels.ChangeTreeNode.Build(changes, oldFolded);
+ tree.Tree = ViewModels.ChangeTreeNode.Build(changes, oldFolded, SortMode, IsUnstagedChange);
var rows = new List();
MakeTreeRows(rows, tree.Tree);
@@ -408,7 +419,8 @@ private void UpdateDataSource(bool onlyViewModeChange)
else if (ViewMode == Models.ChangeViewMode.Grid)
{
var grid = new ViewModels.ChangeCollectionAsGrid();
- grid.Changes.AddRange(changes);
+ var sortedChanges = SortChanges(changes, SortMode);
+ grid.Changes.AddRange(sortedChanges);
if (selected.Count > 0)
grid.SelectedChanges.AddRange(selected);
@@ -417,7 +429,8 @@ private void UpdateDataSource(bool onlyViewModeChange)
else
{
var list = new ViewModels.ChangeCollectionAsList();
- list.Changes.AddRange(changes);
+ var sortedChanges = SortChanges(changes, SortMode);
+ list.Changes.AddRange(sortedChanges);
if (selected.Count > 0)
list.SelectedChanges.AddRange(selected);
@@ -497,6 +510,36 @@ private void UpdateRowTips(Control control, Models.Change change)
ToolTip.SetTip(control, tip);
}
+ private List SortChanges(List changes, Models.ChangeSortMode sortMode)
+ {
+ var sortedChanges = new List(changes);
+
+ if (sortMode == Models.ChangeSortMode.Status)
+ {
+ sortedChanges.Sort((l, r) =>
+ {
+ var leftPriority = Models.Change.GetStatusSortPriority(l, IsUnstagedChange);
+ var rightPriority = Models.Change.GetStatusSortPriority(r, IsUnstagedChange);
+
+ // First sort by status priority
+ var statusComparison = leftPriority.CompareTo(rightPriority);
+ if (statusComparison != 0)
+ return statusComparison;
+
+ // If status priorities are equal, sort by path as secondary sort
+ // Use the same sorting logic as the path-only sort for consistency
+ return Models.NumericSort.Compare(l.Path, r.Path);
+ });
+ }
+ else
+ {
+ // Path sort mode - use NumericSort for consistency
+ sortedChanges.Sort((l, r) => Models.NumericSort.Compare(l.Path, r.Path));
+ }
+
+ return sortedChanges;
+ }
+
private bool _disableSelectionChangingEvent = false;
}
}
diff --git a/src/Views/ChangeViewModeSwitcher.axaml b/src/Views/ChangeViewModeSwitcher.axaml
index b72fcbcb8..31c19fb9e 100644
--- a/src/Views/ChangeViewModeSwitcher.axaml
+++ b/src/Views/ChangeViewModeSwitcher.axaml
@@ -24,6 +24,17 @@
+
+
+
diff --git a/src/Views/ChangeViewModeSwitcher.axaml.cs b/src/Views/ChangeViewModeSwitcher.axaml.cs
index ed3066196..ef70411b1 100644
--- a/src/Views/ChangeViewModeSwitcher.axaml.cs
+++ b/src/Views/ChangeViewModeSwitcher.axaml.cs
@@ -15,6 +15,15 @@ public Models.ChangeViewMode ViewMode
set => SetValue(ViewModeProperty, value);
}
+ public static readonly StyledProperty SortModeProperty =
+ AvaloniaProperty.Register(nameof(SortMode));
+
+ public Models.ChangeSortMode SortMode
+ {
+ get => GetValue(SortModeProperty);
+ set => SetValue(SortModeProperty, value);
+ }
+
public ChangeViewModeSwitcher()
{
InitializeComponent();
@@ -37,5 +46,17 @@ private void SwitchToTree(object sender, RoutedEventArgs e)
ViewMode = Models.ChangeViewMode.Tree;
e.Handled = true;
}
+
+ private void SortByPath(object sender, RoutedEventArgs e)
+ {
+ SortMode = Models.ChangeSortMode.Path;
+ e.Handled = true;
+ }
+
+ private void SortByStatus(object sender, RoutedEventArgs e)
+ {
+ SortMode = Models.ChangeSortMode.Status;
+ e.Handled = true;
+ }
}
}
diff --git a/src/Views/CommitChanges.axaml b/src/Views/CommitChanges.axaml
index 4a1d95bcf..48abd5216 100644
--- a/src/Views/CommitChanges.axaml
+++ b/src/Views/CommitChanges.axaml
@@ -41,13 +41,15 @@
+ ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=CommitChangeViewMode, Mode=TwoWay}"
+ SortMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=CommitChangeSortMode, Mode=TwoWay}"/>
diff --git a/src/Views/RevisionCompare.axaml b/src/Views/RevisionCompare.axaml
index b19bba554..57717c6f2 100644
--- a/src/Views/RevisionCompare.axaml
+++ b/src/Views/RevisionCompare.axaml
@@ -91,12 +91,14 @@
+ ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=CommitChangeViewMode, Mode=TwoWay}"
+ SortMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=CommitChangeSortMode, Mode=TwoWay}"/>
diff --git a/src/Views/StashesPage.axaml b/src/Views/StashesPage.axaml
index 36d3d0881..3e3c2c8e8 100644
--- a/src/Views/StashesPage.axaml
+++ b/src/Views/StashesPage.axaml
@@ -121,13 +121,15 @@
Width="14" Height="14"
Margin="0,0,8,0"
HorizontalAlignment="Right"
- ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=StashChangeViewMode, Mode=TwoWay}"/>
+ ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=StashChangeViewMode, Mode=TwoWay}"
+ SortMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=StashChangeSortMode, Mode=TwoWay}"/>
diff --git a/src/Views/WorkingCopy.axaml b/src/Views/WorkingCopy.axaml
index 99505c9fb..d3ca0ec25 100644
--- a/src/Views/WorkingCopy.axaml
+++ b/src/Views/WorkingCopy.axaml
@@ -118,7 +118,8 @@
+ ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=UnstagedChangeViewMode, Mode=TwoWay}"
+ SortMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=UnstagedChangeSortMode, Mode=TwoWay}"/>
@@ -129,6 +130,7 @@
SelectionMode="Multiple"
Background="{DynamicResource Brush.Contents}"
ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=UnstagedChangeViewMode}"
+ SortMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=UnstagedChangeSortMode}"
Changes="{Binding VisibleUnstaged}"
SelectedChanges="{Binding SelectedUnstaged, Mode=TwoWay}"
ContextRequested="OnUnstagedContextRequested"
@@ -172,7 +174,8 @@
+ ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=StagedChangeViewMode, Mode=TwoWay}"
+ SortMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=StagedChangeSortMode, Mode=TwoWay}"/>
@@ -183,6 +186,7 @@
SelectionMode="Multiple"
Background="{DynamicResource Brush.Contents}"
ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=StagedChangeViewMode}"
+ SortMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=StagedChangeSortMode}"
Changes="{Binding VisibleStaged}"
SelectedChanges="{Binding SelectedStaged, Mode=TwoWay}"
ContextRequested="OnStagedContextRequested"