feature<AssumeUnchanged>: supports update-index --[no]-assume-unchanged

This commit is contained in:
leo 2023-08-24 19:05:38 +08:00
parent 79b5136a46
commit f13b1ee9fe
9 changed files with 272 additions and 3 deletions

View file

@ -0,0 +1,60 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace SourceGit.Commands {
/// <summary>
/// 查看、添加或移除忽略变更文件
/// </summary>
public class AssumeUnchanged {
private string repo;
class ViewCommand : Command {
private static readonly Regex REG = new Regex(@"^(\w)\s+(.+)$");
private List<string> outs = new List<string>();
public ViewCommand(string repo) {
Cwd = repo;
Args = "ls-files -v";
}
public List<string> Result() {
Exec();
return outs;
}
public override void OnReadline(string line) {
var match = REG.Match(line);
if (!match.Success) return;
if (match.Groups[1].Value == "h") {
outs.Add(match.Groups[2].Value);
}
}
}
class ModCommand : Command {
public ModCommand(string repo, string file, bool bAdd) {
var mode = bAdd ? "--assume-unchanged" : "--no-assume-unchanged";
Cwd = repo;
Args = $"update-index {mode} -- \"{file}\"";
}
}
public AssumeUnchanged(string repo) {
this.repo = repo;
}
public List<string> View() {
return new ViewCommand(repo).Result();
}
public void Add(string file) {
new ModCommand(repo, file, true).Exec();
}
public void Remove(string file) {
new ModCommand(repo, file, false).Exec();
}
}
}

View file

@ -70,4 +70,6 @@
<StreamGeometry x:Key="Icon.VSCode">M719 85 388 417l-209-165L87 299v427l92 47 210-164L720 939 939 850V171zM186 610V412l104 104zm526 55L514 512l198-153z</StreamGeometry> <StreamGeometry x:Key="Icon.VSCode">M719 85 388 417l-209-165L87 299v427l92 47 210-164L720 939 939 850V171zM186 610V412l104 104zm526 55L514 512l198-153z</StreamGeometry>
<StreamGeometry x:Key="Icon.Sort">M426.7 554.7v-85.3h341.3v85.3h-341.3m0 256v-85.3h170.7v85.3h-170.7m0-512V213.3h512v85.3H426.7M256 725.3h106.7L213.3 874.7 64 725.3H170.7V298.7H64L213.3 149.3 362.7 298.7H256v426.7z</StreamGeometry> <StreamGeometry x:Key="Icon.Sort">M426.7 554.7v-85.3h341.3v85.3h-341.3m0 256v-85.3h170.7v85.3h-170.7m0-512V213.3h512v85.3H426.7M256 725.3h106.7L213.3 874.7 64 725.3H170.7V298.7H64L213.3 149.3 362.7 298.7H256v426.7z</StreamGeometry>
<StreamGeometry x:Key="Icon.Ignores">M854 170c-189-189-495-189-684 0s-189 495 0 684 495 189 684 0 187-495 0-684zM213 706c-89-137-74-325 48-444 122-122 307-137 444-48L213 706zm106 105 493-493c89 137 74 325-48 444-120 122-307 137-444 48z</StreamGeometry>
<StreamGeometry x:Key="Icon.Empty">M469 235V107h85v128h-85zm-162-94 85 85-60 60-85-85 60-60zm469 60-85 85-60-60 85-85 60 60zm-549 183A85 85 0 01302 341H722a85 85 0 0174 42l131 225A85 85 0 01939 652V832a85 85 0 01-85 85H171a85 85 0 01-85-85v-180a85 85 0 0112-43l131-225zM722 427H302l-100 171h255l10 29a59 59 0 002 5c2 4 5 9 9 14 8 9 18 17 34 17 16 0 26-7 34-17a72 72 0 0011-18l0-0 10-29h255l-100-171zM853 683H624a155 155 0 01-12 17C593 722 560 747 512 747c-48 0-81-25-99-47a155 155 0 01-12-17H171v149h683v-149z</StreamGeometry>
</ResourceDictionary> </ResourceDictionary>

View file

