Subject: Re: [PATCH v3 09/12] get_short_oid / peel_onion: ^{tree} should be tree, not treeish

From: Ævar Arnfjörð Bjarmason <[email-masked]>
Date: Tue, 08 May 2018 20:53:10 +0200

On Tue, May 08 2018, Jeff King wrote:

> On Mon, May 07, 2018 at 01:08:46PM +0900, Junio C Hamano wrote:
>
>> Ævar Arnfjörð Bjarmason <[email-masked]> writes:
>>
>> > Right, and I'm with you so far, this makes sense to me for all existing
>> > uses of the peel syntax, otherwise v2.17.0^{tree} wouldn't be the same
>> > as rev-parse v2.17.0^{tree}^{tree}...
>>
>> More importantly, you could spell v2.17.0 part of the above with a
>> short hexadecimal string.  And that string should be naming some
>> tree-ish, the most important thing being that it is *NOT* required
>> to be a tree (and practically, it is likely that the user has a
>> tree-ish that is *NOT* a tree).
>>
>> I guess I have a reaction to the title
>>
>>     "get_short_oid/peel_onion: ^{tree} should be tree"
>>
>> "X^{tree}" should *RESULT* in a tree, but it should *REQUIRE* X to
>> be a tree-ish.  It is unclear "should be tree" is about the former
>> and I read (perhaps mis-read) it as saying "it should require X to
>> be a tree"---that statement is utterly incorrect as we agreed above.
>
> FWIW, I had the same feeling as you when reading this, that this commit
> (and the one after) are doing the wrong thing. And these paragraphs sum
> it up. The "^{tree}" is about asking us to peel to a tree, not about
> resolving X in the first place. We can use it as a _hint_ when resolving
> X, but the correct hint is "something that can be peeled to a tree", not
> "is definitely a tree".

Maybe I'm just being dense, but I still don't get from this & Junio's
E-Mails what the general rule should be.

I think a response to the part after "leaving that aside" of my upthread
E-Mail
(https://public-inbox.org/git/[email-masked]/) would
help me out.

Not to belabor the point, but here's a patch I came up with to
revisions.txt that's a WIP version of something that would describe the
worldview after this v3:

    diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
    index dfcc49c72c..0bf68f4ad2 100644
    --- a/Documentation/revisions.txt
    +++ b/Documentation/revisions.txt
    @@ -143,29 +143,52 @@ thing no matter the case.
       '<rev>{caret}1{caret}1{caret}1'.  See below for an illustration of
       the usage of this form.

     '<rev>{caret}{<type>}', e.g. 'v0.99.8{caret}\{commit\}'::
       A suffix '{caret}' followed by an object type name enclosed in
       brace pair means dereference the object at '<rev>' recursively until
       an object of type '<type>' is found or the object cannot be
    -  dereferenced anymore (in which case, barf).
    +  dereferenced anymore (in which case either return that object type, or barf).
       For example, if '<rev>' is a commit-ish, '<rev>{caret}\{commit\}'
       describes the corresponding commit object.
       Similarly, if '<rev>' is a tree-ish, '<rev>{caret}\{tree\}'
       describes the corresponding tree object.
       '<rev>{caret}0'
       is a short-hand for '<rev>{caret}\{commit\}'.
     +
     'rev{caret}\{object\}' can be used to make sure 'rev' names an
     object that exists, without requiring 'rev' to be a tag, and
     without dereferencing 'rev'; because a tag is already an object,
     it does not have to be dereferenced even once to get to an object.
     +
     'rev{caret}\{tag\}' can be used to ensure that 'rev' identifies an
     existing tag object.
    ++
    +Object types that don't have a 1=1 mapping to other object types
    +cannot be dereferenced with the peel syntax, and will return an
    +error. E.g. '<treeid>{caret}{commit}' or '<treeid>{caret}{tree}' is
    +allowed because a tag can only point to one commit, and a commit can
    +only point to one tree. But '<treeid>{caret}{blob}' will always
    +produce an error since trees in general don't 1=1 map to blobs, even
    +though the specific '<treeid>' in question might only contain one
    +blob. Note that '<tagid>{caret}{blob}' is not an error if '<tagid>' is
    +a tag that points directly to a blob, since that again becomes
    +unambiguous.
    ++
    +'<rev>{caret}{<type>}' takes on a different meaning when '<rev>' is a
    +SHA-1 that's ambiguous within the object store. In that case we don't
    +have a 1=1 mapping anymore. E.g. e8f2 in git.git can refer to multiple
    +objects of all the different object types. In that case
    +{caret}{<type>} should always be an error to be consistent with the
    +logic above, but that wouldn't be useful to anybody. Instead it'll
    +fall back to being selector syntax for the given object types,
    +e.g. e8f2{caret}{tag} will (as of writing this) return the v2.17.0
    +tag, and {caret}{commit}, {caret}{tree} and {caret}{blob} will return
    +commit, tree and blob objects, respectively.
    +
    [...]

My understanding of what you two are saying is that somehow the peel
semantics should be preserved when we take this beyond the 1=1 mapping
case, but I don't see how if we run with that how we wouldn't need to
introduce the concept of blobish for consistency as I noted upthread.

So it would be very useful to me if you or someone who understands the
behavior you & Junio seem to want could write a version of the patch I
have above where the last paragraph is different, and describes the
desired semantics, because I still don't get it. Why would we 1=many
peel commits to trees as a special case, but not 1=many do the same for
trees & blobs?