Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between tag and commit message

I understand one always needs a message for committing the changes but when and why do I need to also tag a commit? Let's say I made some changes and I commit using

git add -A
git commit -m "add feature 1"

and now

git tag -a -m "includes feature 1" v0.1

The question is when does this make sense.

like image 857
Masoud Ghaderi Avatar asked Mar 21 '18 18:03

Masoud Ghaderi


People also ask

What is the difference between tag and commit?

When it is, a commit will automatically update the master reference to point to that new commit; in other words, branches are mutable references. A tag, on the other hand, is created to point to a specific commit and thereafter does not change, even if the branch moves on. In other words, tags are immutable references.

What is tag and commit in git?

The git commit is a 40-digit hexadecimal SHA1 hash. Quite often we need to bookmark a as the commit hash is difficult to memorize. This is where one can use tags. Tags can be used to name a commit. In other words, tags are labels that can be used to identify a specific commit.

Is a tag a commit?

Tagging is generally used to capture a point in history that is used for a marked version release (i.e. v1. 0.1). A tag is like a branch that doesn't change. Unlike branches, tags, after being created, have no further history of commits.

Do you tag before or after commit?

Usually, you want to name your tag following the successive versions of your software. Using this command, the latest commit (also called HEAD) of your current branch will be tagged. To verify that your Git tag was successfully created, you can run the “git tag” command to list your existing tags.


2 Answers

First, let's define the difference between a commit, a branch name and a tag name. Then I'll outsource the rest of this to the existing question and excellent answer at What is the difference between an annotated and unannotated tag? Note that a lightweight tag (un-annotated) does not take a message; only an annotated tag takes a message.

Defining a commit

A commit is an object in a Git repository. Git repository objects are mostly-permanent and completely read-only, and are consistency-checked so that they are incorruptible. There are four kinds of objects: commits (which we'll describe in detail in a moment), trees, blobs, and annotated tag objects. All four kinds are identified by hash IDs.

A blob is, very roughly, where Git stores your file's contents: if your README file says I am a readme file, the string I am a readme file is stored as a blob. A tree object is, slightly oversimplified, the thing that stores the file's name along with the blob hash ID of the file's contents. Hence, in order for commit 1234567... to store your README file, Git has a tree that says "file README has contents from blob c3c2a8983de728ffcf8f0ccaad014349925f23e6".1

In any case, each commit stores one tree hash ID, which is the saved snapshot of your source files2 at the time you made the commit. It also stores the hash ID of the parent commit(s) of this commit, so that Git can work backwards through the history to find all commits. It stores your name and email address and a timestamp, as the person who made the commit and when.3

After these required items—tree, parent(s), author, and committer—Git adds your log message, which is entirely arbitrary as far as Git itself is concerned. You don't have to supply any log message at all, and if you do supply one, it does not have to make sense. It will, however, be shown to you, and to other people, when they explore the history—the commits—stored in the repository.

Commits form chains, which is history

Because each commit records its earlier parent commit, the set of commits forms a chain that can be read backwards:

A  <-B  <-C   <--master

Git can start with a name, like the branch name master, to get the hash ID of commit C (whatever its real hash ID may be: I use C here as shorthand instead of the actual hash). This hash ID is unique to commit C: no other commit anywhere has that same hash ID.4 Commit C itself stores the hash ID of commit B, so from C we can find B. B stores the hash ID of commit A, so from B we can find A.

This particular repository has only three commits: A is the root commit, the first one we ever made, so it has no parent, and that lets us stop following history.

Branch and tag names find commits

But this also tells us what a branch name is and does: A branch name is a name that identifies a commit, by the commit's hash ID. A tag name does the same thing. So now we might wonder: what's the difference? When should we use a branch name, and when should we use a tag name?

Aside from the issue of name spaces,6 the main difference is that Git will let us get "on" a branch name, using git checkout. Once we are on such a branch, creating a new commit has a side effect: it changes the hash ID associated with the branch name. If we check out master and make a new commit, the parent ID stored in the new commit is the ID of C. Whatever the new commit's hash ID is, as computed by Git, that new hash ID goes into the name master, so that we now have:

A--B--C--D   <-- master

The name master now points to new commit D, which points back to C, which points back to B, and so on. The branch has grown, and the branch name points to the latest commit. Each commit points back to a previous one.

You cannot get "on" a tag like this. The tag name v1.0, once it's set to point to commit C, continues to point to commit C, forever. So this is the main difference between a branch name and a tag name in Git: A branch name changes over time, and even does this automatically when you make commits. A tag name should never7 change.


1c3c2a8983de728ffcf8f0ccaad014349925f23e6 is the hash ID of the content that reads I am a readme file. You can find this by running the following shell command:

$ echo 'I am a readme file' | git hash-object -t blob --stdin
c3c2a8983de728ffcf8f0ccaad014349925f23e6

Note that any blob object anywhere in any Git repository in the universe has this hash ID if it has this content! The content must consist of just those 19 bytes, including the terminating newline (with no carriage-return).

2More precisely, it's the saved index, aka staging area aka cache, as written out by git write-tree.

3Git stores these twice, once as the author of the commit and again as the committer. The two become different if you are, e.g., taking someone else's commit that they emailed you, and inserting it into a repository: then the author is the one who sent you the commit, but you are the committer. There are other situations in which the two become different. For the most part, nobody cares much, but run git log --pretty=fuller to see both.

4Hash IDs can repeat in different repositories, but only if the two repositories are never brought together. To make sure that commit hash IDs are unique, Git includes those time-stamps. This ensures even if you make the same commit you made before, with the same tree and same parent and same log message, if you make it at a different time, it's a different commit. (If you make it at the same time, then it's really exactly the same, and why do you care if you make it once or make it twice?5)

5There is a potential reason to care, but it's quite obscure and mostly irrelevant.

6Technically, a branch name is a reference that starts with refs/heads/, e.g., refs/heads/master is full spelling of the master branch. A tag name is a reference that starts with refs/tags/, such as refs/tags/v1.0. These are the reference name spaces, which include refs/remotes/, refs/notes/, refs/replace/, and refs/stash as well.

7Well, hardly ever. Some people really want a "floating tag". You can do this in Git, if you are careful and know what you are doing. There's no real point, though: if you want a name that moves, use a branch name. That's what they do. If you want a name that doesn't move, use a tag name. That's what they do.

like image 132
torek Avatar answered Oct 20 '22 07:10

torek


It would make sense to specify a tag when you release a version of the software you're producing.

You could then do:

git tag -a v1.0 -m "Release Version 1.0"

Like my comment mentioned, you do not have to tag after every commit, like you mention in your post, you can also create lightweight tags, if you don't want to include a message. This would look like:

git tag v1.0

Hope this helps.

like image 28
dimwittedanimal Avatar answered Oct 20 '22 06:10

dimwittedanimal