diff mbox series

[v2,07/13] builtin/config: introduce "get" subcommand

Message ID 8ceced0fc58e9b4cf1c5e5b678e864f82c1b8c01.1710198711.git.ps@pks.im (mailing list archive)
State Superseded
Headers show
Series builtin/config: introduce subcommands | expand

Commit Message

Patrick Steinhardt March 11, 2024, 11:20 p.m. UTC
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>
---
 Documentation/git-config.txt |  89 +++++++++++++------------
 builtin/config.c             |  69 ++++++++++++++++---
 t/t1300-config.sh            | 125 ++++++++++++++++++++++++-----------
 3 files changed, 192 insertions(+), 91 deletions(-)

Comments

Eric Sunshine March 13, 2024, 3:11 a.m. UTC | #1
On Mon, Mar 11, 2024 at 7:20 PM Patrick Steinhardt <ps@pks.im> wrote:
> 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>
> ---
> diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
> @@ -80,6 +76,12 @@ COMMANDS
> +get::
> +       Get value for one or more config options. Values can be filtered by
> +       regexes and URLs.Returns error code 1 if the key was not found and the
> +       last value if multiple key values were found. If `--all` is set, then
> +       all values will be shown.

s/URLs.Returns/URLs. Returns/

It's not a new problem with this description (since you're mostly just
relocating existing text), but I find the discussion of what is
returned quite confusing and difficult to interpret. Breaking it down
into simpler sentences might help:

    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.

But, doing so may be outside the scope of this patch series and can be
tackled at a later date (or not at all).

> @@ -93,22 +95,16 @@ OPTIONS
> +--all::
> +       With "get", Return all values for a multi-valued key.

s/Return/return/
s/"get"/`get`/

> +---regexp::
> +       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.

s/"get"/`get`/

> @@ -286,7 +271,7 @@ Valid `<type>`'s include:
>  --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 the that variable.

Not a fault of this patch (and need not be fixed by this series): "to
the that" should be either "to the" or "to that".

> @@ -506,25 +509,25 @@ you have to provide a regex matching the value of exactly one line.
>  To query the value for a given key, do
>
>  ------------
> -% git config --get core.filemode
> +% git config get core.filemode
>  ------------
>
>  or
>
>  ------------
> -% git config core.filemode
> +% git config get core.filemode
>  ------------

Meh. We only need to retain one of these examples now, not both, right?

> diff --git a/t/t1300-config.sh b/t/t1300-config.sh
> @@ -17,9 +17,15 @@ do
>  case "$mode" in
>  legacy)
>         mode_prefix="--"
> +       mode_get=""
> +       mode_get_all="--get-all"
> +       mode_get_regexp="--get-regexp"
>         ;;
>  subcommands)
>         mode_prefix=""
> +       mode_get="get"
> +       mode_get_all="get --all"
> +       mode_get_regexp="get --regexp --all --show-names"
>         ;;
>  *)
>         echo "unknown mode $mode" >&2

The variables added by this patch to the `case` arms invalidate the
suggested simplification in my review of [6/13].
Patrick Steinhardt March 27, 2024, 8:42 a.m. UTC | #2
On Tue, Mar 12, 2024 at 11:11:07PM -0400, Eric Sunshine wrote:
> On Mon, Mar 11, 2024 at 7:20 PM Patrick Steinhardt <ps@pks.im> wrote:
> > 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>
> > ---
> > diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
> > @@ -80,6 +76,12 @@ COMMANDS
> > +get::
> > +       Get value for one or more config options. Values can be filtered by
> > +       regexes and URLs.Returns error code 1 if the key was not found and the
> > +       last value if multiple key values were found. If `--all` is set, then
> > +       all values will be shown.
> 
> s/URLs.Returns/URLs. Returns/
> 
> It's not a new problem with this description (since you're mostly just
> relocating existing text), but I find the discussion of what is
> returned quite confusing and difficult to interpret. Breaking it down
> into simpler sentences might help:
> 
>     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.
> 
> But, doing so may be outside the scope of this patch series and can be
> tackled at a later date (or not at all).

I like this description, so let's just go with it.

> > @@ -93,22 +95,16 @@ OPTIONS
> > +--all::
> > +       With "get", Return all values for a multi-valued key.
> 
> s/Return/return/
> s/"get"/`get`/
> 
> > +---regexp::
> > +       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.
> 
> s/"get"/`get`/
> 
> > @@ -286,7 +271,7 @@ Valid `<type>`'s include:
> >  --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 the that variable.
> 
> Not a fault of this patch (and need not be fixed by this series): "to
> the that" should be either "to the" or "to that".

