Find out the branch a commit belongs to in LibGit2Sharp?

半城伤御伤魂 提交于 2019-12-05 16:43:56
nulltoken

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;
    }
}

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));

    …
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!