mirror of
https://fastgit.cc/github.com/sourcegit-scm/sourcegit
synced 2026-04-24 02:40:24 +08:00
refactor: merge BranchTrackStatus to Branch
Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
@@ -26,15 +26,16 @@ namespace SourceGit.Commands
|
||||
return branches;
|
||||
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
var remoteHeads = new Dictionary<string, string>();
|
||||
var mismatched = new HashSet<string>();
|
||||
var remotes = new Dictionary<string, Models.Branch>();
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var b = ParseLine(line);
|
||||
var b = ParseLine(line, mismatched);
|
||||
if (b != null)
|
||||
{
|
||||
branches.Add(b);
|
||||
if (!b.IsLocal)
|
||||
remoteHeads.Add(b.FullName, b.Head);
|
||||
remotes.Add(b.FullName, b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,15 +43,16 @@ namespace SourceGit.Commands
|
||||
{
|
||||
if (b.IsLocal && !string.IsNullOrEmpty(b.Upstream))
|
||||
{
|
||||
if (remoteHeads.TryGetValue(b.Upstream, out var upstreamHead))
|
||||
if (remotes.TryGetValue(b.Upstream, out var upstream))
|
||||
{
|
||||
b.IsUpstreamGone = false;
|
||||
b.TrackStatus ??= await new QueryTrackStatus(WorkingDirectory, b.Head, upstreamHead).GetResultAsync().ConfigureAwait(false);
|
||||
|
||||
if (mismatched.Contains(b.FullName))
|
||||
await new QueryTrackStatus(WorkingDirectory).GetResultAsync(b, upstream).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
b.IsUpstreamGone = true;
|
||||
b.TrackStatus ??= new Models.BranchTrackStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,7 +60,7 @@ namespace SourceGit.Commands
|
||||
return branches;
|
||||
}
|
||||
|
||||
private Models.Branch ParseLine(string line)
|
||||
private Models.Branch ParseLine(string line, HashSet<string> mismatched)
|
||||
{
|
||||
var parts = line.Split('\0');
|
||||
if (parts.Length != 7)
|
||||
@@ -103,11 +105,11 @@ namespace SourceGit.Commands
|
||||
branch.Upstream = parts[4];
|
||||
branch.IsUpstreamGone = false;
|
||||
|
||||
if (!branch.IsLocal ||
|
||||
string.IsNullOrEmpty(branch.Upstream) ||
|
||||
string.IsNullOrEmpty(parts[5]) ||
|
||||
parts[5].Equals("=", StringComparison.Ordinal))
|
||||
branch.TrackStatus = new Models.BranchTrackStatus();
|
||||
if (branch.IsLocal &&
|
||||
!string.IsNullOrEmpty(branch.Upstream) &&
|
||||
!string.IsNullOrEmpty(parts[5]) &&
|
||||
!parts[5].Equals("=", StringComparison.Ordinal))
|
||||
mismatched.Add(branch.FullName);
|
||||
|
||||
branch.WorktreePath = parts[6];
|
||||
return branch;
|
||||
|
||||
@@ -5,31 +5,28 @@ namespace SourceGit.Commands
|
||||
{
|
||||
public class QueryTrackStatus : Command
|
||||
{
|
||||
public QueryTrackStatus(string repo, string local, string upstream)
|
||||
public QueryTrackStatus(string repo)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"rev-list --left-right {local}...{upstream}";
|
||||
}
|
||||
|
||||
public async Task<Models.BranchTrackStatus> GetResultAsync()
|
||||
public async Task GetResultAsync(Models.Branch local, Models.Branch remote)
|
||||
{
|
||||
var status = new Models.BranchTrackStatus();
|
||||
Args = $"rev-list --left-right {local.Head}...{remote.Head}";
|
||||
|
||||
var rs = await ReadToEndAsync().ConfigureAwait(false);
|
||||
if (!rs.IsSuccess)
|
||||
return status;
|
||||
return;
|
||||
|
||||
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (line[0] == '>')
|
||||
status.Behind.Add(line.Substring(1));
|
||||
local.Behind.Add(line.Substring(1));
|
||||
else
|
||||
status.Ahead.Add(line.Substring(1));
|
||||
local.Ahead.Add(line.Substring(1));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,27 +2,6 @@
|
||||
|
||||
namespace SourceGit.Models
|
||||
{
|
||||
public class BranchTrackStatus
|
||||
{
|
||||
public List<string> Ahead { get; set; } = new List<string>();
|
||||
public List<string> Behind { get; set; } = new List<string>();
|
||||
|
||||
public bool IsVisible => Ahead.Count > 0 || Behind.Count > 0;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (Ahead.Count == 0 && Behind.Count == 0)
|
||||
return string.Empty;
|
||||
|
||||
var track = "";
|
||||
if (Ahead.Count > 0)
|
||||
track += $"{Ahead.Count}↑";
|
||||
if (Behind.Count > 0)
|
||||
track += $" {Behind.Count}↓";
|
||||
return track.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
public enum BranchSortMode
|
||||
{
|
||||
Name = 0,
|
||||
@@ -39,11 +18,33 @@ namespace SourceGit.Models
|
||||
public bool IsCurrent { get; set; }
|
||||
public bool IsDetachedHead { get; set; }
|
||||
public string Upstream { get; set; }
|
||||
public BranchTrackStatus TrackStatus { get; set; }
|
||||
public List<string> Ahead { get; set; } = [];
|
||||
public List<string> Behind { get; set; } = [];
|
||||
public string Remote { get; set; }
|
||||
public bool IsUpstreamGone { get; set; }
|
||||
public string WorktreePath { get; set; }
|
||||
|
||||
public bool IsTrackStatusVisible
|
||||
{
|
||||
get
|
||||
{
|
||||
return Ahead.Count + Behind.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public string TrackStatusDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
var ahead = Ahead.Count;
|
||||
var behind = Behind.Count;
|
||||
if (ahead > 0)
|
||||
return behind > 0 ? $"{ahead}↑ {behind}↓" : $"{ahead}↑";
|
||||
|
||||
return behind > 0 ? $"{behind}↓" : string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasWorktree => !IsCurrent && !string.IsNullOrEmpty(WorktreePath);
|
||||
public string FriendlyName => IsLocal ? Name : $"{Remote}/{Name}";
|
||||
}
|
||||
|
||||
@@ -219,12 +219,12 @@ namespace SourceGit.ViewModels
|
||||
return false;
|
||||
|
||||
var lb = _repo.Branches.Find(x => x.IsLocal && x.Upstream == rb.FullName);
|
||||
if (lb == null || lb.TrackStatus.Ahead.Count > 0)
|
||||
if (lb == null || lb.Ahead.Count > 0)
|
||||
{
|
||||
if (_repo.CanCreatePopup())
|
||||
_repo.ShowPopup(new CreateBranch(_repo, rb));
|
||||
}
|
||||
else if (lb.TrackStatus.Behind.Count > 0)
|
||||
else if (lb.Behind.Count > 0)
|
||||
{
|
||||
if (_repo.CanCreatePopup())
|
||||
_repo.ShowPopup(new CheckoutAndFastForward(_repo, lb, rb));
|
||||
@@ -265,7 +265,7 @@ namespace SourceGit.ViewModels
|
||||
continue;
|
||||
|
||||
var lb = _repo.Branches.Find(x => x.IsLocal && x.Upstream == rb.FullName);
|
||||
if (lb is { TrackStatus.Ahead.Count: 0 })
|
||||
if (lb.Ahead.Count == 0)
|
||||
{
|
||||
if (_repo.CanCreatePopup())
|
||||
_repo.ShowPopup(new CheckoutAndFastForward(_repo, lb, rb));
|
||||
|
||||
@@ -1182,7 +1182,7 @@ namespace SourceGit.ViewModels
|
||||
if (_workingCopy != null)
|
||||
_workingCopy.HasRemotes = remotes.Count > 0;
|
||||
|
||||
var hasPendingPullOrPush = CurrentBranch?.TrackStatus.IsVisible ?? false;
|
||||
var hasPendingPullOrPush = CurrentBranch?.IsTrackStatusVisible ?? false;
|
||||
GetOwnerPage()?.ChangeDirtyState(Models.DirtyState.HasPendingPullOrPush, !hasPendingPullOrPush);
|
||||
});
|
||||
}, token);
|
||||
@@ -1465,9 +1465,9 @@ namespace SourceGit.ViewModels
|
||||
{
|
||||
if (b.IsLocal &&
|
||||
b.Upstream.Equals(branch.FullName, StringComparison.Ordinal) &&
|
||||
b.TrackStatus.Ahead.Count == 0)
|
||||
b.Ahead.Count == 0)
|
||||
{
|
||||
if (b.TrackStatus.Behind.Count > 0)
|
||||
if (b.Behind.Count > 0)
|
||||
ShowPopup(new CheckoutAndFastForward(this, b, branch));
|
||||
else if (!b.IsCurrent)
|
||||
await CheckoutBranchAsync(b);
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
Margin="0,4,0,0"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Center"
|
||||
Text="{DynamicResource Text.BranchTree.Status}"
|
||||
IsVisible="{Binding TrackStatus.IsVisible, Mode=OneWay}"/>
|
||||
IsVisible="{Binding IsTrackStatusVisible, Mode=OneWay}"/>
|
||||
<v:BranchTreeNodeTrackStatusTooltip Grid.Row="1" Grid.Column="1"
|
||||
Margin="8,4,0,0"/>
|
||||
|
||||
|
||||
@@ -183,11 +183,11 @@ namespace SourceGit.Views
|
||||
|
||||
if (DataContext is ViewModels.BranchTreeNode { Backend: Models.Branch branch })
|
||||
{
|
||||
var status = branch.TrackStatus.ToString();
|
||||
if (!string.IsNullOrEmpty(status))
|
||||
var desc = branch.TrackStatusDescription;
|
||||
if (!string.IsNullOrEmpty(desc))
|
||||
{
|
||||
_label = new FormattedText(
|
||||
status,
|
||||
desc,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
new Typeface(FontFamily),
|
||||
@@ -212,22 +212,18 @@ namespace SourceGit.Views
|
||||
|
||||
Text = string.Empty;
|
||||
|
||||
if (DataContext is not Models.Branch { TrackStatus: { IsVisible: true } track })
|
||||
if (DataContext is not Models.Branch { IsTrackStatusVisible: true } branch)
|
||||
{
|
||||
SetCurrentValue(IsVisibleProperty, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (track.Ahead.Count > 0)
|
||||
{
|
||||
Text = track.Behind.Count > 0 ?
|
||||
App.Text("BranchTree.AheadBehind", track.Ahead.Count, track.Behind.Count) :
|
||||
App.Text("BranchTree.Ahead", track.Ahead.Count);
|
||||
}
|
||||
else if (track.Behind.Count > 0)
|
||||
{
|
||||
Text = App.Text("BranchTree.Behind", track.Behind.Count);
|
||||
}
|
||||
var ahead = branch.Ahead.Count;
|
||||
var behind = branch.Behind.Count;
|
||||
if (ahead > 0)
|
||||
Text = behind > 0 ? App.Text("BranchTree.AheadBehind", ahead, behind) : App.Text("BranchTree.Ahead", ahead);
|
||||
else
|
||||
Text = App.Text("BranchTree.Behind", behind);
|
||||
|
||||
SetCurrentValue(IsVisibleProperty, true);
|
||||
}
|
||||
@@ -638,7 +634,7 @@ namespace SourceGit.Views
|
||||
var fastForward = new MenuItem();
|
||||
fastForward.Header = App.Text("BranchCM.FastForward", upstream.FriendlyName);
|
||||
fastForward.Icon = App.CreateMenuIcon("Icons.FastForward");
|
||||
fastForward.IsEnabled = branch.TrackStatus.Ahead.Count == 0 && branch.TrackStatus.Behind.Count > 0;
|
||||
fastForward.IsEnabled = branch.Ahead.Count == 0 && branch.Behind.Count > 0;
|
||||
fastForward.Click += async (_, e) =>
|
||||
{
|
||||
if (repo.CanCreatePopup())
|
||||
@@ -685,7 +681,7 @@ namespace SourceGit.Views
|
||||
var fastForward = new MenuItem();
|
||||
fastForward.Header = App.Text("BranchCM.FastForward", upstream.FriendlyName);
|
||||
fastForward.Icon = App.CreateMenuIcon("Icons.FastForward");
|
||||
fastForward.IsEnabled = branch.TrackStatus.Ahead.Count == 0 && branch.TrackStatus.Behind.Count > 0;
|
||||
fastForward.IsEnabled = branch.Ahead.Count == 0 && branch.Behind.Count > 0;
|
||||
fastForward.Click += async (_, e) =>
|
||||
{
|
||||
if (repo.CanCreatePopup())
|
||||
@@ -697,7 +693,7 @@ namespace SourceGit.Views
|
||||
var fetchInto = new MenuItem();
|
||||
fetchInto.Header = App.Text("BranchCM.FetchInto", upstream.FriendlyName, branch.Name);
|
||||
fetchInto.Icon = App.CreateMenuIcon("Icons.Fetch");
|
||||
fetchInto.IsEnabled = branch.TrackStatus.Ahead.Count == 0;
|
||||
fetchInto.IsEnabled = branch.Ahead.Count == 0;
|
||||
fetchInto.Click += async (_, e) =>
|
||||
{
|
||||
if (repo.CanCreatePopup())
|
||||
|
||||
@@ -32,11 +32,11 @@
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="9"
|
||||
Background="{DynamicResource Brush.Badge}"
|
||||
IsVisible="{Binding LocalBranch.TrackStatus.IsVisible}">
|
||||
IsVisible="{Binding LocalBranch.IsTrackStatusVisible, Mode=OneWay}">
|
||||
<TextBlock Foreground="{DynamicResource Brush.BadgeFG}"
|
||||
FontFamily="{DynamicResource Fonts.Monospace}"
|
||||
FontSize="10"
|
||||
Text="{Binding LocalBranch.TrackStatus}"/>
|
||||
Text="{Binding LocalBranch.TrackStatusDescription, Mode=OneWay}"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
@@ -52,14 +52,13 @@ namespace SourceGit.Views
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
if (DataContext is Models.Commit commit && CurrentBranch is not null)
|
||||
if (DataContext is Models.Commit commit && CurrentBranch is { } b)
|
||||
{
|
||||
var sha = commit.SHA;
|
||||
var track = CurrentBranch.TrackStatus;
|
||||
|
||||
if (track.Ahead.Contains(sha))
|
||||
if (b.Ahead.Contains(sha))
|
||||
_status = Status.Ahead;
|
||||
else if (track.Behind.Contains(sha))
|
||||
else if (b.Behind.Contains(sha))
|
||||
_status = Status.Behind;
|
||||
else
|
||||
_status = Status.Normal;
|
||||
|
||||
@@ -23,11 +23,11 @@
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="9"
|
||||
Background="{DynamicResource Brush.Badge}"
|
||||
IsVisible="{Binding Target.TrackStatus.IsVisible}">
|
||||
IsVisible="{Binding Target.IsTrackStatusVisible}">
|
||||
<TextBlock Foreground="{DynamicResource Brush.BadgeFG}"
|
||||
FontFamily="{DynamicResource Fonts.Monospace}"
|
||||
FontSize="10"
|
||||
Text="{Binding Target.TrackStatus}"/>
|
||||
Text="{Binding Target.TrackStatusDescription}"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
@@ -52,11 +52,11 @@
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="9"
|
||||
Background="{DynamicResource Brush.Badge}"
|
||||
IsVisible="{Binding TrackStatus.IsVisible}">
|
||||
IsVisible="{Binding IsTrackStatusVisible}">
|
||||
<TextBlock Foreground="{DynamicResource Brush.BadgeFG}"
|
||||
FontFamily="{DynamicResource Fonts.Monospace}"
|
||||
FontSize="10"
|
||||
Text="{Binding TrackStatus}"/>
|
||||
Text="{Binding TrackStatusDescription, Mode=OneWay}"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
@@ -711,7 +711,7 @@ namespace SourceGit.Views
|
||||
|
||||
if (!isHead)
|
||||
{
|
||||
if (current.TrackStatus.Ahead.Contains(commit.SHA))
|
||||
if (current.Ahead.Contains(commit.SHA))
|
||||
{
|
||||
var upstream = repo.Branches.Find(x => x.FullName.Equals(current.Upstream, StringComparison.Ordinal));
|
||||
var pushRevision = new MenuItem();
|
||||
@@ -911,7 +911,7 @@ namespace SourceGit.Views
|
||||
var fastForward = new MenuItem();
|
||||
fastForward.Header = App.Text("BranchCM.FastForward", upstream);
|
||||
fastForward.Icon = App.CreateMenuIcon("Icons.FastForward");
|
||||
fastForward.IsEnabled = current.TrackStatus.Ahead.Count == 0 && current.TrackStatus.Behind.Count > 0;
|
||||
fastForward.IsEnabled = current.Ahead.Count == 0 && current.Behind.Count > 0;
|
||||
fastForward.Click += async (_, e) =>
|
||||
{
|
||||
var b = repo.Branches.Find(x => x.FriendlyName == upstream);
|
||||
|
||||
Reference in New Issue
Block a user