Все в курсе, что у git раковый UX, но даже он не перестает удивлять. Вот есть в репозитории теги:

$ git tag
v1
v2

Уже на этом этапе я обычно хочу написать tags, ну да ладно. Вот я хочу посмотреть список коммитов, на которые эти теги указывают. Берем первый ответ из гугла:

$ git show-ref --tags
1baddd8efa7f0afac329e16876d94fa54febef4f refs/tags/v1
24105f5ffeb2c93c8dd6f8f10ce0d1701e67a1cd refs/tags/v2

Вроде все логично, однако если сравнить этот вывод с историей:

$ git log --pretty=format:"%H %s"
0c4bd3ad8d403463fbdd6dda50bfe7834ecd2634 second commit
1baddd8efa7f0afac329e16876d94fa54febef4f first commit

То видна проблема — хэши не совпадают. Тут я должен вспомнить, что в git есть два вида тегов: обычные и аннотированные, в которых есть сообщение, автор и т.п.:

$ git for-each-ref refs/tags --format="%(refname:short) %(objecttype)"
v1 commit
v2 tag

Ладно, но как получить то, что я хотел? Для одного тега проще всего запомнить git show $tag, а вот для всего списка нужно всего лишь

$ git for-each-ref --format='%(if)%(*objectname)%(then)%(*objectname)%(else)%(objectname)%(end) %(refname:short)' refs/tags
1baddd8efa7f0afac329e16876d94fa54febef4f v1
0c4bd3ad8d403463fbdd6dda50bfe7834ecd2634 v2
24105f5ffeb2c93c8dd6f8f10ce0d1701e67a1cd v2.1 # oops!

Но даже этот метод (от мейнтейнера git, между прочим!) — неправильный, потому что аннотированные теги могут быть вложенными. Поэтому надо сделать

git tag | while read tag; do echo "$(git rev-parse $tag^{}) $tag"; done