8000 Introduce ObjectDatabase.CalculateHistoryDivergence() · GiTechLab/libgit2sharp@a845db9 · GitHub
[go: up one dir, main page]

Skip to content

Commit a845db9

Browse files
committed
Introduce ObjectDatabase.CalculateHistoryDivergence()
Fix libgit2#562
1 parent 442f7a8 commit a845db9

File tree

5 files changed

+159
-35
lines changed

5 files changed

+159
-35
lines changed

LibGit2Sharp.Tests/ObjectDatabaseFixture.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,5 +481,56 @@ public void CanCreateATagAnnotationWithAnEmptyMessage()
481481
Assert.Equal(string.Empty, tagAnnotation.Message);
482482
}
483483
}
484+
485+
[Theory]
486+
[InlineData("c47800c", "9fd738e", "5b5b025", 1, 2)]
487+
[InlineData("9fd738e", "c47800c", "5b5b025", 2, 1)]
488+
public void CanCalculateHistoryDivergence(
489+
string sinceSha, string untilSha,
490+
string expectedAncestorSha, int? expectedAheadBy, int? expectedBehindBy)
491+
{
492+
using (var repo = new Repository(BareTestRepoPath))
493+
{
494+
var since = repo.Lookup<Commit>(sinceSha);
495+
var until = repo.Lookup<Commit>(untilSha);
496+
497+
HistoryDivergence div = repo.ObjectDatabase.CalculateHistoryDivergence(since, until);
498+
499+
Assert.Equal(expectedAheadBy, div.AheadBy);
500+
Assert.Equal(expectedBehindBy, div.BehindBy);
501+
Assert.Equal(expectedAncestorSha, div.CommonAncestor.Id.ToString(7));
502+
}
503+
}
504+
505+
[Theory]
506+
[InlineData("c47800c", "41bc8c6907", 3, 2)]
507+
public void CanCalculateHistoryDivergenceWhenNoAncestorIsShared(
508+
string sinceSha, string untilSha,
509+
int? expectedAheadBy, int? expectedBehindBy)
510+
{
511+
using (var repo = new Repository(BareTestRepoPath))
512+
{
513+
var since = repo.Lookup<Commit>(sinceSha);
514+
var until = repo.Lookup<Commit>(untilSha);
515+
516+
HistoryDivergence div = repo.ObjectDatabase.CalculateHistoryDivergence(since, until);
517+
518+
Assert.Equal(expectedAheadBy, div.AheadBy);
519+
Assert.Equal(expectedBehindBy, div.BehindBy);
520+
Assert.Null(div.CommonAncestor);
521+
}
522+
}
523+
524+
[Fact]
525+
public void CalculatingHistoryDivergenceWithBadParamsThrows()
526+
{
527+
using (var repo = new Repository(BareTestRepoPath))
528+
{
529+
Assert.Throws<ArgumentNullException>(
530+
() => repo.ObjectDatabase.CalculateHistoryDivergence(repo.Head.Tip, null));
531+
Assert.Throws<ArgumentNullException>(
532+
() => repo.ObjectDatabase.CalculateHistoryDivergence(null, repo.Head.Tip));
533+
}
534+
}
484535
}
485536
}

LibGit2Sharp/BranchTrackingDetails.cs

Lines changed: 11 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using LibGit2Sharp.Core;
2-
using LibGit2Sharp.Core.Compat;
1+
using System;
32

43
namespace LibGit2Sharp
54
{
@@ -8,10 +7,7 @@ namespace LibGit2Sharp
87
/// </summary>
98
public class BranchTrackingDetails
109
{
11-
private readonly Repository repo;
12-
private readonly Branch branch;
13-
private readonly Lazy<Tuple<int?, int?>> aheadBehind;
14-
private readonly Lazy<Commit> commonAncestor;
10+
private readonly HistoryDivergence historyDivergence;
1511

1612
/// <summary>
1713
/// Needed for mocking purposes.
@@ -21,11 +17,13 @@ protected BranchTrackingDetails()
2117

2218
internal BranchTrackingDetails(Repository repo, Branch branch)
2319
{
24-
this.repo = repo;
25-
this.branch = branch;
20+
if (!branch.IsTracking || branch.Tip == null || branch.TrackedBranch.Tip == null)
21+
{
22+
historyDivergence = new NullHistoryDivergence();
23+
return;
24+
}
2625

27-
aheadBehind = new Lazy<Tuple<int?, int?>>(ResolveAheadBehind);
28-
commonAncestor = new Lazy<Commit>(ResolveCommonAncestor);
26+
historyDivergence = repo.ObjectDatabase.CalculateHistoryDivergence(branch.Tip, branch.TrackedBranch.Tip);
2927
}
3028

3129
/// <summary>
@@ -37,7 +35,7 @@ internal BranchTrackingDetails(Repository repo, Branch branch)
3735
/// </summary>
3836
public virtual int? AheadBy
3937
{
40-
get { return aheadBehind.Value.Item1; }
38+
get { return historyDivergence.AheadBy; }
4139
}
4240

4341
/// <summary>
@@ -49,7 +47,7 @@ public virtual int? AheadBy
4947
/// </summary>
5048
public virtual int? BehindBy
5149
{
52-
get { return aheadBehind.Value.Item2; }
50+
get { return historyDivergence.BehindBy; }
5351
}
5452

5553
/// <summary>
@@ -61,29 +59,7 @@ public virtual int? BehindBy
6159
/// </summary>
6260
public virtual Commit CommonAncestor
6361
{
64-
get { return commonAncestor.Value; }
65-
}
66-
67-
private Tuple<int?, int?> ResolveAheadBehind()
68-
{
69-
return branch.IsTracking
70-
? Proxy.git_graph_ahead_behind(repo.Handle, branch.TrackedBranch.Tip, branch.Tip)
71-
: new Tuple<int?, int?>(null, null);
72-
}
73-
74-
private Commit ResolveCommonAncestor()
75-
{
76-
if (!branch.IsTracking)
77-
{
78-
return null;
79-
}
80-
81-
if (branch.Tip == null || branch.TrackedBranch.Tip == null)
82-
{
83-
return null;
84-
}
85-
86-
return repo.Commits.FindCommonAncestor(branch.Tip, branch.TrackedBranch.Tip);
62+
get { return historyDivergence.CommonAncestor; }
8763
}
8864
}
8965
}

