In trying to understand JGit: Retrieve tag associated with a git commit, I arrived at this thread on the JGit mailing list: [jgit-dev] Commits and tags.
In this thread they refer to the peel
method of org.eclipse.jgit.lib.Repository
:
Peel a possibly unpeeled reference to an annotated tag.
I could only find two mentions of peeling in the Git documentation: git-check-ref-format(1) Manual Page and Git Internals - Maintenance and Data Recovery.
What does the term peel mean in Git? How is it useful? What does it have to do with onions?
You already know that each object in a repository has a unique SHA-1, and also an associated type and contents. (From the command line, use git cat-file -t sha1
to see the type of the given object, and git cat-file -p sha1
to see the contents, possibly with some pretty-printing applied but generally fairly raw in format.)
An annotated tag object in a git repository contains an SHA-1. (I hope this part is clear and uncontroversial. :-) )
Typically, the SHA-1 inside an annotated tag object—let's call this the "target-ID", and the object thus named the "target" of the tag—is the ID of a commit object. In this case, all is still pretty clear and simple. But what if it's not?
In particular, the target of an annotated tag might be another annotated tag. If this is the case, you must fetch that second annotated tag, which contains yet another target-ID. You must repeat this process, peeling off tag after tag, until you arrive at a non-tag object. Ideally this will be a commit, but of course it could be any of the remaining three kinds of objects (it's not clear what it means to tag a tree or blob though; only a commit makes sense).
This "peeling" process has been compared to peeling an onion, and that's where the phrase originates.
Note that if you're writing a repository health checker, it might be wise to make sure that the chain of tags does not loop (e.g., what if tag 1234567
has 7654321
as its target, and 7654321
is an annotated tag with 1234567
as its target?). (Edit: as remram points out in a comment, this requires "breaking" SHA-1. That means it's almost impossible for it to happen in practice, just as you won't get a tree that recursively points to itself.)
Edit: how to make a tag that points to another tag:
... make a repo with a commit that can be tagged ...
$ git tag -a anno1 -m 'annotated tag'
$ git tag -a anno2 anno1 -m 'another tag'
$ git cat-file -p anno1
object d4ec8b2d465de0c087d645f52ba5040586b8ce0f
type commit
tag anno1
tagger Chris Torek <chris.torek@gmail.com> 1413933523 -0600
annotated tag
$ git cat-file -p anno2
object cd1e0637c348e46c645819ef6de36679052b4b7f
type tag
tag anno2
tagger Chris Torek <chris.torek@gmail.com> 1413934239 -0600
another tag