Compare commits

...

7 commits

Author SHA1 Message Date
github-actions[bot]
0ac1031c4c doc: Update translation status and missing keys
Some checks failed
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions
Localization Check / localization-check (push) Has been cancelled
2024-12-12 02:03:49 +00:00
leo
2053ce033d
feature: supports merge selected commit to current branch (#800) 2024-12-12 10:03:34 +08:00
leo
e17b53da42
enhance: block-navigation in text diff view
* It is not necessary to re-calculate all the contents when `UseBlockNavigation` changed
* Redraw the text view after `block-navigation` has turned off
2024-12-12 09:44:55 +08:00
leo
9dd4166009
refactor: use MultiBinding instead of code to control visibility of Commit & Push button 2024-12-11 16:08:23 +08:00
leo
a10f9e0dd0
enhance: popup will be closed when cherry-pick or revert failed 2024-12-11 15:27:00 +08:00
leo
0dd6692cd8
enhance: supports --skip while reverting commits 2024-12-11 15:12:25 +08:00
leo
dcaeaef48a
refactor: re-design conflict panel 2024-12-11 11:33:20 +08:00
19 changed files with 366 additions and 189 deletions

View file

@ -47,7 +47,7 @@
## Translation Status ## Translation Status
[![en_US](https://img.shields.io/badge/en__US-100%25-brightgreen)](TRANSLATION.md) [![de__DE](https://img.shields.io/badge/de__DE-97.64%25-yellow)](TRANSLATION.md) [![es__ES](https://img.shields.io/badge/es__ES-97.91%25-yellow)](TRANSLATION.md) [![fr__FR](https://img.shields.io/badge/fr__FR-95.13%25-yellow)](TRANSLATION.md) [![it__IT](https://img.shields.io/badge/it__IT-95.69%25-yellow)](TRANSLATION.md) [![pt__BR](https://img.shields.io/badge/pt__BR-96.94%25-yellow)](TRANSLATION.md) [![ru__RU](https://img.shields.io/badge/ru__RU-98.05%25-yellow)](TRANSLATION.md) [![zh__CN](https://img.shields.io/badge/zh__CN-100.00%25-brightgreen)](TRANSLATION.md) [![zh__TW](https://img.shields.io/badge/zh__TW-100.00%25-brightgreen)](TRANSLATION.md) [![en_US](https://img.shields.io/badge/en__US-100%25-brightgreen)](TRANSLATION.md) [![de__DE](https://img.shields.io/badge/de__DE-97.50%25-yellow)](TRANSLATION.md) [![es__ES](https://img.shields.io/badge/es__ES-97.78%25-yellow)](TRANSLATION.md) [![fr__FR](https://img.shields.io/badge/fr__FR-95.00%25-yellow)](TRANSLATION.md) [![it__IT](https://img.shields.io/badge/it__IT-95.56%25-yellow)](TRANSLATION.md) [![pt__BR](https://img.shields.io/badge/pt__BR-96.81%25-yellow)](TRANSLATION.md) [![ru__RU](https://img.shields.io/badge/ru__RU-97.92%25-yellow)](TRANSLATION.md) [![zh__CN](https://img.shields.io/badge/zh__CN-100.00%25-brightgreen)](TRANSLATION.md) [![zh__TW](https://img.shields.io/badge/zh__TW-100.00%25-brightgreen)](TRANSLATION.md)
## How to Use ## How to Use

View file

@ -1,10 +1,11 @@
### de_DE.axaml: 97.64% ### de_DE.axaml: 97.50%
<details> <details>
<summary>Missing Keys</summary> <summary>Missing Keys</summary>
- Text.BranchCM.MergeMultiBranches - Text.BranchCM.MergeMultiBranches
- Text.CommitCM.Merge
- Text.CommitCM.MergeMultiple - Text.CommitCM.MergeMultiple
- Text.CommitDetail.Files.Search - Text.CommitDetail.Files.Search
- Text.Diff.UseBlockNavigation - Text.Diff.UseBlockNavigation
@ -24,13 +25,14 @@
</details> </details>
### es_ES.axaml: 97.91% ### es_ES.axaml: 97.78%
<details> <details>
<summary>Missing Keys</summary> <summary>Missing Keys</summary>
- Text.BranchCM.MergeMultiBranches - Text.BranchCM.MergeMultiBranches
- Text.CommitCM.Merge
- Text.CommitCM.MergeMultiple - Text.CommitCM.MergeMultiple
- Text.Diff.UseBlockNavigation - Text.Diff.UseBlockNavigation
- Text.FileCM.ResolveUsing - Text.FileCM.ResolveUsing
@ -48,7 +50,7 @@
</details> </details>
### fr_FR.axaml: 95.13% ### fr_FR.axaml: 95.00%
<details> <details>
@ -58,6 +60,7 @@
- Text.CherryPick.AppendSourceToMessage - Text.CherryPick.AppendSourceToMessage
- Text.CherryPick.Mainline.Tips - Text.CherryPick.Mainline.Tips
- Text.CommitCM.CherryPickMultiple - Text.CommitCM.CherryPickMultiple
- Text.CommitCM.Merge
- Text.CommitCM.MergeMultiple - Text.CommitCM.MergeMultiple
- Text.CommitDetail.Files.Search - Text.CommitDetail.Files.Search
- Text.Diff.UseBlockNavigation - Text.Diff.UseBlockNavigation
@ -92,13 +95,14 @@
</details> </details>
### it_IT.axaml: 95.69% ### it_IT.axaml: 95.56%
<details> <details>
<summary>Missing Keys</summary> <summary>Missing Keys</summary>
- Text.BranchCM.MergeMultiBranches - Text.BranchCM.MergeMultiBranches
- Text.CommitCM.Merge
- Text.CommitCM.MergeMultiple - Text.CommitCM.MergeMultiple
- Text.CommitDetail.Files.Search - Text.CommitDetail.Files.Search
- Text.CommitDetail.Info.Children - Text.CommitDetail.Info.Children
@ -132,13 +136,14 @@
</details> </details>
### pt_BR.axaml: 96.94% ### pt_BR.axaml: 96.81%
<details> <details>
<summary>Missing Keys</summary> <summary>Missing Keys</summary>
- Text.BranchCM.MergeMultiBranches - Text.BranchCM.MergeMultiBranches
- Text.CommitCM.Merge
- Text.CommitCM.MergeMultiple - Text.CommitCM.MergeMultiple
- Text.CommitDetail.Files.Search - Text.CommitDetail.Files.Search
- Text.CommitDetail.Info.Children - Text.CommitDetail.Info.Children
@ -163,13 +168,14 @@
</details> </details>
### ru_RU.axaml: 98.05% ### ru_RU.axaml: 97.92%
<details> <details>
<summary>Missing Keys</summary> <summary>Missing Keys</summary>
- Text.BranchCM.MergeMultiBranches - Text.BranchCM.MergeMultiBranches
- Text.CommitCM.Merge
- Text.CommitCM.MergeMultiple - Text.CommitCM.MergeMultiple
- Text.FileCM.ResolveUsing - Text.FileCM.ResolveUsing
- Text.Hotkeys.Global.Clone - Text.Hotkeys.Global.Clone

View file

@ -111,6 +111,7 @@
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">Copy SHA</x:String> <x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">Copy SHA</x:String>
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">Custom Action</x:String> <x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">Custom Action</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">Interactive Rebase ${0}$ to Here</x:String> <x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">Interactive Rebase ${0}$ to Here</x:String>
<x:String x:Key="Text.CommitCM.Merge" xml:space="preserve">Merge to ${0}$</x:String>
<x:String x:Key="Text.CommitCM.MergeMultiple" xml:space="preserve">Merge ...</x:String> <x:String x:Key="Text.CommitCM.MergeMultiple" xml:space="preserve">Merge ...</x:String>
<x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">Rebase ${0}$ to Here</x:String> <x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">Rebase ${0}$ to Here</x:String>
<x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">Reset ${0}$ to Here</x:String> <x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">Reset ${0}$ to Here</x:String>

View file

@ -114,6 +114,7 @@
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">复制提交指纹</x:String> <x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">复制提交指纹</x:String>
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">自定义操作</x:String> <x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">自定义操作</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">交互式变基(rebase -i) ${0}$ 到此处</x:String> <x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">交互式变基(rebase -i) ${0}$ 到此处</x:String>
<x:String x:Key="Text.CommitCM.Merge" xml:space="preserve">合并(merge)此提交至 ${0}$</x:String>
<x:String x:Key="Text.CommitCM.MergeMultiple" xml:space="preserve">合并(merge)...</x:String> <x:String x:Key="Text.CommitCM.MergeMultiple" xml:space="preserve">合并(merge)...</x:String>
<x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">变基(rebase) ${0}$ 到此处</x:String> <x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">变基(rebase) ${0}$ 到此处</x:String>
<x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">重置(reset) ${0}$ 到此处</x:String> <x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">重置(reset) ${0}$ 到此处</x:String>

View file

@ -114,6 +114,7 @@
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">複製提交編號</x:String> <x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">複製提交編號</x:String>
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">自訂動作</x:String> <x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">自訂動作</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">互動式重定基底 (rebase -i) ${0}$ 到此處</x:String> <x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">互動式重定基底 (rebase -i) ${0}$ 到此處</x:String>
<x:String x:Key="Text.CommitCM.Merge" xml:space="preserve">合併 (merge) 此提交到 ${0}$</x:String>
<x:String x:Key="Text.CommitCM.MergeMultiple" xml:space="preserve">合併 (merge)...</x:String> <x:String x:Key="Text.CommitCM.MergeMultiple" xml:space="preserve">合併 (merge)...</x:String>
<x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">重定基底 (rebase) ${0}$ 到此處</x:String> <x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">重定基底 (rebase) ${0}$ 到此處</x:String>
<x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">重設 (reset) ${0}$ 到此處</x:String> <x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">重設 (reset) ${0}$ 到此處</x:String>

View file

@ -72,10 +72,9 @@ namespace SourceGit.ViewModels
return Task.Run(() => return Task.Run(() =>
{ {
var succ = false;
if (IsMergeCommit) if (IsMergeCommit)
{ {
succ = new Commands.CherryPick( new Commands.CherryPick(
_repo.FullPath, _repo.FullPath,
Targets[0].SHA, Targets[0].SHA,
!AutoCommit, !AutoCommit,
@ -84,7 +83,7 @@ namespace SourceGit.ViewModels
} }
else else
{ {
succ = new Commands.CherryPick( new Commands.CherryPick(
_repo.FullPath, _repo.FullPath,
string.Join(' ', Targets.ConvertAll(c => c.SHA)), string.Join(' ', Targets.ConvertAll(c => c.SHA)),
!AutoCommit, !AutoCommit,
@ -93,7 +92,7 @@ namespace SourceGit.ViewModels
} }
CallUIThread(() => _repo.SetWatcherEnabled(true)); CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ; return true;
}); });
} }

View file

@ -0,0 +1,78 @@
namespace SourceGit.ViewModels
{
public class Conflict
{
public object Theirs
{
get;
private set;
}
public object Mine
{
get;
private set;
}
public bool IsResolved
{
get;
private set;
}
public Conflict(Repository repo, WorkingCopy wc, Models.Change change)
{
_wc = wc;
_change = change;
IsResolved = new Commands.IsConflictResolved(repo.FullPath, change).ReadToEnd().IsSuccess;
var context = wc.InProgressContext;
if (context is CherryPickInProgress cherryPick)
{
Theirs = cherryPick.Head;
Mine = repo.CurrentBranch;
}
else if (context is RebaseInProgress rebase)
{
Theirs = repo.Branches.Find(x => x.IsLocal && x.Name == rebase.HeadName) ??
new Models.Branch()
{
IsLocal = true,
Name = rebase.HeadName,
FullName = $"refs/heads/{rebase.HeadName}"
};
Mine = rebase.Onto;
}
else if (context is RevertInProgress revert)
{
Theirs = revert.Head;
Mine = repo.CurrentBranch;
}
else if (context is MergeInProgress merge)
{
Theirs = merge.Source;
Mine = repo.CurrentBranch;
}
}
public void UseTheirs()
{
_wc.UseTheirs([_change]);
}
public void UseMine()
{
_wc.UseMine([_change]);
}
public void OpenExternalMergeTool()
{
_wc.UseExternalMergeTool(_change);
}
private WorkingCopy _wc = null;
private Models.Change _change = null;
}
}

View file

@ -513,6 +513,21 @@ namespace SourceGit.ViewModels
e.Handled = true; e.Handled = true;
}; };
menu.Items.Add(cherryPick); menu.Items.Add(cherryPick);
if (!commit.HasDecorators)
{
var merge = new MenuItem();
merge.Header = new Views.NameHighlightedTextBlock("CommitCM.Merge", current.Name);
merge.Icon = App.CreateMenuIcon("Icons.Merge");
merge.Click += (_, e) =>
{
if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Merge(_repo, commit, current.Name));
e.Handled = true;
};
menu.Items.Add(merge);
}
} }
else else
{ {

View file

@ -4,51 +4,29 @@ namespace SourceGit.ViewModels
{ {
public abstract class InProgressContext public abstract class InProgressContext
{ {
public string Repository public InProgressContext(string repo, string cmd)
{ {
get; _repo = repo;
set; _cmd = cmd;
}
public string Cmd
{
get;
set;
}
public bool CanSkip
{
get;
protected set;
}
public InProgressContext(string repo, string cmd, bool canSkip)
{
Repository = repo;
Cmd = cmd;
CanSkip = canSkip;
} }
public bool Abort() public bool Abort()
{ {
return new Commands.Command() return new Commands.Command()
{ {
WorkingDirectory = Repository, WorkingDirectory = _repo,
Context = Repository, Context = _repo,
Args = $"{Cmd} --abort", Args = $"{_cmd} --abort",
}.Exec(); }.Exec();
} }
public bool Skip() public virtual bool Skip()
{ {
if (!CanSkip)
return true;
return new Commands.Command() return new Commands.Command()
{ {
WorkingDirectory = Repository, WorkingDirectory = _repo,
Context = Repository, Context = _repo,
Args = $"{Cmd} --skip", Args = $"{_cmd} --skip",
}.Exec(); }.Exec();
} }
@ -56,10 +34,10 @@ namespace SourceGit.ViewModels
{ {
return new Commands.Command() return new Commands.Command()
{ {
WorkingDirectory = Repository, WorkingDirectory = _repo,
Context = Repository, Context = _repo,
Editor = Commands.Command.EditorType.None, Editor = Commands.Command.EditorType.None,
Args = $"{Cmd} --continue", Args = $"{_cmd} --continue",
}.Exec(); }.Exec();
} }
@ -75,6 +53,9 @@ namespace SourceGit.ViewModels
return commit.SHA.Substring(0, 10); return commit.SHA.Substring(0, 10);
} }
protected string _repo = string.Empty;
protected string _cmd = string.Empty;
} }
public class CherryPickInProgress : InProgressContext public class CherryPickInProgress : InProgressContext
@ -90,7 +71,7 @@ namespace SourceGit.ViewModels
get => GetFriendlyNameOfCommit(Head); get => GetFriendlyNameOfCommit(Head);
} }
public CherryPickInProgress(Repository repo) : base(repo.FullPath, "cherry-pick", true) public CherryPickInProgress(Repository repo) : base(repo.FullPath, "cherry-pick")
{ {
var headSHA = File.ReadAllText(Path.Combine(repo.GitDir, "CHERRY_PICK_HEAD")).Trim(); var headSHA = File.ReadAllText(Path.Combine(repo.GitDir, "CHERRY_PICK_HEAD")).Trim();
Head = new Commands.QuerySingleCommit(repo.FullPath, headSHA).Result() ?? new Models.Commit() { SHA = headSHA }; Head = new Commands.QuerySingleCommit(repo.FullPath, headSHA).Result() ?? new Models.Commit() { SHA = headSHA };
@ -122,7 +103,7 @@ namespace SourceGit.ViewModels
private set; private set;
} }
public RebaseInProgress(Repository repo) : base(repo.FullPath, "rebase", true) public RebaseInProgress(Repository repo) : base(repo.FullPath, "rebase")
{ {
_gitDir = repo.GitDir; _gitDir = repo.GitDir;
@ -141,8 +122,8 @@ namespace SourceGit.ViewModels
{ {
var succ = new Commands.Command() var succ = new Commands.Command()
{ {
WorkingDirectory = Repository, WorkingDirectory = _repo,
Context = Repository, Context = _repo,
Editor = Commands.Command.EditorType.RebaseEditor, Editor = Commands.Command.EditorType.RebaseEditor,
Args = $"rebase --continue", Args = $"rebase --continue",
}.Exec(); }.Exec();
@ -177,7 +158,7 @@ namespace SourceGit.ViewModels
private set; private set;
} }
public RevertInProgress(Repository repo) : base(repo.FullPath, "revert", false) public RevertInProgress(Repository repo) : base(repo.FullPath, "revert")
{ {
var headSHA = File.ReadAllText(Path.Combine(repo.GitDir, "REVERT_HEAD")).Trim(); var headSHA = File.ReadAllText(Path.Combine(repo.GitDir, "REVERT_HEAD")).Trim();
Head = new Commands.QuerySingleCommit(repo.FullPath, headSHA).Result() ?? new Models.Commit() { SHA = headSHA }; Head = new Commands.QuerySingleCommit(repo.FullPath, headSHA).Result() ?? new Models.Commit() { SHA = headSHA };
@ -203,12 +184,17 @@ namespace SourceGit.ViewModels
get => GetFriendlyNameOfCommit(Source); get => GetFriendlyNameOfCommit(Source);
} }
public MergeInProgress(Repository repo) : base(repo.FullPath, "merge", false) public MergeInProgress(Repository repo) : base(repo.FullPath, "merge")
{ {
Current = Commands.Branch.ShowCurrent(repo.FullPath); Current = Commands.Branch.ShowCurrent(repo.FullPath);
var sourceSHA = File.ReadAllText(Path.Combine(repo.GitDir, "MERGE_HEAD")).Trim(); var sourceSHA = File.ReadAllText(Path.Combine(repo.GitDir, "MERGE_HEAD")).Trim();
Source = new Commands.QuerySingleCommit(repo.FullPath, sourceSHA).Result() ?? new Models.Commit() { SHA = sourceSHA }; Source = new Commands.QuerySingleCommit(repo.FullPath, sourceSHA).Result() ?? new Models.Commit() { SHA = sourceSHA };
} }
public override bool Skip()
{
return true;
}
} }
} }