@ -217,6 +217,7 @@
<sys:String x:Key="Text.FileCM.DiscardMulti">Discard {0} files...</sys:String> <sys:String x:Key="Text.FileCM.DiscardMulti">Discard {0} files...</sys:String>
<sys:String x:Key="Text.FileCM.StashMulti">Stash {0} files...</sys:String> <sys:String x:Key="Text.FileCM.StashMulti">Stash {0} files...</sys:String>
<sys:String x:Key="Text.FileCM.SaveAsPatch">Save As Patch...</sys:String> <sys:String x:Key="Text.FileCM.SaveAsPatch">Save As Patch...</sys:String>
<sys:String x:Key="Text.FileCM.AssumeUnchanged">Assume unchaged</sys:String>
<sys:String x:Key="Text.DeleteBranch">Confirm To Delete Branch</sys:String> <sys:String x:Key="Text.DeleteBranch">Confirm To Delete Branch</sys:String>
<sys:String x:Key="Text.DeleteBranch.Branch">Branch :</sys:String> <sys:String x:Key="Text.DeleteBranch.Branch">Branch :</sys:String>
@ -394,6 +395,7 @@
<sys:String x:Key="Text.WorkingCopy">Changes</sys:String> <sys:String x:Key="Text.WorkingCopy">Changes</sys:String>
<sys:String x:Key="Text.WorkingCopy.Unstaged">UNSTAGED</sys:String> <sys:String x:Key="Text.WorkingCopy.Unstaged">UNSTAGED</sys:String>
<sys:String x:Key="Text.WorkingCopy.Unstaged.ViewAssumeUnchaged">VIEW ASSUME UNCHANGED</sys:String>
<sys:String x:Key="Text.WorkingCopy.Unstaged.Stage">STAGE</sys:String> <sys:String x:Key="Text.WorkingCopy.Unstaged.Stage">STAGE</sys:String>
<sys:String x:Key="Text.WorkingCopy.Unstaged.StageAll">STAGE ALL</sys:String> <sys:String x:Key="Text.WorkingCopy.Unstaged.StageAll">STAGE ALL</sys:String>
<sys:String x:Key="Text.WorkingCopy.Staged">STAGED</sys:String> <sys:String x:Key="Text.WorkingCopy.Staged">STAGED</sys:String>
@ -477,6 +479,10 @@
<sys:String x:Key="Text.Statistics.CommitterName">COMMITTER</sys:String> <sys:String x:Key="Text.Statistics.CommitterName">COMMITTER</sys:String>
<sys:String x:Key="Text.Statistics.CommitAmount">COMMITS</sys:String> <sys:String x:Key="Text.Statistics.CommitAmount">COMMITS</sys:String>
<sys:String x:Key="Text.AssumeUnchanged">FILES ASSUME UNCHANGED</sys:String>
<sys:String x:Key="Text.AssumeUnchanged.Remove">REMOVE</sys:String>
<sys:String x:Key="Text.AssumeUnchanged.Empty">NO FILES ASSUMED AS UNCHANGED</sys:String>
<sys:String x:Key="Text.Weekday.0">SUN</sys:String> <sys:String x:Key="Text.Weekday.0">SUN</sys:String>
<sys:String x:Key="Text.Weekday.1">MON</sys:String> <sys:String x:Key="Text.Weekday.1">MON</sys:String>
<sys:String x:Key="Text.Weekday.2">TUE</sys:String> <sys:String x:Key="Text.Weekday.2">TUE</sys:String>

View file

