Skip to content

Introduce ObjectDatabase.CalculateHistoryDivergence() #564

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 6, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LibGit2Sharp.Tests/BlameFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public void CanStopBlame()
// (be3563a comes after 9fd738e8)
var blame = repo.Blame("new.txt", new BlameOptions {StoppingAt = "be3563a"});
Assert.True(blame[0].FinalCommit.Sha.StartsWith("be3563a"));
}
}
}
}
}
2 changes: 1 addition & 1 deletion LibGit2Sharp.Tests/DiffTreeToTreeFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ public void CanIncludeUnmodifiedEntriesWhenEnabled()
Assert.Equal(2, changes.Count());
Assert.Equal(1, changes.Unmodified.Count());
Assert.Equal(1, changes.Modified.Count());
}
}
}

[Fact]
Expand Down
51 changes: 51 additions & 0 deletions LibGit2Sharp.Tests/ObjectDatabaseFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -481,5 +481,56 @@ public void CanCreateATagAnnotationWithAnEmptyMessage()
Assert.Equal(string.Empty, tagAnnotation.Message);
}
}

[Theory]
[InlineData("c47800c", "9fd738e", "5b5b025", 1, 2)]
[InlineData("9fd738e", "c47800c", "5b5b025", 2, 1)]
public void CanCalculateHistoryDivergence(
string sinceSha, string untilSha,
string expectedAncestorSha, int? expectedAheadBy, int? expectedBehindBy)
{
using (var repo = new Repository(BareTestRepoPath))
{
var since = repo.Lookup<Commit>(sinceSha);
var until = repo.Lookup<Commit>(untilSha);

HistoryDivergence div = repo.ObjectDatabase.CalculateHistoryDivergence(since, until);

Assert.Equal(expectedAheadBy, div.AheadBy);
Assert.Equal(expectedBehindBy, div.BehindBy);
Assert.Equal(expectedAncestorSha, div.CommonAncestor.Id.ToString(7));
}
}

[Theory]
[InlineData("c47800c", "41bc8c6907", 3, 2)]
public void CanCalculateHistoryDivergenceWhenNoAncestorIsShared(
string sinceSha, string untilSha,
int? expectedAheadBy, int? expectedBehindBy)
{
using (var repo = new Repository(BareTestRepoPath))
{
var since = repo.Lookup<Commit>(sinceSha);
var until = repo.Lookup<Commit>(untilSha);

HistoryDivergence div = repo.ObjectDatabase.CalculateHistoryDivergence(since, until);

Assert.Equal(expectedAheadBy, div.AheadBy);
Assert.Equal(expectedBehindBy, div.BehindBy);
Assert.Null(div.CommonAncestor);
}
}

[Fact]
public void CalculatingHistoryDivergenceWithBadParamsThrows()
{
using (var repo = new Repository(BareTestRepoPath))
{
Assert.Throws<ArgumentNullException>(
() => repo.ObjectDatabase.CalculateHistoryDivergence(repo.Head.Tip, null));
Assert.Throws<ArgumentNullException>(
() => repo.ObjectDatabase.CalculateHistoryDivergence(null, repo.Head.Tip));
}
}
}
}
4 changes: 2 additions & 2 deletions LibGit2Sharp.Tests/TreeFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,9 @@ public void CanParseSymlinkTreeEntries()
Tree t = repo.ObjectDatabase.CreateTree(td);

var te = t["A symlink"];

Assert.NotNull(te);