This was fixed via 86f9ce7dd6 (docs: fix typo in git-config `--default`,
2024-03-16).

> > @@ -506,25 +509,25 @@ you have to provide a regex matching the value of exactly one line.
> >  To query the value for a given key, do
> >
> >  ------------
> > -% git config --get core.filemode
> > +% git config get core.filemode
> >  ------------
> >
> >  or
> >
> >  ------------
> > -% git config core.filemode
> > +% git config get core.filemode
> >  ------------
> 
> Meh. We only need to retain one of these examples now, not both, right?

Oh, of course.

Patrick

> > diff --git a/t/t1300-config.sh b/t/t1300-config.sh
> > @@ -17,9 +17,15 @@ do
> >  case "$mode" in
> >  legacy)
> >         mode_prefix="--"
> > +       mode_get=""
> > +       mode_get_all="--get-all"
> > +       mode_get_regexp="--get-regexp"
> >         ;;
> >  subcommands)
> >         mode_prefix=""
> > +       mode_get="get"
> > +       mode_get_all="get --all"
> > +       mode_get_regexp="get --regexp --all --show-names"
> >         ;;
> >  *)
> >         echo "unknown mode $mode" >&2
> 
> The variables added by this patch to the `case` arms invalidate the
> suggested simplification in my review of [6/13].
diff mbox series

Patch

diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
index 976ba26757..f3d5e3e613 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -10,18 +10,14 @@  SYNOPSIS
 --------
 [verse]
 '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>] [--fixed-value] [--show-origin] [--show-scope] [-z|--null] <name> [<value> [<value-pattern>]]
 'git config' [<file-option>] [--type=<type>] --add <name> <value>
 'git config' [<file-option>] [--type=<type>] [--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-all <name> [<value-pattern>]
 'git config' [<file-option>] --rename-section <old-name> <new-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>] -e | --edit
 
@@ -80,6 +76,12 @@  COMMANDS
 list::
 	List all variables set in config file, along with their values.
 
+get::
+	Get value for one or more config options. Values can be filtered by
+	regexes and URLs.Returns error code 1 if the key was not found and the
+	last value if multiple key values were found. If `--all` is set, then
+	all values will be shown.
+
 [[OPTIONS]]
 OPTIONS
 -------
@@ -93,22 +95,16 @@  OPTIONS
 	values.  This is the same as providing '^$' as the `value-pattern`
 	in `--replace-all`.
 
