all repos — legit @ d0c522021ad5e7b85dbfbadfc546676c80d4b99d

web frontend for git, written in go

git: show lightweight annotated tags (#42)

The "TagObjects" function only returns annotated tags (the ones created
with "-a"). Git interpretes lightweight and annotated tags[^1]
differently, so we need to query all reference and check which one have
a tag object attached.

[^1]: https://git-scm.com/book/en/v2/Git-Basics-Tagging
Gabriel mail@gabrielgio.me
Fri, 04 Oct 2024 17:52:56 +0200
commit

d0c522021ad5e7b85dbfbadfc546676c80d4b99d

parent

4447fcda1f06f4d516dfd40e3d306da193aaeeae

1 files changed, 75 insertions(+), 23 deletions(-)

jump to
M git/git.gogit/git.go

@@ -19,7 +19,18 @@ r *git.Repository

h plumbing.Hash } -type TagList []*object.Tag +type TagList struct { + refs []*TagReference + r *git.Repository +} + +// TagReference is used to list both tag and non-annotated tags. +// Non-annotated tags should only contains a reference. +// Annotated tags should contain its reference and its tag information. +type TagReference struct { + ref *plumbing.Reference + tag *object.Tag +} // infoWrapper wraps the property of a TreeEntry so it can export fs.FileInfo // to tar WriteHeader

@@ -31,17 +42,42 @@ modTime time.Time

isDir bool } -func (self TagList) Len() int { - return len(self) +func (self *TagList) Len() int { + return len(self.refs) } -func (self TagList) Swap(i, j int) { - self[i], self[j] = self[j], self[i] +func (self *TagList) Swap(i, j int) { + self.refs[i], self.refs[j] = self.refs[j], self.refs[i] } // sorting tags in reverse chronological order -func (self TagList) Less(i, j int) bool { - return self[i].Tagger.When.After(self[j].Tagger.When) +func (self *TagList) Less(i, j int) bool { + var dateI time.Time + var dateJ time.Time + + if self.refs[i].tag != nil { + dateI = self.refs[i].tag.Tagger.When + } else { + c, err := self.r.CommitObject(self.refs[i].ref.Hash()) + if err != nil { + dateI = time.Now() + } else { + dateI = c.Committer.When + } + } + + if self.refs[j].tag != nil { + dateJ = self.refs[j].tag.Tagger.When + } else { + c, err := self.r.CommitObject(self.refs[j].ref.Hash()) + if err != nil { + dateJ = time.Now() + } else { + dateJ = c.Committer.When + } + } + + return dateI.After(dateJ) } func Open(path string, ref string) (*GitRepo, error) {

@@ -116,31 +152,36 @@ return "Not displaying binary file", nil

} } -func (g *GitRepo) Tags() ([]*object.Tag, error) { - ti, err := g.r.TagObjects() +func (g *GitRepo) Tags() ([]*TagReference, error) { + iter, err := g.r.Tags() if err != nil { return nil, fmt.Errorf("tag objects: %w", err) } - tags := []*object.Tag{} + tags := make([]*TagReference, 0) - _ = ti.ForEach(func(t *object.Tag) error { - for i, existing := range tags { - if existing.Name == t.Name { - if t.Tagger.When.After(existing.Tagger.When) { - tags[i] = t - } - return nil - } + if err := iter.ForEach(func(ref *plumbing.Reference) error { + obj, err := g.r.TagObject(ref.Hash()) + switch err { + case nil: + tags = append(tags, &TagReference{ + ref: ref, + tag: obj, + }) + case plumbing.ErrObjectNotFound: + tags = append(tags, &TagReference{ + ref: ref, + }) + default: + return err } - tags = append(tags, t) return nil - }) + }); err != nil { + return nil, err + } - var tagList TagList - tagList = tags + tagList := &TagList{r: g.r, refs: tags} sort.Sort(tagList) - return tags, nil }

@@ -290,3 +331,14 @@

func (i *infoWrapper) Sys() any { return nil } + +func (t *TagReference) Name() string { + return t.ref.Name().Short() +} + +func (t *TagReference) Message() string { + if t.tag != nil { + return t.tag.Message + } + return "" +}