Assert.Equal(Mode.SymbolicLink, te.Mode);
Assert.Equal(linkContent, te.Target);
}
Expand Down
2 changes: 1 addition & 1 deletion LibGit2Sharp/BlameHunkCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace LibGit2Sharp
public class BlameHunkCollection : IEnumerable<BlameHunk>
{
private readonly IRepository repo;
private readonly List<BlameHunk> hunks = new List<BlameHunk>();
private readonly List<BlameHunk> hunks = new List<BlameHunk>();

/// <summary>
/// For easy mocking
Expand Down
46 changes: 11 additions & 35 deletions LibGit2Sharp/BranchTrackingDetails.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using LibGit2Sharp.Core;
using LibGit2Sharp.Core.Compat;
using System;

namespace LibGit2Sharp
{
Expand All @@ -8,10 +7,7 @@ namespace LibGit2Sharp
/// </summary>
public class BranchTrackingDetails
{
private readonly Repository repo;
private readonly Branch branch;
private readonly Lazy<Tuple<int?, int?>> aheadBehind;
private readonly Lazy<Commit> commonAncestor;
private readonly HistoryDivergence historyDivergence;

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

internal BranchTrackingDetails(Repository repo, Branch branch)
{
this.repo = repo;
this.branch = branch;
if (!branch.IsTracking || branch.Tip == null || branch.TrackedBranch.Tip == null)
{
historyDivergence = new NullHistoryDivergence();
return;
}

aheadBehind = new Lazy<Tuple<int?, int?>>(ResolveAheadBehind);
commonAncestor = new Lazy<Commit>(ResolveCommonAncestor);
historyDivergence = repo.ObjectDatabase.CalculateHistoryDivergence(branch.Tip, branch.TrackedBranch.Tip);
}

/// <summary>
Expand All @@ -37,7 +35,7 @@ internal BranchTrackingDetails(Repository repo, Branch branch)
/// </summary>
public virtual int? AheadBy
{
get { return aheadBehind.Value.Item1; }
get { return historyDivergence.AheadBy; }
}

/// <summary>
Expand All @@ -49,7 +47,7 @@ public virtual int? AheadBy
/// </summary>
public virtual int? BehindBy
{
get { return aheadBehind.Value.Item2; }
get { return historyDivergence.BehindBy; }
}

/// <summary>
Expand All @@ -61,29 +59,7 @@ public virtual int? BehindBy
/// </summary>
public virtual Commit CommonAncestor
{
get { return commonAncestor.Value; }
}

private Tuple<int?, int?> ResolveAheadBehind()
{
return branch.IsTracking
? Proxy.git_graph_ahead_behind(repo.Handle, branch.TrackedBranch.Tip, branch.Tip)
: new Tuple<int?, int?>(null, null);
}

private Commit ResolveCommonAncestor()
{
if (!branch.IsTracking)
{
return null;
}

if (branch.Tip == null || branch.TrackedBranch.Tip == null)
{
return null;
}

return repo.Commits.FindCommonAncestor(branch.Tip, branch.TrackedBranch.Tip);
get { return historyDivergence.CommonAncestor; }
}
}
}
2 changes: 1 addition & 1 deletion LibGit2Sharp/Core/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,7 @@ internal static extern int git_refspec_rtransform(
UIntPtr outlen,
GitRefSpecHandle refSpec,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string name);

[DllImport(libgit2)]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(LaxUtf8NoCleanupMarshaler))]
internal static extern string git_refspec_string(
Expand Down
2 changes: 1 addition & 1 deletion LibGit2Sharp/Core/Proxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2731,7 +2731,7 @@ public static IList<GitRemoteHead> RemoteLsHelper(IntPtr heads, UIntPtr size)
list.Add((GitRemoteHead)Marshal.PtrToStructure(rawHeads[i], typeof (GitRemoteHead)));
}
return list;
}
}
}

private static bool RepositoryStateChecker(RepositorySafeHandle repo, Func<RepositorySafeHandle, int> checker)
Expand Down
81 changes: 81 additions & 0 deletions LibGit2Sharp/HistoryDivergence.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using LibGit2Sharp.Core;
using LibGit2Sharp.Core.Compat;

