* [PATCH v2 01/13] config: move show_all_config()
2026-02-13 23:55 ` [PATCH v2 00/13] " Derrick Stolee via GitGitGadget
@ 2026-02-13 23:55 ` Derrick Stolee via GitGitGadget
2026-02-13 23:55 ` [PATCH v2 02/13] config: add 'gently' parameter to format_config() Derrick Stolee via GitGitGadget
` (12 subsequent siblings)
13 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-13 23:55 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt, Derrick Stolee,
Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
In anticipation of using format_config() in this method, move
show_all_config() lower in the file without changes.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 48 ++++++++++++++++++++++++------------------------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 288ebdfdaa..237f7a934d 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -231,30 +231,6 @@ static void show_config_scope(const struct config_display_options *opts,
strbuf_addch(buf, term);
}
-static int show_all_config(const char *key_, const char *value_,
- const struct config_context *ctx,
- void *cb)
-{
- const struct config_display_options *opts = cb;
- const struct key_value_info *kvi = ctx->kvi;
-
- if (opts->show_origin || opts->show_scope) {
- struct strbuf buf = STRBUF_INIT;
- if (opts->show_scope)
- show_config_scope(opts, kvi, &buf);
- if (opts->show_origin)
- show_config_origin(opts, kvi, &buf);
- /* Use fwrite as "buf" can contain \0's if "end_null" is set. */
- fwrite(buf.buf, 1, buf.len, stdout);
- strbuf_release(&buf);
- }
- if (!opts->omit_values && value_)
- printf("%s%c%s%c", key_, opts->delim, value_, opts->term);
- else
- printf("%s%c", key_, opts->term);
- return 0;
-}
-
struct strbuf_list {
struct strbuf *items;
int nr;
@@ -332,6 +308,30 @@ static int format_config(const struct config_display_options *opts,
return 0;
}
+static int show_all_config(const char *key_, const char *value_,
+ const struct config_context *ctx,
+ void *cb)
+{
+ const struct config_display_options *opts = cb;
+ const struct key_value_info *kvi = ctx->kvi;
+
+ if (opts->show_origin || opts->show_scope) {
+ struct strbuf buf = STRBUF_INIT;
+ if (opts->show_scope)
+ show_config_scope(opts, kvi, &buf);
+ if (opts->show_origin)
+ show_config_origin(opts, kvi, &buf);
+ /* Use fwrite as "buf" can contain \0's if "end_null" is set. */
+ fwrite(buf.buf, 1, buf.len, stdout);
+ strbuf_release(&buf);
+ }
+ if (!opts->omit_values && value_)
+ printf("%s%c%s%c", key_, opts->delim, value_, opts->term);
+ else
+ printf("%s%c", key_, opts->term);
+ return 0;
+}
+
#define GET_VALUE_ALL (1 << 0)
#define GET_VALUE_KEY_REGEXP (1 << 1)
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v2 02/13] config: add 'gently' parameter to format_config()
2026-02-13 23:55 ` [PATCH v2 00/13] " Derrick Stolee via GitGitGadget
2026-02-13 23:55 ` [PATCH v2 01/13] config: move show_all_config() Derrick Stolee via GitGitGadget
@ 2026-02-13 23:55 ` Derrick Stolee via GitGitGadget
2026-02-17 9:04 ` Patrick Steinhardt
2026-02-13 23:55 ` [PATCH v2 03/13] config: make 'git config list --type=<X>' work Derrick Stolee via GitGitGadget
` (11 subsequent siblings)
13 siblings, 1 reply; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-13 23:55 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt, Derrick Stolee,
Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
This parameter is set to 0 for all current callers and is UNUSED.
However, we will start using this option in future changes and in a
critical change that requires gentle parsing (not using die()) to try
parsing all values in a list.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 237f7a934d..b4c4228311 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -242,10 +242,14 @@ struct strbuf_list {
* append it into strbuf `buf`. Returns a negative value on failure,
* 0 on success, 1 on a missing optional value (i.e., telling the
* caller to pretend that <key_,value_> did not exist).
+ *
+ * Note: 'gently' is currently ignored, but will be implemented in
+ * a future change.
*/
static int format_config(const struct config_display_options *opts,
struct strbuf *buf, const char *key_,
- const char *value_, const struct key_value_info *kvi)
+ const char *value_, const struct key_value_info *kvi,
+ int gently UNUSED)
{
if (opts->show_scope)
show_config_scope(opts, kvi, buf);
@@ -372,7 +376,7 @@ static int collect_config(const char *key_, const char *value_,
strbuf_init(&values->items[values->nr], 0);
status = format_config(data->display_opts, &values->items[values->nr++],
- key_, value_, kvi);
+ key_, value_, kvi, 0);
if (status < 0)
return status;
if (status) {
@@ -463,7 +467,7 @@ static int get_value(const struct config_location_options *opts,
strbuf_init(item, 0);
status = format_config(display_opts, item, key_,
- display_opts->default_value, &kvi);
+ display_opts->default_value, &kvi, 0);
if (status < 0)
die(_("failed to format default config value: %s"),
display_opts->default_value);
@@ -743,7 +747,7 @@ static int get_urlmatch(const struct config_location_options *opts,
status = format_config(&display_opts, &buf, item->string,
matched->value_is_null ? NULL : matched->value.buf,
- &matched->kvi);
+ &matched->kvi, 0);
if (!status)
fwrite(buf.buf, 1, buf.len, stdout);
strbuf_release(&buf);
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* Re: [PATCH v2 02/13] config: add 'gently' parameter to format_config()
2026-02-13 23:55 ` [PATCH v2 02/13] config: add 'gently' parameter to format_config() Derrick Stolee via GitGitGadget
@ 2026-02-17 9:04 ` Patrick Steinhardt
0 siblings, 0 replies; 58+ messages in thread
From: Patrick Steinhardt @ 2026-02-17 9:04 UTC (permalink / raw)
To: Derrick Stolee via GitGitGadget
Cc: git, gitster, brian m. carlson, Phillip Wood,
Kristoffer Haugsbakk, Jean-Noël Avila, Derrick Stolee
On Fri, Feb 13, 2026 at 11:55:07PM +0000, Derrick Stolee via GitGitGadget wrote:
> diff --git a/builtin/config.c b/builtin/config.c
> index 237f7a934d..b4c4228311 100644
> --- a/builtin/config.c
> +++ b/builtin/config.c
> @@ -242,10 +242,14 @@ struct strbuf_list {
> * append it into strbuf `buf`. Returns a negative value on failure,
> * 0 on success, 1 on a missing optional value (i.e., telling the
> * caller to pretend that <key_,value_> did not exist).
> + *
> + * Note: 'gently' is currently ignored, but will be implemented in
> + * a future change.
> */
> static int format_config(const struct config_display_options *opts,
> struct strbuf *buf, const char *key_,
> - const char *value_, const struct key_value_info *kvi)
> + const char *value_, const struct key_value_info *kvi,
> + int gently UNUSED)
I'd propose to either make this a bool, or turn it into an enum flag so
that it becomes easier to see at the callsite what the magic "true" or
"1" means:
enum format_config_flags {
/*
* Do not die in case the value cannot be parsed properly, but
* return an error instead.
*/
FORMAT_CONFIG_GENTLY = (1 << 0),
};
format_config(opts, buf, key, value, kv, FORMAT_CONFIG_GENTLY);
I personally prefer this option over using a bool, even though it's a
bit more verbose.
Patrick
^ permalink raw reply [flat|nested] 58+ messages in thread
* [PATCH v2 03/13] config: make 'git config list --type=<X>' work
2026-02-13 23:55 ` [PATCH v2 00/13] " Derrick Stolee via GitGitGadget
2026-02-13 23:55 ` [PATCH v2 01/13] config: move show_all_config() Derrick Stolee via GitGitGadget
2026-02-13 23:55 ` [PATCH v2 02/13] config: add 'gently' parameter to format_config() Derrick Stolee via GitGitGadget
@ 2026-02-13 23:55 ` Derrick Stolee via GitGitGadget
2026-02-17 9:04 ` Patrick Steinhardt
2026-02-13 23:55 ` [PATCH v2 04/13] config: format int64s gently Derrick Stolee via GitGitGadget
` (10 subsequent siblings)
13 siblings, 1 reply; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-13 23:55 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt, Derrick Stolee,
Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
Previously, the --type=<X> argument to 'git config list' was ignored and
did nothing. Now, we add the use of format_config() to the
show_all_config() function so each key-value pair is attempted to be
parsed. This is our first use of the 'gently' parameter with a nonzero
value.
When listing multiple values, our initial settings for the output format
is different. Add a new init helper to specify the fact that keys should
be shown and also add the default delimiters as they were unset in some
cases.
If there is an error in parsing, then the row is not output.
This is a change in behavior! We are starting to respect an option that
was previously ignored, leading to potential user confusion. This is
probably still a good option, since the --type argument did not change
behavior at all previously, so users can get the behavior they expect by
removing the --type argument or adding the --no-type argument.
t1300-config.sh is updated with the current behavior of this formatting
logic to justify the upcoming refactoring of format_config() that will
incrementally fix some of these cases to be more user-friendly.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
Documentation/git-config.adoc | 3 ++
builtin/config.c | 35 ++++++++++--------
t/t1300-config.sh | 70 ++++++++++++++++++++++++++++++++++-
3 files changed, 92 insertions(+), 16 deletions(-)
diff --git a/Documentation/git-config.adoc b/Documentation/git-config.adoc
index ac3b536a15..5300dd4c51 100644
--- a/Documentation/git-config.adoc
+++ b/Documentation/git-config.adoc
@@ -240,6 +240,9 @@ Valid `<type>`'s include:
that the given value is canonicalize-able as an ANSI color, but it is written
as-is.
+
+If the command is in `list` mode, then the `--type <type>` argument will apply
+to each listed config value. If the value does not successfully parse in that
+format, then it will be omitted from the list.
--bool::
--int::
diff --git a/builtin/config.c b/builtin/config.c
index b4c4228311..4c4c791883 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -318,21 +318,12 @@ static int show_all_config(const char *key_, const char *value_,
{
const struct config_display_options *opts = cb;
const struct key_value_info *kvi = ctx->kvi;
+ struct strbuf formatted = STRBUF_INIT;
- if (opts->show_origin || opts->show_scope) {
- struct strbuf buf = STRBUF_INIT;
- if (opts->show_scope)
- show_config_scope(opts, kvi, &buf);
- if (opts->show_origin)
- show_config_origin(opts, kvi, &buf);
- /* Use fwrite as "buf" can contain \0's if "end_null" is set. */
- fwrite(buf.buf, 1, buf.len, stdout);
- strbuf_release(&buf);
- }
- if (!opts->omit_values && value_)
- printf("%s%c%s%c", key_, opts->delim, value_, opts->term);
- else
- printf("%s%c", key_, opts->term);
+ if (format_config(opts, &formatted, key_, value_, kvi, 1) >= 0)
+ fwrite(formatted.buf, 1, formatted.len, stdout);
+
+ strbuf_release(&formatted);
return 0;
}
@@ -872,6 +863,19 @@ static void display_options_init(struct config_display_options *opts)
}
}
+static void display_options_init_list(struct config_display_options *opts)
+{
+ opts->show_keys = 1;
+
+ if (opts->end_nul) {
+ display_options_init(opts);
+ } else {
+ opts->term = '\n';
+ opts->delim = ' ';
+ opts->key_delim = '=';
+ }
+}
+
static int cmd_config_list(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
@@ -890,7 +894,7 @@ static int cmd_config_list(int argc, const char **argv, const char *prefix,
check_argc(argc, 0, 0);
location_options_init(&location_opts, prefix);
- display_options_init(&display_opts);
+ display_options_init_list(&display_opts);
setup_auto_pager("config", 1);
@@ -1321,6 +1325,7 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
if (actions == ACTION_LIST) {
check_argc(argc, 0, 0);
+ display_options_init_list(&display_opts);
if (config_with_options(show_all_config, &display_opts,
&location_opts.source, the_repository,
&location_opts.options) < 0) {
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 9850fcd5b5..362e580604 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -2459,9 +2459,13 @@ done
cat >.git/config <<-\EOF &&
[section]
-foo = true
+foo = True
number = 10
big = 1M
+path = ~/dir
+red = red
+blue = Blue
+date = Fri Jun 4 15:46:55 2010
EOF
test_expect_success 'identical modern --type specifiers are allowed' '
@@ -2503,6 +2507,70 @@ test_expect_success 'unset type specifiers may be reset to conflicting ones' '
test_cmp_config 1048576 --type=bool --no-type --type=int section.big
'
+test_expect_success 'list --type=bool shows only canonicalizable bool values' '
+ cat >expect <<-EOF &&
+ section.foo=true
+ section.number=true
+ section.big=true
+ EOF
+
+ test_must_fail git config ${mode_prefix}list --type=bool
+'
+
+test_expect_success 'list --type=path shows only canonicalizable path values' '
+ cat >expect <<-EOF &&
+ section.foo=True
+ section.number=10
+ section.big=1M
+ section.path=$HOME/dir
+ section.red=red
+ section.blue=Blue
+ section.date=Fri Jun 4 15:46:55 2010
+ EOF
+
+ git config ${mode_prefix}list --type=path >actual 2>err &&
+ test_cmp expect actual &&
+ test_must_be_empty err
+'
+
+test_expect_success 'list --type=expiry-date shows only canonicalizable dates' '
+ cat >expecterr <<-EOF &&
+ error: '\''True'\'' for '\''section.foo'\'' is not a valid timestamp
+ error: '\''~/dir'\'' for '\''section.path'\'' is not a valid timestamp
+ error: '\''red'\'' for '\''section.red'\'' is not a valid timestamp
+ error: '\''Blue'\'' for '\''section.blue'\'' is not a valid timestamp
+ EOF
+
+ git config ${mode_prefix}list --type=expiry-date >actual 2>err &&
+
+ # section.number and section.big parse as relative dates that could
+ # have clock skew in their results.
+ test_grep section.big actual &&
+ test_grep section.number actual &&
+ test_grep "section.date=$(git config --type=expiry-date section.$key)" actual &&
+ test_cmp expecterr err
+'
+
+test_expect_success 'list --type=color shows only canonicalizable color values' '
+ cat >expect <<-EOF &&
+ section.number=<>
+ section.red=<RED>
+ section.blue=<BLUE>
+ EOF
+
+ cat >expecterr <<-EOF &&
+ error: invalid color value: True
+ error: invalid color value: 1M
+ error: invalid color value: ~/dir
+ error: invalid color value: Fri Jun 4 15:46:55 2010
+ EOF
+
+ git config ${mode_prefix}list --type=color >actual.raw 2>err &&
+ test_decode_color <actual.raw >actual &&
+ test_cmp expect actual &&
+ test_cmp expecterr err
+'
+
test_expect_success '--type rejects unknown specifiers' '
test_must_fail git config --type=nonsense section.foo 2>error &&
test_grep "unrecognized --type argument" error
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* Re: [PATCH v2 03/13] config: make 'git config list --type=<X>' work
2026-02-13 23:55 ` [PATCH v2 03/13] config: make 'git config list --type=<X>' work Derrick Stolee via GitGitGadget
@ 2026-02-17 9:04 ` Patrick Steinhardt
2026-02-17 16:11 ` Junio C Hamano
0 siblings, 1 reply; 58+ messages in thread
From: Patrick Steinhardt @ 2026-02-17 9:04 UTC (permalink / raw)
To: Derrick Stolee via GitGitGadget
Cc: git, gitster, brian m. carlson, Phillip Wood,
Kristoffer Haugsbakk, Jean-Noël Avila, Derrick Stolee
On Fri, Feb 13, 2026 at 11:55:08PM +0000, Derrick Stolee via GitGitGadget wrote:
> From: Derrick Stolee <stolee@gmail.com>
>
> Previously, the --type=<X> argument to 'git config list' was ignored and
> did nothing. Now, we add the use of format_config() to the
> show_all_config() function so each key-value pair is attempted to be
> parsed. This is our first use of the 'gently' parameter with a nonzero
> value.
>
> When listing multiple values, our initial settings for the output format
> is different. Add a new init helper to specify the fact that keys should
> be shown and also add the default delimiters as they were unset in some
> cases.
>
> If there is an error in parsing, then the row is not output.
It might make sense to document the rationale behind this decision in
the commit message.
> diff --git a/builtin/config.c b/builtin/config.c
> index b4c4228311..4c4c791883 100644
> --- a/builtin/config.c
> +++ b/builtin/config.c
> @@ -318,21 +318,12 @@ static int show_all_config(const char *key_, const char *value_,
> {
> const struct config_display_options *opts = cb;
> const struct key_value_info *kvi = ctx->kvi;
> + struct strbuf formatted = STRBUF_INIT;
>
> - if (opts->show_origin || opts->show_scope) {
> - struct strbuf buf = STRBUF_INIT;
> - if (opts->show_scope)
> - show_config_scope(opts, kvi, &buf);
> - if (opts->show_origin)
> - show_config_origin(opts, kvi, &buf);
> - /* Use fwrite as "buf" can contain \0's if "end_null" is set. */
> - fwrite(buf.buf, 1, buf.len, stdout);
> - strbuf_release(&buf);
> - }
> - if (!opts->omit_values && value_)
> - printf("%s%c%s%c", key_, opts->delim, value_, opts->term);
> - else
> - printf("%s%c", key_, opts->term);
> + if (format_config(opts, &formatted, key_, value_, kvi, 1) >= 0)
> + fwrite(formatted.buf, 1, formatted.len, stdout);
We could probably use puts(3p) instead, but as we know the length of the
data ahead of time it might be more efficient to use fwrite(3p) indeed.
Ultimately I guess it doesn't matter much.
Patrick
^ permalink raw reply [flat|nested] 58+ messages in thread* Re: [PATCH v2 03/13] config: make 'git config list --type=<X>' work
2026-02-17 9:04 ` Patrick Steinhardt
@ 2026-02-17 16:11 ` Junio C Hamano
2026-02-17 16:13 ` Patrick Steinhardt
0 siblings, 1 reply; 58+ messages in thread
From: Junio C Hamano @ 2026-02-17 16:11 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: Derrick Stolee via GitGitGadget, git, brian m. carlson,
Phillip Wood, Kristoffer Haugsbakk, Jean-Noël Avila,
Derrick Stolee
Patrick Steinhardt <ps@pks.im> writes:
>> - if (!opts->omit_values && value_)
>> - printf("%s%c%s%c", key_, opts->delim, value_, opts->term);
>> - else
>> - printf("%s%c", key_, opts->term);
>> + if (format_config(opts, &formatted, key_, value_, kvi, 1) >= 0)
>> + fwrite(formatted.buf, 1, formatted.len, stdout);
>
> We could probably use puts(3p) instead, but as we know the length of the
> data ahead of time it might be more efficient to use fwrite(3p) indeed.
> Ultimately I guess it doesn't matter much.
>
> Patrick
If we are not always doing LF-delimited output, puts(3) would not
help us very much, I suspect.
^ permalink raw reply [flat|nested] 58+ messages in thread* Re: [PATCH v2 03/13] config: make 'git config list --type=<X>' work
2026-02-17 16:11 ` Junio C Hamano
@ 2026-02-17 16:13 ` Patrick Steinhardt
0 siblings, 0 replies; 58+ messages in thread
From: Patrick Steinhardt @ 2026-02-17 16:13 UTC (permalink / raw)
To: Junio C Hamano
Cc: Derrick Stolee via GitGitGadget, git, brian m. carlson,
Phillip Wood, Kristoffer Haugsbakk, Jean-Noël Avila,
Derrick Stolee
On Tue, Feb 17, 2026 at 08:11:40AM -0800, Junio C Hamano wrote:
> Patrick Steinhardt <ps@pks.im> writes:
>
> >> - if (!opts->omit_values && value_)
> >> - printf("%s%c%s%c", key_, opts->delim, value_, opts->term);
> >> - else
> >> - printf("%s%c", key_, opts->term);
> >> + if (format_config(opts, &formatted, key_, value_, kvi, 1) >= 0)
> >> + fwrite(formatted.buf, 1, formatted.len, stdout);
> >
> > We could probably use puts(3p) instead, but as we know the length of the
> > data ahead of time it might be more efficient to use fwrite(3p) indeed.
> > Ultimately I guess it doesn't matter much.
> >
> > Patrick
>
> If we are not always doing LF-delimited output, puts(3) would not
> help us very much, I suspect.
D'oh, right.
Patrick
^ permalink raw reply [flat|nested] 58+ messages in thread
* [PATCH v2 04/13] config: format int64s gently
2026-02-13 23:55 ` [PATCH v2 00/13] " Derrick Stolee via GitGitGadget
` (2 preceding siblings ...)
2026-02-13 23:55 ` [PATCH v2 03/13] config: make 'git config list --type=<X>' work Derrick Stolee via GitGitGadget
@ 2026-02-13 23:55 ` Derrick Stolee via GitGitGadget
2026-02-14 0:42 ` Junio C Hamano
2026-02-17 9:05 ` Patrick Steinhardt
2026-02-13 23:55 ` [PATCH v2 05/13] config: format bools gently Derrick Stolee via GitGitGadget
` (9 subsequent siblings)
13 siblings, 2 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-13 23:55 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt, Derrick Stolee,
Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
Move the logic for formatting int64 config values into a helper method
and use gentle parsing when needed.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 4c4c791883..d259a91d53 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -237,6 +237,25 @@ struct strbuf_list {
int alloc;
};
+static int format_config_int64(struct strbuf *buf,
+ const char *key_,
+ const char *value_,
+ const struct key_value_info *kvi,
+ int gently)
+{
+ int64_t v = 0;
+ if (gently) {
+ if (git_parse_int64(value_, &v))
+ return -1;
+ } else {
+ /* may die() */
+ v = git_config_int64(key_, value_ ? value_ : "", kvi);
+ }
+
+ strbuf_addf(buf, "%"PRId64, v);
+ return 0;
+}
+
/*
* Format the configuration key-value pair (`key_`, `value_`) and
* append it into strbuf `buf`. Returns a negative value on failure,
@@ -249,8 +268,9 @@ struct strbuf_list {
static int format_config(const struct config_display_options *opts,
struct strbuf *buf, const char *key_,
const char *value_, const struct key_value_info *kvi,
- int gently UNUSED)
+ int gently)
{
+ int res = 0;
if (opts->show_scope)
show_config_scope(opts, kvi, buf);
if (opts->show_origin)
@@ -262,8 +282,7 @@ static int format_config(const struct config_display_options *opts,
strbuf_addch(buf, opts->key_delim);
if (opts->type == TYPE_INT)
- strbuf_addf(buf, "%"PRId64,
- git_config_int64(key_, value_ ? value_ : "", kvi));
+ res = format_config_int64(buf, key_, value_, kvi, gently);
else if (opts->type == TYPE_BOOL)
strbuf_addstr(buf, git_config_bool(key_, value_) ?
"true" : "false");
@@ -309,7 +328,7 @@ static int format_config(const struct config_display_options *opts,
}
}
strbuf_addch(buf, opts->term);
- return 0;
+ return res;
}
static int show_all_config(const char *key_, const char *value_,
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* Re: [PATCH v2 04/13] config: format int64s gently
2026-02-13 23:55 ` [PATCH v2 04/13] config: format int64s gently Derrick Stolee via GitGitGadget
@ 2026-02-14 0:42 ` Junio C Hamano
2026-02-17 9:05 ` Patrick Steinhardt
1 sibling, 0 replies; 58+ messages in thread
From: Junio C Hamano @ 2026-02-14 0:42 UTC (permalink / raw)
To: Derrick Stolee via GitGitGadget
Cc: git, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt, Derrick Stolee
"Derrick Stolee via GitGitGadget" <gitgitgadget@gmail.com> writes:
> +static int format_config_int64(struct strbuf *buf,
> + const char *key_,
> + const char *value_,
> + const struct key_value_info *kvi,
> + int gently)
> +{
> + int64_t v = 0;
> + if (gently) {
> + if (git_parse_int64(value_, &v))
> + return -1;
> + } else {
> + /* may die() */
> + v = git_config_int64(key_, value_ ? value_ : "", kvi);
> + }
> +
> + strbuf_addf(buf, "%"PRId64, v);
> + return 0;
> +}
This establishes the pattern the next handful of patches follow. We
already have in parse.c helpers that we can use for the gentler
parsing, and otherwise we'd use git_config_*() that the caller of
these new helpers were using originally.
I'd have preferred to have the blank line moved to the gap between
the decl and the first statement, i.e.,
> +{
> + int64_t v = 0;
> +
> + if (gently) {
> + if (git_parse_int64(value_, &v))
> + return -1;
> + } else {
> + /* may die() */
> + v = git_config_int64(key_, value_ ? value_ : "", kvi);
> + }
> + strbuf_addf(buf, "%"PRId64, v);
> + return 0;
> +}
These "format X gently" steps look very good.
^ permalink raw reply [flat|nested] 58+ messages in thread* Re: [PATCH v2 04/13] config: format int64s gently
2026-02-13 23:55 ` [PATCH v2 04/13] config: format int64s gently Derrick Stolee via GitGitGadget
2026-02-14 0:42 ` Junio C Hamano
@ 2026-02-17 9:05 ` Patrick Steinhardt
2026-02-23 3:41 ` Derrick Stolee
1 sibling, 1 reply; 58+ messages in thread
From: Patrick Steinhardt @ 2026-02-17 9:05 UTC (permalink / raw)
To: Derrick Stolee via GitGitGadget
Cc: git, gitster, brian m. carlson, Phillip Wood,
Kristoffer Haugsbakk, Jean-Noël Avila, Derrick Stolee
On Fri, Feb 13, 2026 at 11:55:09PM +0000, Derrick Stolee via GitGitGadget wrote:
> diff --git a/builtin/config.c b/builtin/config.c
> index 4c4c791883..d259a91d53 100644
> --- a/builtin/config.c
> +++ b/builtin/config.c
> @@ -237,6 +237,25 @@ struct strbuf_list {
> int alloc;
> };
>
> +static int format_config_int64(struct strbuf *buf,
> + const char *key_,
> + const char *value_,
Why do we have the trailing underscores here?
> @@ -249,8 +268,9 @@ struct strbuf_list {
> static int format_config(const struct config_display_options *opts,
> struct strbuf *buf, const char *key_,
> const char *value_, const struct key_value_info *kvi,
> - int gently UNUSED)
> + int gently)
> {
> + int res = 0;
> if (opts->show_scope)
> show_config_scope(opts, kvi, buf);
> if (opts->show_origin)
> @@ -262,8 +282,7 @@ static int format_config(const struct config_display_options *opts,
> strbuf_addch(buf, opts->key_delim);
>
> if (opts->type == TYPE_INT)
> - strbuf_addf(buf, "%"PRId64,
> - git_config_int64(key_, value_ ? value_ : "", kvi));
> + res = format_config_int64(buf, key_, value_, kvi, gently);
> else if (opts->type == TYPE_BOOL)
> strbuf_addstr(buf, git_config_bool(key_, value_) ?
> "true" : "false");
> @@ -309,7 +328,7 @@ static int format_config(const struct config_display_options *opts,
> }
> }
> strbuf_addch(buf, opts->term);
> - return 0;
> + return res;
> }
Okay. We bubble up the return value now, but we know that the return
value will only be different in case `gently != 0`. Otherwise, any error
would cause us to die.
Patrick
^ permalink raw reply [flat|nested] 58+ messages in thread* Re: [PATCH v2 04/13] config: format int64s gently
2026-02-17 9:05 ` Patrick Steinhardt
@ 2026-02-23 3:41 ` Derrick Stolee
0 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee @ 2026-02-23 3:41 UTC (permalink / raw)
To: Patrick Steinhardt, Derrick Stolee via GitGitGadget
Cc: git, gitster, brian m. carlson, Phillip Wood,
Kristoffer Haugsbakk, Jean-Noël Avila
On 2/17/26 4:05 AM, Patrick Steinhardt wrote:
> On Fri, Feb 13, 2026 at 11:55:09PM +0000, Derrick Stolee via GitGitGadget wrote:
>> diff --git a/builtin/config.c b/builtin/config.c
>> index 4c4c791883..d259a91d53 100644
>> --- a/builtin/config.c
>> +++ b/builtin/config.c
>> @@ -237,6 +237,25 @@ struct strbuf_list {
>> int alloc;
>> };
>>
>> +static int format_config_int64(struct strbuf *buf,
>> + const char *key_,
>> + const char *value_,
>
> Why do we have the trailing underscores here?
This is all to match the existing names from format_config(). This may help to
recognize moved lines by keeping the variable names the same. Definitely not
my preference to use this name format, but I thought it fitting to avoid a
rename of all variables.
Thanks,
-Stolee
^ permalink raw reply [flat|nested] 58+ messages in thread
* [PATCH v2 05/13] config: format bools gently
2026-02-13 23:55 ` [PATCH v2 00/13] " Derrick Stolee via GitGitGadget
` (3 preceding siblings ...)
2026-02-13 23:55 ` [PATCH v2 04/13] config: format int64s gently Derrick Stolee via GitGitGadget
@ 2026-02-13 23:55 ` Derrick Stolee via GitGitGadget
2026-02-13 23:55 ` [PATCH v2 06/13] config: format bools or ints gently Derrick Stolee via GitGitGadget
` (8 subsequent siblings)
13 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-13 23:55 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt, Derrick Stolee,
Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
Move the logic for formatting bool config values into a helper method
and use gentle parsing when needed.
This makes 'git config list --type=bool' not fail when coming across a
non-boolean value. Such unparseable values are filtered out quietly.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 21 +++++++++++++++++++--
t/t1300-config.sh | 4 +++-
2 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index d259a91d53..2c169fc126 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -256,6 +256,24 @@ static int format_config_int64(struct strbuf *buf,
return 0;
}
+static int format_config_bool(struct strbuf *buf,
+ const char *key_,
+ const char *value_,
+ int gently)
+{
+ int v = 0;
+ if (gently) {
+ if ((v = git_parse_maybe_bool(value_)) < 0)
+ return -1;
+ } else {
+ /* may die() */
+ v = git_config_bool(key_, value_);
+ }
+
+ strbuf_addstr(buf, v ? "true" : "false");
+ return 0;
+}
+
/*
* Format the configuration key-value pair (`key_`, `value_`) and
* append it into strbuf `buf`. Returns a negative value on failure,
@@ -284,8 +302,7 @@ static int format_config(const struct config_display_options *opts,
if (opts->type == TYPE_INT)
res = format_config_int64(buf, key_, value_, kvi, gently);
else if (opts->type == TYPE_BOOL)
- strbuf_addstr(buf, git_config_bool(key_, value_) ?
- "true" : "false");
+ res = format_config_bool(buf, key_, value_, gently);
else if (opts->type == TYPE_BOOL_OR_INT) {
int is_bool, v;
v = git_config_bool_or_int(key_, value_, kvi,
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 362e580604..59a82b9aef 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -2514,7 +2514,9 @@ test_expect_success 'list --type=bool shows only canonicalizable bool values' '
section.big=true
EOF
- test_must_fail git config ${mode_prefix}list --type=bool
+ git config ${mode_prefix}list --type=bool >actual 2>err &&
+ test_cmp expect actual &&
+ test_must_be_empty err
'
test_expect_success 'list --type=path shows only canonicalizable path values' '
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v2 06/13] config: format bools or ints gently
2026-02-13 23:55 ` [PATCH v2 00/13] " Derrick Stolee via GitGitGadget
` (4 preceding siblings ...)
2026-02-13 23:55 ` [PATCH v2 05/13] config: format bools gently Derrick Stolee via GitGitGadget
@ 2026-02-13 23:55 ` Derrick Stolee via GitGitGadget
2026-02-17 9:05 ` Patrick Steinhardt
2026-02-13 23:55 ` [PATCH v2 07/13] config: format bools or strings in helper Derrick Stolee via GitGitGadget
` (7 subsequent siblings)
13 siblings, 1 reply; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-13 23:55 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt, Derrick Stolee,
Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
Move the logic for formatting bool-or-int config values into a helper
method and use gentle parsing when needed.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 40 +++++++++++++++++++++++++++++++---------
1 file changed, 31 insertions(+), 9 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 2c169fc126..2c93e1725b 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -274,6 +274,34 @@ static int format_config_bool(struct strbuf *buf,
return 0;
}
+static int format_config_bool_or_int(struct strbuf *buf,
+ const char *key_,
+ const char *value_,
+ const struct key_value_info *kvi,
+ int gently)
+{
+ int v, is_bool = 0;
+
+ if (gently) {
+ v = git_parse_maybe_bool_text(value_);
+
+ if (v >= 0)
+ is_bool = 1;
+ else if (git_parse_int(value_, &v))
+ return -1;
+ } else {
+ v = git_config_bool_or_int(key_, value_, kvi,
+ &is_bool);
+ }
+
+ if (is_bool)
+ strbuf_addstr(buf, v ? "true" : "false");
+ else
+ strbuf_addf(buf, "%d", v);
+
+ return 0;
+}
+
/*
* Format the configuration key-value pair (`key_`, `value_`) and
* append it into strbuf `buf`. Returns a negative value on failure,
@@ -303,15 +331,9 @@ static int format_config(const struct config_display_options *opts,
res = format_config_int64(buf, key_, value_, kvi, gently);
else if (opts->type == TYPE_BOOL)
res = format_config_bool(buf, key_, value_, gently);
- else if (opts->type == TYPE_BOOL_OR_INT) {
- int is_bool, v;
- v = git_config_bool_or_int(key_, value_, kvi,
- &is_bool);
- if (is_bool)
- strbuf_addstr(buf, v ? "true" : "false");
- else
- strbuf_addf(buf, "%d", v);
- } else if (opts->type == TYPE_BOOL_OR_STR) {
+ else if (opts->type == TYPE_BOOL_OR_INT)
+ res = format_config_bool_or_int(buf, key_, value_, kvi, gently);
+ else if (opts->type == TYPE_BOOL_OR_STR) {
int v = git_parse_maybe_bool(value_);
if (v < 0)
strbuf_addstr(buf, value_);
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* Re: [PATCH v2 06/13] config: format bools or ints gently
2026-02-13 23:55 ` [PATCH v2 06/13] config: format bools or ints gently Derrick Stolee via GitGitGadget
@ 2026-02-17 9:05 ` Patrick Steinhardt
2026-02-23 3:25 ` Derrick Stolee
0 siblings, 1 reply; 58+ messages in thread
From: Patrick Steinhardt @ 2026-02-17 9:05 UTC (permalink / raw)
To: Derrick Stolee via GitGitGadget
Cc: git, gitster, brian m. carlson, Phillip Wood,
Kristoffer Haugsbakk, Jean-Noël Avila, Derrick Stolee
On Fri, Feb 13, 2026 at 11:55:11PM +0000, Derrick Stolee via GitGitGadget wrote:
> diff --git a/builtin/config.c b/builtin/config.c
> index 2c169fc126..2c93e1725b 100644
> --- a/builtin/config.c
> +++ b/builtin/config.c
> @@ -274,6 +274,34 @@ static int format_config_bool(struct strbuf *buf,
> return 0;
> }
>
> +static int format_config_bool_or_int(struct strbuf *buf,
> + const char *key_,
> + const char *value_,
> + const struct key_value_info *kvi,
> + int gently)
> +{
> + int v, is_bool = 0;
> +
> + if (gently) {
> + v = git_parse_maybe_bool_text(value_);
This function also returns `1` in case `!value`. Is this intended? I
guess so due to our implicit bool thingy, and `git_config_bool_or_int()`
seems to behave the same.
Patrick
^ permalink raw reply [flat|nested] 58+ messages in thread* Re: [PATCH v2 06/13] config: format bools or ints gently
2026-02-17 9:05 ` Patrick Steinhardt
@ 2026-02-23 3:25 ` Derrick Stolee
0 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee @ 2026-02-23 3:25 UTC (permalink / raw)
To: Patrick Steinhardt, Derrick Stolee via GitGitGadget
Cc: git, gitster, brian m. carlson, Phillip Wood,
Kristoffer Haugsbakk, Jean-Noël Avila
On 2/17/26 4:05 AM, Patrick Steinhardt wrote:
> On Fri, Feb 13, 2026 at 11:55:11PM +0000, Derrick Stolee via GitGitGadget wrote:
>> diff --git a/builtin/config.c b/builtin/config.c
>> index 2c169fc126..2c93e1725b 100644
>> --- a/builtin/config.c
>> +++ b/builtin/config.c
>> @@ -274,6 +274,34 @@ static int format_config_bool(struct strbuf *buf,
>> return 0;
>> }
>>
>> +static int format_config_bool_or_int(struct strbuf *buf,
>> + const char *key_,
>> + const char *value_,
>> + const struct key_value_info *kvi,
>> + int gently)
>> +{
>> + int v, is_bool = 0;
>> +
>> + if (gently) {
>> + v = git_parse_maybe_bool_text(value_);
>
> This function also returns `1` in case `!value`. Is this intended? I
> guess so due to our implicit bool thingy, and `git_config_bool_or_int()`
> seems to behave the same.
Do you mean in the case of a NULL value?
Based on the rules for iterating through config values, deep down in
get_value() the value parameter sent to the function is never NULL.
It may be an empty string, but never NULL.
Thanks,
-Stolee
^ permalink raw reply [flat|nested] 58+ messages in thread
* [PATCH v2 07/13] config: format bools or strings in helper
2026-02-13 23:55 ` [PATCH v2 00/13] " Derrick Stolee via GitGitGadget
` (5 preceding siblings ...)
2026-02-13 23:55 ` [PATCH v2 06/13] config: format bools or ints gently Derrick Stolee via GitGitGadget
@ 2026-02-13 23:55 ` Derrick Stolee via GitGitGadget
2026-02-13 23:55 ` [PATCH v2 08/13] parse: add git_parse_maybe_pathname() Derrick Stolee via GitGitGadget
` (6 subsequent siblings)
13 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-13 23:55 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt, Derrick Stolee,
Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
Move the logic for formatting bool-or-string config values into a
helper. This parsing has always been gentle, so this is not unlocking
new behavior. This extraction is only to match the formatting of the
other cases that do need a behavior change.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 2c93e1725b..0c539ff98e 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -302,6 +302,18 @@ static int format_config_bool_or_int(struct strbuf *buf,
return 0;
}
+/* This mode is always gentle. */
+static int format_config_bool_or_str(struct strbuf *buf,
+ const char *value_)
+{
+ int v = git_parse_maybe_bool(value_);
+ if (v < 0)
+ strbuf_addstr(buf, value_);
+ else
+ strbuf_addstr(buf, v ? "true" : "false");
+ return 0;
+}
+
/*
* Format the configuration key-value pair (`key_`, `value_`) and
* append it into strbuf `buf`. Returns a negative value on failure,
@@ -333,13 +345,9 @@ static int format_config(const struct config_display_options *opts,
res = format_config_bool(buf, key_, value_, gently);
else if (opts->type == TYPE_BOOL_OR_INT)
res = format_config_bool_or_int(buf, key_, value_, kvi, gently);
- else if (opts->type == TYPE_BOOL_OR_STR) {
- int v = git_parse_maybe_bool(value_);
- if (v < 0)
- strbuf_addstr(buf, value_);
- else
- strbuf_addstr(buf, v ? "true" : "false");
- } else if (opts->type == TYPE_PATH) {
+ else if (opts->type == TYPE_BOOL_OR_STR)
+ res = format_config_bool_or_str(buf, value_);
+ else if (opts->type == TYPE_PATH) {
char *v;
if (git_config_pathname(&v, key_, value_) < 0)
return -1;
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v2 08/13] parse: add git_parse_maybe_pathname()
2026-02-13 23:55 ` [PATCH v2 00/13] " Derrick Stolee via GitGitGadget
` (6 preceding siblings ...)
2026-02-13 23:55 ` [PATCH v2 07/13] config: format bools or strings in helper Derrick Stolee via GitGitGadget
@ 2026-02-13 23:55 ` Derrick Stolee via GitGitGadget
2026-02-13 23:55 ` [PATCH v2 09/13] config: format paths gently Derrick Stolee via GitGitGadget
` (5 subsequent siblings)
13 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-13 23:55 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt, Derrick Stolee,
Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
The git_config_pathname() method parses a config value as a path, but
always die()s on an error. Move this logic into a gentler parsing
algorithm that will return an error value instead of ending the process.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
config.c | 14 +-------------
parse.c | 24 ++++++++++++++++++++++++
parse.h | 2 ++
3 files changed, 27 insertions(+), 13 deletions(-)
diff --git a/config.c b/config.c
index 7f6d53b473..83257b7a97 100644
--- a/config.c
+++ b/config.c
@@ -1278,24 +1278,12 @@ int git_config_string(char **dest, const char *var, const char *value)
int git_config_pathname(char **dest, const char *var, const char *value)
{
- bool is_optional;
- char *path;
-
if (!value)
return config_error_nonbool(var);
- is_optional = skip_prefix(value, ":(optional)", &value);
- path = interpolate_path(value, 0);
- if (!path)
+ if (git_parse_maybe_pathname(value, dest) < 0)
die(_("failed to expand user dir in: '%s'"), value);
- if (is_optional && is_missing_file(path)) {
- free(path);
- *dest = NULL;
- return 0;
- }
-
- *dest = path;
return 0;
}
diff --git a/parse.c b/parse.c
index 48313571aa..3f37f0b93a 100644
--- a/parse.c
+++ b/parse.c
@@ -1,6 +1,7 @@
#include "git-compat-util.h"
#include "gettext.h"
#include "parse.h"
+#include "path.h"
static uintmax_t get_unit_factor(const char *end)
{
@@ -209,3 +210,26 @@ unsigned long git_env_ulong(const char *k, unsigned long val)
die(_("failed to parse %s"), k);
return val;
}
+
+int git_parse_maybe_pathname(const char *value, char **dest)
+{
+ bool is_optional;
+ char *path;
+
+ if (!value)
+ return -1;
+
+ is_optional = skip_prefix(value, ":(optional)", &value);
+ path = interpolate_path(value, 0);
+ if (!path)
+ return -1;
+
+ if (is_optional && is_missing_file(path)) {
+ free(path);
+ *dest = NULL;
+ return 0;
+ }
+
+ *dest = path;
+ return 0;
+}
diff --git a/parse.h b/parse.h
index ea32de9a91..4f97c3727a 100644
--- a/parse.h
+++ b/parse.h
@@ -19,4 +19,6 @@ int git_parse_maybe_bool_text(const char *value);
int git_env_bool(const char *, int);
unsigned long git_env_ulong(const char *, unsigned long);
+int git_parse_maybe_pathname(const char *value, char **dest);
+
#endif /* PARSE_H */
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v2 09/13] config: format paths gently
2026-02-13 23:55 ` [PATCH v2 00/13] " Derrick Stolee via GitGitGadget
` (7 preceding siblings ...)
2026-02-13 23:55 ` [PATCH v2 08/13] parse: add git_parse_maybe_pathname() Derrick Stolee via GitGitGadget
@ 2026-02-13 23:55 ` Derrick Stolee via GitGitGadget
2026-02-17 9:05 ` Patrick Steinhardt
2026-02-13 23:55 ` [PATCH v2 10/13] config: format expiry dates gently Derrick Stolee via GitGitGadget
` (4 subsequent siblings)
13 siblings, 1 reply; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-13 23:55 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt, Derrick Stolee,
Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
Move the logic for formatting path config values into a helper method
and use gentle parsing when needed.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 35 +++++++++++++++++++++++++----------
1 file changed, 25 insertions(+), 10 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 0c539ff98e..4664651dd2 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -314,6 +314,28 @@ static int format_config_bool_or_str(struct strbuf *buf,
return 0;
}
+static int format_config_path(struct strbuf *buf,
+ const char *key_,
+ const char *value_,
+ int gently)
+{
+ char *v;
+ if (gently) {
+ if (git_parse_maybe_pathname(value_, &v) < 0)
+ return -1;
+ } else if (git_config_pathname(&v, key_, value_) < 0) {
+ return -1;
+ }
+
+ if (v)
+ strbuf_addstr(buf, v);
+ else
+ return 1; /* :(optional)no-such-file */
+
+ free(v);
+ return 0;
+}
+
/*
* Format the configuration key-value pair (`key_`, `value_`) and
* append it into strbuf `buf`. Returns a negative value on failure,
@@ -347,16 +369,9 @@ static int format_config(const struct config_display_options *opts,
res = format_config_bool_or_int(buf, key_, value_, kvi, gently);
else if (opts->type == TYPE_BOOL_OR_STR)
res = format_config_bool_or_str(buf, value_);
- else if (opts->type == TYPE_PATH) {
- char *v;
- if (git_config_pathname(&v, key_, value_) < 0)
- return -1;
- if (v)
- strbuf_addstr(buf, v);
- else
- return 1; /* :(optional)no-such-file */
- free((char *)v);
- } else if (opts->type == TYPE_EXPIRY_DATE) {
+ else if (opts->type == TYPE_PATH)
+ res = format_config_path(buf, key_, value_, gently);
+ else if (opts->type == TYPE_EXPIRY_DATE) {
timestamp_t t;
if (git_config_expiry_date(&t, key_, value_) < 0)
return -1;
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* Re: [PATCH v2 09/13] config: format paths gently
2026-02-13 23:55 ` [PATCH v2 09/13] config: format paths gently Derrick Stolee via GitGitGadget
@ 2026-02-17 9:05 ` Patrick Steinhardt
0 siblings, 0 replies; 58+ messages in thread
From: Patrick Steinhardt @ 2026-02-17 9:05 UTC (permalink / raw)
To: Derrick Stolee via GitGitGadget
Cc: git, gitster, brian m. carlson, Phillip Wood,
Kristoffer Haugsbakk, Jean-Noël Avila, Derrick Stolee
On Fri, Feb 13, 2026 at 11:55:14PM +0000, Derrick Stolee via GitGitGadget wrote:
> diff --git a/builtin/config.c b/builtin/config.c
> index 0c539ff98e..4664651dd2 100644
> --- a/builtin/config.c
> +++ b/builtin/config.c
> @@ -314,6 +314,28 @@ static int format_config_bool_or_str(struct strbuf *buf,
> return 0;
> }
>
> +static int format_config_path(struct strbuf *buf,
> + const char *key_,
> + const char *value_,
> + int gently)
> +{
> + char *v;
> + if (gently) {
> + if (git_parse_maybe_pathname(value_, &v) < 0)
> + return -1;
> + } else if (git_config_pathname(&v, key_, value_) < 0) {
> + return -1;
> + }
> +
> + if (v)
> + strbuf_addstr(buf, v);
> + else
> + return 1; /* :(optional)no-such-file */
Okay, this is the first callsite where we return a vaule `> 0`, if I see
correctly. But in `show_all_config()` we check for `res >= 0`, and if so
we would print the configuration regardless.
But `buf` will now be an empty string. So wouldn't this cause us to
print such an empty string, too? I'm not quite sure whether this
behaviour is intentional or not, or whether I'm missing something here.
In any case, I think this should be documented in the commit message.
Patrick
^ permalink raw reply [flat|nested] 58+ messages in thread
* [PATCH v2 10/13] config: format expiry dates gently
2026-02-13 23:55 ` [PATCH v2 00/13] " Derrick Stolee via GitGitGadget
` (8 preceding siblings ...)
2026-02-13 23:55 ` [PATCH v2 09/13] config: format paths gently Derrick Stolee via GitGitGadget
@ 2026-02-13 23:55 ` Derrick Stolee via GitGitGadget
2026-02-13 23:55 ` [PATCH v2 11/13] color: add color_parse_gently() Derrick Stolee via GitGitGadget
` (3 subsequent siblings)
13 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-13 23:55 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt, Derrick Stolee,
Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
Move the logic for formatting expiry date config values into a helper
method and use gentle parsing when needed.
There is an unfortunate asymmetry in these two parsing methods, but we
need to treat a positive response from parse_expiry_date() as an error
or we will get incorrect values.
This updates the behavior of 'git config list --type=expiry-date' to be
quiet when attempting parsing on non-date values.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 27 +++++++++++++++++++++------
t/t1300-config.sh | 9 +--------
2 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 4664651dd2..71b685d943 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -3,6 +3,7 @@
#include "abspath.h"
#include "config.h"
#include "color.h"
+#include "date.h"
#include "editor.h"
#include "environment.h"
#include "gettext.h"
@@ -336,6 +337,23 @@ static int format_config_path(struct strbuf *buf,
return 0;
}
+static int format_config_expiry_date(struct strbuf *buf,
+ const char *key_,
+ const char *value_,
+ int gently)
+{
+ timestamp_t t;
+ if (gently) {
+ if (parse_expiry_date(value_, &t))
+ return -1;
+ } else if (git_config_expiry_date(&t, key_, value_) < 0) {
+ return -1;
+ }
+
+ strbuf_addf(buf, "%"PRItime, t);
+ return 0;
+}
+
/*
* Format the configuration key-value pair (`key_`, `value_`) and
* append it into strbuf `buf`. Returns a negative value on failure,
@@ -371,12 +389,9 @@ static int format_config(const struct config_display_options *opts,
res = format_config_bool_or_str(buf, value_);
else if (opts->type == TYPE_PATH)
res = format_config_path(buf, key_, value_, gently);
- else if (opts->type == TYPE_EXPIRY_DATE) {
- timestamp_t t;
- if (git_config_expiry_date(&t, key_, value_) < 0)
- return -1;
- strbuf_addf(buf, "%"PRItime, t);
- } else if (opts->type == TYPE_COLOR) {
+ else if (opts->type == TYPE_EXPIRY_DATE)
+ res = format_config_expiry_date(buf, key_, value_, gently);
+ else if (opts->type == TYPE_COLOR) {
char v[COLOR_MAXLEN];
if (git_config_color(v, key_, value_) < 0)
return -1;
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 59a82b9aef..c134d85d8a 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -2536,13 +2536,6 @@ test_expect_success 'list --type=path shows only canonicalizable path values' '
'
test_expect_success 'list --type=expiry-date shows only canonicalizable dates' '
- cat >expecterr <<-EOF &&
- error: '\''True'\'' for '\''section.foo'\'' is not a valid timestamp
- error: '\''~/dir'\'' for '\''section.path'\'' is not a valid timestamp
- error: '\''red'\'' for '\''section.red'\'' is not a valid timestamp
- error: '\''Blue'\'' for '\''section.blue'\'' is not a valid timestamp
- EOF
-
git config ${mode_prefix}list --type=expiry-date >actual 2>err &&
# section.number and section.big parse as relative dates that could
@@ -2550,7 +2543,7 @@ test_expect_success 'list --type=expiry-date shows only canonicalizable dates' '
test_grep section.big actual &&
test_grep section.number actual &&
test_grep "section.date=$(git config --type=expiry-date section.$key)" actual &&
- test_cmp expecterr err
+ test_must_be_empty err
'
test_expect_success 'list --type=color shows only canonicalizable color values' '
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v2 11/13] color: add color_parse_gently()
2026-02-13 23:55 ` [PATCH v2 00/13] " Derrick Stolee via GitGitGadget
` (9 preceding siblings ...)
2026-02-13 23:55 ` [PATCH v2 10/13] config: format expiry dates gently Derrick Stolee via GitGitGadget
@ 2026-02-13 23:55 ` Derrick Stolee via GitGitGadget
2026-02-17 9:05 ` Patrick Steinhardt
2026-02-13 23:55 ` [PATCH v2 12/13] config: format colors gently Derrick Stolee via GitGitGadget
` (2 subsequent siblings)
13 siblings, 1 reply; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-13 23:55 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt, Derrick Stolee,
Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
When parsing colors, a failed parse leads to an error message due to the
result returning error(). To allow for quiet parsing, create
color_parse_gently().
To accomplish this, convert the implementation of color_parse_mem() into
a static color_parse_mem_1() helper that adds a 'gently' parameter. The
color_parse_gently() method can then use this. Since it is a near
equivalent to color_parse(), move that method down in the file so they
can be nearby while also appearing after color_parse_mem_1().
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
color.c | 25 ++++++++++++++++++-------
color.h | 1 +
2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/color.c b/color.c
index 07ac8c9d40..ec8872d2dd 100644
--- a/color.c
+++ b/color.c
@@ -223,11 +223,6 @@ static int parse_attr(const char *name, size_t len)
return -1;
}
-int color_parse(const char *value, char *dst)
-{
- return color_parse_mem(value, strlen(value), dst);
-}
-
/*
* Write the ANSI color codes for "c" to "out"; the string should
* already have the ANSI escape code in it. "out" should have enough
@@ -264,7 +259,8 @@ static int color_empty(const struct color *c)
return c->type <= COLOR_NORMAL;
}
-int color_parse_mem(const char *value, int value_len, char *dst)
+static int color_parse_mem_1(const char *value, int value_len,
+ char *dst, int gently)
{
const char *ptr = value;
int len = value_len;
@@ -365,10 +361,25 @@ int color_parse_mem(const char *value, int value_len, char *dst)
OUT(0);
return 0;
bad:
- return error(_("invalid color value: %.*s"), value_len, value);
+ return gently ? -1 : error(_("invalid color value: %.*s"), value_len, value);
#undef OUT
}
+int color_parse_mem(const char *value, int value_len, char *dst)
+{
+ return color_parse_mem_1(value, value_len, dst, 0);
+}
+
+int color_parse(const char *value, char *dst)
+{
+ return color_parse_mem(value, strlen(value), dst);
+}
+
+int color_parse_gently(const char *value, char *dst)
+{
+ return color_parse_mem_1(value, strlen(value), dst, 1);
+}
+
enum git_colorbool git_config_colorbool(const char *var, const char *value)
{
if (value) {
diff --git a/color.h b/color.h
index 43e6c9ad09..30c783405d 100644
--- a/color.h
+++ b/color.h
@@ -118,6 +118,7 @@ bool want_color_fd(int fd, enum git_colorbool var);
* terminal.
*/
int color_parse(const char *value, char *dst);
+int color_parse_gently(const char *value, char *dst);
int color_parse_mem(const char *value, int len, char *dst);
/*
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* Re: [PATCH v2 11/13] color: add color_parse_gently()
2026-02-13 23:55 ` [PATCH v2 11/13] color: add color_parse_gently() Derrick Stolee via GitGitGadget
@ 2026-02-17 9:05 ` Patrick Steinhardt
2026-02-17 16:20 ` Junio C Hamano
0 siblings, 1 reply; 58+ messages in thread
From: Patrick Steinhardt @ 2026-02-17 9:05 UTC (permalink / raw)
To: Derrick Stolee via GitGitGadget
Cc: git, gitster, brian m. carlson, Phillip Wood,
Kristoffer Haugsbakk, Jean-Noël Avila, Derrick Stolee
On Fri, Feb 13, 2026 at 11:55:16PM +0000, Derrick Stolee via GitGitGadget wrote:
> diff --git a/color.c b/color.c
> index 07ac8c9d40..ec8872d2dd 100644
> --- a/color.c
> +++ b/color.c
> @@ -264,7 +259,8 @@ static int color_empty(const struct color *c)
> return c->type <= COLOR_NORMAL;
> }
>
> -int color_parse_mem(const char *value, int value_len, char *dst)
> +static int color_parse_mem_1(const char *value, int value_len,
> + char *dst, int gently)
> {
> const char *ptr = value;
> int len = value_len;
> @@ -365,10 +361,25 @@ int color_parse_mem(const char *value, int value_len, char *dst)
> OUT(0);
> return 0;
> bad:
> - return error(_("invalid color value: %.*s"), value_len, value);
> + return gently ? -1 : error(_("invalid color value: %.*s"), value_len, value);
> #undef OUT
> }
As far as I can see this isn't really about whether or not the function
should be gentle. It's rather whether or not the function should print
an error message when it sees an error.
So should we rename the parameter to `quiet`?
>
> +int color_parse_mem(const char *value, int value_len, char *dst)
> +{
> + return color_parse_mem_1(value, value_len, dst, 0);
> +}
> +
> +int color_parse(const char *value, char *dst)
> +{
> + return color_parse_mem(value, strlen(value), dst);
> +}
> +
> +int color_parse_gently(const char *value, char *dst)
> +{
> + return color_parse_mem_1(value, strlen(value), dst, 1);
> +}
And if so, this should probably be called `color_parse_quiet()`.
Patrick
^ permalink raw reply [flat|nested] 58+ messages in thread* Re: [PATCH v2 11/13] color: add color_parse_gently()
2026-02-17 9:05 ` Patrick Steinhardt
@ 2026-02-17 16:20 ` Junio C Hamano
2026-02-23 2:12 ` Derrick Stolee
0 siblings, 1 reply; 58+ messages in thread
From: Junio C Hamano @ 2026-02-17 16:20 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: Derrick Stolee via GitGitGadget, git, brian m. carlson,
Phillip Wood, Kristoffer Haugsbakk, Jean-Noël Avila,
Derrick Stolee
Patrick Steinhardt <ps@pks.im> writes:
> On Fri, Feb 13, 2026 at 11:55:16PM +0000, Derrick Stolee via GitGitGadget wrote:
>> diff --git a/color.c b/color.c
>> index 07ac8c9d40..ec8872d2dd 100644
>> --- a/color.c
>> +++ b/color.c
>> @@ -264,7 +259,8 @@ static int color_empty(const struct color *c)
>> return c->type <= COLOR_NORMAL;
>> }
>>
>> -int color_parse_mem(const char *value, int value_len, char *dst)
>> +static int color_parse_mem_1(const char *value, int value_len,
>> + char *dst, int gently)
>> {
>> const char *ptr = value;
>> int len = value_len;
>> @@ -365,10 +361,25 @@ int color_parse_mem(const char *value, int value_len, char *dst)
>> OUT(0);
>> return 0;
>> bad:
>> - return error(_("invalid color value: %.*s"), value_len, value);
>> + return gently ? -1 : error(_("invalid color value: %.*s"), value_len, value);
>> #undef OUT
>> }
>
> As far as I can see this isn't really about whether or not the function
> should be gentle. It's rather whether or not the function should print
> an error message when it sees an error.
Do you mean that this error() call is not die(), the flag does not
fit the usual "gently" criteria? In other words, should we make
this call die() if we call it "gently"?
>
> So should we rename the parameter to `quiet`?
>
>>
>> +int color_parse_mem(const char *value, int value_len, char *dst)
>> +{
>> + return color_parse_mem_1(value, value_len, dst, 0);
>> +}
>> +
>> +int color_parse(const char *value, char *dst)
>> +{
>> + return color_parse_mem(value, strlen(value), dst);
>> +}
>> +
>> +int color_parse_gently(const char *value, char *dst)
>> +{
>> + return color_parse_mem_1(value, strlen(value), dst, 1);
>> +}
>
> And if so, this should probably be called `color_parse_quiet()`.
>
> Patrick
^ permalink raw reply [flat|nested] 58+ messages in thread* Re: [PATCH v2 11/13] color: add color_parse_gently()
2026-02-17 16:20 ` Junio C Hamano
@ 2026-02-23 2:12 ` Derrick Stolee
2026-02-23 5:03 ` Junio C Hamano
0 siblings, 1 reply; 58+ messages in thread
From: Derrick Stolee @ 2026-02-23 2:12 UTC (permalink / raw)
To: Junio C Hamano, Patrick Steinhardt
Cc: Derrick Stolee via GitGitGadget, git, brian m. carlson,
Phillip Wood, Kristoffer Haugsbakk, Jean-Noël Avila
On 2/17/26 11:20 AM, Junio C Hamano wrote:
> Patrick Steinhardt <ps@pks.im> writes:
>
>> On Fri, Feb 13, 2026 at 11:55:16PM +0000, Derrick Stolee via GitGitGadget wrote:
>>> diff --git a/color.c b/color.c
>>> index 07ac8c9d40..ec8872d2dd 100644
>>> --- a/color.c
>>> +++ b/color.c
>>> @@ -264,7 +259,8 @@ static int color_empty(const struct color *c)
>>> return c->type <= COLOR_NORMAL;
>>> }
>>>
>>> -int color_parse_mem(const char *value, int value_len, char *dst)
>>> +static int color_parse_mem_1(const char *value, int value_len,
>>> + char *dst, int gently)
>>> {
>>> const char *ptr = value;
>>> int len = value_len;
>>> @@ -365,10 +361,25 @@ int color_parse_mem(const char *value, int value_len, char *dst)
>>> OUT(0);
>>> return 0;
>>> bad:
>>> - return error(_("invalid color value: %.*s"), value_len, value);
>>> + return gently ? -1 : error(_("invalid color value: %.*s"), value_len, value);
>>> #undef OUT
>>> }
>>
>> As far as I can see this isn't really about whether or not the function
>> should be gentle. It's rather whether or not the function should print
>> an error message when it sees an error.
>
> Do you mean that this error() call is not die(), the flag does not
> fit the usual "gently" criteria? In other words, should we make
> this call die() if we call it "gently"?
This is an interesting case where the existing color parsing logic is
not following the typical pattern that uses die() on a failed parse.
If we want to change the behavior to die() later, then that could be
considered, though I don't want to consider the ramifications right now.
I think the easiest "local" fix is to use the 'quiet' way, though it adds
some asymmetry in the config code in how it uses the 'gently' parameter.
Let me give this a try in the next version so we can see how it feels.
Thanks,
-Stolee
^ permalink raw reply [flat|nested] 58+ messages in thread* Re: [PATCH v2 11/13] color: add color_parse_gently()
2026-02-23 2:12 ` Derrick Stolee
@ 2026-02-23 5:03 ` Junio C Hamano
0 siblings, 0 replies; 58+ messages in thread
From: Junio C Hamano @ 2026-02-23 5:03 UTC (permalink / raw)
To: Derrick Stolee
Cc: Patrick Steinhardt, Derrick Stolee via GitGitGadget, git,
brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila
Derrick Stolee <stolee@gmail.com> writes:
>> Do you mean that this error() call is not die(), the flag does not
>> fit the usual "gently" criteria? In other words, should we make
>> this call die() if we call it "gently"?
>
> This is an interesting case where the existing color parsing logic is
> not following the typical pattern that uses die() on a failed parse.
I see. I personally would view that an existing bug worth fixing,
but I ...
> If we want to change the behavior to die() later, then that could be
> considered, though I don't want to consider the ramifications right now.
... agree with you that it should be fixed outside the scope of this
topic.
> I think the easiest "local" fix is to use the 'quiet' way, though it adds
> some asymmetry in the config code in how it uses the 'gently' parameter.
Or, just add comments to the function that takes gently but does not
die() to warn those who would add new callers. They can pass
gently=1 if they want to handle the errors themselves and keep it
that way. If they want the function to die, well they have to wait
until the function is fixed to behave like everybody else.
^ permalink raw reply [flat|nested] 58+ messages in thread
* [PATCH v2 12/13] config: format colors gently
2026-02-13 23:55 ` [PATCH v2 00/13] " Derrick Stolee via GitGitGadget
` (10 preceding siblings ...)
2026-02-13 23:55 ` [PATCH v2 11/13] color: add color_parse_gently() Derrick Stolee via GitGitGadget
@ 2026-02-13 23:55 ` Derrick Stolee via GitGitGadget
2026-02-13 23:55 ` [PATCH v2 13/13] config: restructure format_config() Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 00/13] Make 'git config list --type=' parse and filter types Derrick Stolee via GitGitGadget
13 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-13 23:55 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt, Derrick Stolee,
Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
Move the logic for formatting color config value into a helper method
and use gentle parsing when needed.
This removes error messages when parsing a list of config values that do
not match color formats.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 27 +++++++++++++++++++++------
t/t1300-config.sh | 9 +--------
2 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 71b685d943..e8c02e5f21 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -354,6 +354,24 @@ static int format_config_expiry_date(struct strbuf *buf,
return 0;
}
+static int format_config_color(struct strbuf *buf,
+ const char *key_,
+ const char *value_,
+ int gently)
+{
+ char v[COLOR_MAXLEN];
+
+ if (gently) {
+ if (color_parse_gently(value_, v) < 0)
+ return -1;
+ } else if (git_config_color(v, key_, value_) < 0) {
+ return -1;
+ }
+
+ strbuf_addstr(buf, v);
+ return 0;
+}
+
/*
* Format the configuration key-value pair (`key_`, `value_`) and
* append it into strbuf `buf`. Returns a negative value on failure,
@@ -391,12 +409,9 @@ static int format_config(const struct config_display_options *opts,
res = format_config_path(buf, key_, value_, gently);
else if (opts->type == TYPE_EXPIRY_DATE)
res = format_config_expiry_date(buf, key_, value_, gently);
- else if (opts->type == TYPE_COLOR) {
- char v[COLOR_MAXLEN];
- if (git_config_color(v, key_, value_) < 0)
- return -1;
- strbuf_addstr(buf, v);
- } else if (value_) {
+ else if (opts->type == TYPE_COLOR)
+ res = format_config_color(buf, key_, value_, gently);
+ else if (value_) {
strbuf_addstr(buf, value_);
} else {
/* Just show the key name; back out delimiter */
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index c134d85d8a..79b2ee203c 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -2553,17 +2553,10 @@ test_expect_success 'list --type=color shows only canonicalizable color values'
section.blue=<BLUE>
EOF
- cat >expecterr <<-EOF &&
- error: invalid color value: True
- error: invalid color value: 1M
- error: invalid color value: ~/dir
- error: invalid color value: Fri Jun 4 15:46:55 2010
- EOF
-
git config ${mode_prefix}list --type=color >actual.raw 2>err &&
test_decode_color <actual.raw >actual &&
test_cmp expect actual &&
- test_cmp expecterr err
+ test_must_be_empty err
'
test_expect_success '--type rejects unknown specifiers' '
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v2 13/13] config: restructure format_config()
2026-02-13 23:55 ` [PATCH v2 00/13] " Derrick Stolee via GitGitGadget
` (11 preceding siblings ...)
2026-02-13 23:55 ` [PATCH v2 12/13] config: format colors gently Derrick Stolee via GitGitGadget
@ 2026-02-13 23:55 ` Derrick Stolee via GitGitGadget
2026-02-17 9:05 ` Patrick Steinhardt
2026-02-23 12:26 ` [PATCH v3 00/13] Make 'git config list --type=' parse and filter types Derrick Stolee via GitGitGadget
13 siblings, 1 reply; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-13 23:55 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt, Derrick Stolee,
Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
The recent changes have replaced the bodies of most if/else-if cases
with simple helper method calls. This makes it easy to adapt the
structure into a clearer switch statement, leaving a simple if/else in
the default case.
Make things a little simpler to read by reducing the nesting depth via a
new goto statement when we want to skip values.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 59 ++++++++++++++++++++++++++++++++----------------
1 file changed, 40 insertions(+), 19 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index e8c02e5f21..1de3ce0eaa 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -393,25 +393,44 @@ static int format_config(const struct config_display_options *opts,
show_config_origin(opts, kvi, buf);
if (opts->show_keys)
strbuf_addstr(buf, key_);
- if (!opts->omit_values) {
- if (opts->show_keys)
- strbuf_addch(buf, opts->key_delim);
-
- if (opts->type == TYPE_INT)
- res = format_config_int64(buf, key_, value_, kvi, gently);
- else if (opts->type == TYPE_BOOL)
- res = format_config_bool(buf, key_, value_, gently);
- else if (opts->type == TYPE_BOOL_OR_INT)
- res = format_config_bool_or_int(buf, key_, value_, kvi, gently);
- else if (opts->type == TYPE_BOOL_OR_STR)
- res = format_config_bool_or_str(buf, value_);
- else if (opts->type == TYPE_PATH)
- res = format_config_path(buf, key_, value_, gently);
- else if (opts->type == TYPE_EXPIRY_DATE)
- res = format_config_expiry_date(buf, key_, value_, gently);
- else if (opts->type == TYPE_COLOR)
- res = format_config_color(buf, key_, value_, gently);
- else if (value_) {
+
+ if (opts->omit_values)
+ goto terminator;
+
+ if (opts->show_keys)
+ strbuf_addch(buf, opts->key_delim);
+
+ switch (opts->type) {
+ case TYPE_INT:
+ res = format_config_int64(buf, key_, value_, kvi, gently);
+ break;
+
+ case TYPE_BOOL:
+ res = format_config_bool(buf, key_, value_, gently);
+ break;
+
+ case TYPE_BOOL_OR_INT:
+ res = format_config_bool_or_int(buf, key_, value_, kvi, gently);
+ break;
+
+ case TYPE_BOOL_OR_STR:
+ res = format_config_bool_or_str(buf, value_);
+ break;
+
+ case TYPE_PATH:
+ res = format_config_path(buf, key_, value_, gently);
+ break;
+
+ case TYPE_EXPIRY_DATE:
+ res = format_config_expiry_date(buf, key_, value_, gently);
+ break;
+
+ case TYPE_COLOR:
+ res = format_config_color(buf, key_, value_, gently);
+ break;
+
+ default:
+ if (value_) {
strbuf_addstr(buf, value_);
} else {
/* Just show the key name; back out delimiter */
@@ -419,6 +438,8 @@ static int format_config(const struct config_display_options *opts,
strbuf_setlen(buf, buf->len - 1);
}
}
+
+terminator:
strbuf_addch(buf, opts->term);
return res;
}
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* Re: [PATCH v2 13/13] config: restructure format_config()
2026-02-13 23:55 ` [PATCH v2 13/13] config: restructure format_config() Derrick Stolee via GitGitGadget
@ 2026-02-17 9:05 ` Patrick Steinhardt
0 siblings, 0 replies; 58+ messages in thread
From: Patrick Steinhardt @ 2026-02-17 9:05 UTC (permalink / raw)
To: Derrick Stolee via GitGitGadget
Cc: git, gitster, brian m. carlson, Phillip Wood,
Kristoffer Haugsbakk, Jean-Noël Avila, Derrick Stolee
On Fri, Feb 13, 2026 at 11:55:18PM +0000, Derrick Stolee via GitGitGadget wrote:
> diff --git a/builtin/config.c b/builtin/config.c
> index e8c02e5f21..1de3ce0eaa 100644
> --- a/builtin/config.c
> +++ b/builtin/config.c
> @@ -393,25 +393,44 @@ static int format_config(const struct config_display_options *opts,
> show_config_origin(opts, kvi, buf);
> if (opts->show_keys)
> strbuf_addstr(buf, key_);
> - if (!opts->omit_values) {
> - if (opts->show_keys)
> - strbuf_addch(buf, opts->key_delim);
> -
> - if (opts->type == TYPE_INT)
> - res = format_config_int64(buf, key_, value_, kvi, gently);
> - else if (opts->type == TYPE_BOOL)
> - res = format_config_bool(buf, key_, value_, gently);
> - else if (opts->type == TYPE_BOOL_OR_INT)
> - res = format_config_bool_or_int(buf, key_, value_, kvi, gently);
> - else if (opts->type == TYPE_BOOL_OR_STR)
> - res = format_config_bool_or_str(buf, value_);
> - else if (opts->type == TYPE_PATH)
> - res = format_config_path(buf, key_, value_, gently);
> - else if (opts->type == TYPE_EXPIRY_DATE)
> - res = format_config_expiry_date(buf, key_, value_, gently);
> - else if (opts->type == TYPE_COLOR)
> - res = format_config_color(buf, key_, value_, gently);
> - else if (value_) {
> +
> + if (opts->omit_values)
> + goto terminator;
> +
> + if (opts->show_keys)
> + strbuf_addch(buf, opts->key_delim);
> +
> + switch (opts->type) {
I very much prefer this layout. Switches are more verbose, but if you
ask me they are easier to parse.
> + case TYPE_INT:
> + res = format_config_int64(buf, key_, value_, kvi, gently);
> + break;
> +
That being said, I'm not a huge fan of the empty newlines here. But feel
free to ignore.
> + case TYPE_BOOL:
> + res = format_config_bool(buf, key_, value_, gently);
> + break;
> +
> + case TYPE_BOOL_OR_INT:
> + res = format_config_bool_or_int(buf, key_, value_, kvi, gently);
> + break;
> +
> + case TYPE_BOOL_OR_STR:
> + res = format_config_bool_or_str(buf, value_);
> + break;
> +
> + case TYPE_PATH:
> + res = format_config_path(buf, key_, value_, gently);
> + break;
> +
> + case TYPE_EXPIRY_DATE:
> + res = format_config_expiry_date(buf, key_, value_, gently);
> + break;
> +
> + case TYPE_COLOR:
> + res = format_config_color(buf, key_, value_, gently);
> + break;
> +
> + default:
Should we maybe handle all valid types explicitly and have the `default`
case `BUG()` instead?
Patrick
^ permalink raw reply [flat|nested] 58+ messages in thread
* [PATCH v3 00/13] Make 'git config list --type=' parse and filter types
2026-02-13 23:55 ` [PATCH v2 00/13] " Derrick Stolee via GitGitGadget
` (12 preceding siblings ...)
2026-02-13 23:55 ` [PATCH v2 13/13] config: restructure format_config() Derrick Stolee via GitGitGadget
@ 2026-02-23 12:26 ` Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 01/13] config: move show_all_config() Derrick Stolee via GitGitGadget
` (12 more replies)
13 siblings, 13 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-23 12:26 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt,
Derrick Stolee via GitGitGadget, Derrick Stolee
I started down this road based on feedback on my 'git config-batch' RFC [1].
[1]
https://lore.kernel.org/git/pull.2033.git.1770214803.gitgitgadget@gmail.com/
I had described my intention to use 'git config-batch' as a single process
to load multiple config values one-by-one. Brian mentioned that 'git config
list -z' would probably suffice, so I started experimenting in that
direction [2].
[2]
https://github.com/git-ecosystem/git-credential-manager/compare/main...derrickstolee:config-list
However, I ran into a problem: the most critical performance bottleneck is
related to path-formatted config values that are queried with 'git config
get --type=path -z'. It wasn't hard to update things to lazily load the full
list of config values by type [3], but I then noticed a big problem!
[3]
https://github.com/git-ecosystem/git-credential-manager/commit/d403c8e24ce6f37da920cce23842dd5a6cf6481d
Problem: 'git config list' doesn't respect --type=<X>!
This boils down to the fact that the iterator function show_all_config()
doesn't call format_config(), which includes the type-parsing code.
This wasn't super trivial to update:
1. format_config() uses git_config_parse_*() methods, which die() on a bad
parse.
2. The path parsing code didn't have a gentle version.
3. The two paths ('git config list' and 'git config --list') needed to
standardize their display options to work with format_config().
4. Finally, we need to filter out key-value pairs that don't match the
given type.
Updates in v2
=============
Based on the positive feedback in round one, this is no longer an RFC.
* format_config() now uses a 'gently' parameter instead of 'die_on_parse'
(flipped).
* format_config() is more carefully updated with helper methods and a
global refactor.
* New gentle parsing code is introduced right before the format_config()
helper is created to use it.
* I squashed the change that updates the display_opts initial state into
the patch that uses format_config() for the 'list' command. The initial
state change on its own leads to test failures, so I am making a slightly
bigger patch to keep things passing tests at every change.
* More tests for 'git config list --type=<X>' are added.
* I rearranged things so the 'git config list --type' integration follows
the format_config() update immediately. The tests at that time show what
such a trivial implementation would do, including failing on bool parsing
and having several error messages for color and expiry-date parsing. The
tests modify as these issues are fixed with gentle parsers.
* I have a prototype implementation of GCM using this option in [4] and it
gets the performance improvements I was hoping for. It requires polish
and a compatibility check that uses the Git version to guarantee that
this --type behavior change is recognized.
[4] https://github.com/git-ecosystem/git-credential-manager/pull/2268
Updates in V3
=============
* Expanded the commit message of patch 3 to include reasoning for the
filter.
* Expanded the commit message of patch 3 to specify that tests are added
demonstrating problematic behavior before they are fixed in later
patches.
* New test cases are added for ':(optional)' macros and int parsing.
* The uses of git_parse_int64() and git_parse_int() were incorrect. These
are fixed after being revealed by new tests.
* The git_parse_maybe_pathname() was removed after realizing it did not
contribute to a behavior change. Path parsing was already gentle, it just
needed assistance with ':(optional)' macros for nonexistent paths.
* A distinction is made between parsing 'gently' (do not die()) and
'quietly' (do not error()). Neither cause the command to fail or emit to
stderr, but the distinction is made by what the original parsing behavior
did.
* The conversion of the format_config() logic into a switch() is made more
complete by adding a BUG() statement for the default case.
* The options for the config type are now converted into an enum to make
such switch() statements easier to validate as being complete.
Thanks for any and all feedback, -Stolee
Derrick Stolee (13):
config: move show_all_config()
config: add 'gently' parameter to format_config()
config: make 'git config list --type=<X>' work
config: format int64s gently
config: format bools gently
config: format bools or ints gently
config: format bools or strings in helper
config: format paths gently
config: format expiry dates quietly
color: add color_parse_quietly()
config: format colors quietly
config: restructure format_config()
config: use an enum for type
Documentation/git-config.adoc | 3 +
builtin/config.c | 306 +++++++++++++++++++++++++---------
color.c | 25 ++-
color.h | 1 +
t/t1300-config.sh | 84 +++++++++-
5 files changed, 331 insertions(+), 88 deletions(-)
base-commit: 67ad42147a7acc2af6074753ebd03d904476118f
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2044%2Fderrickstolee%2Fconfig-list-type-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2044/derrickstolee/config-list-type-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/2044
Range-diff vs v2:
1: bca83d8ca8 = 1: bca83d8ca8 config: move show_all_config()
2: 93c94a1b25 = 2: 93c94a1b25 config: add 'gently' parameter to format_config()
3: 6d2a48a3b7 ! 3: 2b2a325b55 config: make 'git config list --type=<X>' work
@@ Commit message
be shown and also add the default delimiters as they were unset in some
cases.
- If there is an error in parsing, then the row is not output.
+ Our intention is that if there is an error in parsing, then the row is
+ not output. This is necessary to avoid the caller needing to build their
+ own validator to understand the difference between valid, canonicalized
+ types and other raw string values. The raw values will always be
+ available to the user if they do not specify the --type=<X> option.
+
+ The current behavior is more complicated, including error messages on
+ bad parsing or potentially complete failure of the command. We add
+ tests at this point that demonstrate the current behavior so we can
+ witness the fix in future changes that parse these values quietly and
+ gently.
This is a change in behavior! We are starting to respect an option that
was previously ignored, leading to potential user confusion. This is
@@ t/t1300-config.sh: done
+red = red
+blue = Blue
+date = Fri Jun 4 15:46:55 2010
++missing=:(optional)no-such-path
++exists=:(optional)expect
EOF
test_expect_success 'identical modern --type specifiers are allowed' '
@@ t/t1300-config.sh: test_expect_success 'unset type specifiers may be reset to co
test_cmp_config 1048576 --type=bool --no-type --type=int section.big
'
++test_expect_success 'list --type=int shows only canonicalizable int values' '
++ cat >expect <<-EOF &&
++ section.number=10
++ section.big=1048576
++ EOF
++
++ test_must_fail git config ${mode_prefix}list --type=int
++'
++
+test_expect_success 'list --type=bool shows only canonicalizable bool values' '
+ cat >expect <<-EOF &&
+ section.foo=true
@@ t/t1300-config.sh: test_expect_success 'unset type specifiers may be reset to co
+ test_must_fail git config ${mode_prefix}list --type=bool
+'
+
++test_expect_success 'list --type=bool-or-int shows only canonicalizable values' '
++ cat >expect <<-EOF &&
++ section.foo=true
++ section.number=10
++ section.big=1048576
++ EOF
++
++ test_must_fail git config ${mode_prefix}list --type=bool-or-int
++'
++
+test_expect_success 'list --type=path shows only canonicalizable path values' '
++ # TODO: handling of missing path is incorrect here.
+ cat >expect <<-EOF &&
+ section.foo=True
+ section.number=10
@@ t/t1300-config.sh: test_expect_success 'unset type specifiers may be reset to co
+ section.red=red
+ section.blue=Blue
+ section.date=Fri Jun 4 15:46:55 2010
++ section.missing=section.exists=expect
+ EOF
+
+ git config ${mode_prefix}list --type=path >actual 2>err &&
@@ t/t1300-config.sh: test_expect_success 'unset type specifiers may be reset to co
+ error: '\''~/dir'\'' for '\''section.path'\'' is not a valid timestamp
+ error: '\''red'\'' for '\''section.red'\'' is not a valid timestamp
+ error: '\''Blue'\'' for '\''section.blue'\'' is not a valid timestamp
++ error: '\'':(optional)no-such-path'\'' for '\''section.missing'\'' is not a valid timestamp
++ error: '\'':(optional)expect'\'' for '\''section.exists'\'' is not a valid timestamp
+ EOF
+
+ git config ${mode_prefix}list --type=expiry-date >actual 2>err &&
@@ t/t1300-config.sh: test_expect_success 'unset type specifiers may be reset to co
+ error: invalid color value: 1M
+ error: invalid color value: ~/dir
+ error: invalid color value: Fri Jun 4 15:46:55 2010
++ error: invalid color value: :(optional)no-such-path
++ error: invalid color value: :(optional)expect
+ EOF
+
+ git config ${mode_prefix}list --type=color >actual.raw 2>err &&
4: 2bca4d2316 ! 4: 4835ee5180 config: format int64s gently
@@ builtin/config.c: struct strbuf_list {
+{
+ int64_t v = 0;
+ if (gently) {
-+ if (git_parse_int64(value_, &v))
++ if (!git_parse_int64(value_, &v))
+ return -1;
+ } else {
+ /* may die() */
@@ builtin/config.c: static int format_config(const struct config_display_options *
}
static int show_all_config(const char *key_, const char *value_,
+
+ ## t/t1300-config.sh ##
+@@ t/t1300-config.sh: test_expect_success 'list --type=int shows only canonicalizable int values' '
+ section.big=1048576
+ EOF
+
+- test_must_fail git config ${mode_prefix}list --type=int
++ git config ${mode_prefix}list --type=int >actual 2>err &&
++ test_cmp expect actual &&
++ test_must_be_empty err
+ '
+
+ test_expect_success 'list --type=bool shows only canonicalizable bool values' '
5: f8e0b8304f ! 5: 24eb757a40 config: format bools gently
@@ t/t1300-config.sh: test_expect_success 'list --type=bool shows only canonicaliza
+ test_must_be_empty err
'
- test_expect_success 'list --type=path shows only canonicalizable path values' '
+ test_expect_success 'list --type=bool-or-int shows only canonicalizable values' '
6: 0a428d2ffe ! 6: 02849ca621 config: format bools or ints gently
@@ builtin/config.c: static int format_config_bool(struct strbuf *buf,
+
+ if (v >= 0)
+ is_bool = 1;
-+ else if (git_parse_int(value_, &v))
++ else if (!git_parse_int(value_, &v))
+ return -1;
+ } else {
+ v = git_config_bool_or_int(key_, value_, kvi,
@@ builtin/config.c: static int format_config(const struct config_display_options *
int v = git_parse_maybe_bool(value_);
if (v < 0)
strbuf_addstr(buf, value_);
+
+ ## t/t1300-config.sh ##
+@@ t/t1300-config.sh: test_expect_success 'list --type=bool-or-int shows only canonicalizable values'
+ section.big=1048576
+ EOF
+
+- test_must_fail git config ${mode_prefix}list --type=bool-or-int
++ git config ${mode_prefix}list --type=bool-or-int >actual 2>err &&
++ test_cmp expect actual &&
++ test_must_be_empty err
+ '
+
+ test_expect_success 'list --type=path shows only canonicalizable path values' '
7: 3fec3abbd6 = 7: 9f06db29b9 config: format bools or strings in helper
8: fafafc5465 < -: ---------- parse: add git_parse_maybe_pathname()
9: d1cfa0c5e1 ! 8: d198c238e9 config: format paths gently
@@ Commit message
Move the logic for formatting path config values into a helper method
and use gentle parsing when needed.
+ We need to be careful about how to handle the ':(optional)' macro, which
+ as tested in t1311-config-optional.sh must allow for ignoring a missing
+ path when other multiple values exist, but cause 'git config get' to
+ fail if it is the only possible value and thus no result is output.
+
+ In the case of our list, we need to omit those values silently. This
+ necessitates the use of the 'gently' parameter here.
+
Signed-off-by: Derrick Stolee <stolee@gmail.com>
## builtin/config.c ##
@@ builtin/config.c: static int format_config_bool_or_str(struct strbuf *buf,
+ int gently)
+{
+ char *v;
-+ if (gently) {
-+ if (git_parse_maybe_pathname(value_, &v) < 0)
-+ return -1;
-+ } else if (git_config_pathname(&v, key_, value_) < 0) {
++
++ if (git_config_pathname(&v, key_, value_) < 0)
+ return -1;
-+ }
+
+ if (v)
+ strbuf_addstr(buf, v);
+ else
-+ return 1; /* :(optional)no-such-file */
++ return gently ? -1 : 1; /* :(optional)no-such-file */
+
+ free(v);
+ return 0;
@@ builtin/config.c: static int format_config(const struct config_display_options *
timestamp_t t;
if (git_config_expiry_date(&t, key_, value_) < 0)
return -1;
+
+ ## t/t1300-config.sh ##
+@@ t/t1300-config.sh: test_expect_success 'list --type=bool-or-int shows only canonicalizable values'
+ '
+
+ test_expect_success 'list --type=path shows only canonicalizable path values' '
+- # TODO: handling of missing path is incorrect here.
+ cat >expect <<-EOF &&
+ section.foo=True
+ section.number=10
+@@ t/t1300-config.sh: test_expect_success 'list --type=path shows only canonicalizable path values' '
+ section.red=red
+ section.blue=Blue
+ section.date=Fri Jun 4 15:46:55 2010
+- section.missing=section.exists=expect
++ section.exists=expect
+ EOF
+
+ git config ${mode_prefix}list --type=path >actual 2>err &&
10: 9221ca2352 ! 9: 7568a0bc34 config: format expiry dates gently
@@ Metadata
Author: Derrick Stolee <stolee@gmail.com>
## Commit message ##
- config: format expiry dates gently
+ config: format expiry dates quietly
Move the logic for formatting expiry date config values into a helper
- method and use gentle parsing when needed.
+ method and use quiet parsing when needed.
+
+ Note that git_config_expiry_date() will show an error on a bad parse and
+ not die() like most other git_config...() parsers. Thus, we use
+ 'quietly' here instead of 'gently'.
There is an unfortunate asymmetry in these two parsing methods, but we
need to treat a positive response from parse_expiry_date() as an error
@@ builtin/config.c: static int format_config_path(struct strbuf *buf,
+static int format_config_expiry_date(struct strbuf *buf,
+ const char *key_,
+ const char *value_,
-+ int gently)
++ int quietly)
+{
+ timestamp_t t;
-+ if (gently) {
++ if (quietly) {
+ if (parse_expiry_date(value_, &t))
+ return -1;
+ } else if (git_config_expiry_date(&t, key_, value_) < 0) {
@@ t/t1300-config.sh: test_expect_success 'list --type=path shows only canonicaliza
- error: '\''~/dir'\'' for '\''section.path'\'' is not a valid timestamp
- error: '\''red'\'' for '\''section.red'\'' is not a valid timestamp
- error: '\''Blue'\'' for '\''section.blue'\'' is not a valid timestamp
+- error: '\'':(optional)no-such-path'\'' for '\''section.missing'\'' is not a valid timestamp
+- error: '\'':(optional)expect'\'' for '\''section.exists'\'' is not a valid timestamp
- EOF
-
git config ${mode_prefix}list --type=expiry-date >actual 2>err &&
11: ddf6131ac9 ! 10: d98966f53a color: add color_parse_gently()
@@ Metadata
Author: Derrick Stolee <stolee@gmail.com>
## Commit message ##
- color: add color_parse_gently()
+ color: add color_parse_quietly()
When parsing colors, a failed parse leads to an error message due to the
result returning error(). To allow for quiet parsing, create
- color_parse_gently().
+ color_parse_quietly(). This is in contrast to an ..._gently() version
+ because the original does not die(), so both options are technically
+ 'gentle'.
To accomplish this, convert the implementation of color_parse_mem() into
- a static color_parse_mem_1() helper that adds a 'gently' parameter. The
- color_parse_gently() method can then use this. Since it is a near
+ a static color_parse_mem_1() helper that adds a 'quiet' parameter. The
+ color_parse_quietly() method can then use this. Since it is a near
equivalent to color_parse(), move that method down in the file so they
can be nearby while also appearing after color_parse_mem_1().
@@ color.c: static int color_empty(const struct color *c)
-int color_parse_mem(const char *value, int value_len, char *dst)
+static int color_parse_mem_1(const char *value, int value_len,
-+ char *dst, int gently)
++ char *dst, int quiet)
{
const char *ptr = value;
int len = value_len;
@@ color.c: int color_parse_mem(const char *value, int value_len, char *dst)
return 0;
bad:
- return error(_("invalid color value: %.*s"), value_len, value);
-+ return gently ? -1 : error(_("invalid color value: %.*s"), value_len, value);
++ return quiet ? -1 : error(_("invalid color value: %.*s"), value_len, value);
#undef OUT
}
@@ color.c: int color_parse_mem(const char *value, int value_len, char *dst)
+ return color_parse_mem(value, strlen(value), dst);
+}
+
-+int color_parse_gently(const char *value, char *dst)
++int color_parse_quietly(const char *value, char *dst)
+{
+ return color_parse_mem_1(value, strlen(value), dst, 1);
+}
@@ color.h: bool want_color_fd(int fd, enum git_colorbool var);
* terminal.
*/
int color_parse(const char *value, char *dst);
-+int color_parse_gently(const char *value, char *dst);
++int color_parse_quietly(const char *value, char *dst);
int color_parse_mem(const char *value, int len, char *dst);
/*
12: d14937e6d1 ! 11: 078065cff0 config: format colors gently
@@ Metadata
Author: Derrick Stolee <stolee@gmail.com>
## Commit message ##
- config: format colors gently
+ config: format colors quietly
Move the logic for formatting color config value into a helper method
- and use gentle parsing when needed.
+ and use quiet parsing when needed.
This removes error messages when parsing a list of config values that do
not match color formats.
@@ builtin/config.c: static int format_config_expiry_date(struct strbuf *buf,
+ char v[COLOR_MAXLEN];
+
+ if (gently) {
-+ if (color_parse_gently(value_, v) < 0)
++ if (color_parse_quietly(value_, v) < 0)
+ return -1;
+ } else if (git_config_color(v, key_, value_) < 0) {
+ return -1;
@@ t/t1300-config.sh: test_expect_success 'list --type=color shows only canonicaliz
- error: invalid color value: 1M
- error: invalid color value: ~/dir
- error: invalid color value: Fri Jun 4 15:46:55 2010
+- error: invalid color value: :(optional)no-such-path
+- error: invalid color value: :(optional)expect
- EOF
-
git config ${mode_prefix}list --type=color >actual.raw 2>err &&
13: 48fc882785 ! 12: 76fc7670fc config: restructure format_config()
@@ Commit message
Signed-off-by: Derrick Stolee <stolee@gmail.com>
## builtin/config.c ##
+@@ builtin/config.c: struct config_display_options {
+ .key_delim = ' ', \
+ }
+
++#define TYPE_NONE 0
+ #define TYPE_BOOL 1
+ #define TYPE_INT 2
+ #define TYPE_BOOL_OR_INT 3
@@ builtin/config.c: static int format_config(const struct config_display_options *opts,
show_config_origin(opts, kvi, buf);
if (opts->show_keys)
@@ builtin/config.c: static int format_config(const struct config_display_options *
+ res = format_config_color(buf, key_, value_, gently);
+ break;
+
-+ default:
++ case TYPE_NONE:
+ if (value_) {
strbuf_addstr(buf, value_);
} else {
/* Just show the key name; back out delimiter */
-@@ builtin/config.c: static int format_config(const struct config_display_options *opts,
+ if (opts->show_keys)
strbuf_setlen(buf, buf->len - 1);
}
++ break;
++
++ default:
++ BUG("undefined type %d", opts->type);
}
+
+terminator:
-: ---------- > 13: 3c32c037bc config: use an enum for type
--
gitgitgadget
^ permalink raw reply [flat|nested] 58+ messages in thread* [PATCH v3 01/13] config: move show_all_config()
2026-02-23 12:26 ` [PATCH v3 00/13] Make 'git config list --type=' parse and filter types Derrick Stolee via GitGitGadget
@ 2026-02-23 12:26 ` Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 02/13] config: add 'gently' parameter to format_config() Derrick Stolee via GitGitGadget
` (11 subsequent siblings)
12 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-23 12:26 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt,
Derrick Stolee via GitGitGadget, Derrick Stolee, Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
In anticipation of using format_config() in this method, move
show_all_config() lower in the file without changes.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 48 ++++++++++++++++++++++++------------------------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 288ebdfdaa..237f7a934d 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -231,30 +231,6 @@ static void show_config_scope(const struct config_display_options *opts,
strbuf_addch(buf, term);
}
-static int show_all_config(const char *key_, const char *value_,
- const struct config_context *ctx,
- void *cb)
-{
- const struct config_display_options *opts = cb;
- const struct key_value_info *kvi = ctx->kvi;
-
- if (opts->show_origin || opts->show_scope) {
- struct strbuf buf = STRBUF_INIT;
- if (opts->show_scope)
- show_config_scope(opts, kvi, &buf);
- if (opts->show_origin)
- show_config_origin(opts, kvi, &buf);
- /* Use fwrite as "buf" can contain \0's if "end_null" is set. */
- fwrite(buf.buf, 1, buf.len, stdout);
- strbuf_release(&buf);
- }
- if (!opts->omit_values && value_)
- printf("%s%c%s%c", key_, opts->delim, value_, opts->term);
- else
- printf("%s%c", key_, opts->term);
- return 0;
-}
-
struct strbuf_list {
struct strbuf *items;
int nr;
@@ -332,6 +308,30 @@ static int format_config(const struct config_display_options *opts,
return 0;
}
+static int show_all_config(const char *key_, const char *value_,
+ const struct config_context *ctx,
+ void *cb)
+{
+ const struct config_display_options *opts = cb;
+ const struct key_value_info *kvi = ctx->kvi;
+
+ if (opts->show_origin || opts->show_scope) {
+ struct strbuf buf = STRBUF_INIT;
+ if (opts->show_scope)
+ show_config_scope(opts, kvi, &buf);
+ if (opts->show_origin)
+ show_config_origin(opts, kvi, &buf);
+ /* Use fwrite as "buf" can contain \0's if "end_null" is set. */
+ fwrite(buf.buf, 1, buf.len, stdout);
+ strbuf_release(&buf);
+ }
+ if (!opts->omit_values && value_)
+ printf("%s%c%s%c", key_, opts->delim, value_, opts->term);
+ else
+ printf("%s%c", key_, opts->term);
+ return 0;
+}
+
#define GET_VALUE_ALL (1 << 0)
#define GET_VALUE_KEY_REGEXP (1 << 1)
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v3 02/13] config: add 'gently' parameter to format_config()
2026-02-23 12:26 ` [PATCH v3 00/13] Make 'git config list --type=' parse and filter types Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 01/13] config: move show_all_config() Derrick Stolee via GitGitGadget
@ 2026-02-23 12:26 ` Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 03/13] config: make 'git config list --type=<X>' work Derrick Stolee via GitGitGadget
` (10 subsequent siblings)
12 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-23 12:26 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt,
Derrick Stolee via GitGitGadget, Derrick Stolee, Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
This parameter is set to 0 for all current callers and is UNUSED.
However, we will start using this option in future changes and in a
critical change that requires gentle parsing (not using die()) to try
parsing all values in a list.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 237f7a934d..b4c4228311 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -242,10 +242,14 @@ struct strbuf_list {
* append it into strbuf `buf`. Returns a negative value on failure,
* 0 on success, 1 on a missing optional value (i.e., telling the
* caller to pretend that <key_,value_> did not exist).
+ *
+ * Note: 'gently' is currently ignored, but will be implemented in
+ * a future change.
*/
static int format_config(const struct config_display_options *opts,
struct strbuf *buf, const char *key_,
- const char *value_, const struct key_value_info *kvi)
+ const char *value_, const struct key_value_info *kvi,
+ int gently UNUSED)
{
if (opts->show_scope)
show_config_scope(opts, kvi, buf);
@@ -372,7 +376,7 @@ static int collect_config(const char *key_, const char *value_,
strbuf_init(&values->items[values->nr], 0);
status = format_config(data->display_opts, &values->items[values->nr++],
- key_, value_, kvi);
+ key_, value_, kvi, 0);
if (status < 0)
return status;
if (status) {
@@ -463,7 +467,7 @@ static int get_value(const struct config_location_options *opts,
strbuf_init(item, 0);
status = format_config(display_opts, item, key_,
- display_opts->default_value, &kvi);
+ display_opts->default_value, &kvi, 0);
if (status < 0)
die(_("failed to format default config value: %s"),
display_opts->default_value);
@@ -743,7 +747,7 @@ static int get_urlmatch(const struct config_location_options *opts,
status = format_config(&display_opts, &buf, item->string,
matched->value_is_null ? NULL : matched->value.buf,
- &matched->kvi);
+ &matched->kvi, 0);
if (!status)
fwrite(buf.buf, 1, buf.len, stdout);
strbuf_release(&buf);
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v3 03/13] config: make 'git config list --type=<X>' work
2026-02-23 12:26 ` [PATCH v3 00/13] Make 'git config list --type=' parse and filter types Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 01/13] config: move show_all_config() Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 02/13] config: add 'gently' parameter to format_config() Derrick Stolee via GitGitGadget
@ 2026-02-23 12:26 ` Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 04/13] config: format int64s gently Derrick Stolee via GitGitGadget
` (9 subsequent siblings)
12 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-23 12:26 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt,
Derrick Stolee via GitGitGadget, Derrick Stolee, Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
Previously, the --type=<X> argument to 'git config list' was ignored and
did nothing. Now, we add the use of format_config() to the
show_all_config() function so each key-value pair is attempted to be
parsed. This is our first use of the 'gently' parameter with a nonzero
value.
When listing multiple values, our initial settings for the output format
is different. Add a new init helper to specify the fact that keys should
be shown and also add the default delimiters as they were unset in some
cases.
Our intention is that if there is an error in parsing, then the row is
not output. This is necessary to avoid the caller needing to build their
own validator to understand the difference between valid, canonicalized
types and other raw string values. The raw values will always be
available to the user if they do not specify the --type=<X> option.
The current behavior is more complicated, including error messages on
bad parsing or potentially complete failure of the command. We add
tests at this point that demonstrate the current behavior so we can
witness the fix in future changes that parse these values quietly and
gently.
This is a change in behavior! We are starting to respect an option that
was previously ignored, leading to potential user confusion. This is
probably still a good option, since the --type argument did not change
behavior at all previously, so users can get the behavior they expect by
removing the --type argument or adding the --no-type argument.
t1300-config.sh is updated with the current behavior of this formatting
logic to justify the upcoming refactoring of format_config() that will
incrementally fix some of these cases to be more user-friendly.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
Documentation/git-config.adoc | 3 ++
builtin/config.c | 35 +++++++------
t/t1300-config.sh | 97 ++++++++++++++++++++++++++++++++++-
3 files changed, 119 insertions(+), 16 deletions(-)
diff --git a/Documentation/git-config.adoc b/Documentation/git-config.adoc
index ac3b536a15..5300dd4c51 100644
--- a/Documentation/git-config.adoc
+++ b/Documentation/git-config.adoc
@@ -240,6 +240,9 @@ Valid `<type>`'s include:
that the given value is canonicalize-able as an ANSI color, but it is written
as-is.
+
+If the command is in `list` mode, then the `--type <type>` argument will apply
+to each listed config value. If the value does not successfully parse in that
+format, then it will be omitted from the list.
--bool::
--int::
diff --git a/builtin/config.c b/builtin/config.c
index b4c4228311..4c4c791883 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -318,21 +318,12 @@ static int show_all_config(const char *key_, const char *value_,
{
const struct config_display_options *opts = cb;
const struct key_value_info *kvi = ctx->kvi;
+ struct strbuf formatted = STRBUF_INIT;
- if (opts->show_origin || opts->show_scope) {
- struct strbuf buf = STRBUF_INIT;
- if (opts->show_scope)
- show_config_scope(opts, kvi, &buf);
- if (opts->show_origin)
- show_config_origin(opts, kvi, &buf);
- /* Use fwrite as "buf" can contain \0's if "end_null" is set. */
- fwrite(buf.buf, 1, buf.len, stdout);
- strbuf_release(&buf);
- }
- if (!opts->omit_values && value_)
- printf("%s%c%s%c", key_, opts->delim, value_, opts->term);
- else
- printf("%s%c", key_, opts->term);
+ if (format_config(opts, &formatted, key_, value_, kvi, 1) >= 0)
+ fwrite(formatted.buf, 1, formatted.len, stdout);
+
+ strbuf_release(&formatted);
return 0;
}
@@ -872,6 +863,19 @@ static void display_options_init(struct config_display_options *opts)
}
}
+static void display_options_init_list(struct config_display_options *opts)
+{
+ opts->show_keys = 1;
+
+ if (opts->end_nul) {
+ display_options_init(opts);
+ } else {
+ opts->term = '\n';
+ opts->delim = ' ';
+ opts->key_delim = '=';
+ }
+}
+
static int cmd_config_list(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
@@ -890,7 +894,7 @@ static int cmd_config_list(int argc, const char **argv, const char *prefix,
check_argc(argc, 0, 0);
location_options_init(&location_opts, prefix);
- display_options_init(&display_opts);
+ display_options_init_list(&display_opts);
setup_auto_pager("config", 1);
@@ -1321,6 +1325,7 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
if (actions == ACTION_LIST) {
check_argc(argc, 0, 0);
+ display_options_init_list(&display_opts);
if (config_with_options(show_all_config, &display_opts,
&location_opts.source, the_repository,
&location_opts.options) < 0) {
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 9850fcd5b5..dc744c0bae 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -2459,9 +2459,15 @@ done
cat >.git/config <<-\EOF &&
[section]
-foo = true
+foo = True
number = 10
big = 1M
+path = ~/dir
+red = red
+blue = Blue
+date = Fri Jun 4 15:46:55 2010
+missing=:(optional)no-such-path
+exists=:(optional)expect
EOF
test_expect_success 'identical modern --type specifiers are allowed' '
@@ -2503,6 +2509,95 @@ test_expect_success 'unset type specifiers may be reset to conflicting ones' '
test_cmp_config 1048576 --type=bool --no-type --type=int section.big
'
+test_expect_success 'list --type=int shows only canonicalizable int values' '
+ cat >expect <<-EOF &&
+ section.number=10
+ section.big=1048576
+ EOF
+
+ test_must_fail git config ${mode_prefix}list --type=int
+'
+
+test_expect_success 'list --type=bool shows only canonicalizable bool values' '
+ cat >expect <<-EOF &&
+ section.foo=true
+ section.number=true
+ section.big=true
+ EOF
+
+ test_must_fail git config ${mode_prefix}list --type=bool
+'
+
+test_expect_success 'list --type=bool-or-int shows only canonicalizable values' '
+ cat >expect <<-EOF &&
+ section.foo=true
+ section.number=10
+ section.big=1048576
+ EOF
+
+ test_must_fail git config ${mode_prefix}list --type=bool-or-int
+'
+
+test_expect_success 'list --type=path shows only canonicalizable path values' '
+ # TODO: handling of missing path is incorrect here.
+ cat >expect <<-EOF &&
+ section.foo=True
+ section.number=10
+ section.big=1M
+ section.path=$HOME/dir
+ section.red=red
+ section.blue=Blue
+ section.date=Fri Jun 4 15:46:55 2010
+ section.missing=section.exists=expect
+ EOF
+
+ git config ${mode_prefix}list --type=path >actual 2>err &&
+ test_cmp expect actual &&
+ test_must_be_empty err
+'
+
+test_expect_success 'list --type=expiry-date shows only canonicalizable dates' '
+ cat >expecterr <<-EOF &&
+ error: '\''True'\'' for '\''section.foo'\'' is not a valid timestamp
+ error: '\''~/dir'\'' for '\''section.path'\'' is not a valid timestamp
+ error: '\''red'\'' for '\''section.red'\'' is not a valid timestamp
+ error: '\''Blue'\'' for '\''section.blue'\'' is not a valid timestamp
+ error: '\'':(optional)no-such-path'\'' for '\''section.missing'\'' is not a valid timestamp
+ error: '\'':(optional)expect'\'' for '\''section.exists'\'' is not a valid timestamp
+ EOF
+
+ git config ${mode_prefix}list --type=expiry-date >actual 2>err &&
+
+ # section.number and section.big parse as relative dates that could
+ # have clock skew in their results.
+ test_grep section.big actual &&
+ test_grep section.number actual &&
+ test_grep "section.date=$(git config --type=expiry-date section.$key)" actual &&
+ test_cmp expecterr err
+'
+
+test_expect_success 'list --type=color shows only canonicalizable color values' '
+ cat >expect <<-EOF &&
+ section.number=<>
+ section.red=<RED>
+ section.blue=<BLUE>
+ EOF
+
+ cat >expecterr <<-EOF &&
+ error: invalid color value: True
+ error: invalid color value: 1M
+ error: invalid color value: ~/dir
+ error: invalid color value: Fri Jun 4 15:46:55 2010
+ error: invalid color value: :(optional)no-such-path
+ error: invalid color value: :(optional)expect
+ EOF
+
+ git config ${mode_prefix}list --type=color >actual.raw 2>err &&
+ test_decode_color <actual.raw >actual &&
+ test_cmp expect actual &&
+ test_cmp expecterr err
+'
+
test_expect_success '--type rejects unknown specifiers' '
test_must_fail git config --type=nonsense section.foo 2>error &&
test_grep "unrecognized --type argument" error
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v3 04/13] config: format int64s gently
2026-02-23 12:26 ` [PATCH v3 00/13] Make 'git config list --type=' parse and filter types Derrick Stolee via GitGitGadget
` (2 preceding siblings ...)
2026-02-23 12:26 ` [PATCH v3 03/13] config: make 'git config list --type=<X>' work Derrick Stolee via GitGitGadget
@ 2026-02-23 12:26 ` Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 05/13] config: format bools gently Derrick Stolee via GitGitGadget
` (8 subsequent siblings)
12 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-23 12:26 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt,
Derrick Stolee via GitGitGadget, Derrick Stolee, Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
Move the logic for formatting int64 config values into a helper method
and use gentle parsing when needed.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 27 +++++++++++++++++++++++----
t/t1300-config.sh | 4 +++-
2 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 4c4c791883..448b148563 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -237,6 +237,25 @@ struct strbuf_list {
int alloc;
};
+static int format_config_int64(struct strbuf *buf,
+ const char *key_,
+ const char *value_,
+ const struct key_value_info *kvi,
+ int gently)
+{
+ int64_t v = 0;
+ if (gently) {
+ if (!git_parse_int64(value_, &v))
+ return -1;
+ } else {
+ /* may die() */
+ v = git_config_int64(key_, value_ ? value_ : "", kvi);
+ }
+
+ strbuf_addf(buf, "%"PRId64, v);
+ return 0;
+}
+
/*
* Format the configuration key-value pair (`key_`, `value_`) and
* append it into strbuf `buf`. Returns a negative value on failure,
@@ -249,8 +268,9 @@ struct strbuf_list {
static int format_config(const struct config_display_options *opts,
struct strbuf *buf, const char *key_,
const char *value_, const struct key_value_info *kvi,
- int gently UNUSED)
+ int gently)
{
+ int res = 0;
if (opts->show_scope)
show_config_scope(opts, kvi, buf);
if (opts->show_origin)
@@ -262,8 +282,7 @@ static int format_config(const struct config_display_options *opts,
strbuf_addch(buf, opts->key_delim);
if (opts->type == TYPE_INT)
- strbuf_addf(buf, "%"PRId64,
- git_config_int64(key_, value_ ? value_ : "", kvi));
+ res = format_config_int64(buf, key_, value_, kvi, gently);
else if (opts->type == TYPE_BOOL)
strbuf_addstr(buf, git_config_bool(key_, value_) ?
"true" : "false");
@@ -309,7 +328,7 @@ static int format_config(const struct config_display_options *opts,
}
}
strbuf_addch(buf, opts->term);
- return 0;
+ return res;
}
static int show_all_config(const char *key_, const char *value_,
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index dc744c0bae..05a812fd6d 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -2515,7 +2515,9 @@ test_expect_success 'list --type=int shows only canonicalizable int values' '
section.big=1048576
EOF
- test_must_fail git config ${mode_prefix}list --type=int
+ git config ${mode_prefix}list --type=int >actual 2>err &&
+ test_cmp expect actual &&
+ test_must_be_empty err
'
test_expect_success 'list --type=bool shows only canonicalizable bool values' '
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v3 05/13] config: format bools gently
2026-02-23 12:26 ` [PATCH v3 00/13] Make 'git config list --type=' parse and filter types Derrick Stolee via GitGitGadget
` (3 preceding siblings ...)
2026-02-23 12:26 ` [PATCH v3 04/13] config: format int64s gently Derrick Stolee via GitGitGadget
@ 2026-02-23 12:26 ` Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 06/13] config: format bools or ints gently Derrick Stolee via GitGitGadget
` (7 subsequent siblings)
12 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-23 12:26 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt,
Derrick Stolee via GitGitGadget, Derrick Stolee, Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
Move the logic for formatting bool config values into a helper method
and use gentle parsing when needed.
This makes 'git config list --type=bool' not fail when coming across a
non-boolean value. Such unparseable values are filtered out quietly.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 21 +++++++++++++++++++--
t/t1300-config.sh | 4 +++-
2 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 448b148563..d8b38c51d3 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -256,6 +256,24 @@ static int format_config_int64(struct strbuf *buf,
return 0;
}
+static int format_config_bool(struct strbuf *buf,
+ const char *key_,
+ const char *value_,
+ int gently)
+{
+ int v = 0;
+ if (gently) {
+ if ((v = git_parse_maybe_bool(value_)) < 0)
+ return -1;
+ } else {
+ /* may die() */
+ v = git_config_bool(key_, value_);
+ }
+
+ strbuf_addstr(buf, v ? "true" : "false");
+ return 0;
+}
+
/*
* Format the configuration key-value pair (`key_`, `value_`) and
* append it into strbuf `buf`. Returns a negative value on failure,
@@ -284,8 +302,7 @@ static int format_config(const struct config_display_options *opts,
if (opts->type == TYPE_INT)
res = format_config_int64(buf, key_, value_, kvi, gently);
else if (opts->type == TYPE_BOOL)
- strbuf_addstr(buf, git_config_bool(key_, value_) ?
- "true" : "false");
+ res = format_config_bool(buf, key_, value_, gently);
else if (opts->type == TYPE_BOOL_OR_INT) {
int is_bool, v;
v = git_config_bool_or_int(key_, value_, kvi,
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 05a812fd6d..568cfaa3c5 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -2527,7 +2527,9 @@ test_expect_success 'list --type=bool shows only canonicalizable bool values' '
section.big=true
EOF
- test_must_fail git config ${mode_prefix}list --type=bool
+ git config ${mode_prefix}list --type=bool >actual 2>err &&
+ test_cmp expect actual &&
+ test_must_be_empty err
'
test_expect_success 'list --type=bool-or-int shows only canonicalizable values' '
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v3 06/13] config: format bools or ints gently
2026-02-23 12:26 ` [PATCH v3 00/13] Make 'git config list --type=' parse and filter types Derrick Stolee via GitGitGadget
` (4 preceding siblings ...)
2026-02-23 12:26 ` [PATCH v3 05/13] config: format bools gently Derrick Stolee via GitGitGadget
@ 2026-02-23 12:26 ` Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 07/13] config: format bools or strings in helper Derrick Stolee via GitGitGadget
` (6 subsequent siblings)
12 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-23 12:26 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt,
Derrick Stolee via GitGitGadget, Derrick Stolee, Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
Move the logic for formatting bool-or-int config values into a helper
method and use gentle parsing when needed.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 40 +++++++++++++++++++++++++++++++---------
t/t1300-config.sh | 4 +++-
2 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index d8b38c51d3..491a880e56 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -274,6 +274,34 @@ static int format_config_bool(struct strbuf *buf,
return 0;
}
+static int format_config_bool_or_int(struct strbuf *buf,
+ const char *key_,
+ const char *value_,
+ const struct key_value_info *kvi,
+ int gently)
+{
+ int v, is_bool = 0;
+
+ if (gently) {
+ v = git_parse_maybe_bool_text(value_);
+
+ if (v >= 0)
+ is_bool = 1;
+ else if (!git_parse_int(value_, &v))
+ return -1;
+ } else {
+ v = git_config_bool_or_int(key_, value_, kvi,
+ &is_bool);
+ }
+
+ if (is_bool)
+ strbuf_addstr(buf, v ? "true" : "false");
+ else
+ strbuf_addf(buf, "%d", v);
+
+ return 0;
+}
+
/*
* Format the configuration key-value pair (`key_`, `value_`) and
* append it into strbuf `buf`. Returns a negative value on failure,
@@ -303,15 +331,9 @@ static int format_config(const struct config_display_options *opts,
res = format_config_int64(buf, key_, value_, kvi, gently);
else if (opts->type == TYPE_BOOL)
res = format_config_bool(buf, key_, value_, gently);
- else if (opts->type == TYPE_BOOL_OR_INT) {
- int is_bool, v;
- v = git_config_bool_or_int(key_, value_, kvi,
- &is_bool);
- if (is_bool)
- strbuf_addstr(buf, v ? "true" : "false");
- else
- strbuf_addf(buf, "%d", v);
- } else if (opts->type == TYPE_BOOL_OR_STR) {
+ else if (opts->type == TYPE_BOOL_OR_INT)
+ res = format_config_bool_or_int(buf, key_, value_, kvi, gently);
+ else if (opts->type == TYPE_BOOL_OR_STR) {
int v = git_parse_maybe_bool(value_);
if (v < 0)
strbuf_addstr(buf, value_);
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 568cfaa3c5..1fc8e788ee 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -2539,7 +2539,9 @@ test_expect_success 'list --type=bool-or-int shows only canonicalizable values'
section.big=1048576
EOF
- test_must_fail git config ${mode_prefix}list --type=bool-or-int
+ git config ${mode_prefix}list --type=bool-or-int >actual 2>err &&
+ test_cmp expect actual &&
+ test_must_be_empty err
'
test_expect_success 'list --type=path shows only canonicalizable path values' '
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v3 07/13] config: format bools or strings in helper
2026-02-23 12:26 ` [PATCH v3 00/13] Make 'git config list --type=' parse and filter types Derrick Stolee via GitGitGadget
` (5 preceding siblings ...)
2026-02-23 12:26 ` [PATCH v3 06/13] config: format bools or ints gently Derrick Stolee via GitGitGadget
@ 2026-02-23 12:26 ` Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 08/13] config: format paths gently Derrick Stolee via GitGitGadget
` (5 subsequent siblings)
12 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-23 12:26 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt,
Derrick Stolee via GitGitGadget, Derrick Stolee, Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
Move the logic for formatting bool-or-string config values into a
helper. This parsing has always been gentle, so this is not unlocking
new behavior. This extraction is only to match the formatting of the
other cases that do need a behavior change.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 491a880e56..79c139c5b0 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -302,6 +302,18 @@ static int format_config_bool_or_int(struct strbuf *buf,
return 0;
}
+/* This mode is always gentle. */
+static int format_config_bool_or_str(struct strbuf *buf,
+ const char *value_)
+{
+ int v = git_parse_maybe_bool(value_);
+ if (v < 0)
+ strbuf_addstr(buf, value_);
+ else
+ strbuf_addstr(buf, v ? "true" : "false");
+ return 0;
+}
+
/*
* Format the configuration key-value pair (`key_`, `value_`) and
* append it into strbuf `buf`. Returns a negative value on failure,
@@ -333,13 +345,9 @@ static int format_config(const struct config_display_options *opts,
res = format_config_bool(buf, key_, value_, gently);
else if (opts->type == TYPE_BOOL_OR_INT)
res = format_config_bool_or_int(buf, key_, value_, kvi, gently);
- else if (opts->type == TYPE_BOOL_OR_STR) {
- int v = git_parse_maybe_bool(value_);
- if (v < 0)
- strbuf_addstr(buf, value_);
- else
- strbuf_addstr(buf, v ? "true" : "false");
- } else if (opts->type == TYPE_PATH) {
+ else if (opts->type == TYPE_BOOL_OR_STR)
+ res = format_config_bool_or_str(buf, value_);
+ else if (opts->type == TYPE_PATH) {
char *v;
if (git_config_pathname(&v, key_, value_) < 0)
return -1;
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v3 08/13] config: format paths gently
2026-02-23 12:26 ` [PATCH v3 00/13] Make 'git config list --type=' parse and filter types Derrick Stolee via GitGitGadget
` (6 preceding siblings ...)
2026-02-23 12:26 ` [PATCH v3 07/13] config: format bools or strings in helper Derrick Stolee via GitGitGadget
@ 2026-02-23 12:26 ` Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 09/13] config: format expiry dates quietly Derrick Stolee via GitGitGadget
` (4 subsequent siblings)
12 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-23 12:26 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt,
Derrick Stolee via GitGitGadget, Derrick Stolee, Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
Move the logic for formatting path config values into a helper method
and use gentle parsing when needed.
We need to be careful about how to handle the ':(optional)' macro, which
as tested in t1311-config-optional.sh must allow for ignoring a missing
path when other multiple values exist, but cause 'git config get' to
fail if it is the only possible value and thus no result is output.
In the case of our list, we need to omit those values silently. This
necessitates the use of the 'gently' parameter here.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 32 ++++++++++++++++++++++----------
t/t1300-config.sh | 3 +--
2 files changed, 23 insertions(+), 12 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 79c139c5b0..2828b6dcf1 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -314,6 +314,25 @@ static int format_config_bool_or_str(struct strbuf *buf,
return 0;
}
+static int format_config_path(struct strbuf *buf,
+ const char *key_,
+ const char *value_,
+ int gently)
+{
+ char *v;
+
+ if (git_config_pathname(&v, key_, value_) < 0)
+ return -1;
+
+ if (v)
+ strbuf_addstr(buf, v);
+ else
+ return gently ? -1 : 1; /* :(optional)no-such-file */
+
+ free(v);
+ return 0;
+}
+
/*
* Format the configuration key-value pair (`key_`, `value_`) and
* append it into strbuf `buf`. Returns a negative value on failure,
@@ -347,16 +366,9 @@ static int format_config(const struct config_display_options *opts,
res = format_config_bool_or_int(buf, key_, value_, kvi, gently);
else if (opts->type == TYPE_BOOL_OR_STR)
res = format_config_bool_or_str(buf, value_);
- else if (opts->type == TYPE_PATH) {
- char *v;
- if (git_config_pathname(&v, key_, value_) < 0)
- return -1;
- if (v)
- strbuf_addstr(buf, v);
- else
- return 1; /* :(optional)no-such-file */
- free((char *)v);
- } else if (opts->type == TYPE_EXPIRY_DATE) {
+ else if (opts->type == TYPE_PATH)
+ res = format_config_path(buf, key_, value_, gently);
+ else if (opts->type == TYPE_EXPIRY_DATE) {
timestamp_t t;
if (git_config_expiry_date(&t, key_, value_) < 0)
return -1;
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 1fc8e788ee..48d9c554d8 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -2545,7 +2545,6 @@ test_expect_success 'list --type=bool-or-int shows only canonicalizable values'
'
test_expect_success 'list --type=path shows only canonicalizable path values' '
- # TODO: handling of missing path is incorrect here.
cat >expect <<-EOF &&
section.foo=True
section.number=10
@@ -2554,7 +2553,7 @@ test_expect_success 'list --type=path shows only canonicalizable path values' '
section.red=red
section.blue=Blue
section.date=Fri Jun 4 15:46:55 2010
- section.missing=section.exists=expect
+ section.exists=expect
EOF
git config ${mode_prefix}list --type=path >actual 2>err &&
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v3 09/13] config: format expiry dates quietly
2026-02-23 12:26 ` [PATCH v3 00/13] Make 'git config list --type=' parse and filter types Derrick Stolee via GitGitGadget
` (7 preceding siblings ...)
2026-02-23 12:26 ` [PATCH v3 08/13] config: format paths gently Derrick Stolee via GitGitGadget
@ 2026-02-23 12:26 ` Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 10/13] color: add color_parse_quietly() Derrick Stolee via GitGitGadget
` (3 subsequent siblings)
12 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-23 12:26 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt,
Derrick Stolee via GitGitGadget, Derrick Stolee, Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
Move the logic for formatting expiry date config values into a helper
method and use quiet parsing when needed.
Note that git_config_expiry_date() will show an error on a bad parse and
not die() like most other git_config...() parsers. Thus, we use
'quietly' here instead of 'gently'.
There is an unfortunate asymmetry in these two parsing methods, but we
need to treat a positive response from parse_expiry_date() as an error
or we will get incorrect values.
This updates the behavior of 'git config list --type=expiry-date' to be
quiet when attempting parsing on non-date values.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 27 +++++++++++++++++++++------
t/t1300-config.sh | 11 +----------
2 files changed, 22 insertions(+), 16 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 2828b6dcf1..ee77ddc87c 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -3,6 +3,7 @@
#include "abspath.h"
#include "config.h"
#include "color.h"
+#include "date.h"
#include "editor.h"
#include "environment.h"
#include "gettext.h"
@@ -333,6 +334,23 @@ static int format_config_path(struct strbuf *buf,
return 0;
}
+static int format_config_expiry_date(struct strbuf *buf,
+ const char *key_,
+ const char *value_,
+ int quietly)
+{
+ timestamp_t t;
+ if (quietly) {
+ if (parse_expiry_date(value_, &t))
+ return -1;
+ } else if (git_config_expiry_date(&t, key_, value_) < 0) {
+ return -1;
+ }
+
+ strbuf_addf(buf, "%"PRItime, t);
+ return 0;
+}
+
/*
* Format the configuration key-value pair (`key_`, `value_`) and
* append it into strbuf `buf`. Returns a negative value on failure,
@@ -368,12 +386,9 @@ static int format_config(const struct config_display_options *opts,
res = format_config_bool_or_str(buf, value_);
else if (opts->type == TYPE_PATH)
res = format_config_path(buf, key_, value_, gently);
- else if (opts->type == TYPE_EXPIRY_DATE) {
- timestamp_t t;
- if (git_config_expiry_date(&t, key_, value_) < 0)
- return -1;
- strbuf_addf(buf, "%"PRItime, t);
- } else if (opts->type == TYPE_COLOR) {
+ else if (opts->type == TYPE_EXPIRY_DATE)
+ res = format_config_expiry_date(buf, key_, value_, gently);
+ else if (opts->type == TYPE_COLOR) {
char v[COLOR_MAXLEN];
if (git_config_color(v, key_, value_) < 0)
return -1;
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 48d9c554d8..72bdd6ab03 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -2562,15 +2562,6 @@ test_expect_success 'list --type=path shows only canonicalizable path values' '
'
test_expect_success 'list --type=expiry-date shows only canonicalizable dates' '
- cat >expecterr <<-EOF &&
- error: '\''True'\'' for '\''section.foo'\'' is not a valid timestamp
- error: '\''~/dir'\'' for '\''section.path'\'' is not a valid timestamp
- error: '\''red'\'' for '\''section.red'\'' is not a valid timestamp
- error: '\''Blue'\'' for '\''section.blue'\'' is not a valid timestamp
- error: '\'':(optional)no-such-path'\'' for '\''section.missing'\'' is not a valid timestamp
- error: '\'':(optional)expect'\'' for '\''section.exists'\'' is not a valid timestamp
- EOF
-
git config ${mode_prefix}list --type=expiry-date >actual 2>err &&
# section.number and section.big parse as relative dates that could
@@ -2578,7 +2569,7 @@ test_expect_success 'list --type=expiry-date shows only canonicalizable dates' '
test_grep section.big actual &&
test_grep section.number actual &&
test_grep "section.date=$(git config --type=expiry-date section.$key)" actual &&
- test_cmp expecterr err
+ test_must_be_empty err
'
test_expect_success 'list --type=color shows only canonicalizable color values' '
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v3 10/13] color: add color_parse_quietly()
2026-02-23 12:26 ` [PATCH v3 00/13] Make 'git config list --type=' parse and filter types Derrick Stolee via GitGitGadget
` (8 preceding siblings ...)
2026-02-23 12:26 ` [PATCH v3 09/13] config: format expiry dates quietly Derrick Stolee via GitGitGadget
@ 2026-02-23 12:26 ` Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 11/13] config: format colors quietly Derrick Stolee via GitGitGadget
` (2 subsequent siblings)
12 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-23 12:26 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt,
Derrick Stolee via GitGitGadget, Derrick Stolee, Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
When parsing colors, a failed parse leads to an error message due to the
result returning error(). To allow for quiet parsing, create
color_parse_quietly(). This is in contrast to an ..._gently() version
because the original does not die(), so both options are technically
'gentle'.
To accomplish this, convert the implementation of color_parse_mem() into
a static color_parse_mem_1() helper that adds a 'quiet' parameter. The
color_parse_quietly() method can then use this. Since it is a near
equivalent to color_parse(), move that method down in the file so they
can be nearby while also appearing after color_parse_mem_1().
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
color.c | 25 ++++++++++++++++++-------
color.h | 1 +
2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/color.c b/color.c
index 07ac8c9d40..00b53f97ac 100644
--- a/color.c
+++ b/color.c
@@ -223,11 +223,6 @@ static int parse_attr(const char *name, size_t len)
return -1;
}
-int color_parse(const char *value, char *dst)
-{
- return color_parse_mem(value, strlen(value), dst);
-}
-
/*
* Write the ANSI color codes for "c" to "out"; the string should
* already have the ANSI escape code in it. "out" should have enough
@@ -264,7 +259,8 @@ static int color_empty(const struct color *c)
return c->type <= COLOR_NORMAL;
}
-int color_parse_mem(const char *value, int value_len, char *dst)
+static int color_parse_mem_1(const char *value, int value_len,
+ char *dst, int quiet)
{
const char *ptr = value;
int len = value_len;
@@ -365,10 +361,25 @@ int color_parse_mem(const char *value, int value_len, char *dst)
OUT(0);
return 0;
bad:
- return error(_("invalid color value: %.*s"), value_len, value);
+ return quiet ? -1 : error(_("invalid color value: %.*s"), value_len, value);
#undef OUT
}
+int color_parse_mem(const char *value, int value_len, char *dst)
+{
+ return color_parse_mem_1(value, value_len, dst, 0);
+}
+
+int color_parse(const char *value, char *dst)
+{
+ return color_parse_mem(value, strlen(value), dst);
+}
+
+int color_parse_quietly(const char *value, char *dst)
+{
+ return color_parse_mem_1(value, strlen(value), dst, 1);
+}
+
enum git_colorbool git_config_colorbool(const char *var, const char *value)
{
if (value) {
diff --git a/color.h b/color.h
index 43e6c9ad09..0d72540300 100644
--- a/color.h
+++ b/color.h
@@ -118,6 +118,7 @@ bool want_color_fd(int fd, enum git_colorbool var);
* terminal.
*/
int color_parse(const char *value, char *dst);
+int color_parse_quietly(const char *value, char *dst);
int color_parse_mem(const char *value, int len, char *dst);
/*
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v3 11/13] config: format colors quietly
2026-02-23 12:26 ` [PATCH v3 00/13] Make 'git config list --type=' parse and filter types Derrick Stolee via GitGitGadget
` (9 preceding siblings ...)
2026-02-23 12:26 ` [PATCH v3 10/13] color: add color_parse_quietly() Derrick Stolee via GitGitGadget
@ 2026-02-23 12:26 ` Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 12/13] config: restructure format_config() Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 13/13] config: use an enum for type Derrick Stolee via GitGitGadget
12 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-23 12:26 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt,
Derrick Stolee via GitGitGadget, Derrick Stolee, Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
Move the logic for formatting color config value into a helper method
and use quiet parsing when needed.
This removes error messages when parsing a list of config values that do
not match color formats.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 27 +++++++++++++++++++++------
t/t1300-config.sh | 11 +----------
2 files changed, 22 insertions(+), 16 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index ee77ddc87c..45304076dc 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -351,6 +351,24 @@ static int format_config_expiry_date(struct strbuf *buf,
return 0;
}
+static int format_config_color(struct strbuf *buf,
+ const char *key_,
+ const char *value_,
+ int gently)
+{
+ char v[COLOR_MAXLEN];
+
+ if (gently) {
+ if (color_parse_quietly(value_, v) < 0)
+ return -1;
+ } else if (git_config_color(v, key_, value_) < 0) {
+ return -1;
+ }
+
+ strbuf_addstr(buf, v);
+ return 0;
+}
+
/*
* Format the configuration key-value pair (`key_`, `value_`) and
* append it into strbuf `buf`. Returns a negative value on failure,
@@ -388,12 +406,9 @@ static int format_config(const struct config_display_options *opts,
res = format_config_path(buf, key_, value_, gently);
else if (opts->type == TYPE_EXPIRY_DATE)
res = format_config_expiry_date(buf, key_, value_, gently);
- else if (opts->type == TYPE_COLOR) {
- char v[COLOR_MAXLEN];
- if (git_config_color(v, key_, value_) < 0)
- return -1;
- strbuf_addstr(buf, v);
- } else if (value_) {
+ else if (opts->type == TYPE_COLOR)
+ res = format_config_color(buf, key_, value_, gently);
+ else if (value_) {
strbuf_addstr(buf, value_);
} else {
/* Just show the key name; back out delimiter */
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 72bdd6ab03..128971ee12 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -2579,19 +2579,10 @@ test_expect_success 'list --type=color shows only canonicalizable color values'
section.blue=<BLUE>
EOF
- cat >expecterr <<-EOF &&
- error: invalid color value: True
- error: invalid color value: 1M
- error: invalid color value: ~/dir
- error: invalid color value: Fri Jun 4 15:46:55 2010
- error: invalid color value: :(optional)no-such-path
- error: invalid color value: :(optional)expect
- EOF
-
git config ${mode_prefix}list --type=color >actual.raw 2>err &&
test_decode_color <actual.raw >actual &&
test_cmp expect actual &&
- test_cmp expecterr err
+ test_must_be_empty err
'
test_expect_success '--type rejects unknown specifiers' '
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v3 12/13] config: restructure format_config()
2026-02-23 12:26 ` [PATCH v3 00/13] Make 'git config list --type=' parse and filter types Derrick Stolee via GitGitGadget
` (10 preceding siblings ...)
2026-02-23 12:26 ` [PATCH v3 11/13] config: format colors quietly Derrick Stolee via GitGitGadget
@ 2026-02-23 12:26 ` Derrick Stolee via GitGitGadget
2026-02-23 12:26 ` [PATCH v3 13/13] config: use an enum for type Derrick Stolee via GitGitGadget
12 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-23 12:26 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt,
Derrick Stolee via GitGitGadget, Derrick Stolee, Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
The recent changes have replaced the bodies of most if/else-if cases
with simple helper method calls. This makes it easy to adapt the
structure into a clearer switch statement, leaving a simple if/else in
the default case.
Make things a little simpler to read by reducing the nesting depth via a
new goto statement when we want to skip values.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 64 ++++++++++++++++++++++++++++++++++--------------
1 file changed, 45 insertions(+), 19 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 45304076dc..2e8bc6590c 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -124,6 +124,7 @@ struct config_display_options {
.key_delim = ' ', \
}
+#define TYPE_NONE 0
#define TYPE_BOOL 1
#define TYPE_INT 2
#define TYPE_BOOL_OR_INT 3
@@ -390,32 +391,57 @@ static int format_config(const struct config_display_options *opts,
show_config_origin(opts, kvi, buf);
if (opts->show_keys)
strbuf_addstr(buf, key_);
- if (!opts->omit_values) {
- if (opts->show_keys)
- strbuf_addch(buf, opts->key_delim);
-
- if (opts->type == TYPE_INT)
- res = format_config_int64(buf, key_, value_, kvi, gently);
- else if (opts->type == TYPE_BOOL)
- res = format_config_bool(buf, key_, value_, gently);
- else if (opts->type == TYPE_BOOL_OR_INT)
- res = format_config_bool_or_int(buf, key_, value_, kvi, gently);
- else if (opts->type == TYPE_BOOL_OR_STR)
- res = format_config_bool_or_str(buf, value_);
- else if (opts->type == TYPE_PATH)
- res = format_config_path(buf, key_, value_, gently);
- else if (opts->type == TYPE_EXPIRY_DATE)
- res = format_config_expiry_date(buf, key_, value_, gently);
- else if (opts->type == TYPE_COLOR)
- res = format_config_color(buf, key_, value_, gently);
- else if (value_) {
+
+ if (opts->omit_values)
+ goto terminator;
+
+ if (opts->show_keys)
+ strbuf_addch(buf, opts->key_delim);
+
+ switch (opts->type) {
+ case TYPE_INT:
+ res = format_config_int64(buf, key_, value_, kvi, gently);
+ break;
+
+ case TYPE_BOOL:
+ res = format_config_bool(buf, key_, value_, gently);
+ break;
+
+ case TYPE_BOOL_OR_INT:
+ res = format_config_bool_or_int(buf, key_, value_, kvi, gently);
+ break;
+
+ case TYPE_BOOL_OR_STR:
+ res = format_config_bool_or_str(buf, value_);
+ break;
+
+ case TYPE_PATH:
+ res = format_config_path(buf, key_, value_, gently);
+ break;
+
+ case TYPE_EXPIRY_DATE:
+ res = format_config_expiry_date(buf, key_, value_, gently);
+ break;
+
+ case TYPE_COLOR:
+ res = format_config_color(buf, key_, value_, gently);
+ break;
+
+ case TYPE_NONE:
+ if (value_) {
strbuf_addstr(buf, value_);
} else {
/* Just show the key name; back out delimiter */
if (opts->show_keys)
strbuf_setlen(buf, buf->len - 1);
}
+ break;
+
+ default:
+ BUG("undefined type %d", opts->type);
}
+
+terminator:
strbuf_addch(buf, opts->term);
return res;
}
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread* [PATCH v3 13/13] config: use an enum for type
2026-02-23 12:26 ` [PATCH v3 00/13] Make 'git config list --type=' parse and filter types Derrick Stolee via GitGitGadget
` (11 preceding siblings ...)
2026-02-23 12:26 ` [PATCH v3 12/13] config: restructure format_config() Derrick Stolee via GitGitGadget
@ 2026-02-23 12:26 ` Derrick Stolee via GitGitGadget
12 siblings, 0 replies; 58+ messages in thread
From: Derrick Stolee via GitGitGadget @ 2026-02-23 12:26 UTC (permalink / raw)
To: git
Cc: gitster, brian m. carlson, Phillip Wood, Kristoffer Haugsbakk,
Jean-Noël Avila, Patrick Steinhardt,
Derrick Stolee via GitGitGadget, Derrick Stolee, Derrick Stolee
From: Derrick Stolee <stolee@gmail.com>
The --type=<X> option for 'git config' has previously been defined using
macros, but using a typed enum is better for tracking the possible
values.
Move the definition up to make sure it is defined before a macro uses
some of its terms.
Update the initializer for config_display_options to explicitly set
'type' to TYPE_NONE even though this is implied by a zero value.
This assists in knowing that the switch statement added in the previous
change has a complete set of cases for a properly-valued enum.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
builtin/config.c | 23 +++++++++++++----------
1 file changed, 13 insertions(+), 10 deletions(-)
diff --git a/builtin/config.c b/builtin/config.c
index 2e8bc6590c..7c4857be62 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -86,6 +86,17 @@ struct config_location_options {
.respect_includes_opt = -1, \
}
+enum config_type {
+ TYPE_NONE = 0,
+ TYPE_BOOL,
+ TYPE_INT,
+ TYPE_BOOL_OR_INT,
+ TYPE_PATH,
+ TYPE_EXPIRY_DATE,
+ TYPE_COLOR,
+ TYPE_BOOL_OR_STR,
+};
+
#define CONFIG_TYPE_OPTIONS(type) \
OPT_GROUP(N_("Type")), \
OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type), \
@@ -111,7 +122,7 @@ struct config_display_options {
int show_origin;
int show_scope;
int show_keys;
- int type;
+ enum config_type type;
char *default_value;
/* Populated via `display_options_init()`. */
int term;
@@ -122,17 +133,9 @@ struct config_display_options {
.term = '\n', \
.delim = '=', \
.key_delim = ' ', \
+ .type = TYPE_NONE, \
}
-#define TYPE_NONE 0
-#define TYPE_BOOL 1
-#define TYPE_INT 2
-#define TYPE_BOOL_OR_INT 3
-#define TYPE_PATH 4
-#define TYPE_EXPIRY_DATE 5
-#define TYPE_COLOR 6
-#define TYPE_BOOL_OR_STR 7
-
#define OPT_CALLBACK_VALUE(s, l, v, h, i) { \
.type = OPTION_CALLBACK, \
.short_name = (s), \
--
gitgitgadget
^ permalink raw reply related [flat|nested] 58+ messages in thread