mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-22 20:37:19 -08:00
refactor: ux for in progress action (cherry-pick/rebase/revert/merge)
This commit is contained in:
parent
814af539cd
commit
53bcafa5ed
7 changed files with 243 additions and 123 deletions
45
src/SourceGit/Resources/Locales.Designer.cs
generated
45
src/SourceGit/Resources/Locales.Designer.cs
generated
|
@ -942,15 +942,6 @@ namespace SourceGit.Resources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Conflict detected! Press 'Abort' to restore original HEAD..
|
||||
/// </summary>
|
||||
public static string Text_Conflict_Tip {
|
||||
get {
|
||||
return ResourceManager.GetString("Text.Conflict.Tip", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Copy.
|
||||
/// </summary>
|
||||
|
@ -2049,6 +2040,42 @@ namespace SourceGit.Resources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Cherry-Pick in progress. Press 'Abort' to restore original HEAD..
|
||||
/// </summary>
|
||||
public static string Text_InProgress_CherryPick {
|
||||
get {
|
||||
return ResourceManager.GetString("Text.InProgress.CherryPick", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Merge request in progress. Press 'Abort' to restore original HEAD..
|
||||
/// </summary>
|
||||
public static string Text_InProgress_Merge {
|
||||
get {
|
||||
return ResourceManager.GetString("Text.InProgress.Merge", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Rebase in progress. Press 'Abort' to restore original HEAD..
|
||||
/// </summary>
|
||||
public static string Text_InProgress_Rebase {
|
||||
get {
|
||||
return ResourceManager.GetString("Text.InProgress.Rebase", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Revert in progress. Press 'Abort' to restore original HEAD..
|
||||
/// </summary>
|
||||
public static string Text_InProgress_Revert {
|
||||
get {
|
||||
return ResourceManager.GetString("Text.InProgress.Revert", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Source Git.
|
||||
/// </summary>
|
||||
|
|
|
@ -1161,9 +1161,6 @@
|
|||
<data xml:space="preserve" name="Text.WorkingCopy.IncludeUntracked">
|
||||
<value>INCLUDE UNTRACKED FILES</value>
|
||||
</data>
|
||||
<data xml:space="preserve" name="Text.Conflict.Tip">
|
||||
<value>Conflict detected! Press 'Abort' to restore original HEAD.</value>
|
||||
</data>
|
||||
<data xml:space="preserve" name="Text.ClearStashes">
|
||||
<value>Clear Stashes</value>
|
||||
</data>
|
||||
|
@ -1338,4 +1335,16 @@
|
|||
<data name="Text.About.SourceCode" xml:space="preserve">
|
||||
<value>• Source code can be found at </value>
|
||||
</data>
|
||||
<data name="Text.InProgress.CherryPick" xml:space="preserve">
|
||||
<value>Cherry-Pick in progress. Press 'Abort' to restore original HEAD.</value>
|
||||
</data>
|
||||
<data name="Text.InProgress.Rebase" xml:space="preserve">
|
||||
<value>Rebase in progress. Press 'Abort' to restore original HEAD.</value>
|
||||
</data>
|
||||
<data name="Text.InProgress.Revert" xml:space="preserve">
|
||||
<value>Revert in progress. Press 'Abort' to restore original HEAD.</value>
|
||||
</data>
|
||||
<data name="Text.InProgress.Merge" xml:space="preserve">
|
||||
<value>Merge request in progress. Press 'Abort' to restore original HEAD.</value>
|
||||
</data>
|
||||
</root>
|
|
@ -1161,9 +1161,6 @@
|
|||
<data xml:space="preserve" name="Text.WorkingCopy.IncludeUntracked">
|
||||
<value>INCLUDE UNTRACKED FILES</value>
|
||||
</data>
|
||||
<data xml:space="preserve" name="Text.Conflict.Tip">
|
||||
<value>Conflict detected! Press 'Abort' to restore original HEAD.</value>
|
||||
</data>
|
||||
<data xml:space="preserve" name="Text.ClearStashes">
|
||||
<value>Clear Stashes</value>
|
||||
</data>
|
||||
|
@ -1338,4 +1335,16 @@
|
|||
<data name="Text.About.SourceCode" xml:space="preserve">
|
||||
<value>• Source code can be found at </value>
|
||||
</data>
|
||||
<data name="Text.InProgress.CherryPick" xml:space="preserve">
|
||||
<value>Cherry-Pick in progress. Press 'Abort' to restore original HEAD.</value>
|
||||
</data>
|
||||
<data name="Text.InProgress.Rebase" xml:space="preserve">
|
||||
<value>Rebase in progress. Press 'Abort' to restore original HEAD.</value>
|
||||
</data>
|
||||
<data name="Text.InProgress.Revert" xml:space="preserve">
|
||||
<value>Revert in progress. Press 'Abort' to restore original HEAD.</value>
|
||||
</data>
|
||||
<data name="Text.InProgress.Merge" xml:space="preserve">
|
||||
<value>Merge request in progress. Press 'Abort' to restore original HEAD.</value>
|
||||
</data>
|
||||
</root>
|
|
@ -1158,9 +1158,6 @@
|
|||
<data xml:space="preserve" name="Text.WorkingCopy.IncludeUntracked">
|
||||
<value>显示未跟踪文件</value>
|
||||
</data>
|
||||
<data xml:space="preserve" name="Text.Conflict.Tip">
|
||||
<value>检测到本地冲突! 点击【终止合并】回滚到合并操作前的状态。</value>
|
||||
</data>
|
||||
<data xml:space="preserve" name="Text.ClearStashes">
|
||||
<value>丢弃贮藏确认</value>
|
||||
</data>
|
||||
|
@ -1338,4 +1335,16 @@
|
|||
<data name="Text.Repository.Fleet" xml:space="preserve">
|
||||
<value>在 Fleet 中打开</value>
|
||||
</data>
|
||||
<data name="Text.InProgress.CherryPick" xml:space="preserve">
|
||||
<value>挑选(Cherry-Pick)操作进行中。点击【终止】回滚到操作前的状态。</value>
|
||||
</data>
|
||||
<data name="Text.InProgress.Rebase" xml:space="preserve">
|
||||
<value>变基(Rebase)操作进行中。点击【终止】回滚到操作前的状态。</value>
|
||||
</data>
|
||||
<data name="Text.InProgress.Revert" xml:space="preserve">
|
||||
<value>回滚提交操作进行中。点击【终止】回滚到操作前的状态。</value>
|
||||
</data>
|
||||
<data name="Text.InProgress.Merge" xml:space="preserve">
|
||||
<value>合并操作进行中。点击【终止】回滚到操作前的状态。</value>
|
||||
</data>
|
||||
</root>
|
89
src/SourceGit/ViewModels/InProgressContexts.cs
Normal file
89
src/SourceGit/ViewModels/InProgressContexts.cs
Normal file
|
@ -0,0 +1,89 @@
|
|||
using System.IO;
|
||||
|
||||
namespace SourceGit.ViewModels
|
||||
{
|
||||
public abstract class InProgressContext
|
||||
{
|
||||
public string Repository
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string Cmd
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public InProgressContext(string repo, string cmd)
|
||||
{
|
||||
Repository = repo;
|
||||
Cmd = cmd;
|
||||
}
|
||||
|
||||
public void Abort()
|
||||
{
|
||||
new Commands.Command()
|
||||
{
|
||||
WorkingDirectory = Repository,
|
||||
Context = Repository,
|
||||
Args = $"{Cmd} --abort",
|
||||
}.Exec();
|
||||
}
|
||||
|
||||
public virtual bool Continue()
|
||||
{
|
||||
return new Commands.Command()
|
||||
{
|
||||
WorkingDirectory = Repository,
|
||||
Context = Repository,
|
||||
Args = $"-c core.editor=true {Cmd} --continue",
|
||||
}.Exec();
|
||||
}
|
||||
}
|
||||
|
||||
public class CherryPickInProgress : InProgressContext
|
||||
{
|
||||
public CherryPickInProgress(string repo) : base(repo, "cherry-pick") { }
|
||||
}
|
||||
|
||||
public class RebaseInProgress : InProgressContext
|
||||
{
|
||||
public RebaseInProgress(Repository repo) : base(repo.FullPath, "rebase")
|
||||
{
|
||||
_gitDir = repo.GitDir;
|
||||
}
|
||||
|
||||
public override bool Continue()
|
||||
{
|
||||
var succ = base.Continue();
|
||||
if (succ)
|
||||
{
|
||||
var rebaseMergeHead = Path.Combine(_gitDir, "REBASE_HEAD");
|
||||
var rebaseMergeFolder = Path.Combine(_gitDir, "rebase-merge");
|
||||
var rebaseApplyFolder = Path.Combine(_gitDir, "rebase-apply");
|
||||
if (File.Exists(rebaseMergeHead))
|
||||
File.Delete(rebaseMergeHead);
|
||||
if (Directory.Exists(rebaseMergeFolder))
|
||||
Directory.Delete(rebaseMergeFolder);
|
||||
if (Directory.Exists(rebaseApplyFolder))
|
||||
Directory.Delete(rebaseApplyFolder);
|
||||
}
|
||||
|
||||
return succ;
|
||||
}
|
||||
|
||||
private string _gitDir;
|
||||
}
|
||||
|
||||
public class RevertInProgress : InProgressContext
|
||||
{
|
||||
public RevertInProgress(string repo) : base(repo, "revert") { }
|
||||
}
|
||||
|
||||
public class MergeInProgress : InProgressContext
|
||||
{
|
||||
public MergeInProgress(string repo) : base(repo, "merge") { }
|
||||
}
|
||||
}
|
|
@ -141,20 +141,6 @@ namespace SourceGit.ViewModels
|
|||
get => _stashesPage == null ? 0 : _stashesPage.Count;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsConflictBarVisible
|
||||
{
|
||||
get => _isConflictBarVisible;
|
||||
private set => SetProperty(ref _isConflictBarVisible, value);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool HasUnsolvedConflict
|
||||
{
|
||||
get => _hasUnsolvedConflict;
|
||||
private set => SetProperty(ref _hasUnsolvedConflict, value);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool CanCommitWithPush
|
||||
{
|
||||
|
@ -219,6 +205,20 @@ namespace SourceGit.ViewModels
|
|||
set => SetProperty(ref _isSubmoduleGroupExpanded, value);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public InProgressContext InProgressContext
|
||||
{
|
||||
get => _inProgressContext;
|
||||
private set => SetProperty(ref _inProgressContext, value);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool HasUnsolvedConflicts
|
||||
{
|
||||
get => _hasUnsolvedConflicts;
|
||||
private set => SetProperty(ref _hasUnsolvedConflicts, value);
|
||||
}
|
||||
|
||||
public void Open()
|
||||
{
|
||||
_watcher = new Models.Watcher(this);
|
||||
|
@ -227,8 +227,8 @@ namespace SourceGit.ViewModels
|
|||
_stashesPage = new StashesPage(this);
|
||||
_selectedView = _histories;
|
||||
_selectedViewIndex = 0;
|
||||
_isConflictBarVisible = false;
|
||||
_hasUnsolvedConflict = false;
|
||||
_inProgressContext = null;
|
||||
_hasUnsolvedConflicts = false;
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
|
@ -262,6 +262,9 @@ namespace SourceGit.ViewModels
|
|||
_isTagGroupExpanded = false;
|
||||
_isSubmoduleGroupExpanded = false;
|
||||
|
||||
_inProgressContext = null;
|
||||
_hasUnsolvedConflicts = false;
|
||||
|
||||
_remotes.Clear();
|
||||
_branches.Clear();
|
||||
_localBranchTrees.Clear();
|
||||
|
@ -450,90 +453,34 @@ namespace SourceGit.ViewModels
|
|||
|
||||
public async void ContinueMerge()
|
||||
{
|
||||
var cherryPickMerge = Path.Combine(_gitDir, "CHERRY_PICK_HEAD");
|
||||
var rebaseMerge = Path.Combine(_gitDir, "REBASE_HEAD");
|
||||
var rebaseMergeFolder = Path.Combine(_gitDir, "rebase-merge");
|
||||
var revertMerge = Path.Combine(_gitDir, "REVERT_HEAD");
|
||||
var otherMerge = Path.Combine(_gitDir, "MERGE_HEAD");
|
||||
|
||||
var mode = "";
|
||||
if (File.Exists(cherryPickMerge))
|
||||
if (_inProgressContext != null)
|
||||
{
|
||||
mode = "cherry-pick";
|
||||
}
|
||||
else if (File.Exists(rebaseMerge) && Directory.Exists(rebaseMergeFolder))
|
||||
{
|
||||
mode = "rebase";
|
||||
}
|
||||
else if (File.Exists(revertMerge))
|
||||
{
|
||||
mode = "revert";
|
||||
}
|
||||
else if (File.Exists(otherMerge))
|
||||
{
|
||||
mode = "merge";
|
||||
SetWatcherEnabled(false);
|
||||
var succ = await Task.Run(_inProgressContext.Continue);
|
||||
if (succ && _workingCopy != null)
|
||||
{
|
||||
_workingCopy.CommitMessage = string.Empty;
|
||||
}
|
||||
SetWatcherEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
MarkWorkingCopyDirtyManually();
|
||||
return;
|
||||
}
|
||||
|
||||
var cmd = new Commands.Command();
|
||||
cmd.WorkingDirectory = _fullpath;
|
||||
cmd.Context = _fullpath;
|
||||
cmd.Args = $"-c core.editor=true {mode} --continue";
|
||||
|
||||
SetWatcherEnabled(false);
|
||||
var succ = await Task.Run(cmd.Exec);
|
||||
SetWatcherEnabled(true);
|
||||
|
||||
if (succ)
|
||||
{
|
||||
if (_workingCopy != null)
|
||||
_workingCopy.CommitMessage = string.Empty;
|
||||
|
||||
if (mode == "rebase")
|
||||
{
|
||||
if (File.Exists(rebaseMerge))
|
||||
File.Delete(rebaseMerge);
|
||||
if (Directory.Exists(rebaseMergeFolder))
|
||||
Directory.Delete(rebaseMergeFolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async void AbortMerge()
|
||||
{
|
||||
var cmd = new Commands.Command();
|
||||
cmd.WorkingDirectory = _fullpath;
|
||||
cmd.Context = _fullpath;
|
||||
|
||||
if (File.Exists(Path.Combine(_gitDir, "CHERRY_PICK_HEAD")))
|
||||
if (_inProgressContext != null)
|
||||
{
|
||||
cmd.Args = "cherry-pick --abort";
|
||||
}
|
||||
else if (File.Exists(Path.Combine(_gitDir, "REBASE_HEAD")))
|
||||
{
|
||||
cmd.Args = "rebase --abort";
|
||||
}
|
||||
else if (File.Exists(Path.Combine(_gitDir, "REVERT_HEAD")))
|
||||
{
|
||||
cmd.Args = "revert --abort";
|
||||
}
|
||||
else if (File.Exists(Path.Combine(_gitDir, "MERGE_HEAD")))
|
||||
{
|
||||
cmd.Args = "merge --abort";
|
||||
SetWatcherEnabled(false);
|
||||
await Task.Run(_inProgressContext.Abort);
|
||||
SetWatcherEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
MarkWorkingCopyDirtyManually();
|
||||
return;
|
||||
}
|
||||
|
||||
SetWatcherEnabled(false);
|
||||
await Task.Run(cmd.Exec);
|
||||
SetWatcherEnabled(true);
|
||||
}
|
||||
|
||||
public void RefreshBranches()
|
||||
|
@ -622,30 +569,39 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
var changes = new Commands.QueryLocalChanges(FullPath, _includeUntracked).Result();
|
||||
var hasUnsolvedConflict = _workingCopy.SetData(changes);
|
||||
var inProgress = null as InProgressContext;
|
||||
|
||||
var cherryPickMerge = Path.Combine(_gitDir, "CHERRY_PICK_HEAD");
|
||||
var rebaseMerge = Path.Combine(_gitDir, "REBASE_HEAD");
|
||||
var rebaseMergeFolder = Path.Combine(_gitDir, "rebase-merge");
|
||||
var revertMerge = Path.Combine(_gitDir, "REVERT_HEAD");
|
||||
var otherMerge = Path.Combine(_gitDir, "MERGE_HEAD");
|
||||
var runningMerge = (File.Exists(cherryPickMerge) ||
|
||||
(File.Exists(rebaseMerge) && Directory.Exists(rebaseMergeFolder)) ||
|
||||
File.Exists(revertMerge) ||
|
||||
File.Exists(otherMerge));
|
||||
|
||||
if (!runningMerge)
|
||||
var rebaseApplyFolder = Path.Combine(_gitDir, "rebase-apply");
|
||||
if (File.Exists(Path.Combine(_gitDir, "CHERRY_PICK_HEAD")))
|
||||
{
|
||||
inProgress = new CherryPickInProgress(_fullpath);
|
||||
}
|
||||
else if (File.Exists(Path.Combine(_gitDir, "REBASE_HEAD")) && Directory.Exists(rebaseMergeFolder))
|
||||
{
|
||||
inProgress = new RebaseInProgress(this);
|
||||
}
|
||||
else if (File.Exists(Path.Combine(_gitDir, "REVERT_HEAD")))
|
||||
{
|
||||
inProgress = new RevertInProgress(_fullpath);
|
||||
}
|
||||
else if (File.Exists(Path.Combine(_gitDir, "MERGE_HEAD")))
|
||||
{
|
||||
inProgress = new MergeInProgress(_fullpath);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Directory.Exists(rebaseMergeFolder))
|
||||
Directory.Delete(rebaseMergeFolder, true);
|
||||
var applyFolder = Path.Combine(_gitDir, "rebase-apply");
|
||||
if (Directory.Exists(applyFolder))
|
||||
Directory.Delete(applyFolder, true);
|
||||
|
||||
if (Directory.Exists(rebaseApplyFolder))
|
||||
Directory.Delete(rebaseApplyFolder, true);
|
||||
}
|
||||
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
IsConflictBarVisible = runningMerge;
|
||||
HasUnsolvedConflict = hasUnsolvedConflict;
|
||||
InProgressContext = inProgress;
|
||||
HasUnsolvedConflicts = hasUnsolvedConflict;
|
||||
OnPropertyChanged(nameof(WorkingCopyChangesCount));
|
||||
});
|
||||
}
|
||||
|
@ -1359,9 +1315,10 @@ namespace SourceGit.ViewModels
|
|||
private List<Models.BranchTreeNode> _remoteBranchTrees = new List<Models.BranchTreeNode>();
|
||||
private List<Models.Tag> _tags = new List<Models.Tag>();
|
||||
private List<string> _submodules = new List<string>();
|
||||
private bool _isConflictBarVisible = false;
|
||||
private bool _hasUnsolvedConflict = false;
|
||||
private bool _canCommitWithPush = false;
|
||||
private bool _includeUntracked = true;
|
||||
|
||||
private InProgressContext _inProgressContext = null;
|
||||
private bool _hasUnsolvedConflicts = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -463,15 +463,35 @@
|
|||
BorderBrush="{DynamicResource Brush.Border0}"/>
|
||||
|
||||
<!-- Right -->
|
||||
<Grid Grid.Column="2" RowDefinitions="Auto,*">
|
||||
<Grid Height="26" Grid.Row="0" ColumnDefinitions="*,Auto,Auto,Auto" Background="{DynamicResource Brush.Conflict}" IsVisible="{Binding IsConflictBarVisible}">
|
||||
<TextBlock Grid.Column="0" Margin="8,0" FontWeight="Bold" Foreground="{DynamicResource Brush.FG3}" Text="{DynamicResource Text.Conflict.Tip}"/>
|
||||
<Grid Grid.Column="2" RowDefinitions="Auto,*">
|
||||
<Grid Grid.Row="0" Height="26" ColumnDefinitions="*,Auto,Auto,Auto" Background="{DynamicResource Brush.Conflict}" IsVisible="{Binding InProgressContext, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<ContentControl Grid.Column="0" Margin="8,0" Content="{Binding InProgressContext}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="vm:CherryPickInProgress">
|
||||
<TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.FG3}" Text="{DynamicResource Text.InProgress.CherryPick}"/>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="vm:RebaseInProgress">
|
||||
<TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.FG3}" Text="{DynamicResource Text.InProgress.Rebase}"/>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="vm:RevertInProgress">
|
||||
<TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.FG3}" Text="{DynamicResource Text.InProgress.Revert}"/>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="vm:MergeInProgress">
|
||||
<TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.FG3}" Text="{DynamicResource Text.InProgress.Merge}"/>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
|
||||
<Button Grid.Column="1" Classes="flat" FontWeight="Regular" Content="{DynamicResource Text.Repository.Resolve}" Height="20" Padding="8,0" Margin="4,0" Command="{Binding GotoResolve}">
|
||||
<Button.IsVisible>
|
||||
<Binding Path="SelectedViewIndex" Converter="{x:Static c:IntConverters.IsNotOne}"/>
|
||||
</Button.IsVisible>
|
||||
</Button>
|
||||
<Button Grid.Column="2" Classes="flat primary" FontWeight="Regular" Content="{DynamicResource Text.Repository.Continue}" Height="20" Padding="8,0" Margin="4,0" Command="{Binding ContinueMerge}" IsVisible="{Binding !HasUnsolvedConflict}"/>
|
||||
|
||||
<Button Grid.Column="2" Classes="flat primary" FontWeight="Regular" Content="{DynamicResource Text.Repository.Continue}" Height="20" Padding="8,0" Margin="4,0" Command="{Binding ContinueMerge}" IsVisible="{Binding !HasUnsolvedConflicts}"/>
|
||||
<Button Grid.Column="3" Classes="flat" FontWeight="Regular" Content="{DynamicResource Text.Repository.Abort}" Height="20" Padding="8,0" Margin="4,0" Command="{Binding AbortMerge}"/>
|
||||
</Grid>
|
||||
|
||||
|
|
Loading…
Reference in a new issue