Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions src/Commands/Reword.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.IO;
using System.Threading.Tasks;

namespace SourceGit.Commands
{
public class Reword : Command
{
public Reword(string repo, string message)
{
_tmpFile = Path.GetTempFileName();
_message = message;

WorkingDirectory = repo;
Context = repo;
Args = $"commit --amend --only --allow-empty --file={_tmpFile.Quoted()}";
}

public async Task<bool> RunAsync()
{
try
{
await File.WriteAllTextAsync(_tmpFile, _message).ConfigureAwait(false);
var succ = await ExecAsync().ConfigureAwait(false);
File.Delete(_tmpFile);
return succ;
}
catch
{
return false;
}
}

private readonly string _tmpFile;
private readonly string _message;
}
}
4 changes: 4 additions & 0 deletions src/Resources/Locales/en_US.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@
<x:String x:Key="Text.CommitCM.InteractiveRebase.Squash" xml:space="preserve">Squash into Parent...</x:String>
<x:String x:Key="Text.CommitCM.MergeMultiple" xml:space="preserve">Merge...</x:String>
<x:String x:Key="Text.CommitCM.PushRevision" xml:space="preserve">Push ${0}$ to ${1}$...</x:String>
<x:String x:Key="Text.CommitCM.QuickReword" xml:space="preserve">Quick Reword...</x:String>
<x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">Rebase ${0}$ on ${1}$...</x:String>
<x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">Reset ${0}$ to ${1}$...</x:String>
<x:String x:Key="Text.CommitCM.Revert" xml:space="preserve">Revert Commit...</x:String>
Expand Down Expand Up @@ -877,6 +878,9 @@
<x:String x:Key="Text.Revert" xml:space="preserve">Revert Commit</x:String>
<x:String x:Key="Text.Revert.Commit" xml:space="preserve">Commit:</x:String>
<x:String x:Key="Text.Revert.CommitChanges" xml:space="preserve">Commit revert changes</x:String>
<x:String x:Key="Text.Reword" xml:space="preserve">Reword Commit</x:String>
<x:String x:Key="Text.Reword.Commit" xml:space="preserve">Commit:</x:String>
<x:String x:Key="Text.Reword.Message" xml:space="preserve">Message:</x:String>
<x:String x:Key="Text.Running" xml:space="preserve">Running. Please wait...</x:String>
<x:String x:Key="Text.Save" xml:space="preserve">SAVE</x:String>
<x:String x:Key="Text.SaveAs" xml:space="preserve">Save As...</x:String>
Expand Down
4 changes: 4 additions & 0 deletions src/Resources/Locales/zh_CN.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@
<x:String x:Key="Text.CommitCM.InteractiveRebase.Squash" xml:space="preserve">合并至父提交...</x:String>
<x:String x:Key="Text.CommitCM.MergeMultiple" xml:space="preserve">合并(merge)...</x:String>
<x:String x:Key="Text.CommitCM.PushRevision" xml:space="preserve">推送(push) ${0}$ 到 ${1}$...</x:String>
<x:String x:Key="Text.CommitCM.QuickReword" xml:space="preserve">快速修改提交信息...</x:String>
<x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">变基(rebase) ${0}$ 到 ${1}$...</x:String>
<x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">重置(reset) ${0}$ 到 ${1}$...</x:String>
<x:String x:Key="Text.CommitCM.Revert" xml:space="preserve">回滚此提交...</x:String>
Expand Down Expand Up @@ -881,6 +882,9 @@
<x:String x:Key="Text.Revert" xml:space="preserve">回滚操作确认</x:String>
<x:String x:Key="Text.Revert.Commit" xml:space="preserve">目标提交 :</x:String>
<x:String x:Key="Text.Revert.CommitChanges" xml:space="preserve">回滚后提交更改</x:String>
<x:String x:Key="Text.Reword" xml:space="preserve">修改提交信息</x:String>
<x:String x:Key="Text.Reword.Commit" xml:space="preserve">目标提交 :</x:String>
<x:String x:Key="Text.Reword.Message" xml:space="preserve">提交信息:</x:String>
<x:String x:Key="Text.Running" xml:space="preserve">执行操作中,请耐心等待...</x:String>
<x:String x:Key="Text.Save" xml:space="preserve">保 存</x:String>
<x:String x:Key="Text.SaveAs" xml:space="preserve">另存为...</x:String>
Expand Down
4 changes: 4 additions & 0 deletions src/Resources/Locales/zh_TW.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@
<x:String x:Key="Text.CommitCM.InteractiveRebase.Squash" xml:space="preserve">合併至父提交...</x:String>
<x:String x:Key="Text.CommitCM.MergeMultiple" xml:space="preserve">合併 (merge)...</x:String>
<x:String x:Key="Text.CommitCM.PushRevision" xml:space="preserve">推送 (push) ${0}$ 至 ${1}$...</x:String>
<x:String x:Key="Text.CommitCM.QuickReword" xml:space="preserve">快速修改提交訊息...</x:String>
<x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">重定基底 (rebase) ${0}$ 至 ${1}$...</x:String>
<x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">重設 (reset) ${0}$ 至 ${1}$...</x:String>
<x:String x:Key="Text.CommitCM.Revert" xml:space="preserve">復原此提交...</x:String>
Expand Down Expand Up @@ -880,6 +881,9 @@
<x:String x:Key="Text.Revert" xml:space="preserve">復原操作確認</x:String>
<x:String x:Key="Text.Revert.Commit" xml:space="preserve">目標提交:</x:String>
<x:String x:Key="Text.Revert.CommitChanges" xml:space="preserve">復原後提交變更</x:String>
<x:String x:Key="Text.Reword" xml:space="preserve">修改提交訊息</x:String>
<x:String x:Key="Text.Reword.Commit" xml:space="preserve">目標提交:</x:String>
<x:String x:Key="Text.Reword.Message" xml:space="preserve">提交訊息:</x:String>
<x:String x:Key="Text.Running" xml:space="preserve">正在執行操作,請耐心等待...</x:String>
<x:String x:Key="Text.Save" xml:space="preserve">儲存</x:String>
<x:String x:Key="Text.SaveAs" xml:space="preserve">另存新檔...</x:String>
Expand Down
107 changes: 107 additions & 0 deletions src/ViewModels/Reword.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
using System;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;