View file

@ -32,6 +32,17 @@ namespace SourceGit.ViewModels
View = new Views.Merge() { DataContext = this }; View = new Views.Merge() { DataContext = this };
} }
public Merge(Repository repo, Models.Commit source, string into)
{
_repo = repo;
_sourceName = source.SHA;
Source = source;
Into = into;
SelectedMode = AutoSelectMergeMode();
View = new Views.Merge() { DataContext = this };
}
public Merge(Repository repo, Models.Tag source, string into) public Merge(Repository repo, Models.Tag source, string into)
{ {
_repo = repo; _repo = repo;

View file

@ -764,6 +764,11 @@ namespace SourceGit.ViewModels
_workingCopy?.StashAll(autoStart); _workingCopy?.StashAll(autoStart);
} }
public void SkipMerge()
{
_workingCopy?.SkipMerge();
}
public void AbortMerge() public void AbortMerge()
{ {
_workingCopy?.AbortMerge(); _workingCopy?.AbortMerge();

View file

@ -31,9 +31,9 @@ namespace SourceGit.ViewModels
return Task.Run(() => return Task.Run(() =>
{ {
var succ = new Commands.Revert(_repo.FullPath, Target.SHA, AutoCommit).Exec(); new Commands.Revert(_repo.FullPath, Target.SHA, AutoCommit).Exec();
CallUIThread(() => _repo.SetWatcherEnabled(true)); CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ; return true;
}); });
} }

