{"thread":{"id":"39959","subject":"[PATCH 0/2] negative hideRefs for overriding","startedAt":"2015-07-28T19:57:47Z","lastAt":"2015-07-30T23:28:35Z","messageCount":7,"participants":["Jeff King","Junio C Hamano","Eric Sunshine"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"266976","messageId":"20150728195747.GA13596@peff.net","threadId":"39959","inReplyTo":null,"subject":"[PATCH 0/2] negative hideRefs for overriding","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-07-28T19:57:47Z","receivedAt":"2015-07-28T19:57:47Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"At GitHub, we keep some information in a private part of the refs\nnamespace. We use transfer.hideRefs so that users do not see it when\nfetching or pushing, and that works well. However, sometimes we want to\nexpose part of the hidden namespace (e.g., for an internal fetch or\npush), and that cannot be done with the existing code. Usually config\nvariables are last-one-wins, so you can simply overwrite any existing\nvalues with \"git -c ...\". But for multi-valued config like hideRefs,\nthat just appends to the list, and the ref remains hidden.\n\nThis series adds negation to hideRefs, which gives us a reasonable\nlast-one-wins setup. That allows \"git -c\" to unhide a specific set of\nrefs (though note you have to use \"--upload-pack='git -c ...'\" since\nupload-pack does not share our environment). It also allows more complex\nconfig, like hiding all of \"refs/foo\" except for \"refs/foo/bar\". We\ndon't use that ourselves, but it might come in handy (and logically\nfalls out of the last-one-wins setup).\n\nThe first patch is some documentation cleanup. The interesting bit is in\nthe second one.\n\n  [1/2]: docs/config.txt: reorder hideRefs config\n  [2/2]: refs: support negative transfer.hideRefs\n\n-Peff\n"},{"id":"266977","messageId":"20150728195911.GA13795@peff.net","threadId":"39959","inReplyTo":"20150728195747.GA13596@peff.net","subject":"[PATCH 1/2] docs/config.txt: reorder hideRefs config","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-07-28T19:59:11Z","receivedAt":"2015-07-28T19:59:11Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"The descriptions for receive.hideRefs and\nuploadpack.hideRefs are largely the same, and then\ntransfer.hideRefs refers to both of them. Instead, let's\nmake transfer.hideRefs the \"master\" source, and refer to it\nfrom the other sites (with appropriate program-specific\nannotations).\n\nThis avoids duplication, and will make it easier to document\nchanges to the config option without having to copy and\npaste the description in two places.\n\nWhile we're at it, this fixes some bogus subject/verb\nagreement in the original description.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nI think this makes sense, though I could also see an argument that the\nreader would rather hit the individual program's hideRefs config first\nand not get redirected. The second patch relies on this textually, but\nif we want to drop this one, I can rebase the second to just add the new\ntext in both places.\n\n Documentation/config.txt | 32 +++++++++++++++-----------------\n 1 file changed, 15 insertions(+), 17 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 43bb53c..448eb9d 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -2242,13 +2242,10 @@ receive.denyNonFastForwards::\n \tset when initializing a shared repository.\n \n receive.hideRefs::\n-\tString(s) `receive-pack` uses to decide which refs to omit\n-\tfrom its initial advertisement.  Use more than one\n-\tdefinitions to specify multiple prefix strings. A ref that\n-\tare under the hierarchies listed on the value of this\n-\tvariable is excluded, and is hidden when responding to `git\n-\tpush`, and an attempt to update or delete a hidden ref by\n-\t`git push` is rejected.\n+\tThis variable is the same as `transfer.hideRefs`, but applies\n+\tonly to `receive-pack` (and so affects pushes, but not fetches).\n+\tAn attempt to update or delete a hidden ref by `git push` is\n+\trejected.\n \n receive.updateServerInfo::\n \tIf set to true, git-receive-pack will run git-update-server-info\n@@ -2536,9 +2533,13 @@ transfer.fsckObjects::\n \tDefaults to false.\n \n transfer.hideRefs::\n-\tThis variable can be used to set both `receive.hideRefs`\n-\tand `uploadpack.hideRefs` at the same time to the same\n-\tvalues.  See entries for these other variables.\n+\tString(s) `receive-pack` and `upload-pack` use to decide which\n+\trefs to omit from their initial advertisements.  Use more than\n+\tone definition to specify multiple prefix strings. A ref that is\n+\tunder the hierarchies listed in the value of this variable is\n+\texcluded, and is hidden when responding to `git push` or `git\n+\tfetch`.  See `receive.hideRefs` and `uploadpack.hideRefs` for\n+\tprogram-specific versions of this config.\n \n transfer.unpackLimit::\n \tWhen `fetch.unpackLimit` or `receive.unpackLimit` are\n@@ -2553,13 +2554,10 @@ uploadarchive.allowUnreachable::\n \t`false`.\n \n uploadpack.hideRefs::\n-\tString(s) `upload-pack` uses to decide which refs to omit\n-\tfrom its initial advertisement.  Use more than one\n-\tdefinitions to specify multiple prefix strings. A ref that\n-\tare under the hierarchies listed on the value of this\n-\tvariable is excluded, and is hidden from `git ls-remote`,\n-\t`git fetch`, etc.  An attempt to fetch a hidden ref by `git\n-\tfetch` will fail.  See also `uploadpack.allowTipSHA1InWant`.\n+\tThis variable is the same as `transfer.hideRefs`, but applies\n+\tonly to `upload-pack` (and so affects only fetches, not pushes).\n+\tAn attempt to fetch a hidden ref by `git fetch` will fail.  See\n+\talso `uploadpack.allowTipSHA1InWant`.\n \n uploadpack.allowTipSHA1InWant::\n \tWhen `uploadpack.hideRefs` is in effect, allow `upload-pack`\n-- \n2.5.0.rc3.557.g17a1555\n"},{"id":"266978","messageId":"20150728195934.GB13795@peff.net","threadId":"39959","inReplyTo":"20150728195747.GA13596@peff.net","subject":"[PATCH 2/2] refs: support negative transfer.hideRefs","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-07-28T19:59:34Z","receivedAt":"2015-07-28T19:59:34Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"If you hide a hierarchy of refs using the transfer.hideRefs\nconfig, there is no way to later override that config to\n\"unhide\" it. This patch implements a \"negative\" hide which\ncauses matches to immediately be marked as unhidden, even if\nanother match would hide it. We take care to apply the\nmatches in reverse-order from how they are fed to us by the\nconfig machinery, as that lets our usual \"last one wins\"\nconfig precedence work (and entries in .git/config, for\nexample, will override /etc/gitconfig).\n\nThere are two alternatives that were considered and\nrejected:\n\n  1. A generic config mechanism for removing an item from a\n     list. E.g.: (e.g., \"[transfer] hideRefs -= refs/foo\").\n\n     This is nice because it could apply to other\n     multi-valued config, as well. But it is not nearly as\n     flexible. There is no way to say:\n\n       [transfer]\n       hideRefs = refs/secret\n       hideRefs = refs/secret/not-so-secret\n\n     Having explicit negative specifications means we can\n     override previous entries, even if they are not the\n     same literal string.\n\n  2. Adding another variable to override some parts of\n     hideRefs (e.g., \"exposeRefs\").\n\n     This solves the problem from alternative (1), but it\n     cannot easily obey the normal config precedence,\n     because it would use two separate lists. For example:\n\n       [transfer]\n       hideRefs = refs/secret\n       exposeRefs = refs/secret/not-so-secret\n       hideRefs = refs/secret/not-so-secret/no-really-its-secret\n\n     With two lists, we have to apply the \"expose\" rules\n     first, and only then apply the \"hide\" rules. But that\n     does not match what the above config intends.\n\n     Of course we could internally parse that to a single\n     list, respecting the ordering, which saves us having to\n     invent the new \"!\" syntax. But using a single name\n     communicates to the user that the ordering _is_\n     important. And \"!\" is well-known for negation, and\n     should not appear at the beginning of a ref (it is\n     actually valid in a ref-name, but all entries here\n     should be fully-qualified, starting with \"refs/\").\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n Documentation/config.txt |  5 +++++\n refs.c                   | 18 +++++++++++++-----\n t/t5512-ls-remote.sh     | 15 +++++++++++++++\n 3 files changed, 33 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 448eb9d..a7fbd0a 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -2540,6 +2540,11 @@ transfer.hideRefs::\n \texcluded, and is hidden when responding to `git push` or `git\n \tfetch`.  See `receive.hideRefs` and `uploadpack.hideRefs` for\n \tprogram-specific versions of this config.\n++\n+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 transfer.unpackLimit::\n \tWhen `fetch.unpackLimit` or `receive.unpackLimit` are\ndiff --git a/refs.c b/refs.c\nindex 7ac05cf..68f2cb0 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -4159,17 +4159,25 @@ int parse_hide_refs_config(const char *var, const char *value, const char *secti\n \n int ref_is_hidden(const char *refname)\n {\n-\tstruct string_list_item *item;\n+\tint i;\n \n \tif (!hide_refs)\n \t\treturn 0;\n-\tfor_each_string_list_item(item, hide_refs) {\n+\tfor (i = hide_refs->nr - 1; i >= 0; i--) {\n+\t\tconst char *match = hide_refs->items[i].string;\n+\t\tint neg = 0;\n \t\tint len;\n-\t\tif (!starts_with(refname, item->string))\n+\n+\t\tif (*match == '!') {\n+\t\t\tneg = 1;\n+\t\t\tmatch++;\n+\t\t}\n+\n+\t\tif (!starts_with(refname, match))\n \t\t\tcontinue;\n-\t\tlen = strlen(item->string);\n+\t\tlen = strlen(match);\n \t\tif (!refname[len] || refname[len] == '/')\n-\t\t\treturn 1;\n+\t\t\treturn !neg;\n \t}\n \treturn 0;\n }\ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex 3bd9759..728a1dc 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -128,6 +128,11 @@ test_expect_success 'Report match with --exit-code' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'set up some extra tags for ref hiding' '\n+\tgit tag magic/one &&\n+\tgit tag magic/two\n+'\n+\n for configsection in transfer uploadpack\n do\n \ttest_expect_success \"Hide some refs with $configsection.hiderefs\" '\n@@ -138,6 +143,16 @@ do\n \t\tsed -e \"/\trefs\\/tags\\//d\" >expect &&\n \t\ttest_cmp expect actual\n \t'\n+\n+\ttest_expect_success \"Override hiding of $configsection.hiderefs\" '\n+\t\ttest_when_finished \"test_unconfig $configsection.hiderefs\" &&\n+\t\tgit config --add $configsection.hiderefs refs/tags &&\n+\t\tgit config --add $configsection.hiderefs \"!refs/tags/magic\" &&\n+\t\tgit config --add $configsection.hiderefs refs/tags/magic/one &&\n+\t\tgit ls-remote . >actual &&\n+\t\tverbose grep refs/tags/magic/two actual\n+\t'\n+\n done\n \n test_done\n-- \n2.5.0.rc3.557.g17a1555\n"},{"id":"266988","messageId":"xmqqwpxkca4o.fsf@gitster.dls.corp.google.com","threadId":"39959","inReplyTo":"20150728195934.GB13795@peff.net","subject":"Re: [PATCH 2/2] refs: support negative transfer.hideRefs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-07-28T20:14:47Z","receivedAt":"2015-07-28T20:14:47Z","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> If you hide a hierarchy of refs using the transfer.hideRefs\n> config, there is no way to later override that config to\n> \"unhide\" it. This patch implements a \"negative\" hide which\n> causes matches to immediately be marked as unhidden, even if\n> another match would hide it. We take care to apply the\n> matches in reverse-order from how they are fed to us by the\n> config machinery, as that lets our usual \"last one wins\"\n> config precedence work (and entries in .git/config, for\n> example, will override /etc/gitconfig).\n>\n> There are two alternatives that were considered and\n> rejected:\n> ...\n>   1. A generic config mechanism for removing an item from a\n>      ...\n>   2. Adding another variable to override some parts of\n>      ...\n>      Of course we could internally parse that to a single\n>      list, respecting the ordering, which saves us having to\n>      invent the new \"!\" syntax. But using a single name\n>      communicates to the user that the ordering _is_\n>      important. And \"!\" is well-known for negation, and\n>      should not appear at the beginning of a ref (it is\n>      actually valid in a ref-name, but all entries here\n>      should be fully-qualified, starting with \"refs/\").\n\nI notice that the only time you said that you chose '!' prefix as\nthe way to express this new \"negative\" is as a side note to the\nrejected second variant ;-).  The first paragraph would have been a\ngood place to say that, because the first thing I wondered after\nreading three lines (including the subject) into the log was \"ok, it\nmakes sense and I know what alternatives were considered and\ndiscarded for what reasons without reading the rest, now did he use\nprefix '-', prefix '~', prefix '^', or prefix '!' for the new\nsyntax, or did he use something else?\"\n\nIt would have been very nice if you chose an invalid ref character\nas the negative prefix, and unfortunately '!', which would also have\nbeen my first choice for this prefix, is not an invalid character,\nwhich is a bit sad.\n\nBoth patches make sense.  Will queue.\n\nThanks.\n"},{"id":"266989","messageId":"20150728202326.GA14916@peff.net","threadId":"39959","inReplyTo":"xmqqwpxkca4o.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH 2/2] refs: support negative transfer.hideRefs","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-07-28T20:23:26Z","receivedAt":"2015-07-28T20:23:26Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Jul 28, 2015 at 01:14:47PM -0700, Junio C Hamano wrote:\n\n> I notice that the only time you said that you chose '!' prefix as\n> the way to express this new \"negative\" is as a side note to the\n> rejected second variant ;-).  The first paragraph would have been a\n> good place to say that, because the first thing I wondered after\n> reading three lines (including the subject) into the log was \"ok, it\n> makes sense and I know what alternatives were considered and\n> discarded for what reasons without reading the rest, now did he use\n> prefix '-', prefix '~', prefix '^', or prefix '!' for the new\n> syntax, or did he use something else?\"\n\nYeah, I agree it should come earlier, probably as an example. Below is a\nre-roll. I also realized I do not explicitly test that mixing and\nmatching transfer.* and uploadpack.* works (they should override each\nother as if they are part of the same list). It does work, and the\nre-roll below has an extra test.\n\n> It would have been very nice if you chose an invalid ref character\n> as the negative prefix, and unfortunately '!', which would also have\n> been my first choice for this prefix, is not an invalid character,\n> which is a bit sad.\n\nYeah, I considered \"^\" for that reason, but IMHO it doesn't _quite_ mean\nnegation. Here \"!\" means the same thing as it does in .gitignore and\nelsewhere. And since the refs are fully qualified, I think it is\neffectively invalid (we do not look at \"$GIT_DIR/!refs/\" in the ref\nadvertisement, after all).\n\n-- >8 --\nSubject: refs: support negative transfer.hideRefs\n\nIf you hide a hierarchy of refs using the transfer.hideRefs\nconfig, there is no way to later override that config to\n\"unhide\" it. This patch implements a \"negative\" hide which\ncauses matches to immediately be marked as unhidden, even if\nanother match would hide it. We take care to apply the\nmatches in reverse-order from how they are fed to us by the\nconfig machinery, as that lets our usual \"last one wins\"\nconfig precedence work (and entries in .git/config, for\nexample, will override /etc/gitconfig).\n\nSo you can now do:\n\n  $ git config --system transfer.hideRefs refs/secret\n  $ git config transfer.hideRefs '!refs/secret/not-so-secret'\n\nto hide refs/secret in all repos, except for one public bit\nin one specific repo. Or you can even do:\n\n  $ git clone \\\n      -u \"git -c transfer.hiderefs=\"!refs/foo\" upload-pack\" \\\n      remote:repo.git\n\nto clone remote:repo.git, overriding any hiding it has\nconfigured.\n\nThere are two alternatives that were considered and\nrejected:\n\n  1. A generic config mechanism for removing an item from a\n     list. E.g.: (e.g., \"[transfer] hideRefs -= refs/foo\").\n\n     This is nice because it could apply to other\n     multi-valued config, as well. But it is not nearly as\n     flexible. There is no way to say:\n\n       [transfer]\n       hideRefs = refs/secret\n       hideRefs = refs/secret/not-so-secret\n\n     Having explicit negative specifications means we can\n     override previous entries, even if they are not the\n     same literal string.\n\n  2. Adding another variable to override some parts of\n     hideRefs (e.g., \"exposeRefs\").\n\n     This solves the problem from alternative (1), but it\n     cannot easily obey the normal config precedence,\n     because it would use two separate lists. For example:\n\n       [transfer]\n       hideRefs = refs/secret\n       exposeRefs = refs/secret/not-so-secret\n       hideRefs = refs/secret/not-so-secret/no-really-its-secret\n\n     With two lists, we have to apply the \"expose\" rules\n     first, and only then apply the \"hide\" rules. But that\n     does not match what the above config intends.\n\n     Of course we could internally parse that to a single\n     list, respecting the ordering, which saves us having to\n     invent the new \"!\" syntax. But using a single name\n     communicates to the user that the ordering _is_\n     important. And \"!\" is well-known for negation, and\n     should not appear at the beginning of a ref (it is\n     actually valid in a ref-name, but all entries here\n     should be fully-qualified, starting with \"refs/\").\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n Documentation/config.txt |  5 +++++\n refs.c                   | 18 +++++++++++++-----\n t/t5512-ls-remote.sh     | 22 ++++++++++++++++++++++\n 3 files changed, 40 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 448eb9d..a7fbd0a 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -2540,6 +2540,11 @@ transfer.hideRefs::\n \texcluded, and is hidden when responding to `git push` or `git\n \tfetch`.  See `receive.hideRefs` and `uploadpack.hideRefs` for\n \tprogram-specific versions of this config.\n++\n+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 transfer.unpackLimit::\n \tWhen `fetch.unpackLimit` or `receive.unpackLimit` are\ndiff --git a/refs.c b/refs.c\nindex 7ac05cf..68f2cb0 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -4159,17 +4159,25 @@ int parse_hide_refs_config(const char *var, const char *value, const char *secti\n \n int ref_is_hidden(const char *refname)\n {\n-\tstruct string_list_item *item;\n+\tint i;\n \n \tif (!hide_refs)\n \t\treturn 0;\n-\tfor_each_string_list_item(item, hide_refs) {\n+\tfor (i = hide_refs->nr - 1; i >= 0; i--) {\n+\t\tconst char *match = hide_refs->items[i].string;\n+\t\tint neg = 0;\n \t\tint len;\n-\t\tif (!starts_with(refname, item->string))\n+\n+\t\tif (*match == '!') {\n+\t\t\tneg = 1;\n+\t\t\tmatch++;\n+\t\t}\n+\n+\t\tif (!starts_with(refname, match))\n \t\t\tcontinue;\n-\t\tlen = strlen(item->string);\n+\t\tlen = strlen(match);\n \t\tif (!refname[len] || refname[len] == '/')\n-\t\t\treturn 1;\n+\t\t\treturn !neg;\n \t}\n \treturn 0;\n }\ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex 3bd9759..afde495 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -128,6 +128,11 @@ test_expect_success 'Report match with --exit-code' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'set up some extra tags for ref hiding' '\n+\tgit tag magic/one &&\n+\tgit tag magic/two\n+'\n+\n for configsection in transfer uploadpack\n do\n \ttest_expect_success \"Hide some refs with $configsection.hiderefs\" '\n@@ -138,6 +143,23 @@ do\n \t\tsed -e \"/\trefs\\/tags\\//d\" >expect &&\n \t\ttest_cmp expect actual\n \t'\n+\n+\ttest_expect_success \"Override hiding of $configsection.hiderefs\" '\n+\t\ttest_when_finished \"test_unconfig $configsection.hiderefs\" &&\n+\t\tgit config --add $configsection.hiderefs refs/tags &&\n+\t\tgit config --add $configsection.hiderefs \"!refs/tags/magic\" &&\n+\t\tgit config --add $configsection.hiderefs refs/tags/magic/one &&\n+\t\tgit ls-remote . >actual &&\n+\t\tverbose grep refs/tags/magic/two actual\n+\t'\n+\n done\n \n+test_expect_success 'overrides work between mixed transfer/upload-pack hideRefs' '\n+\ttest_config uploadpack.hiderefs refs/tags &&\n+\ttest_config transfer.hiderefs \"!refs/tags/magic\" &&\n+\tgit ls-remote . >actual &&\n+\tverbose grep refs/tags/magic actual\n+'\n+\n test_done\n-- \n2.5.0.rc3.557.g17a1555\n"},{"id":"267176","messageId":"CAPig+cTJuCWwhzrAt47yCEMv4yrTX-C1e9L_yBwyqJ-YbGfcuA@mail.gmail.com","threadId":"39959","inReplyTo":"20150728195934.GB13795@peff.net","subject":"Re: [PATCH 2/2] refs: support negative transfer.hideRefs","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-07-30T20:17:35Z","receivedAt":"2015-07-30T20:17:35Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Tue, Jul 28, 2015 at 3:59 PM, Jeff King <peff@peff.net> wrote:\n> If you hide a hierarchy of refs using the transfer.hideRefs\n> config, there is no way to later override that config to\n> \"unhide\" it. This patch implements a \"negative\" hide which\n> causes matches to immediately be marked as unhidden, even if\n> another match would hide it. We take care to apply the\n> matches in reverse-order from how they are fed to us by the\n> config machinery, as that lets our usual \"last one wins\"\n> config precedence work (and entries in .git/config, for\n> example, will override /etc/gitconfig).\n>\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n> +test_expect_success 'set up some extra tags for ref hiding' '\n> +       git tag magic/one &&\n> +       git tag magic/two\n> +'\n> +\n>  for configsection in transfer uploadpack\n>  do\n>         test_expect_success \"Hide some refs with $configsection.hiderefs\" '\n> @@ -138,6 +143,16 @@ do\n>                 sed -e \"/       refs\\/tags\\//d\" >expect &&\n>                 test_cmp expect actual\n>         '\n> +\n> +       test_expect_success \"Override hiding of $configsection.hiderefs\" '\n> +               test_when_finished \"test_unconfig $configsection.hiderefs\" &&\n> +               git config --add $configsection.hiderefs refs/tags &&\n> +               git config --add $configsection.hiderefs \"!refs/tags/magic\" &&\n> +               git config --add $configsection.hiderefs refs/tags/magic/one &&\n> +               git ls-remote . >actual &&\n> +               verbose grep refs/tags/magic/two actual\n\nFor completeness, do you also want to add\n\n    !grep refs/tags/magic/one actual\n\nto confirm that the third hideRefs did indeed override the second one?\n\n> +       '\n> +\n>  done\n>\n>  test_done\n> --\n> 2.5.0.rc3.557.g17a1555\n"},{"id":"267180","messageId":"20150730232835.GA5805@sigill.intra.peff.net","threadId":"39959","inReplyTo":"CAPig+cTJuCWwhzrAt47yCEMv4yrTX-C1e9L_yBwyqJ-YbGfcuA@mail.gmail.com","subject":"Re: [PATCH 2/2] refs: support negative transfer.hideRefs","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-07-30T23:28:35Z","receivedAt":"2015-07-30T23:28:35Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jul 30, 2015 at 04:17:35PM -0400, Eric Sunshine wrote:\n\n> > +       test_expect_success \"Override hiding of $configsection.hiderefs\" '\n> > +               test_when_finished \"test_unconfig $configsection.hiderefs\" &&\n> > +               git config --add $configsection.hiderefs refs/tags &&\n> > +               git config --add $configsection.hiderefs \"!refs/tags/magic\" &&\n> > +               git config --add $configsection.hiderefs refs/tags/magic/one &&\n> > +               git ls-remote . >actual &&\n> > +               verbose grep refs/tags/magic/two actual\n> \n> For completeness, do you also want to add\n> \n>     !grep refs/tags/magic/one actual\n> \n> to confirm that the third hideRefs did indeed override the second one?\n\nYeah, I think that is a good change. We could also test_cmp the whole\noutput, but I didn't want to be dependent on other junk from previous\ntests.\n\n-Peff\n"}]}