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?
    }
}
zpete
  • 1,725
  • 2
  • 18
  • 31

2 Answers2

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.

nulltoken
  • 64,429
  • 20
  • 138
  • 130
  • 1
    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`)? – zpete Mar 21 '14 at 10:25
  • ReachableFrom() will indeed perform many revwalks (one for each passed in ref to examine). – nulltoken Mar 21 '14 at 15:15
  • 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](http://stackoverflow.com/questions/19808208) 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. – nulltoken Mar 21 '14 at 19:49
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);
    });
Bruno Medeiros
  • 2,251
  • 21
  • 34