{"thread":{"id":"35605","subject":"Re: Bug report: stash in upstream caused remote fetch to fail","startedAt":"2014-01-03T21:12:51Z","lastAt":"2014-01-15T10:48:26Z","messageCount":10,"participants":["Matt Burke","Jeff King","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"232640","messageId":"CAECVvXYD69Xrp85bVJg6XogvctUTwrFDae+3tawFgoCAUGhwGg@mail.gmail.com","threadId":"35605","inReplyTo":null,"subject":"Re: Bug report: stash in upstream caused remote fetch to fail","fromName":"Matt Burke","fromEmail":"spraints@gmail.com","sentAt":"2014-01-03T21:12:51Z","receivedAt":"2014-01-03T21:12:51Z","isPatch":false,"sender":{"key":"spraints@gmail.com","avatar":null},"body":"I ran into the same (or similar) problem as reported in\n<http://www.spinics.net/lists/git/msg173391.html>. I have a script\nthat, among other things, clones a git repository. Here's where it\ndoes that:\n\n+ git init -q\n+ git fetch -q -fu ../../../other '+refs/*:refs/*'\nfatal: bad object 9b985fbe6a2b783c16756077a8be261c94b6c197\nerror: ../../../other did not send all necessary objects\n\nIn ../../../other:\n\n$ git rev-parse stash@{0}\n9b985fbe6a2b783c16756077a8be261c94b6c197\n$ grep stash .git/packed-refs\n9b985fbe6a2b783c16756077a8be261c94b6c197 refs/stash\n$ cat .git/refs/stash\n9b985fbe6a2b783c16756077a8be261c94b6c197\n\nI removed the line from packed-refs and removed the refs/stash file,\nand the problem went away. Restoring packed-refs or refs/stash makes\nthe error occur again.\n\nWhen this was reported before, Thomas Rast wrote:\n\n> Do you, by any chance, still have a copy of the upstream repo before you\n> trashed the stash?  It would be interesting to know whether there was\n> actually some repository corruption going on (that went unnoticed by\n> fsck, no less) or if there was a bug in the transmission.\n\nI've still got the repository, and am happy to help debug this.\n\n--\nMatt\n"},{"id":"232717","messageId":"20140106152742.GA26221@sigill.intra.peff.net","threadId":"35605","inReplyTo":"CAECVvXYD69Xrp85bVJg6XogvctUTwrFDae+3tawFgoCAUGhwGg@mail.gmail.com","subject":"Re: Bug report: stash in upstream caused remote fetch to fail","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-01-06T15:27:42Z","receivedAt":"2014-01-06T15:27:42Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jan 03, 2014 at 04:12:51PM -0500, Matt Burke wrote:\n\n> + git init -q\n> + git fetch -q -fu ../../../other '+refs/*:refs/*'\n> fatal: bad object 9b985fbe6a2b783c16756077a8be261c94b6c197\n> error: ../../../other did not send all necessary objects\n\nI was going to ask you to send your repository, but I can easily\nreproduce here. I guess people don't run into it because it's uncommon\nto fetch the whole refs/ namespace from a non-bare repo (and bare repos\ndo not tend to have stashes). Here's a minimal reproduction recipe:\n\n  git init repo &&\n  cd repo &&\n  echo content >foo &&\n  git add . &&\n  git commit -m foo &&\n  echo more >>foo &&\n  git stash &&\n  git init --bare sub &&\n  cd sub &&\n  git fetch .. 'refs/*:refs/*'\n\nIt looks like we are not feeding refs/stash properly to pack-objects.\nI'll try to take a closer look later today.\n\n-Peff\n"},{"id":"232723","messageId":"xmqqbnzpkrvk.fsf@gitster.dls.corp.google.com","threadId":"35605","inReplyTo":"20140106152742.GA26221@sigill.intra.peff.net","subject":"Re: Bug report: stash in upstream caused remote fetch to fail","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-01-06T16:16:31Z","receivedAt":"2014-01-06T16:16:31Z","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 Fri, Jan 03, 2014 at 04:12:51PM -0500, Matt Burke wrote:\n>\n>> + git init -q\n>> + git fetch -q -fu ../../../other '+refs/*:refs/*'\n>> fatal: bad object 9b985fbe6a2b783c16756077a8be261c94b6c197\n>> error: ../../../other did not send all necessary objects\n>\n> I was going to ask you to send your repository, but I can easily\n> reproduce here. I guess people don't run into it because it's uncommon\n> to fetch the whole refs/ namespace from a non-bare repo (and bare repos\n> do not tend to have stashes). Here's a minimal reproduction recipe:\n>\n>   git init repo &&\n>   cd repo &&\n>   echo content >foo &&\n>   git add . &&\n>   git commit -m foo &&\n>   echo more >>foo &&\n>   git stash &&\n>   git init --bare sub &&\n>   cd sub &&\n>   git fetch .. 'refs/*:refs/*'\n>\n> It looks like we are not feeding refs/stash properly to pack-objects.\n> I'll try to take a closer look later today.\n\nI looked at this in the past and I vaguely recall that we reject it\nin the for-each-ref loop with check-ref-format saying \"eh, that is a\nsingle-level name\".\n\nAt that point I stopped digging, thinking it was a feature ;-)\nbased on your exact observation about stash vs bare/non-bare.\n"},{"id":"232753","messageId":"20140106193625.GA27062@sigill.intra.peff.net","threadId":"35605","inReplyTo":"xmqqbnzpkrvk.fsf@gitster.dls.corp.google.com","subject":"Re: Bug report: stash in upstream caused remote fetch to fail","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-01-06T19:36:26Z","receivedAt":"2014-01-06T19:36:26Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jan 06, 2014 at 08:16:31AM -0800, Junio C Hamano wrote:\n\n> > I was going to ask you to send your repository, but I can easily\n> > reproduce here. I guess people don't run into it because it's uncommon\n> > to fetch the whole refs/ namespace from a non-bare repo (and bare repos\n> > do not tend to have stashes). Here's a minimal reproduction recipe:\n> >\n> >   git init repo &&\n> >   cd repo &&\n> >   echo content >foo &&\n> >   git add . &&\n> >   git commit -m foo &&\n> >   echo more >>foo &&\n> >   git stash &&\n> >   git init --bare sub &&\n> >   cd sub &&\n> >   git fetch .. 'refs/*:refs/*'\n> >\n> > It looks like we are not feeding refs/stash properly to pack-objects.\n> > I'll try to take a closer look later today.\n> \n> I looked at this in the past and I vaguely recall that we reject it\n> in the for-each-ref loop with check-ref-format saying \"eh, that is a\n> single-level name\".\n> \n> At that point I stopped digging, thinking it was a feature ;-)\n> based on your exact observation about stash vs bare/non-bare.\n\nI am fine with rejecting it with a warning, but we should not then\ncomplain that the other side did not send us the object, since we should\nnot be asking for it at all. I also do not see us complaining about the\nfunny ref anywhere.  So there is definitely _a_ bug here. :)\n\nI think somebody else mentioned recently that we do not handle malformed\nrefs consistently. I think it was:\n\n  http://article.gmane.org/gmane.comp.version-control.git/239381\n\nwhich might or might not be related.\n\n-Peff\n"},{"id":"232757","messageId":"xmqq61pwj25q.fsf@gitster.dls.corp.google.com","threadId":"35605","inReplyTo":"20140106193625.GA27062@sigill.intra.peff.net","subject":"Re: Bug report: stash in upstream caused remote fetch to fail","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-01-06T20:17:21Z","receivedAt":"2014-01-06T20:17:21Z","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 Mon, Jan 06, 2014 at 08:16:31AM -0800, Junio C Hamano wrote:\n>\n>> > I was going to ask you to send your repository, but I can easily\n>> > reproduce here. I guess people don't run into it because it's uncommon\n>> > to fetch the whole refs/ namespace from a non-bare repo (and bare repos\n>> > do not tend to have stashes). Here's a minimal reproduction recipe:\n>> >\n>> >   git init repo &&\n>> >   cd repo &&\n>> >   echo content >foo &&\n>> >   git add . &&\n>> >   git commit -m foo &&\n>> >   echo more >>foo &&\n>> >   git stash &&\n>> >   git init --bare sub &&\n>> >   cd sub &&\n>> >   git fetch .. 'refs/*:refs/*'\n>> >\n>> > It looks like we are not feeding refs/stash properly to pack-objects.\n>> > I'll try to take a closer look later today.\n>> \n>> I looked at this in the past and I vaguely recall that we reject it\n>> in the for-each-ref loop with check-ref-format saying \"eh, that is a\n>> single-level name\".\n>> \n>> At that point I stopped digging, thinking it was a feature ;-)\n>> based on your exact observation about stash vs bare/non-bare.\n>\n> I am fine with rejecting it with a warning, but we should not then\n> complain that the other side did not send us the object, since we should\n> not be asking for it at all. I also do not see us complaining about the\n> funny ref anywhere.  So there is definitely _a_ bug here. :)\n\nOh, no question about that.  I was just pointing somebody who\nalready has volunteered to take a look in a direction I recall was\nwhere the issue was ;-)\n\nThanks.\n\n>\n> I think somebody else mentioned recently that we do not handle malformed\n> refs consistently. I think it was:\n>\n>   http://article.gmane.org/gmane.comp.version-control.git/239381\n>\n> which might or might not be related.\n>\n> -Peff\n"},{"id":"232780","messageId":"20140106230348.GA7811@sigill.intra.peff.net","threadId":"35605","inReplyTo":"xmqq61pwj25q.fsf@gitster.dls.corp.google.com","subject":"Re: Bug report: stash in upstream caused remote fetch to fail","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-01-06T23:03:48Z","receivedAt":"2014-01-06T23:03:48Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jan 06, 2014 at 12:17:21PM -0800, Junio C Hamano wrote:\n\n> > I am fine with rejecting it with a warning, but we should not then\n> > complain that the other side did not send us the object, since we should\n> > not be asking for it at all. I also do not see us complaining about the\n> > funny ref anywhere.  So there is definitely _a_ bug here. :)\n> \n> Oh, no question about that.  I was just pointing somebody who\n> already has volunteered to take a look in a direction I recall was\n> where the issue was ;-)\n\nOh, crud, did I volunteer? :)\n\nSo I found the problem, but I'm really not sure what to make of it. We\ndo check the refname format when evaluating the refspecs, in:\n\n    do_fetch\n      get_ref_map\n        get_fetch_map\n          check_refname_format\n\nBefore calling it, we check that it starts with \"refs/\", and then pass\nthe _whole_ refname into check_refname_format. So the latter sees\n\"refs/stash\". And that's acceptable, as it's not a single-level ref.\nThus we do not get the \"funny ref\" message.\n\nThe code looks like this:\n\n  if (!starts_with((*rmp)->peer_ref->name, \"refs/\") ||\n      check_refname_format((*rmp)->peer_ref->name, 0)) {\n        /* print funny ref and ignore */\n\nThen we ask fetch_refs_via_pack to get the actual objects for us. And\nit checks our refs again, with this call chain:\n\n  do_fetch\n    fetch_refs\n      transport_fetch_refs\n        fetch_refs_via_pack\n          fetch_pack\n            do_fetch_pack\n              everything_local\n                filter_refs\n                  check_refname_format\n\nHere, the code looks like this:\n\n  if (!memcmp(ref->name, \"refs/\", 5) &&\n      check_refname_format(ref->name + 5, 0))\n    ; /* trash */\n\nAt first I thought we are doing the same check (is it syntactically\nvalid, and is it in \"refs/\"), but we're not. We are actually checking\nthe format _only_ of stuff in \"refs/\", and ignoring the rest. Which\nreally makes no sense to me.\n\nIf it were \"memcmp(...) || check_refname_format()\", then it would be\nroughly the same check. But it would still be wrong, because note that\nwe pass only the bits under \"refs/\" to check_refname_format. So it sees\nonly \"stash\", and then complains that it is single-level.\n\nSo the symptom we are seeing is because we are filtering with two\ndifferent rulesets in different places. But I'm really not sure how to\nresolve it. The one in filter_refs seems nonsensical to me.\n\nChecking _only_ things under refs/ doesn't make sense. And even if that\nwas sensible, feeding half a ref to check_refname_format does not work.\nIn addition to the single-level check, it has other rules that want\nto see the whole ref (e.g., the ref \"@\" is not valid, but \"refs/@\" is\nOK; it cannot distinguish them without seeing the prefix).\n\nSo I can see two options:\n\n  1. Make the check in filter_refs look like the one in get_fetch_map.\n     That at least makes them the same, which alleviates the symptom.\n     But we still are running two checks, and if they ever get out of\n     sync, it causes problems.\n\n  2. Abolish the check in filter_refs. I think this makes the most sense\n     from the perspective of fetch, because we will already have cleaned up\n     the ref list. But we might need to leave the filtering in place for\n     people who call fetch-pack as a bare plumbing command.\n\nIt's really not clear to me what the check in filter_refs was trying to\ndo. It dates all the way back to 1baaae5 (Make maximal use of the remote\nrefs, 2005-10-28), but there is not much explanation. I haven't dug into\nthe list around that time to see if there's any discussion.\n\n-Peff\n"},{"id":"232783","messageId":"xmqq4n5ghf0z.fsf@gitster.dls.corp.google.com","threadId":"35605","inReplyTo":"20140106230348.GA7811@sigill.intra.peff.net","subject":"Re: Bug report: stash in upstream caused remote fetch to fail","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-01-06T23:22:20Z","receivedAt":"2014-01-06T23:22:20Z","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> Then we ask fetch_refs_via_pack to get the actual objects for us. And\n> it checks our refs again, with this call chain:\n>\n>   do_fetch\n>     fetch_refs\n>       transport_fetch_refs\n>         fetch_refs_via_pack\n>           fetch_pack\n>             do_fetch_pack\n>               everything_local\n>                 filter_refs\n>                   check_refname_format\n>\n> Here, the code looks like this:\n>\n>   if (!memcmp(ref->name, \"refs/\", 5) &&\n>       check_refname_format(ref->name + 5, 0))\n>     ; /* trash */\n\nI think this should feed ref->name, not ref->name + 5; an obvious\nalternative would be to use REFNAME_ALLOW_ONELEVEL; you are also\nright that && is probably a misspelt ||; this is about protecting\nourselves from creating garbage in our ref namespace, so accepting\nanything outside refs/ makes little sense.\n\n> It's really not clear to me what the check in filter_refs was trying to\n> do. It dates all the way back to 1baaae5 (Make maximal use of the remote\n> refs, 2005-10-28), but there is not much explanation. I haven't dug into\n> the list around that time to see if there's any discussion.\n\nI think the \"funny refs\" the log message talks about is about\nfiltering \"we know we can reach these objects via our alternates,\nbut these are not refs we actually have\".\n"},{"id":"232795","messageId":"7vtxdg1nsg.fsf@alter.siamese.dyndns.org","threadId":"35605","inReplyTo":"xmqq4n5ghf0z.fsf@gitster.dls.corp.google.com","subject":"Re: Bug report: stash in upstream caused remote fetch to fail","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-01-07T03:19:43Z","receivedAt":"2014-01-07T03:19:43Z","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>> It's really not clear to me what the check in filter_refs was trying to\n>> do. It dates all the way back to 1baaae5 (Make maximal use of the remote\n>> refs, 2005-10-28), but there is not much explanation. I haven't dug into\n>> the list around that time to see if there's any discussion.\n>\n> I think the \"funny refs\" the log message talks about is about\n> filtering \"we know we can reach these objects via our alternates,\n> but these are not refs we actually have\".\n\nActually, I think the above recollection of mine was completely\nbogus.  The && is there because we do allow things like \"HEAD\" (they\nare the funny ones) as well as things inside refs/, and the latter\nis the only thing we had a check-ref-format to dictate the format\nwhen the code was written.\n\nI do not mind tightening things a bit (e.g. outside refs/, only\nallow HEAD and nothing else).  A good first step might be to enforce\nallow-onelevel outside refs/ (so that we can allow \"HEAD\") and for\nthose inside refs/ check without allow-onelevel but without skipping\nthe prefix.\n\nIt is a separate story if it makes much sense to allow fetching\nrefs/stash or ignoring when running \"git clone\".  Operationally, I\nthink it makes more sense to ignore refs/stash, not because it is a\none-level name, but because what a stash is.\n"},{"id":"233141","messageId":"20140115104612.GE14335@sigill.intra.peff.net","threadId":"35605","inReplyTo":"7vtxdg1nsg.fsf@alter.siamese.dyndns.org","subject":"Re: Bug report: stash in upstream caused remote fetch to fail","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-01-15T10:46:13Z","receivedAt":"2014-01-15T10:46:13Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jan 06, 2014 at 07:19:43PM -0800, Junio C Hamano wrote:\n\n> Actually, I think the above recollection of mine was completely\n> bogus.  The && is there because we do allow things like \"HEAD\" (they\n> are the funny ones) as well as things inside refs/, and the latter\n> is the only thing we had a check-ref-format to dictate the format\n> when the code was written.\n> \n> I do not mind tightening things a bit (e.g. outside refs/, only\n> allow HEAD and nothing else).  A good first step might be to enforce\n> allow-onelevel outside refs/ (so that we can allow \"HEAD\") and for\n> those inside refs/ check without allow-onelevel but without skipping\n> the prefix.\n> \n> It is a separate story if it makes much sense to allow fetching\n> refs/stash or ignoring when running \"git clone\".  Operationally, I\n> think it makes more sense to ignore refs/stash, not because it is a\n> one-level name, but because what a stash is.\n\nThis discussion stalled, but I finally got around to looking at it\ntoday. I agree that we should leave aside more complex policy for now,\nand start with bringing the \"fetch\" and \"fetch-pack\" filters into\nharmony. That turns off format-checking for things outside \"refs/\" (so\nallows \"HEAD\"), and checks the whole string for things inside \"refs/\"\n(so it does not fall afoul of the one-level check).\n\nI ended up with the patch below, which converts fetch-pack to match\nfetch. However, reading the original one-level check in 03feddd\n(git-check-ref-format: reject funny ref names., 2005-10-13), it does\nseem like it was meant to reject \"refs/foo\". It contains:\n\n        if (level < 2)\n                return -1; /* at least of form \"heads/blah\" */\n\nIt seems like the meaning of this check changed over the years. I am not\nsure if that was intentional or not. :)\n\nSo we could go the other direction, and harmonize on disallowing\n\"refs/foo\". I don't particularly care that much. The nasty thing now is\nthe mismatch between the two spots, which means that \"fetch\" doesn't\njust ignore the ref, but bombs out with a missing object.\n\n\n-- >8 --\nSubject: fetch-pack: do not filter out one-level refs\n\nCurrently fetching a one-level ref like \"refs/foo\" does not\nwork consistently. The outer \"git fetch\" program filters the\nlist of refs, checking each against check_refname_format.\nThen it feeds the result to do_fetch_pack to actually\nnegotiate the haves/wants and get the pack. The fetch-pack\ncode does its own filter, and it behaves differently.\n\nThe fetch-pack filter looks for refs in \"refs/\", and then\nfeeds everything _after_ the slash (i.e., just \"foo\") into\ncheck_refname_format.  But check_refname_format is not\ndesigned to look at a partial refname. It complains that the\nref has only one component, thinking it is at the root\n(i.e., alongside \"HEAD\"), when in reality we just fed it a\npartial refname.\n\nAs a result, we omit a ref like \"refs/foo\" from the pack\nrequest, even though \"git fetch\" then tries to store the\nresulting ref.  If we happen to get the object anyway (e.g.,\nbecause the ref is contained in another ref we are\nfetching), then the fetch succeeds. But if it is a unique\nobject, we fail when trying to update \"refs/foo\".\n\nWe can fix this by just passing the whole refname into\ncheck_refname_format; we know the part we were omitting is\n\"refs/\", which is acceptable in a refname. This at least\nmakes the checks consistent with each other.\n\nThis problem happens most commonly with \"refs/stash\", which\nis the only one-level ref in wide use. However, our test\ndoes not use \"refs/stash\", as we may later want to restrict\nit specifically (not because it is one-level, but because\nof the semantics of stashes).\n\nWe may also want to do away with the multiple levels of\nfiltering (which can cause problems when they are out of\nsync), or even forbid one-level refs entirely. However,\nthose decisions can come later; this fixes the most\nimmediate problem, which is the mismatch between the two.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n fetch-pack.c     |  2 +-\n t/t5510-fetch.sh | 11 +++++++++++\n 2 files changed, 12 insertions(+), 1 deletion(-)\n\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 760ed16..b28ccd1 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -505,7 +505,7 @@ static void filter_refs(struct fetch_pack_args *args,\n \t\tnext = ref->next;\n \n \t\tif (!memcmp(ref->name, \"refs/\", 5) &&\n-\t\t    check_refname_format(ref->name + 5, 0))\n+\t\t    check_refname_format(ref->name, 0))\n \t\t\t; /* trash */\n \t\telse {\n \t\t\twhile (i < nr_sought) {\ndiff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh\nindex 12674ac..ab28594 100755\n--- a/t/t5510-fetch.sh\n+++ b/t/t5510-fetch.sh\n@@ -640,4 +640,15 @@ test_expect_success 'branchname D/F conflict resolved by --prune' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'fetching a one-level ref works' '\n+\ttest_commit extra &&\n+\tgit reset --hard HEAD^ &&\n+\tgit update-ref refs/foo extra &&\n+\tgit init one-level &&\n+\t(\n+\t\tcd one-level &&\n+\t\tgit fetch .. HEAD refs/foo\n+\t)\n+'\n+\n test_done\n-- \n1.8.5.2.500.g8060133\n"},{"id":"233142","messageId":"20140115104826.GF14335@sigill.intra.peff.net","threadId":"35605","inReplyTo":"20140115104612.GE14335@sigill.intra.peff.net","subject":"Re: Bug report: stash in upstream caused remote fetch to fail","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-01-15T10:48:26Z","receivedAt":"2014-01-15T10:48:26Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jan 15, 2014 at 05:46:13AM -0500, Jeff King wrote:\n\n> This discussion stalled, but I finally got around to looking at it\n> today. I agree that we should leave aside more complex policy for now,\n> and start with bringing the \"fetch\" and \"fetch-pack\" filters into\n> harmony. That turns off format-checking for things outside \"refs/\" (so\n> allows \"HEAD\"), and checks the whole string for things inside \"refs/\"\n> (so it does not fall afoul of the one-level check).\n\nBy the way, an interesting implication of this is that I do not think\nthere is any format check on things outside of refs/. If you were to do\n\n  git fetch ... +*:*\n\nyou would write whatever crap the other side gives you. I can't imagine\nany reason a client would _ever_ do that, though, so I don't think it's\na big deal. We tend to fetch HEAD explicitly by name, and that's it.\n\n-Peff\n"}]}