Skip to content

Commit 7d0536d

Browse files
committed
feature: when trying to checkout a local branch from its tracking upstream and it is behind the upstream, show Checkout & Fast-Forward popup
Signed-off-by: leo <[email protected]>
1 parent 6c04f53 commit 7d0536d

File tree

8 files changed

+203
-6
lines changed

8 files changed

+203
-6
lines changed

src/Resources/Locales/en_US.axaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@
8686
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Stash &amp; Reapply</x:String>
8787
<x:String x:Key="Text.Checkout.RecurseSubmodules" xml:space="preserve">Update all submodules</x:String>
8888
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">Branch:</x:String>
89+
<x:String x:Key="Text.Checkout.WithFastForward" xml:space="preserve">Checkout &amp; Fast-Forward</x:String>
90+
<x:String x:Key="Text.Checkout.WithFastForward.Upstream" xml:space="preserve">Fast-Forward to:</x:String>
8991
<x:String x:Key="Text.CherryPick" xml:space="preserve">Cherry Pick</x:String>
9092
<x:String x:Key="Text.CherryPick.AppendSourceToMessage" xml:space="preserve">Append source to commit message</x:String>
9193
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit(s):</x:String>

src/Resources/Locales/zh_CN.axaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@
9090
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">贮藏并自动恢复</x:String>
9191
<x:String x:Key="Text.Checkout.RecurseSubmodules" xml:space="preserve">同时更新所有子模块</x:String>
9292
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">目标分支 :</x:String>
93+
<x:String x:Key="Text.Checkout.WithFastForward" xml:space="preserve">检出分支并快进</x:String>
94+
<x:String x:Key="Text.Checkout.WithFastForward.Upstream" xml:space="preserve">上游分支 :</x:String>
9395
<x:String x:Key="Text.CherryPick" xml:space="preserve">挑选提交</x:String>
9496
<x:String x:Key="Text.CherryPick.AppendSourceToMessage" xml:space="preserve">提交信息中追加来源信息</x:String>
9597
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">提交列表 :</x:String>

