{"thread":{"id":"33319","subject":"Bug in \"git rev-parse --verify\"","startedAt":"2013-03-28T13:04:27Z","lastAt":"2013-04-02T16:56:46Z","messageCount":22,"participants":["Michael Haggerty","Jeff King","Junio C Hamano","Elia Pinto"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"212506","messageId":"51543FDB.9010109@alum.mit.edu","threadId":"33319","inReplyTo":null,"subject":"Bug in \"git rev-parse --verify\"","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2013-03-28T13:04:27Z","receivedAt":"2013-03-28T13:04:27Z","isPatch":false,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On Junio's master, \"git rev-parse --verify\" accepts *any* 40-digit\nhexadecimal number.  For example, pass it 40 \"1\" characters, and it\naccepts the argument:\n\n$ git rev-parse --verify 1111111111111111111111111111111111111111\n1111111111111111111111111111111111111111\n$ echo $?\n0\n\nObviously, my repo doesn't have an object with this hash :-) so I think\nthis argument should be rejected.\n\nIf you add or remove a digit (to make the length different than 40), it\nis correctly rejected:\n\n$ git rev-parse --verify 111111111111111111111111111111111111111\nfatal: Needed a single revision\n$ echo $?\n128\n\nI believe that \"git rev-parse --verify\" is meant to verify that the\nargument is an actual object, and that it should reject fictional SHA1s.\n (If not then the documentation should be clarified.)  The same problem\nalso exists in 1.8.2 but I haven't checked how much older it is.\n\nThe behavior presumably comes from the following clause in get_sha1_basic():\n\n\tif (len == 40 && !get_sha1_hex(str, sha1))\n\t\treturn 0;\n\nI won't have time to pursue this.\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\nhttp://softwareswirl.blogspot.com/\n"},{"id":"212518","messageId":"20130328140510.GB12898@sigill.intra.peff.net","threadId":"33319","inReplyTo":"51543FDB.9010109@alum.mit.edu","subject":"Re: Bug in \"git rev-parse --verify\"","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2013-03-28T14:05:10Z","receivedAt":"2013-03-28T14:05:10Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Mar 28, 2013 at 02:04:27PM +0100, Michael Haggerty wrote:\n\n> $ git rev-parse --verify 1111111111111111111111111111111111111111\n> 1111111111111111111111111111111111111111\n> $ echo $?\n> 0\n>\n> [...]\n>\n> I believe that \"git rev-parse --verify\" is meant to verify that the\n> argument is an actual object, and that it should reject fictional SHA1s.\n>  (If not then the documentation should be clarified.)  The same problem\n> also exists in 1.8.2 but I haven't checked how much older it is.\n\nI think it is only about verifying the name of the object. I.e., that\nyou can resolve the argument to an object. It has always behaved this\nway; I even just tested with git v0.99.\n\nI can't think of any reason it would not be helpful to have it _also_\nverify that we have the object in question. Most of the time that would\nbe a no-op, as any ref we resolve should point to a valid object, but it\nwould mean we could catch repository corruption (i.e., missing objects)\nearly.\n\nDoing a has_sha1_file() check would be relatively quick. Doing a full\nparse_object and checking the sha1 would be more robust, but would mean\nthat:\n\n  blob=`git rev-parse --verify HEAD:some-large-file`\n\nwould become much more expensive (and presumably you are about to access\nthe object _anyway_, at which point you would notice problems, so it is\nredundantly expensive).\n\n-Peff\n"},{"id":"212523","messageId":"7vtxnvwp3k.fsf@alter.siamese.dyndns.org","threadId":"33319","inReplyTo":"20130328140510.GB12898@sigill.intra.peff.net","subject":"Re: Bug in \"git rev-parse --verify\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-28T14:55:43Z","receivedAt":"2013-03-28T14:55:43Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Thu, Mar 28, 2013 at 02:04:27PM +0100, Michael Haggerty wrote:\n>\n>> $ git rev-parse --verify 1111111111111111111111111111111111111111\n>> 1111111111111111111111111111111111111111\n>> $ echo $?\n>> 0\n>>\n>> [...]\n>>\n>> I believe that \"git rev-parse --verify\" is meant to verify that the\n>> argument is an actual object, and that it should reject fictional SHA1s.\n>>  (If not then the documentation should be clarified.)  The same problem\n>> also exists in 1.8.2 but I haven't checked how much older it is.\n>\n> I think it is only about verifying the name of the object. I.e., that\n> you can resolve the argument to an object. It has always behaved this\n> way; I even just tested with git v0.99.\n\nCorrect.  It is about \"is it well formed and something we can turn\ninto 20-byte object name?\" and nothing more.  It certainly does not\nmean \"do we have it?\", as the function needs to be able to validate\nsomething we do not yet have.\n"},{"id":"212529","messageId":"515462FB.9040605@alum.mit.edu","threadId":"33319","inReplyTo":"CAPc5daUqzz=9TBmj2Q0MHqEc6gMHxXoGr9+JV3hq76zDKJAyCw@mail.gmail.com","subject":"Re: Bug in \"git rev-parse --verify\"","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2013-03-28T15:34:19Z","receivedAt":"2013-03-28T15:34:19Z","isPatch":false,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 03/28/2013 02:48 PM, Junio C Hamano wrote:\n> I think it has always been about \"is this well formed and we can turn it\n> into a raw 20-byte object name?\" and never about\"does it exist?\"\n\nThat's surprising.  The man page says\n\n    --verify\n        The parameter given must be usable as a single, valid object name.\n        Otherwise barf and abort.\n\n\"Valid\", to me, implies that the parameter should be the name of an\nactual object, and this also seems a more useful concept to me and more\nconsistent with the command's behavior when passed other arguments.\n\n\nIs there a simple way to verify an object name more strictly and convert\nit to an SHA1?  I can only think of solutions that require two commands,\nlike\n\n    git cat-file -e $ARG && git rev-parse --verify $ARG\n\nI suppose in most contexts where one wants to know whether an object\nname is valid, one should also verify that the object has the type that\nyou expect:\n\n    test X$(git cat-file -t $ARG) = Xcommit &&\n        git rev-parse --verify $ARG\n\nor (allowing tag dereferencing)\n\n    git cat-file -e $ARG^{commit} &&\n        git rev-parse --verify $ARG^{commit}\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\nhttp://softwareswirl.blogspot.com/\n"},{"id":"212532","messageId":"20130328153808.GB3337@sigill.intra.peff.net","threadId":"33319","inReplyTo":"515462FB.9040605@alum.mit.edu","subject":"Re: Bug in \"git rev-parse --verify\"","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2013-03-28T15:38:08Z","receivedAt":"2013-03-28T15:38:08Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Mar 28, 2013 at 04:34:19PM +0100, Michael Haggerty wrote:\n\n> Is there a simple way to verify an object name more strictly and convert\n> it to an SHA1?  I can only think of solutions that require two commands,\n> like\n> \n>     git cat-file -e $ARG && git rev-parse --verify $ARG\n\nIs the rev-parse line doing anything there? If $ARG does not resolve to\na sha1, then wouldn't cat-file have failed?\n\n-Peff\n"},{"id":"212533","messageId":"5154672F.10303@alum.mit.edu","threadId":"33319","inReplyTo":"20130328153808.GB3337@sigill.intra.peff.net","subject":"Re: Bug in \"git rev-parse --verify\"","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2013-03-28T15:52:15Z","receivedAt":"2013-03-28T15:52:15Z","isPatch":false,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 03/28/2013 04:38 PM, Jeff King wrote:\n> On Thu, Mar 28, 2013 at 04:34:19PM +0100, Michael Haggerty wrote:\n> \n>> Is there a simple way to verify an object name more strictly and convert\n>> it to an SHA1?  I can only think of solutions that require two commands,\n>> like\n>>\n>>     git cat-file -e $ARG && git rev-parse --verify $ARG\n> \n> Is the rev-parse line doing anything there? If $ARG does not resolve to\n> a sha1, then wouldn't cat-file have failed?\n\nIt's outputting the SHA1, which cat-file seems incapable of providing in\na useful way.\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\nhttp://softwareswirl.blogspot.com/\n"},{"id":"212545","messageId":"20130328163848.GA7194@sigill.intra.peff.net","threadId":"33319","inReplyTo":"5154672F.10303@alum.mit.edu","subject":"Re: Bug in \"git rev-parse --verify\"","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2013-03-28T16:38:48Z","receivedAt":"2013-03-28T16:38:48Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Mar 28, 2013 at 04:52:15PM +0100, Michael Haggerty wrote:\n\n> On 03/28/2013 04:38 PM, Jeff King wrote:\n> > On Thu, Mar 28, 2013 at 04:34:19PM +0100, Michael Haggerty wrote:\n> > \n> >> Is there a simple way to verify an object name more strictly and convert\n> >> it to an SHA1?  I can only think of solutions that require two commands,\n> >> like\n> >>\n> >>     git cat-file -e $ARG && git rev-parse --verify $ARG\n> > \n> > Is the rev-parse line doing anything there? If $ARG does not resolve to\n> > a sha1, then wouldn't cat-file have failed?\n> \n> It's outputting the SHA1, which cat-file seems incapable of providing in\n> a useful way.\n\nAh, I see; I was looking too much at your example, and not thinking\nabout how you would want to use it in a script.\n\n-Peff\n"},{"id":"212555","messageId":"7vli97v558.fsf@alter.siamese.dyndns.org","threadId":"33319","inReplyTo":"20130328153808.GB3337@sigill.intra.peff.net","subject":"Re: Bug in \"git rev-parse --verify\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-28T16:52:03Z","receivedAt":"2013-03-28T16:52:03Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Thu, Mar 28, 2013 at 04:34:19PM +0100, Michael Haggerty wrote:\n>\n>> Is there a simple way to verify an object name more strictly and convert\n>> it to an SHA1?  I can only think of solutions that require two commands,\n>> like\n>> \n>>     git cat-file -e $ARG && git rev-parse --verify $ARG\n>\n> Is the rev-parse line doing anything there? If $ARG does not resolve to\n> a sha1, then wouldn't cat-file have failed?\n>\n> -Peff\n\nYou could force rev-parse to resolve the input to an existing\nobject, with something like this:\n\n\tgit rev-parse --verify \"$ARG^{}\"\n\nIt will unwrap a tag, so the output may end up pointing at a object\nthat is different from $ARG in such a case.\n\nBut what is the purpose of turning a random string to a random\n40-hex in the first place?\n"},{"id":"212672","messageId":"51565F96.1020203@alum.mit.edu","threadId":"33319","inReplyTo":"7vli97v558.fsf@alter.siamese.dyndns.org","subject":"Re: Bug in \"git rev-parse --verify\"","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2013-03-30T03:44:22Z","receivedAt":"2013-03-30T03:44:22Z","isPatch":false,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 03/28/2013 05:52 PM, Junio C Hamano wrote:\n> You could force rev-parse to resolve the input to an existing\n> object, with something like this:\n> \n> \tgit rev-parse --verify \"$ARG^{}\"\n> \n> It will unwrap a tag, so the output may end up pointing at a object\n> that is different from $ARG in such a case.\n\nYes, if unwrapping tags is OK then this would work.\n\n> But what is the purpose of turning a random string to a random\n> 40-hex in the first place?\n\nIn non-trivial scripts, it makes sense to convert user input into a\nknown and verified quantity (SHA1) once, while processing external\ninputs, and not have to think about it afterwards.  Verifying and\nconverting to pure-SHA1s as soon as possible has several advantages:\n\n1. An SHA1 is a canonical representation of the argument, useful for\nexample as the key in a hash map for for looking for the presence of a\ncommit in a rev-list output.\n\n2. An SHA1 is persistent.  For example, I use them when caching\nbenchmark results across versions.  Moreover, they are safe for use in\nfilenames.  The persistence also makes scripts more robust against\nsimultaneous changes to the repo by other processes, whereas if I use a\nstring like \"branch^\" multiple times, there is no guarantee that it\nalways refers to the same commit.\n\n3. Verifying arguments at one spot centralizes error-checking at the\nstart of a script and eliminates one reason for random git commands to\nfail later (when error recovery is perhaps more difficult).\n\n4. Converting once avoids the overhead of repeated conversion from a\nfree-form committish into an object name if the argument needs to be\npassed to multiple git commands (though presumably the overhead is\ninsignificant in most cases).\n\nUndoubtedly in many cases this practice of\nearly-verification-and-conversion is unnecessary, or the same benefit\ncould be had from either verifying or converting without doing both.\nBut verifying-and-converting is easy, cheap, and means not having to\ndecide on a case-by-case basis whether it could have been avoided.\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\nhttp://softwareswirl.blogspot.com/\n"},{"id":"212673","messageId":"7vk3opr0ke.fsf@alter.siamese.dyndns.org","threadId":"33319","inReplyTo":"51565F96.1020203@alum.mit.edu","subject":"Re: Bug in \"git rev-parse --verify\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-30T04:09:05Z","receivedAt":"2013-03-30T04:09:05Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael Haggerty <mhagger@alum.mit.edu> writes:\n\n> 1. An SHA1 is a canonical representation of the argument, useful for\n> example as the key in a hash map for for looking for the presence of a\n> commit in a rev-list output.\n>\n> 2. An SHA1 is persistent.  For example, I use them when caching\n> benchmark results across versions.  Moreover, they are safe for use in\n> filenames.  The persistence also makes scripts more robust against\n> simultaneous changes to the repo by other processes, whereas if I use a\n> string like \"branch^\" multiple times, there is no guarantee that it\n> always refers to the same commit.\n\nThese two are half-irrelevant; they only call for use of the current\n\"rev-parse --verify\" that always gives you 40-hex.  The more\nimportant one is the next one.\n\n> 3. Verifying arguments at one spot centralizes error-checking at the\n> start of a script and eliminates one reason for random git commands to\n> fail later (when error recovery is perhaps more difficult).\n\nNot necessarily, unless your script is a very narrow corner case\nthat is satisfied with \"any kind of object goes\".  When a parameter\nhas to be commit for some purpose and another parameter can be any\ntree-ish, you would want to validate them _with_ type requirement.\n\nIf you are using the \"object name persistency\" to create a cache of\n\"how many times the word 'gogopuff' appears in the entire tree?\",\nyou want to cache the result keyed with the object name of the tree,\nwhether your user gives you v1.8.0 (tag), v1.8.0^0 (commit), or\nv1.8.0^{tree} (tree), and you want to unwrap the user input down to\ntree object name to look up the pre-computed result for the cache to\nbe any useful.\n\n> 4. Converting once avoids the overhead of repeated conversion from a\n> free-form committish into an object name if the argument needs to be\n> passed to multiple git commands (though presumably the overhead is\n> insignificant in most cases).\n\nTrue.\n\nSo why not verify arguments while making sure of their type early\nwith 'rev-parse --verify \"$userinput^{desiredtype}\"?\n"},{"id":"212674","messageId":"7vfvzdr09w.fsf@alter.siamese.dyndns.org","threadId":"33319","inReplyTo":"7vk3opr0ke.fsf@alter.siamese.dyndns.org","subject":"Re: Bug in \"git rev-parse --verify\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-30T04:15:23Z","receivedAt":"2013-03-30T04:15:23Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n>> 3. Verifying arguments at one spot centralizes error-checking at the\n>> start of a script and eliminates one reason for random git commands to\n>> fail later (when error recovery is perhaps more difficult).\n>\n> Not necessarily, unless your script is a very narrow corner case\n> that is satisfied with \"any kind of object goes\".\n\nClarification.  I meant \"A single central point to check is a useful\nconcept, but centrally checking 'does this exist? I do not care what\nit is' is not necessarily useful and I suspect it is not useful more\noften than it is\".  When you care if something exists, you often\nwant to know what it is and other aspects of that thing at the same\ntime.\n"},{"id":"212675","messageId":"51567844.7030503@alum.mit.edu","threadId":"33319","inReplyTo":"7vk3opr0ke.fsf@alter.siamese.dyndns.org","subject":"Re: Bug in \"git rev-parse --verify\"","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2013-03-30T05:29:40Z","receivedAt":"2013-03-30T05:29:40Z","isPatch":false,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 03/30/2013 05:09 AM, Junio C Hamano wrote:\n> So why not verify arguments while making sure of their type early\n> with 'rev-parse --verify \"$userinput^{desiredtype}\"?\n\nYes, that's a better solution in almost all cases.  Thanks for the tip.\n\n(It doesn't change my opinion that the documentation for \"rev-parse\n--verify\" is misleading, but given that you don't appear to want to\nchange its behavior I will submit a documentation patch.)\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\nhttp://softwareswirl.blogspot.com/\n"},{"id":"212676","messageId":"7vboa1qtnb.fsf@alter.siamese.dyndns.org","threadId":"33319","inReplyTo":"51567844.7030503@alum.mit.edu","subject":"Re: Bug in \"git rev-parse --verify\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-30T06:38:32Z","receivedAt":"2013-03-30T06:38:32Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael Haggerty <mhagger@alum.mit.edu> writes:\n\n> On 03/30/2013 05:09 AM, Junio C Hamano wrote:\n>> So why not verify arguments while making sure of their type early\n>> with 'rev-parse --verify \"$userinput^{desiredtype}\"?\n>\n> Yes, that's a better solution in almost all cases.  Thanks for the tip.\n>\n> (It doesn't change my opinion that the documentation for \"rev-parse\n> --verify\" is misleading, but given that you don't appear to want to\n> change its behavior I will submit a documentation patch.)\n\nIt does not matter what I want.  What matters is that changing the\ndefinition is a _wrong_ thing to do, as --verify is designed to be\nusable for objects you may not yet have.\n\nWhat we may want is another type peeling operator, ^{object}.\nmakes sure it is an object, that lets you say:\n\n    rev-parse --verify 572a535454612a046e7dd7404dcca94d6243c788^{object}\n\nIt asks \"I have this 40-hex; I want an object out of it\", just like\nfrotz^{tree} is \"I have 'frotz'; I want a tree-ish\" for any value of\n'frotz'.\n\nWith that, a use case that it wants to see _any_ object can safely\nuse 'rev-parse --verify \"$userinput^{object}' without an annotated\ntag getting in the way.\n\nHow does that sound?\n"},{"id":"212678","messageId":"7vhajtpdtc.fsf@alter.siamese.dyndns.org","threadId":"33319","inReplyTo":"7vboa1qtnb.fsf@alter.siamese.dyndns.org","subject":"Re: Bug in \"git rev-parse --verify\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-30T07:05:51Z","receivedAt":"2013-03-30T07:05:51Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> What we may want is another type peeling operator, ^{object}.\n> that makes sure it is an object, like this:\n>\n>     rev-parse --verify 572a535454612a046e7dd7404dcca94d6243c788^{object}\n>\n> It asks \"I have this 40-hex; I want an object out of it\", just like\n> frotz^{tree} is \"I have 'frotz'; I want a tree-ish\" for any value of\n> 'frotz'.\n>\n> With that, a use case that it wants to see _any_ object can safely\n> use 'rev-parse --verify \"$userinput^{object}' without an annotated\n> tag getting in the way.\n>\n> How does that sound?\n\nPerhaps something like this.  Note that the last hunk is unrelated\nthinko-fix I noticed while browsing the code.\n\n-- >8 --\nSubject: sha1_name.c: ^{object} peeler\n\nA string that names an object can be suffixed with ^{type} peeler to\nsay \"I have this object name; peel it until you get this type. If\nyou cannot do so, it is an error\".  v1.8.2^{commit} asks for a commit\nthat is pointed at an annotated tag v1.8.2; v1.8.2^{tree} unwraps it\nfurther to the top-level tree object.  A special suffix ^{} (i.e. no\ntype specified) means \"I do not care what it unwraps to; just peel\nannotated tag until you get something that is not a tag\".\n\nWhen you have a random user-supplied string, you can turn it to a\nbare 40-hex object name, and cause it to error out if such an object\ndoes not exist, with:\n\n\tgit rev-parse --verify \"$userstring^{}\"\n\nfor most objects, but this does not yield the tag object name when\n$userstring refers to an annotated tag.\n\nIntroduce a new suffix, ^{object}, that only makes sure the given\nname refers to an existing object.  Then\n\n\tgit rev-parse --verify \"$userstring^{object}\"\n\nbecomes a way to make sure $userstring refers to an existing object.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n sha1_name.c | 6 +++++-\n 1 file changed, 5 insertions(+), 1 deletion(-)\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex c50630a..85b6e75 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -594,7 +594,7 @@ struct object *peel_to_type(const char *name, int namelen,\n \twhile (1) {\n \t\tif (!o || (!o->parsed && !parse_object(o->sha1)))\n \t\t\treturn NULL;\n-\t\tif (o->type == expected_type)\n+\t\tif (expected_type == OBJ_ANY || o->type == expected_type)\n \t\t\treturn o;\n \t\tif (o->type == OBJ_TAG)\n \t\t\to = ((struct tag*) o)->tagged;\n@@ -645,6 +645,8 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)\n \t\texpected_type = OBJ_TREE;\n \telse if (!strncmp(blob_type, sp, 4) && sp[4] == '}')\n \t\texpected_type = OBJ_BLOB;\n+\telse if (!prefixcmp(sp, \"object}\"))\n+\t\texpected_type = OBJ_ANY;\n \telse if (sp[0] == '}')\n \t\texpected_type = OBJ_NONE;\n \telse if (sp[0] == '/')\n@@ -654,6 +656,8 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)\n \n \tif (expected_type == OBJ_COMMIT)\n \t\tlookup_flags = GET_SHA1_COMMITTISH;\n+\telse if (expected_type == OBJ_TREE)\n+\t\tlookup_flags = GET_SHA1_TREEISH;\n \n \tif (get_sha1_1(name, sp - name - 2, outer, lookup_flags))\n \t\treturn -1;\n"},{"id":"212679","messageId":"51569DB0.1010102@alum.mit.edu","threadId":"33319","inReplyTo":"7vhajtpdtc.fsf@alter.siamese.dyndns.org","subject":"Re: Bug in \"git rev-parse --verify\"","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2013-03-30T08:09:20Z","receivedAt":"2013-03-30T08:09:20Z","isPatch":false,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 03/30/2013 08:05 AM, Junio C Hamano wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n> \n>> What we may want is another type peeling operator, ^{object}.\n>> that makes sure it is an object, like this:\n>>\n>>     rev-parse --verify 572a535454612a046e7dd7404dcca94d6243c788^{object}\n>>\n>> It asks \"I have this 40-hex; I want an object out of it\", just like\n>> frotz^{tree} is \"I have 'frotz'; I want a tree-ish\" for any value of\n>> 'frotz'.\n>>\n>> With that, a use case that it wants to see _any_ object can safely\n>> use 'rev-parse --verify \"$userinput^{object}' without an annotated\n>> tag getting in the way.\n>>\n>> How does that sound?\n> \n> Perhaps something like this.  Note that the last hunk is unrelated\n> thinko-fix I noticed while browsing the code.\n\nSounds reasonable to me.  I'm not familiar with this code, but your\nchange looks simple enough.  Plus documentation change in\nDocumentation/revisions.txt, of course.\n\nThanks,\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\nhttp://softwareswirl.blogspot.com/\n"},{"id":"212680","messageId":"CA+EOSBnXPgLhaCgDp5t94eFUXxiA-iufuJR8KCCvOTgczLCtWw@mail.gmail.com","threadId":"33319","inReplyTo":"7vhajtpdtc.fsf@alter.siamese.dyndns.org","subject":"Re: Bug in \"git rev-parse --verify\"","fromName":"Elia Pinto","fromEmail":"gitter.spiros@gmail.com","sentAt":"2013-03-30T08:14:02Z","receivedAt":"2013-03-30T08:14:02Z","isPatch":false,"sender":{"key":"gitter.spiros@gmail.com","avatar":"https://avatars.githubusercontent.com/u/158490?v=4"},"body":"Fwiw, look very a sound idea for me.\n\nBest\n\n2013/3/30, Junio C Hamano <gitster@pobox.com>:\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> What we may want is another type peeling operator, ^{object}.\n>> that makes sure it is an object, like this:\n>>\n>>     rev-parse --verify 572a535454612a046e7dd7404dcca94d6243c788^{object}\n>>\n>> It asks \"I have this 40-hex; I want an object out of it\", just like\n>> frotz^{tree} is \"I have 'frotz'; I want a tree-ish\" for any value of\n>> 'frotz'.\n>>\n>> With that, a use case that it wants to see _any_ object can safely\n>> use 'rev-parse --verify \"$userinput^{object}' without an annotated\n>> tag getting in the way.\n>>\n>> How does that sound?\n>\n> Perhaps something like this.  Note that the last hunk is unrelated\n> thinko-fix I noticed while browsing the code.\n>\n> -- >8 --\n> Subject: sha1_name.c: ^{object} peeler\n>\n> A string that names an object can be suffixed with ^{type} peeler to\n> say \"I have this object name; peel it until you get this type. If\n> you cannot do so, it is an error\".  v1.8.2^{commit} asks for a commit\n> that is pointed at an annotated tag v1.8.2; v1.8.2^{tree} unwraps it\n> further to the top-level tree object.  A special suffix ^{} (i.e. no\n> type specified) means \"I do not care what it unwraps to; just peel\n> annotated tag until you get something that is not a tag\".\n>\n> When you have a random user-supplied string, you can turn it to a\n> bare 40-hex object name, and cause it to error out if such an object\n> does not exist, with:\n>\n> \tgit rev-parse --verify \"$userstring^{}\"\n>\n> for most objects, but this does not yield the tag object name when\n> $userstring refers to an annotated tag.\n>\n> Introduce a new suffix, ^{object}, that only makes sure the given\n> name refers to an existing object.  Then\n>\n> \tgit rev-parse --verify \"$userstring^{object}\"\n>\n> becomes a way to make sure $userstring refers to an existing object.\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  sha1_name.c | 6 +++++-\n>  1 file changed, 5 insertions(+), 1 deletion(-)\n>\n> diff --git a/sha1_name.c b/sha1_name.c\n> index c50630a..85b6e75 100644\n> --- a/sha1_name.c\n> +++ b/sha1_name.c\n> @@ -594,7 +594,7 @@ struct object *peel_to_type(const char *name, int\n> namelen,\n>  \twhile (1) {\n>  \t\tif (!o || (!o->parsed && !parse_object(o->sha1)))\n>  \t\t\treturn NULL;\n> -\t\tif (o->type == expected_type)\n> +\t\tif (expected_type == OBJ_ANY || o->type == expected_type)\n>  \t\t\treturn o;\n>  \t\tif (o->type == OBJ_TAG)\n>  \t\t\to = ((struct tag*) o)->tagged;\n> @@ -645,6 +645,8 @@ static int peel_onion(const char *name, int len,\n> unsigned char *sha1)\n>  \t\texpected_type = OBJ_TREE;\n>  \telse if (!strncmp(blob_type, sp, 4) && sp[4] == '}')\n>  \t\texpected_type = OBJ_BLOB;\n> +\telse if (!prefixcmp(sp, \"object}\"))\n> +\t\texpected_type = OBJ_ANY;\n>  \telse if (sp[0] == '}')\n>  \t\texpected_type = OBJ_NONE;\n>  \telse if (sp[0] == '/')\n> @@ -654,6 +656,8 @@ static int peel_onion(const char *name, int len,\n> unsigned char *sha1)\n>\n>  \tif (expected_type == OBJ_COMMIT)\n>  \t\tlookup_flags = GET_SHA1_COMMITTISH;\n> +\telse if (expected_type == OBJ_TREE)\n> +\t\tlookup_flags = GET_SHA1_TREEISH;\n>\n>  \tif (get_sha1_1(name, sp - name - 2, outer, lookup_flags))\n>  \t\treturn -1;\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n>\n\n-- \nInviato dal mio dispositivo mobile\n"},{"id":"212757","messageId":"7v38vbp53n.fsf_-_@alter.siamese.dyndns.org","threadId":"33319","inReplyTo":"7vhajtpdtc.fsf@alter.siamese.dyndns.org","subject":"[PATCH 1/2] peel_onion: disambiguate to favor tree-ish when we want a tree-ish","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-31T22:38:36Z","receivedAt":"2013-03-31T22:38:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The function already knows when interpreting $foo^{commit} to tell\nthe underlying get_sha1_1() to expect a commit-ish while evaluating\n$foo.  Teach it to do the same when asked for $foo^{tree}; we are\nexpecting a tree-ish and $foo should be disambiguated in favor of a\ntree-ish, discarding a possible ambiguous match with a blob object.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\nJunio C Hamano <gitster@pobox.com> writes:\n\n> Perhaps something like this.  Note that the last hunk is unrelated\n> thinko-fix I noticed while browsing the code.\n\n sha1_name.c | 2 ++\n 1 file changed, 2 insertions(+)\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex c50630a..45788df 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -654,6 +654,8 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)\n \n \tif (expected_type == OBJ_COMMIT)\n \t\tlookup_flags = GET_SHA1_COMMITTISH;\n+\telse if (expected_type == OBJ_TREE)\n+\t\tlookup_flags = GET_SHA1_TREEISH;\n \n \tif (get_sha1_1(name, sp - name - 2, outer, lookup_flags))\n \t\treturn -1;\n-- \n1.8.2-441-g6e6f07b\n"},{"id":"212758","messageId":"7vy5d3nqik.fsf_-_@alter.siamese.dyndns.org","threadId":"33319","inReplyTo":"7vhajtpdtc.fsf@alter.siamese.dyndns.org","subject":"[PATCH 2/2] peel_onion(): teach $foo^{object} peeler","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-31T22:38:59Z","receivedAt":"2013-03-31T22:38:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"A string that names an object can be suffixed with ^{type} peeler to\nsay \"I have this object name; peel it until you get this type. If\nyou cannot do so, it is an error\".  v1.8.2^{commit} asks for a commit\nthat is pointed at an annotated tag v1.8.2; v1.8.2^{tree} unwraps it\nfurther to the top-level tree object.  A special suffix ^{} (i.e. no\ntype specified) means \"I do not care what it unwraps to; just peel\nannotated tag until you get something that is not a tag\".\n\nWhen you have a random user-supplied string, you can turn it to a\nbare 40-hex object name, and cause it to error out if such an object\ndoes not exist, with:\n\n\tgit rev-parse --verify \"$userstring^{}\"\n\nfor most objects, but this does not yield the tag object name when\n$userstring refers to an annotated tag.\n\nIntroduce a new suffix, ^{object}, that only makes sure the given\nname refers to an existing object.  Then\n\n\tgit rev-parse --verify \"$userstring^{object}\"\n\nbecomes a way to make sure $userstring refers to an existing object.\n\nThis is necessary because the plumbing \"rev-parse --verify\" is only\nabout \"make sure the argument is something we can feed to get_sha1()\nand turn it into a raw 20-byte object name SHA-1\" and is not about\n\"make sure that 20-byte object name SHA-1 refers to an object that\nexists in our object store\".  When the given $userstring is already\na 40-hex, by definition \"rev-parse --verify $userstring\" can turn it\ninto a raw 20-byte object name.  With \"$userstring^{object}\", we can\nmake sure that the 40-hex string names an object that exists in our\nobject store before \"--verify\" kicks in.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n sha1_name.c | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 45788df..85b6e75 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -594,7 +594,7 @@ struct object *peel_to_type(const char *name, int namelen,\n \twhile (1) {\n \t\tif (!o || (!o->parsed && !parse_object(o->sha1)))\n \t\t\treturn NULL;\n-\t\tif (o->type == expected_type)\n+\t\tif (expected_type == OBJ_ANY || o->type == expected_type)\n \t\t\treturn o;\n \t\tif (o->type == OBJ_TAG)\n \t\t\to = ((struct tag*) o)->tagged;\n@@ -645,6 +645,8 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)\n \t\texpected_type = OBJ_TREE;\n \telse if (!strncmp(blob_type, sp, 4) && sp[4] == '}')\n \t\texpected_type = OBJ_BLOB;\n+\telse if (!prefixcmp(sp, \"object}\"))\n+\t\texpected_type = OBJ_ANY;\n \telse if (sp[0] == '}')\n \t\texpected_type = OBJ_NONE;\n \telse if (sp[0] == '/')\n-- \n1.8.2-441-g6e6f07b\n"},{"id":"212862","messageId":"515A94C7.3000406@alum.mit.edu","threadId":"33319","inReplyTo":"7vy5d3nqik.fsf_-_@alter.siamese.dyndns.org","subject":"Re: [PATCH 2/2] peel_onion(): teach $foo^{object} peeler","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2013-04-02T08:20:23Z","receivedAt":"2013-04-02T08:20:23Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"While I was in the middle of suggesting documentation for this new\nsyntax, I discovered that you already added documentation to your repo\nbut didn't mention the new version on the mailing list (or maybe I\noverlooked it).  It would be helpful if you would submit your own\nchanges to the mailing list to make it harder for the rest of us to\noverlook them--and easier to look over them :-)\n\nThe documentation looks fine to me.\n\nOff topic: Your patch reminds me of something else that surprised me:\nthere is no \"$userstring^{tag}\".  I suppose it would be a bit ambiguous,\ngiven that tags can point at tags, and it would also be less useful than\nthe other suffixes.  But its absence irked the completionist in me :-)\n\nMichael\n\nOn 04/01/2013 12:38 AM, Junio C Hamano wrote:\n> A string that names an object can be suffixed with ^{type} peeler to\n> say \"I have this object name; peel it until you get this type. If\n> you cannot do so, it is an error\".  v1.8.2^{commit} asks for a commit\n> that is pointed at an annotated tag v1.8.2; v1.8.2^{tree} unwraps it\n> further to the top-level tree object.  A special suffix ^{} (i.e. no\n> type specified) means \"I do not care what it unwraps to; just peel\n> annotated tag until you get something that is not a tag\".\n> \n> When you have a random user-supplied string, you can turn it to a\n> bare 40-hex object name, and cause it to error out if such an object\n> does not exist, with:\n> \n> \tgit rev-parse --verify \"$userstring^{}\"\n> \n> for most objects, but this does not yield the tag object name when\n> $userstring refers to an annotated tag.\n> \n> Introduce a new suffix, ^{object}, that only makes sure the given\n> name refers to an existing object.  Then\n> \n> \tgit rev-parse --verify \"$userstring^{object}\"\n> \n> becomes a way to make sure $userstring refers to an existing object.\n> \n> This is necessary because the plumbing \"rev-parse --verify\" is only\n> about \"make sure the argument is something we can feed to get_sha1()\n> and turn it into a raw 20-byte object name SHA-1\" and is not about\n> \"make sure that 20-byte object name SHA-1 refers to an object that\n> exists in our object store\".  When the given $userstring is already\n> a 40-hex, by definition \"rev-parse --verify $userstring\" can turn it\n> into a raw 20-byte object name.  With \"$userstring^{object}\", we can\n> make sure that the 40-hex string names an object that exists in our\n> object store before \"--verify\" kicks in.\n> \n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  sha1_name.c | 4 +++-\n>  1 file changed, 3 insertions(+), 1 deletion(-)\n> \n> diff --git a/sha1_name.c b/sha1_name.c\n> index 45788df..85b6e75 100644\n> --- a/sha1_name.c\n> +++ b/sha1_name.c\n> @@ -594,7 +594,7 @@ struct object *peel_to_type(const char *name, int namelen,\n>  \twhile (1) {\n>  \t\tif (!o || (!o->parsed && !parse_object(o->sha1)))\n>  \t\t\treturn NULL;\n> -\t\tif (o->type == expected_type)\n> +\t\tif (expected_type == OBJ_ANY || o->type == expected_type)\n>  \t\t\treturn o;\n>  \t\tif (o->type == OBJ_TAG)\n>  \t\t\to = ((struct tag*) o)->tagged;\n> @@ -645,6 +645,8 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)\n>  \t\texpected_type = OBJ_TREE;\n>  \telse if (!strncmp(blob_type, sp, 4) && sp[4] == '}')\n>  \t\texpected_type = OBJ_BLOB;\n> +\telse if (!prefixcmp(sp, \"object}\"))\n> +\t\texpected_type = OBJ_ANY;\n>  \telse if (sp[0] == '}')\n>  \t\texpected_type = OBJ_NONE;\n>  \telse if (sp[0] == '/')\n> \n\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\nhttp://softwareswirl.blogspot.com/\n"},{"id":"212889","messageId":"7vfvz9gclo.fsf@alter.siamese.dyndns.org","threadId":"33319","inReplyTo":"515A94C7.3000406@alum.mit.edu","subject":"Re: [PATCH 2/2] peel_onion(): teach $foo^{object} peeler","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-04-02T15:45:55Z","receivedAt":"2013-04-02T15:45:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael Haggerty <mhagger@alum.mit.edu> writes:\n\n> Off topic: Your patch reminds me of something else that surprised me:\n> there is no \"$userstring^{tag}\".  I suppose it would be a bit ambiguous,\n> given that tags can point at tags, and it would also be less useful than\n> the other suffixes.  But its absence irked the completionist in me :-)\n\nYes, unfortunately, foo^{type} means \"start from foo, and until what\nyou are looking at it is of type, repeatedly peel to see if you can\nget to an object of that type, or stop and report an error\".  If a\ntag A points at another tag B, which in turn points at an object C,\nyou will never see B by applying usual peeling operator.\n\nAlso, v1.8.2^{tag} would be give the tag itself, while master^{tag}\nwould not report the commit \"master\" but would error out, which\nwould be useless.  You are better off doing `git cat-file -t foo`\nand seeing if it is a tag object at that point.\n"},{"id":"212900","messageId":"515B083A.5050808@alum.mit.edu","threadId":"33319","inReplyTo":"7vfvz9gclo.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 2/2] peel_onion(): teach $foo^{object} peeler","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2013-04-02T16:32:58Z","receivedAt":"2013-04-02T16:32:58Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 04/02/2013 05:45 PM, Junio C Hamano wrote:\n> Michael Haggerty <mhagger@alum.mit.edu> writes:\n> \n>> Off topic: Your patch reminds me of something else that surprised me:\n>> there is no \"$userstring^{tag}\".  I suppose it would be a bit ambiguous,\n>> given that tags can point at tags, and it would also be less useful than\n>> the other suffixes.  But its absence irked the completionist in me :-)\n> \n> Yes, unfortunately, foo^{type} means \"start from foo, and until what\n> you are looking at it is of type, repeatedly peel to see if you can\n> get to an object of that type, or stop and report an error\".  If a\n> tag A points at another tag B, which in turn points at an object C,\n> you will never see B by applying usual peeling operator.\n> \n> Also, v1.8.2^{tag} would be give the tag itself, while master^{tag}\n> would not report the commit \"master\" but would error out, which\n> would be useless.  You are better off doing `git cat-file -t foo`\n> and seeing if it is a tag object at that point.\n\nAll correct, of course.  But the user would never use \"master^{tag}\"\nunless he wants a tag and nothing else, so erroring out would be exactly\nthe thing he wants in that case.  This is no different than the\n\"^{commit}\" part of \"master^{tree}^{commit}\", which correctly errors out\nbecause a commit cannot be inferred from a tree.\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\nhttp://softwareswirl.blogspot.com/\n"},{"id":"212906","messageId":"7v6204g9bl.fsf@alter.siamese.dyndns.org","threadId":"33319","inReplyTo":"515B083A.5050808@alum.mit.edu","subject":"Re: [PATCH 2/2] peel_onion(): teach $foo^{object} peeler","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-04-02T16:56:46Z","receivedAt":"2013-04-02T16:56:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael Haggerty <mhagger@alum.mit.edu> writes:\n\n> On 04/02/2013 05:45 PM, Junio C Hamano wrote:\n>\n>> Also, v1.8.2^{tag} would be give the tag itself, while master^{tag}\n>> would not report the commit \"master\" but would error out, which\n>> would be useless.  You are better off doing `git cat-file -t foo`\n>> and seeing if it is a tag object at that point.\n>\n> All correct, of course.  But the user would never use \"master^{tag}\"\n> unless he wants a tag and nothing else, so erroring out would be exactly\n> the thing he wants in that case.  This is no different than the\n> \"^{commit}\" part of \"master^{tree}^{commit}\", which correctly errors out\n> because a commit cannot be inferred from a tree.\n\nCorrect; I was only saying adding it is not something that solves a\nproblem that cannot be solved with the current system (i.e. no added\nvalue from feature point-of-view).  I would not object to a patch to\nallow \"git rev-parse v1.8.2^{tag}\" for completeness.\n\nWe may want to rethink if we can lose the hardcoded lengths like 6,\n3, 4, 4 from here, but I didn't bother ;-).\n\n\n sha1_name.c | 8 +++++---\n 1 file changed, 5 insertions(+), 3 deletions(-)\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 85b6e75..47f39a8 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -639,16 +639,18 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)\n \t\treturn -1;\n \n \tsp++; /* beginning of type name, or closing brace for empty */\n-\tif (!strncmp(commit_type, sp, 6) && sp[6] == '}')\n+\tif (!strncmp(tag_type, sp, 3) && sp[3] == '}')\n+\t\texpected_type = OBJ_TAG;\n+\telse if (!strncmp(commit_type, sp, 6) && sp[6] == '}')\n \t\texpected_type = OBJ_COMMIT;\n \telse if (!strncmp(tree_type, sp, 4) && sp[4] == '}')\n \t\texpected_type = OBJ_TREE;\n \telse if (!strncmp(blob_type, sp, 4) && sp[4] == '}')\n \t\texpected_type = OBJ_BLOB;\n \telse if (!prefixcmp(sp, \"object}\"))\n-\t\texpected_type = OBJ_ANY;\n+\t\texpected_type = OBJ_ANY; /* ok as long as it exists */\n \telse if (sp[0] == '}')\n-\t\texpected_type = OBJ_NONE;\n+\t\texpected_type = OBJ_NONE; /* unwrap until we get a non-tag */\n \telse if (sp[0] == '/')\n \t\texpected_type = OBJ_COMMIT;\n \telse\n"}]}