Haimantika Mitra
Haimantika Mitra

Reputation: 119

How to get the git tags for a particular hash in go using go-git package to get an output similar to git describe --tags --always

I am using the go-git package to get the tags, on using the function "TagObject", it is returning null. How should I write it?

Actual file:

hashCommit, _ := r.Head()
tagObj, _ := r.TagObject(hashCommit.Hash())

Test file:

tags, err := testAppDir.Tags()
                    h.AssertNil(t, err)
                    tags.ForEach(func(t *plumbing.Reference) error {
                        fmt.Println("the tag inside test", t)
                        return nil
                    })

How do I get the tags in my actual file? Error:

  - "describe": string(""),
 + "describe": (*object.Tag)(nil)

Upvotes: 3

Views: 3326

Answers (1)

NuLo
NuLo

Reputation: 1528

I think this will work for that particular case.

Since tags have a reference to the commit they tagged but there is no reference back, the getTags function returns a map that inverts that relation and allows us to find the tag that is attached to a commit (note that it is assumed that there is only one tag for a commit which may not be true).

We then take that map and see if the head has a tag and if so print it. Otherwise we'll go through the log starting on the head and searching for the first tagged commit. If we find any we'll print the tag and a short version of the commit (there doesn't seem to be a method to get a reliable short hash so I took the first 8 chars)

Finally if nothing is found the short hash is printed using the method described before.

This is a naive implementation that may have problems with repositories with a large amount of tags.

Please note that I used an updated version of go-git.

package main

import (
    "errors"
    "fmt"
    "github.com/go-git/go-git/v5"
    "github.com/go-git/go-git/v5/plumbing"
    "io"
    "log"
)

func getTags(r *git.Repository) (map[plumbing.Hash]string, error) {
    tags := make(map[plumbing.Hash]string)

    iter, err := r.Tags()
    if err != nil {
        return nil, err
    }

    for {
        ref, err := iter.Next()
        if errors.Is(err, io.EOF) {
            break
        }
        if err != nil{
            return nil, err
        }
        tags[ref.Hash()] = ref.Name().Short()

    }
    return tags, nil
}

func main() {
    appPath := "" 
    r, err := git.PlainOpen(appPath)

    if err != nil {
        log.Fatal(err)
    }
    hashCommit, err := r.Head()
    if err != nil {
        log.Fatal("head", err)
    }
    fmt.Println("hash", hashCommit)

    tags, err := getTags(r)

    // check if last commit is tagged
    if str, ok := tags[hashCommit.Hash()]; ok {
        fmt.Println(str)
        return
    }

    // check if any commit is tagged
    cIter, err := r.Log(&git.LogOptions{From: hashCommit.Hash()})
    for {
        commit, err := cIter.Next()
        if errors.Is(err, io.EOF) {
            break
        }
        if err != nil{
            log.Fatal(err)
        }

        if str, ok := tags[commit.Hash]; ok {
            fmt.Printf("%s-%s\n", str, hashCommit.Hash().String()[:8])
            return
        }
    }

    fmt.Println(hashCommit.Hash().String()[:8])
}

Upvotes: 3

Related Questions