src/Resources/Locales/zh_TW.axaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@
9090
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">擱置變更並自動復原</x:String>
9191
<x:String x:Key="Text.Checkout.RecurseSubmodules" xml:space="preserve">同時更新所有子模組</x:String>
9292
<x:String x:Key="Text.Checkout.Target" xml:space="preserve">目標分支:</x:String>
93+
<x:String x:Key="Text.Checkout.WithFastForward" xml:space="preserve">簽出分支並快轉</x:String>
94+
<x:String x:Key="Text.Checkout.WithFastForward.Upstream" xml:space="preserve">上游分支 :</x:String>
9395
<x:String x:Key="Text.CherryPick" xml:space="preserve">揀選提交</x:String>
9496
<x:String x:Key="Text.CherryPick.AppendSourceToMessage" xml:space="preserve">提交資訊中追加來源資訊</x:String>
9597
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">提交列表:</x:String>
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
using System.Threading.Tasks;
2+
3+
namespace SourceGit.ViewModels
4+
{
5+
public class CheckoutAndFastForward : Popup
6+
{
7+
public Models.Branch LocalBranch
8+
{
9+
get;
10+
}
11+
12+
public Models.Branch RemoteBrach
13+
{
14+
get;
15+
}
16+
17+
public bool DiscardLocalChanges
18+
{
19+
get;
20+
set;
21+
}
22+
23+
public bool IsRecurseSubmoduleVisible
24+
{
25+
get => _repo.Submodules.Count > 0;
26+
}
27+
28+
public bool RecurseSubmodules
29+
{
30+
get => _repo.Settings.UpdateSubmodulesOnCheckoutBranch;
31+
set => _repo.Settings.UpdateSubmodulesOnCheckoutBranch = value;
32+
}
33+
34+
public CheckoutAndFastForward(Repository repo, Models.Branch localBranch, Models.Branch remoteBranch)
35+
{
36+
_repo = repo;
37+
LocalBranch = localBranch;
38+
RemoteBrach = remoteBranch;
39+
}
40+
41+
public override Task<bool> Sure()
42+
{
43+
_repo.SetWatcherEnabled(false);
44+
ProgressDescription = $"Checkout and Fast-Forward '{LocalBranch.Name}' ...";
45+
46+
var log = _repo.CreateLog($"Checkout and Fast-Forward '{LocalBranch.Name}' ...");
47+
Use(log);
48+
49+
var updateSubmodules = IsRecurseSubmoduleVisible && RecurseSubmodules;
50+
return Task.Run(() =>
51+
{
52+
var succ = false;
53+
var needPopStash = false;
54+
55+
if (DiscardLocalChanges)
56+
{
57+
succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(LocalBranch.Name, RemoteBrach.Head, true, true);
58+
}
59+
else
60+
{
61+
var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result();
62+
if (changes > 0)
63+
{
64+
succ = new Commands.Stash(_repo.FullPath).Use(log).Push("CHECKOUT_AND_FASTFORWARD_AUTO_STASH");
65+
if (!succ)
66+
{
67+
log.Complete();
68+
CallUIThread(() => _repo.SetWatcherEnabled(true));
69+
return false;
70+
}
71+
72+
needPopStash = true;
73+
}
74+
75+
succ = new Commands.Checkout(_repo.FullPath).Use(log).Branch(LocalBranch.Name, RemoteBrach.Head, false, true);
76+
}
77+
78+
if (succ)
79+
{
80+
if (updateSubmodules)
81+
{
82+
var submodules = new Commands.QueryUpdatableSubmodules(_repo.FullPath).Result();
83+
if (submodules.Count > 0)
84+
new Commands.Submodule(_repo.FullPath).Use(log).Update(submodules, true, true);
85+
}
86+
87+
if (needPopStash)
88+
new Commands.Stash(_repo.FullPath).Use(log).Pop("stash@{0}");
89+
}
90+
91+
log.Complete();
92+
93+
CallUIThread(() =>
94+
{
95+
ProgressDescription = "Waiting for branch updated...";
96+
97+
if (_repo.HistoriesFilterMode == Models.FilterMode.Included)
98+
_repo.SetBranchFilterMode(LocalBranch, Models.FilterMode.Included, true, false);
99+
100+
_repo.MarkBranchesDirtyManually();
101+
_repo.SetWatcherEnabled(true);
102+
});
103+
104+
Task.Delay(400).Wait();
105+
return succ;
106+
});
107+
}
108+
109+
private Repository _repo;
110+
}
111+
}

src/ViewModels/Histories.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -236,11 +236,13 @@ public void DoubleTapped(Models.Commit commit)
236236
var remoteBranch = _repo.Branches.Find(x => x.FriendlyName == d.Name);
237237
if (remoteBranch != null)
238238
{
239+
// If there's a local branch that is tracking on this remote branch and it does not ahead of
240+
// its upstream, show `Create and Fast-Forward` popup.
239241
var localBranch = _repo.Branches.Find(x => x.IsLocal && x.Upstream == remoteBranch.FullName);
240-
if (localBranch != null)
242+
if (localBranch is { TrackStatus: { Ahead: { Count: 0 } } })
241243
{
242-
if (!localBranch.IsCurrent)
243-
_repo.CheckoutBranch(localBranch);
244+
if (_repo.CanCreatePopup())
245+
_repo.ShowPopup(new CheckoutAndFastForward(_repo, localBranch, remoteBranch));
244246
return;
245247
}
246248
}