@ -216,6 +216,7 @@
<sys:String x:Key="Text.FileCM.DiscardMulti">放弃 {0} 个文件的更改...</sys:String> <sys:String x:Key="Text.FileCM.DiscardMulti">放弃 {0} 个文件的更改...</sys:String>
<sys:String x:Key="Text.FileCM.StashMulti">贮藏选中的 {0} 个文件...</sys:String> <sys:String x:Key="Text.FileCM.StashMulti">贮藏选中的 {0} 个文件...</sys:String>
<sys:String x:Key="Text.FileCM.SaveAsPatch">另存为补丁...</sys:String> <sys:String x:Key="Text.FileCM.SaveAsPatch">另存为补丁...</sys:String>
<sys:String x:Key="Text.FileCM.AssumeUnchanged">不跟踪此文件的更改</sys:String>
<sys:String x:Key="Text.DeleteBranch">确定要删除此分支吗?</sys:String> <sys:String x:Key="Text.DeleteBranch">确定要删除此分支吗?</sys:String>
<sys:String x:Key="Text.DeleteBranch.Branch">分支名 </sys:String> <sys:String x:Key="Text.DeleteBranch.Branch">分支名 </sys:String>
@ -393,6 +394,7 @@
<sys:String x:Key="Text.WorkingCopy">本地更改</sys:String> <sys:String x:Key="Text.WorkingCopy">本地更改</sys:String>
<sys:String x:Key="Text.WorkingCopy.Unstaged">未暂存</sys:String> <sys:String x:Key="Text.WorkingCopy.Unstaged">未暂存</sys:String>
<sys:String x:Key="Text.WorkingCopy.Unstaged.ViewAssumeUnchaged">查看忽略变更文件</sys:String>
<sys:String x:Key="Text.WorkingCopy.Unstaged.Stage">暂存选中</sys:String> <sys:String x:Key="Text.WorkingCopy.Unstaged.Stage">暂存选中</sys:String>
<sys:String x:Key="Text.WorkingCopy.Unstaged.StageAll">暂存所有</sys:String> <sys:String x:Key="Text.WorkingCopy.Unstaged.StageAll">暂存所有</sys:String>
<sys:String x:Key="Text.WorkingCopy.Staged">已暂存</sys:String> <sys:String x:Key="Text.WorkingCopy.Staged">已暂存</sys:String>
@ -476,6 +478,10 @@
<sys:String x:Key="Text.Statistics.CommitterName">提交者</sys:String> <sys:String x:Key="Text.Statistics.CommitterName">提交者</sys:String>
<sys:String x:Key="Text.Statistics.CommitAmount">提交次数</sys:String> <sys:String x:Key="Text.Statistics.CommitAmount">提交次数</sys:String>
<sys:String x:Key="Text.AssumeUnchanged">不跟踪更改的文件</sys:String>
<sys:String x:Key="Text.AssumeUnchanged.Remove">移除</sys:String>
<sys:String x:Key="Text.AssumeUnchanged.Empty">没有不跟踪更改的文件</sys:String>
<sys:String x:Key="Text.Weekday.0">星期日</sys:String> <sys:String x:Key="Text.Weekday.0">星期日</sys:String>
<sys:String x:Key="Text.Weekday.1">星期一</sys:String> <sys:String x:Key="Text.Weekday.1">星期一</sys:String>
<sys:String x:Key="Text.Weekday.2">星期二</sys:String> <sys:String x:Key="Text.Weekday.2">星期二</sys:String>

View file