LibGit2Sharp/HistoryDivergence.cs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using LibGit2Sharp.Core;
2+
using LibGit2Sharp.Core.Compat;
3+
4+
namespace LibGit2Sharp
5+
{
6+
/// <summary>
7+
/// Holds information about the potential ancestor
8+
/// and distance from it and two specified <see cref="Commit"/>s.
9+
/// </summary>
10+
public class HistoryDivergence
11+
{
12+
private readonly Lazy<Commit> commonAncestor;
13+
14+
/// <summary>
15+
/// Needed for mocking purposes.
16+
/// </summary>
17+
protected HistoryDivergence()
18+
{ }
19+
20+
internal HistoryDivergence(Repository repo, Commit one, Commit another)
21+
{
22+
commonAncestor = new Lazy<Commit>(() => repo.Commits.FindCommonAncestor(one, another));
23+
Tuple<int?, int?> div = Proxy.git_graph_ahead_behind(repo.Handle, another, one);
24+
25+
One = one;
26+
Another = another;
27+
AheadBy = div.Item1;
28+
BehindBy = div.Item2;
29+
}
30+
31+
/// <summary>
32+
/// Gets the <see cref="Commit"/> being used as a reference.
33+
/// </summary>
34+
public virtual Commit One { get; private set; }
35+
36+
/// <summary>
F987
37+
/// Gets the <see cref="Commit"/> being compared against <see cref="One"/>.
38+
/// </summary>
39+
public virtual Commit Another { get; private set; }
40+
41+
/// <summary>
42+
/// Gets the number of commits that are reachable from <see cref="One"/>,
43+
/// but not from <see cref="Another"/>.
44+
/// <para>
45+
/// This property will return <c>null</c> when <see cref="One"/>
46+
/// and <see cref="Another"/> do not share a common ancestor.
47+
/// </para>
48+
/// </summary>
49+
public virtual int? AheadBy { get; private set; }
50+
51+
/// <summary>
52+
/// Gets the number of commits that are reachable from <see cref="Second"/>,
53+
/// but not from <see cref="One"/>.
54+
/// <para>
55+
/// This property will return <c>null</c> when <see cref="One"/>
56+
/// and <see cref="Another"/> do not share a common ancestor.
57+
/// </para>
58+
/// </summary>
59+
public virtual int? BehindBy { get; private set; }
60+
61+
/// <summary>
62+
/// Returns the best possible common ancestor <see cref="Commit"/> of <see cref="One"/>
63+
/// and <see cref="Another"/> or null if none found.
64+
/// </summary>
65+
public virtual Commit CommonAncestor
66+
{
67+
get
68+
{
69+
return commonAncestor.Value;
70+
}
71+
}
72+
}
73+
74+
internal class NullHistoryDivergence : HistoryDivergence
75+
{
76+
public override Commit CommonAncestor
77+
{
78+
get { return null; }
79+
}
80+
}
81+
}

LibGit2Sharp/LibGit2Sharp.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
<Compile Include="Core\Handles\BlameSafeHandle.cs" />
8484
<Compile Include="Core\PushTransferProgressCallbacks.cs" />
8585
<Compile Include="Core\PackbuilderCallbacks.cs" />
86+
<Compile Include="HistoryDivergence.cs" />
8687
<Compile Include="PushOptions.cs" />
8788
<Compile Include="Core\GitBuf.cs" />
8889
<Compile Include="FilteringOptions.cs" />

LibGit2Sharp/ObjectDatabase.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,5 +235,20 @@ public virtual TagAnnotation CreateTagAnnotation(string name, GitObject target,
235235

236236
return repo.Lookup<TagAnnotation>(tagId);
237237
}
238+
239+
/// <summary>
240+
/// Returns the merge base (best common ancestor) of the given commits
241+
/// and the distance between each of these commits and this base.
242+
/// </summary>
243+
/// <param name="one">The <see cref="Commit"/> being used as a reference.</param>
244+
/// <param name="another">The <see cref="Commit"/> being compared against <paramref name="one"/>.</param>
245+
/// <returns>A instance of <see cref="HistoryDivergence"/>.</returns>
246+
public virtual HistoryDivergence CalculateHistoryDivergence(Commit one, Commit another)
247+
{
248+
Ensure.ArgumentNotNull(one, "one");
249+
Ensure.ArgumentNotNull(another, "another");
250+
251+
return new HistoryDivergence(repo, one, another);
252+
}
238253
}
239254
}

0 commit comments

Comments
 (0)
0