diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml
index afdff5da..ee035551 100644
--- a/src/Resources/Locales/en_US.axaml
+++ b/src/Resources/Locales/en_US.axaml
@@ -86,6 +86,8 @@
Stash & Reapply
Update all submodules
Branch:
+ Checkout & Fast-Forward
+ Fast-Forward to:
Cherry Pick
Append source to commit message
Commit(s):
diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml
index c7e57c97..2a117fb8 100644
--- a/src/Resources/Locales/zh_CN.axaml
+++ b/src/Resources/Locales/zh_CN.axaml
@@ -90,6 +90,8 @@
贮藏并自动恢复
同时更新所有子模块
目标分支 :
+ 检出分支并快进
+ 上游分支 :
挑选提交
提交信息中追加来源信息
提交列表 :
diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml
index 18a3b04e..29a5346d 100644
--- a/src/Resources/Locales/zh_TW.axaml
+++ b/src/Resources/Locales/zh_TW.axaml
@@ -90,6 +90,8 @@
擱置變更並自動復原
同時更新所有子模組
目標分支:
+ 簽出分支並快轉
+ 上游分支 :
揀選提交
提交資訊中追加來源資訊
提交列表:
diff --git a/src/ViewModels/CheckoutAndFastForward.cs b/src/ViewModels/CheckoutAndFastForward.cs
new file mode 100644
index 00000000..8e62a452
--- /dev/null
+++ b/src/ViewModels/CheckoutAndFastForward.cs
@@ -0,0 +1,111 @@
+using System.Threading.Tasks;
+
+namespace SourceGit.ViewModels
+{
+ public class CheckoutAndFastForward : Popup
+ {
+ public Models.Branch LocalBranch
+ {
+ get;
+ }
+
+ public Models.Branch RemoteBrach
+ {
+ get;
+ }
+
+ public bool DiscardLocalChanges
+ {
+ get;
+ set;
+ }
+
+ public bool IsRecurseSubmoduleVisible
+ {
+ get => _repo.Submodules.Count > 0;
+ }
+
+ public bool RecurseSubmodules
+ {
+ get => _repo.Settings.UpdateSubmodulesOnCheckoutBranch;
+ set => _repo.Settings.UpdateSubmodulesOnCheckoutBranch = value;
+ }
+
+ public CheckoutAndFastForward(Repository repo, Models.Branch localBranch, Models.Branch remoteBranch)
+ {
+ _repo = repo;
+ LocalBranch = localBranch;
+ RemoteBrach = remoteBranch;
+ }
+
+ public override Task Sure()
+ {
+ _repo.SetWatcherEnabled(false);
+ ProgressDescription = $"Checkout and Fast-Forward '{LocalBranch.Name}' ...";
+
+ var log = _repo.CreateLog($"Checkout and Fast-Forward '{LocalBranch.Name}' ...");
+ Use(log);
+
+ var updateSubmodules = IsRecurseSubmoduleVisible && RecurseSubmodules;
+ return Task.Run(() =>
+ {
+ var succ = false;
+ var needPopStash = false;
+
+ if (DiscardLocalChanges)
+ {
+ succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(LocalBranch.Name, RemoteBrach.Head, true, true);
+ }
+ else
+ {
+ var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result();
+ if (changes > 0)
+ {
+ succ = new Commands.Stash(_repo.FullPath).Use(log).Push("CHECKOUT_AND_FASTFORWARD_AUTO_STASH");
+ if (!succ)
+ {
+ log.Complete();
+ CallUIThread(() => _repo.SetWatcherEnabled(true));
+ return false;
+ }
+
+ needPopStash = true;
+ }
+
+ succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(LocalBranch.Name, RemoteBrach.Head, false, true);
+ }
+
+ if (succ)
+ {
+ if (updateSubmodules)
+ {
+ var submodules = new Commands.QueryUpdatableSubmodules(_repo.FullPath).Result();
+ if (submodules.Count > 0)
+ new Commands.Submodule(_repo.FullPath).Use(log).Update(submodules, true, true);
+ }
+
+ if (needPopStash)
+ new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}");
+ }
+
+ log.Complete();
+
+ CallUIThread(() =>
+ {
+ ProgressDescription = "Waiting for branch updated...";
+
+ if (_repo.HistoriesFilterMode == Models.FilterMode.Included)
+ _repo.SetBranchFilterMode(LocalBranch, Models.FilterMode.Included, true, false);
+
+ _repo.MarkBranchesDirtyManually();
+ _repo.SetWatcherEnabled(true);
+ });
+
+ Task.Delay(400).Wait();
+ return succ;
+ });
+ }
+
+ private Repository _repo;
+ }
+}
diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs
index 044d436e..43f060d7 100644
--- a/src/ViewModels/Histories.cs
+++ b/src/ViewModels/Histories.cs
@@ -236,11 +236,13 @@ namespace SourceGit.ViewModels
var remoteBranch = _repo.Branches.Find(x => x.FriendlyName == d.Name);
if (remoteBranch != null)
{
+ // If there's a local branch that is tracking on this remote branch and it does not ahead of
+ // its upstream, show `Create and Fast-Forward` popup.
var localBranch = _repo.Branches.Find(x => x.IsLocal && x.Upstream == remoteBranch.FullName);
- if (localBranch != null)
+ if (localBranch is { TrackStatus: { Ahead: { Count: 0 } } })
{
- if (!localBranch.IsCurrent)
- _repo.CheckoutBranch(localBranch);
+ if (_repo.CanCreatePopup())
+ _repo.ShowPopup(new CheckoutAndFastForward(_repo, localBranch, remoteBranch));
return;
}
}
diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs
index 43a67ff4..af72e72a 100644
--- a/src/ViewModels/Repository.cs
+++ b/src/ViewModels/Repository.cs
@@ -1316,7 +1316,7 @@ namespace SourceGit.ViewModels
{
if (branch.IsLocal)
{
- var worktree = _worktrees.Find(x => x.Branch == branch.FullName);
+ var worktree = _worktrees.Find(x => x.Branch.Equals(branch.FullName, StringComparison.Ordinal));
if (worktree != null)
{
OpenWorktree(worktree);
@@ -1341,9 +1341,13 @@ namespace SourceGit.ViewModels
{
foreach (var b in _branches)
{
- if (b.IsLocal && b.Upstream == branch.FullName)
+ if (b.IsLocal &&
+ b.Upstream.Equals(branch.FullName, StringComparison.Ordinal) &&
+ b.TrackStatus.Ahead.Count == 0)
{
- if (!b.IsCurrent)
+ if (b.TrackStatus.Behind.Count > 0)
+ ShowPopup(new CheckoutAndFastForward(this, b, branch));
+ else if (!b.IsCurrent)
CheckoutBranch(b);
return;
diff --git a/src/Views/CheckoutAndFastForward.axaml b/src/Views/CheckoutAndFastForward.axaml
new file mode 100644
index 00000000..725c081e
--- /dev/null
+++ b/src/Views/CheckoutAndFastForward.axaml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Views/CheckoutAndFastForward.axaml.cs b/src/Views/CheckoutAndFastForward.axaml.cs
new file mode 100644
index 00000000..c54f5a1f
--- /dev/null
+++ b/src/Views/CheckoutAndFastForward.axaml.cs
@@ -0,0 +1,12 @@
+using Avalonia.Controls;
+
+namespace SourceGit.Views
+{
+ public partial class CheckoutAndFastForward : UserControl
+ {
+ public CheckoutAndFastForward()
+ {
+ InitializeComponent();
+ }
+ }
+}