Git
Git Tags
Version Control
Git Command Line
Software Development

How to list all tags along with the full message in git?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Listing Git tags is easy; listing each tag together with its full annotation message is slightly different. The key detail is that only annotated tags have their own message body, so the best tool is git for-each-ref rather than plain git tag.

Understand the difference between lightweight and annotated tags

Before choosing a command, make sure the repository actually stores tag messages.

  • lightweight tags are just named references to commits
  • annotated tags are full Git objects with metadata and a message

If a tag was created with git tag v1.2.0, there is usually no tag message to print. If it was created with git tag -a v1.2.0 -m "release notes", the message exists and Git can show it.

You can inspect the tag type with:

bash
git for-each-ref refs/tags --format='%(refname:short) %(objecttype)'

Entries with object type tag are annotated. Tags that resolve straight to a commit behave differently because there is no separate annotation object.

Use git for-each-ref for full message output

The most flexible command is:

bash
git for-each-ref refs/tags \
  --sort=-creatordate \
  --format='%(refname:short)%0a%(contents)%0a----'

This prints:

  • the short tag name
  • the tag contents
  • a separator line

%(contents) is the important placeholder. For annotated tags, it prints the full annotation text. For lightweight tags, it may be empty or fall back to commit-related content depending on the object.

If you also want the date:

bash
git for-each-ref refs/tags \
  --sort=-creatordate \
  --format='%(creatordate:short) %(refname:short)%0a%(contents)%0a----'

Showing one tag in detail

If you only need a single tag, git show is often easier to read:

bash
git show --no-patch v1.2.0

For an annotated tag, Git shows tagger metadata and the full message before the referenced commit. That makes it handy for manual inspection, but it is not the best format for scripting across many tags.

If you want the raw stored object:

bash
git cat-file -p v1.2.0

This is useful when you want to see exactly what Git stored inside the tag object.

Producing parseable output

Human-friendly output is not always automation-friendly. If you want stable delimiters, format the command more carefully:

bash
git for-each-ref refs/tags \
  --format='%(refname:short)|%(creatordate:iso8601)|%(contents:subject)'

Then a small script can split on | safely. For example:

python
1import subprocess
2
3cmd = [
4    "git",
5    "for-each-ref",
6    "refs/tags",
7    "--format=%(refname:short)|%(creatordate:iso8601)|%(contents:subject)",
8]
9
10output = subprocess.check_output(cmd, text=True)
11for line in output.splitlines():
12    tag, created, subject = line.split("|", 2)
13    print(tag, created, subject)

For full multi-line messages, choose a stronger separator than a single newline because tag bodies themselves can contain blank lines.

Creating tags so message listing works well

If your release process depends on readable tag messages, standardize on annotated tags:

bash
1git tag -a v2.3.0 -m "Release 2.3.0
2
3Adds retry logic for failed payments."
4git push origin v2.3.0

That gives future tooling something meaningful to display. Without annotation messages, the best any listing command can do is show the commit subject.

Common Pitfalls

The biggest mistake is expecting a full message from lightweight tags. They do not have one, so the command is not wrong when the output is empty.

Another issue is using git tag -n and assuming it prints the complete annotation. It usually prints only a summary line, which is useful for a quick scan but not for full release notes.

People also forget to sort the output. In large repositories, the default order may not match release chronology or semantic version order, so include an explicit sort field.

Finally, avoid scraping git show output in automation. git for-each-ref with custom placeholders is much more stable.

Summary

  • Use git for-each-ref when you want all tags with message content.
  • Full tag messages exist only for annotated tags.
  • '%(contents) prints the stored annotation text for annotated tags.'
  • 'git show is convenient for a single tag, while git for-each-ref is better for many tags.'
  • If tag messages matter to your workflow, create annotated tags consistently.

Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Basis Lab
No course covers this one yet

Basis Lab writes one for you from a sentence about what you want to be able to do, then teaches it and checks you understood. Your first course is free.

Build my course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions