The final object left to cover is the tag. Strangely (or not, depending on your view of Git) there are two types of tags. There are lightweight tags which are almost like branches, but here I’ll introduce the tag object.
A tag is a shorthand way of naming an object, usually a commit, so it can be referred to easily. A tag object differs from a lightweight tag in that it is a complete object with an author, message, and date. It can also be cryptographically signed with GPG. Very much like a commit.
The obvious use for tags is to mark releases. v1.0, v1.7, etc. It’s easy to check out these commits by using the memorable name rather than the sha. Using the object tag is useful here if you need to sign these milestones.
Another use for tags is to mark points in code that you might want to go back to; such as before you embark on implementing a mad idea and just creating a separate branch isn’t enough. A tag object here is useful because you create the tag with a message explaining why you are creating the tag.
I sometimes use tags to park dead branches. If I’ve followed a line of development that I want to shelve, I create a tag at the tip of the branch and delete the branch. That way, when I look at the state of my repository, I don’t see these dead branches listed, but I can always go back to it by creating a branch from that tag.
You can create a branch based off a tag by using the normal
git checkout or
git branch commands:
git branch newBranch PreCrazy will create a new branch based on the commit pointed to by PreCrazy.
You can checkout a tag directly without creating a branch off it. But this creates a “detached head”. Usually HEAD points to a branch rather than to a commit directly, but when you check out a commit without creating a branch then HEAD points directly to a commit, and you will see a helpful message on the console to tell you what you have done. If you wish, you can always move back to a branch with
git checkout because those references still exist even though HEAD has moved. You can still add commits to the repository and they will form a chain, but since they are not on a branch, they are liable to be garbage collected away at some point and deleted.
Creating a tag object.
The simplest way to create a tag object is to create one with an inline message:
git tag v1.0 -m"Tagging version 1.0"
If a longer message is required use the
-a flag (shorthand for creating and annotated commit) instead and the default editor will come up making it easier to create a message.
git tag -a v1.0
These two examples create tags at the current head commit. But you can tag previous commits simply by passing in the sha of the commit
git tag -a v2.0 e34f77c
You can create tag objects for more than just commits, you can tag blobs and trees as well, just by passing in the sha of the blob or the tree. Why anyone would want to do this is beyond me. It isn’t as if you can check out a single file based on a tagged blob, although you could reference it’s contents. Maybe it can be used to cryptographically sign a file or a tree as coming from a particular source so verify it’s integrity.
Listing tag objects
git tag will list all the tags in the repository. If you mostly use version tagging, then the names will be self explanatory. You can further examine tags using
git cat-file -p <tagname> which I prefer to
git show <tagname> which also shows a diff. Graphical tools such as Gitk show tagged commits, but not tagged files or trees, so it’s worth using the command line options sometimes to see if there is anything else lurking.
A tag is a convenient way of assigning a shorthand name to a commit and marking significant points. A tag object allows for extra information to be added to this shorthand name, such as committer information, a message, or an electronic signature. Tag objects can also be assigned to git objects other than commits, such as blobs and trees.
There is more that I can write about tags and the other objects. It helps me a great deal when using git to know about how these building blocks combine to create a repository. Even though there are hundreds of ways of sending commands to git, they mostly just work on these objects. Keeping that in mind makes using Git less complex.