找到指向提交的标签的最快方法是什么?

时间:2013-11-06 09:26:38

标签: libgit2 libgit2sharp

使用libgit2sharp我想执行以下操作:

foreach( Commit commit in repo.Commits )
{
    // How to implement assignedTags?
    foreach( Tag tag in commit.assignedTags ) {}
}

我想将所有标签分配给当前提交。什么是最好的方法呢?迭代所有标签并查看是否tag.Target.Sha == commit.Sha?多数表现不太好。还有另一种方式吗?

2 个答案:

答案 0 :(得分:8)

  

所以我希望将所有标签分配给当前提交。什么是最好的方法呢?迭代所有标签并查看是否tag.Target.Sha == commit.Sha?多数表现不太好。还有另一种方式吗?

对于标签,有两件事需要考虑。

  • 标记可以指向除提交(例如树或Blob)之外的其他内容
  • 标记可以指向另一个标记(链接注释标记)

以下代码应符合您的需要,并考虑以上几点。

注意: repo.Commits只会枚举从当前分支(HEAD)可以访问的提交。下面的代码 对此进行扩展以轻松浏览所有可访问的提交。

...

using (var repo = new Repository("Path/to/your/repo"))
{
    // Build up a cached dictionary of all the tags that point to a commit
    var dic = TagsPerPeeledCommitId(repo);

    // Let's enumerate all the reachable commits (similarly to `git log --all`)
    foreach (Commit commit in repo.Commits.QueryBy(new CommitFilter {Since = repo.Refs}))
    {
        foreach (var tags in AssignedTags(commit, dic))
        {
            Console.WriteLine("Tag {0} points at {1}", tags.Name, commit.Id);
        }
    }
}

....

private static IEnumerable<Tag> AssignedTags(Commit commit, Dictionary<ObjectId, List<Tag>> tags)
{
    if (!tags.ContainsKey(commit.Id))
    {
        return Enumerable.Empty<Tag>();
    }

    return tags[commit.Id];
}

private static Dictionary<ObjectId, List<Tag>> TagsPerPeeledCommitId(Repository repo)
{
    var tagsPerPeeledCommitId = new Dictionary<ObjectId, List<Tag>>();

    foreach (Tag tag in repo.Tags)
    {
        GitObject peeledTarget = tag.PeeledTarget;

        if (!(peeledTarget is Commit))
        {
            // We're not interested by Tags pointing at Blobs or Trees
            continue;
        }

        ObjectId commitId = peeledTarget.Id;

        if (!tagsPerPeeledCommitId.ContainsKey(commitId))
        {
            // A Commit may be pointed at by more than one Tag
            tagsPerPeeledCommitId.Add(commitId, new List<Tag>());
        }

        tagsPerPeeledCommitId[commitId].Add(tag);
    }

    return tagsPerPeeledCommitId;
}

答案 1 :(得分:0)

这是nulltoken的另一个版本的答案,但使用ILookup类而不是字典。有点好的IMO:

private static ILookup<ObjectId, Tag> CreateCommitIdToTagLookup(Repository repo)
{
    var commitIdToTagLookup =
        repo.Tags
        .Select(tag => new { Commit = tag.PeeledTarget as Commit, Tag = tag })
        .Where(x => x.Commit != null)
        .ToLookup(x => x.Commit.Id, x => x.Tag);

    return commitIdToTagLookup;
}

和简单的用法示例:

using (var repo = new Repository("Path/to/your/repo"))
{
    var commitIdToTagLookup = CreateCommitIdToTagLookup(repo);

    foreach (var commit in repo.Commits)
    {
        foreach (var tag in commitIdToTagLookup[commit.Id])
        {
            Console.WriteLine($"Tag {tag.FriendlyName} points at {commit.Id}");
        }
    }
}