builtin/config: introduce "get" subcommand

Introduce a new "get" subcommand to git-config(1). Please refer to
preceding commits regarding the motivation behind this change.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Patrick Steinhardt 2024-05-06 10:56:29 +02:00 committed by Junio C Hamano
parent 14970509c6
commit 4e51389000
3 changed files with 194 additions and 99 deletions

View File

@ -10,18 +10,14 @@ SYNOPSIS
-------- --------
[verse] [verse]
'git config list' [<file-option>] [<display-option>] [--includes] 'git config list' [<file-option>] [<display-option>] [--includes]
'git config get' [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] <name>
'git config' [<file-option>] [--type=<type>] [--comment=<message>] [--fixed-value] [--show-origin] [--show-scope] [-z|--null] <name> [<value> [<value-pattern>]] 'git config' [<file-option>] [--type=<type>] [--comment=<message>] [--fixed-value] [--show-origin] [--show-scope] [-z|--null] <name> [<value> [<value-pattern>]]
'git config' [<file-option>] [--type=<type>] [--comment=<message>] --add <name> <value> 'git config' [<file-option>] [--type=<type>] [--comment=<message>] --add <name> <value>
'git config' [<file-option>] [--type=<type>] [--comment=<message>] [--fixed-value] --replace-all <name> <value> [<value-pattern>] 'git config' [<file-option>] [--type=<type>] [--comment=<message>] [--fixed-value] --replace-all <name> <value> [<value-pattern>]
'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] --get <name> [<value-pattern>]
'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] --get-all <name> [<value-pattern>]
'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] [--name-only] --get-regexp <name-regex> [<value-pattern>]
'git config' [<file-option>] [--type=<type>] [-z|--null] --get-urlmatch <name> <URL>
'git config' [<file-option>] [--fixed-value] --unset <name> [<value-pattern>] 'git config' [<file-option>] [--fixed-value] --unset <name> [<value-pattern>]
'git config' [<file-option>] [--fixed-value] --unset-all <name> [<value-pattern>] 'git config' [<file-option>] [--fixed-value] --unset-all <name> [<value-pattern>]
'git config' [<file-option>] --rename-section <old-name> <new-name> 'git config' [<file-option>] --rename-section <old-name> <new-name>
'git config' [<file-option>] --remove-section <name> 'git config' [<file-option>] --remove-section <name>
'git config' [<file-option>] --get-color <name> [<default>]
'git config' [<file-option>] --get-colorbool <name> [<stdout-is-tty>] 'git config' [<file-option>] --get-colorbool <name> [<stdout-is-tty>]
'git config' [<file-option>] -e | --edit 'git config' [<file-option>] -e | --edit
@ -80,6 +76,12 @@ COMMANDS
list:: list::
List all variables set in config file, along with their values. List all variables set in config file, along with their values.
get::
Emits the value of the specified key. If key is present multiple times
in the configuration, emits the last value. If `--all` is specified,
emits all values associated with key. Returns error code 1 if key is
not present.
[[OPTIONS]] [[OPTIONS]]
OPTIONS OPTIONS
------- -------
@ -105,22 +107,16 @@ OPTIONS
not contain linefeed characters (no multi-line comments are not contain linefeed characters (no multi-line comments are
permitted). permitted).
--get:: --all::
Get the value for a given key (optionally filtered by a regex With `get`, return all values for a multi-valued key.
matching the value). Returns error code 1 if the key was not
found and the last value if multiple key values were found.
--get-all:: ---regexp::
Like get, but returns all values for a multi-valued key. With `get`, interpret the name as a regular expression. Regular
expression matching is currently case-sensitive and done against a
canonicalized version of the key in which section and variable names
are lowercased, but subsection names are not.
--get-regexp:: --url=<URL>::
Like --get-all, but interprets the name as a regular expression and
writes out the key names. Regular expression matching is currently
case-sensitive and done against a canonicalized version of the key
in which section and variable names are lowercased, but subsection
names are not.
--get-urlmatch <name> <URL>::
When given a two-part <name> as <section>.<key>, the value for When given a two-part <name> as <section>.<key>, the value for
<section>.<URL>.<key> whose <URL> part matches the best to the <section>.<URL>.<key> whose <URL> part matches the best to the
given URL is returned (if no such key exists, the value for given URL is returned (if no such key exists, the value for
@ -251,7 +247,7 @@ Valid `<type>`'s include:
--name-only:: --name-only::
Output only the names of config variables for `list` or Output only the names of config variables for `list` or
`--get-regexp`. `get`.
--show-origin:: --show-origin::
Augment the output of all queried config options with the Augment the output of all queried config options with the
@ -275,17 +271,6 @@ Valid `<type>`'s include:
When the color setting for `name` is undefined, the command uses When the color setting for `name` is undefined, the command uses
`color.ui` as fallback. `color.ui` as fallback.
--get-color <name> [<default>]::
Find the color configured for `name` (e.g. `color.diff.new`) and
output it as the ANSI color escape sequence to the standard
output. The optional `default` parameter is used instead, if
there is no color configured for `name`.
+
`--type=color [--default=<default>]` is preferred over `--get-color`
(but note that `--get-color` will omit the trailing newline printed by
`--type=color`).
-e:: -e::
--edit:: --edit::
Opens an editor to modify the specified config file; either Opens an editor to modify the specified config file; either
@ -299,7 +284,7 @@ Valid `<type>`'s include:
config files. config files.
--default <value>:: --default <value>::
When using `--get`, and the requested variable is not found, behave as if When using `get`, and the requested variable is not found, behave as if
<value> were the value assigned to that variable. <value> were the value assigned to that variable.
DEPRECATED MODES DEPRECATED MODES
@ -308,15 +293,33 @@ DEPRECATED MODES
The following modes have been deprecated in favor of subcommands. It is The following modes have been deprecated in favor of subcommands. It is
recommended to migrate to the new syntax. recommended to migrate to the new syntax.
'git config <name>'::
Replaced by `git config get <name>`.
-l:: -l::
--list:: --list::
Replaced by `git config list`. Replaced by `git config list`.
--get <name> [<value-pattern>]::
Replaced by `git config get [--value=<pattern>] <name>`.
--get-all <name> [<value-pattern>]::
Replaced by `git config get [--value=<pattern>] --all --show-names <name>`.
--get-regexp <name-regexp>::
Replaced by `git config get --all --show-names --regexp <name-regexp>`.
--get-urlmatch <name> <URL>::
Replaced by `git config get --all --show-names --url=<URL> <name>`.
--get-color <name> [<default>]::
Replaced by `git config get --type=color [--default=<default>] <name>`.
CONFIGURATION CONFIGURATION
------------- -------------
`pager.config` is only respected when listing configuration, i.e., when `pager.config` is only respected when listing configuration, i.e., when
using `list` or any of the `--get-*` which may return multiple results. using `list` or `get` which may return multiple results. The default is to use
The default is to use a pager. a pager.
[[FILES]] [[FILES]]
FILES FILES
@ -519,25 +522,19 @@ you have to provide a regex matching the value of exactly one line.
To query the value for a given key, do To query the value for a given key, do
------------ ------------
% git config --get core.filemode % git config get core.filemode
------------
or
------------
% git config core.filemode
------------ ------------
or, to query a multivar: or, to query a multivar:
------------ ------------
% git config --get core.gitproxy "for kernel.org$" % git config get --value="for kernel.org$" core.gitproxy
------------ ------------
If you want to know all the values for a multivar, do: If you want to know all the values for a multivar, do:
------------ ------------
% git config --get-all core.gitproxy % git config get --all --show-names core.gitproxy
------------ ------------
If you like to live dangerously, you can replace *all* core.gitproxy by a If you like to live dangerously, you can replace *all* core.gitproxy by a
@ -571,8 +568,8 @@ script:
------------ ------------
#!/bin/sh #!/bin/sh
WS=$(git config --get-color color.diff.whitespace "blue reverse") WS=$(git config get --type=color --default="blue reverse" color.diff.whitespace)
RESET=$(git config --get-color "" "reset") RESET=$(git config get --type=color --default="reset" "")
echo "${WS}your whitespace color or blue reverse${RESET}" echo "${WS}your whitespace color or blue reverse${RESET}"
------------ ------------
@ -580,11 +577,11 @@ For URLs in `https://weak.example.com`, `http.sslVerify` is set to
false, while it is set to `true` for all others: false, while it is set to `true` for all others:
------------ ------------
% git config --type=bool --get-urlmatch http.sslverify https://good.example.com % git config get --type=bool --url=https://good.example.com http.sslverify
true true
% git config --type=bool --get-urlmatch http.sslverify https://weak.example.com % git config get --type=bool --url=https://weak.example.com http.sslverify
false false
% git config --get-urlmatch http https://weak.example.com % git config get --url=https://weak.example.com http
http.cookieFile /tmp/cookie.txt http.cookieFile /tmp/cookie.txt
http.sslverify false http.sslverify false
------------ ------------

View File

@ -17,7 +17,7 @@
static const char *const builtin_config_usage[] = { static const char *const builtin_config_usage[] = {
N_("git config list [<file-option>] [<display-option>] [--includes]"), N_("git config list [<file-option>] [<display-option>] [--includes]"),
N_("git config [<options>]"), N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] <name>"),
NULL NULL
}; };
@ -26,6 +26,11 @@ static const char *const builtin_config_list_usage[] = {
NULL NULL
}; };
static const char *const builtin_config_get_usage[] = {
N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] <name>"),
NULL
};
static char *key; static char *key;
static regex_t *key_regexp; static regex_t *key_regexp;
static const char *value_pattern; static const char *value_pattern;
@ -722,6 +727,16 @@ static void handle_nul(void) {
OPT_STRING('f', "file", &given_config_source.file, N_("file"), N_("use given config file")), \ OPT_STRING('f', "file", &given_config_source.file, N_("file"), N_("use given config file")), \
OPT_STRING(0, "blob", &given_config_source.blob, N_("blob-id"), N_("read config from given blob object")) OPT_STRING(0, "blob", &given_config_source.blob, N_("blob-id"), N_("read config from given blob object"))
#define CONFIG_TYPE_OPTIONS \
OPT_GROUP(N_("Type")), \
OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type), \
OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL), \
OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT), \
OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT), \
OPT_CALLBACK_VALUE(0, "bool-or-str", &type, N_("value is --bool or string"), TYPE_BOOL_OR_STR), \
OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH), \
OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE)
#define CONFIG_DISPLAY_OPTIONS \ #define CONFIG_DISPLAY_OPTIONS \
OPT_GROUP(N_("Display options")), \ OPT_GROUP(N_("Display options")), \
OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")), \ OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")), \
@ -746,14 +761,7 @@ static struct option builtin_config_options[] = {
OPT_CMDMODE('e', "edit", &actions, N_("open an editor"), ACTION_EDIT), OPT_CMDMODE('e', "edit", &actions, N_("open an editor"), ACTION_EDIT),
OPT_CMDMODE(0, "get-color", &actions, N_("find the color configured: slot [<default>]"), ACTION_GET_COLOR), OPT_CMDMODE(0, "get-color", &actions, N_("find the color configured: slot [<default>]"), ACTION_GET_COLOR),
OPT_CMDMODE(0, "get-colorbool", &actions, N_("find the color setting: slot [<stdout-is-tty>]"), ACTION_GET_COLORBOOL), OPT_CMDMODE(0, "get-colorbool", &actions, N_("find the color setting: slot [<stdout-is-tty>]"), ACTION_GET_COLORBOOL),
OPT_GROUP(N_("Type")), CONFIG_TYPE_OPTIONS,
OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type),
OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL),
OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT),
OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT),
OPT_CALLBACK_VALUE(0, "bool-or-str", &type, N_("value is --bool or string"), TYPE_BOOL_OR_STR),
OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH),
OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
CONFIG_DISPLAY_OPTIONS, CONFIG_DISPLAY_OPTIONS,
OPT_GROUP(N_("Other")), OPT_GROUP(N_("Other")),
OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")), OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
@ -799,8 +807,51 @@ static int cmd_config_list(int argc, const char **argv, const char *prefix)
return 0; return 0;
} }
static int cmd_config_get(int argc, const char **argv, const char *prefix)
{
const char *value_pattern = NULL, *url = NULL;
int flags = 0;
struct option opts[] = {
CONFIG_LOCATION_OPTIONS,
CONFIG_TYPE_OPTIONS,
OPT_GROUP(N_("Filter options")),
OPT_BOOL(0, "all", &do_all, N_("return all values for multi-valued config options")),
OPT_BOOL(0, "regexp", &use_key_regexp, N_("interpret the name as a regular expression")),
OPT_STRING(0, "value", &value_pattern, N_("pattern"), N_("show config with values matching the pattern")),
OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE),
OPT_STRING(0, "url", &url, N_("URL"), N_("show config matching the given URL")),
CONFIG_DISPLAY_OPTIONS,
OPT_BOOL(0, "show-names", &show_keys, N_("show config keys in addition to their values")),
OPT_GROUP(N_("Other")),
OPT_BOOL(0, "includes", &respect_includes_opt, N_("respect include directives on lookup")),
OPT_STRING(0, "default", &default_value, N_("value"), N_("use default value when missing entry")),
OPT_END(),
};
argc = parse_options(argc, argv, prefix, opts, builtin_config_get_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
check_argc(argc, 1, 1);
if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern)
die(_("--fixed-value only applies with 'value-pattern'"));
if (default_value && (do_all || url))
die(_("--default= cannot be used with --all or --url="));
if (url && (do_all || use_key_regexp || value_pattern))
die(_("--url= cannot be used with --all, --regexp or --value"));
handle_config_location(prefix);
handle_nul();
setup_auto_pager("config", 1);
if (url)
return get_urlmatch(argv[0], url);
return get_value(argv[0], value_pattern, flags);
}
static struct option builtin_subcommand_options[] = { static struct option builtin_subcommand_options[] = {
OPT_SUBCOMMAND("list", &subcommand, cmd_config_list), OPT_SUBCOMMAND("list", &subcommand, cmd_config_list),
OPT_SUBCOMMAND("get", &subcommand, cmd_config_get),
OPT_END(), OPT_END(),
}; };

View File

@ -17,9 +17,15 @@ do
case "$mode" in case "$mode" in
legacy) legacy)
mode_prefix="--" mode_prefix="--"
mode_get=""
mode_get_all="--get-all"
mode_get_regexp="--get-regexp"
;; ;;
subcommands) subcommands)
mode_prefix="" mode_prefix=""
mode_get="get"
mode_get_all="get --all"
mode_get_regexp="get --regexp --all --show-names"
;; ;;
*) *)
BUG "unknown mode $mode";; BUG "unknown mode $mode";;
@ -398,7 +404,7 @@ test_expect_success 'multi-valued get-all returns all' '
wow wow
wow2 for me wow2 for me
EOF EOF
git config --get-all nextsection.nonewline >actual && git config ${mode_get_all} nextsection.nonewline >actual &&
test_cmp expect actual test_cmp expect actual
' '
@ -500,7 +506,7 @@ nextsection.nonewline wow2 for me
EOF EOF
test_expect_success '--get-regexp' ' test_expect_success '--get-regexp' '
git config --get-regexp in >output && git config ${mode_get_regexp} in >output &&
test_cmp expect output test_cmp expect output
' '
@ -510,7 +516,7 @@ nextsection.nonewline
EOF EOF
test_expect_success '--name-only --get-regexp' ' test_expect_success '--name-only --get-regexp' '
git config --name-only --get-regexp in >output && git config ${mode_get_regexp} --name-only in >output &&
test_cmp expect output test_cmp expect output
' '
@ -521,7 +527,7 @@ EOF
test_expect_success '--add' ' test_expect_success '--add' '
git config --add nextsection.nonewline "wow4 for you" && git config --add nextsection.nonewline "wow4 for you" &&
git config --get-all nextsection.nonewline > output && git config ${mode_get_all} nextsection.nonewline > output &&
test_cmp expect output test_cmp expect output
' '
@ -543,21 +549,21 @@ test_expect_success 'get variable with empty value' '
echo novalue.variable > expect echo novalue.variable > expect
test_expect_success 'get-regexp variable with no value' ' test_expect_success 'get-regexp variable with no value' '
git config --get-regexp novalue > output && git config ${mode_get_regexp} novalue > output &&
test_cmp expect output test_cmp expect output
' '
echo 'novalue.variable true' > expect echo 'novalue.variable true' > expect
test_expect_success 'get-regexp --bool variable with no value' ' test_expect_success 'get-regexp --bool variable with no value' '
git config --bool --get-regexp novalue > output && git config ${mode_get_regexp} --bool novalue > output &&
test_cmp expect output test_cmp expect output
' '
echo 'emptyvalue.variable ' > expect echo 'emptyvalue.variable ' > expect
test_expect_success 'get-regexp variable with empty value' ' test_expect_success 'get-regexp variable with empty value' '
git config --get-regexp emptyvalue > output && git config ${mode_get_regexp} emptyvalue > output &&
test_cmp expect output test_cmp expect output
' '
@ -1131,7 +1137,7 @@ test_expect_success 'quoting' '
' '
test_expect_success 'key with newline' ' test_expect_success 'key with newline' '
test_must_fail git config "key.with test_must_fail git config ${mode_get} "key.with
newline" 123' newline" 123'
test_expect_success 'value with newline' 'git config key.sub value.with\\\ test_expect_success 'value with newline' 'git config key.sub value.with\\\
@ -1185,7 +1191,7 @@ test_expect_success '--null --list' '
' '
test_expect_success '--null --get-regexp' ' test_expect_success '--null --get-regexp' '
git config --null --get-regexp "val[0-9]" >result.raw && git config ${mode_get_regexp} --null "val[0-9]" >result.raw &&
nul_to_q <result.raw >result && nul_to_q <result.raw >result &&
echo >>result && echo >>result &&
test_cmp expect result test_cmp expect result
@ -1194,21 +1200,21 @@ test_expect_success '--null --get-regexp' '
test_expect_success 'inner whitespace kept verbatim, spaces only' ' test_expect_success 'inner whitespace kept verbatim, spaces only' '
echo "foo bar" >expect && echo "foo bar" >expect &&
git config section.val "foo bar" && git config section.val "foo bar" &&
git config --get section.val >actual && git config ${mode_get} section.val >actual &&
test_cmp expect actual test_cmp expect actual
' '
test_expect_success 'inner whitespace kept verbatim, horizontal tabs only' ' test_expect_success 'inner whitespace kept verbatim, horizontal tabs only' '
echo "fooQQbar" | q_to_tab >expect && echo "fooQQbar" | q_to_tab >expect &&
git config section.val "$(cat expect)" && git config section.val "$(cat expect)" &&
git config --get section.val >actual && git config ${mode_get} section.val >actual &&
test_cmp expect actual test_cmp expect actual
' '
test_expect_success 'inner whitespace kept verbatim, horizontal tabs and spaces' ' test_expect_success 'inner whitespace kept verbatim, horizontal tabs and spaces' '
echo "foo Q bar" | q_to_tab >expect && echo "foo Q bar" | q_to_tab >expect &&
git config section.val "$(cat expect)" && git config section.val "$(cat expect)" &&
git config --get section.val >actual && git config ${mode_get} section.val >actual &&
test_cmp expect actual test_cmp expect actual
' '
@ -1283,11 +1289,11 @@ test_expect_success 'git -c can represent empty string' '
' '
test_expect_success 'key sanity-checking' ' test_expect_success 'key sanity-checking' '
test_must_fail git config foo=bar && test_must_fail git config ${mode_get} foo=bar &&
test_must_fail git config foo=.bar && test_must_fail git config ${mode_get} foo=.bar &&
test_must_fail git config foo.ba=r && test_must_fail git config ${mode_get} foo.ba=r &&
test_must_fail git config foo.1bar && test_must_fail git config ${mode_get} foo.1bar &&
test_must_fail git config foo."ba test_must_fail git config ${mode_get} foo."ba
z".bar && z".bar &&
test_must_fail git config . false && test_must_fail git config . false &&
test_must_fail git config .foo false && test_must_fail git config .foo false &&
@ -1336,7 +1342,7 @@ test_expect_success 'git -c complains about empty key and value' '
' '
test_expect_success 'multiple git -c appends config' ' test_expect_success 'multiple git -c appends config' '
test_config alias.x "!git -c x.two=2 config --get-regexp ^x\.*" && test_config alias.x "!git -c x.two=2 config ${mode_get_regexp} ^x\.*" &&
cat >expect <<-\EOF && cat >expect <<-\EOF &&
x.one 1 x.one 1
x.two 2 x.two 2
@ -1502,7 +1508,7 @@ test_expect_success 'GIT_CONFIG_PARAMETERS handles old-style entries' '
v="${SQ}key.one=foo${SQ}" && v="${SQ}key.one=foo${SQ}" &&
v="$v ${SQ}key.two=bar${SQ}" && v="$v ${SQ}key.two=bar${SQ}" &&
v="$v ${SQ}key.ambiguous=section.whatever=value${SQ}" && v="$v ${SQ}key.ambiguous=section.whatever=value${SQ}" &&
GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual && GIT_CONFIG_PARAMETERS=$v git config ${mode_get_regexp} "key.*" >actual &&
cat >expect <<-EOF && cat >expect <<-EOF &&
key.one foo key.one foo
key.two bar key.two bar
@ -1515,7 +1521,7 @@ test_expect_success 'GIT_CONFIG_PARAMETERS handles new-style entries' '
v="${SQ}key.one${SQ}=${SQ}foo${SQ}" && v="${SQ}key.one${SQ}=${SQ}foo${SQ}" &&
v="$v ${SQ}key.two${SQ}=${SQ}bar${SQ}" && v="$v ${SQ}key.two${SQ}=${SQ}bar${SQ}" &&
v="$v ${SQ}key.ambiguous=section.whatever${SQ}=${SQ}value${SQ}" && v="$v ${SQ}key.ambiguous=section.whatever${SQ}=${SQ}value${SQ}" &&
GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual && GIT_CONFIG_PARAMETERS=$v git config ${mode_get_regexp} "key.*" >actual &&
cat >expect <<-EOF && cat >expect <<-EOF &&
key.one foo key.one foo
key.two bar key.two bar
@ -1529,7 +1535,7 @@ test_expect_success 'old and new-style entries can mix' '
v="$v ${SQ}key.newone${SQ}=${SQ}newfoo${SQ}" && v="$v ${SQ}key.newone${SQ}=${SQ}newfoo${SQ}" &&
v="$v ${SQ}key.oldtwo=oldbar${SQ}" && v="$v ${SQ}key.oldtwo=oldbar${SQ}" &&
v="$v ${SQ}key.newtwo${SQ}=${SQ}newbar${SQ}" && v="$v ${SQ}key.newtwo${SQ}=${SQ}newbar${SQ}" &&
GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual && GIT_CONFIG_PARAMETERS=$v git config ${mode_get_regexp} "key.*" >actual &&
cat >expect <<-EOF && cat >expect <<-EOF &&
key.oldone oldfoo key.oldone oldfoo
key.newone newfoo key.newone newfoo
@ -1542,7 +1548,7 @@ test_expect_success 'old and new-style entries can mix' '
test_expect_success 'old and new bools with ambiguous subsection' ' test_expect_success 'old and new bools with ambiguous subsection' '
v="${SQ}key.with=equals.oldbool${SQ}" && v="${SQ}key.with=equals.oldbool${SQ}" &&
v="$v ${SQ}key.with=equals.newbool${SQ}=" && v="$v ${SQ}key.with=equals.newbool${SQ}=" &&
GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual && GIT_CONFIG_PARAMETERS=$v git config ${mode_get_regexp} "key.*" >actual &&
cat >expect <<-EOF && cat >expect <<-EOF &&
key.with equals.oldbool key.with equals.oldbool
key.with=equals.newbool key.with=equals.newbool
@ -1556,7 +1562,7 @@ test_expect_success 'detect bogus GIT_CONFIG_PARAMETERS' '
env.two two env.two two
EOF EOF
GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ} ${SQ}env.two=two${SQ}" \ GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ} ${SQ}env.two=two${SQ}" \
git config --get-regexp "env.*" >actual && git config ${mode_get_regexp} "env.*" >actual &&
test_cmp expect actual && test_cmp expect actual &&
cat >expect <<-EOF && cat >expect <<-EOF &&
@ -1564,12 +1570,12 @@ test_expect_success 'detect bogus GIT_CONFIG_PARAMETERS' '
env.two two env.two two
EOF EOF
GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ}\\$SQ$SQ$SQ ${SQ}env.two=two${SQ}" \ GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ}\\$SQ$SQ$SQ ${SQ}env.two=two${SQ}" \
git config --get-regexp "env.*" >actual && git config ${mode_get_regexp} "env.*" >actual &&
test_cmp expect actual && test_cmp expect actual &&
test_must_fail env \ test_must_fail env \
GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ}\\$SQ ${SQ}env.two=two${SQ}" \ GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ}\\$SQ ${SQ}env.two=two${SQ}" \
git config --get-regexp "env.*" git config ${mode_get_regexp} "env.*"
' '
test_expect_success 'git --config-env=key=envvar support' ' test_expect_success 'git --config-env=key=envvar support' '
@ -1617,7 +1623,7 @@ test_expect_success 'git -c and --config-env work together' '
ENVVAR=env-value git \ ENVVAR=env-value git \
-c bar.cmd=cmd-value \ -c bar.cmd=cmd-value \
--config-env=bar.env=ENVVAR \ --config-env=bar.env=ENVVAR \
config --get-regexp "^bar.*" >actual && config ${mode_get_regexp} "^bar.*" >actual &&
test_cmp expect actual test_cmp expect actual
' '
@ -1645,7 +1651,7 @@ test_expect_success 'git config handles environment config pairs' '
GIT_CONFIG_COUNT=2 \ GIT_CONFIG_COUNT=2 \
GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="foo" \ GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="foo" \
GIT_CONFIG_KEY_1="pair.two" GIT_CONFIG_VALUE_1="bar" \ GIT_CONFIG_KEY_1="pair.two" GIT_CONFIG_VALUE_1="bar" \
git config --get-regexp "pair.*" >actual && git config ${mode_get_regexp} "pair.*" >actual &&
cat >expect <<-EOF && cat >expect <<-EOF &&
pair.one foo pair.one foo
pair.two bar pair.two bar
@ -1655,7 +1661,7 @@ test_expect_success 'git config handles environment config pairs' '
test_expect_success 'git config ignores pairs without count' ' test_expect_success 'git config ignores pairs without count' '
test_must_fail env GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \ test_must_fail env GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
git config pair.one 2>error && git config ${mode_get} pair.one 2>error &&
test_must_be_empty error test_must_be_empty error
' '
@ -1663,7 +1669,7 @@ test_expect_success 'git config ignores pairs exceeding count' '
GIT_CONFIG_COUNT=1 \ GIT_CONFIG_COUNT=1 \
GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \ GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
GIT_CONFIG_KEY_1="pair.two" GIT_CONFIG_VALUE_1="value" \ GIT_CONFIG_KEY_1="pair.two" GIT_CONFIG_VALUE_1="value" \
git config --get-regexp "pair.*" >actual 2>error && git config ${mode_get_regexp} "pair.*" >actual 2>error &&
cat >expect <<-EOF && cat >expect <<-EOF &&
pair.one value pair.one value
EOF EOF
@ -1674,14 +1680,14 @@ test_expect_success 'git config ignores pairs exceeding count' '
test_expect_success 'git config ignores pairs with zero count' ' test_expect_success 'git config ignores pairs with zero count' '
test_must_fail env \ test_must_fail env \
GIT_CONFIG_COUNT=0 GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \ GIT_CONFIG_COUNT=0 GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
git config pair.one 2>error && git config ${mode_get} pair.one 2>error &&
test_must_be_empty error test_must_be_empty error
' '
test_expect_success 'git config ignores pairs with empty count' ' test_expect_success 'git config ignores pairs with empty count' '
test_must_fail env \ test_must_fail env \
GIT_CONFIG_COUNT= GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \ GIT_CONFIG_COUNT= GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
git config pair.one 2>error && git config ${mode_get} pair.one 2>error &&
test_must_be_empty error test_must_be_empty error
' '
@ -1720,7 +1726,7 @@ test_expect_success 'environment overrides config file' '
one = value one = value
EOF EOF
GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=pair.one GIT_CONFIG_VALUE_0=override \ GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=pair.one GIT_CONFIG_VALUE_0=override \
git config pair.one >actual && git config ${mode_get} pair.one >actual &&
cat >expect <<-EOF && cat >expect <<-EOF &&
override override
EOF EOF
@ -1730,7 +1736,7 @@ test_expect_success 'environment overrides config file' '
test_expect_success 'GIT_CONFIG_PARAMETERS overrides environment config' ' test_expect_success 'GIT_CONFIG_PARAMETERS overrides environment config' '
GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=pair.one GIT_CONFIG_VALUE_0=value \ GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=pair.one GIT_CONFIG_VALUE_0=value \
GIT_CONFIG_PARAMETERS="${SQ}pair.one=override${SQ}" \ GIT_CONFIG_PARAMETERS="${SQ}pair.one=override${SQ}" \
git config pair.one >actual && git config ${mode_get} pair.one >actual &&
cat >expect <<-EOF && cat >expect <<-EOF &&
override override
EOF EOF
@ -1805,20 +1811,28 @@ test_expect_success 'urlmatch' '
test_expect_code 1 git config --bool --get-urlmatch doesnt.exist https://good.example.com >actual && test_expect_code 1 git config --bool --get-urlmatch doesnt.exist https://good.example.com >actual &&
test_must_be_empty actual && test_must_be_empty actual &&
test_expect_code 1 git config get --url=https://good.example.com --bool doesnt.exist >actual &&
test_must_be_empty actual &&
echo true >expect && echo true >expect &&
git config --bool --get-urlmatch http.SSLverify https://good.example.com >actual && git config --bool --get-urlmatch http.SSLverify https://good.example.com >actual &&
test_cmp expect actual && test_cmp expect actual &&
git config get --bool --url=https://good.example.com http.SSLverify >actual &&
test_cmp expect actual &&
echo false >expect && echo false >expect &&
git config --bool --get-urlmatch http.sslverify https://weak.example.com >actual && git config --bool --get-urlmatch http.sslverify https://weak.example.com >actual &&
test_cmp expect actual && test_cmp expect actual &&
git config get --bool --url=https://weak.example.com http.sslverify >actual &&
test_cmp expect actual &&
{ {
echo http.cookiefile /tmp/cookie.txt && echo http.cookiefile /tmp/cookie.txt &&
echo http.sslverify false echo http.sslverify false
} >expect && } >expect &&
git config --get-urlmatch HTTP https://weak.example.com >actual && git config --get-urlmatch HTTP https://weak.example.com >actual &&
test_cmp expect actual &&
git config get --url=https://weak.example.com HTTP >actual &&
test_cmp expect actual test_cmp expect actual
' '
@ -1834,6 +1848,8 @@ test_expect_success 'urlmatch with --show-scope' '
local http.sslverify false local http.sslverify false
EOF EOF
git config --get-urlmatch --show-scope HTTP https://weak.example.com >actual && git config --get-urlmatch --show-scope HTTP https://weak.example.com >actual &&
test_cmp expect actual &&
git config get --url=https://weak.example.com --show-scope HTTP >actual &&
test_cmp expect actual test_cmp expect actual
' '
@ -1866,45 +1882,67 @@ test_expect_success 'urlmatch favors more specific URLs' '
echo http.cookiefile /tmp/root.txt >expect && echo http.cookiefile /tmp/root.txt >expect &&
git config --get-urlmatch HTTP https://example.com >actual && git config --get-urlmatch HTTP https://example.com >actual &&
test_cmp expect actual && test_cmp expect actual &&
git config get --url=https://example.com HTTP >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/subdirectory.txt >expect && echo http.cookiefile /tmp/subdirectory.txt >expect &&
git config --get-urlmatch HTTP https://example.com/subdirectory >actual && git config --get-urlmatch HTTP https://example.com/subdirectory >actual &&
test_cmp expect actual && test_cmp expect actual &&
git config get --url=https://example.com/subdirectory HTTP >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/subdirectory.txt >expect && echo http.cookiefile /tmp/subdirectory.txt >expect &&
git config --get-urlmatch HTTP https://example.com/subdirectory/nested >actual && git config --get-urlmatch HTTP https://example.com/subdirectory/nested >actual &&
test_cmp expect actual && test_cmp expect actual &&
git config get --url=https://example.com/subdirectory/nested HTTP >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/user.txt >expect && echo http.cookiefile /tmp/user.txt >expect &&
git config --get-urlmatch HTTP https://user@example.com/ >actual && git config --get-urlmatch HTTP https://user@example.com/ >actual &&
test_cmp expect actual && test_cmp expect actual &&
git config get --url=https://user@example.com/ HTTP >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/subdirectory.txt >expect && echo http.cookiefile /tmp/subdirectory.txt >expect &&
git config --get-urlmatch HTTP https://averylonguser@example.com/subdirectory >actual && git config --get-urlmatch HTTP https://averylonguser@example.com/subdirectory >actual &&
test_cmp expect actual && test_cmp expect actual &&
git config get --url=https://averylonguser@example.com/subdirectory HTTP >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/preceding.txt >expect && echo http.cookiefile /tmp/preceding.txt >expect &&
git config --get-urlmatch HTTP https://preceding.example.com >actual && git config --get-urlmatch HTTP https://preceding.example.com >actual &&
test_cmp expect actual && test_cmp expect actual &&
git config get --url=https://preceding.example.com HTTP >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/wildcard.txt >expect && echo http.cookiefile /tmp/wildcard.txt >expect &&
git config --get-urlmatch HTTP https://wildcard.example.com >actual && git config --get-urlmatch HTTP https://wildcard.example.com >actual &&
test_cmp expect actual && test_cmp expect actual &&
git config get --url=https://wildcard.example.com HTTP >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/sub.txt >expect && echo http.cookiefile /tmp/sub.txt >expect &&
git config --get-urlmatch HTTP https://sub.example.com/wildcardwithsubdomain >actual && git config --get-urlmatch HTTP https://sub.example.com/wildcardwithsubdomain >actual &&
test_cmp expect actual && test_cmp expect actual &&
git config get --url=https://sub.example.com/wildcardwithsubdomain HTTP >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/trailing.txt >expect && echo http.cookiefile /tmp/trailing.txt >expect &&
git config --get-urlmatch HTTP https://trailing.example.com >actual && git config --get-urlmatch HTTP https://trailing.example.com >actual &&
test_cmp expect actual && test_cmp expect actual &&
git config get --url=https://trailing.example.com HTTP >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/sub.txt >expect && echo http.cookiefile /tmp/sub.txt >expect &&
git config --get-urlmatch HTTP https://user@sub.example.com >actual && git config --get-urlmatch HTTP https://user@sub.example.com >actual &&
test_cmp expect actual && test_cmp expect actual &&
git config get --url=https://user@sub.example.com HTTP >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/multiwildcard.txt >expect && echo http.cookiefile /tmp/multiwildcard.txt >expect &&
git config --get-urlmatch HTTP https://wildcard.example.org >actual && git config --get-urlmatch HTTP https://wildcard.example.org >actual &&
test_cmp expect actual &&
git config get --url=https://wildcard.example.org HTTP >actual &&
test_cmp expect actual test_cmp expect actual
' '
@ -2027,7 +2065,7 @@ test_expect_success '--unset last key removes section (except if commented)' '
[one] [one]
EOF EOF
git config --unset two.subsection.key && git config --unset two.subsection.key &&
test "not [two subsection]" = "$(git config one.key)" && test "not [two subsection]" = "$(git config ${mode_get} one.key)" &&
test_line_count = 3 .git/config test_line_count = 3 .git/config
' '
@ -2150,7 +2188,7 @@ test_expect_success '--show-origin with --get-regexp' '
file:$HOME/.gitconfig user.global true file:$HOME/.gitconfig user.global true
file:.git/config user.local true file:.git/config user.local true
EOF EOF
git config --show-origin --get-regexp "user\.[g|l].*" >output && git config ${mode_get_regexp} --show-origin "user\.[g|l].*" >output &&
test_cmp expect output test_cmp expect output
' '
@ -2158,7 +2196,7 @@ test_expect_success '--show-origin getting a single key' '
cat >expect <<-\EOF && cat >expect <<-\EOF &&
file:.git/config local file:.git/config local
EOF EOF
git config --show-origin user.override >output && git config ${mode_get} --show-origin user.override >output &&
test_cmp expect output test_cmp expect output
' '
@ -2290,7 +2328,7 @@ test_expect_success '--show-scope getting a single value' '
cat >expect <<-\EOF && cat >expect <<-\EOF &&
local true local true
EOF EOF
git config --show-scope --get user.local >output && git config ${mode_get} --show-scope user.local >output &&
test_cmp expect output test_cmp expect output
' '
@ -2559,9 +2597,9 @@ test_expect_success 'refuse --fixed-value for incompatible actions' '
# These modes complain when --fixed-value has no value-pattern # These modes complain when --fixed-value has no value-pattern
test_must_fail git config --file=config --fixed-value dev.null bogus && test_must_fail git config --file=config --fixed-value dev.null bogus &&
test_must_fail git config --file=config --fixed-value --replace-all dev.null bogus && test_must_fail git config --file=config --fixed-value --replace-all dev.null bogus &&
test_must_fail git config --file=config --fixed-value --get dev.null && test_must_fail git config ${mode_prefix}get --file=config --fixed-value dev.null &&
test_must_fail git config --file=config --fixed-value --get-all dev.null && test_must_fail git config ${mode_get_all} --file=config --fixed-value dev.null &&
test_must_fail git config --file=config --fixed-value --get-regexp "dev.*" && test_must_fail git config ${mode_get_regexp} --file=config --fixed-value "dev.*" &&
test_must_fail git config --file=config --fixed-value --unset dev.null && test_must_fail git config --file=config --fixed-value --unset dev.null &&
test_must_fail git config --file=config --fixed-value --unset-all dev.null test_must_fail git config --file=config --fixed-value --unset-all dev.null
' '
@ -2591,12 +2629,12 @@ test_expect_success '--fixed-value uses exact string matching' '
cp initial config && cp initial config &&
test_must_fail git config --file=config --unset fixed.test "$META" && test_must_fail git config --file=config --unset fixed.test "$META" &&
git config --file=config --fixed-value --unset fixed.test "$META" && git config --file=config --fixed-value --unset fixed.test "$META" &&
test_must_fail git config --file=config fixed.test && test_must_fail git config ${mode_get} --file=config fixed.test &&
cp initial config && cp initial config &&
test_must_fail git config --file=config --unset-all fixed.test "$META" && test_must_fail git config --file=config --unset-all fixed.test "$META" &&
git config --file=config --fixed-value --unset-all fixed.test "$META" && git config --file=config --fixed-value --unset-all fixed.test "$META" &&
test_must_fail git config --file=config fixed.test && test_must_fail git config ${mode_get} --file=config fixed.test &&
cp initial config && cp initial config &&
git config --file=config --replace-all fixed.test bogus "$META" && git config --file=config --replace-all fixed.test bogus "$META" &&
@ -2623,18 +2661,27 @@ test_expect_success '--get and --get-all with --fixed-value' '
git config --file=config --add fixed.test "$META" && git config --file=config --add fixed.test "$META" &&
git config --file=config --get fixed.test bogus && git config --file=config --get fixed.test bogus &&
git config get --file=config --value=bogus fixed.test &&
test_must_fail git config --file=config --get fixed.test "$META" && test_must_fail git config --file=config --get fixed.test "$META" &&
test_must_fail git config get --file=config --value="$META" fixed.test &&
git config --file=config --get --fixed-value fixed.test "$META" && git config --file=config --get --fixed-value fixed.test "$META" &&
git config get --file=config --fixed-value --value="$META" fixed.test &&
test_must_fail git config --file=config --get --fixed-value fixed.test non-existent && test_must_fail git config --file=config --get --fixed-value fixed.test non-existent &&
git config --file=config --get-all fixed.test bogus && git config --file=config --get-all fixed.test bogus &&
git config get --all --file=config --value=bogus fixed.test &&
test_must_fail git config --file=config --get-all fixed.test "$META" && test_must_fail git config --file=config --get-all fixed.test "$META" &&
test_must_fail git config get --all --file=config --value="$META" fixed.test &&
git config --file=config --get-all --fixed-value fixed.test "$META" && git config --file=config --get-all --fixed-value fixed.test "$META" &&
git config get --all --file=config --value="$META" --fixed-value fixed.test &&
test_must_fail git config --file=config --get-all --fixed-value fixed.test non-existent && test_must_fail git config --file=config --get-all --fixed-value fixed.test non-existent &&
git config --file=config --get-regexp fixed+ bogus && git config --file=config --get-regexp fixed+ bogus &&
git config get --regexp --file=config --value=bogus fixed+ &&
test_must_fail git config --file=config --get-regexp fixed+ "$META" && test_must_fail git config --file=config --get-regexp fixed+ "$META" &&
test_must_fail git config get --regexp --file=config --value="$META" fixed+ &&
git config --file=config --get-regexp --fixed-value fixed+ "$META" && git config --file=config --get-regexp --fixed-value fixed+ "$META" &&
git config get --regexp --file=config --fixed-value --value="$META" fixed+ &&
test_must_fail git config --file=config --get-regexp --fixed-value fixed+ non-existent test_must_fail git config --file=config --get-regexp --fixed-value fixed+ non-existent
' '