Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
944 views
in Technique[技术] by (71.8m points)

git tag - Why isn't my tag listed when I checkout with Git GUI?

I have a local Git repository with three annotated tags: v0.1.0, v0.1.1, and v0.1.2.

When I view my project's history with gitk (Repository → Visualize master's history), I can see each tag assigned to the proper commit.

Project history in gitk

However, when I try to checkout my tags in Git GUI (Branch → Checkout... → Tags), the tag for v0.1.1 doesn't appear.

Git GUI tag list

When I went to check each tag in gitk, I noticed that the details for v0.1.0 and v0.1.2 listed them as type commit, while the tag for v0.1.1 was listed as type tag.

Details for tag v0.1.1

It's worth noting that I've rewritten history on this tag to fix a typo. I edited my tag message using git tag <tag name> <tag name> -f -m "<new message>".

Why can't I see my v0.1.1 tag when checking out with Git GUI? Why does it appear as type tag?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Tags can point to any object in the git repository. If your tag type is "tag", then you have a tag pointing to another tag.

Lightweight tags are not objects; thus, they have no hash ID of their own and nothing else (like another tag) can point to them. They are literally just easy-to-remember names pointing to some object's hash ID, a little less than a branch name.

However, annotated tags are objects; they are like commits, with their own message, author, created date and, most importantly, their own hash ID. This means that, somewhat confusingly, they can be tagged.

Sure enough, as you described in your comment, this is exactly what happened. Acting on the advice found in How do you rename a Git tag?, you did the following:

# avoid this...
git tag new old

Since old was an annotated tag, the target for the new tag will be the old tag, not the commit that it was pointing to.

If you want to rename an annotated tag, you should use

git tag -a new old^{}

old^{} will dereference the tag recursively until a non-tag object is found (in our case, a commit), and use that as the target object for new.


To further illustrate: let's say you have a repo... oh, like this one: https://github.com/cyborgx37/sandbox/releases

In this repo you create an annotated tag like so:

> git tag -m "Version 0.1-beat" v0.1

Oh shoot... you misspelled "beta" and also you've decided that you want the tag name to be v0.1-b. Since this has already been published, you decide to do the sane thing and just create a new tag. Following advice you found on the internet, you create the tag you actually wanted (I appended __tag for reasons that will become clear) by copying the first tag:

> git tag -m "Version 0.1-beta" v0.1-b__tag v0.1

Only, these are annotated tags, meaning they are actual objects. So when you created v0.1-b__tag, you actually pointed it at v0.1. You can see the result clearly using cat-file and show.

Here's v0.1:

> git cat-file -p v0.1

object 5cf4de319291579d4416da8e0eba8a2973f8b0cf
type commit
tag v0.1
tagger JDB <[email protected]> 1521058797 -0400

Version 0.1-beat
> git show v0.1

tag v0.1
Tagger: JDB <[email protected]>
Date:   Wed Mar 14 16:19:57 2018 -0400

Version 0.1-beat

commit 5cf4de319291579d4416da8e0eba8a2973f8b0cf (HEAD -> master, tag: v0.1-b__tag, tag: v0.1, origin/master)
Author: JDB <[email protected]>
Date:   Tue Oct 10 12:17:00 2017 -0400

    add gitignore

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..42d9955
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+file.txt

Notice that v0.1-b__tag is different both in its target type as well as its history:

> git cat-file -p v0.1-b__tag

object 889b82584b2294486f4956dfea17b05e6224fb7f
type tag
tag v0.1-b__tag
tagger JDB <[email protected]> 1521059058 -0400

Version 0.1-beta
> git show v0.1-b__tag

tag v0.1-b__tag
Tagger: JDB <[email protected]>
Date:   Wed Mar 14 16:24:18 2018 -0400

Version 0.1-beta

tag v0.1
Tagger: JDB <[email protected]>
Date:   Wed Mar 14 16:19:57 2018 -0400

Version 0.1-beat

commit 5cf4de319291579d4416da8e0eba8a2973f8b0cf (HEAD -> master, tag: v0.1-b__tag, tag: v0.1, origin/master)
Author: JDB <[email protected]>
Date:   Tue Oct 10 12:17:00 2017 -0400

    add gitignore

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..42d9955
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+file.txt

Apparently Git GUI is rather selective about what types of objects can be checked out (commits, not tags), so it's ignoring your tag pointing at another tag.

If you use the git tag -a new old^{} approach I suggested above, you can avoid the drama and get what you wanted in the first place. I'll create a new tag, v0.1-b__commit that points to v0.1's commit, rather than to v0.1 directly:

> git tag -m "Version 0.1-beta" v0.1-b__commit v0.1^{}
> git cat-file -p v0.1-b__commit

object 5cf4de319291579d4416da8e0eba8a2973f8b0cf
type commit
tag v0.1-b__commit
tagger JDB <[email protected]> 1521059039 -0400

Version 0.1-beta
> git show v0.1-b__commit

tag v0.1-b__commit
Tagger: JDB <[email protected]>
Date:   Wed Mar 14 16:23:59 2018 -0400

Version 0.1-beta

commit 5cf4de319291579d4416da8e0eba8a2973f8b0cf (HEAD -> master, tag: v0.1-b__tag, tag: v0.1-b__commit, tag: v0.1, origin/master)
Author: JDB <[email protected]>
Date:   Tue Oct 10 12:17:00 2017 -0400

    add gitignore

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..42d9955
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+file.txt

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...