mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-23 20:47:25 -08:00
feature<Histories>: add reword/squash context menu for HEAD commit
This commit is contained in:
parent
76f192785c
commit
59fa5304d8
9 changed files with 279 additions and 6 deletions
|
@ -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
16
src/Commands/Reword.cs
Normal 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}\"";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
59
src/Views/Popups/Reword.xaml
Normal file
59
src/Views/Popups/Reword.xaml
Normal 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>
|
40
src/Views/Popups/Reword.xaml.cs
Normal file
40
src/Views/Popups/Reword.xaml.cs
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
73
src/Views/Popups/Squash.xaml
Normal file
73
src/Views/Popups/Squash.xaml
Normal 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>
|
40
src/Views/Popups/Squash.xaml.cs
Normal file
40
src/Views/Popups/Squash.xaml.cs
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue