diff options
author | Jeff King <peff@peff.net> | 2015-07-28 16:23:26 -0400 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2015-08-07 11:47:36 -0700 |
commit | 2bc31d1631229d863376d48ef84eb846fea1df02 (patch) | |
tree | be540f6670eeccb59a8ae618941b4ed9000f2d97 /refs.c | |
parent | cc118a65b4590cc2d669679260bad7ca627f2a30 (diff) | |
download | git-2bc31d1631229d863376d48ef84eb846fea1df02.tar.gz git-2bc31d1631229d863376d48ef84eb846fea1df02.tar.xz |
refs: support negative transfer.hideRefs
If you hide a hierarchy of refs using the transfer.hideRefs
config, there is no way to later override that config to
"unhide" it. This patch implements a "negative" hide which
causes matches to immediately be marked as unhidden, even if
another match would hide it. We take care to apply the
matches in reverse-order from how they are fed to us by the
config machinery, as that lets our usual "last one wins"
config precedence work (and entries in .git/config, for
example, will override /etc/gitconfig).
So you can now do:
$ git config --system transfer.hideRefs refs/secret
$ git config transfer.hideRefs '!refs/secret/not-so-secret'
to hide refs/secret in all repos, except for one public bit
in one specific repo. Or you can even do:
$ git clone \
-u "git -c transfer.hiderefs="!refs/foo" upload-pack" \
remote:repo.git
to clone remote:repo.git, overriding any hiding it has
configured.
There are two alternatives that were considered and
rejected:
1. A generic config mechanism for removing an item from a
list. E.g.: (e.g., "[transfer] hideRefs -= refs/foo").
This is nice because it could apply to other
multi-valued config, as well. But it is not nearly as
flexible. There is no way to say:
[transfer]
hideRefs = refs/secret
hideRefs = refs/secret/not-so-secret
Having explicit negative specifications means we can
override previous entries, even if they are not the
same literal string.
2. Adding another variable to override some parts of
hideRefs (e.g., "exposeRefs").
This solves the problem from alternative (1), but it
cannot easily obey the normal config precedence,
because it would use two separate lists. For example:
[transfer]
hideRefs = refs/secret
exposeRefs = refs/secret/not-so-secret
hideRefs = refs/secret/not-so-secret/no-really-its-secret
With two lists, we have to apply the "expose" rules
first, and only then apply the "hide" rules. But that
does not match what the above config intends.
Of course we could internally parse that to a single
list, respecting the ordering, which saves us having to
invent the new "!" syntax. But using a single name
communicates to the user that the ordering _is_
important. And "!" is well-known for negation, and
should not appear at the beginning of a ref (it is
actually valid in a ref-name, but all entries here
should be fully-qualified, starting with "refs/").
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'refs.c')
-rw-r--r-- | refs.c | 18 |
1 files changed, 13 insertions, 5 deletions
@@ -4159,17 +4159,25 @@ int parse_hide_refs_config(const char *var, const char *value, const char *secti int ref_is_hidden(const char *refname) { - struct string_list_item *item; + int i; if (!hide_refs) return 0; - for_each_string_list_item(item, hide_refs) { + for (i = hide_refs->nr - 1; i >= 0; i--) { + const char *match = hide_refs->items[i].string; + int neg = 0; int len; - if (!starts_with(refname, item->string)) + + if (*match == '!') { + neg = 1; + match++; + } + + if (!starts_with(refname, match)) continue; - len = strlen(item->string); + len = strlen(match); if (!refname[len] || refname[len] == '/') - return 1; + return !neg; } return 0; } |