---get::
-	Get the value for a given key (optionally filtered by a regex
-	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::
-	Like get, but returns all values for a multi-valued key.
+--all::
+	With "get", Return all values for a multi-valued key.
 
---get-regexp::
-	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.
+---regexp::
+	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-urlmatch <name> <URL>::
+--url=<URL>::
 	When given a two-part <name> as <section>.<key>, the value for
 	<section>.<URL>.<key> whose <URL> part matches the best to the
 	given URL is returned (if no such key exists, the value for
@@ -239,7 +235,7 @@  Valid `<type>`'s include:
 
 --name-only::
 	Output only the names of config variables for `list` or
-	`--get-regexp`.
+	`get`.
 
 --show-origin::
 	Augment the output of all queried config options with the
@@ -263,17 +259,6 @@  Valid `<type>`'s include:
 	When the color setting for `name` is undefined, the command uses
 	`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::
 --edit::
 	Opens an editor to modify the specified config file; either
@@ -286,7 +271,7 @@  Valid `<type>`'s include:
 	config files.
 
 --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 the that variable.
 
 DEPRECATED MODES
@@ -295,15 +280,33 @@  DEPRECATED MODES
 The following modes have been deprecated in favor of subcommands. It is
 recommended to migrate to the new syntax.
 
+'git config <name>'::
+	Replaced by `git config get <name>`.
+
 -l::
 --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
 -------------
 `pager.config` is only respected when listing configuration, i.e., when
-using `list` or any of the `--get-*` which may return multiple results.
-The default is to use a pager.
+using `list` or `get` which may return multiple results. The default is to use
+a pager.
 
 [[FILES]]
 FILES
@@ -506,25 +509,25 @@  you have to provide a regex matching the value of exactly one line.
 To query the value for a given key, do
 
 ------------
-% git config --get core.filemode
+% git config get core.filemode
 ------------
 
 or
 
 ------------
-% git config core.filemode
+% git config get core.filemode
 ------------
 
 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:
 
 ------------
-% 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
@@ -558,8 +561,8 @@  script:
 
 ------------
 #!/bin/sh
-WS=$(git config --get-color color.diff.whitespace "blue reverse")
-RESET=$(git config --get-color "" "reset")
+WS=$(git config get --type=color --default="blue reverse" color.diff.whitespace)
+RESET=$(git config get --type=color --default="reset" "")
 echo "${WS}your whitespace color or blue reverse${RESET}"
 ------------
 
@@ -567,11 +570,11 @@  For URLs in `https://weak.example.com`, `http.sslVerify` is set to
 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
-% 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
-% git config --get-urlmatch http https://weak.example.com
+% git config get --url=https://weak.example.com http
 http.cookieFile /tmp/cookie.txt
 http.sslverify false
 ------------
diff --git a/builtin/config.c b/builtin/config.c
index ee7ac9381e..aaa8b15e86 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -17,7 +17,7 @@ 
 
 static const char *const builtin_config_usage[] = {
 	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
 };
 
@@ -26,6 +26,11 @@  static const char *const builtin_config_list_usage[] = {
 	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 regex_t *key_regexp;
 static const char *value_pattern;
@@ -721,6 +726,16 @@  static void handle_nul(void) {
 	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"))
 
+#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 \
 	OPT_GROUP(N_("Display options")), \
 	OPT_BOOL('z', "null", &end_nul, N_("terminate values with NUL byte")), \
@@ -745,14 +760,7 @@  static struct option builtin_config_options[] = {
 	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-colorbool", &actions, N_("find the color setting: slot [<stdout-is-tty>]"), ACTION_GET_COLORBOOL),
-	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),
+	CONFIG_TYPE_OPTIONS,
 	CONFIG_DISPLAY_OPTIONS,
 	OPT_GROUP(N_("Other")),
 	OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
@@ -797,8 +805,51 @@  static int cmd_config_list(int argc, const char **argv, const char *prefix)
 	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[] = {
 	OPT_SUBCOMMAND("list", &subcommand, cmd_config_list),
+	OPT_SUBCOMMAND("get", &subcommand, cmd_config_get),
 	OPT_END(),
 };
 
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 720f0ee929..7f6746936e 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -17,9 +17,15 @@  do
 case "$mode" in
 legacy)
 	mode_prefix="--"
+	mode_get=""
+	mode_get_all="--get-all"
+	mode_get_regexp="--get-regexp"
 	;;
 subcommands)
 	mode_prefix=""
+	mode_get="get"
+	mode_get_all="get --all"
+	mode_get_regexp="get --regexp --all --show-names"
 	;;
 *)
 	echo "unknown mode $mode" >&2
@@ -289,7 +295,7 @@  test_expect_success 'multi-valued get-all returns all' '
 	wow
 	wow2 for me
 	EOF
-	git config --get-all nextsection.nonewline >actual &&
+	git config ${mode_get_all} nextsection.nonewline >actual &&
 	test_cmp expect actual
 '
 
@@ -391,7 +397,7 @@  nextsection.nonewline wow2 for me
 EOF
 
 test_expect_success '--get-regexp' '
-	git config --get-regexp in >output &&
+	git config ${mode_get_regexp} in >output &&
 	test_cmp expect output
 '
 
@@ -401,7 +407,7 @@  nextsection.nonewline
 EOF
 
 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
 '
 
@@ -412,7 +418,7 @@  EOF
 
 test_expect_success '--add' '
 	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
 '
 
@@ -434,21 +440,21 @@  test_expect_success 'get variable with empty value' '
 echo novalue.variable > expect
 
 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
 '
 
 echo 'novalue.variable true' > expect
 
 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
 '
 
 echo 'emptyvalue.variable ' > expect
 
 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
 '
 
@@ -1022,7 +1028,7 @@  test_expect_success 'quoting' '
 '
 
 test_expect_success 'key with newline' '
-	test_must_fail git config "key.with
+	test_must_fail git config ${mode_get} "key.with
 newline" 123'
 
 test_expect_success 'value with newline' 'git config key.sub value.with\\\
@@ -1076,7 +1082,7 @@  test_expect_success '--null --list' '
 '
 
 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 &&
 	echo >>result &&
 	test_cmp expect result
@@ -1158,11 +1164,11 @@  test_expect_success 'git -c can represent empty string' '
 '
 
 test_expect_success 'key sanity-checking' '
-	test_must_fail git config foo=bar &&
-	test_must_fail git config foo=.bar &&
-	test_must_fail git config foo.ba=r &&
-	test_must_fail git config foo.1bar &&
-	test_must_fail git config foo."ba
+	test_must_fail git config ${mode_get} foo=bar &&
+	test_must_fail git config ${mode_get} foo=.bar &&
+	test_must_fail git config ${mode_get} foo.ba=r &&
+	test_must_fail git config ${mode_get} foo.1bar &&
+	test_must_fail git config ${mode_get} foo."ba
 				z".bar &&
 	test_must_fail git config . false &&
 	test_must_fail git config .foo false &&
@@ -1211,7 +1217,7 @@  test_expect_success 'git -c complains about empty key and value' '
 '
 
 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 &&
 	x.one 1
 	x.two 2
@@ -1377,7 +1383,7 @@  test_expect_success 'GIT_CONFIG_PARAMETERS handles old-style entries' '
 	v="${SQ}key.one=foo${SQ}" &&
 	v="$v  ${SQ}key.two=bar${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 &&
 	key.one foo
 	key.two bar
@@ -1390,7 +1396,7 @@  test_expect_success 'GIT_CONFIG_PARAMETERS handles new-style entries' '
 	v="${SQ}key.one${SQ}=${SQ}foo${SQ}" &&
 	v="$v  ${SQ}key.two${SQ}=${SQ}bar${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 &&
 	key.one foo
 	key.two bar
@@ -1404,7 +1410,7 @@  test_expect_success 'old and new-style entries can mix' '
 	v="$v ${SQ}key.newone${SQ}=${SQ}newfoo${SQ}" &&
 	v="$v ${SQ}key.oldtwo=oldbar${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 &&
 	key.oldone oldfoo
 	key.newone newfoo
@@ -1417,7 +1423,7 @@  test_expect_success 'old and new-style entries can mix' '
 test_expect_success 'old and new bools with ambiguous subsection' '
 	v="${SQ}key.with=equals.oldbool${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 &&
 	key.with equals.oldbool
 	key.with=equals.newbool
@@ -1431,7 +1437,7 @@  test_expect_success 'detect bogus GIT_CONFIG_PARAMETERS' '
 	env.two two
 	EOF
 	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 &&
 
 	cat >expect <<-EOF &&
@@ -1439,12 +1445,12 @@  test_expect_success 'detect bogus GIT_CONFIG_PARAMETERS' '
 	env.two two
 	EOF
 	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_must_fail env \
 		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' '
@@ -1492,7 +1498,7 @@  test_expect_success 'git -c and --config-env work together' '
 	ENVVAR=env-value git \
 		-c bar.cmd=cmd-value \
 		--config-env=bar.env=ENVVAR \
-		config --get-regexp "^bar.*" >actual &&
+		config ${mode_get_regexp} "^bar.*" >actual &&
 	test_cmp expect actual
 '
 
@@ -1520,7 +1526,7 @@  test_expect_success 'git config handles environment config pairs' '
 	GIT_CONFIG_COUNT=2 \
 		GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="foo" \
 		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 &&
 	pair.one foo
 	pair.two bar
@@ -1530,7 +1536,7 @@  test_expect_success 'git config handles environment config pairs' '
 
 test_expect_success 'git config ignores pairs without count' '
 	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
 '
 
@@ -1538,7 +1544,7 @@  test_expect_success 'git config ignores pairs exceeding count' '
 	GIT_CONFIG_COUNT=1 \
 		GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="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 &&
 	pair.one value
 	EOF
@@ -1549,14 +1555,14 @@  test_expect_success 'git config ignores pairs exceeding count' '
 test_expect_success 'git config ignores pairs with zero count' '
 	test_must_fail env \
 		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_expect_success 'git config ignores pairs with empty count' '
 	test_must_fail env \
 		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
 '
 
@@ -1595,7 +1601,7 @@  test_expect_success 'environment overrides config file' '
 	one = value
 	EOF
 	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 &&
 	override
 	EOF
@@ -1605,7 +1611,7 @@  test_expect_success 'environment overrides config file' '
 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_PARAMETERS="${SQ}pair.one=override${SQ}" \
-		git config pair.one >actual &&
+		git config ${mode_get} pair.one >actual &&
 	cat >expect <<-EOF &&
 	override
 	EOF
@@ -1680,20 +1686,28 @@  test_expect_success 'urlmatch' '
 
 	test_expect_code 1 git config --bool --get-urlmatch doesnt.exist https://good.example.com >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 &&
 	git config --bool --get-urlmatch http.SSLverify https://good.example.com >actual &&
 	test_cmp expect actual &&
+	git config get --bool --url=https://good.example.com http.SSLverify >actual &&
+	test_cmp expect actual &&
 
 	echo false >expect &&
 	git config --bool --get-urlmatch http.sslverify https://weak.example.com >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.sslverify false
 	} >expect &&
 	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
 '
 