@ -0,0 +1,100 @@
<controls:Window
x:Class="SourceGit.Views.AssumeUnchanged"
x:Name="me"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:SourceGit.Views.Controls"
mc:Ignorable="d"
WindowStartupLocation="CenterOwner"
Title="{DynamicResource Text.AssumeUnchanged}"
Width="600" MinHeight="200" SizeToContent="Height"
ResizeMode="NoResize">
<Window.Resources>
<Style x:Key="Style.DataGridRow.Change" TargetType="{x:Type DataGridRow}" BasedOn="{StaticResource Style.DataGridRow}">
<EventSetter Event="RequestBringIntoView" Handler="OnRequestBringIntoView"/>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28"/>
<RowDefinition Height="1"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Title bar -->
<Grid Grid.Row="0" Background="{DynamicResource Brush.TitleBar}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- Icon -->
<Path Grid.Column="0" Margin="6,0" Width="16" Height="16" Data="{StaticResource Icon.Ignores}"/>
<!-- Title -->
<TextBlock Grid.Column="1" Text="{DynamicResource Text.AssumeUnchanged}"/>
<!-- Close -->
<controls:IconButton
Grid.Column="3"
Click="OnQuit"
Width="28"
IconSize="10"
Icon="{StaticResource Icon.Close}"
HoverBackground="Red"
WindowChrome.IsHitTestVisibleInChrome="True"/>
</Grid>
<Rectangle
Grid.Row="1"
Height="1"
HorizontalAlignment="Stretch"
Fill="{DynamicResource Brush.Border0}"/>
<DataGrid
Grid.Row="2"
x:Name="list"
Margin="8,4"
RowHeight="24"
SelectionMode="Extended"
SelectionUnit="FullRow"
Background="{DynamicResource Brush.Contents}"
ItemsSource="{Binding ElementName=me, Path=Files}"
RowStyle="{StaticResource Style.DataGridRow.Change}"
Visibility="Collapsed">
<DataGrid.Columns>
<DataGridTemplateColumn IsReadOnly="True" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Margin="8,0" Text="{Binding .}" FontSize="14"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="32">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<controls:IconButton
Grid.Column="6"
Click="Remove"
Width="12" Height="12"
Margin="4,0"
Icon="{StaticResource Icon.Close}"
ToolTip="{DynamicResource Text.AssumeUnchanged.Remove}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<StackPanel Grid.Row="2" x:Name="mask" Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Collapsed">
<Path Width="48" Height="48" Margin="0,32,0,8" Data="{StaticResource Icon.Empty}" Fill="{DynamicResource Brush.FG2}"/>
<TextBlock Margin="0,0,0,32" Text="{DynamicResource Text.AssumeUnchanged.Empty}" Foreground="{DynamicResource Brush.FG2}"/>
</StackPanel>
</Grid>
</controls:Window>

View file

@ -0,0 +1,64 @@
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace SourceGit.Views {
/// <summary>
/// 管理不跟踪变更的文件
/// </summary>
public partial class AssumeUnchanged : Controls.Window {
private string repo = null;
public ObservableCollection<string> Files { get; set; }
public AssumeUnchanged(string repo) {
this.repo = repo;
this.Files = new ObservableCollection<string>();
InitializeComponent();
Task.Run(() => {
var unchanged = new Commands.AssumeUnchanged(repo).View();
Dispatcher.Invoke(() => {
if (unchanged.Count > 0) {
foreach (var file in unchanged) Files.Add(file);
mask.Visibility = Visibility.Collapsed;
list.Visibility = Visibility.Visible;
list.ItemsSource = Files;
} else {
list.Visibility = Visibility.Collapsed;
mask.Visibility = Visibility.Visible;
}
});
});
}
private void OnQuit(object sender, RoutedEventArgs e) {
Close();
}
private void OnRequestBringIntoView(object sender, RequestBringIntoViewEventArgs e) {
e.Handled = true;
}
private void Remove(object sender, RoutedEventArgs e) {
var btn = sender as Button;
if (btn == null) return;
var file = btn.DataContext as string;
if (file == null) return;
new Commands.AssumeUnchanged(repo).Remove(file);
Files.Remove(file);
if (Files.Count == 0) {
list.Visibility = Visibility.Collapsed;
mask.Visibility = Visibility.Visible;
}
e.Handled = true;
}
}
}

View file

