doubenggua9430 2019-09-16 09:47
浏览 487
已采纳

获取特定分支的标签

Using go-git : is there a way to get only (lightweight and annotated) tags of a specific branch ?

As I’m mainly interested in the tags of the master branch, something like git tag --merged would be sufficient too.

It doesn’t seem to be possible with the basic go-git methods like Tags()...

  • 写回答

1条回答 默认 最新

  • doushan2311 2019-09-17 15:24
    关注

    Not exactly a short solution, but the following code achieved the goal by:

    1. Read the commit hashes of the entire branch.
    2. Read all the tags of the repository.
    3. Check and only print the tag of which the hash is in the branch.

    Note: Didn't try with annotated tag yet. But it should be close.

    package main
    
    import (
        "log"
    
        "github.com/src-d/go-billy/memfs"
        "gopkg.in/src-d/go-git.v4"
        "gopkg.in/src-d/go-git.v4/plumbing"
        "gopkg.in/src-d/go-git.v4/plumbing/object"
        "gopkg.in/src-d/go-git.v4/storage/memory"
    )
    
    func getBranchHashes(repo *git.Repository, branchName string) (hashes map[plumbing.Hash]bool, err error) {
    
        // get branch reference name
        branch, err := repo.Branch("master")
        if err != nil {
            return
        }
    
        // get reference of the reference name
        ref, err := repo.Reference(branch.Merge, true)
        if err != nil {
            return
        }
    
        // retrieve logs from the branch reference commit
        // (default order is depth first)
        logs, err := repo.Log(&git.LogOptions{
            From: ref.Hash(),
        })
        if err != nil {
            return
        }
        defer logs.Close()
    
        // a channel to collect all hashes
        chHash := make(chan plumbing.Hash)
        chErr := make(chan error)
        go func() {
            err = logs.ForEach(func(commit *object.Commit) (err error) {
                chHash <- commit.Hash
                return
            })
            if err != nil {
                chErr <- err
            }
            close(chErr)
            close(chHash)
        }()
    
        // make all hashes into a map
        hashes = make(map[plumbing.Hash]bool)
    hashLoop:
        for {
            select {
            case err = <-chErr:
                if err != nil {
                    return
                }
                break hashLoop
            case h := <-chHash:
                hashes[h] = true
            }
        }
        return
    }
    
    type TagRef struct {
        Hash plumbing.Hash
        Name string
    }
    
    func main() {
        // Filesystem abstraction based on memory
        fs := memfs.New()
    
        // Git objects storer based on memory
        storer := memory.NewStorage()
    
        // Clones the repository into the worktree (fs) and storer all the .git
        // content into the storer
        repo, err := git.Clone(storer, fs, &git.CloneOptions{
            URL: "https://github.com/yookoala/gofast.git",
        })
        if err != nil {
            log.Fatal(err)
        }
    
        hashes, err := getBranchHashes(repo, "master")
        if err != nil {
            log.Fatal(err)
        }
    
        // get all tags in the repo
        tags, err := repo.Tags()
        if err != nil {
            log.Fatal(err)
        }
    
        tagRefs := make(chan TagRef)
        go func() {
            err = tags.ForEach(func(ref *plumbing.Reference) (err error) {
                if annotedTag, err := repo.TagObject(ref.Hash()); err != plumbing.ErrObjectNotFound {
                    if annotedTag.TargetType == plumbing.CommitObject {
                        tagRefs <- TagRef{
                            Hash: annotedTag.Target,
                            Name: ref.Name().Short(),
                        }
                    }
                    return nil
                }
                tagRefs <- TagRef{
                    Hash: ref.Hash(),
                    Name: ref.Name().Short(),
                }
                return
            })
            if err != nil {
                log.Fatal(err)
            }
    
            close(tagRefs)
        }()
    
        for tagRef := range tagRefs {
            if _, ok := hashes[tagRef.Hash]; ok {
                log.Printf("tag: %s, hash: %s", tagRef.Name, tagRef.Hash)
            }
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥30 seata使用出现报错,其他服务找不到seata
  • ¥35 引用csv数据文件(4列1800行),通过高斯-赛德尔法拟合曲线,在选取(每五十点取1点)数据,求该数据点的曲率中心。
  • ¥20 程序只发送0X01,串口助手显示不正确,配置看了没有问题115200-8-1-no,如何解决?
  • ¥15 Google speech command 数据集获取
  • ¥15 vue3+element-plus页面崩溃
  • ¥15 像这种代码要怎么跑起来?
  • ¥15 安卓C读取/dev/fastpipe屏幕像素数据
  • ¥15 pyqt5tools安装失败
  • ¥15 mmdetection
  • ¥15 nginx代理报502的错误