How to easily get all Refs for a given Commit?
Asked Answered
D

2

0

Is there an easy way to find all References (e.g. Tags) for a given Commit? For example:

using( Repository repo = new Repository( path_to_repo ) )
{
    foreach( Commit commit in repo.Commits )
    {
        List<Reference> assignedRefs = commit.Refs; // <- how to do this?
    }
}
Demulsify answered 21/3, 2014 at 6:51 Comment(0)
S
1

The code below retrieves all the references that can reach the selected commit.

using( Repository repo = new Repository( path_to_repo ) )
{
    foreach( Commit commit in repo.Commits )
    {
        IEnumerable<Reference> refs =
               repo.Refs.ReachableFrom(new[] { commit });
    }
}

If you want to only retrieve Tags, the method exposes an overload to help you with this.

using( Repository repo = new Repository( path_to_repo ) )
{
    var allTags = repo.Refs.Where(r => r.IsTag()).ToList();

    foreach( Commit commit in repo.Commits )
    {
        IEnumerable<Reference> refs =
               repo.Refs.ReachableFrom(allTags, new[] { commit });
    }
}

Note: This code will retrieve all refs that either directly point to the chosen commit or point to an ancestor of this commit. In this sense, it behaves similarly to the git rev-list command.

Sulphuric answered 21/3, 2014 at 8:45 Comment(3)
The call to repo.Refs.ReachableFrom is very slow. I guess I have to get all Refs once and map them into a dictionary if I want to display a list of commits along with its refs (like git log --decorate)?Demulsify
ReachableFrom() will indeed perform many revwalks (one for each passed in ref to examine).Sulphuric
Oh! I see. You don't care about reachable commits. You only need the commits that are directly pointed at by a reference. In this case, keeping a copy of the Refs would be the way to go. Beware of the Tags (and their potentially chaining behavior), see this SO question to properly tackle this. I'll properly update my answer in the next few days to provide you with a more detailed piece of code.Sulphuric
A
0

As @user1130329 pointed out, going through all refs multiple times can be very expensive. Just as an alternative, this is what I have done here for a similar case:

logs = _repo.Commits
    .QueryBy(filter)
    .Select(c => new LogEntry
    {
        Id = c.Id.Sha,
        // other fields
    })
    .ToList();

var logsDictionary = logs.ToDictionary(d => d.Id);

_repo.Refs
    .Where(r => r.IsTag || r.IsLocalBranch)
    .ForEach(r =>
    {
        if (r.IsTag) logsDictionary.GetValueOrDefault(r.TargetIdentifier)?.Tags.Add(r.CanonicalName);
        if (r.IsLocalBranch) logsDictionary.GetValueOrDefault(r.TargetIdentifier)?.Heads.Add(r.CanonicalName);
    });
Ammo answered 5/12, 2018 at 3:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.