View file

@ -11,26 +11,6 @@ using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels namespace SourceGit.ViewModels
{ {
public class ConflictContext : ObservableObject
{
public bool IsResolved
{
get => _isResolved;
set => SetProperty(ref _isResolved, value);
}
public ConflictContext(string repo, Models.Change change)
{
Task.Run(() =>
{
var result = new Commands.IsConflictResolved(repo, change).ReadToEnd().IsSuccess;
Dispatcher.UIThread.Post(() => IsResolved = result);
});
}
private bool _isResolved = false;
}
public class WorkingCopy : ObservableObject public class WorkingCopy : ObservableObject
{ {
public bool IncludeUntracked public bool IncludeUntracked
@ -49,11 +29,7 @@ namespace SourceGit.ViewModels
public bool CanCommitWithPush public bool CanCommitWithPush
{ {
get => _canCommitWithPush; get => _canCommitWithPush;
set set => SetProperty(ref _canCommitWithPush, value);
{
if (SetProperty(ref _canCommitWithPush, value))
OnPropertyChanged(nameof(IsCommitWithPushVisible));
}
} }
public bool HasUnsolvedConflicts public bool HasUnsolvedConflicts
@ -109,16 +85,10 @@ namespace SourceGit.ViewModels
Staged = GetStagedChanges(); Staged = GetStagedChanges();
SelectedStaged = []; SelectedStaged = [];
OnPropertyChanged(nameof(IsCommitWithPushVisible));
} }
} }
} }
public bool IsCommitWithPushVisible
{
get => !UseAmend && CanCommitWithPush;
}
public List<Models.Change> Unstaged public List<Models.Change> Unstaged
{ {
get => _unstaged; get => _unstaged;
@ -440,6 +410,54 @@ namespace SourceGit.ViewModels
} }
} }
public async void UseTheirs(List<Models.Change> changes)
{
var files = new List<string>();
foreach (var change in changes)
{
if (change.IsConflit)
files.Add(change.Path);
}
_repo.SetWatcherEnabled(false);
var succ = await Task.Run(() => new Commands.Checkout(_repo.FullPath).UseTheirs(files));
if (succ)
{
await Task.Run(() => new Commands.Add(_repo.FullPath, changes).Exec());
}
_repo.MarkWorkingCopyDirtyManually();
_repo.SetWatcherEnabled(true);
}
public async void UseMine(List<Models.Change> changes)
{
var files = new List<string>();
foreach (var change in changes)
{
if (change.IsConflit)
files.Add(change.Path);
}
_repo.SetWatcherEnabled(false);
var succ = await Task.Run(() => new Commands.Checkout(_repo.FullPath).UseMine(files));
if (succ)
{
await Task.Run(() => new Commands.Add(_repo.FullPath, changes).Exec());
}
_repo.MarkWorkingCopyDirtyManually();
_repo.SetWatcherEnabled(true);
}
public async void UseExternalMergeTool(Models.Change change)
{
var toolType = Preference.Instance.ExternalMergeToolType;
var toolPath = Preference.Instance.ExternalMergeToolPath;
_repo.SetWatcherEnabled(false);
await Task.Run(() => Commands.MergeTool.OpenForMerge(_repo.FullPath, toolType, toolPath, change.Path));
_repo.SetWatcherEnabled(true);
}
public void ContinueMerge() public void ContinueMerge()
{ {
if (_inProgressContext != null) if (_inProgressContext != null)
@ -463,6 +481,29 @@ namespace SourceGit.ViewModels
} }
} }
public void SkipMerge()
{
if (_inProgressContext != null)
{
_repo.SetWatcherEnabled(false);
Task.Run(() =>
{
var succ = _inProgressContext.Skip();
Dispatcher.UIThread.Invoke(() =>
{
if (succ)
CommitMessage = string.Empty;
_repo.SetWatcherEnabled(true);
});
});
}
else
{
_repo.MarkWorkingCopyDirtyManually();
}
}
public void AbortMerge() public void AbortMerge()
{ {
if (_inProgressContext != null) if (_inProgressContext != null)
@ -1438,59 +1479,11 @@ namespace SourceGit.ViewModels
if (change == null) if (change == null)
DetailContext = null; DetailContext = null;
else if (change.IsConflit && isUnstaged) else if (change.IsConflit && isUnstaged)
DetailContext = new ConflictContext(_repo.FullPath, change); DetailContext = new Conflict(_repo, this, change);
else else
DetailContext = new DiffContext(_repo.FullPath, new Models.DiffOption(change, isUnstaged), _detailContext as DiffContext); DetailContext = new DiffContext(_repo.FullPath, new Models.DiffOption(change, isUnstaged), _detailContext as DiffContext);
} }
private async void UseTheirs(List<Models.Change> changes)
{
var files = new List<string>();
foreach (var change in changes)
{
if (change.IsConflit)
files.Add(change.Path);
}
_repo.SetWatcherEnabled(false);
var succ = await Task.Run(() => new Commands.Checkout(_repo.FullPath).UseTheirs(files));
if (succ)
{
await Task.Run(() => new Commands.Add(_repo.FullPath, changes).Exec());
}
_repo.MarkWorkingCopyDirtyManually();
_repo.SetWatcherEnabled(true);
}
private async void UseMine(List<Models.Change> changes)
{
var files = new List<string>();
foreach (var change in changes)
{
if (change.IsConflit)
files.Add(change.Path);
}
_repo.SetWatcherEnabled(false);
var succ = await Task.Run(() => new Commands.Checkout(_repo.FullPath).UseMine(files));
if (succ)
{
await Task.Run(() => new Commands.Add(_repo.FullPath, changes).Exec());
}
_repo.MarkWorkingCopyDirtyManually();
_repo.SetWatcherEnabled(true);
}
private async void UseExternalMergeTool(Models.Change change)
{
var toolType = Preference.Instance.ExternalMergeToolType;
var toolPath = Preference.Instance.ExternalMergeToolPath;
_repo.SetWatcherEnabled(false);
await Task.Run(() => Commands.MergeTool.OpenForMerge(_repo.FullPath, toolType, toolPath, change.Path));
_repo.SetWatcherEnabled(true);
}
private void DoCommit(bool autoStage, bool autoPush, bool allowEmpty) private void DoCommit(bool autoStage, bool autoPush, bool allowEmpty)
{ {
if (!PopupHost.CanCreatePopup()) if (!PopupHost.CanCreatePopup())

View file

@ -77,7 +77,7 @@
HorizontalAlignment="Right" HorizontalAlignment="Right"
IsVisible="{Binding InProgress, Converter={x:Static BoolConverters.Not}}"> IsVisible="{Binding InProgress, Converter={x:Static BoolConverters.Not}}">
<Button Classes="flat primary" <Button Classes="flat primary"
Width="80" Height="28" Width="100" Height="28"
Padding="0" Padding="0"
HorizontalContentAlignment="Center" HorizontalContentAlignment="Center"
VerticalContentAlignment="Center" VerticalContentAlignment="Center"
@ -85,7 +85,7 @@
Click="OnPopupSure" Click="OnPopupSure"
HotKey="Enter"/> HotKey="Enter"/>
<Button Classes="flat" <Button Classes="flat"
Width="80" Height="28" Width="100" Height="28"
Margin="8,0,0,0" Margin="8,0,0,0"
Padding="0" Padding="0"
HorizontalContentAlignment="Center" HorizontalContentAlignment="Center"

View file

@ -4,6 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:m="using:SourceGit.Models" xmlns:m="using:SourceGit.Models"
xmlns:vm="using:SourceGit.ViewModels" xmlns:vm="using:SourceGit.ViewModels"
xmlns:c="using:SourceGit.Converters"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.Merge" x:Class="SourceGit.Views.Merge"
x:DataType="vm:Merge"> x:DataType="vm:Merge">
@ -11,7 +12,7 @@
<TextBlock FontSize="18" <TextBlock FontSize="18"
Classes="bold" Classes="bold"
Text="{DynamicResource Text.Merge}"/> Text="{DynamicResource Text.Merge}"/>
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32" ColumnDefinitions="150,*"> <Grid Margin="0,16,0,0" RowDefinitions="32,32,32" ColumnDefinitions="130,*">
<TextBlock Grid.Row="0" Grid.Column="0" <TextBlock Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center" HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0" Margin="0,0,8,0"
@ -25,6 +26,14 @@
</StackPanel> </StackPanel>
</DataTemplate> </DataTemplate>
<DataTemplate DataType="m:Commit">
<Grid ColumnDefinitions="Auto,Auto,*">
<Path Grid.Column="0" Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
<TextBlock Grid.Column="1" Classes="primary" VerticalAlignment="Center" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
<TextBlock Grid.Column="2" VerticalAlignment="Center" Text="{Binding Subject}" Margin="4,0,0,0" TextTrimming="CharacterEllipsis"/>
</Grid>
</DataTemplate>
<DataTemplate DataType="m:Tag"> <DataTemplate DataType="m:Tag">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<Path Width="14" Height="14" Data="{StaticResource Icons.Tag}"/> <Path Width="14" Height="14" Data="{StaticResource Icons.Tag}"/>

View file

@ -547,7 +547,7 @@
<!-- Right --> <!-- Right -->
<Grid Grid.Column="2" RowDefinitions="Auto,Auto,*"> <Grid Grid.Column="2" RowDefinitions="Auto,Auto,*">
<Grid Grid.Row="0" Height="28" ColumnDefinitions="*,Auto,Auto" Background="{DynamicResource Brush.Conflict}" IsVisible="{Binding InProgressContext, Converter={x:Static ObjectConverters.IsNotNull}}"> <Grid Grid.Row="0" Height="28" ColumnDefinitions="*,Auto" Background="{DynamicResource Brush.Conflict}" IsVisible="{Binding InProgressContext, Converter={x:Static ObjectConverters.IsNotNull}}">
<ContentControl Grid.Column="0" Margin="8,0" Content="{Binding InProgressContext}"> <ContentControl Grid.Column="0" Margin="8,0" Content="{Binding InProgressContext}">
<ContentControl.DataTemplates> <ContentControl.DataTemplates>
<DataTemplate DataType="m:Commit"> <DataTemplate DataType="m:Commit">
@ -563,27 +563,39 @@
</DataTemplate> </DataTemplate>
<DataTemplate DataType="vm:CherryPickInProgress"> <DataTemplate DataType="vm:CherryPickInProgress">
<StackPanel Orientation="Horizontal"> <Grid ColumnDefinitions="*,Auto">
<TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.CherryPick}"/> <StackPanel Grid.Column="0" Orientation="Horizontal">
<TextBlock FontWeight="Bold" Margin="4,0,0,0" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.CherryPick.Head}"/> <TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.CherryPick}"/>
<TextBlock FontWeight="Bold" Margin="4,0,0,0" Foreground="DarkOrange" Text="{Binding Head.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" ToolTip.Tip="{Binding Head}"/> <TextBlock FontWeight="Bold" Margin="4,0,0,0" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.CherryPick.Head}"/>
</StackPanel> <TextBlock FontWeight="Bold" Margin="4,0,0,0" Foreground="DarkOrange" Text="{Binding Head.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" ToolTip.Tip="{Binding Head}"/>
</StackPanel>
<Button Grid.Column="1" Classes="flat" FontWeight="Regular" BorderThickness="0" Content="{DynamicResource Text.Repository.Skip}" Padding="8,2" Click="OnSkipInProgress"/>
</Grid>
</DataTemplate> </DataTemplate>
<DataTemplate DataType="vm:RebaseInProgress"> <DataTemplate DataType="vm:RebaseInProgress">
<StackPanel Orientation="Horizontal"> <Grid ColumnDefinitions="*,Auto">
<TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.Rebase}"/> <StackPanel Grid.Column="0" Orientation="Horizontal">
<TextBlock FontWeight="Bold" Margin="4,0,0,0" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.Rebase.StoppedAt}"/> <TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.Rebase}"/>
<TextBlock FontWeight="Bold" Margin="4,0,0,0" Foreground="DarkOrange" Text="{Binding StoppedAt.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" ToolTip.Tip="{Binding StoppedAt}"/> <TextBlock FontWeight="Bold" Margin="4,0,0,0" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.Rebase.StoppedAt}"/>
</StackPanel> <TextBlock FontWeight="Bold" Margin="4,0,0,0" Foreground="DarkOrange" Text="{Binding StoppedAt.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" ToolTip.Tip="{Binding StoppedAt}"/>
</StackPanel>
<Button Grid.Column="1" Classes="flat" FontWeight="Regular" BorderThickness="0" Content="{DynamicResource Text.Repository.Skip}" Padding="8,2" Click="OnSkipInProgress"/>
</Grid>
</DataTemplate> </DataTemplate>
<DataTemplate DataType="vm:RevertInProgress"> <DataTemplate DataType="vm:RevertInProgress">
<StackPanel Orientation="Horizontal"> <Grid ColumnDefinitions="*,Auto">
<TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.Revert}"/> <StackPanel Grid.Column="0" Orientation="Horizontal">
<TextBlock FontWeight="Bold" Margin="4,0,0,0" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.Revert.Head}"/> <TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.Revert}"/>
<TextBlock FontWeight="Bold" Margin="4,0,0,0" Foreground="DarkOrange" Text="{Binding Head.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" ToolTip.Tip="{Binding Head}"/> <TextBlock FontWeight="Bold" Margin="4,0,0,0" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.Revert.Head}"/>
</StackPanel> <TextBlock FontWeight="Bold" Margin="4,0,0,0" Foreground="DarkOrange" Text="{Binding Head.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" ToolTip.Tip="{Binding Head}"/>
</StackPanel>
<Button Grid.Column="1" Classes="flat" FontWeight="Regular" BorderThickness="0" Content="{DynamicResource Text.Repository.Skip}" Padding="8,2" Click="OnSkipInProgress"/>
</Grid>
</DataTemplate> </DataTemplate>
<DataTemplate DataType="vm:MergeInProgress"> <DataTemplate DataType="vm:MergeInProgress">
@ -598,30 +610,12 @@
</ContentControl.DataTemplates> </ContentControl.DataTemplates>
</ContentControl> </ContentControl>
<ContentControl Grid.Column="1" Margin="4,0" Content="{Binding InProgressContext}"> <Button Grid.Column="1"
<ContentControl.DataTemplates>
<DataTemplate DataType="vm:CherryPickInProgress">
<Button Classes="flat" FontWeight="Regular" BorderThickness="0" Content="{DynamicResource Text.Repository.Skip}" Padding="8,2" Command="{Binding Skip}"/>
</DataTemplate>
<DataTemplate DataType="vm:RebaseInProgress">
<Button Classes="flat" FontWeight="Regular" BorderThickness="0" Content="{DynamicResource Text.Repository.Skip}" Padding="8,2" Command="{Binding Skip}"/>
</DataTemplate>
<DataTemplate DataType="vm:RevertInProgress">
</DataTemplate>
<DataTemplate DataType="vm:MergeInProgress">
</DataTemplate>
</ContentControl.DataTemplates>
</ContentControl>
<Button Grid.Column="2"
Classes="flat" Classes="flat"
FontWeight="Regular" FontWeight="Regular"
BorderThickness="0" BorderThickness="0"
Content="{DynamicResource Text.Repository.Abort}" Content="{DynamicResource Text.Repository.Abort}"
Padding="8,2" Margin="4,0" Padding="8,2" Margin="0,0,8,0"
Command="{Binding AbortMerge}"/> Command="{Binding AbortMerge}"/>
</Grid> </Grid>

