ChatGPT解决这个技术问题 Extra ChatGPT

Show which git tag you are on?

I'm having trouble finding out which tag is currently checked out.

When I do:

git checkout tag1
git branch

I can't seem to find out which tag I'm on. It only logs:

* (no branch)
master

Is it possible to find out which tags are checked out? In the above example, this would be tag1.


T
Tim

Edit: Jakub Narębski has more git-fu. The following much simpler command works perfectly:

git describe --tags

(Or without the --tags if you have checked out an annotated tag. My tag is lightweight, so I need the --tags.)

original answer follows:

git describe --exact-match --tags $(git log -n1 --pretty='%h')

Someone with more git-fu may have a more elegant solution...

This leverages the fact that git-log reports the log starting from what you've checked out. %h prints the abbreviated hash. Then git describe --exact-match --tags finds the tag (lightweight or annotated) that exactly matches that commit.

The $() syntax above assumes you're using bash or similar.


Just using git describe would show tag name if you are exactly on (annotated) tag, or <tag>-<n>-g<shortened sha-1> if not, where <n> is number of commits since <tag>.
@Jakub - Thanks. I added --exact-match to my answer seconds before your comment. Nice to know that you can remove it and still get good info from fuzzier input.
Thanks, this was exactly what I was looking for. Btw, even git-describe --exact-match (without --tags) works for me.
Using git rev-parse HEAD is a better solution than git log -n1 --pretty='%h'... but why you cannot simply write HEAD (or nothing, as git describe defaults to HEAD)?
only Guybrush hates porcelain
M
M K

This worked for me git describe --tags --abbrev=0

Edit 2020: As mentioned by some of the comments below, this might, or might not work for you, so be careful!


Yes. this works even if you are not exactly on that tag! :)
Uhhh. ... If you checkout the hash three commits after the tag, you are not "on that tag." It tells you the last tag before or at the commit that's checked out. So this is incorrect.
Works on Windows too :)
Add --exact-match to this answer to only look at the current commit's tag.
G
George Pavelka

Show all tags on current HEAD (or commit)

git tag --points-at HEAD

Note that this command does not report an error at the command-line even if the result comes up empty. Bug? It also returns a list if there are multiple tags at that location. It's the best answer but scripters should proceed with caution keeping these caveats in mind.
Following @ingyhere's comment. Yes it's good information that it does not have an error, and people need to handle the result accordingly. But I wouldn't call it a bug. For my case, "empty if no tags" is valid. Other cases, someone can save it to a variable then check if it is empty (link to bash instructions)
That meas there are no tags pointing at current HEAD.
D
Daniel Serodio

git describe is a porcelain command, which you should avoid:

http://git-blame.blogspot.com/2013/06/checking-current-branch-programatically.html

Instead, I used:

git name-rev --tags --name-only $(git rev-parse HEAD)

It is returning "undefined"
This outputs a trailing ^0 for commits which correspond to tags (eg, for tag 1.0 it outputs 1.0^0). Is there any way of having Git output only 1.0, or should I use sed for this?
Just some conceptual nitpicking: I think you inverted the meanings of porcelain and plumbing. It's ok to use porcelain, it's high level and meant for normal use. Plumbing ist internal (as the name suggests) and is only not recommended because the git developers reserve the right to change their arguments and output without warning. So your first suggestion is actually the slightly more appropriate one.
The linked article says to avoid using "git branch" because it doesn't work for this use case. I can't think of any good reason to avoid using git describe. Like Leo says, "Porcelain" commands are the commands you are generally supposed to use. Avoid the plumbing commands unless you really know what you are doing. "git describe" works great.
"Porcelain" commands are the ones you should use, not the ones you should avoid. They are the commands whose output is machine readable and will not change in future versions, so can be relied upon in scripts etc. Non porcelain commands tend to produce more human-readable output, but it may change in future versions e.g. to make it more readable, not because something important has actually changed.
m
mipadi

When you check out a tag, you have what's called a "detached head". Normally, Git's HEAD commit is a pointer to the branch that you currently have checked out. However, if you check out something other than a local branch (a tag or a remote branch, for example) you have a "detached head" -- you're not really on any branch. You should not make any commits while on a detached head.

It's okay to check out a tag if you don't want to make any edits. If you're just examining the contents of files, or you want to build your project from a tag, it's okay to git checkout my_tag and work with the files, as long as you don't make any commits. If you want to start modifying files, you should create a branch based on the tag:

$ git checkout -b my_tag_branch my_tag

will create a new branch called my_tag_branch starting from my_tag. It's safe to commit changes on this branch.


Fantastic answer.
c
chriswatrous

git log --decorate

This will tell you what refs are pointing to the currently checked out commit.


s
snazzybouche

Here's a fun one for a certain set of use cases. If your repository has versions such as v1.0.0, v1.1.0, v1.1.1 etc, and also shorthand versions such as v1 that point to whatever is the latest v1.x.x, the following will give you a reference to the currently-checked-out commit in relation to the most recent fully versioned tag, with fallbacks if that doesn't work:

git describe --tags --exact-match --match "v*.*.*" \
  || git describe --match "v*.*.*" --tags \
  || git describe --tags \
  || git rev-parse HEAD

So let's say you have the following commits:

* 4444444 (main, origin/main, tag: v2.0.0, tag: v2.0, tag: v2)
* 3333333
* 2222222 (tag: v1.1.0, tag: v1.1, tag: v1)
* 1111111 (tag: v1.0.0, tag: v1.0)
* 0000000

Output of the above command for a few example HEADs:

git checkout main -> v2.0.0

git checkout 3333333 -> v1.1.0-1-g3333333

git checkout 2222222 -> v1.1.0

git checkout v1 -> v1.1.0

git checkout 0000000 -> 0000000 (full ref)