src/ViewModels/Repository.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,7 +1316,7 @@ public void CheckoutBranch(Models.Branch branch)
13161316
{
13171317
if (branch.IsLocal)
13181318
{
1319-
var worktree = _worktrees.Find(x => x.Branch == branch.FullName);
1319+
var worktree = _worktrees.Find(x => x.Branch.Equals(branch.FullName, StringComparison.Ordinal));
13201320
if (worktree != null)
13211321
{
13221322
OpenWorktree(worktree);
@@ -1341,9 +1341,13 @@ public void CheckoutBranch(Models.Branch branch)
13411341
{
13421342
foreach (var b in _branches)
13431343
{
1344-
if (b.IsLocal && b.Upstream == branch.FullName)
1344+
if (b.IsLocal &&
1345+
b.Upstream.Equals(branch.FullName, StringComparison.Ordinal) &&
1346+
b.TrackStatus.Ahead.Count == 0)
13451347
{
1346-
if (!b.IsCurrent)
1348+
if (b.TrackStatus.Behind.Count > 0)
1349+
ShowPopup(new CheckoutAndFastForward(this, b, branch));
1350+
else if (!b.IsCurrent)
13471351
CheckoutBranch(b);
13481352

13491353
return;
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<UserControl xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5+
xmlns:m="using:SourceGit.Models"
6+
xmlns:vm="using:SourceGit.ViewModels"
7+
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
8+
x:Class="SourceGit.Views.CheckoutAndFastForward"
9+
x:DataType="vm:CheckoutAndFastForward">
10+
<StackPanel Orientation="Vertical" Margin="8,0">
11+
<TextBlock FontSize="18"
12+
Classes="bold"
13+
Text="{DynamicResource Text.Checkout.WithFastForward}"/>
14+
15+
<Grid Margin="0,16,0,0" ColumnDefinitions="140,*">
16+
<Grid.RowDefinitions>
17+
<RowDefinition Height="32"/>
18+
<RowDefinition Height="32"/>
19+
<RowDefinition Height="Auto" MinHeight="32"/>
20+
<RowDefinition Height="Auto"/>
21+
</Grid.RowDefinitions>
22+
23+
<TextBlock Grid.Row="0" Grid.Column="0"
24+
HorizontalAlignment="Right" VerticalAlignment="Center"
25+
Margin="0,0,8,0"
26+
Text="{DynamicResource Text.Checkout.Target}"/>
27+
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
28+
<Path Width="14" Height="14" Margin="4,0" Data="{StaticResource Icons.Branch}"/>
29+
<TextBlock Text="{Binding LocalBranch.Name}"/>
30+
</StackPanel>
31+
32+
<TextBlock Grid.Row="1" Grid.Column="0"
33+
HorizontalAlignment="Right" VerticalAlignment="Center"
34+
Margin="0,0,8,0"
35+
Text="{DynamicResource Text.Checkout.WithFastForward.Upstream}"/>
36+
<StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal">
37+
<Path Width="14" Height="14" Margin="4,0" Data="{StaticResource Icons.Branch}"/>
38+
<TextBlock Text="{Binding RemoteBrach.FriendlyName}"/>
39+
</StackPanel>
40+
41+
<TextBlock Grid.Row="2" Grid.Column="0"
42+
HorizontalAlignment="Right" VerticalAlignment="Center"
43+
Margin="0,0,8,0"
44+
Text="{DynamicResource Text.Checkout.LocalChanges}"/>
45+
<WrapPanel Grid.Row="2" Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center">
46+
<RadioButton GroupName="LocalChanges"
47+
Margin="0,0,8,0"
48+
Content="{DynamicResource Text.Checkout.LocalChanges.StashAndReply}"
49+
IsChecked="{Binding !DiscardLocalChanges, Mode=TwoWay}"/>
50+
<RadioButton GroupName="LocalChanges"
51+
Content="{DynamicResource Text.Checkout.LocalChanges.Discard}"/>
52+
</WrapPanel>
53+
54+
<CheckBox Grid.Row="3" Grid.Column="1"
55+
Height="32"
56+
Content="{DynamicResource Text.Checkout.RecurseSubmodules}"
57+
IsChecked="{Binding RecurseSubmodules, Mode=TwoWay}"
58+
IsVisible="{Binding IsRecurseSubmoduleVisible}"
59+
ToolTip.Tip="--recurse-submodules"/>
60+
</Grid>
61+
</StackPanel>
62+
</UserControl>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using Avalonia.Controls;
2+
3+
namespace SourceGit.Views
4+
{
5+
public partial class CheckoutAndFastForward : UserControl
6+
{
7+
public CheckoutAndFastForward()
8+
{
9+
InitializeComponent();
10+
}
11+
}
12+
}

0 commit comments

Comments
 (0)