namespace SourceGit.ViewModels
{
public class Reword : Popup
{
public Models.Commit Target
{
get;
}

public string Message
{
get;
}

public Reword(Repository repo, Models.Commit target, string message)
{
_repo = repo;
Target = target;
Message = message;
}

public override async Task<bool> Sure()
{
using var lockWatcher = _repo.LockWatcher();
ProgressDescription = $"Reword commit '{Target.SHA}' ...";

var log = _repo.CreateLog($"Reword '{Target.SHA}'");
Use(log);

var succ = Target.IsCurrentHead
? await RewordHeadAsync(log)
: await RewordWithRebaseAsync(log);

log.Complete();

if (succ)
{
// The rewritten commit sits at the same distance from HEAD as the original did,
// so re-select it once the history is reloaded instead of jumping back to the top.
var sha = await new Commands.QueryRevisionByRefName(_repo.FullPath, $"HEAD~{_distance}").GetResultAsync();
if (!string.IsNullOrEmpty(sha))
_repo.NavigateToCommit(sha, true);
}

_repo.MarkBranchesDirtyManually();
return true;
}

private async Task<bool> RewordHeadAsync(CommandLog log)
{
_distance = 0;
return await new Commands.Reword(_repo.FullPath, Message)
.Use(log)
.RunAsync();
}

private async Task<bool> RewordWithRebaseAsync(CommandLog log)
{
var onto = Target.Parents[0];
var commits = await new Commands.QueryCommitsForInteractiveRebase(_repo.FullPath, onto).GetResultAsync();

var collection = new Models.InteractiveRebaseJobCollection();
collection.OrigHead = _repo.CurrentBranch.Head;
collection.Onto = onto;

_distance = -1;
for (var i = commits.Count - 1; i >= 0; i--)
{
var c = commits[i];
var isTarget = c.Commit.SHA.Equals(Target.SHA, StringComparison.Ordinal);
if (isTarget)
_distance = i;

collection.Jobs.Add(new Models.InteractiveRebaseJob()
{
SHA = c.Commit.SHA,
Action = isTarget ? Models.InteractiveRebaseAction.Reword : Models.InteractiveRebaseAction.Pick,
Message = isTarget ? Message : c.Message,
});
}

if (_distance < 0)
{
_repo.SendNotification($"Commit '{Target.SHA}' is not reachable from HEAD!", true);
return false;
}

var jobsFile = Path.Combine(_repo.GitDir, "sourcegit.interactive_rebase");
await using (var stream = File.Create(jobsFile))
{
await JsonSerializer.SerializeAsync(stream, collection, JsonCodeGen.Default.InteractiveRebaseJobCollection);
}

return await new Commands.InteractiveRebase(_repo.FullPath, onto, true, false)
.Use(log)
.ExecAsync();
}

private readonly Repository _repo = null;
private int _distance = 0;
}
}
35 changes: 16 additions & 19 deletions src/Views/CommitMessageEditor.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@
x:Name="ThisControl"
Icon="/App.ico"
Title="{DynamicResource Text.CodeEditor}"
Width="800"
SizeToContent="Height"
CanResize="False"
Width="800" Height="520"
MinWidth="600" MinHeight="360"
WindowStartupLocation="CenterScreen">
<Grid RowDefinitions="Auto,*">
<Grid RowDefinitions="Auto,*,Auto">
<!-- TitleBar -->
<Grid Grid.Row="0" Height="28" IsVisible="{Binding !#ThisControl.UseSystemWindowFrame}">
<Border Background="{DynamicResource Brush.TitleBar}"
Expand All @@ -35,22 +34,20 @@
IsVisible="{OnPlatform True, macOS=False}"/>
</Grid>