@@ -1709,6 +1723,8 @@  test_expect_success 'urlmatch with --show-scope' '
 	local	http.sslverify false
 	EOF
 	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
 '
 
@@ -1741,45 +1757,67 @@  test_expect_success 'urlmatch favors more specific URLs' '
 	echo http.cookiefile /tmp/root.txt >expect &&
 	git config --get-urlmatch HTTP https://example.com >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 &&
 	git config --get-urlmatch HTTP https://example.com/subdirectory >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 &&
 	git config --get-urlmatch HTTP https://example.com/subdirectory/nested >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 &&
 	git config --get-urlmatch HTTP https://user@example.com/ >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 &&
 	git config --get-urlmatch HTTP https://averylonguser@example.com/subdirectory >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 &&
 	git config --get-urlmatch HTTP https://preceding.example.com >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 &&
 	git config --get-urlmatch HTTP https://wildcard.example.com >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 &&
 	git config --get-urlmatch HTTP https://sub.example.com/wildcardwithsubdomain >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 &&
 	git config --get-urlmatch HTTP https://trailing.example.com >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 &&
 	git config --get-urlmatch HTTP https://user@sub.example.com >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 &&
 	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
 '
 
@@ -1902,7 +1940,7 @@  test_expect_success '--unset last key removes section (except if commented)' '
 	[one]
 	EOF
 	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
 '
 