View file

@ -428,5 +428,13 @@ namespace SourceGit.Views
e.Handled = true; e.Handled = true;
} }
private void OnSkipInProgress(object sender, RoutedEventArgs e)
{
if (DataContext is ViewModels.Repository repo)
repo.SkipMerge();
e.Handled = true;
}
} }
} }

View file

@ -719,19 +719,22 @@ namespace SourceGit.Views
else if (change.Property == BlockNavigationProperty) else if (change.Property == BlockNavigationProperty)
{ {
var oldValue = change.OldValue as ViewModels.BlockNavigation; var oldValue = change.OldValue as ViewModels.BlockNavigation;
var newValue = change.NewValue as ViewModels.BlockNavigation;
if (oldValue != null) if (oldValue != null)
{
oldValue.PropertyChanged -= OnBlockNavigationPropertyChanged; oldValue.PropertyChanged -= OnBlockNavigationPropertyChanged;
if (oldValue.Current != -1)
TextArea?.TextView?.Redraw();
}
var newValue = change.NewValue as ViewModels.BlockNavigation;
if (newValue != null) if (newValue != null)
newValue.PropertyChanged += OnBlockNavigationPropertyChanged; newValue.PropertyChanged += OnBlockNavigationPropertyChanged;
InvalidateVisual();
} }
} }
private void OnBlockNavigationPropertyChanged(object _1, PropertyChangedEventArgs _2) private void OnBlockNavigationPropertyChanged(object _1, PropertyChangedEventArgs _2)
{ {
TextArea.TextView.Redraw(); TextArea?.TextView?.Redraw();
} }
private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e) private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e)
@ -1576,7 +1579,7 @@ namespace SourceGit.Views
UseBlockNavigationProperty.Changed.AddClassHandler<TextDiffView>((v, _) => UseBlockNavigationProperty.Changed.AddClassHandler<TextDiffView>((v, _) =>
{ {
v.RefreshContent(v.DataContext as Models.TextDiff, false); v.RefreshBlockNavigation();
}); });
SelectedChunkProperty.Changed.AddClassHandler<TextDiffView>((v, _) => SelectedChunkProperty.Changed.AddClassHandler<TextDiffView>((v, _) =>
@ -1664,6 +1667,14 @@ namespace SourceGit.Views
Editor.Content = diff; Editor.Content = diff;
} }
RefreshBlockNavigation();
IsUnstagedChange = diff.Option.IsUnstaged;
EnableChunkSelection = diff.Option.WorkingCopyChange != null;
}
private void RefreshBlockNavigation()
{
if (UseBlockNavigation) if (UseBlockNavigation)
{ {
BlockNavigation = new ViewModels.BlockNavigation(Editor.Content); BlockNavigation = new ViewModels.BlockNavigation(Editor.Content);
@ -1674,9 +1685,6 @@ namespace SourceGit.Views
BlockNavigation = null; BlockNavigation = null;
BlockNavigationIndicator = "-/-"; BlockNavigationIndicator = "-/-";
} }
IsUnstagedChange = diff.Option.IsUnstaged;
EnableChunkSelection = diff.Option.WorkingCopyChange != null;
} }
private void OnStageChunk(object _1, RoutedEventArgs _2) private void OnStageChunk(object _1, RoutedEventArgs _2)