namespace LibGit2Sharp
{
/// <summary>
/// Holds information about the potential ancestor
/// and distance from it and two specified <see cref="Commit"/>s.
/// </summary>
public class HistoryDivergence
{
private readonly Lazy<Commit> commonAncestor;

/// <summary>
/// Needed for mocking purposes.
/// </summary>
protected HistoryDivergence()
{ }

internal HistoryDivergence(Repository repo, Commit one, Commit another)
{
commonAncestor = new Lazy<Commit>(() => repo.Commits.FindCommonAncestor(one, another));
Tuple<int?, int?> div = Proxy.git_graph_ahead_behind(repo.Handle, another, one);

One = one;
Another = another;
AheadBy = div.Item1;
BehindBy = div.Item2;
}

/// <summary>
/// Gets the <see cref="Commit"/> being used as a reference.
/// </summary>
public virtual Commit One { get; private set; }

/// <summary>
/// Gets the <see cref="Commit"/> being compared against <see cref="One"/>.
/// </summary>
public virtual Commit Another { get; private set; }

/// <summary>
/// Gets the number of commits that are reachable from <see cref="One"/>,
/// but not from <see cref="Another"/>.
/// <para>
/// This property will return <c>null</c> when <see cref="One"/>
/// and <see cref="Another"/> do not share a common ancestor.
/// </para>
/// </summary>
public virtual int? AheadBy { get; private set; }

/// <summary>
/// Gets the number of commits that are reachable from <see cref="Second"/>,
/// but not from <see cref="One"/>.
/// <para>
/// This property will return <c>null</c> when <see cref="One"/>
/// and <see cref="Another"/> do not share a common ancestor.
/// </para>
/// </summary>
public virtual int? BehindBy { get; private set; }

/// <summary>
/// Returns the best possible common ancestor <see cref="Commit"/> of <see cref="One"/>
/// and <see cref="Another"/> or null if none found.
/// </summary>
public virtual Commit CommonAncestor
{
get
{
return commonAncestor.Value;
}
}
}

internal class NullHistoryDivergence : HistoryDivergence
{
public override Commit CommonAncestor
{
get { return null; }
}
}
}
1 change: 1 addition & 0 deletions LibGit2Sharp/LibGit2Sharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
<Compile Include="Core\Handles\BlameSafeHandle.cs" />
<Compile Include="Core\PushTransferProgressCallbacks.cs" />
<Compile Include="Core\PackbuilderCallbacks.cs" />
<Compile Include="HistoryDivergence.cs" />
<Compile Include="PushOptions.cs" />
<Compile Include="Core\GitBuf.cs" />
<Compile Include="FilteringOptions.cs" />
Expand Down
15 changes: 15 additions & 0 deletions LibGit2Sharp/ObjectDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,5 +235,20 @@ public virtual TagAnnotation CreateTagAnnotation(string name, GitObject target,

return repo.Lookup<TagAnnotation>(tagId);
}

/// <summary>
/// Returns the merge base (best common ancestor) of the given commits
/// and the distance between each of these commits and this base.
/// </summary>
/// <param name="one">The <see cref="Commit"/> being used as a reference.</param>
/// <param name="another">The <see cref="Commit"/> being compared against <paramref name="one"/>.</param>
/// <returns>A instance of <see cref="HistoryDivergence"/>.</returns>
public virtual HistoryDivergence CalculateHistoryDivergence(Commit one, Commit another)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dahlbyk @carlosmn I'm really lacking some inspiration about how to express what this method does/returns. Any help would be greatly appreciated.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about

Retrieves some details about the graph relationship between those
two commits such as their best ancestor, if any, and the distance from this latter and the commits

/cc @ethomson @jamill @ben

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some details but not others?

Returns the merge base (best common ancestor) of the given commits and the distance between each commit and this base.

maybe?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returns the merge base (best common ancestor) of the given commits and the distance between each commit and this base.

This is nice.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What @ethomson said.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say amend to say "distance between each of these commits", as "each commit" sounds odd now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 for @carlosmn's suggestion.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@carlosmn The NameWhisperer

{
Ensure.ArgumentNotNull(one, "one");
Ensure.ArgumentNotNull(another, "another");

return new HistoryDivergence(repo, one, another);
}
}
}
6 changes: 3 additions & 3 deletions LibGit2Sharp/RemoteUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ public virtual ICollection<string> FetchRefSpecs
/// be used during a Push operation
/// </summary>
/// <remarks>Changing the list updates the <see cref="Remote" />.</remarks>
public virtual ICollection<string> PushRefSpecs
{
public virtual ICollection<string> PushRefSpecs
{
get { return pushRefSpecs; }
set { pushRefSpecs.ReplaceAll(value); }
set { pushRefSpecs.ReplaceAll(value); }
}

private class UpdatingCollection<T> : ICollection<T>
Expand Down
2 changes: 1 addition & 1 deletion LibGit2Sharp/Repository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,7 @@ public static string Clone(string sourceUrl, string workdirPath,
Credentials credentials = null)
{
CheckoutCallbacks checkoutCallbacks = CheckoutCallbacks.GenerateCheckoutCallbacks(onCheckoutProgress, null);

var callbacks = new RemoteCallbacks(null, onTransferProgress, null, credentials);
GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks();

Expand Down
2 changes: 1 addition & 1 deletion LibGit2Sharp/RepositoryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ internal static IEnumerable<ObjectId> Committishes(this Repository repo, object
{
ObjectId singleReturnValue = null;

if (identifier is string)
if (identifier is string)
{
singleReturnValue = DereferenceToCommit(repo, identifier as string);
}
Expand Down
2 changes: 1 addition & 1 deletion LibGit2Sharp/SimilarityOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public static SimilarityOptions Default
/// The mode for detecting renames and copies
/// </summary>
public RenameDetectionMode RenameDetectionMode { get; set; }

/// <summary>
/// The mode for handling whitespace when comparing files
/// </summary>
Expand Down