gitgit-taggit-gui

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?


Solution

  • 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 # ⇦ v0.1 is a tag which points to a commit
    tag v0.1
    tagger JDB <jd@domain.com> 1521058797 -0400
        
    Version 0.1-beat
    
    > git show v0.1
    
    # v0.1 is a tag
    # ⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩
    
    tag v0.1
    Tagger: JDB <jd@domain.com>
    Date:   Wed Mar 14 16:19:57 2018 -0400
    
    Version 0.1-beat
    
    # which is pointing directly to a commit
    # ⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩
    
    commit 5cf4de319291579d4416da8e0eba8a2973f8b0cf (HEAD -> master, tag: v0.1-b__tag, tag: v0.1, origin/master)
    Author: JDB <jd@domain.com>
    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 # ⇦ v0.1-b__tag is a tag which points to a tag
    tag v0.1-b__tag
    tagger JDB <jd@domain.com> 1521059058 -0400
    
    Version 0.1-beta
    
    > git show v0.1-b__tag
    
    # v0.1-b__tag is a tag
    # ⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩
    
    tag v0.1-b__tag
    Tagger: JDB <jd@domain.com>
    Date:   Wed Mar 14 16:24:18 2018 -0400
    
    Version 0.1-beta
    
    # which is pointing to the v0.1 tag
    # ⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩
    
    tag v0.1
    Tagger: JDB <jd@domain.com>
    Date:   Wed Mar 14 16:19:57 2018 -0400
    
    Version 0.1-beat
    
    # which is pointing to the intended target commit
    # ⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩⇩
    
    commit 5cf4de319291579d4416da8e0eba8a2973f8b0cf (HEAD -> master, tag: v0.1-b__tag, tag: v0.1, origin/master)
    Author: JDB <jd@domain.com>
    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 <jd@domain.com> 1521059039 -0400
    
    Version 0.1-beta
    
    > git show v0.1-b__commit
    
    tag v0.1-b__commit
    Tagger: JDB <jd@domain.com>
    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 <jd@domain.com>
    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