{"thread":{"id":"2054","subject":"Strangely broken git repo","startedAt":"2005-10-10T04:26:05Z","lastAt":"2005-10-12T22:01:46Z","messageCount":21,"participants":["Martin Langhoff (CatalystIT)","Junio C Hamano","Linus Torvalds","Morten Welinder","Johannes Schindelin","Matthias Urlichs","Nick Hengeveld","Petr Baudis","H. Peter Anvin"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"9867","messageId":"4349ED5D.6020703@catalyst.net.nz","threadId":"2054","inReplyTo":"46a038f90510082014i6b296f2bvbac56e25344cbdf2@mail.gmail.com","subject":"Strangely broken git repo","fromName":"Martin Langhoff (CatalystIT)","fromEmail":"martin@catalyst.net.nz","sentAt":"2005-10-10T04:26:05Z","receivedAt":"2005-10-10T04:26:05Z","isPatch":false,"sender":{"key":"martin@laptop.org","avatar":null},"body":"Hi!\n\nWe are having strange problems pushing (and pulling) with a particular\nhead in a git repo. The repo is publicly available via http, and when\nI clone it it gives me a lot of errors\n\n$ cg-clone http://locke.catalyst.net.nz/git/moodle.git#moodle--topnz\n...\nGetting index for pack 3e3492f365bb0d4a1ae11dfa7cee9ebbf345e647\nGetting pack 3113eb34ef85482c87c3575721ce978c7232071f\nwhich contains 007a0323cf0941476dc262f6e3aff6bb9600dcd8\nerror: The requested file was not found\n... (many more like these)\nFINISHED --15:56:38--\nDownloaded: 4,723 bytes in 1 files\nNew branch: 6759e2800c0cef00017c63b7dbbed80e481dbe2c\nCloned to moodle.git#moodle--topnz/ (origin\nhttp://locke.catalyst.net.nz/git/moodle.git#moodle--topnz available as\nbranch \"origin\")\naporo:~/tmp/moodle.git#moodle--topnz martin$ git-fsck-objects\nbad sha1 file: .git/objects/00/7a0323cf0941476dc262f6e3aff6bb9600dcd8.temp\n... (many more like these)\n\nWhen using git+ssh, we are seeing very strange stalls during the\nfetch, and when trying to push a couple of small new commits, it has\ngiven us (from a Debian etch-ppc, git 0.99.8.b) gives us \"fatal unpack\nshould have generated <sha1> but I can't find it\".\n\nThis has been discussed earlier here\nhttp://www.gelato.unsw.edu.au/archives/git/0508/7152.html -- but our\nscenario doesn't involve rewinding or any strange trickery, it's just\nclone - edit - commit - push.\n\n From a different machine (Debian sarge, i386, git 0.99.8b) the same\noperation succeeds.\n\nOn the repo itself, I've run git-fsck-objects --full --strict and it\nonly complained about dangling tags. There are some heads on that repo\nthat I have deleted a while ago without purging unreachable objects,\nso I kind of expected those.\n\nThere are some automated jobs that touch this repo and may have messed\nthings up:\n  - cronjobs running git-cvsimport and git-archimport and pushing to \nthis repo\n  - weekly git-repack run over the repo\n\nUff. I have the feeling that this isn't a very complete picture, but\nI'm not sure what else to do to debug this one. Pointers welcome.\n\ncheers,\n\n\nmartin\n"},{"id":"9871","messageId":"7v4q7p927d.fsf@assigned-by-dhcp.cox.net","threadId":"2054","inReplyTo":"4349ED5D.6020703@catalyst.net.nz","subject":"Re: Strangely broken git repo","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-10T09:00:06Z","receivedAt":"2005-10-10T09:00:06Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Martin Langhoff (CatalystIT)\" <martin@catalyst.net.nz> writes:\n\n> $ cg-clone http://locke.catalyst.net.nz/git/moodle.git#moodle--topnz\n> ...\n> Getting index for pack 3e3492f365bb0d4a1ae11dfa7cee9ebbf345e647\n> Getting pack 3113eb34ef85482c87c3575721ce978c7232071f\n> which contains 007a0323cf0941476dc262f6e3aff6bb9600dcd8\n> error: The requested file was not found\n> ... (many more like these)\n\nSo it failed to grab 007a0323cf0941476dc262f6e3aff6bb9600dcd8,\nbut that is OK.  That object is in a pack:\npack-3113eb34ef85482c87c3575721ce978c7232071f has it.\n\n> FINISHED --15:56:38--\n> Downloaded: 4,723 bytes in 1 files\n> New branch: 6759e2800c0cef00017c63b7dbbed80e481dbe2c\n> Cloned to moodle.git#moodle--topnz/ (origin\n> http://locke.catalyst.net.nz/git/moodle.git#moodle--topnz available as\n> branch \"origin\")\n> aporo:~/tmp/moodle.git#moodle--topnz martin$ git-fsck-objects\n> bad sha1 file: .git/objects/00/7a0323cf0941476dc262f6e3aff6bb9600dcd8.temp\n> ... (many more like these)\n\nThis *.temp file is what git-http-fetch creates while retrieving\nthe object.  After successfully downloading it, it is renamed to\nits final name (i.e. sans .temp), but that rename did not\nhappen.  Well, this object is in a pack, so after failing to\nretrieve that, we should have got the list of packs, retrieved\npack index files, and grabbed the pack that contained that\nobject.  We *should* clean up the *.temp file for this object\nwhe we do this, but I do not think we do.  But I do not think\nthis is the _cause_ of your problem.  It is a symptom that\nsomething is going wrong -- namely, the question is why it was\nnot found in pack-3113eb34ef85482c87c3575721ce978c7232071f.  Did\nthe client download that pack?\n\nI just tried to clone your repository with 'git clone', and saw\nsomething failing, but I think the object trasfer went fine all\nthe way down to the initial commit.  I can see this object in my\ncloned repository:\n\n        commit 34cc394a7427adf730cfd3fb482dc6d6d5b58775\n        Author: Martin Langhoff <martin@catalyst.net.nz>\n        Date:   Tue Aug 3 02:50:51 2004 +0000\n\n            initial import\n\nThere are funky tag names in your refs/tags directory.  The\nreally core tools should be able to grok them just fine, but\ngit-http-fetch failed with this from curl library:\n\nThe requested URL returned error: 404\nerror: Couldn't get http://locke.catalyst.net.nz/git/moodle.git/refs/tags/MOODLE_15_MERGED **INVALID** for tags/MOODLE_15_MERGED **INVALID**\n\nI do not speak curl, but I wonder if we should be quoting\nthese funky characters like SP and asterisk in the URL when we\nmake that request, or it is what the library does for us.\n\nHmph.  Interesting.  I just tried.\n\n$ curl 'http://locke.catalyst.net.nz/git/moodle.git/refs/tags/MOODLE_15_MERGED **INVALID**'\n\ngives an error page \"404 Not Found\", while\n\n$ wget -O - -o /dev/null 'http://locke.catalyst.net.nz/git/moodle.git/refs/tags/MOODLE_15_MERGED **INVALID**'\n\nworks fine and gives 2ddfec0dfd0cffd4892af9aaf48ee29c40c7ada3\nback.  So we do need to fix things up somewhat in our scripts as\nwell.\n\nAnyway, I think I know the problems 'git-clone' would have had\nif you tried to clone it with it (not cg-clone which I do not\nknow much about), and luckily it is only towards the end (after\nfetching most of the heads, but hitting the first funky tag).\nWe should be able to fix this relatively easily.\n\nOh, Daniel and Nick, while I was reading the http-fetch.c code,\nI noticed another thing.\n\nThe fetch_alternates() function was supposed to be call-once and\nwe have a static variable got_alternates that becomes 1 when it\nruns for the first time.  However, there are other 'return 0's\nintroduced that does not set got_alternates to 1.\n\nI am wondering if the semantics has changed that now we chain\nthe alternates?  Initially, if we are cloning/fetching from\nrepository A, which borrows from repository B (i.e. alternates\nwe retrieve from A would name B), and if B in turn borrows from\nC, then we assumed that A's alternates would also name C, and\nthat was the reason why fetch_alternates() was call-once\nfunction.  I do not mind if we change it to chain the alternates\nfile, but if that is the case we should move the got_alternates\nvariable into \"struct alt_base\", and pass the struct, not just\nalt->base, to fetch_alternates(), like this (untested, of\ncourse):\n\ndiff --git a/http-fetch.c b/http-fetch.c\nindex 5821c9e..2301f88 100644\n--- a/http-fetch.c\n+++ b/http-fetch.c\n@@ -38,6 +38,7 @@ struct alt_base\n {\n \tchar *base;\n \tint got_indices;\n+\tint got_alternates;\n \tstruct packed_git *packs;\n \tstruct alt_base *next;\n };\n@@ -529,8 +530,6 @@ void prefetch(unsigned char *sha1)\n #endif\n }\n \n-static int got_alternates = 0;\n-\n static int fetch_index(struct alt_base *repo, unsigned char *sha1)\n {\n \tchar *hex = sha1_to_hex(sha1);\n@@ -611,8 +610,9 @@ static int setup_index(struct alt_base *\n \treturn 0;\n }\n \n-static int fetch_alternates(char *base)\n+static int fetch_alternates(struct alt_base *this_alt)\n {\n+\tchar *base = this_alt->base;\n \tint ret = 0;\n \tstruct buffer buffer;\n \tchar *url;\n@@ -622,15 +622,17 @@ static int fetch_alternates(char *base)\n \tstruct alt_base *tail = alt;\n \n \tstruct active_request_slot *slot;\n-\tif (got_alternates)\n+\tif (this_alt->got_alternates)\n \t\treturn 0;\n+\tthis_alt->got_alternates = 1;\n \tdata = xmalloc(4096);\n \tbuffer.size = 4095;\n \tbuffer.posn = 0;\n \tbuffer.buffer = data;\n \n \tif (get_verbosely)\n-\t\tfprintf(stderr, \"Getting alternates list\\n\");\n+\t\tfprintf(stderr, \"Getting alternates list for %s\\n\",\n+\t\t\tbase);\n \t\n \turl = xmalloc(strlen(base) + 31);\n \tsprintf(url, \"%s/objects/info/http-alternates\", base);\n@@ -721,7 +723,6 @@ static int fetch_alternates(char *base)\n \t\t}\n \t\ti = posn + 1;\n \t}\n-\tgot_alternates = 1;\n \t\n \treturn ret;\n }\n@@ -1092,9 +1093,10 @@ int main(int argc, char **argv)\n \talt = xmalloc(sizeof(*alt));\n \talt->base = url;\n \talt->got_indices = 0;\n+\talt->got_alternates = 0;\n \talt->packs = NULL;\n \talt->next = NULL;\n-\tfetch_alternates(alt->base);\n+\tfetch_alternates(alt);\n \n \tif (pull(commit_id))\n \t\treturn 1;\n"},{"id":"9883","messageId":"Pine.LNX.4.64.0510100742070.14597@g5.osdl.org","threadId":"2054","inReplyTo":"7v4q7p927d.fsf@assigned-by-dhcp.cox.net","subject":"Re: Strangely broken git repo","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-10T14:54:31Z","receivedAt":"2005-10-10T14:54:31Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Mon, 10 Oct 2005, Junio C Hamano wrote:\n> \n> Hmph.  Interesting.  I just tried.\n> \n> $ curl 'http://locke.catalyst.net.nz/git/moodle.git/refs/tags/MOODLE_15_MERGED **INVALID**'\n> \n> gives an error page \"404 Not Found\", while\n> \n> $ wget -O - -o /dev/null 'http://locke.catalyst.net.nz/git/moodle.git/refs/tags/MOODLE_15_MERGED **INVALID**'\n> \n> works fine and gives 2ddfec0dfd0cffd4892af9aaf48ee29c40c7ada3\n> back.  So we do need to fix things up somewhat in our scripts as\n> well.\n\nIt seems to be the space. Doing\n\n  $ curl 'http://locke.catalyst.net.nz/git/moodle.git/refs/tags/MOODLE_15_MERGED%20**INVALID**'\n\nworks ok (ie %20 instead of ' ').\n\nAs far as I can tell, we should probably _also_ quote any curl-specific \nstuff. As far as I can tell from the manual, if the tag were to have \nspecial characters like '[' and '{', curl might confuse them with being \nrange specifiers.\n\n\t\tLinus\n"},{"id":"9885","messageId":"Pine.LNX.4.64.0510100800580.14597@g5.osdl.org","threadId":"2054","inReplyTo":"Pine.LNX.4.64.0510100742070.14597@g5.osdl.org","subject":"Re: Strangely broken git repo","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-10T15:21:30Z","receivedAt":"2005-10-10T15:21:30Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Mon, 10 Oct 2005, Linus Torvalds wrote:\n> \n> It seems to be the space.\n\nDoing an strace on curl vs wget shows that curl seems to do no quoting at \nall. I'd personally argue that that is a serious bug in curl: it sure as \nhell knows that it's a http transport, and it seems to be just doing\n\n\tGET %s HTTP/1.0\\r\\nUser-agent:...\n\nwithout any sanity checking at all.\n\n\t\tLinus\n"},{"id":"9896","messageId":"118833cc0510101119n4e7e9399x705993b4608d63b6@mail.gmail.com","threadId":"2054","inReplyTo":"Pine.LNX.4.64.0510100800580.14597@g5.osdl.org","subject":"Re: Strangely broken git repo","fromName":"Morten Welinder","fromEmail":"mwelinder@gmail.com","sentAt":"2005-10-10T18:19:43Z","receivedAt":"2005-10-10T18:19:43Z","isPatch":false,"sender":{"key":"mwelinder@gmail.com","avatar":null},"body":"Spaces in URLs are off-spec.  (And common, go figure.)\n\nM.\n"},{"id":"9898","messageId":"Pine.LNX.4.64.0510101123100.14597@g5.osdl.org","threadId":"2054","inReplyTo":"118833cc0510101119n4e7e9399x705993b4608d63b6@mail.gmail.com","subject":"Re: Strangely broken git repo","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-10T18:23:59Z","receivedAt":"2005-10-10T18:23:59Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Mon, 10 Oct 2005, Morten Welinder wrote:\n>\n> Spaces in URLs are off-spec.  (And common, go figure.)\n\nThey may be off-spec in url's, but that doesn't mean that \"curl\" should \njust ignore them. It should either escape them, or refuse them. Using \nuser-supplied data without any checks is usually a really bad idea.\n\n\t\t\tLinus\n"},{"id":"9900","messageId":"Pine.LNX.4.63.0510102030410.7162@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"2054","inReplyTo":"118833cc0510101119n4e7e9399x705993b4608d63b6@mail.gmail.com","subject":"Re: Strangely broken git repo","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2005-10-10T18:30:57Z","receivedAt":"2005-10-10T18:30:57Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 10 Oct 2005, Morten Welinder wrote:\n\n> Spaces in URLs are off-spec.  (And common, go figure.)\n\n%20\n\nHth,\nDscho\n"},{"id":"9945","messageId":"7vzmpgznfj.fsf_-_@assigned-by-dhcp.cox.net","threadId":"2054","inReplyTo":"7v4q7p927d.fsf@assigned-by-dhcp.cox.net","subject":"Quote reference names while fetching with curl.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-11T04:29:20Z","receivedAt":"2005-10-11T04:29:20Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\n\ncurl_escape ought to do this, but we should not let it quote slashes\n(nobody said refs/tags can have subdirectories), so we roll our own\nsafer version.  With this, the last part of git-clone that used to fail\nnow works, which reads:\n\n $ git-http-fetch -v -a -w 'tags/MOODLE_15_MERGED **INVALID**' \\\n   'tags/MOODLE_15_MERGED **INVALID**' \\\n   http://locke.catalyst.net.nz/git/moodle.git/\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n  Junio C Hamano <junkio@cox.net> writes:\n\n  > I do not speak curl, but I wonder if we should be quoting\n  > these funky characters like SP and asterisk in the URL when we\n  > make that request, or it is what the library does for us.\n  >\n  > Hmph.  Interesting.  I just tried.\n  >\n  > $ curl 'http://locke.catalyst.net.nz/git/moodle.git/refs/tags/MOODLE_15_MERGED **INVALID**'\n  >\n  > gives an error page \"404 Not Found\", while\n  >\n  > $ wget -O - -o /dev/null 'http://locke.catalyst.net.nz/git/moodle.git/refs/tags/MOODLE_15_MERGED **INVALID**'\n  >\n  > works fine and gives 2ddfec0dfd0cffd4892af9aaf48ee29c40c7ada3\n  > back.  So we do need to fix things up somewhat in our scripts as\n  > well.\n  >\n  > Anyway, I think I know the problems 'git-clone' would have had\n  > if you tried to clone it with it (not cg-clone which I do not\n  > know much about), and luckily it is only towards the end (after\n  > fetching most of the heads, but hitting the first funky tag).\n  > We should be able to fix this relatively easily.\n\n  With this patch on top of the parallel transfer http-fetch in\n  proposed updates branch, git-clone successfully cloned your\n  repository.\n\n  But in general, we should avoid spaces in reference names.\n  Scripts have problem with them.  For example, \"git-fetch\n  --tags\" currently cannot handle it.  If people cared deeply\n  enough maybe they can rewrite parts of it in Perl and send me\n  a patch ;-).\n\n  Anyway, I _do_ care about the really core part (i.e. things\n  written in C, roughly speaking), so this patch will likely\n  make into \"master\" branch.\n\n http-fetch.c |   57 +++++++++++++++++++++++++++++++++++++++++++++++++--------\n 1 files changed, 49 insertions(+), 8 deletions(-)\n\napplies-to: 4ac37eb1d8cf308455b69828c5df8f64634b5789\n1d32c9c017af915a390693021938ae8c56f33007\ndiff --git a/http-fetch.c b/http-fetch.c\nindex e537591..acae805 100644\n--- a/http-fetch.c\n+++ b/http-fetch.c\n@@ -969,9 +969,56 @@ int fetch(unsigned char *sha1)\n \t\t     alt->base);\n }\n \n+static inline int needs_quote(int ch)\n+{\n+\tswitch (ch) {\n+\tcase '/': case '-':\n+\tcase 'A'...'Z':\n+\tcase 'a'...'z':\n+\tcase '0'...'9':\n+\t\treturn 0;\n+\tdefault:\n+\t\treturn 1;\n+\t}\n+}\n+\n+static inline int hex(int v)\n+{\n+\tif (v < 10) return '0' + v;\n+\telse return 'A' + v - 10;\n+}\n+\n+static char *quote_ref_url(const char *base, const char *ref)\n+{\n+\tconst char *cp;\n+\tchar *dp, *qref;\n+\tint len, baselen, ch;\n+\n+\tbaselen = strlen(base);\n+\tlen = baselen + 6; /* \"refs/\" + NUL */\n+\tfor (cp = ref; (ch = *cp) != 0; cp++, len++)\n+\t\tif (needs_quote(ch))\n+\t\t\tlen += 2; /* extra two hex plus replacement % */\n+\tqref = xmalloc(len);\n+\tmemcpy(qref, base, baselen);\n+\tmemcpy(qref + baselen, \"refs/\", 5);\n+\tfor (cp = ref, dp = qref + baselen + 5; (ch = *cp) != 0; cp++) {\n+\t\tif (needs_quote(ch)) {\n+\t\t\t*dp++ = '%';\n+\t\t\t*dp++ = hex((ch >> 4) & 0xF);\n+\t\t\t*dp++ = hex(ch & 0xF);\n+\t\t}\n+\t\telse\n+\t\t\t*dp++ = ch;\n+\t}\n+\t*dp = 0;\n+\n+\treturn qref;\n+}\n+\n int fetch_ref(char *ref, unsigned char *sha1)\n {\n-        char *url, *posn;\n+        char *url;\n         char hex[42];\n         struct buffer buffer;\n \tchar *base = alt->base;\n@@ -981,13 +1028,7 @@ int fetch_ref(char *ref, unsigned char *\n         buffer.buffer = hex;\n         hex[41] = '\\0';\n         \n-        url = xmalloc(strlen(base) + 6 + strlen(ref));\n-        strcpy(url, base);\n-        posn = url + strlen(base);\n-        strcpy(posn, \"refs/\");\n-        posn += 5;\n-        strcpy(posn, ref);\n-\n+\turl = quote_ref_url(base, ref);\n \tslot = get_active_slot();\n \tcurl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);\n \tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n---\n0.99.8.GIT\n"},{"id":"9946","messageId":"7virw4zlod.fsf_-_@assigned-by-dhcp.cox.net","threadId":"2054","inReplyTo":"7vzmpgznfj.fsf_-_@assigned-by-dhcp.cox.net","subject":"[PATCH] git-fetch --tags: deal with tags with spaces in them.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-11T05:07:14Z","receivedAt":"2005-10-11T05:07:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"git-fetch --tags\" can get confused with tags with spaces in their names,\nit used to use shell IFS to split the list of tags and also used curl\nwhich insists the URL to be escaped.  Fix it so it can work with Martin's\nmoodle repository http://locke.catalyst.net.nz/git/moodle.git/.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n    Junio C Hamano <junkio@cox.net> writes:\n\n    >   But in general, we should avoid spaces in reference names.\n    >   Scripts have problem with them.  For example, \"git-fetch\n    >   --tags\" currently cannot handle it.  If people cared deeply\n    >   enough maybe they can rewrite parts of it in Perl and send me\n    >   a patch ;-).\n\n    And as usual, I end up being \"people\", but I did not use\n    Perl ;-).  Only lightly tested but it should fetch tags from\n    your repository.  I did not want to keep slurping those 70MB\n    and 16MB packs, so I cheated by creating a small repository\n    with funky tag names locally while testing.\n\n git-fetch.sh |   21 +++++++++++++--------\n 1 files changed, 13 insertions(+), 8 deletions(-)\n\napplies-to: 5db8c58bc7403c7b076dea420133e6e890835e1a\nc1a4b1dd71e23d877dfbf04a2ac8b1c238fc5eb4\ndiff --git a/git-fetch.sh b/git-fetch.sh\nindex d398866..b3f3782 100755\n--- a/git-fetch.sh\n+++ b/git-fetch.sh\n@@ -5,6 +5,10 @@\n _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'\n _x40=\"$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40\"\n \n+LF='\n+'\n+IFS=\"$LF\"\n+\n tags=\n append=\n force=\n@@ -170,11 +174,14 @@ esac\n reflist=$(get_remote_refs_for_fetch \"$@\")\n if test \"$tags\"\n then\n-\ttaglist=$(git-ls-remote --tags \"$remote\" | awk '{ print \".\"$2\":\"$2 }')\n+\ttaglist=$(git-ls-remote --tags \"$remote\" |\n+\t\tsed -e '\n+\t\t\ts/^[^\t]*\t//\n+\t\t\ts/.*/&:&/')\n \tif test \"$#\" -gt 1\n \tthen\n \t\t# remote URL plus explicit refspecs; we need to merge them.\n-\t\treflist=\"$reflist $taglist\"\n+\t\treflist=\"$reflist$LF$taglist\"\n \telse\n \t\t# No explicit refspecs; fetch tags only.\n \t\treflist=$taglist\n@@ -183,7 +190,7 @@ fi\n \n for ref in $reflist\n do\n-    refs=\"$refs $ref\"\n+    refs=\"$refs$LF$ref\"\n \n     # These are relative path from $GIT_DIR, typically starting at refs/\n     # but may be HEAD\n@@ -204,7 +211,7 @@ do\n     remote_name=$(expr \"$ref\" : '\\([^:]*\\):')\n     local_name=$(expr \"$ref\" : '[^:]*:\\(.*\\)')\n \n-    rref=\"$rref $remote_name\"\n+    rref=\"$rref$LF$remote_name\"\n \n     # There are transports that can fetch only one head at a time...\n     case \"$remote\" in\n@@ -212,11 +219,9 @@ do\n \tif [ -n \"$GIT_SSL_NO_VERIFY\" ]; then\n \t    curl_extra_args=\"-k\"\n \tfi\n-\thead=$(curl -nsf $curl_extra_args \"$remote/$remote_name\") &&\n-\texpr \"$head\" : \"$_x40\\$\" >/dev/null ||\n-\t\tdie \"Failed to fetch $remote_name from $remote\"\n \techo >&2 Fetching \"$remote_name from $remote\" using http\n-\tgit-http-fetch -v -a \"$head\" \"$remote/\" || exit\n+\tref_name=`expr \"$remote_name\" : 'refs/\\(.*\\)'`\n+\tgit-http-fetch -v -a \"$ref_name\" \"$remote/\" || exit\n \t;;\n     rsync://*)\n \tTMP_HEAD=\"$GIT_DIR/TMP_HEAD\"\n---\n0.99.8.GIT\n"},{"id":"9948","messageId":"7vzmpgy4g4.fsf@assigned-by-dhcp.cox.net","threadId":"2054","inReplyTo":"7virw4zlod.fsf_-_@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] git-fetch --tags: deal with tags with spaces in them.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-11T06:04:43Z","receivedAt":"2005-10-11T06:04:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> \"git-fetch --tags\" can get confused with tags with spaces in their names,\n> it used to use shell IFS to split the list of tags and also used curl\n> which insists the URL to be escaped.  Fix it so it can work with Martin's\n> moodle repository http://locke.catalyst.net.nz/git/moodle.git/.\n\nThe one I sent to the list was buggy and broke usual multi-head\nfetches, and what I have in the proposed updates branch is a\nreplacement one.\n\nWe cannot still do arbitrary reference names, but at least now\nwe allow spaces in them.  But I am not sure if this is a good\nchange.\n\nDo we in general want to support references with [^-a-zA-Z0-9.]\nin them?  Most notably spaces?\n\nThe current replacement patch implies that .git/remotes/\nshort-cut file format now has a slight incompatible change.  You\ncannot have more than one refspec on single Pull: line.  I used\nto have:\n\n\tPull: master:ko-master +pu:ko-pu maint:ko-maint\n\nbut these should now be split into multiple lines, like this:\n\n\tPull: master:ko-master\n\tPull: +pu:ko-pu\n\tPull: maint:ko-maint\n\nThe latter format, one refpair per line, has always been\nsupported, BTW.\n\nOpinions?\n"},{"id":"9977","messageId":"pan.2005.10.11.19.55.52.92821@smurf.noris.de","threadId":"2054","inReplyTo":"7virw4zlod.fsf_-_@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] git-fetch --tags: deal with tags with spaces in them.","fromName":"Matthias Urlichs","fromEmail":"smurf@smurf.noris.de","sentAt":"2005-10-11T19:55:53Z","receivedAt":"2005-10-11T19:55:53Z","isPatch":true,"sender":{"key":"matthias@urlichs.de","avatar":"https://gravatar.com/avatar/2708905af227313eba6f2b2ae0f7d0259b5ac5d71baef58fe5a13c699ce0bbf0?d=mp&s=160"},"body":"Hi, Junio C Hamano wrote:\n\n> I cheated by creating a small repository\n>     with funky tag names locally while testing.\n\nYour patch is missing the file \"t/t5410-send-funky-names.sh\".\n\n;-)\n\n-- \nMatthias Urlichs   |   {M:U} IT Design @ m-u-it.de   |  smurf@smurf.noris.de\nDisclaimer: The quote was selected randomly. Really. | http://smurf.noris.de\n - -\nBeing generous is inborn; being altruistic is a learned perversity. No\nresemblance ...\n\t\t\t\t\t-- Lazarus Long\n"},{"id":"9994","messageId":"20051012032646.GA14819@reactrix.com","threadId":"2054","inReplyTo":"7v4q7p927d.fsf@assigned-by-dhcp.cox.net","subject":"Re: Strangely broken git repo","fromName":"Nick Hengeveld","fromEmail":"nickh@reactrix.com","sentAt":"2005-10-12T03:26:46Z","receivedAt":"2005-10-12T03:26:46Z","isPatch":false,"sender":{"key":"nickh@reactrix.com","avatar":null},"body":"On Mon, Oct 10, 2005 at 02:00:06AM -0700, Junio C Hamano wrote:\n\n> The fetch_alternates() function was supposed to be call-once and\n> we have a static variable got_alternates that becomes 1 when it\n> runs for the first time.  However, there are other 'return 0's\n> introduced that does not set got_alternates to 1.\n\nOops, thanks for catching that - I'll fix it.\n\n> I am wondering if the semantics has changed that now we chain\n> the alternates?  Initially, if we are cloning/fetching from\n> repository A, which borrows from repository B (i.e. alternates\n> we retrieve from A would name B), and if B in turn borrows from\n> C, then we assumed that A's alternates would also name C, and\n> that was the reason why fetch_alternates() was call-once\n> function.  I do not mind if we change it to chain the alternates\n> file, but if that is the case we should move the got_alternates\n> variable into \"struct alt_base\", and pass the struct, not just\n> alt->base, to fetch_alternates(), like this (untested, of\n> course):\n\nI'd thought about chaining the alternates, but wasn't sure whether it's\nsafe to consider all alternates in the chain equivalent.  I would want to\nimplement fetching the chain such that it could happen parallel to other\nrequest and not block the pull.  I think it would also be useful to track\nthe network performance of each alternate and prefer faster sources as\nnew requests are started.\n\n-- \nFor a successful technology, reality must take precedence over public\nrelations, for nature cannot be fooled.\n"},{"id":"9995","messageId":"7virw3qs8a.fsf@assigned-by-dhcp.cox.net","threadId":"2054","inReplyTo":"20051012032646.GA14819@reactrix.com","subject":"Re: Strangely broken git repo","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-12T04:22:45Z","receivedAt":"2005-10-12T04:22:45Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nick Hengeveld <nickh@reactrix.com> writes:\n\n> Oops, thanks for catching that - I'll fix it.\n\nThat's OK.  It turns out that fetch_alternates() function itself\nis now called from the main just once; it used to be called\nlazily and needed the call-once guard.\n\n> I'd thought about chaining the alternates, but wasn't sure whether it's\n> safe to consider all alternates in the chain equivalent.\n\nWell, I decided we shouldn't, because the original repository\nthat has objects/info/alternates surely doesn't.\n"},{"id":"10000","messageId":"7vk6gjl2uu.fsf@assigned-by-dhcp.cox.net","threadId":"2054","inReplyTo":"7vzmpgy4g4.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] git-fetch --tags: deal with tags with spaces in them.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-12T05:29:45Z","receivedAt":"2005-10-12T05:29:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> We cannot still do arbitrary reference names, but at least now\n> we allow spaces in them.  But I am not sure if this is a good\n> change.\n>\n> Do we in general want to support references with [^-a-zA-Z0-9.]\n> in them?  Most notably spaces?\n>\n> Opinions?\n\nHere is mine.\n\nI do not personally think it is too much of a restriction if we\nsaid we only allow tags using letters from [-a-zA-Z0-9.] (yes I\nam trying to be controversial by not allowing even latin-1\nnames).  Even without going that far, if we just said we do not\nallow shell metacharacters in tagnames (i.e. assuming UTF-8\nencoded pathnames, non-ascii part of unicode character space is\nallowed), I suspect things will get much simpler to handle.\n\nThe troublesome tags Martin's repository had were autocreated\nwith cvsimport.  That is something we could easily fix (I think\nwe already do certain tagname munging).\n"},{"id":"10007","messageId":"20051012082632.GL30889@pasky.or.cz","threadId":"2054","inReplyTo":"7vk6gjl2uu.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] git-fetch --tags: deal with tags with spaces in them.","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2005-10-12T08:26:32Z","receivedAt":"2005-10-12T08:26:32Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Wed, Oct 12, 2005 at 07:29:45AM CEST, I got a letter\nwhere Junio C Hamano <junkio@cox.net> told me that...\n> I do not personally think it is too much of a restriction if we\n> said we only allow tags using letters from [-a-zA-Z0-9.] (yes I\n> am trying to be controversial by not allowing even latin-1\n> names).\n\nI think this is perfectly reasonable, as long as you also throw _ to the\nset. ;-) Actually, cg-tag now already does at least\n\n(echo $name | egrep -qv '[^a-zA-Z0-9_.@!:-]') || \\\n        die \"name contains invalid characters\"\n\nbut I'm in no way emotionally attached to the @!: characters.\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"},{"id":"10030","messageId":"434D2D8F.2020407@zytor.com","threadId":"2054","inReplyTo":"7vk6gjl2uu.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] git-fetch --tags: deal with tags with spaces in them.","fromName":"H. Peter Anvin","fromEmail":"hpa@zytor.com","sentAt":"2005-10-12T15:36:47Z","receivedAt":"2005-10-12T15:36:47Z","isPatch":true,"sender":{"key":"hpa@zytor.com","avatar":null},"body":"Junio C Hamano wrote:\n> \n> Here is mine.\n> \n> I do not personally think it is too much of a restriction if we\n> said we only allow tags using letters from [-a-zA-Z0-9.] (yes I\n> am trying to be controversial by not allowing even latin-1\n> names).  Even without going that far, if we just said we do not\n> allow shell metacharacters in tagnames (i.e. assuming UTF-8\n> encoded pathnames, non-ascii part of unicode character space is\n> allowed), I suspect things will get much simpler to handle.\n> \n> The troublesome tags Martin's repository had were autocreated\n> with cvsimport.  That is something we could easily fix (I think\n> we already do certain tagname munging).\n> \n\nI don't know about this.  Saying we only support ASCII tagnames can be \nquote brutal for non-English-language projects.  Even with the set \nabove, we'd at the very least need underscore, and I know of at least \none project which require # in tagnames.  In short, I don't think we can \nmake that decision for people.\n\nWe can disallow whitespace, and we *have* to disallow at least newline \ndue to the file format; I believe we should disallow all control \ncharacters (0-31, 127-159.)\n\n\t-hpa\n"},{"id":"10031","messageId":"434D3000.5020601@zytor.com","threadId":"2054","inReplyTo":"434D2D8F.2020407@zytor.com","subject":"Re: [PATCH] git-fetch --tags: deal with tags with spaces in them.","fromName":"H. Peter Anvin","fromEmail":"hpa@zytor.com","sentAt":"2005-10-12T15:47:12Z","receivedAt":"2005-10-12T15:47:12Z","isPatch":true,"sender":{"key":"hpa@zytor.com","avatar":null},"body":"H. Peter Anvin wrote:\n> \n> We can disallow whitespace, and we *have* to disallow at least newline \n> due to the file format; I believe we should disallow all control \n> characters (0-31, 127-159.)\n> \n\nActually, disallowing anything 128 and above means knowing the encoding \nsystem.  If we enforce UTF-8, we should presumably disallow at the very \nleast U+FFFE and U+FFFF too.\n\nC99 contains a list of Unicode characters allowed in C identifiers.  I \nbelieve we should allow those characters (plus at a minimum -+.#:@) as \nwell, but I'd much rather we didn't make those kinds of decisions for \nthe user.  If we have *specific* characters we can't tolerate we should \nrule them out (like control characters), but even that occationally \nleads to major frustration on the part of the user: \"why can't I use '.' \nin tag names in CVS\"?\n\n\t-hpa\n"},{"id":"10034","messageId":"7v4q7mip30.fsf@assigned-by-dhcp.cox.net","threadId":"2054","inReplyTo":"434D2D8F.2020407@zytor.com","subject":"Re: [PATCH] git-fetch --tags: deal with tags with spaces in them.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-12T18:10:11Z","receivedAt":"2005-10-12T18:10:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"H. Peter Anvin\" <hpa@zytor.com> writes:\n\n> We can disallow whitespace, and we *have* to disallow at least newline \n> due to the file format; I believe we should disallow all control \n> characters (0-31, 127-159.)\n\nI agree.\n\nCurrently SP, TAB, and LF are all we care about, and nothing\nelse; NUL does not even count.  But if we are codifying a list\nof disallowed byte values, excluding all control characters is\nprobably a sane thing to do, without introducing arbitrary and\nunnecessary limitation too much.\n"},{"id":"10035","messageId":"7vslv6ef6q.fsf@assigned-by-dhcp.cox.net","threadId":"2054","inReplyTo":"434D3000.5020601@zytor.com","subject":"Re: [PATCH] git-fetch --tags: deal with tags with spaces in them.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-12T18:57:33Z","receivedAt":"2005-10-12T18:57:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"H. Peter Anvin\" <hpa@zytor.com> writes:\n\n> H. Peter Anvin wrote:\n>> We can disallow whitespace, and we *have* to disallow at least\n>> newline due to the file format; I believe we should disallow all\n>> control characters (0-31, 127-159.)\n>\n> Actually, disallowing anything 128 and above means knowing the encoding \n> system.  If we enforce UTF-8, we should presumably disallow at the very \n> least U+FFFE and U+FFFF too.\n\nHmph.  I think enforcing (or rather supporting preferentially)\nUTF-8 in log messages was alright, but enforcing UTF-8 tagnames\nimply UTF-8 host pathnames because we do not currently convert\nwhen we fetch refs from remote and store locally.\n\n * git-clone-pack, git-fetch-pack and git-peek-remote run\n   git-upload-pack on the other end.  Currently upload-pack\n   sends a list of refs read from the remote filesystem without\n   conversion, and:\n\n   (1) clone-pack uses the names without conversion to replicate\n       refs on the local filesystem.\n\n   (2) fetch-pack sends the names given on the command line,\n       and/or read from the local filesystem, to upload-pack\n       without conversion.\n\n   (3) fetch-pack and peek-remote outputs the names obtained\n       from the remote without conversion to stdout.\n\n * over http, the encoding of the refnames client sees is what\n   is stored in project.git/info/refs on the remote.  Currently,\n   update-server-info reads from the filesystem and writes this\n   file out without conversion.  While walking the commits,\n   names are not used, so there is no refname encoding issues.\n\nWhat we should do at this point is to declare that exchanging\nrefnames between systems is to happen after converting them to\nUTF-8.  And version 1.0 just assumes pathnames are UTF-8.\n\nIf people on systems with non UTF-8 pathnames cared enough, the\ntools can be made aware of local pathname encodings, and taught\nhow to convert what for_each_ref() read from the filesystem, the\nrefspecs given from the command line, etc. to UTF-8.  But that\ncan come later.\n"},{"id":"10047","messageId":"7v64s2cs3c.fsf@assigned-by-dhcp.cox.net","threadId":"2054","inReplyTo":"7v4q7mip30.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] git-check-ref-format: reject funny ref names.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-12T22:01:43Z","receivedAt":"2005-10-12T22:01:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Update check_ref_format() function to reject ref names that:\n\n * has a path component that begins with a \".\", or\n * has ASCII control character, \"~\", \"^\", \":\" or SP, anywhere, or\n * ends with a \"/\".\n\nUse it in 'git-checkout -b', 'git-branch', and 'git-tag' to make sure\nthat newly created refs are well-formed.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n * This is the beginning of currently two-patch series.  This\n   one \"fixes\" the programs that trivially create new refs.\n   Also check_ref_format() is used by commit walkers when\n   writing a new ref or updating an existing ref, so this patch\n   makes them to refuse funny refs being created.\n\n Makefile           |    2 +-\n check-ref-format.c |   17 ++++++++++++++\n git-branch.sh      |   63 +++++++++++++++++++++++++++++-----------------------\n git-checkout.sh    |    2 ++\n git-tag.sh         |    2 ++\n refs.c             |   52 +++++++++++++++++++++++++++++++++++--------\n 6 files changed, 100 insertions(+), 38 deletions(-)\n create mode 100644 check-ref-format.c\n\napplies-to: ea37b42d53264d65f746b3e42577349e8a44d5c4\n3fa00f52f80e5e51cc8098979ce0883c77caab52\ndiff --git a/Makefile b/Makefile\nindex 7c8f647..2860d47 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -120,7 +120,7 @@ PROGRAMS = \\\n \tgit-ssh-upload$X git-tar-tree$X git-unpack-file$X \\\n \tgit-unpack-objects$X git-update-index$X git-update-server-info$X \\\n \tgit-upload-pack$X git-verify-pack$X git-write-tree$X \\\n-\tgit-update-ref$X git-symbolic-ref$X \\\n+\tgit-update-ref$X git-symbolic-ref$X git-check-ref-format$X \\\n \t$(SIMPLE_PROGRAMS)\n \n # Backward compatibility -- to be removed after 1.0\ndiff --git a/check-ref-format.c b/check-ref-format.c\nnew file mode 100644\nindex 0000000..a0adb3d\n--- /dev/null\n+++ b/check-ref-format.c\n@@ -0,0 +1,17 @@\n+/*\n+ * GIT - The information manager from hell\n+ */\n+\n+#include \"cache.h\"\n+#include \"refs.h\"\n+\n+#include <stdio.h>\n+\n+int main(int ac, char **av)\n+{\n+\tif (ac != 2)\n+\t\tusage(\"git-check-ref-format refname\");\n+\tif (check_ref_format(av[1]))\n+\t\texit(1);\n+\treturn 0;\n+}\ndiff --git a/git-branch.sh b/git-branch.sh\nindex 074229c..e2db906 100755\n--- a/git-branch.sh\n+++ b/git-branch.sh\n@@ -13,38 +13,42 @@ If two arguments, create a new branch <b\n }\n \n delete_branch () {\n-    option=\"$1\" branch_name=\"$2\"\n+    option=\"$1\"\n+    shift\n     headref=$(GIT_DIR=\"$GIT_DIR\" git-symbolic-ref HEAD |\n     \t       sed -e 's|^refs/heads/||')\n-    case \",$headref,\" in\n-    \",$branch_name,\")\n-\tdie \"Cannot delete the branch you are on.\" ;;\n-    ,,)\n-\tdie \"What branch are you on anyway?\" ;;\n-    esac\n-    branch=$(cat \"$GIT_DIR/refs/heads/$branch_name\") &&\n-\tbranch=$(git-rev-parse --verify \"$branch^0\") ||\n-\t    die \"Seriously, what branch are you talking about?\"\n-    case \"$option\" in\n-    -D)\n-\t;;\n-    *)\n-\tmbs=$(git-merge-base -a \"$branch\" HEAD | tr '\\012' ' ')\n-\tcase \" $mbs \" in\n-\t*' '$branch' '*)\n-\t    # the merge base of branch and HEAD contains branch --\n-\t    # which means that the HEAD contains everything in the HEAD.\n+    for branch_name\n+    do\n+\tcase \",$headref,\" in\n+\t\",$branch_name,\")\n+\t    die \"Cannot delete the branch you are on.\" ;;\n+\t,,)\n+\t    die \"What branch are you on anyway?\" ;;\n+\tesac\n+\tbranch=$(cat \"$GIT_DIR/refs/heads/$branch_name\") &&\n+\t    branch=$(git-rev-parse --verify \"$branch^0\") ||\n+\t\tdie \"Seriously, what branch are you talking about?\"\n+\tcase \"$option\" in\n+\t-D)\n \t    ;;\n \t*)\n-\t    echo >&2 \"The branch '$branch_name' is not a strict subset of your current HEAD.\n-If you are sure you want to delete it, run 'git branch -D $branch_name'.\"\n-\t    exit 1\n+\t    mbs=$(git-merge-base -a \"$branch\" HEAD | tr '\\012' ' ')\n+\t    case \" $mbs \" in\n+\t    *' '$branch' '*)\n+\t\t# the merge base of branch and HEAD contains branch --\n+\t\t# which means that the HEAD contains everything in the HEAD.\n+\t\t;;\n+\t    *)\n+\t\techo >&2 \"The branch '$branch_name' is not a strict subset of your current HEAD.\n+    If you are sure you want to delete it, run 'git branch -D $branch_name'.\"\n+\t\texit 1\n+\t\t;;\n+\t    esac\n \t    ;;\n \tesac\n-\t;;\n-    esac\n-    rm -f \"$GIT_DIR/refs/heads/$branch_name\"\n-    echo \"Deleted branch $branch_name.\"\n+\trm -f \"$GIT_DIR/refs/heads/$branch_name\"\n+\techo \"Deleted branch $branch_name.\"\n+    done\n     exit 0\n }\n \n@@ -52,7 +56,7 @@ while case \"$#,$1\" in 0,*) break ;; *,-*\n do\n \tcase \"$1\" in\n \t-d | -D)\n-\t\tdelete_branch \"$1\" \"$2\"\n+\t\tdelete_branch \"$@\"\n \t\texit\n \t\t;;\n \t--)\n@@ -93,6 +97,9 @@ branchname=\"$1\"\n \n rev=$(git-rev-parse --verify \"$head\") || exit\n \n-[ -e \"$GIT_DIR/refs/heads/$branchname\" ] && die \"$branchname already exists\"\n+[ -e \"$GIT_DIR/refs/heads/$branchname\" ] &&\n+\tdie \"$branchname already exists.\"\n+git-check-ref-format \"heads/$branchname\" ||\n+\tdie \"we do not like '$branchname' as a branch name.\"\n \n echo $rev > \"$GIT_DIR/refs/heads/$branchname\"\ndiff --git a/git-checkout.sh b/git-checkout.sh\nindex c382590..2c053a3 100755\n--- a/git-checkout.sh\n+++ b/git-checkout.sh\n@@ -17,6 +17,8 @@ while [ \"$#\" != \"0\" ]; do\n \t\t\tdie \"git checkout: -b needs a branch name\"\n \t\t[ -e \"$GIT_DIR/refs/heads/$newbranch\" ] &&\n \t\t\tdie \"git checkout: branch $newbranch already exists\"\n+\t\tgit-check-ref-format \"heads/$newbranch\" ||\n+\t\t\tdie \"we do not like '$newbranch' as a branch name.\"\n \t\t;;\n \t\"-f\")\n \t\tforce=1\ndiff --git a/git-tag.sh b/git-tag.sh\nindex 25c1a0e..faa7667 100755\n--- a/git-tag.sh\n+++ b/git-tag.sh\n@@ -53,6 +53,8 @@ if [ -e \"$GIT_DIR/refs/tags/$name\" -a -z\n     die \"tag '$name' already exists\"\n fi\n shift\n+git-check-ref-format \"tags/$name\" ||\n+\tdie \"we do not like '$name' as a tag name.\"\n \n object=$(git-rev-parse --verify --default HEAD \"$@\") || exit 1\n type=$(git-cat-file -t $object) || exit 1\ndiff --git a/refs.c b/refs.c\nindex 5a8cbd4..2d2144c 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -335,17 +335,51 @@ int write_ref_sha1(const char *ref, int \n \treturn retval;\n }\n \n+/*\n+ * Make sure \"ref\" is something reasonable to have under \".git/refs/\";\n+ * We do not like it if:\n+ *\n+ * - any path component of it begins with \".\", or\n+ * - it has ASCII control character, \"~\", \"^\", \":\" or SP, anywhere, or\n+ * - it ends with a \"/\".\n+ */\n+\n+static inline int bad_ref_char(int ch)\n+{\n+\treturn (((unsigned) ch) <= ' ' ||\n+\t\tch == '~' || ch == '^' || ch == ':');\n+}\n+\n int check_ref_format(const char *ref)\n {\n-\tchar *middle;\n-\tif (ref[0] == '.' || ref[0] == '/')\n-\t\treturn -1;\n-\tmiddle = strchr(ref, '/');\n-\tif (!middle || !middle[1])\n-\t\treturn -1;\n-\tif (strchr(middle + 1, '/'))\n-\t\treturn -1;\n-\treturn 0;\n+\tint ch, level;\n+\tconst char *cp = ref;\n+\n+\tlevel = 0;\n+\twhile (1) {\n+\t\twhile ((ch = *cp++) == '/')\n+\t\t\t; /* tolerate duplicated slashes */\n+\t\tif (!ch)\n+\t\t\treturn -1; /* should not end with slashes */\n+\n+\t\t/* we are at the beginning of the path component */\n+\t\tif (ch == '.' || bad_ref_char(ch))\n+\t\t\treturn -1;\n+\n+\t\t/* scan the rest of the path component */\n+\t\twhile ((ch = *cp++) != 0) {\n+\t\t\tif (bad_ref_char(ch))\n+\t\t\t\treturn -1;\n+\t\t\tif (ch == '/')\n+\t\t\t\tbreak;\n+\t\t}\n+\t\tlevel++;\n+\t\tif (!ch) {\n+\t\t\tif (level < 2)\n+\t\t\t\treturn -1; /* at least of form \"heads/blah\" */\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n }\n \n int write_ref_sha1_unlocked(const char *ref, const unsigned char *sha1)\n---\n0.99.8.GIT\n"},{"id":"10046","messageId":"7vzmpebdit.fsf@assigned-by-dhcp.cox.net","threadId":"2054","inReplyTo":"7v4q7mip30.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] Refuse to create funny refs in clone-pack, git-fetch and receive-pack.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-12T22:01:46Z","receivedAt":"2005-10-12T22:01:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Using git-check-ref-format, make sure we do not create refs with\nfunny names when cloning from elsewhere (clone-pack), fast forwarding\nlocal heads (git-fetch), or somebody pushes into us (receive-pack).\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n * This is the second installment.  Cloning over HTTP uses the\n   commit walker '-w' ref updates, and should already be covered\n   by the previous \"check_ref_format()\" updates.\n\n clone-pack.c        |    6 ++++++\n git-parse-remote.sh |    6 ++++++\n receive-pack.c      |    4 ++++\n 3 files changed, 16 insertions(+), 0 deletions(-)\n\napplies-to: 409fe70483c97167e9b7d396334ec5f96932694d\n8da42e4b3363de13ede2f006ad96ee8268e52250\ndiff --git a/clone-pack.c b/clone-pack.c\nindex c102ca8..48bee96 100644\n--- a/clone-pack.c\n+++ b/clone-pack.c\n@@ -34,6 +34,12 @@ static void write_one_ref(struct ref *re\n \tint fd;\n \tchar *hex;\n \n+\tif (!strncmp(ref->name, \"refs/\", 5) &&\n+\t    check_ref_format(ref->name + 5)) {\n+\t\terror(\"refusing to create funny ref '%s' locally\", ref->name);\n+\t\treturn;\n+\t}\n+\n \tif (safe_create_leading_directories(path))\n \t\tdie(\"unable to create leading directory for %s\", ref->name);\n \tfd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0666);\ndiff --git a/git-parse-remote.sh b/git-parse-remote.sh\nindex 5e75e15..aea7b0e 100755\n--- a/git-parse-remote.sh\n+++ b/git-parse-remote.sh\n@@ -94,6 +94,12 @@ canon_refs_list_for_fetch () {\n \t\theads/* | tags/* ) local=\"refs/$local\" ;;\n \t\t*) local=\"refs/heads/$local\" ;;\n \t\tesac\n+\n+\t\tif local_ref_name=$(expr \"$local\" : 'refs/\\(.*\\)')\n+\t\tthen\n+\t\t   git-check-ref-format \"$local_ref_name\" ||\n+\t\t   die \"* refusing to create funny ref '$local_ref_name' locally\"\n+\t\tfi\n \t\techo \"${dot_prefix}${force}${remote}:${local}\"\n \t\tdot_prefix=.\n \tdone\ndiff --git a/receive-pack.c b/receive-pack.c\nindex 06857eb..8f157bc 100644\n--- a/receive-pack.c\n+++ b/receive-pack.c\n@@ -95,6 +95,10 @@ static int update(const char *name,\n \tchar new_hex[60], *old_hex, *lock_name;\n \tint newfd, namelen, written;\n \n+\tif (!strncmp(name, \"refs/\", 5) && check_ref_format(name + 5))\n+\t\treturn error(\"refusing to create funny ref '%s' locally\",\n+\t\t\t     name);\n+\n \tnamelen = strlen(name);\n \tlock_name = xmalloc(namelen + 10);\n \tmemcpy(lock_name, name, namelen);\n---\n0.99.8.GIT\n"}]}