@@ -2025,7 +2063,7 @@  test_expect_success '--show-origin with --get-regexp' '
 	file:$HOME/.gitconfig	user.global true
 	file:.git/config	user.local true
 	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
 '
 
@@ -2033,7 +2071,7 @@  test_expect_success '--show-origin getting a single key' '
 	cat >expect <<-\EOF &&
 	file:.git/config	local
 	EOF
-	git config --show-origin user.override >output &&
+	git config ${mode_get} --show-origin user.override >output &&
 	test_cmp expect output
 '
 
@@ -2165,7 +2203,7 @@  test_expect_success '--show-scope getting a single value' '
 	cat >expect <<-\EOF &&
 	local	true
 	EOF
-	git config --show-scope --get user.local >output &&
+	git config ${mode_get} --show-scope user.local >output &&
 	test_cmp expect output
 '
 
@@ -2434,9 +2472,9 @@  test_expect_success 'refuse --fixed-value for incompatible actions' '
 	# 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 --replace-all dev.null bogus &&
-	test_must_fail git config --file=config --fixed-value --get dev.null &&
-	test_must_fail git config --file=config --fixed-value --get-all dev.null &&
-	test_must_fail git config --file=config --fixed-value --get-regexp "dev.*" &&
+	test_must_fail git config ${mode_prefix}get --file=config --fixed-value dev.null &&
+	test_must_fail git config ${mode_get_all} --file=config --fixed-value dev.null &&
+	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-all dev.null
 '
@@ -2466,12 +2504,12 @@  test_expect_success '--fixed-value uses exact string matching' '
 	cp initial config &&
 	test_must_fail git config --file=config --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 &&
 	test_must_fail git config --file=config --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 &&
 	git config --file=config --replace-all fixed.test bogus "$META" &&
@@ -2498,18 +2536,27 @@  test_expect_success '--get and --get-all with --fixed-value' '
 	git config --file=config --add fixed.test "$META" &&
 
 	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 get --file=config --value="$META" fixed.test &&
 	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 &&
 
 	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 get --all --file=config --value="$META" fixed.test &&
 	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 &&
 
 	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 get --regexp --file=config --value="$META" fixed+ &&
 	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
 '