mirror of
https://github.com/sourcegit-scm/sourcegit
synced 2025-05-22 12:45:00 +00:00
feature: add an indicator that shows those commits the current branch ahead/behind its upstream
This commit is contained in:
parent
9de2853003
commit
f0649c95b5
12 changed files with 180 additions and 194 deletions
|
@ -24,20 +24,8 @@ namespace SourceGit.Commands
|
|||
{
|
||||
Exec();
|
||||
|
||||
foreach (var b in _branches)
|
||||
{
|
||||
if (b.IsLocal && !string.IsNullOrEmpty(b.UpstreamTrackStatus))
|
||||
{
|
||||
if (b.UpstreamTrackStatus == "=")
|
||||
{
|
||||
b.UpstreamTrackStatus = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
b.UpstreamTrackStatus = ParseTrackStatus(b.Name, b.Upstream);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var b in _needQueryTrackStatus)
|
||||
b.TrackStatus = new QueryTrackStatus(WorkingDirectory, b.Name, b.Upstream).Result();
|
||||
|
||||
return _branches;
|
||||
}
|
||||
|
@ -84,35 +72,16 @@ namespace SourceGit.Commands
|
|||
branch.Head = parts[1];
|
||||
branch.IsCurrent = parts[2] == "*";
|
||||
branch.Upstream = parts[3];
|
||||
branch.UpstreamTrackStatus = parts[4];
|
||||
|
||||
if (branch.IsLocal && !parts[4].Equals("=", StringComparison.Ordinal))
|
||||
_needQueryTrackStatus.Add(branch);
|
||||
else
|
||||
branch.TrackStatus = new Models.BranchTrackStatus();
|
||||
|
||||
_branches.Add(branch);
|
||||
}
|
||||
|
||||
private string ParseTrackStatus(string local, string upstream)
|
||||
{
|
||||
var cmd = new Command();
|
||||
cmd.WorkingDirectory = WorkingDirectory;
|
||||
cmd.Context = Context;
|
||||
cmd.Args = $"rev-list --left-right --count {local}...{upstream}";
|
||||
|
||||
var rs = cmd.ReadToEnd();
|
||||
if (!rs.IsSuccess)
|
||||
return string.Empty;
|
||||
|
||||
var match = REG_AHEAD_BEHIND().Match(rs.StdOut);
|
||||
if (!match.Success)
|
||||
return string.Empty;
|
||||
|
||||
var ahead = int.Parse(match.Groups[1].Value);
|
||||
var behind = int.Parse(match.Groups[2].Value);
|
||||
var track = "";
|
||||
if (ahead > 0)
|
||||
track += $"{ahead}↑";
|
||||
if (behind > 0)
|
||||
track += $" {behind}↓";
|
||||
return track.Trim();
|
||||
}
|
||||
|
||||
private readonly List<Models.Branch> _branches = new List<Models.Branch>();
|
||||
private List<Models.Branch> _needQueryTrackStatus = new List<Models.Branch>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@ namespace SourceGit.Commands
|
|||
argsBuilder.Append("--all-match -i");
|
||||
search = argsBuilder.ToString();
|
||||
}
|
||||
|
||||
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
|
@ -63,7 +62,9 @@ namespace SourceGit.Commands
|
|||
ParseParent(line);
|
||||
break;
|
||||
case 2:
|
||||
ParseDecorators(line);
|
||||
_current.ParseDecorators(line);
|
||||
if (_current.IsMerged && !_isHeadFounded)
|
||||
_isHeadFounded = true;
|
||||
break;
|
||||
case 3:
|
||||
_current.Author = Models.User.FindOrAdd(line);
|
||||
|
@ -114,74 +115,6 @@ namespace SourceGit.Commands
|
|||
_current.Parents.Add(data.Substring(idx + 1));
|
||||
}
|
||||
|
||||
private void ParseDecorators(string data)
|
||||
{
|
||||
if (data.Length < 3)
|
||||
return;
|
||||
|
||||
var subs = data.Split(',', StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var sub in subs)
|
||||
{
|
||||
var d = sub.Trim();
|
||||
if (d.EndsWith("/HEAD", StringComparison.Ordinal))
|
||||
continue;
|
||||
|
||||
if (d.StartsWith("tag: refs/tags/", StringComparison.Ordinal))
|
||||
{
|
||||
_current.Decorators.Add(new Models.Decorator()
|
||||
{
|
||||
Type = Models.DecoratorType.Tag,
|
||||
Name = d.Substring(15),
|
||||
});
|
||||
}
|
||||
else if (d.StartsWith("HEAD -> refs/heads/", StringComparison.Ordinal))
|
||||
{
|
||||
_current.IsMerged = true;
|
||||
_current.Decorators.Add(new Models.Decorator()
|
||||
{
|
||||
Type = Models.DecoratorType.CurrentBranchHead,
|
||||
Name = d.Substring(19),
|
||||
});
|
||||
}
|
||||
else if (d.Equals("HEAD"))
|
||||
{
|
||||
_current.IsMerged = true;
|
||||
_current.Decorators.Add(new Models.Decorator()
|
||||
{
|
||||
Type = Models.DecoratorType.CurrentCommitHead,
|
||||
Name = d,
|
||||
});
|
||||
}
|
||||
else if (d.StartsWith("refs/heads/", StringComparison.Ordinal))
|
||||
{
|
||||
_current.Decorators.Add(new Models.Decorator()
|
||||
{
|
||||
Type = Models.DecoratorType.LocalBranchHead,
|
||||
Name = d.Substring(11),
|
||||
});
|
||||
}
|
||||
else if (d.StartsWith("refs/remotes/", StringComparison.Ordinal))
|
||||
{
|
||||
_current.Decorators.Add(new Models.Decorator()
|
||||
{
|
||||
Type = Models.DecoratorType.RemoteBranchHead,
|
||||
Name = d.Substring(13),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_current.Decorators.Sort((l, r) =>
|
||||
{
|
||||
if (l.Type != r.Type)
|
||||
return (int)l.Type - (int)r.Type;
|
||||
else
|
||||
return string.Compare(l.Name, r.Name, StringComparison.Ordinal);
|
||||
});
|
||||
|
||||
if (_current.IsMerged && !_isHeadFounded)
|
||||
_isHeadFounded = true;
|
||||
}
|
||||
|
||||
private void MarkFirstMerged()
|
||||
{
|
||||
Args = $"log --since=\"{_commits[^1].CommitterTimeStr}\" --format=\"%H\"";
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace SourceGit.Commands
|
|||
if (!string.IsNullOrEmpty(lines[1]))
|
||||
commit.Parents.AddRange(lines[1].Split(' ', StringSplitOptions.RemoveEmptyEntries));
|
||||
if (!string.IsNullOrEmpty(lines[2]))
|
||||
commit.IsMerged = ParseDecorators(commit.Decorators, lines[2]);
|
||||
commit.ParseDecorators(lines[2]);
|
||||
commit.Author = Models.User.FindOrAdd(lines[3]);
|
||||
commit.AuthorTime = ulong.Parse(lines[4]);
|
||||
commit.Committer = Models.User.FindOrAdd(lines[5]);
|
||||
|
@ -39,70 +39,6 @@ namespace SourceGit.Commands
|
|||
return null;
|
||||
}
|
||||
|
||||
private bool ParseDecorators(List<Models.Decorator> decorators, string data)
|
||||
{
|
||||
bool isHeadOfCurrent = false;
|
||||
|
||||
var subs = data.Split(',', StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var sub in subs)
|
||||
{
|
||||
var d = sub.Trim();
|
||||
if (d.EndsWith("/HEAD", StringComparison.Ordinal))
|
||||
continue;
|
||||
|
||||
if (d.StartsWith("tag: refs/tags/", StringComparison.Ordinal))
|
||||
{
|
||||
decorators.Add(new Models.Decorator()
|
||||
{
|
||||
Type = Models.DecoratorType.Tag,
|
||||
Name = d.Substring(15),
|
||||
});
|
||||
}
|
||||
else if (d.StartsWith("HEAD -> refs/heads/", StringComparison.Ordinal))
|
||||
{
|
||||
isHeadOfCurrent = true;
|
||||
decorators.Add(new Models.Decorator()
|
||||
{
|
||||
Type = Models.DecoratorType.CurrentBranchHead,
|
||||
Name = d.Substring(19),
|
||||
});
|
||||
}
|
||||
else if (d.Equals("HEAD"))
|
||||
{
|
||||
isHeadOfCurrent = true;
|
||||
decorators.Add(new Models.Decorator()
|
||||
{
|
||||
Type = Models.DecoratorType.CurrentCommitHead,
|
||||
Name = d,
|
||||
});
|
||||
}
|
||||
else if (d.StartsWith("refs/heads/", StringComparison.Ordinal))
|
||||
{
|
||||
decorators.Add(new Models.Decorator()
|
||||
{
|
||||
Type = Models.DecoratorType.LocalBranchHead,
|
||||
Name = d.Substring(11),
|
||||
});
|
||||
}
|
||||
else if (d.StartsWith("refs/remotes/", StringComparison.Ordinal))
|
||||
{
|
||||
decorators.Add(new Models.Decorator()
|
||||
{
|
||||
Type = Models.DecoratorType.RemoteBranchHead,
|
||||
Name = d.Substring(13),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
decorators.Sort((l, r) =>
|
||||
{
|
||||
if (l.Type != r.Type)
|
||||
return (int)l.Type - (int)r.Type;
|
||||
else
|
||||
return string.Compare(l.Name, r.Name, StringComparison.Ordinal);
|
||||
});
|
||||
|
||||
return isHeadOfCurrent;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
34
src/Commands/QueryTrackStatus.cs
Normal file
34
src/Commands/QueryTrackStatus.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class QueryTrackStatus : Command
|
||||
{
|
||||
public QueryTrackStatus(string repo, string local, string upstream)
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
Args = $"rev-list --left-right {local}...{upstream}";
|
||||
}
|
||||
|
||||
public Models.BranchTrackStatus Result()
|
||||
{
|
||||
var status = new Models.BranchTrackStatus();
|
||||
|
||||
var rs = ReadToEnd();
|
||||
if (!rs.IsSuccess)
|
||||
return status;
|
||||
|
||||
var lines = rs.StdOut.Split(['\n', '\r'], StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (line[0] == '>')
|
||||
status.Behind.Add(line.Substring(1));
|
||||
else
|
||||
status.Ahead.Add(line.Substring(1));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue