gitterminology

What does peel mean in Git?


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?


Solution

  • 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