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)
            }
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器