Question

I am looping through commits in LibGit2Sharp:

Repository repo = new Repository("Z:/www/gg");

foreach (LibGit2Sharp.Commit commit in repo.Commits)
{
    ...
}

I can retrieve properties like Author and Message, but I do not see anything about what branch it belongs to? Ideally I would like to have a pointer to the branch object, but even a name would be fine in this scenario.

This is what the debugger shows up:

enter image description here

This is what I am looking for:

enter image description here

TortoiseGit's behavior of showing the most relevant branch name:

enter image description here

Example repository: https://docs.google.com/open?id=0B-3-X85VysdNcmZIaGVTSDZSenVGbTJxYlI2SUlsZw

Was it helpful?

Solution

There is currently no built-in way to mimic git branch --contains <commit>.

However, you might work around this limit by explicitly walking each branch and comparing each popped commit against the searched one.

Following test demonstrates this

[Test]
public void CanSearchBranchesContainingASpecificCommit()
{
    using (var repo = new Repository(StandardTestRepoPath))
    {
        const string commitSha = "5b5b025afb0b4c913b4c338a42934a3863bf3644";
        IEnumerable<Branch> branches = ListBranchesContaininingCommit(repo, commitSha);

        branches.Count().ShouldEqual(6);
    }
}

private IEnumerable<Branch> ListBranchesContaininingCommit(Repository repo, string commitSha)
{
    foreach (var branch in repo.Branches)
    {
        var commits = repo.Commits.QueryBy(new CommitFilter { Since = branch }).Where(c => c.Sha == commitSha);

        if (!commits.Any())
        {
            continue;
        }

        yield return branch;
    }
}

Note: This code has been successfully tested against the current tip of the development branch of LibGit2Sharp.

UPDATE:

Following the discussion in the comments, here's a little update which I hope will fulfill your request.

The code below will return all the branches containing the searched commit. If the commit happens to be the tip of at least one branch, those branches will be returned instead.

[Test]
public void CanSearchBranchesContainingASpecificCommit()
{
    using (var repo = new Repository(StandardTestRepoPath))
    {
        const string commitSha = "5b5b025afb0b4c913b4c338a42934a3863bf3644";
        IEnumerable<Branch> branches = ListBranchesContaininingCommit(repo, commitSha);

        branches.Count().ShouldEqual(6);

        const string otherCommitSha = "4a202b346bb0fb0db7eff3cffeb3c70babbd2045";
        branches = ListBranchesContaininingCommit(repo, otherCommitSha);

        branches.Count().ShouldEqual(1); // origin/packed-test
    }
}

private IEnumerable<Branch> ListBranchesContaininingCommit(Repository repo, string commitSha)
{
    bool directBranchHasBeenFound = false;
    foreach (var branch in repo.Branches)
    {
        if (branch.Tip.Sha != commitSha)
        {
            continue;
        }

        directBranchHasBeenFound = true;
        yield return branch;
    }

    if (directBranchHasBeenFound)
    {
        yield break;
    }

    foreach (var branch in repo.Branches)
    {
        var commits = repo.Commits.QueryBy(new CommitFilter { Since = branch }).Where(c => c.Sha == commitSha);

        if (!commits.Any())
        {
            continue;
        }

        yield return branch;
    }
}

OTHER TIPS

Git does not store branch information with commits. You'd have to walk the history DAG and see if the commit is reachable from the refs.

On the commandline with normal git you would run git branch --contains $SHA1

As knittl said, git doesn't store that information. A commit is a fixed state of the repository with some metadata. Since a commit is immutable and what branches it belongs to can change, branch information can't be stored directly in the commit.

So, to find out whether a certain commit actually belongs to some branch, you need to walk through the commits of that branch and compare them with the one commit.

To make this faster, you can store all the commits for each branch in a HashSet<T> like this:

var branchCommits =
    repo.Branches.Select(
        b => new
             {
                 b.Name,
                 Commits = new HashSet<Commit>(b.Commits)
             })
        .ToArray();

foreach (Commit commit in branch.Commits)
{
    var commitBranches = branchCommits.Where(b => b.Commits.Contains(commit));

    …
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top