{"thread":{"id":"16537","subject":"[PATCH 0/6 (v2)] Detecting HEAD more reliably while cloning","startedAt":"2008-12-01T14:12:49Z","lastAt":"2008-12-02T02:36:43Z","messageCount":17,"participants":["Junio C Hamano","Jakub Narebski","Johannes Sixt","Shawn O. Pearce","Jeff King"],"isPatch":true,"patchVersion":2,"patchTotal":6},"messages":[{"id":"96847","messageId":"1228140775-29212-1-git-send-email-gitster@pobox.com","threadId":"16537","inReplyTo":null,"subject":"[PATCH 0/6 (v2)] Detecting HEAD more reliably while cloning","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-01T14:12:49Z","receivedAt":"2008-12-01T14:12:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This is another approach to the same problem that a repository cloned from\nanother repository whose default branch is not 'master' can use 'master'\nas the default.\n\nThe current code has to guess where the HEAD in the original repository\npoints at, because the original protocol tells what object each ref points\nat but does not talk about which other ref a symbolic ref points at.  The\nimplication of this is that if you prepare another branch that points at\nyour master, like this:\n\n\t$ git checkout -b another master\n\nand keep that other branch checked out (and in sync with 'master'), a\nclone made from such a repository may incorrectly have its HEAD pointing\nat 'master', not 'another'.\n\nInstead of introducing a full-fledged protocol extension, this round hides\nthe new information in the same place as the server capabilities list that\nis used to implement protocol extension is hidden from older clients.\nThis way, it does not have to work around the code structure imposed by\nthe transport API, does not have to introduce an extra round trip, and\ndoes not have to trigger an annoying (but harmless) error message when an\nolder client contacts a new uploader.\n\n  [1/6] get_remote_heads(): refactor code to read \"server capabilities\"\n  [2/6] connect.c::read_extra_info(): prepare to receive more than server\n        capabilities\n  [3/6] connect.c::read_extra_info(): find where HEAD points at\n  [4/6] clone: find the current branch more explicitly\n  [5/6] upload-pack: send the HEAD information\n  [6/6] clone: test the new HEAD detection logic\n\nThe first four are the client side, the fifth one is the uploader side,\nand the last one is the test.  After storing these patches in separate\nfiles, you would build this history (on top of 'master'):\n\n    git am 1 2 3 4\n    git reset --hard HEAD~4    5---------------M---6\n    git am 5                  /               /\n    git merge HEAD@{2}        ---1---2---3---4\n    git am 6\n\n builtin-clone.c  |   24 +++++++++++++++++++-----\n connect.c        |   47 +++++++++++++++++++++++++++++++++++++++++++----\n t/t5601-clone.sh |   11 +++++++++++\n upload-pack.c    |   14 +++++++++++---\n 4 files changed, 84 insertions(+), 12 deletions(-)\n"},{"id":"96849","messageId":"1228140775-29212-2-git-send-email-gitster@pobox.com","threadId":"16537","inReplyTo":"1228140775-29212-1-git-send-email-gitster@pobox.com","subject":"[PATCH 1/6 (v2)] get_remote_heads(): refactor code to read \"server capabilities\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-01T14:12:50Z","receivedAt":"2008-12-01T14:12:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This just moves the code to read the server capability list that is hidden\nafter \"40-byte hex object name, SP, refname, NUL\" on the information the\nuploading end initially sends.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n connect.c |   21 +++++++++++++++++----\n 1 files changed, 17 insertions(+), 4 deletions(-)\n\ndiff --git a/connect.c b/connect.c\nindex 584e04c..932c503 100644\n--- a/connect.c\n+++ b/connect.c\n@@ -49,6 +49,21 @@ static void add_extra_have(struct extra_have_objects *extra, unsigned char *sha1\n }\n \n /*\n+ * \"line\" points at the byte just after \"40-byte hex, SP, refname,\n+ * NUL\".  \"len\" is the remaining number of bytes.  The caller knows\n+ * that the original packet contains more information than that.\n+ */\n+static void read_extra_info(char *line, int len)\n+{\n+\t/*\n+\t * The first such \"extra\" piece of information is the list of\n+\t * server capabilities.\n+\t */\n+\tfree(server_capabilities);\n+\tserver_capabilities = xstrdup(line);\n+}\n+\n+/*\n  * Read all the refs from the other end\n  */\n struct ref **get_remote_heads(int in, struct ref **list,\n@@ -78,10 +93,8 @@ struct ref **get_remote_heads(int in, struct ref **list,\n \t\tname = buffer + 41;\n \n \t\tname_len = strlen(name);\n-\t\tif (len != name_len + 41) {\n-\t\t\tfree(server_capabilities);\n-\t\t\tserver_capabilities = xstrdup(name + name_len + 1);\n-\t\t}\n+\t\tif (len != name_len + 41)\n+\t\t\tread_extra_info(name + name_len + 1, len - (name_len + 41));\n \n \t\tif (extra_have &&\n \t\t    name_len == 5 && !memcmp(\".have\", name, 5)) {\n-- \n1.6.0.4.864.g0f47a\n"},{"id":"96848","messageId":"1228140775-29212-3-git-send-email-gitster@pobox.com","threadId":"16537","inReplyTo":"1228140775-29212-2-git-send-email-gitster@pobox.com","subject":"[PATCH 2/6 (v2)] connect.c::read_extra_info(): prepare to receive more than server capabilities","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-01T14:12:51Z","receivedAt":"2008-12-01T14:12:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This still does not actually parse and accept anything more than the list\nof server capabilities, but prepares for the uploader that sends more\n\"extra\" information than that.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n connect.c |    5 ++++-\n 1 files changed, 4 insertions(+), 1 deletions(-)\n\ndiff --git a/connect.c b/connect.c\nindex 932c503..114d691 100644\n--- a/connect.c\n+++ b/connect.c\n@@ -59,8 +59,11 @@ static void read_extra_info(char *line, int len)\n \t * The first such \"extra\" piece of information is the list of\n \t * server capabilities.\n \t */\n+\tint infolen = strlen(line) + 1;\n+\n \tfree(server_capabilities);\n-\tserver_capabilities = xstrdup(line);\n+\tserver_capabilities = xmalloc(infolen);\n+\tmemcpy(server_capabilities, line, infolen);\n }\n \n /*\n-- \n1.6.0.4.864.g0f47a\n"},{"id":"96850","messageId":"1228140775-29212-4-git-send-email-gitster@pobox.com","threadId":"16537","inReplyTo":"1228140775-29212-3-git-send-email-gitster@pobox.com","subject":"[PATCH 3/6 (v2)] connect.c::read_extra_info(): find where HEAD points at","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-01T14:12:52Z","receivedAt":"2008-12-01T14:12:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This actually implements the protocol extension to receive the HEAD symref\ninformation that is hidden after the server capabilities list.  Nobody\nuses the information yet, though.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n connect.c |   27 +++++++++++++++++++++++++--\n 1 files changed, 25 insertions(+), 2 deletions(-)\n\ndiff --git a/connect.c b/connect.c\nindex 114d691..aa4757a 100644\n--- a/connect.c\n+++ b/connect.c\n@@ -53,7 +53,7 @@ static void add_extra_have(struct extra_have_objects *extra, unsigned char *sha1\n  * NUL\".  \"len\" is the remaining number of bytes.  The caller knows\n  * that the original packet contains more information than that.\n  */\n-static void read_extra_info(char *line, int len)\n+static void read_extra_info(char *line, int len, char **hpa)\n {\n \t/*\n \t * The first such \"extra\" piece of information is the list of\n@@ -64,6 +64,20 @@ static void read_extra_info(char *line, int len)\n \tfree(server_capabilities);\n \tserver_capabilities = xmalloc(infolen);\n \tmemcpy(server_capabilities, line, infolen);\n+\tif (infolen == len)\n+\t\treturn;\n+\t/*\n+\t * The uploader can optionally tell us where the HEAD pointer\n+\t * points at after that.\n+\t */\n+\tline += infolen;\n+\tlen -= infolen;\n+\n+\tinfolen = strlen(line) + 1;\n+\n+\tfree(*hpa);\n+\t*hpa = xmalloc(infolen);\n+\tmemcpy(*hpa, line, infolen);\n }\n \n /*\n@@ -74,6 +88,9 @@ struct ref **get_remote_heads(int in, struct ref **list,\n \t\t\t      unsigned int flags,\n \t\t\t      struct extra_have_objects *extra_have)\n {\n+\tstruct ref **ref_list = list;\n+\tchar *head_points_at = NULL;\n+\n \t*list = NULL;\n \tfor (;;) {\n \t\tstruct ref *ref;\n@@ -97,7 +114,8 @@ struct ref **get_remote_heads(int in, struct ref **list,\n \n \t\tname_len = strlen(name);\n \t\tif (len != name_len + 41)\n-\t\t\tread_extra_info(name + name_len + 1, len - (name_len + 41));\n+\t\t\tread_extra_info(name + name_len + 1, len - (name_len + 41),\n+\t\t\t\t\t&head_points_at);\n \n \t\tif (extra_have &&\n \t\t    name_len == 5 && !memcmp(\".have\", name, 5)) {\n@@ -114,6 +132,11 @@ struct ref **get_remote_heads(int in, struct ref **list,\n \t\t*list = ref;\n \t\tlist = &ref->next;\n \t}\n+\tif (head_points_at) {\n+\t\tstruct ref *head = find_ref_by_name(*ref_list, \"HEAD\");\n+\t\tif (head)\n+\t\t\thead->symref = head_points_at;\n+\t}\n \treturn list;\n }\n \n-- \n1.6.0.4.864.g0f47a\n"},{"id":"96851","messageId":"1228140775-29212-5-git-send-email-gitster@pobox.com","threadId":"16537","inReplyTo":"1228140775-29212-4-git-send-email-gitster@pobox.com","subject":"[PATCH 4/6 (v2)] clone: find the current branch more explicitly","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-01T14:12:53Z","receivedAt":"2008-12-01T14:12:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This makes \"git clone\" use the HEAD information sent by an updated\nuploader to point the resulting HEAD at the current branch that is not\n'master' but happens to point at the same commit as 'master'.\n\nIOW, immediately after doing:\n\n    $ git checkout -b another master\n\na clone made out of that repository will check out 'another' branch, not\n'master'.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin-clone.c |   24 +++++++++++++++++++-----\n 1 files changed, 19 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin-clone.c b/builtin-clone.c\nindex 2feac9c..a8b8d56 100644\n--- a/builtin-clone.c\n+++ b/builtin-clone.c\n@@ -299,13 +299,27 @@ static const struct ref *locate_head(const struct ref *refs,\n \tconst struct ref *remote_head = NULL;\n \tconst struct ref *remote_master = NULL;\n \tconst struct ref *r;\n-\tfor (r = refs; r; r = r->next)\n-\t\tif (!strcmp(r->name, \"HEAD\"))\n+\n+\tfor (r = refs; r; r = r->next) {\n+\t\tif (!strcmp(r->name, \"HEAD\")) {\n \t\t\tremote_head = r;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n \n-\tfor (r = mapped_refs; r; r = r->next)\n-\t\tif (!strcmp(r->name, \"refs/heads/master\"))\n-\t\t\tremote_master = r;\n+\tif (remote_head && remote_head->symref) {\n+\t\tfor (r = mapped_refs; r; r = r->next)\n+\t\t\tif (!strcmp(r->name, remote_head->symref)) {\n+\t\t\t\tremote_master = r;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t}\n+\n+\tif (!remote_master) {\n+\t\tfor (r = mapped_refs; r; r = r->next)\n+\t\t\tif (!strcmp(r->name, \"refs/heads/master\"))\n+\t\t\t\tremote_master = r;\n+\t}\n \n \tif (remote_head_p)\n \t\t*remote_head_p = remote_head;\n-- \n1.6.0.4.864.g0f47a\n"},{"id":"96852","messageId":"1228140775-29212-6-git-send-email-gitster@pobox.com","threadId":"16537","inReplyTo":"1228140775-29212-5-git-send-email-gitster@pobox.com","subject":"[PATCH 5/6 (v2)] upload-pack: send the HEAD information","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-01T14:12:54Z","receivedAt":"2008-12-01T14:12:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This implements the server side of protocol extension to show which branch\nthe HEAD points at.  The information is sent after the terminating NUL\nthat comes after the server capabilities list, to cause older clients to\nignore it, while allowing newer clients to make use of that information\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n upload-pack.c |   14 +++++++++++---\n 1 files changed, 11 insertions(+), 3 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex e5adbc0..4aa444a 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -579,9 +579,17 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo\n \tif (!o)\n \t\tdie(\"git upload-pack: cannot find object %s:\", sha1_to_hex(sha1));\n \n-\tif (capabilities)\n-\t\tpacket_write(1, \"%s %s%c%s\\n\", sha1_to_hex(sha1), refname,\n-\t\t\t0, capabilities);\n+\tif (capabilities) {\n+\t\tunsigned char dummy[20];\n+\t\tconst char *target = resolve_ref(\"HEAD\", dummy, 0, NULL);\n+\n+\t\tif (!target)\n+\t\t\tpacket_write(1, \"%s %s%c%s\\n\", sha1_to_hex(sha1), refname,\n+\t\t\t\t     0, capabilities);\n+\t\telse\n+\t\t\tpacket_write(1, \"%s %s%c%s%c%s\\n\", sha1_to_hex(sha1), refname,\n+\t\t\t\t     0, capabilities, 0, target);\n+\t}\n \telse\n \t\tpacket_write(1, \"%s %s\\n\", sha1_to_hex(sha1), refname);\n \tcapabilities = NULL;\n-- \n1.6.0.4.864.g0f47a\n"},{"id":"96853","messageId":"1228140775-29212-7-git-send-email-gitster@pobox.com","threadId":"16537","inReplyTo":"1228140775-29212-6-git-send-email-gitster@pobox.com","subject":"[PATCH 6/6 (v2)] clone: test the new HEAD detection logic","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-01T14:12:55Z","receivedAt":"2008-12-01T14:12:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t5601-clone.sh |   11 +++++++++++\n 1 files changed, 11 insertions(+), 0 deletions(-)\n\ndiff --git a/t/t5601-clone.sh b/t/t5601-clone.sh\nindex 78a3fa6..6d4665b 100755\n--- a/t/t5601-clone.sh\n+++ b/t/t5601-clone.sh\n@@ -125,4 +125,15 @@ test_expect_success 'clone to destination with extra trailing /' '\n \n '\n \n+test_expect_success 'clone from a repository with two identical branches' '\n+\n+\t(\n+\t\tcd src &&\n+\t\tgit checkout -b another master\n+\t) &&\n+\tgit clone src target-3 &&\n+\ttest \"z$( cd target-3 && git symbolic-ref HEAD )\" = zrefs/heads/another\n+\n+'\n+\n test_done\n-- \n1.6.0.4.864.g0f47a\n"},{"id":"96860","messageId":"gh10h8$usu$1@ger.gmane.org","threadId":"16537","inReplyTo":"1228140775-29212-6-git-send-email-gitster@pobox.com","subject":"Re: [PATCH 5/6 (v2)] upload-pack: send the HEAD information","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-12-01T15:40:26Z","receivedAt":"2008-12-01T15:40:26Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Junio C Hamano wrote:\n\n> This implements the server side of protocol extension to show which branch\n> the HEAD points at.  The information is sent after the terminating NUL\n> that comes after the server capabilities list, to cause older clients to\n> ignore it, while allowing newer clients to make use of that information\n\nBy the way, is negotiating protocol extensions, and supported protocol\nextensions documented somewhere in Documentation/technical/ ?\n\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"96861","messageId":"4934082B.5050802@viscovery.net","threadId":"16537","inReplyTo":"1228140775-29212-1-git-send-email-gitster@pobox.com","subject":"Re: [PATCH 0/6 (v2)] Detecting HEAD more reliably while cloning","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2008-12-01T15:52:11Z","receivedAt":"2008-12-01T15:52:11Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Junio C Hamano schrieb:\n> Instead of introducing a full-fledged protocol extension, this round hides\n> the new information in the same place as the server capabilities list that\n> is used to implement protocol extension is hidden from older clients.\n\nNot that it makes a lot of difference, but why do you want to *hide* the\ninformation? Can't we just have a capability-with-parameter:\n\n ... shallow no-progress include-tag head=refs/heads/foo\\ bar ...\n\n(with spaces and backslashes escaped)?\n\n-- Hannes\n"},{"id":"96864","messageId":"20081201162011.GI23984@spearce.org","threadId":"16537","inReplyTo":"1228140775-29212-6-git-send-email-gitster@pobox.com","subject":"Re: [PATCH 5/6 (v2)] upload-pack: send the HEAD information","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-12-01T16:20:11Z","receivedAt":"2008-12-01T16:20:11Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Junio C Hamano <gitster@pobox.com> wrote:\n> This implements the server side of protocol extension to show which branch\n> the HEAD points at.  The information is sent after the terminating NUL\n> that comes after the server capabilities list, to cause older clients to\n> ignore it, while allowing newer clients to make use of that information\n\nOk, not to paint the bikeshed another color or anything ... but\ncan we do something to make this slightly more extensible?  I like\nthe \"lets hide it behind the NUL\" bit a lot better than the prior\niteration, but I wonder if we shouldn't do something slightly\ndifferent.\n\nMaybe we put on the first capability line a flag that lets the\nclient know we have symref data in the advertised list, and then\ninstead of sticking only HEAD into that first ref we put the names\nof the symrefs after the ref they point to.\n\nSo we might see something like:\n\n  xxxx......................... refs/heads/boo\\0with-symref\\0\n  xxxx......................... refs/heads/master\\0HEAD\\0\n  xxxx......................... refs/remotes/origin/HEAD\\0refs/remotes/origin/master\\0\n\netc.  Its probably harder to produce the output for, but it permits\nadvertising all of the symrefs on the remote side, which may be good\nfor --mirror, among other uses.  It also should make it easier to put\nmultiple symrefs down pointing at the same real ref, they could just\nbe a space delimited list stored after the ref name, and if its the\nfirst ref in the stream, after the other capability advertisement.\n\nActually, since the capability line is space delimited and space is\nnot valid in a ref name, we could just include into the capability\nline like \"symref=HEAD\", but I still like the idea of listing it\nafter each ref, to reduce the risk of running into pkt-line length\nlimitations.\n\n-- \nShawn.\n"},{"id":"96878","messageId":"20081201174414.GA22185@coredump.intra.peff.net","threadId":"16537","inReplyTo":"1228140775-29212-6-git-send-email-gitster@pobox.com","subject":"Re: [PATCH 5/6 (v2)] upload-pack: send the HEAD information","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2008-12-01T17:44:15Z","receivedAt":"2008-12-01T17:44:15Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Dec 01, 2008 at 06:12:54AM -0800, Junio C Hamano wrote:\n\n> +\t\t\tpacket_write(1, \"%s %s%c%s%c%s\\n\", sha1_to_hex(sha1), refname,\n> +\t\t\t\t     0, capabilities, 0, target);\n\nYuck. My two complaints are:\n\n  (1) this implicitly handles only the HEAD symref. I don't think any\n      others are in common use, but the rest of git handles arbitrary\n      symrefs just fine. It would be a shame to needlessly limit the\n      protocol. Can we at least make it <ref>:<ref> to allow later\n      expansion to other symrefs?\n\n      (1a) As a follow-on to that, because the client is not requesting\n      anything, how would we ask for other symrefs if we want to do so\n      later?  I think it would be nice to eventually allow copying of\n      arbitrary symrefs within the refs/* hierarchy (e.g.,\n      project-specific branch aliases). Sending all symrefs right off\n      the bat is potentially large and wasteful.\n\n  (2) You've used up the first such expansion slot forever. Now it's \"if\n      I want to tell you the symref, there is an extra slot, and\n      otherwise none\". But if we ever want to use the _next_ slot, then\n      you will always have to send this slot (blank, I guess?). It gets\n      even more complicated if you ever want to an arbitrary number of\n      symref mappings. Maybe a short header to say \"this slot contains a\n      symref target\"?\n\nSo (1) and (2) together would make it something like:\n\n   <capabilities>\\0\n   symref HEAD:refs/heads/master\\0\n   symref refs/heads/alias:refs/heads/branch\\n\n\nwhich would make adding any new features in the expansion slots easier.\nBut that still doesn't address (1a). I really like the other proposal a\nlot better.\n\n-Peff\n"},{"id":"96887","messageId":"7voczvr7qz.fsf@gitster.siamese.dyndns.org","threadId":"16537","inReplyTo":"20081201162011.GI23984@spearce.org","subject":"Re: [PATCH 5/6 (v2)] upload-pack: send the HEAD information","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-01T19:54:44Z","receivedAt":"2008-12-01T19:54:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Shawn O. Pearce\" <spearce@spearce.org> writes:\n\n> Maybe we put on the first capability line a flag that lets the\n> client know we have symref data in the advertised list, and then\n> instead of sticking only HEAD into that first ref we put the names\n> of the symrefs after the ref they point to.\n>\n> So we might see something like:\n>\n>   xxxx......................... refs/heads/boo\\0with-symref\\0\n>   xxxx......................... refs/heads/master\\0HEAD\\0\n>   xxxx......................... refs/remotes/origin/HEAD\\0refs/remotes/origin/master\\0\n>\n> etc.  Its probably harder to produce the output for, but it permits\n> advertising all of the symrefs on the remote side, which may be good\n> for --mirror, among other uses.  It also should make it easier to put\n> multiple symrefs down pointing at the same real ref, they could just\n> be a space delimited list stored after the ref name, and if its the\n> first ref in the stream, after the other capability advertisement.\n\nIt certainly is possible, and I think the arrangement v2 code makes\nalready keeps that option to talk about symrefs other than HEAD open.  If\nyou want to send all the symref information, you would show something\nlike:\n\n    xxxx... HEAD\\0<caps>\\0refs/heads/master\\n\n    xxxx... refs/heads/master\\n\n    xxxx... refs/remotes/origin/HEAD\\0<caps>\\0refs/remotes/origin/master\\n\n    xxxx... refs/remotes/origin/master\\n\n\nBut in this round I am not interested in giving any \"random symref\"\ninformation but \"HEAD\", so I omitted it from the code.  \n\nNotice that you need to repeat the capabilities list on each and every\nline that describes a symbolic ref for that to work (and you do not need\n\"with-symref\"), though.  See what ll. 80-84 in connect.c does.\n\n\tif (len != name_len + 41) {\n\t\tfree(server_capabilities);\n\t\tserver_capabilities = xstrdup(name + name_len + 1);\n\t}\n\nHistorical accident mandates that the first hidden piece of information on\neach and all of these lines _must_ be the capabilities list.\n"},{"id":"96897","messageId":"7vk5ajqs63.fsf@gitster.siamese.dyndns.org","threadId":"16537","inReplyTo":"20081201174414.GA22185@coredump.intra.peff.net","subject":"Re: [PATCH 5/6 (v2)] upload-pack: send the HEAD information","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-02T01:31:16Z","receivedAt":"2008-12-02T01:31:16Z","isPatch":true,"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, Dec 01, 2008 at 06:12:54AM -0800, Junio C Hamano wrote:\n>\n>> +\t\t\tpacket_write(1, \"%s %s%c%s%c%s\\n\", sha1_to_hex(sha1), refname,\n>> +\t\t\t\t     0, capabilities, 0, target);\n>\n> Yuck. My two complaints are:\n>\n>   (1) this implicitly handles only the HEAD symref.\n\nBut this information *is* on the \"40-hex name\" line that describes the\nHEAD ;-)\n\nYou can trivially extend it to add this to other symbolic refs if you are\ninterested.  I wasn't.\n"},{"id":"96898","messageId":"7vfxl7qs2e.fsf@gitster.siamese.dyndns.org","threadId":"16537","inReplyTo":"4934082B.5050802@viscovery.net","subject":"Re: [PATCH 0/6 (v2)] Detecting HEAD more reliably while cloning","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-02T01:33:29Z","receivedAt":"2008-12-02T01:33:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j.sixt@viscovery.net> writes:\n\n> Junio C Hamano schrieb:\n>> Instead of introducing a full-fledged protocol extension, this round hides\n>> the new information in the same place as the server capabilities list that\n>> is used to implement protocol extension is hidden from older clients.\n>\n> Not that it makes a lot of difference, but why do you want to *hide* the\n> information? Can't we just have a capability-with-parameter:\n>\n>  ... shallow no-progress include-tag head=refs/heads/foo\\ bar ...\n>\n> (with spaces and backslashes escaped)?\n\nThe ref namespace is reasonably tight (most importantly I do not think you\ncan have space) so there is no need for quoting.  If we were to go that\nroute of making them extended \"capabilities\", the right syntax would be\n\n    ... symref-HEAD=refs/heads/master symref-refs/remotes/origin/HEAD=refs/remotes/origin/master ...\n\nor something like that.\n"},{"id":"96908","messageId":"20081202015924.GA6529@coredump.intra.peff.net","threadId":"16537","inReplyTo":"7vk5ajqs63.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 5/6 (v2)] upload-pack: send the HEAD information","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2008-12-02T01:59:25Z","receivedAt":"2008-12-02T01:59:25Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Dec 01, 2008 at 05:31:16PM -0800, Junio C Hamano wrote:\n\n> > Yuck. My two complaints are:\n> >\n> >   (1) this implicitly handles only the HEAD symref.\n> \n> But this information *is* on the \"40-hex name\" line that describes the\n> HEAD ;-)\n\nAhhh. OK. I see, I misunderstood the protocol a bit. So let me revise my\ncomplaints. ;)\n\n  (1) If there are multiple symrefs to report, we have to keep\n      re-sending the server capabilities (I think you mentioned this in\n      the subthread with Shawn).\n\n  (2) Similar to (2) before. If we ever add a _third_ extra slot, we\n      will be stuck sending the symref field each time we want to use\n      that third slot (though if the client properly treats an empty\n      slot the same as non-existent, this only wastes a single byte for\n      the NUL).\n\n  (3) If HEAD doesn't point to a valid object, we have no place to put\n      the symref. Or is it kosher to say\n\n        0000000000000000000000000000000000000000 HEAD\\0...\\0refs/heads/master\n\n      ? I think it would be nice eventually to be able to clone a HEAD\n      pointing to yet-to-be-born branch.\n\n-Peff\n"},{"id":"96911","messageId":"7v1vwrqpvf.fsf@gitster.siamese.dyndns.org","threadId":"16537","inReplyTo":"20081202015924.GA6529@coredump.intra.peff.net","subject":"Re: [PATCH 5/6 (v2)] upload-pack: send the HEAD information","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-02T02:20:52Z","receivedAt":"2008-12-02T02:20:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n>   (1) If there are multiple symrefs to report, we have to keep\n>       re-sending the server capabilities (I think you mentioned this in\n>       the subthread with Shawn).\n\nThis is nothing new, so there is nothing to complain about here.\n\nThe ref advertisement section is not very extensible to begin with and we\nshould consider ourselves lucky that Sergey Vlasov found the hole\n(cf. $gmane/10710) we are exploiting to carry \"server capabilities\"; I do\nnot think we should nor can stuff any more than absolute minimum in the\nsection.\n\n>   (3) If HEAD doesn't point to a valid object, we have no place to put\n>       the symref. Or is it kosher to say\n>\n>         0000000000000000000000000000000000000000 HEAD\\0...\\0refs/heads/master\n>\n>       ? I think it would be nice eventually to be able to clone a HEAD\n>       pointing to yet-to-be-born branch.\n\nI think sending 0{40} would break older clients, but older clients cannot\nclone from an empty repository anyway, so that should not be so bad.  I\nhowever do not think it is such a big thing to be able to clone void\nanyway.\n\nYou just have to train yourself to announce that your repository is\nclonable _after_ making it actually clonable.\n"},{"id":"96916","messageId":"20081202023643.GA6804@coredump.intra.peff.net","threadId":"16537","inReplyTo":"7v1vwrqpvf.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 5/6 (v2)] upload-pack: send the HEAD information","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2008-12-02T02:36:43Z","receivedAt":"2008-12-02T02:36:43Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Dec 01, 2008 at 06:20:52PM -0800, Junio C Hamano wrote:\n\n> I think sending 0{40} would break older clients, but older clients cannot\n> clone from an empty repository anyway, so that should not be so bad.  I\n> however do not think it is such a big thing to be able to clone void\n> anyway.\n> \n> You just have to train yourself to announce that your repository is\n> clonable _after_ making it actually clonable.\n\nI disagree. 99% of the time we see people complain about this, it is not\n\"I tried to announce my repo to people but it didn't have any commits\"\nbut rather \"why must I hack, init remote, then push, instead of init\nremote, hack, push\"[1].\n\nThat is, some segment of people (myself included) want to say first \"I'm\nstarting a new project, and so I'm going to create a spot for it on my\nserver\". Of course we can train ourselves to do it in the other order,\nbut it is an unnecessary complication.\n\n-Peff\n\n[1] Actually, it is more than just arbitrary preference. It is less\ntyping to do:\n\n    ssh remote 'mkdir foo && cd foo && git init --bare'\n    git clone remote:foo\n    hack hack hack; commit\n    git push\n\nthan\n\n    git init\n    hack hack hack; commit\n    ssh remote 'mkdir foo && cd foo && git init --bare'\n    git push\n    git remote add -m refs/heads/master origin remote:foo\n"}]}