【问题标题】:What's the fastest way to find Tags pointing to Commits?找到指向提交的标签的最快方法是什么?
【发布时间】:2013-11-17 11:04:29
【问题描述】:

使用 libgit2sharp 我想做以下事情:

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

我想获取分配给当前提交的所有标签。最好的方法是什么?遍历所有标签,看看是否tag.Target.Sha == commit.Sha?那不是很高效。还有其他方法吗?

【问题讨论】:

    标签: libgit2 libgit2sharp


    【解决方案1】:

    所以我想获取分配给当前提交的所有标签。最好的方法是什么?遍历所有标签,看看是否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;
    }
    

    【讨论】:

    • 非常感谢 - 这非常有效。应该是 LibGit2Sharps 的 Commit-Object 本身的一部分。
    【解决方案2】:

    这是 nulltoken 答案的另一个版本,但使用 ILookupclass 而不是字典。更好一点的国际海事组织:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-24
      • 1970-01-01
      • 2010-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多