feature<Histories>: add reword/squash context menu for HEAD commit

This commit is contained in:
leo 2021-08-05 20:38:38 +08:00
parent 76f192785c
commit 59fa5304d8
9 changed files with 279 additions and 6 deletions

View file

@ -5,14 +5,12 @@ namespace SourceGit.Commands {
/// `git commit`命令
/// </summary>
public class Commit : Command {
private string msg = null;
public Commit(string repo, string message, bool amend) {
msg = Path.GetTempFileName();
File.WriteAllText(msg, message);
var file = Path.GetTempFileName();
File.WriteAllText(file, message);
Cwd = repo;
Args = $"commit --file=\"{msg}\"";
Args = $"commit --file=\"{file}\"";
if (amend) Args += " --amend --no-edit";
}
}

16
src/Commands/Reword.cs Normal file
View file

@ -0,0 +1,16 @@
using System.IO;
namespace SourceGit.Commands {
/// <summary>
/// 编辑HEAD的提交信息
/// </summary>
public class Reword : Command {
public Reword(string repo, string msg) {
var tmp = Path.GetTempFileName();
File.WriteAllText(tmp, msg);
Cwd = repo;
Args = $"commit --amend --allow-empty --file=\"{tmp}\"";
}
}
}

View file

@ -196,6 +196,8 @@
<sys:String x:Key="Text.CommitCM.InteractiveRebase">Interactive Rebase '{0}' from Here</sys:String>
<sys:String x:Key="Text.CommitCM.Rebase">Rebase '{0}' to Here</sys:String>
<sys:String x:Key="Text.CommitCM.CherryPick">Cherry-Pick This Commit</sys:String>
<sys:String x:Key="Text.CommitCM.Reword">Reword</sys:String>
<sys:String x:Key="Text.CommitCM.Squash">Squash Into Parent</sys:String>
<sys:String x:Key="Text.CommitCM.Revert">Revert Commit</sys:String>
<sys:String x:Key="Text.CommitCM.SaveAsPatch">Save as Patch ...</sys:String>
<sys:String x:Key="Text.CommitCM.CopySHA">Copy Commit SHA</sys:String>
@ -466,6 +468,15 @@
<sys:String x:Key="Text.Hotkeys.Refresh">Reload current repository if possible</sys:String>
<sys:String x:Key="Text.Hotkeys.ToggleStage">Stage or unstage selected files</sys:String>
<sys:String x:Key="Text.Reword">Reword Commit Message</sys:String>
<sys:String x:Key="Text.Reword.On">On :</sys:String>
<sys:String x:Key="Text.Reword.Message">Message :</sys:String>
<sys:String x:Key="Text.Squash">Squash HEAD Into Parent</sys:String>
<sys:String x:Key="Text.Squash.Head">HEAD :</sys:String>
<sys:String x:Key="Text.Squash.To">To :</sys:String>
<sys:String x:Key="Text.Squash.Message">Reword :</sys:String>
<sys:String x:Key="Text.NotConfigured">Git has NOT been configured. Please to go [Preference] and configure it first.</sys:String>
<sys:String x:Key="Text.PathNotFound">Path[{0}] not exists!</sys:String>
<sys:String x:Key="Text.MissingBash">Can NOT locate bash.exe. Make sure bash.exe exists under the same folder with git.exe</sys:String>
@ -486,7 +497,7 @@
<sys:String x:Key="Text.EmptyTagName">Tag name can NOT be null</sys:String>
<sys:String x:Key="Text.BadTagName">Bad name for tag. Regex: ^[\\w\\-\\.]+$</sys:String>
<sys:String x:Key="Text.DuplicatedTagName">Duplicated tag name!</sys:String>
<sys:String x:Key="Text.EmptyCommitMessage">Commit subject can NOT be empty</sys:String>
<sys:String x:Key="Text.EmptyCommitMessage">Commit message can NOT be empty</sys:String>
<sys:String x:Key="Text.BadPatchFile">Invalid path for patch file</sys:String>
<sys:String x:Key="Text.BadRelativePath">Invalid relative path</sys:String>
<sys:String x:Key="Text.BadArchiveFile">Invalid path for archive file</sys:String>

View file

@ -195,6 +195,8 @@
<sys:String x:Key="Text.CommitCM.InteractiveRebase">从此处开始对 '{0}' 交互式变基</sys:String>
<sys:String x:Key="Text.CommitCM.Rebase">变基 '{0}' 到此处</sys:String>
<sys:String x:Key="Text.CommitCM.CherryPick">挑选此提交</sys:String>
<sys:String x:Key="Text.CommitCM.Reword">编辑提交信息</sys:String>
<sys:String x:Key="Text.CommitCM.Squash">合并此提交到上一个提交</sys:String>
<sys:String x:Key="Text.CommitCM.Revert">回滚此提交</sys:String>
<sys:String x:Key="Text.CommitCM.SaveAsPatch">另存为补丁 ...</sys:String>
<sys:String x:Key="Text.CommitCM.CopySHA">复制提交指纹</sys:String>
@ -465,6 +467,15 @@
<sys:String x:Key="Text.Hotkeys.Refresh">重新加载当前仓库信息(仅在仓库页起效)</sys:String>
<sys:String x:Key="Text.Hotkeys.ToggleStage">暂存或从暂存中移除当前选中</sys:String>
<sys:String x:Key="Text.Reword">编辑提交信息</sys:String>
<sys:String x:Key="Text.Reword.On">提交:</sys:String>
<sys:String x:Key="Text.Reword.Message">提交信息:</sys:String>
<sys:String x:Key="Text.Squash">合并HEAD到上一个提交</sys:String>
<sys:String x:Key="Text.Squash.Head">当前提交 :</sys:String>
<sys:String x:Key="Text.Squash.To">合并到 :</sys:String>
<sys:String x:Key="Text.Squash.Message">修改提交信息:</sys:String>
<sys:String x:Key="Text.NotConfigured">GIT尚未配置。请打开【偏好设置】配置GIT路径。</sys:String>
<sys:String x:Key="Text.PathNotFound">路径({0})不存在或不可读取!</sys:String>
<sys:String x:Key="Text.MissingBash">无法找到bash.exe请确保其在git.exe同目录中</sys:String>

View file

@ -0,0 +1,59 @@
<controls:PopupWidget
x:Class="SourceGit.Views.Popups.Reword"
x:Name="me"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:controls="clr-namespace:SourceGit.Views.Controls"
xmlns:validations="clr-namespace:SourceGit.Views.Validations"
mc:Ignorable="d"
d:DesignWidth="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0" Grid.Column="0"
Margin="0,0,8,0"
Text="{DynamicResource Text.Reword.On}"
HorizontalAlignment="Right"/>
<StackPanel
Grid.Row="0" Grid.Column="1"
Orientation="Horizontal"
VerticalAlignment="Center">
<Path Width="14" Height="14" Data="{StaticResource Icon.Commit}"/>
<TextBlock x:Name="txtCurrent" Margin="8,0,0,0"/>
</StackPanel>
<TextBlock
Grid.Row="1" Grid.Column="0"
Margin="0,8,8,0"
HorizontalAlignment="Right" VerticalAlignment="Top"
Text="{DynamicResource Text.Reword.Message}"/>
<controls:TextEdit
Grid.Row="1" Grid.Column="1"
x:Name="txtMsg"
Height="100" Margin="0,8,0,0" Padding="1"
AcceptsReturn="True"
AcceptsTab="True"
TextWrapping="Wrap"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<controls:TextEdit.Text>
<Binding ElementName="me" Path="Msg" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<validations:CommitMessage/>
</Binding.ValidationRules>
</Binding>
</controls:TextEdit.Text>
</controls:TextEdit>
</Grid>
</controls:PopupWidget>

View file

@ -0,0 +1,40 @@
using System.Threading.Tasks;
using System.Windows.Controls;
namespace SourceGit.Views.Popups {
/// <summary>
/// 编辑HEAD的提交描述
/// </summary>
public partial class Reword : Controls.PopupWidget {
private string repo = null;
private string old = null;
public string Msg { get; set; }
public Reword(string repo, Models.Commit commit) {
this.repo = repo;
this.old = $"{commit.Subject}\n{commit.Message}".Trim();
this.Msg = old;
InitializeComponent();
txtCurrent.Text = $"{commit.ShortSHA} {commit.Subject}";
}
public override string GetTitle() {
return App.Text("Reword");
}
public override Task<bool> Start() {
txtMsg.GetBindingExpression(TextBox.TextProperty).UpdateSource();
if (Validation.GetHasError(txtMsg)) return null;
return Task.Run(() => {
if (old == Msg) return true;
Models.Watcher.SetEnabled(repo, false);
new Commands.Reword(repo, Msg).Exec();
Models.Watcher.SetEnabled(repo, true);
return true;
});
}
}
}

View file

@ -0,0 +1,73 @@
<controls:PopupWidget
x:Class="SourceGit.Views.Popups.Squash"
x:Name="me"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:controls="clr-namespace:SourceGit.Views.Controls"
xmlns:validations="clr-namespace:SourceGit.Views.Validations"
mc:Ignorable="d"
d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition Height="32"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0" Grid.Column="0"
Margin="0,0,8,0"
Text="{DynamicResource Text.Squash.Head}"
HorizontalAlignment="Right"/>
<StackPanel
Grid.Row="0" Grid.Column="1"
Orientation="Horizontal"
VerticalAlignment="Center">
<Path Width="14" Height="14" Data="{StaticResource Icon.Commit}"/>
<TextBlock x:Name="txtHead" Margin="8,0,0,0"/>
</StackPanel>
<TextBlock
Grid.Row="1" Grid.Column="0"
Margin="0,0,8,0"
Text="{DynamicResource Text.Squash.To}"
HorizontalAlignment="Right"/>
<StackPanel
Grid.Row="1" Grid.Column="1"
Orientation="Horizontal"
VerticalAlignment="Center">
<Path Width="14" Height="14" Data="{StaticResource Icon.Commit}"/>
<TextBlock x:Name="txtParent" Margin="8,0,0,0"/>
</StackPanel>
<TextBlock
Grid.Row="2" Grid.Column="0"
Margin="0,8,8,0"
HorizontalAlignment="Right" VerticalAlignment="Top"
Text="{DynamicResource Text.Squash.Message}"/>
<controls:TextEdit
Grid.Row="2" Grid.Column="1"
x:Name="txtMsg"
Height="100" Margin="0,8,0,0" Padding="1"
AcceptsReturn="True"
AcceptsTab="True"
TextWrapping="Wrap"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<controls:TextEdit.Text>
<Binding ElementName="me" Path="Msg" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<validations:CommitMessage/>
</Binding.ValidationRules>
</Binding>
</controls:TextEdit.Text>
</controls:TextEdit>
</Grid>
</controls:PopupWidget>

View file

@ -0,0 +1,40 @@
using System.Threading.Tasks;
using System.Windows.Controls;
namespace SourceGit.Views.Popups {
/// <summary>
/// 合并当前HEAD提交到上一个
/// </summary>
public partial class Squash : Controls.PopupWidget {
private string repo = null;
private string to = null;
public string Msg { get; set; }
public Squash(string repo, Models.Commit head, Models.Commit parent) {
this.repo = repo;
this.to = parent.SHA;
this.Msg = $"{parent.Subject}\n{parent.Message}".Trim();
InitializeComponent();
txtHead.Text = $"{head.ShortSHA} {head.Subject}";
txtParent.Text = $"{parent.ShortSHA} {parent.Subject}";
}
public override string GetTitle() {
return App.Text("Squash");
}
public override Task<bool> Start() {
txtMsg.GetBindingExpression(TextBox.TextProperty).UpdateSource();
if (Validation.GetHasError(txtMsg)) return null;
return Task.Run(() => {
Models.Watcher.SetEnabled(repo, false);
var succ = new Commands.Reset(repo, to, "--soft").Exec();
if (succ) new Commands.Commit(repo, Msg, true).Exec();
Models.Watcher.SetEnabled(repo, true);
return true;
});
}
}
}

View file

@ -294,6 +294,31 @@ namespace SourceGit.Views.Widgets {
e.Handled = true;
};
menu.Items.Add(reset);
} else {
var reword = new MenuItem();
reword.Header = App.Text("CommitCM.Reword");
reword.Click += (o, e) => {
new Popups.Reword(repo.Path, commit).Show();
e.Handled = true;
};
menu.Items.Add(reword);
var squash = new MenuItem();
squash.Header = App.Text("CommitCM.Squash");
squash.IsEnabled = commit.Parents.Count == 1;
squash.Click += (o, e) => {
foreach (var c in cachedCommits) {
if (c.SHA == commit.Parents[0]) {
new Popups.Squash(repo.Path, commit, c).Show();
e.Handled = true;
return;
}
}
Models.Exception.Raise("Can NOT found parent of HEAD!");
e.Handled = true;
};
menu.Items.Add(squash);
}
if (!merged) {