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();
+ }
+ }
+}