Reputation: 4811
So far I know I can use git tag -a tag_name -m "tag message"
to make annotated tag.
And then using git show tag_name
to view the change infos of a specific tag.
Actually, this tag was bound to a commit. So what I really view is the changes of that commit.
So, does git tag
mainly works as alias or reminder, so we don't need to remember those inhuman HEADS?
Or there are some magic functions of tag that I don't know so far?
Upvotes: 2
Views: 750
Reputation: 489173
There is already a pretty good answer, but I wanted to add an answer that goes in a different direction.
In a significant way, the answer to the question as asked ("does a tag serve as an alias") is yes, but this could be misleading, because in git, all names act as aliases (in the situations where this makes sense).
More specifically, the "true name" of any git object is its SHA-1 ID, which is probably what you refer to when you mention "those inhuman HEADS". Each SHA-1 is a 40-character string like c18b86734113ee2aeb0e140c922c8fbd4accc860
. A tag is a way of finding such an ID—but so is a branch name like master
or devel
, and so are strings like HEAD
, HEAD^
, master~3
, and so on.
In fact, git has a fairly rich syntactic system for turning names into SHA-1 IDs, documented in the gitrevisions page. For instance, to find a commit that contains the string "bug1234", you can write git show :/bug1234
. (The colon indicates something special going on, the slash specifies a search, and the remainder of the text is actually a full-blown regular expression.)
What makes a tag name different, semantically speaking, from a branch name is that a branch name is expected to resolve to different commit IDs over time, and in fact, making a new commit while "on" a branch (as in, git status
says on branch master
) automatically updates the branch-name-to-ID mapping.1 A tag name, by contrast, is not expected to move like this, and git won't move it so easily. (One can "force move" a tag, at the cost of potentially confusing other users who have already saved the name-to-ID mapping: those other users are rather likely to keep using the old ID.)
As the other answer notes, there are two forms of tags, "lightweight" (pointing directly to a commit2) and "annotated" (which is really a pair, with a lightweight tag pointing to an actual tag object, which then stores some data including another pointer; the second pointer then points to the commit).
You may use the git rev-parse
command to turn a revision specifier into a raw SHA-1 ID. This command has a bunch of other features, but one of its central pieces simply drops arguments into the revision syntax handler. Naming a raw SHA-1 names that SHA-1;3 giving a branch or tag name gets you the thing to which the branch or tag points.
This last is where the difference between a lightweight tag and an annotated tag becomes significant. If you have annotated tag annotag
pointing to a commit, the command git rev-parse annotag
gets you the SHA-1 ID for the tag object, not for the commit itself. If you have a lightweight tag lightag
pointing to the same commit, git rev-parse lightag
gets you the SHA-1 ID for the commit. In fact, this different behavior is often what you want—but if not, it's easy to handle, because among all the other fancy syntax, there is a suffix syntax letting you specify that you must get a commit object: git rev-parse v1.2^{commit}
says to turn the v1.2
string into a commit. If v1.2
is an annotated tag, git will find the commit to which it points.4
In addition to the special syntaxes for "peeling off" tags (see footnote 4), git commands that need a commit will automatically do the peeling. For instance, git show
will, given an annotated tag name, show the tag and the object to which the tag points.
In summary, then, both branch names and tag names are aliases, but their purposes are different: tags are "fixed" aliases (for one specific, unchanging SHA-1), while branch-names are "variable" aliases (the latest SHA-1 in some sort of history).
1In fact, this is really what being "on a branch" means: that making a new commit will not just make the new commit, but will also update the branch-name-to-commit-ID mapping. If you specifically use --detach
to get into "detached HEAD" mode, or if you check out a tag ID or otherwise get "off" a branch into this "detached HEAD" mode, you can still make new commits. Each time you do so, the new commit ID is stored in the HEAD
file, rather than in a branch file. Since the HEAD
file is overwritten with the branch name or raw commit ID once you check out a different branch or commit, any such new commits are effectively only temporary, unless you give them a branch or tag name later. This is how the rebase
command works internally, for instance: it gets off the branch, copies commits as new temporary commits, and when it finishes copying the last commit, it re-shuffles the branch name so that the new commits are no longer temporary, and it's the old commit-chain that has become temporary.
2In fact, a tag can point to any git object. Normally a lightweight tag should point to a commit, and the lightweight entry for an annotated tag must (to make any sense) point to the annotated tag object. One annotated tag object can, however, point to another annotated tag object, and so on, and it's possible—and even useful, for special purposes—to make references (not necessarily tags) that point directly to tree or blob objects.
3In fact, if you feed a 40-character SHA-1 string to git rev-parse
, that ID need not exist in the repository. If you use an abbreviated form, however, rev-parse
will look for the object, failing if the ID is missing or ambiguous, or finding the full 40-character form if not.
4Note that this assumes that the tag points to a commit, possibly after following some number of intermediate annotated tags. A slightly different syntax, rev^{}
, tells git that if the rev
argument is an annotated tag, it should follow that tag to its object, and if that object is also a tag, it should follow again, and repeat until it reaches a non-tag. This process is also called "peeling".
Note also that some command interpreters treat braces specially, so in some cases you may need to protect some of these strings using quotes.
Upvotes: 9
Reputation: 26555
Actually git knows about two kind of tags:
Whenever you use git tag -a
you will create an annotated tag. You usually use that for a release. It will store who created the tag and when done, you can add a message and maybe even sign your tag. All those information is not available in a lightweight tag.
Have a look at git help tag
for more details.
Upvotes: 3