config: make 'git config list --type=<X>' work

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> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Feb 23, 2026 at 12:26 UTC 1ef1f9d53a1607dd8fd38e0dbae67e405c3b3563
3 files changed +119 -16
Documentation/git-config.adoc
+3
@@ -240,6 +240,9 @@ Valid `<type>`'s include:
240 that the given value is canonicalize-able as an ANSI color, but it is written
241 as-is.
242 +
243 +If the command is in `list` mode, then the `--type <type>` argument will apply
244 +to each listed config value. If the value does not successfully parse in that
245 +format, then it will be omitted from the list.
246
247 --bool::
248 --int::
builtin/config.c
+20 -15
@@ -318,21 +318,12 @@ static int show_all_config(const char *key_, const char *value_,
318 {
319 const struct config_display_options *opts = cb;
320 const struct key_value_info *kvi = ctx->kvi;
321 + struct strbuf formatted = STRBUF_INIT;
322
322 - if (opts->show_origin || opts->show_scope) {
323 - struct strbuf buf = STRBUF_INIT;
324 - if (opts->show_scope)
325 - show_config_scope(opts, kvi, &buf);
326 - if (opts->show_origin)
327 - show_config_origin(opts, kvi, &buf);
328 - /* Use fwrite as "buf" can contain \0's if "end_null" is set. */
329 - fwrite(buf.buf, 1, buf.len, stdout);
330 - strbuf_release(&buf);
331 - }
332 - if (!opts->omit_values && value_)
333 - printf("%s%c%s%c", key_, opts->delim, value_, opts->term);
334 - else
335 - printf("%s%c", key_, opts->term);
323 + if (format_config(opts, &formatted, key_, value_, kvi, 1) >= 0)
324 + fwrite(formatted.buf, 1, formatted.len, stdout);
325 +
326 + strbuf_release(&formatted);
327 return 0;
328 }
329
@@ -872,6 +863,19 @@ static void display_options_init(struct config_display_options *opts)
863 }
864 }
865
866 +static void display_options_init_list(struct config_display_options *opts)
867 +{
868 + opts->show_keys = 1;
869 +
870 + if (opts->end_nul) {
871 + display_options_init(opts);
872 + } else {
873 + opts->term = '\n';
874 + opts->delim = ' ';
875 + opts->key_delim = '=';
876 + }
877 +}
878 +
879 static int cmd_config_list(int argc, const char **argv, const char *prefix,
880 struct repository *repo UNUSED)
881 {
@@ -890,7 +894,7 @@ static int cmd_config_list(int argc, const char **argv, const char *prefix,
894 check_argc(argc, 0, 0);
895
896 location_options_init(&location_opts, prefix);
893 - display_options_init(&display_opts);
897 + display_options_init_list(&display_opts);
898
899 setup_auto_pager("config", 1);
900
@@ -1321,6 +1325,7 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
1325
1326 if (actions == ACTION_LIST) {
1327 check_argc(argc, 0, 0);
1328 + display_options_init_list(&display_opts);
1329 if (config_with_options(show_all_config, &display_opts,
1330 &location_opts.source, the_repository,
1331 &location_opts.options) < 0) {
t/t1300-config.sh
+96 -1
@@ -2459,9 +2459,15 @@ done
2459
2460 cat >.git/config <<-\EOF &&
2461 [section]
2462 -foo = true
2462 +foo = True
2463 number = 10
2464 big = 1M
2465 +path = ~/dir
2466 +red = red
2467 +blue = Blue
2468 +date = Fri Jun 4 15:46:55 2010
2469 +missing=:(optional)no-such-path
2470 +exists=:(optional)expect
2471 EOF
2472
2473 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' '
2509 test_cmp_config 1048576 --type=bool --no-type --type=int section.big
2510 '
2511
2512 +test_expect_success 'list --type=int shows only canonicalizable int values' '
2513 + cat >expect <<-EOF &&
2514 + section.number=10
2515 + section.big=1048576
2516 + EOF
2517 +
2518 + test_must_fail git config ${mode_prefix}list --type=int
2519 +'
2520 +
2521 +test_expect_success 'list --type=bool shows only canonicalizable bool values' '
2522 + cat >expect <<-EOF &&
2523 + section.foo=true
2524 + section.number=true
2525 + section.big=true
2526 + EOF
2527 +
2528 + test_must_fail git config ${mode_prefix}list --type=bool
2529 +'
2530 +
2531 +test_expect_success 'list --type=bool-or-int shows only canonicalizable values' '
2532 + cat >expect <<-EOF &&
2533 + section.foo=true
2534 + section.number=10
2535 + section.big=1048576
2536 + EOF
2537 +
2538 + test_must_fail git config ${mode_prefix}list --type=bool-or-int
2539 +'
2540 +
2541 +test_expect_success 'list --type=path shows only canonicalizable path values' '
2542 + # TODO: handling of missing path is incorrect here.
2543 + cat >expect <<-EOF &&
2544 + section.foo=True
2545 + section.number=10
2546 + section.big=1M
2547 + section.path=$HOME/dir
2548 + section.red=red
2549 + section.blue=Blue
2550 + section.date=Fri Jun 4 15:46:55 2010
2551 + section.missing=section.exists=expect
2552 + EOF
2553 +
2554 + git config ${mode_prefix}list --type=path >actual 2>err &&
2555 + test_cmp expect actual &&
2556 + test_must_be_empty err
2557 +'
2558 +
2559 +test_expect_success 'list --type=expiry-date shows only canonicalizable dates' '
2560 + cat >expecterr <<-EOF &&
2561 + error: '\''True'\'' for '\''section.foo'\'' is not a valid timestamp
2562 + error: '\''~/dir'\'' for '\''section.path'\'' is not a valid timestamp
2563 + error: '\''red'\'' for '\''section.red'\'' is not a valid timestamp
2564 + error: '\''Blue'\'' for '\''section.blue'\'' is not a valid timestamp
2565 + error: '\'':(optional)no-such-path'\'' for '\''section.missing'\'' is not a valid timestamp
2566 + error: '\'':(optional)expect'\'' for '\''section.exists'\'' is not a valid timestamp
2567 + EOF
2568 +
2569 + git config ${mode_prefix}list --type=expiry-date >actual 2>err &&
2570 +
2571 + # section.number and section.big parse as relative dates that could
2572 + # have clock skew in their results.
2573 + test_grep section.big actual &&
2574 + test_grep section.number actual &&
2575 + test_grep "section.date=$(git config --type=expiry-date section.$key)" actual &&
2576 + test_cmp expecterr err
2577 +'
2578 +
2579 +test_expect_success 'list --type=color shows only canonicalizable color values' '
2580 + cat >expect <<-EOF &&
2581 + section.number=<>
2582 + section.red=<RED>
2583 + section.blue=<BLUE>
2584 + EOF
2585 +
2586 + cat >expecterr <<-EOF &&
2587 + error: invalid color value: True
2588 + error: invalid color value: 1M
2589 + error: invalid color value: ~/dir
2590 + error: invalid color value: Fri Jun 4 15:46:55 2010
2591 + error: invalid color value: :(optional)no-such-path
2592 + error: invalid color value: :(optional)expect
2593 + EOF
2594 +
2595 + git config ${mode_prefix}list --type=color >actual.raw 2>err &&
2596 + test_decode_color <actual.raw >actual &&
2597 + test_cmp expect actual &&
2598 + test_cmp expecterr err
2599 +'
2600 +
2601 test_expect_success '--type rejects unknown specifiers' '
2602 test_must_fail git config --type=nonsense section.foo 2>error &&
2603 test_grep "unrecognized --type argument" error