Skip to content

Commit f0649c9

Browse files
committed
feature: add an indicator that shows those commits the current branch ahead/behind its upstream
1 parent 9de2853 commit f0649c9

File tree

12 files changed

+179
-193
lines changed

12 files changed

+179
-193
lines changed

src/Commands/QueryBranches.cs

Lines changed: 8 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,8 @@ public QueryBranches(string repo)
2424
{
2525
Exec();
2626

27-
foreach (var b in _branches)
28-
{
29-
if (b.IsLocal && !string.IsNullOrEmpty(b.UpstreamTrackStatus))
30-
{
31-
if (b.UpstreamTrackStatus == "=")
32-
{
33-
b.UpstreamTrackStatus = string.Empty;
34-
}
35-
else
36-
{
37-
b.UpstreamTrackStatus = ParseTrackStatus(b.Name, b.Upstream);
38-
}
39-
}
40-
}
27+
foreach (var b in _needQueryTrackStatus)
28+
b.TrackStatus = new QueryTrackStatus(WorkingDirectory, b.Name, b.Upstream).Result();
4129

4230
return _branches;
4331
}
@@ -84,35 +72,16 @@ protected override void OnReadline(string line)
8472
branch.Head = parts[1];
8573
branch.IsCurrent = parts[2] == "*";
8674
branch.Upstream = parts[3];
87-
branch.UpstreamTrackStatus = parts[4];
88-
_branches.Add(branch);
89-
}
9075

91-
private string ParseTrackStatus(string local, string upstream)
92-
{
93-
var cmd = new Command();
94-
cmd.WorkingDirectory = WorkingDirectory;
95-
cmd.Context = Context;
96-
cmd.Args = $"rev-list --left-right --count {local}...{upstream}";
97-
98-
var rs = cmd.ReadToEnd();
99-
if (!rs.IsSuccess)
100-
return string.Empty;
101-
102-
var match = REG_AHEAD_BEHIND().Match(rs.StdOut);
103-
if (!match.Success)
104-
return string.Empty;
76+
if (branch.IsLocal && !parts[4].Equals("=", StringComparison.Ordinal))
77+
_needQueryTrackStatus.Add(branch);
78+
else
79+
branch.TrackStatus = new Models.BranchTrackStatus();
10580

106-
var ahead = int.Parse(match.Groups[1].Value);
107-
var behind = int.Parse(match.Groups[2].Value);
108-
var track = "";
109-
if (ahead > 0)
110-
track += $"{ahead}↑";
111-
if (behind > 0)
112-
track += $" {behind}↓";
113-
return track.Trim();
81+
_branches.Add(branch);
11482
}
11583

11684
private readonly List<Models.Branch> _branches = new List<Models.Branch>();
85+
private List<Models.Branch> _needQueryTrackStatus = new List<Models.Branch>();
11786
}
11887
}

src/Commands/QueryCommits.cs

Lines changed: 3 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ public QueryCommits(string repo, int maxCount, string messageFilter, bool isFile
3333
argsBuilder.Append("--all-match -i");
3434
search = argsBuilder.ToString();
3535
}
36-
3736

3837
WorkingDirectory = repo;
3938
Context = repo;
@@ -63,7 +62,9 @@ public QueryCommits(string repo, int maxCount, string messageFilter, bool isFile
6362
ParseParent(line);
6463
break;
6564
case 2:
66-
ParseDecorators(line);
65+
_current.ParseDecorators(line);
66+
if (_current.IsMerged && !_isHeadFounded)
67+
_isHeadFounded = true;
6768
break;
6869
case 3:
6970
_current.Author = Models.User.FindOrAdd(line);
@@ -114,74 +115,6 @@ private void ParseParent(string data)
114115
_current.Parents.Add(data.Substring(idx + 1));
115116
}
116117

