diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index bf7d660e..a299c320 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -53,7 +53,11 @@ Show as List Show as Tree Checkout Branch + Checkout Commit + Warning: By doing a commit checkout, your Head will be detached Branch : + Commit SHA : + Commit Short SHA : Local Changes : Stash & Reapply Discard @@ -73,6 +77,7 @@ CLOSE Cherry-Pick This Commit Copy SHA + Checkout commit${0} Rebase${0}$to Here Reset${0}$to Here Revert Commit diff --git a/src/SourceGit.csproj b/src/SourceGit.csproj index 657b49f3..0cc2f21e 100644 --- a/src/SourceGit.csproj +++ b/src/SourceGit.csproj @@ -44,4 +44,11 @@ + + + + CheckoutCommit.axaml + Code + + diff --git a/src/ViewModels/CheckoutCommit.cs b/src/ViewModels/CheckoutCommit.cs new file mode 100644 index 00000000..e27537ac --- /dev/null +++ b/src/ViewModels/CheckoutCommit.cs @@ -0,0 +1,87 @@ +using System.Threading.Tasks; + +namespace SourceGit.ViewModels +{ + public class CheckoutCommit: Popup + { + public string Commit + { + get; + private set; + } + + public bool HasLocalChanges + { + get => _repo.WorkingCopyChangesCount > 0; + } + + public bool AutoStash + { + get => _autoStash; + set => SetProperty(ref _autoStash, value); + } + + public CheckoutCommit(Repository repo, string commit) + { + _repo = repo; + Commit = commit; + View = new Views.CheckoutCommit() { DataContext = this }; + } + + public override Task Sure() + { + _repo.SetWatcherEnabled(false); + ProgressDescription = $"Checkout Commit '{Commit}' ..."; + + return Task.Run(() => + { + var needPopStash = false; + if (HasLocalChanges) + { + if (AutoStash) + { + SetProgressDescription("Adding untracked changes ..."); + var succ = new Commands.Add(_repo.FullPath).Exec(); + if (succ) + { + SetProgressDescription("Stash local changes ..."); + succ = new Commands.Stash(_repo.FullPath).Push("CHECKOUT_AUTO_STASH"); + } + + if (!succ) + { + CallUIThread(() => _repo.SetWatcherEnabled(true)); + return false; + } + + needPopStash = true; + } + else + { + SetProgressDescription("Discard local changes ..."); + Commands.Discard.All(_repo.FullPath); + } + } + + SetProgressDescription("Checkout commit ..."); + var rs = new Commands.Checkout(_repo.FullPath).Commit(Commit, SetProgressDescription); + + if (needPopStash) + { + SetProgressDescription("Re-apply local changes..."); + rs = new Commands.Stash(_repo.FullPath).Apply("stash@{0}"); + if (rs) + { + rs = new Commands.Stash(_repo.FullPath).Drop("stash@{0}"); + } + } + + CallUIThread(() => _repo.SetWatcherEnabled(true)); + return rs; + }); + } + + private readonly Repository _repo = null; + private bool _autoStash = true; + } +} diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs index 8cab66c1..3065bcb0 100644 --- a/src/ViewModels/Histories.cs +++ b/src/ViewModels/Histories.cs @@ -1,9 +1,11 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Globalization; using System.Threading.Tasks; using Avalonia.Controls; +using Avalonia.Data.Converters; using Avalonia.Platform.Storage; using Avalonia.Threading; @@ -234,6 +236,20 @@ namespace SourceGit.ViewModels e.Handled = true; }; menu.Items.Add(reset); + + var checkoutCommit = new MenuItem(); + + var shortSha = Converters.StringConverters.ToShortSHA + .Convert(commit.SHA, typeof(string), null, CultureInfo.CurrentCulture); + + checkoutCommit.Header = new Views.NameHighlightedTextBlock("CommitCM.Checkout", shortSha); + checkoutCommit.Icon = App.CreateMenuIcon("Icons.Check"); + checkoutCommit.Click += (o, e) => + { + _repo.CheckoutCommit(commit.SHA); + e.Handled = true; + }; + menu.Items.Add(checkoutCommit); } else { diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index a0f84a15..7f9592b8 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -722,6 +722,14 @@ namespace SourceGit.ViewModels PopupHost.ShowAndStartPopup(new Checkout(this, branch)); } + public void CheckoutCommit(string commit) + { + if (!PopupHost.CanCreatePopup()) + return; + + PopupHost.ShowPopup(new CheckoutCommit(this, commit)); + } + public void CreateNewTag() { var current = Branches.Find(x => x.IsCurrent); diff --git a/src/Views/CheckoutCommit.axaml b/src/Views/CheckoutCommit.axaml new file mode 100644 index 00000000..70bce62f --- /dev/null +++ b/src/Views/CheckoutCommit.axaml @@ -0,0 +1,45 @@ + + + + + + + + + + () + + + + + + + + + + + + + + diff --git a/src/Views/CheckoutCommit.axaml.cs b/src/Views/CheckoutCommit.axaml.cs new file mode 100644 index 00000000..f44fd6c7 --- /dev/null +++ b/src/Views/CheckoutCommit.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia.Controls; + +namespace SourceGit.Views +{ + public partial class CheckoutCommit : UserControl + { + public bool HasLocalChanges; + public CheckoutCommit() + { + InitializeComponent(); + } + } +}