View file

@ -2,6 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:m="using:SourceGit.Models"
xmlns:vm="using:SourceGit.ViewModels" xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views" xmlns:v="using:SourceGit.Views"
xmlns:c="using:SourceGit.Converters" xmlns:c="using:SourceGit.Converters"
@ -169,13 +170,67 @@
<ContentControl Content="{Binding DetailContext}"> <ContentControl Content="{Binding DetailContext}">
<ContentControl.DataTemplates> <ContentControl.DataTemplates>
<DataTemplate DataType="vm:ConflictContext"> <DataTemplate DataType="vm:Conflict">
<Border Background="{DynamicResource Brush.Window}" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}"> <Border Background="{DynamicResource Brush.Window}" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center"> <Grid VerticalAlignment="Center">
<StackPanel Orientation="Vertical" IsVisible="{Binding !IsResolved}"> <StackPanel Orientation="Vertical" IsVisible="{Binding !IsResolved}">
<Path Width="64" Height="64" Data="{StaticResource Icons.Conflict}" Fill="{DynamicResource Brush.FG2}"/> <StackPanel.DataTemplates>
<TextBlock Margin="0,16,0,8" FontSize="20" FontWeight="Bold" Text="{DynamicResource Text.WorkingCopy.Conflicts}" Foreground="{DynamicResource Brush.FG2}" HorizontalAlignment="Center"/> <DataTemplate DataType="m:Branch">
<TextBlock Text="{DynamicResource Text.WorkingCopy.ResolveTip}" Foreground="{DynamicResource Brush.FG2}" HorizontalAlignment="Center"/> <StackPanel Orientation="Horizontal">
<Path Width="12" Height="12" Data="{StaticResource Icons.Branch}"/>
<TextBlock Margin="4,0,0,0" Text="{Binding FriendlyName}"/>
<TextBlock Margin="4,0,0,0" Text="{Binding Head, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="m:Commit">
<StackPanel Orientation="Horizontal">
<Path Width="12" Height="12" Margin="0,6,0,0" Data="{StaticResource Icons.Commit}"/>
<v:CommitRefsPresenter Margin="8,0,0,0"
TagBackground="{DynamicResource Brush.DecoratorTag}"
Foreground="{DynamicResource Brush.FG1}"
FontFamily="{DynamicResource Fonts.Primary}"
FontSize="11"
VerticalAlignment="Center"
UseGraphColor="False"/>
<TextBlock Margin="4,0,0,0" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange"/>
<TextBlock Margin="4,0,0,0" Text="{Binding Subject}"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="m:Tag">
<StackPanel Orientation="Horizontal">
<Path Width="12" Height="12" Data="{StaticResource Icons.Tag}"/>
<TextBlock Margin="4,0,0,0" Text="{Binding Name}"/>
<TextBlock Margin="4,0,0,0" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange"/>
</StackPanel>
</DataTemplate>
</StackPanel.DataTemplates>
<Path Width="64" Height="64" Data="{StaticResource Icons.Conflict}" Fill="{DynamicResource Brush.FG2}" HorizontalAlignment="Center"/>
<TextBlock Margin="0,16" FontSize="20" FontWeight="Bold" Text="{DynamicResource Text.WorkingCopy.Conflicts}" Foreground="{DynamicResource Brush.FG2}" HorizontalAlignment="Center"/>
<Border Margin="16,0" Padding="8" CornerRadius="4" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}">
<Border.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.And}">
<Binding Path="Theirs" Converter="{x:Static ObjectConverters.IsNotNull}"/>
<Binding Path="Mine" Converter="{x:Static ObjectConverters.IsNotNull}"/>
</MultiBinding>
</Border.IsVisible>
<Grid Margin="8,0,0,0" RowDefinitions="32,32" ColumnDefinitions="Auto,*">
<TextBlock Grid.Row="0" Grid.Column="0" Classes="info_label" Text="THEIRS"/>
<ContentControl Grid.Row="0" Grid.Column="1" Margin="16,0,0,0" Content="{Binding Theirs}"/>
<TextBlock Grid.Row="1" Grid.Column="0" Classes="info_label" Text="MINE"/>
<ContentControl Grid.Row="1" Grid.Column="1" Margin="16,0,0,0" Content="{Binding Mine}"/>
</Grid>
</Border>
<StackPanel Margin="0,8,0,0" Orientation="Horizontal" HorizontalAlignment="Center">
<Button Classes="flat" Content="USE THEIRS" Command="{Binding UseTheirs}"/>
<Button Classes="flat" Margin="8,0,0,0" Content="USE MINE" Command="{Binding UseMine}"/>
<Button Classes="flat" Margin="8,0,0,0" Content="OPEN EXTERNAL MERGETOOL" Command="{Binding OpenExternalMergeTool}"/>
</StackPanel>
</StackPanel> </StackPanel>
<StackPanel Orientation="Vertical" IsVisible="{Binding IsResolved}"> <StackPanel Orientation="Vertical" IsVisible="{Binding IsResolved}">
@ -300,8 +355,15 @@
HotKey="Alt+Enter" HotKey="Alt+Enter"
ToolTip.Tip="{OnPlatform Alt+Enter, macOS=⌥+Enter}" ToolTip.Tip="{OnPlatform Alt+Enter, macOS=⌥+Enter}"
ToolTip.Placement="Top" ToolTip.Placement="Top"
ToolTip.VerticalOffset="0" ToolTip.VerticalOffset="0">
IsVisible="{Binding IsCommitWithPushVisible}"/> <Button.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.And}">
<Binding Path="UseAmend" Converter="{x:Static BoolConverters.Not}"/>
<Binding Path="CanCommitWithPush"/>
<Binding Path="InProgressContext" Converter="{x:Static ObjectConverters.IsNull}"/>
</MultiBinding>
</Button.IsVisible>
</Button>
</Grid> </Grid>
</Grid> </Grid>
</Grid> </Grid>