117-
private void ParseDecorators(string data)
118-
{
119-
if (data.Length < 3)
120-
return;
121-
122-
var subs = data.Split(',', StringSplitOptions.RemoveEmptyEntries);
123-
foreach (var sub in subs)
124-
{
125-
var d = sub.Trim();
126-
if (d.EndsWith("/HEAD", StringComparison.Ordinal))
127-
continue;
128-
129-
if (d.StartsWith("tag: refs/tags/", StringComparison.Ordinal))
130-
{
131-
_current.Decorators.Add(new Models.Decorator()
132-
{
133-
Type = Models.DecoratorType.Tag,
134-
Name = d.Substring(15),
135-
});
136-
}
137-
else if (d.StartsWith("HEAD -> refs/heads/", StringComparison.Ordinal))
138-
{
139-
_current.IsMerged = true;
140-
_current.Decorators.Add(new Models.Decorator()
141-
{
142-
Type = Models.DecoratorType.CurrentBranchHead,
143-
Name = d.Substring(19),
144-
});
145-
}
146-
else if (d.Equals("HEAD"))
147-
{
148-
_current.IsMerged = true;
149-
_current.Decorators.Add(new Models.Decorator()
150-
{
151-
Type = Models.DecoratorType.CurrentCommitHead,
152-
Name = d,
153-
});
154-
}
155-
else if (d.StartsWith("refs/heads/", StringComparison.Ordinal))
156-
{
157-
_current.Decorators.Add(new Models.Decorator()
158-
{
159-
Type = Models.DecoratorType.LocalBranchHead,
160-
Name = d.Substring(11),
161-
});
162-
}
163-
else if (d.StartsWith("refs/remotes/", StringComparison.Ordinal))
164-
{
165-
_current.Decorators.Add(new Models.Decorator()
166-
{
167-
Type = Models.DecoratorType.RemoteBranchHead,
168-
Name = d.Substring(13),
169-
});
170-
}
171-
}
172-
173-
_current.Decorators.Sort((l, r) =>
174-
{
175-
if (l.Type != r.Type)
176-
return (int)l.Type - (int)r.Type;
177-
else
178-
return string.Compare(l.Name, r.Name, StringComparison.Ordinal);
179-
});
180-
181-
if (_current.IsMerged && !_isHeadFounded)
182-
_isHeadFounded = true;
183-
}
184-
185118
private void MarkFirstMerged()
186119
{
187120
Args = $"log --since=\"{_commits[^1].CommitterTimeStr}\" --format=\"%H\"";

src/Commands/QuerySingleCommit.cs

Lines changed: 2 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public Models.Commit Result()
2626
if (!string.IsNullOrEmpty(lines[1]))
2727
commit.Parents.AddRange(lines[1].Split(' ', StringSplitOptions.RemoveEmptyEntries));
2828
if (!string.IsNullOrEmpty(lines[2]))
29-
commit.IsMerged = ParseDecorators(commit.Decorators, lines[2]);
29+
commit.ParseDecorators(lines[2]);
3030
commit.Author = Models.User.FindOrAdd(lines[3]);
3131
commit.AuthorTime = ulong.Parse(lines[4]);
3232
commit.Committer = Models.User.FindOrAdd(lines[5]);
@@ -39,70 +39,6 @@ public Models.Commit Result()
3939
return null;
4040
}
4141

