Best way to get tags on a commit?
I have come up with the following solution. It is far from optimal. It reads all the tags in the repo just to find out the tags on one commit.
I feel there must be a better way but haven't figured it out yet from looking at the api docs.
If there is a much better approach for this I would be happy to submit an PR to the examples folder for it after.
import * as Git from "nodegit"
type TagWithCommits = {
commit: Git.Object
tags: Git.Reference[]
}
async function getTaggedCommits(
repo: Git.Repository,
): Promise<TagWithCommits[]> {
const refs: Git.Reference[] = await (repo.getReferences as any)()
const commitsWithTags: Record<string, TagWithCommits> = {}
for (const ref of refs) {
if (!ref.isTag()) continue
const commit = await ref.peel(Git.Object.TYPE.COMMIT)
const id = commit.id().tostrS()
let entry = commitsWithTags[id]
if (!entry) {
commitsWithTags[id] = entry = { tags: [], commit }
}
entry.tags.push(ref)
}
return Object.values(commitsWithTags)
}
async function getTagsOnCommit(c: Git.Commit): Promise<Git.Reference[]> {
const repo = c.owner()
const taggedCommits = await getTaggedCommits(repo)
const taggedCommit = taggedCommits.filter(
tc => tc.commit.id().tostrS() === c.id().tostrS(),
)
if (taggedCommit.length > 1) {
throw new Error(
"Found multiple tagged commit matches which should be impossible",
)
} else if (taggedCommit.length === 1) {
return taggedCommit[0].tags
} else {
return []
}
}
Git.Repository.open(".")
.then(async repo => {
const commit = await repo.getHeadCommit()
const tagsOnCommit = await getTagsOnCommit(commit)
if (tagsOnCommit.length) {
console.log(
"The current commit (%s) has tags: %s",
commit,
tagsOnCommit.map(r => r.shorthand()).join(", "),
)
} else {
console.log("The current commit (%s) has no tags", commit)
}
})
.catch(console.error)
With git CLI I would just do git tag --points-at HEAD.
I discovered https://github.com/steveukx/git-js and it seems that it would better serve my present needs. Will leave this issue open in case its of use to others.
Outside of switching to git-js, has anyone ever come up with a solution for this?
This library is lower level than I think is being expected here. Tags as stored in the .git repository are flat files that list what sha they point to. In order for git to run git tag --points-at HEAD, git has to internally walk the entire refs tree in the .git folder and read every entry and then parse which pont to the particular oid you asked it to check against. This solution is the only way for any git-like library to perform the action we're asking to do here.
I would be willing to accept a PR to NodeGit to wrap this behavior up as a convenience function though.
@implausible thanks for the explanation, will optimise my end.