mirror of
https://fastgit.cc/github.com/sourcegit-scm/sourcegit
synced 2026-04-21 13:20:30 +08:00
feature: add Reset File(s) to <revision> context menu entry to selected change(s) in revision compare view (#2079)
Co-authored-by: ybeapps <ybeapps@gmail.com> Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
@@ -95,6 +95,7 @@
|
||||
<x:String x:Key="Text.ChangeCM.GenerateCommitMessage" xml:space="preserve">Generate commit message</x:String>
|
||||
<x:String x:Key="Text.ChangeCM.Merge" xml:space="preserve">Merge (Built-in)</x:String>
|
||||
<x:String x:Key="Text.ChangeCM.MergeExternal" xml:space="preserve">Merge (External)</x:String>
|
||||
<x:String x:Key="Text.ChangeCM.ResetFileTo" xml:space="preserve">Reset File(s) to ${0}$</x:String>
|
||||
<x:String x:Key="Text.ChangeDisplayMode" xml:space="preserve">CHANGE DISPLAY MODE</x:String>
|
||||
<x:String x:Key="Text.ChangeDisplayMode.Grid" xml:space="preserve">Show as File and Dir List</x:String>
|
||||
<x:String x:Key="Text.ChangeDisplayMode.List" xml:space="preserve">Show as Path List</x:String>
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<x:String x:Key="Text.ChangeCM.GenerateCommitMessage" xml:space="preserve">生成提交信息</x:String>
|
||||
<x:String x:Key="Text.ChangeCM.Merge" xml:space="preserve">解决冲突(内部工具)</x:String>
|
||||
<x:String x:Key="Text.ChangeCM.MergeExternal" xml:space="preserve">解决冲突(外部工具)</x:String>
|
||||
<x:String x:Key="Text.ChangeCM.ResetFileTo" xml:space="preserve">重置文件到 ${0}$</x:String>
|
||||
<x:String x:Key="Text.ChangeDisplayMode" xml:space="preserve">切换变更显示模式</x:String>
|
||||
<x:String x:Key="Text.ChangeDisplayMode.Grid" xml:space="preserve">文件名+路径列表模式</x:String>
|
||||
<x:String x:Key="Text.ChangeDisplayMode.List" xml:space="preserve">全路径列表模式</x:String>
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<x:String x:Key="Text.ChangeCM.GenerateCommitMessage" xml:space="preserve">產生提交訊息</x:String>
|
||||
<x:String x:Key="Text.ChangeCM.Merge" xml:space="preserve">解決衝突 (內建工具)</x:String>
|
||||
<x:String x:Key="Text.ChangeCM.MergeExternal" xml:space="preserve">解決衝突 (外部工具)</x:String>
|
||||
<x:String x:Key="Text.ChangeCM.ResetFileTo" xml:space="preserve">重設檔案到 ${0}$</x:String>
|
||||
<x:String x:Key="Text.ChangeDisplayMode" xml:space="preserve">切換變更顯示模式</x:String>
|
||||
<x:String x:Key="Text.ChangeDisplayMode.Grid" xml:space="preserve">檔案名稱 + 路徑列表模式</x:String>
|
||||
<x:String x:Key="Text.ChangeDisplayMode.List" xml:space="preserve">全路徑列表模式</x:String>
|
||||
|
||||
@@ -206,7 +206,7 @@ namespace SourceGit.ViewModels
|
||||
|
||||
var end = commits[0] as Models.Commit;
|
||||
var start = commits[1] as Models.Commit;
|
||||
DetailContext = new RevisionCompare(_repo.FullPath, start, end);
|
||||
DetailContext = new RevisionCompare(_repo, start, end);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -403,7 +403,7 @@ namespace SourceGit.ViewModels
|
||||
_repo.SearchCommitContext.Selected = null;
|
||||
head = await new Commands.QuerySingleCommit(_repo.FullPath, "HEAD").GetResultAsync();
|
||||
if (head != null)
|
||||
DetailContext = new RevisionCompare(_repo.FullPath, commit, head);
|
||||
DetailContext = new RevisionCompare(_repo, commit, head);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -413,7 +413,7 @@ namespace SourceGit.ViewModels
|
||||
|
||||
public void CompareWithWorktree(Models.Commit commit)
|
||||
{
|
||||
DetailContext = new RevisionCompare(_repo.FullPath, commit, null);
|
||||
DetailContext = new RevisionCompare(_repo, commit, null);
|
||||
}
|
||||
|
||||
private Repository _repo = null;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Avalonia.Threading;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
@@ -26,7 +28,30 @@ namespace SourceGit.ViewModels
|
||||
private set => SetProperty(ref _endPoint, value);
|
||||
}
|
||||
|
||||
public bool CanSaveAsPatch { get; }
|
||||
public string LeftSideDesc
|
||||
{
|
||||
get => GetDesc(StartPoint);
|
||||
}
|
||||
|
||||
public string RightSideDesc
|
||||
{
|
||||
get => GetDesc(EndPoint);
|
||||
}
|
||||
|
||||
public bool CanResetToLeft
|
||||
{
|
||||
get => !_repo.IsBare && _startPoint != null;
|
||||
}
|
||||
|
||||
public bool CanResetToRight
|
||||
{
|
||||
get => !_repo.IsBare && _endPoint != null;
|
||||
}
|
||||
|
||||
public bool CanSaveAsPatch
|
||||
{
|
||||
get => _startPoint != null && _endPoint != null;
|
||||
}
|
||||
|
||||
public int TotalChanges
|
||||
{
|
||||
@@ -50,7 +75,7 @@ namespace SourceGit.ViewModels
|
||||
if (value is { Count: 1 })
|
||||
{
|
||||
var option = new Models.DiffOption(GetSHA(_startPoint), GetSHA(_endPoint), value[0]);
|
||||
DiffContext = new DiffContext(_repo, option, _diffContext);
|
||||
DiffContext = new DiffContext(_repo.FullPath, option, _diffContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -76,12 +101,11 @@ namespace SourceGit.ViewModels
|
||||
private set => SetProperty(ref _diffContext, value);
|
||||
}
|
||||
|
||||
public RevisionCompare(string repo, Models.Commit startPoint, Models.Commit endPoint)
|
||||
public RevisionCompare(Repository repo, Models.Commit startPoint, Models.Commit endPoint)
|
||||
{
|
||||
_repo = repo;
|
||||
_startPoint = (object)startPoint ?? new Models.Null();
|
||||
_endPoint = (object)endPoint ?? new Models.Null();
|
||||
CanSaveAsPatch = startPoint != null && endPoint != null;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
@@ -100,23 +124,12 @@ namespace SourceGit.ViewModels
|
||||
public void OpenChangeWithExternalDiffTool(Models.Change change)
|
||||
{
|
||||
var opt = new Models.DiffOption(GetSHA(_startPoint), GetSHA(_endPoint), change);
|
||||
new Commands.DiffTool(_repo, opt).Open();
|
||||
new Commands.DiffTool(_repo.FullPath, opt).Open();
|
||||
}
|
||||
|
||||
public void NavigateTo(string commitSHA)
|
||||
{
|
||||
var launcher = App.GetLauncher();
|
||||
if (launcher == null)
|
||||
return;
|
||||
|
||||
foreach (var page in launcher.Pages)
|
||||
{
|
||||
if (page.Data is Repository repo && repo.FullPath.Equals(_repo))
|
||||
{
|
||||
repo.NavigateToCommit(commitSHA);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_repo?.NavigateToCommit(commitSHA);
|
||||
}
|
||||
|
||||
public void Swap()
|
||||
@@ -130,14 +143,170 @@ namespace SourceGit.ViewModels
|
||||
|
||||
public string GetAbsPath(string path)
|
||||
{
|
||||
return Native.OS.GetAbsPath(_repo, path);
|
||||
return Native.OS.GetAbsPath(_repo.FullPath, path);
|
||||
}
|
||||
|
||||
public async Task ResetToLeftAsync(Models.Change change)
|
||||
{
|
||||
var sha = GetSHA(_startPoint);
|
||||
var log = _repo.CreateLog($"Reset File to '{GetDesc(_startPoint)}'");
|
||||
|
||||
if (change.Index == Models.ChangeState.Added)
|
||||
{
|
||||
var fullpath = Native.OS.GetAbsPath(_repo.FullPath, change.Path);
|
||||
if (File.Exists(fullpath))
|
||||
await new Commands.Remove(_repo.FullPath, [change.Path])
|
||||
.Use(log)
|
||||
.ExecAsync();
|
||||
}
|
||||
else if (change.Index == Models.ChangeState.Renamed)
|
||||
{
|
||||
var renamed = Native.OS.GetAbsPath(_repo.FullPath, change.Path);
|
||||
if (File.Exists(renamed))
|
||||
await new Commands.Remove(_repo.FullPath, [change.Path])
|
||||
.Use(log)
|
||||
.ExecAsync();
|
||||
|
||||
await new Commands.Checkout(_repo.FullPath)
|
||||
.Use(log)
|
||||
.FileWithRevisionAsync(change.OriginalPath, sha);
|
||||
}
|
||||
else
|
||||
{
|
||||
await new Commands.Checkout(_repo.FullPath)
|
||||
.Use(log)
|
||||
.FileWithRevisionAsync(change.Path, sha);
|
||||
}
|
||||
|
||||
log.Complete();
|
||||
}
|
||||
|
||||
public async Task ResetToRightAsync(Models.Change change)
|
||||
{
|
||||
var sha = GetSHA(_endPoint);
|
||||
var log = _repo.CreateLog($"Reset File to '{GetDesc(_endPoint)}'");
|
||||
|
||||
if (change.Index == Models.ChangeState.Deleted)
|
||||
{
|
||||
var fullpath = Native.OS.GetAbsPath(_repo.FullPath, change.Path);
|
||||
if (File.Exists(fullpath))
|
||||
await new Commands.Remove(_repo.FullPath, [change.Path])
|
||||
.Use(log)
|
||||
.ExecAsync();
|
||||
}
|
||||
else if (change.Index == Models.ChangeState.Renamed)
|
||||
{
|
||||
var old = Native.OS.GetAbsPath(_repo.FullPath, change.OriginalPath);
|
||||
if (File.Exists(old))
|
||||
await new Commands.Remove(_repo.FullPath, [change.OriginalPath])
|
||||
.Use(log)
|
||||
.ExecAsync();
|
||||
|
||||
await new Commands.Checkout(_repo.FullPath)
|
||||
.Use(log)
|
||||
.FileWithRevisionAsync(change.Path, sha);
|
||||
}
|
||||
else
|
||||
{
|
||||
await new Commands.Checkout(_repo.FullPath)
|
||||
.Use(log)
|
||||
.FileWithRevisionAsync(change.Path, sha);
|
||||
}
|
||||
|
||||
log.Complete();
|
||||
}
|
||||
|
||||
public async Task ResetMultipleToLeftAsync(List<Models.Change> changes)
|
||||
{
|
||||
var sha = GetSHA(_startPoint);
|
||||
var checkouts = new List<string>();
|
||||
var removes = new List<string>();
|
||||
|
||||
foreach (var c in changes)
|
||||
{
|
||||
if (c.Index == Models.ChangeState.Added)
|
||||
{
|
||||
var fullpath = Native.OS.GetAbsPath(_repo.FullPath, c.Path);
|
||||
if (File.Exists(fullpath))
|
||||
removes.Add(c.Path);
|
||||
}
|
||||
else if (c.Index == Models.ChangeState.Renamed)
|
||||
{
|
||||
var old = Native.OS.GetAbsPath(_repo.FullPath, c.Path);
|
||||
if (File.Exists(old))
|
||||
removes.Add(c.Path);
|
||||
|
||||
checkouts.Add(c.OriginalPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
checkouts.Add(c.Path);
|
||||
}
|
||||
}
|
||||
|
||||
var log = _repo.CreateLog($"Reset Files to '{GetDesc(_startPoint)}'");
|
||||
|
||||
if (removes.Count > 0)
|
||||
await new Commands.Remove(_repo.FullPath, removes)
|
||||
.Use(log)
|
||||
.ExecAsync();
|
||||
|
||||
if (checkouts.Count > 0)
|
||||
await new Commands.Checkout(_repo.FullPath)
|
||||
.Use(log)
|
||||
.MultipleFilesWithRevisionAsync(checkouts, sha);
|
||||
|
||||
log.Complete();
|
||||
}
|
||||
|
||||
public async Task ResetMultipleToRightAsync(List<Models.Change> changes)
|
||||
{
|
||||
var sha = GetSHA(_endPoint);
|
||||
var checkouts = new List<string>();
|
||||
var removes = new List<string>();
|
||||
|
||||
foreach (var c in changes)
|
||||
{
|
||||
if (c.Index == Models.ChangeState.Deleted)
|
||||
{
|
||||
var fullpath = Native.OS.GetAbsPath(_repo.FullPath, c.Path);
|
||||
if (File.Exists(fullpath))
|
||||
removes.Add(c.Path);
|
||||
}
|
||||
else if (c.Index == Models.ChangeState.Renamed)
|
||||
{
|
||||
var renamed = Native.OS.GetAbsPath(_repo.FullPath, c.OriginalPath);
|
||||
if (File.Exists(renamed))
|
||||
removes.Add(c.OriginalPath);
|
||||
|
||||
checkouts.Add(c.Path);
|
||||
}
|
||||
else
|
||||
{
|
||||
checkouts.Add(c.Path);
|
||||
}
|
||||
}
|
||||
|
||||
var log = _repo.CreateLog($"Reset Files to '{GetDesc(_endPoint)}'");
|
||||
|
||||
if (removes.Count > 0)
|
||||
await new Commands.Remove(_repo.FullPath, removes)
|
||||
.Use(log)
|
||||
.ExecAsync();
|
||||
|
||||
if (checkouts.Count > 0)
|
||||
await new Commands.Checkout(_repo.FullPath)
|
||||
.Use(log)
|
||||
.MultipleFilesWithRevisionAsync(checkouts, sha);
|
||||
|
||||
log.Complete();
|
||||
}
|
||||
|
||||
public async Task SaveChangesAsPatchAsync(List<Models.Change> changes, string saveTo)
|
||||
{
|
||||
var succ = await Commands.SaveChangesAsPatch.ProcessRevisionCompareChangesAsync(_repo, changes ?? _changes, GetSHA(_startPoint), GetSHA(_endPoint), saveTo);
|
||||
var succ = await Commands.SaveChangesAsPatch.ProcessRevisionCompareChangesAsync(_repo.FullPath, changes ?? _changes, GetSHA(_startPoint), GetSHA(_endPoint), saveTo);
|
||||
if (succ)
|
||||
App.SendNotification(_repo, App.Text("SaveAsPatchSuccess"));
|
||||
App.SendNotification(_repo.FullPath, App.Text("SaveAsPatchSuccess"));
|
||||
}
|
||||
|
||||
public void ClearSearchFilter()
|
||||
@@ -171,7 +340,7 @@ namespace SourceGit.ViewModels
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
_changes = await new Commands.CompareRevisions(_repo, GetSHA(_startPoint), GetSHA(_endPoint))
|
||||
_changes = await new Commands.CompareRevisions(_repo.FullPath, GetSHA(_startPoint), GetSHA(_endPoint))
|
||||
.ReadAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
@@ -205,7 +374,12 @@ namespace SourceGit.ViewModels
|
||||
return obj is Models.Commit commit ? commit.SHA : string.Empty;
|
||||
}
|
||||
|
||||
private string _repo;
|
||||
private string GetDesc(object obj)
|
||||
{
|
||||
return obj is Models.Commit commit ? commit.GetFriendlyName() : App.Text("Worktree");
|
||||
}
|
||||
|
||||
private Repository _repo;
|
||||
private bool _isLoading = true;
|
||||
private object _startPoint = null;
|
||||
private object _endPoint = null;
|
||||
|
||||
@@ -83,6 +83,26 @@ namespace SourceGit.Views
|
||||
menu.Items.Add(explore);
|
||||
}
|
||||
|
||||
var resetToLeft = new MenuItem();
|
||||
resetToLeft.Header = App.Text("ChangeCM.ResetFileTo", vm.LeftSideDesc);
|
||||
resetToLeft.Icon = App.CreateMenuIcon("Icons.File.Checkout");
|
||||
resetToLeft.IsEnabled = vm.CanResetToLeft;
|
||||
resetToLeft.Click += async (_, ev) =>
|
||||
{
|
||||
await vm.ResetToLeftAsync(change);
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
var resetToRight = new MenuItem();
|
||||
resetToRight.Header = App.Text("ChangeCM.ResetFileTo", vm.RightSideDesc);
|
||||
resetToRight.Icon = App.CreateMenuIcon("Icons.File.Checkout");
|
||||
resetToRight.IsEnabled = vm.CanResetToRight;
|
||||
resetToRight.Click += async (_, ev) =>
|
||||
{
|
||||
await vm.ResetToRightAsync(change);
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
var copyPath = new MenuItem();
|
||||
copyPath.Header = App.Text("CopyPath");
|
||||
copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
|
||||
@@ -106,11 +126,34 @@ namespace SourceGit.Views
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
menu.Items.Add(patch);
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
menu.Items.Add(resetToLeft);
|
||||
menu.Items.Add(resetToRight);
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
menu.Items.Add(copyPath);
|
||||
menu.Items.Add(copyFullPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
var resetToLeft = new MenuItem();
|
||||
resetToLeft.Header = App.Text("ChangeCM.ResetFileTo", vm.LeftSideDesc);
|
||||
resetToLeft.Icon = App.CreateMenuIcon("Icons.File.Checkout");
|
||||
resetToLeft.IsEnabled = vm.CanResetToLeft;
|
||||
resetToLeft.Click += async (_, ev) =>
|
||||
{
|
||||
await vm.ResetMultipleToLeftAsync(selected);
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
var resetToRight = new MenuItem();
|
||||
resetToRight.Header = App.Text("ChangeCM.ResetFileTo", vm.RightSideDesc);
|
||||
resetToRight.Icon = App.CreateMenuIcon("Icons.File.Checkout");
|
||||
resetToRight.IsEnabled = vm.CanResetToRight;
|
||||
resetToRight.Click += async (_, ev) =>
|
||||
{
|
||||
await vm.ResetMultipleToRightAsync(selected);
|
||||
ev.Handled = true;
|
||||
};
|
||||
|
||||
var copyPath = new MenuItem();
|
||||
copyPath.Header = App.Text("CopyPath");
|
||||
copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
|
||||
@@ -141,6 +184,9 @@ namespace SourceGit.Views
|
||||
|
||||
menu.Items.Add(patch);
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
menu.Items.Add(resetToLeft);
|
||||
menu.Items.Add(resetToRight);
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
menu.Items.Add(copyPath);
|
||||
menu.Items.Add(copyFullPath);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user