42-
private bool ParseDecorators(List<Models.Decorator> decorators, string data)
43-
{
44-
bool isHeadOfCurrent = false;
45-
46-
var subs = data.Split(',', StringSplitOptions.RemoveEmptyEntries);
47-
foreach (var sub in subs)
48-
{
49-
var d = sub.Trim();
50-
if (d.EndsWith("/HEAD", StringComparison.Ordinal))
51-
continue;
52-
53-
if (d.StartsWith("tag: refs/tags/", StringComparison.Ordinal))
54-
{
55-
decorators.Add(new Models.Decorator()
56-
{
57-
Type = Models.DecoratorType.Tag,
58-
Name = d.Substring(15),
59-
});
60-
}
61-
else if (d.StartsWith("HEAD -> refs/heads/", StringComparison.Ordinal))
62-
{
63-
isHeadOfCurrent = true;
64-
decorators.Add(new Models.Decorator()
65-
{
66-
Type = Models.DecoratorType.CurrentBranchHead,
67-
Name = d.Substring(19),
68-
});
69-
}
70-
else if (d.Equals("HEAD"))
71-
{
72-
isHeadOfCurrent = true;
73-
decorators.Add(new Models.Decorator()
74-
{
75-
Type = Models.DecoratorType.CurrentCommitHead,
76-
Name = d,
77-
});
78-
}
79-
else if (d.StartsWith("refs/heads/", StringComparison.Ordinal))
80-
{
81-
decorators.Add(new Models.Decorator()
82-
{
83-
Type = Models.DecoratorType.LocalBranchHead,
84-
Name = d.Substring(11),
85-
});
86-
}
87-
else if (d.StartsWith("refs/remotes/", StringComparison.Ordinal))
88-
{
89-
decorators.Add(new Models.Decorator()
90-
{
91-
Type = Models.DecoratorType.RemoteBranchHead,
92-
Name = d.Substring(13),
93-
});
94-
}
95-
}
96-
97-
decorators.Sort((l, r) =>
98-
{
99-
if (l.Type != r.Type)
100-
return (int)l.Type - (int)r.Type;
101-
else
102-
return string.Compare(l.Name, r.Name, StringComparison.Ordinal);
103-
});
104-
105-
return isHeadOfCurrent;
106-
}
42+
10743
}
10844
}

src/Commands/QueryTrackStatus.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
3+
namespace SourceGit.Commands
4+
{
5+
public class QueryTrackStatus : Command
6+
{
7+
public QueryTrackStatus(string repo, string local, string upstream)
8+
{
9+
WorkingDirectory = repo;
10+
Context = repo;
11+
Args = $"rev-list --left-right {local}...{upstream}";
12+
}
13+
14+
public Models.BranchTrackStatus Result()
15+
{
16+
var status = new Models.BranchTrackStatus();
17+
18+
var rs = ReadToEnd();
19+
if (!rs.IsSuccess)
20+
return status;
21+
22+
var lines = rs.StdOut.Split(['\n', '\r'], StringSplitOptions.RemoveEmptyEntries);
23+
foreach (var line in lines)
24+
{
25+
if (line[0] == '>')
26+
status.Behind.Add(line.Substring(1));
27+
else
28+
status.Ahead.Add(line.Substring(1));
29+
}
30+
31+
return status;
32+
}
33+
}
34+
}

src/Models/Branch.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
1-
namespace SourceGit.Models
1+
using System.Collections.Generic;
2+
3+
namespace SourceGit.Models
24
{
5+
public class BranchTrackStatus
6+
{
7+
public List<string> Ahead { get; set; } = new List<string>();
8+
public List<string> Behind { get; set; } = new List<string>();
9+
10+
public override string ToString()
11+
{
12+
if (Ahead.Count == 0 && Behind.Count == 0)
13+
return string.Empty;
14+
15+
var track = "";
16+
if (Ahead.Count > 0)
17+
track += $"{Ahead.Count}↑";
18+
if (Behind.Count > 0)
19+
track += $" {Behind.Count}↓";
20+
return track.Trim();
21+
}
22+
}
23+
324
public class Branch
425
{
526
public string Name { get; set; }
@@ -8,7 +29,7 @@ public class Branch
829
public bool IsLocal { get; set; }
930
public bool IsCurrent { get; set; }
1031
public string Upstream { get; set; }
11-
public string UpstreamTrackStatus { get; set; }
32+
public BranchTrackStatus TrackStatus { get; set; }
1233
public string Remote { get; set; }
1334
public bool IsHead { get; set; }
1435

0 commit comments

Comments
 (0)