77

I need Git command to get/find last tag starting with 'v' to get last versioning commit (I am using tags with v letter at the beginning to tag next application version (example: v0.9.1beta).

Is there any way to do it?

Lukasz
  • 19,816
  • 17
  • 83
  • 139

9 Answers9

98

Use the following command:

git describe --tags --match="v[0-9]*" HEAD

It will also modify the version if you did something with the source tree since your last versioned tag.

NOTE: --match accepts a glob, not a regex, and therefore the command shown may match other tags, e.g. v1234_this_matches_too.

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
KARASZI István
  • 30,900
  • 8
  • 101
  • 128
  • 13
    If you want just the tag use the "short output" with `--abbrev=0`. – Kevin Cox Aug 17 '13 at 02:11
  • 11
    The [`git describe` doc](https://git-scm.com/docs/git-describe) says that `--match` takes a glob, not a regex. – Craig McQueen Oct 28 '16 at 04:51
  • 2
    @CraigMcQueen that is a glob, and that's why it is working and filters out `v1.0.0` and not only `v1234`. I added a note to clarify that. – KARASZI István Oct 28 '16 at 07:36
  • In case one really needs a RegEx, I added [another answer](https://stackoverflow.com/a/42131335/321973) – Tobias Kienzler Feb 09 '17 at 08:15
  • 3
    The question is asking to find the last *tag* matching the pattern. So I think `--tags` must be added at the end. Otherwise only annotated tags will be shown. – rineez Oct 24 '18 at 06:49
17
git tag -l -n v*
racerror
  • 1,599
  • 8
  • 9
  • 2
    It lists all tag matching criteria. I need only last one, so git describe --match v*. Anyway thanks for hints as tags and describe command are linked together on the git manual pages. – Lukasz Oct 05 '10 at 21:17
  • this worked for me, as `git describe` wasn't flexible enough (returned an ugly tag, and wasn't always the most recent). `git tag --list --sort=-version:refname "v*" | head -n 1` – Red Twoon Dec 15 '20 at 20:40
14

The problem with using git describe as the other answers do is that git describe will show you tags that are reachable from HEAD (or the commit you specify.)

Imagine you have 3 tags, v1, v2, and v3. If HEAD is at a point between v2 and v3, git describe would return v2 rather than v3.

If you actually want the latest tag, first of all you need annotated tags as lightweight tags have no date metadata.

Then this command will do it:

git for-each-ref --sort=-taggerdate --count=1 refs/tags/v*

Joe Alcorn
  • 143
  • 1
  • 5
12

Also with git describe you could get the latest tag not just reachable from HEAD with :

git describe --match "v*" --abbrev=0 --tags $(git rev-list --tags --max-count=1)

Barthelemy Pavy
  • 520
  • 3
  • 7
7

KARASZI István's answer already explains how to find tags matching a glob, which is usually fine enough. Should you ever need a real RegEx though:

for tag in $(git tag | grep YOURREGEX); do
    git describe --tags --long --match="$tag" 2>/dev/null
done | sort -k2 -t"-" | head -n1
  • If you only want the nearest tag (i.e. what --abrev=0 would achieve), append | cut -d"-" -f1
  • If you don't want --long's behaviour of also outputting an exactly matching tag including the -0-hash part, append | sed -e's/-0-.*$//' instead.

The question's example tag would probably use a Regex ^v\d+\.\d+\.\d+\D*$ (though the \D*$ might be optional).

Tobias Kienzler
  • 25,759
  • 22
  • 127
  • 221
  • ...though this is obviously worse in terms of performance, since `git describe` is run for _each_ tag matching the RegEx. – Tobias Kienzler Feb 09 '17 at 08:22
  • 2
    For my usecase (see regex) with inconsistent tag naming (with or without prefix) this helped a lot, and only uses one execution of git describe. `git describe --abbrev=0 --tags --match="*$(git tag | grep -E "^(releases?\/|v)?[0-9]+\.[0-9]+\.[0-9]+$" | sed -E 's/.*([0-9]+\.[0-9]+\.[0-9]+)$/\1/' | sort -V -r | head -n 1)"`. Maybe this helps for similar further usecases. – qwc Jan 12 '21 at 09:50
  • @qwc thanks, the command helped me to get the latest git tag with certain features. – Shassain Sep 16 '21 at 23:31
  • @qwc thanks, the command is working, but can you provide us a brief explaination about your command so that we can use in other use cases as well. – Madhan Nov 04 '21 at 06:54
  • @Madhan I guess my answer deserves an edit when I have some time, please ping me if I forget to do so by next week ;) – Tobias Kienzler Nov 05 '21 at 07:29
6

While a single pattern --match "v[0-9]*" is enough here, know that Git 2.13 (Q2 2017) will improve that:

"git describe" and "git name-rev" have been taught to take more than one refname patterns to restrict the set of refs to base their naming output on, and also learned to take negative patterns to name refs not to be used for naming via their "--exclude" option.

See commit 77d21f2, commit 43f8080, commit 96415b4, commit 290be66, commit 4a68748 (18 Jan 2017) by Jacob Keller (jacob-keller).
(Merged by Junio C Hamano -- gitster -- in commit 1b32498, 27 Feb 2017)

You now can have multiple match pattern:

--match <pattern>:

Only consider tags matching the given glob(7) pattern, excluding the "refs/tags/" prefix.
This can be used to avoid leaking private tags from the repository.

If given multiple times, a list of patterns will be accumulated, and tags matching any of the patterns will be considered.
Use --no-match to clear and reset the list of patterns.

And you have also an exclude pattern (or several) now!

--exclude <pattern>::

Do not consider tags matching the given glob(7) pattern, excluding the "refs/tags/" prefix.

This can be used to narrow the tag space and find only tags matching some meaningful criteria.
If given multiple times, a list of patterns will be accumulated and tags matching any of the patterns will be excluded.
When combined with --match a tag will be considered when it matches at least one --match pattern and does not match any of the --exclude patterns.
Use --no-exclude to clear and reset the list of patterns.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
1
git describe --match v*

Use this.

Chuck Norris
  • 15,207
  • 15
  • 92
  • 123
Lukasz
  • 19,816
  • 17
  • 83
  • 139
0

I use

git tag -l --format "%(objecttype) %(refname:short)" --sort=-version:refname --merged HEAD "v*"

git tag interprets the pattern as glob. So you cannot specify a full blown regex. Just use a minimal glob (v*) or even no glob at all. You will receive more than only one matching tag in sorted order (highest tag version first) and you will be able to regex the output afterwards.

Henning
  • 1,289
  • 2
  • 11
  • 25
-4

Something more complex would be along the lines of:

/v[0-9]+(\.[0-9]+).*/
Otieno Rowland
  • 2,182
  • 1
  • 26
  • 34
  • Have you looked at all the answers? An example of how to use the above string was already given like: git describe --match "/v[0-9]+(\.[0-9]+).*/" --abbrev=4 HEAD – Otieno Rowland Aug 07 '19 at 11:29
  • That is not working, cause --match parameter only supports glob patterns no regex patterns – qoomon Aug 07 '19 at 15:05
  • It worked for me, so most likely you are missing something or we have different versions of tools used. – Otieno Rowland May 12 '21 at 13:20