{"thread":{"id":"40726","subject":"[PATCH v3 0/4] Improve hideRefs when used with namespaces","startedAt":"2015-11-05T06:07:27Z","lastAt":"2015-11-05T20:46:34Z","messageCount":6,"participants":["Lukas Fleischer","Junio C Hamano"],"isPatch":true,"patchVersion":3,"patchTotal":4},"messages":[{"id":"272933","messageId":"1446703651-9049-1-git-send-email-lfleischer@lfos.de","threadId":"40726","inReplyTo":null,"subject":"[PATCH v3 0/4] Improve hideRefs when used with namespaces","fromName":"Lukas Fleischer","fromEmail":"lfleischer@lfos.de","sentAt":"2015-11-05T06:07:27Z","receivedAt":"2015-11-05T06:07:27Z","isPatch":true,"sender":{"key":"lfleischer@lfos.de","avatar":"https://avatars.githubusercontent.com/u/5530842?v=4"},"body":"This is a first set of patches improving documentation and behavior of\nthe transfer.hideRefs feature as discussed in [1]. In particular,\nhideRefs is changed to generally match stripped refs by default and\nmatch full refs when prefixed with \"^\". The documentation is updated\naccordingly. Basic tests are added.\n\nChanges since v2:\n\n* Reword the additions to the documentation as suggested by Junio.\n* Fix the return value in show_ref_cb().\n\n[1] http://marc.info/?l=git&m=144604694223920\n\nLukas Fleischer (4):\n  Document the semantics of hideRefs with namespaces\n  upload-pack: strip refs before calling ref_is_hidden()\n  Add support for matching full refs in hideRefs\n  t5509: add basic tests for hideRefs\n\n Documentation/config.txt         |  9 +++++++++\n builtin/receive-pack.c           | 27 ++++++++++++++++++++------\n refs.c                           | 15 ++++++++++++---\n refs.h                           | 10 +++++++++-\n t/t5509-fetch-push-namespaces.sh | 41 ++++++++++++++++++++++++++++++++++++++++\n upload-pack.c                    | 13 ++++++++-----\n 6 files changed, 100 insertions(+), 15 deletions(-)\n\n-- \n2.6.2\n"},{"id":"272934","messageId":"1446703651-9049-2-git-send-email-lfleischer@lfos.de","threadId":"40726","inReplyTo":"1446703651-9049-1-git-send-email-lfleischer@lfos.de","subject":"[PATCH v3 1/4] Document the semantics of hideRefs with namespaces","fromName":"Lukas Fleischer","fromEmail":"lfleischer@lfos.de","sentAt":"2015-11-05T06:07:28Z","receivedAt":"2015-11-05T06:07:28Z","isPatch":true,"sender":{"key":"lfleischer@lfos.de","avatar":"https://avatars.githubusercontent.com/u/5530842?v=4"},"body":"Right now, there is no clear definition of how transfer.hideRefs should\nbehave when a namespace is set. Explain that hideRefs prefixes match\nstripped names in that case. This is how hideRefs patterns are currently\nhandled in receive-pack.\n\nSigned-off-by: Lukas Fleischer <lfleischer@lfos.de>\n---\n Documentation/config.txt | 8 ++++++++\n 1 file changed, 8 insertions(+)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 1204072..74a81e0 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -2684,6 +2684,14 @@ You may also include a `!` in front of the ref name to negate the entry,\n explicitly exposing it, even if an earlier entry marked it as hidden.\n If you have multiple hideRefs values, later entries override earlier ones\n (and entries in more-specific config files override less-specific ones).\n++\n+If a namespace is set, the namespace prefix is stripped from each reference\n+before references are matched against hideRefs patterns. For example, if the\n+prefix `refs/heads/master` is specified in `transfer.hideRefs` and the current\n+namespace is `foo`, then `refs/namespaces/foo/refs/heads/master` is omitted\n+from the advertisements but `refs/heads/master` and\n+`refs/namespaces/bar/refs/heads/master` are still advertised as so-called\n+\"have\" lines.\n \n transfer.unpackLimit::\n \tWhen `fetch.unpackLimit` or `receive.unpackLimit` are\n-- \n2.6.2\n"},{"id":"272935","messageId":"1446703651-9049-3-git-send-email-lfleischer@lfos.de","threadId":"40726","inReplyTo":"1446703651-9049-1-git-send-email-lfleischer@lfos.de","subject":"[PATCH v3 2/4] upload-pack: strip refs before calling ref_is_hidden()","fromName":"Lukas Fleischer","fromEmail":"lfleischer@lfos.de","sentAt":"2015-11-05T06:07:29Z","receivedAt":"2015-11-05T06:07:29Z","isPatch":true,"sender":{"key":"lfleischer@lfos.de","avatar":"https://avatars.githubusercontent.com/u/5530842?v=4"},"body":"Make hideRefs handling in upload-pack consistent with the behavior\ndescribed in the documentation by stripping refs before comparing them\nwith prefixes in hideRefs.\n\nSigned-off-by: Lukas Fleischer <lfleischer@lfos.de>\n---\n upload-pack.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex d0bc3ca..4ca960e 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -692,7 +692,7 @@ static int mark_our_ref(const char *refname, const struct object_id *oid)\n {\n \tstruct object *o = lookup_unknown_object(oid->hash);\n \n-\tif (ref_is_hidden(refname)) {\n+\tif (refname && ref_is_hidden(refname)) {\n \t\to->flags |= HIDDEN_REF;\n \t\treturn 1;\n \t}\n@@ -703,7 +703,7 @@ static int mark_our_ref(const char *refname, const struct object_id *oid)\n static int check_ref(const char *refname, const struct object_id *oid,\n \t\t     int flag, void *cb_data)\n {\n-\tmark_our_ref(refname, oid);\n+\tmark_our_ref(strip_namespace(refname), oid);\n \treturn 0;\n }\n \n@@ -726,7 +726,7 @@ static int send_ref(const char *refname, const struct object_id *oid,\n \tconst char *refname_nons = strip_namespace(refname);\n \tstruct object_id peeled;\n \n-\tif (mark_our_ref(refname, oid))\n+\tif (mark_our_ref(refname_nons, oid))\n \t\treturn 0;\n \n \tif (capabilities) {\n-- \n2.6.2\n"},{"id":"272937","messageId":"1446703651-9049-4-git-send-email-lfleischer@lfos.de","threadId":"40726","inReplyTo":"1446703651-9049-1-git-send-email-lfleischer@lfos.de","subject":"[PATCH v3 3/4] Add support for matching full refs in hideRefs","fromName":"Lukas Fleischer","fromEmail":"lfleischer@lfos.de","sentAt":"2015-11-05T06:07:30Z","receivedAt":"2015-11-05T06:07:30Z","isPatch":true,"sender":{"key":"lfleischer@lfos.de","avatar":"https://avatars.githubusercontent.com/u/5530842?v=4"},"body":"In addition to matching stripped refs, one can now add hideRefs patterns\nthat the full (unstripped) ref is matched against. To distinguish\nbetween stripped and full matches, those new patterns must be prefixed\nwith a circumflex (^).\n\nThis commit also removes support for the undocumented and unintended\nhideRefs settings \"have\" (suppressing all \"have\" lines) and\n\"capabilities^{}\" (suppressing the capabilities line).\n\nSigned-off-by: Lukas Fleischer <lfleischer@lfos.de>\n---\n Documentation/config.txt |  3 ++-\n builtin/receive-pack.c   | 27 +++++++++++++++++++++------\n refs.c                   | 15 ++++++++++++---\n refs.h                   | 10 +++++++++-\n upload-pack.c            | 13 ++++++++-----\n 5 files changed, 52 insertions(+), 16 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 74a81e0..d816338 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -2691,7 +2691,8 @@ prefix `refs/heads/master` is specified in `transfer.hideRefs` and the current\n namespace is `foo`, then `refs/namespaces/foo/refs/heads/master` is omitted\n from the advertisements but `refs/heads/master` and\n `refs/namespaces/bar/refs/heads/master` are still advertised as so-called\n-\"have\" lines.\n+\"have\" lines. In order to match refs before stripping, add a `^` in front of\n+the ref name. If you combine `!` and `^`, `!` must be specified first.\n \n transfer.unpackLimit::\n \tWhen `fetch.unpackLimit` or `receive.unpackLimit` are\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex bcb624b..f06f70a 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -195,9 +195,6 @@ static int receive_pack_config(const char *var, const char *value, void *cb)\n \n static void show_ref(const char *path, const unsigned char *sha1)\n {\n-\tif (ref_is_hidden(path))\n-\t\treturn;\n-\n \tif (sent_capabilities) {\n \t\tpacket_write(1, \"%s %s\\n\", sha1_to_hex(sha1), path);\n \t} else {\n@@ -219,9 +216,14 @@ static void show_ref(const char *path, const unsigned char *sha1)\n \t}\n }\n \n-static int show_ref_cb(const char *path, const struct object_id *oid, int flag, void *unused)\n+static int show_ref_cb(const char *path_full, const struct object_id *oid,\n+\t\t       int flag, void *unused)\n {\n-\tpath = strip_namespace(path);\n+\tconst char *path = strip_namespace(path_full);\n+\n+\tif (ref_is_hidden(path, path_full))\n+\t\treturn 0;\n+\n \t/*\n \t * Advertise refs outside our current namespace as \".have\"\n \t * refs, so that the client can use them to minimize data\n@@ -1195,16 +1197,29 @@ static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20])\n \n static void reject_updates_to_hidden(struct command *commands)\n {\n+\tstruct strbuf refname_full = STRBUF_INIT;\n+\tsize_t prefix_len;\n \tstruct command *cmd;\n \n+\tstrbuf_addstr(&refname_full, get_git_namespace());\n+\tprefix_len = refname_full.len;\n+\n \tfor (cmd = commands; cmd; cmd = cmd->next) {\n-\t\tif (cmd->error_string || !ref_is_hidden(cmd->ref_name))\n+\t\tif (cmd->error_string)\n+\t\t\tcontinue;\n+\n+\t\tstrbuf_setlen(&refname_full, prefix_len);\n+\t\tstrbuf_addstr(&refname_full, cmd->ref_name);\n+\n+\t\tif (!ref_is_hidden(cmd->ref_name, refname_full.buf))\n \t\t\tcontinue;\n \t\tif (is_null_sha1(cmd->new_sha1))\n \t\t\tcmd->error_string = \"deny deleting a hidden ref\";\n \t\telse\n \t\t\tcmd->error_string = \"deny updating a hidden ref\";\n \t}\n+\n+\tstrbuf_release(&refname_full);\n }\n \n static int should_process_cmd(struct command *cmd)\ndiff --git a/refs.c b/refs.c\nindex 72d96ed..892fffb 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -321,7 +321,7 @@ int parse_hide_refs_config(const char *var, const char *value, const char *secti\n \treturn 0;\n }\n \n-int ref_is_hidden(const char *refname)\n+int ref_is_hidden(const char *refname, const char *refname_full)\n {\n \tint i;\n \n@@ -329,6 +329,7 @@ int ref_is_hidden(const char *refname)\n \t\treturn 0;\n \tfor (i = hide_refs->nr - 1; i >= 0; i--) {\n \t\tconst char *match = hide_refs->items[i].string;\n+\t\tconst char *subject;\n \t\tint neg = 0;\n \t\tint len;\n \n@@ -337,10 +338,18 @@ int ref_is_hidden(const char *refname)\n \t\t\tmatch++;\n \t\t}\n \n-\t\tif (!starts_with(refname, match))\n+\t\tif (*match == '^') {\n+\t\t\tsubject = refname_full;\n+\t\t\tmatch++;\n+\t\t} else {\n+\t\t\tsubject = refname;\n+\t\t}\n+\n+\t\t/* refname can be NULL when namespaces are used. */\n+\t\tif (!subject || !starts_with(subject, match))\n \t\t\tcontinue;\n \t\tlen = strlen(match);\n-\t\tif (!refname[len] || refname[len] == '/')\n+\t\tif (!subject[len] || subject[len] == '/')\n \t\t\treturn !neg;\n \t}\n \treturn 0;\ndiff --git a/refs.h b/refs.h\nindex 69fa4df..116c461 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -604,7 +604,15 @@ int update_ref(const char *msg, const char *refname,\n \n extern int parse_hide_refs_config(const char *var, const char *value, const char *);\n \n-extern int ref_is_hidden(const char *);\n+/*\n+ * Check whether a ref is hidden. If no namespace is set, both the first and\n+ * the second parameter point to the full ref name. If a namespace is set and\n+ * the ref is inside that namespace, the first parameter is a pointer to the\n+ * name of the ref with the namespace prefix removed. If a namespace is set and\n+ * the ref is outside that namespace, the first parameter is NULL. The second\n+ * parameter always points to the full ref name.\n+ */\n+extern int ref_is_hidden(const char *, const char *);\n \n enum ref_type {\n \tREF_TYPE_PER_WORKTREE,\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 4ca960e..08efb1d 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -688,11 +688,12 @@ static void receive_needs(void)\n }\n \n /* return non-zero if the ref is hidden, otherwise 0 */\n-static int mark_our_ref(const char *refname, const struct object_id *oid)\n+static int mark_our_ref(const char *refname, const char *refname_full,\n+\t\t\tconst struct object_id *oid)\n {\n \tstruct object *o = lookup_unknown_object(oid->hash);\n \n-\tif (refname && ref_is_hidden(refname)) {\n+\tif (ref_is_hidden(refname, refname_full)) {\n \t\to->flags |= HIDDEN_REF;\n \t\treturn 1;\n \t}\n@@ -700,10 +701,12 @@ static int mark_our_ref(const char *refname, const struct object_id *oid)\n \treturn 0;\n }\n \n-static int check_ref(const char *refname, const struct object_id *oid,\n+static int check_ref(const char *refname_full, const struct object_id *oid,\n \t\t     int flag, void *cb_data)\n {\n-\tmark_our_ref(strip_namespace(refname), oid);\n+\tconst char *refname = strip_namespace(refname_full);\n+\n+\tmark_our_ref(refname, refname_full, oid);\n \treturn 0;\n }\n \n@@ -726,7 +729,7 @@ static int send_ref(const char *refname, const struct object_id *oid,\n \tconst char *refname_nons = strip_namespace(refname);\n \tstruct object_id peeled;\n \n-\tif (mark_our_ref(refname_nons, oid))\n+\tif (mark_our_ref(refname_nons, refname, oid))\n \t\treturn 0;\n \n \tif (capabilities) {\n-- \n2.6.2\n"},{"id":"272936","messageId":"1446703651-9049-5-git-send-email-lfleischer@lfos.de","threadId":"40726","inReplyTo":"1446703651-9049-1-git-send-email-lfleischer@lfos.de","subject":"[PATCH v3 4/4] t5509: add basic tests for hideRefs","fromName":"Lukas Fleischer","fromEmail":"lfleischer@lfos.de","sentAt":"2015-11-05T06:07:31Z","receivedAt":"2015-11-05T06:07:31Z","isPatch":true,"sender":{"key":"lfleischer@lfos.de","avatar":"https://avatars.githubusercontent.com/u/5530842?v=4"},"body":"Test whether regular and full hideRefs patterns work as expected when\nnamespaces are used.\n\nHelped-by: Eric Sunshine <sunshine@sunshineco.com>\nSigned-off-by: Lukas Fleischer <lfleischer@lfos.de>\n---\n t/t5509-fetch-push-namespaces.sh | 41 ++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 41 insertions(+)\n\ndiff --git a/t/t5509-fetch-push-namespaces.sh b/t/t5509-fetch-push-namespaces.sh\nindex cc0b31f..bc44ac3 100755\n--- a/t/t5509-fetch-push-namespaces.sh\n+++ b/t/t5509-fetch-push-namespaces.sh\n@@ -82,4 +82,45 @@ test_expect_success 'mirroring a repository using a ref namespace' '\n \t)\n '\n \n+test_expect_success 'hide namespaced refs with transfer.hideRefs' '\n+\tGIT_NAMESPACE=namespace \\\n+\t\tgit -C pushee -c transfer.hideRefs=refs/tags \\\n+\t\tls-remote \"ext::git %s .\" >actual &&\n+\tprintf \"$commit1\\trefs/heads/master\\n\" >expected &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'check that transfer.hideRefs does not match unstripped refs' '\n+\tGIT_NAMESPACE=namespace \\\n+\t\tgit -C pushee -c transfer.hideRefs=refs/namespaces/namespace/refs/tags \\\n+\t\tls-remote \"ext::git %s .\" >actual &&\n+\tprintf \"$commit1\\trefs/heads/master\\n\" >expected &&\n+\tprintf \"$commit0\\trefs/tags/0\\n\" >>expected &&\n+\tprintf \"$commit1\\trefs/tags/1\\n\" >>expected &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'hide full refs with transfer.hideRefs' '\n+\tGIT_NAMESPACE=namespace \\\n+\t\tgit -C pushee -c transfer.hideRefs=\"^refs/namespaces/namespace/refs/tags\" \\\n+\t\tls-remote \"ext::git %s .\" >actual &&\n+\tprintf \"$commit1\\trefs/heads/master\\n\" >expected &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'try to update a hidden ref' '\n+\ttest_config -C pushee transfer.hideRefs refs/heads/master &&\n+\ttest_must_fail git -C original push pushee-namespaced master\n+'\n+\n+test_expect_success 'try to update a ref that is not hidden' '\n+\ttest_config -C pushee transfer.hideRefs refs/namespaces/namespace/refs/heads/master &&\n+\tgit -C original push pushee-namespaced master\n+'\n+\n+test_expect_success 'try to update a hidden full ref' '\n+\ttest_config -C pushee transfer.hideRefs \"^refs/namespaces/namespace/refs/heads/master\" &&\n+\ttest_must_fail git -C original push pushee-namespaced master\n+'\n+\n test_done\n-- \n2.6.2\n"},{"id":"272972","messageId":"xmqqegg45g45.fsf@gitster.mtv.corp.google.com","threadId":"40726","inReplyTo":"1446703651-9049-1-git-send-email-lfleischer@lfos.de","subject":"Re: [PATCH v3 0/4] Improve hideRefs when used with namespaces","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-11-05T20:46:34Z","receivedAt":"2015-11-05T20:46:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thanks; will replace what has been queued.\n"}]}