1. Introduction
Git provides many features to support its main task of version tracking. One way to categorize commits into a secondary structure is Git tagging. Effectively, the use of tags enables a more human-readable name to be assigned as a ref (reference) to a commit instead of its commit identifier (ID).
In this tutorial, we explore ways to use the tag subcommand for listing and filtering tags. First, we briefly refresh our knowledge about a simple way to show all tags. After that, we turn to Git output formatting with the main example of tags. Finally, we show some advanced filtering when listing tags.
We tested the code in this tutorial on Debian 12 (Bookworm) with GNU Bash 5.2.15. Unless otherwise specified, it should work in most POSIX-compliant environments.
2. Tag Listing
The tag subcommand provides a way to –list all tags irrespective of their relationship to the commit tree:
$ git tag --list
antag
major
minor
xavier
This feature can be useful when working with automated scripts. In many cases, we can –ignore-case when working with sorting and filters and use –color as appropriate.
However, sometimes, we may want to show more information about tags or exclude some of them from the results. To that end, we employ the –list flag of the tag subcommand in many of the following general examples.
3. Git Output Formatting
Git provides many ways to format output that aren’t necessarily specific to a given object type. Here, we use tags for demonstration purposes, but the options apply to other objects, such as branches and commits as well.
3.1. Output Format
One of the most fundamental ways to augment any Git output is the –format option. It enables the specification of a format string, according to which the results are structured.
To understand the option better, let’s format the output of a tag list:
$ git tag --list --format='%(refname)'
refs/tags/tag1
refs/tags/tag10
refs/tags/tag11
refs/tags/tag12
refs/tags/tag13
[...]
Specifiers (or fields) are surrounded by () parentheses, prefixed by a % percent sign. In the context of a –format string, Git interpolates such expressions, expanding them to their respective result.
In this case, we use the refname specifier, which shows the full tag ref path. Further, refname supports modifiers in the form of suffixes:
- :short gets the minimal non-ambiguous ref name
- [l|r]strip=
strips a given number of characters on the left or right
There are other field names and modifiers:
+---------------------+--------------------------------------------------------------------------+
| Field (Specifier) | Description |
+---------------------+--------------------------------------------------------------------------+
| refname | name of ref as path |
| | :short, :[l|r]strip=<N> |
+---------------------+--------------------------------------------------------------------------+
| objecttype | object type such as blob, tree, commit, tag |
+---------------------+--------------------------------------------------------------------------+
| objectsize | object size |
| | :disk |
+---------------------+--------------------------------------------------------------------------+
| objectname | object name (SHA-1) |
| | :short |
+---------------------+--------------------------------------------------------------------------+
| deltabase | if stored as delta, the delta base, else null object |
+---------------------+--------------------------------------------------------------------------+
| upstream | show upstream of ref |
| | :short, :[l|r]strip=<N>, :trackshort, :track, :remotename, :remoteref |
+---------------------+--------------------------------------------------------------------------+
| push | local ref that is push for displayed ref |
| | :short, :[l|r]strip=<N>, :trackshort, :track, :remotename, :remoteref |
+---------------------+--------------------------------------------------------------------------+
| HEAD | * if HEAD is current ref |
+---------------------+--------------------------------------------------------------------------+
| color | change color |
| | :<COLOR_NAME> |
+---------------------+--------------------------------------------------------------------------+
| align | align text |
| | :width, :position |
+---------------------+--------------------------------------------------------------------------+
| if, then, else, end | conditionals |
| | :<CONDITION> |
+---------------------+--------------------------------------------------------------------------+
| symref | resolve symbolic ref |
| | :short, :[l|r]strip=<N> |
+---------------------+--------------------------------------------------------------------------+
| signature | signature |
| | :grade, :signer, :key, :fingerprint, :primarykeyfingerprint, :trustlevel |
+---------------------+--------------------------------------------------------------------------+
| worktreepath | absolute path to worktree of checked-out ref |
+---------------------+--------------------------------------------------------------------------+
| ahead-behind | commit distance to given commit |
| | :<COMMIT> |
+---------------------+--------------------------------------------------------------------------+
| describe | general details |
| | :tags, :abbrev, :match, :exclude |
+---------------------+--------------------------------------------------------------------------+
| raw:size | raw data size |
+---------------------+--------------------------------------------------------------------------+
| contents | message details |
| | :size, :subject, :body, :signature, :lines=<N> |
+---------------------+--------------------------------------------------------------------------+
Notably, some fields are special operator specifiers such as if, align, and color.
3.2. –column View
Many Git commands employ the –column option for formatting their output as columns instead of lists.
Let’s demonstrate with the tag subcommand.
For example, we can get the list of tags filling column by column, which is the default in most cases:
$ git tag --list --column=column
tag1 tag14 tag19 tag23 tag28 tag32 tag37 tag41 tag46 tag50 tag55 tag6 tag64 tag9
tag10 tag15 tag2 tag24 tag29 tag33 tag38 tag42 tag47 tag51 tag56 tag60 tag65
tag11 tag16 tag20 tag25 tag3 tag34 tag39 tag43 tag48 tag52 tag57 tag61 tag66
tag12 tag17 tag21 tag26 tag30 tag35 tag4 tag44 tag49 tag53 tag58 tag62 tag7
tag13 tag18 tag22 tag27 tag31 tag36 tag40 tag45 tag5 tag54 tag59 tag63 tag8
Alternatively, we can fill going [row]s-first:
$ git tag --list --column=row
tag1 tag10 tag11 tag12 tag13 tag14 tag15 tag16 tag17 tag18 tag19 tag2 tag20 tag21
tag22 tag23 tag24 tag25 tag26 tag27 tag28 tag29 tag3 tag30 tag31 tag32 tag33 tag34
tag35 tag36 tag37 tag38 tag39 tag4 tag40 tag41 tag42 tag43 tag44 tag45 tag46 tag47
tag48 tag49 tag5 tag50 tag51 tag52 tag53 tag54 tag55 tag56 tag57 tag58 tag59 tag6
tag60 tag61 tag62 tag63 tag64 tag65 tag66 tag7 tag8 tag9
Other options dictate when to use columns, provide ways to make the output more –dense, and others.
3.3. –sort Names
Since automated processing may require a certain order, some Git commands make use of the –sort option to augment their output respectively.
To demonstrate, let’s check the default tag order:
$ git tag --list
tag1
tag10
tag11
tag12
tag13
[...]
This is a basic ascending alphanumeric sort. Adding a – prefix reverses the order.
Now, we can employ a –sort by author:
$ git tag --list --sort=author
tag1
tag3
tag7
tag9
tag11
[...]
This way, we get the tags in groups by the author key. Internally, each group uses alphanumeric sorting.
Notably, other keys we can use are committerdate and even v:refname:
$ git tag --list --sort=v:refname
tag1
tag2
tag3
tag4
tag5
To further sort by several keys, we can specify –sort multiple times.
4. Tag Filtering
In addition to the regular output formatting options, the tag subcommand provides tag-specific filters.
4.1. Tag –points-at Object
Although we can use log and other subcommands for the purpose, the –points-at option provides a more concise way of getting the objects that a tag points to.
Let’s see it in action:
$ git tag --list --points-at 1add4face0666a430100e7737dd1a56c8914cdd0
tag1
In this case, we see only tag1 points at commmit 1add4face0666a430100e7737dd1a56c8914cdd0.
4.2. Tag –contains or –no-contains Commit
While we can see which tags a commit has, we might also want to list only tags that relate to a given commit in a certain way.
For instance, to get all tags that are reachable from a given commit, we use –contains:
$ git tag --list --contains 1add4face0666a430100e7737dd1a56c8914cdd0
tag1
tag11
tag21
tag31
tag41
Similarly, we can exclude a given commit via –no-contains:
$ git tag --list --no-contains 1add4face0666a430100e7737dd1a56c8914cdd0
tag12
tag13
tag14
tag15
tag16
[...]
In fact, we can omit the –list flag since both of the above options imply it.
4.3. View –merged and –no-merged Tags
When merging commits, one of them might have a tag association. Merged tags are the outcome of commit merges, where the tag remains on the new commit after the merge.
For example, if we merge a secondary branch into the main or master branch, the tags from that branch should remain.
So, –merged only shows tags that were part of a merge, while –no-merged excludes such tags.
Notably, a rebase rewrites history, so tags on any squashed or omitted commits are lost.
5. Summary
In this article, we talked about Git formatted output and filtering with the main example of tags.
In conclusion, knowing how to display tags in a structured manner based on criteria can be helpful when performing simple checks, debugging, and automating tasks.