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 metadata提取的PDF元数据,如何转换为一个Excel
  • ¥15 关于arduino编程toCharArray()函数的使用
  • ¥100 vc++混合CEF采用CLR方式编译报错
  • ¥15 coze 的插件输入飞书多维表格 app_token 后一直显示错误,如何解决?
  • ¥15 vite+vue3+plyr播放本地public文件夹下视频无法加载
  • ¥15 c#逐行读取txt文本,但是每一行里面数据之间空格数量不同
  • ¥50 如何openEuler 22.03上安装配置drbd
  • ¥20 ING91680C BLE5.3 芯片怎么实现串口收发数据
  • ¥15 无线连接树莓派,无法执行update,如何解决?(相关搜索:软件下载)
  • ¥15 Windows11, backspace, enter, space键失灵