@ -41,6 +41,7 @@
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<controls:ChangeDisplaySwitcher <controls:ChangeDisplaySwitcher
@ -61,8 +62,15 @@
x:Name="iconStaging" x:Name="iconStaging"
IsAnimating="{Binding ElementName=unstagedContainer, Path=IsStaging}" IsAnimating="{Binding ElementName=unstagedContainer, Path=IsStaging}"
Visibility="{Binding ElementName=unstagedContainer, Path=IsStaging, Converter={StaticResource BoolToCollapsed}}"/> Visibility="{Binding ElementName=unstagedContainer, Path=IsStaging, Converter={StaticResource BoolToCollapsed}}"/>
<ToggleButton <controls:IconButton
Grid.Column="4" Grid.Column="4"
Click="ViewAssumeUnchanged"
Width="14" Height="14"
Margin="4,0"
Icon="{StaticResource Icon.Ignores}"
ToolTip="{DynamicResource Text.WorkingCopy.Unstaged.ViewAssumeUnchaged}"/>
<ToggleButton
Grid.Column="5"
Width="14" Height="14" Width="14" Height="14"
Margin="4,0" Margin="4,0"
Style="{StaticResource Style.ToggleButton.Eye}" Style="{StaticResource Style.ToggleButton.Eye}"
@ -70,14 +78,14 @@
IsChecked="{Binding Source={x:Static models:Preference.Instance}, Path=Git.IncludeUntrackedInWC, Mode=TwoWay}" IsChecked="{Binding Source={x:Static models:Preference.Instance}, Path=Git.IncludeUntrackedInWC, Mode=TwoWay}"
Checked="ToggleIncludeUntracked" Unchecked="ToggleIncludeUntracked"/> Checked="ToggleIncludeUntracked" Unchecked="ToggleIncludeUntracked"/>
<controls:IconButton <controls:IconButton
Grid.Column="5" Grid.Column="6"
Click="StageSelected" Click="StageSelected"
Width="14" Height="14" Width="14" Height="14"
Margin="4,0" Margin="4,0"
Icon="{StaticResource Icon.Down}" Icon="{StaticResource Icon.Down}"
ToolTip="{DynamicResource Text.WorkingCopy.Unstaged.Stage}"/> ToolTip="{DynamicResource Text.WorkingCopy.Unstaged.Stage}"/>
<controls:IconButton <controls:IconButton
Grid.Column="6" Grid.Column="7"
Click="StageAll" Click="StageAll"
Width="14" Height="14" Width="14" Height="14"
Margin="4,0" Margin="4,0"

View file

@ -98,6 +98,12 @@ namespace SourceGit.Views.Widgets {
} }
#region STAGE_UNSTAGE #region STAGE_UNSTAGE
private void ViewAssumeUnchanged(object sender, RoutedEventArgs e) {
var dialog = new AssumeUnchanged(repo.Path);
dialog.Owner = App.Current.MainWindow;
dialog.ShowDialog();
}
private void StageSelected(object sender, RoutedEventArgs e) { private void StageSelected(object sender, RoutedEventArgs e) {
unstagedContainer.StageSelected(); unstagedContainer.StageSelected();
} }

View file

@ -1,4 +1,5 @@
using Microsoft.Win32; using Microsoft.Win32;
using SourceGit.Models;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
@ -484,6 +485,14 @@ namespace SourceGit.Views.Widgets {
menu.Items.Add(patch); menu.Items.Add(patch);
menu.Items.Add(new Separator()); menu.Items.Add(new Separator());
if (node.Change != null) { if (node.Change != null) {
var assumeUnchanged = new MenuItem();
assumeUnchanged.Header = App.Text("FileCM.AssumeUnchanged");
assumeUnchanged.Click += (o, e) => {
new Commands.AssumeUnchanged(repo).Add(node.Path);
e.Handled = true;
};
menu.Items.Add(assumeUnchanged);
var history = new MenuItem(); var history = new MenuItem();
history.Header = App.Text("FileHistory"); history.Header = App.Text("FileHistory");
history.Click += (o, e) => { history.Click += (o, e) => {
@ -622,6 +631,13 @@ namespace SourceGit.Views.Widgets {
e.Handled = true; e.Handled = true;
}; };
var assumeUnchanged = new MenuItem();
assumeUnchanged.Header = App.Text("FileCM.AssumeUnchanged");
assumeUnchanged.Click += (o, e) => {
new Commands.AssumeUnchanged(repo).Add(change.Path);
e.Handled = true;
};
menu.Items.Add(explore); menu.Items.Add(explore);
menu.Items.Add(new Separator()); menu.Items.Add(new Separator());
menu.Items.Add(stage); menu.Items.Add(stage);
@ -629,6 +645,7 @@ namespace SourceGit.Views.Widgets {
menu.Items.Add(stash); menu.Items.Add(stash);
menu.Items.Add(patch); menu.Items.Add(patch);
menu.Items.Add(new Separator()); menu.Items.Add(new Separator());
menu.Items.Add(assumeUnchanged);
menu.Items.Add(history); menu.Items.Add(history);
menu.Items.Add(new Separator()); menu.Items.Add(new Separator());
menu.Items.Add(copyPath); menu.Items.Add(copyPath);