<StackPanel Grid.Row="1" Orientation="Vertical" Margin="8">
<v:CommitMessageToolBox x:Name="Editor" Height="400"/>
<v:CommitMessageToolBox Grid.Row="1" x:Name="Editor" Margin="8,8,8,0"/>

<StackPanel Margin="0,8,0,4" Orientation="Horizontal" HorizontalAlignment="Center" Spacing="8">
<Button Classes="flat primary"
Width="80"
Content="{DynamicResource Text.Sure}"
Click="SaveAndClose"
HorizontalAlignment="Center"/>
<Button Classes="flat"
Width="80"
Content="{DynamicResource Text.Cancel}"
Click="CancelAndClose"
HotKey="Escape"
HorizontalAlignment="Center"/>
</StackPanel>
<StackPanel Grid.Row="2" Margin="8,8,8,12" Orientation="Horizontal" HorizontalAlignment="Center" Spacing="8">
<Button Classes="flat primary"
Width="80"
Content="{DynamicResource Text.Sure}"
Click="SaveAndClose"
HorizontalAlignment="Center"/>
<Button Classes="flat"
Width="80"
Content="{DynamicResource Text.Cancel}"
Click="CancelAndClose"
HotKey="Escape"
HorizontalAlignment="Center"/>
</StackPanel>
</Grid>
</v:ChromelessWindow>
24 changes: 24 additions & 0 deletions src/Views/Histories.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1312,7 +1312,31 @@ private ContextMenu CreateContextMenuForSingleCommit(ViewModels.Repository repo,
interactiveRebase.Items.Add(fixup);
interactiveRebase.Items.Add(drop);

var quickReword = new MenuItem();
quickReword.Header = App.Text("CommitCM.QuickReword");
quickReword.Icon = this.CreateMenuIcon("Icons.Rename");
quickReword.Click += async (_, e) =>
{
e.Handled = true;

if (!repo.CanCreatePopup() || TopLevel.GetTopLevel(this) is not Window owner)
return;

var message = await new Commands.QueryCommitFullMessage(repo.FullPath, commit.SHA).GetResultAsync();
var editor = new CommitMessageEditor();
editor.AsBuiltin(repo.Settings.ConventionalTypesOverride, message, msg =>
{
if (string.IsNullOrWhiteSpace(msg) || msg.Equals(message, StringComparison.Ordinal))
return;

if (repo.CanCreatePopup())
_ = repo.ShowAndStartPopupAsync(new ViewModels.Reword(repo, commit, msg));
});
await editor.ShowDialog(owner);
};

menu.Items.Add(new MenuItem() { Header = "-" });
menu.Items.Add(quickReword);
menu.Items.Add(interactiveRebase);
}
else
Expand Down
62 changes: 62 additions & 0 deletions src/Views/Reword.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<UserControl xmlns="https://github.com/avaloniaui"
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:vm="using:SourceGit.ViewModels"
xmlns:c="using:SourceGit.Converters"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
x:Class="SourceGit.Views.Reword"
x:DataType="vm:Reword">
<StackPanel Orientation="Vertical" Margin="8,0">
<StackPanel Orientation="Horizontal">
<Path Width="16" Height="16"
Data="{StaticResource Icons.Rename}"/>

<TextBlock FontSize="18"
Margin="8,0,0,0"
Classes="bold"
Text="{DynamicResource Text.Reword}"/>
</StackPanel>

<Grid Margin="0,16,0,0" RowDefinitions="32,Auto" ColumnDefinitions="130,*">
<TextBlock Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
Text="{DynamicResource Text.Reword.Commit}"/>

<Grid Grid.Row="0" Grid.Column="1" ColumnDefinitions="Auto,Auto,*">
<Path Grid.Column="0" Width="14" Height="14" Data="{StaticResource Icons.Commit}"/>
<TextBlock Grid.Column="1"
VerticalAlignment="Center"
Text="{Binding Target.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}"
FontFamily="{DynamicResource Fonts.Monospace}"
Foreground="DarkOrange"
Margin="8,0,0,0"/>
<TextBlock Grid.Column="2"
VerticalAlignment="Center"
Text="{Binding Target.Subject}"
Margin="4,0,0,0"
TextTrimming="CharacterEllipsis"/>
</Grid>

<TextBlock Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Top"
Margin="0,6,8,0"
Text="{DynamicResource Text.Reword.Message}"/>

<Border Grid.Row="1" Grid.Column="1"
MaxHeight="200"
Background="{DynamicResource Brush.Contents}"
BorderThickness="1"
BorderBrush="{DynamicResource Brush.Border2}"
CornerRadius="4">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<TextBlock Margin="6"
Text="{Binding Message}"
TextWrapping="Wrap"
FontFamily="{DynamicResource Fonts.Monospace}"/>
</ScrollViewer>
</Border>
</Grid>
</StackPanel>
</UserControl>
12 changes: 12 additions & 0 deletions src/Views/Reword.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Avalonia.Controls;

namespace SourceGit.Views
{
public partial class Reword : UserControl
{
public Reword()
{
InitializeComponent();
}
}
}