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 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 java 的protected权限 ,问题在注释里
  • ¥15 这个是哪里有问题啊?