{"thread":{"id":"64153","subject":"[PATCH 0/13] unraveling the mysteries of color variables","startedAt":"2025-09-16T20:10:38Z","lastAt":"2025-09-16T23:14:00Z","messageCount":18,"participants":["Jeff King","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":13},"messages":[{"id":"526475","messageId":"20250916201036.GA612463@coredump.intra.peff.net","threadId":"64153","inReplyTo":null,"subject":"[PATCH 0/13] unraveling the mysteries of color variables","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-16T20:10:36Z","receivedAt":"2025-09-16T20:10:38Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"While reviewing the patches that were applied as jk/add-i-patch, Patrick\nnoted that we could be using GIT_COLOR_UNKNOWN in more places. I punted\nthere because I knew it would be a bit of a rabbit hole, and I think the\npatch count here perhaps justifies that view. ;)\n\nThe good news is that my digging did uncover two minor bugs, which are\nfixed here in patches 2 and 3. And the series should improve the\nreadability of the code by using named constants and appropriate types\nmore consistently.\n\nThe latter part of the series untangles some of the oddities related to\ncolor variables. I think the results are more readable, but they aren't\nstrictly necessary because of C's weak type system (and because we\ndefine our constants in a favorable way). The final patch is gross and\nshould not be applied, but I included it here as it explains how I was\nable to find all of the oddities.\n\n  [01/13]: color: use GIT_COLOR_* instead of numeric constants\n  [02/13]: color: return enum from git_config_colorbool()\n  [03/13]: grep: don't treat grep_opt.color as a strict bool\n  [04/13]: diff: simplify color_moved check when flushing\n  [05/13]: diff: don't use diff_options.use_color as a strict bool\n  [06/13]: diff: pass o->use_color directly to fill_metainfo()\n  [07/13]: diff: stop passing ecbdata->use_color as boolean\n  [08/13]: pretty: use format_commit_context.auto_color as colorbool\n  [09/13]: color: use git_colorbool enum to type to store colorbools\n  [10/13]: color: return bool from want_color()\n  [11/13]: add-interactive: retain colorbool values longer\n  [12/13]: config: store want_color() result in a separate bool\n  [13/13]: color: convert git_colorbool into a struct\n\n add-interactive.c     | 25 ++++++++++----------\n add-interactive.h     |  4 ++--\n advice.c              |  2 +-\n builtin/add.c         |  2 +-\n builtin/am.c          |  4 ++--\n builtin/branch.c      |  2 +-\n builtin/clean.c       |  2 +-\n builtin/commit.c      |  4 ++--\n builtin/config.c      | 27 +++++++++++-----------\n builtin/grep.c        |  2 +-\n builtin/log.c         |  4 ++--\n builtin/push.c        |  2 +-\n builtin/range-diff.c  |  3 ++-\n builtin/show-branch.c |  2 +-\n color.c               | 30 ++++++++++++------------\n color.h               | 15 +++++++-----\n combine-diff.c        |  2 +-\n diff.c                | 54 ++++++++++++++++++++-----------------------\n diff.h                |  5 ++--\n grep.c                |  4 ++--\n grep.h                |  4 ++--\n log-tree.c            |  4 ++--\n log-tree.h            |  2 +-\n parse-options-cb.c    |  6 ++---\n pretty.c              | 12 +++++-----\n pretty.h              |  3 ++-\n ref-filter.h          |  4 ++--\n sequencer.c           |  2 +-\n sideband.c            |  8 +++----\n transport.c           |  2 +-\n wt-status.c           |  6 ++---\n wt-status.h           |  2 +-\n 32 files changed, 127 insertions(+), 123 deletions(-)\n\n-Peff\n"},{"id":"526476","messageId":"20250916201235.GA612811@coredump.intra.peff.net","threadId":"64153","inReplyTo":"20250916201036.GA612463@coredump.intra.peff.net","subject":"Re: [PATCH 0/13] unraveling the mysteries of color variables","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-16T20:12:35Z","receivedAt":"2025-09-16T20:12:36Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Sep 16, 2025 at 04:10:37PM -0400, Jeff King wrote:\n\n>   [01/13]: color: use GIT_COLOR_* instead of numeric constants\n>   [02/13]: color: return enum from git_config_colorbool()\n>   [03/13]: grep: don't treat grep_opt.color as a strict bool\n>   [04/13]: diff: simplify color_moved check when flushing\n>   [05/13]: diff: don't use diff_options.use_color as a strict bool\n>   [06/13]: diff: pass o->use_color directly to fill_metainfo()\n>   [07/13]: diff: stop passing ecbdata->use_color as boolean\n>   [08/13]: pretty: use format_commit_context.auto_color as colorbool\n>   [09/13]: color: use git_colorbool enum to type to store colorbools\n>   [10/13]: color: return bool from want_color()\n>   [11/13]: add-interactive: retain colorbool values longer\n>   [12/13]: config: store want_color() result in a separate bool\n>   [13/13]: color: convert git_colorbool into a struct\n\nI forgot to mention that these should be applied on top of\njk/add-i-color. Patch 11 touches the same spot in a way that creates\nlots of conflicts (the problems there pre-date that recent topic, but it\nwas expanded from one color variable to two).\n\n-Peff\n"},{"id":"526478","messageId":"20250916201328.GA612873@coredump.intra.peff.net","threadId":"64153","inReplyTo":"20250916201036.GA612463@coredump.intra.peff.net","subject":"[PATCH 01/13] color: use GIT_COLOR_* instead of numeric constants","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-16T20:13:28Z","receivedAt":"2025-09-16T20:13:29Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Long ago Git's decision to show color for a subsytem was stored in a\ntri-state variable: it could be true (1), false (0), or unknown (-1).\nBut since daa0c3d971 (color: delay auto-color decision until point of\nuse, 2011-08-17) we want to carry around a new state, \"auto\", which\nbases the decision on the tty-ness of stdout (rather than collapsing\nthat \"auto\" state to a true/false immediately).\n\nThat commit introduced a set of GIT_COLOR_* defines to represent each\nstate: UNKNOWN, ALWAYS, NEVER, and AUTO. But it only used the AUTO\nvalue, and left alone code using bare 0/1/-1 values. And of course since\nthen we've grown many new spots that use those bare values.\n\nLet's switch all of these to use the named constants. That should make\nthe code a bit easier to read, as it is more obvious that we're\nrepresenting a color decision.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n add-interactive.c     |  9 +++++----\n advice.c              |  2 +-\n builtin/add.c         |  2 +-\n builtin/am.c          |  4 ++--\n builtin/branch.c      |  2 +-\n builtin/clean.c       |  2 +-\n builtin/commit.c      |  2 +-\n builtin/config.c      | 12 ++++++------\n builtin/grep.c        |  2 +-\n builtin/push.c        |  2 +-\n builtin/range-diff.c  |  3 ++-\n builtin/show-branch.c |  2 +-\n color.c               | 12 ++++++------\n diff.c                |  6 +++---\n grep.h                |  2 +-\n parse-options-cb.c    |  2 +-\n pretty.c              |  2 +-\n ref-filter.h          |  2 +-\n sideband.c            |  4 ++--\n transport.c           |  2 +-\n wt-status.c           |  6 +++---\n 21 files changed, 42 insertions(+), 40 deletions(-)\n\ndiff --git a/add-interactive.c b/add-interactive.c\nindex 4604c69140..34c020673e 100644\n--- a/add-interactive.c\n+++ b/add-interactive.c\n@@ -42,7 +42,7 @@ static int check_color_config(struct repository *r, const char *var)\n \tint ret;\n \n \tif (repo_config_get_value(r, var, &value))\n-\t\tret = -1;\n+\t\tret = GIT_COLOR_UNKNOWN;\n \telse\n \t\tret = git_config_colorbool(var, value);\n \n@@ -51,7 +51,8 @@ static int check_color_config(struct repository *r, const char *var)\n \t * the value parsed by git_color_config(), which may not have been\n \t * called by the main command.\n \t */\n-\tif (ret < 0 && !repo_config_get_value(r, \"color.ui\", &value))\n+\tif (ret == GIT_COLOR_UNKNOWN &&\n+\t    !repo_config_get_value(r, \"color.ui\", &value))\n \t\tret = git_config_colorbool(\"color.ui\", value);\n \n \treturn want_color(ret);\n@@ -130,8 +131,8 @@ void clear_add_i_state(struct add_i_state *s)\n \tFREE_AND_NULL(s->interactive_diff_filter);\n \tFREE_AND_NULL(s->interactive_diff_algorithm);\n \tmemset(s, 0, sizeof(*s));\n-\ts->use_color_interactive = -1;\n-\ts->use_color_diff = -1;\n+\ts->use_color_interactive = GIT_COLOR_UNKNOWN;\n+\ts->use_color_diff = GIT_COLOR_UNKNOWN;\n }\n \n /*\ndiff --git a/advice.c b/advice.c\nindex e5f0ff8449..a00aaad9de 100644\n--- a/advice.c\n+++ b/advice.c\n@@ -7,7 +7,7 @@\n #include \"help.h\"\n #include \"string-list.h\"\n \n-static int advice_use_color = -1;\n+static int advice_use_color = GIT_COLOR_UNKNOWN;\n static char advice_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n \tGIT_COLOR_YELLOW,\t/* HINT */\ndiff --git a/builtin/add.c b/builtin/add.c\nindex 740c7c4581..4cd3d183f9 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -200,7 +200,7 @@ static int edit_patch(struct repository *repo,\n \n \targc = setup_revisions(argc, argv, &rev, NULL);\n \trev.diffopt.output_format = DIFF_FORMAT_PATCH;\n-\trev.diffopt.use_color = 0;\n+\trev.diffopt.use_color = GIT_COLOR_NEVER;\n \trev.diffopt.flags.ignore_dirty_submodules = 1;\n \tout = xopen(file, O_CREAT | O_WRONLY | O_TRUNC, 0666);\n \trev.diffopt.file = xfdopen(out, \"w\");\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 6073d64ae9..277c2e7937 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -1408,7 +1408,7 @@ static void write_commit_patch(const struct am_state *state, struct commit *comm\n \trev_info.no_commit_id = 1;\n \trev_info.diffopt.flags.binary = 1;\n \trev_info.diffopt.flags.full_index = 1;\n-\trev_info.diffopt.use_color = 0;\n+\trev_info.diffopt.use_color = GIT_COLOR_NEVER;\n \trev_info.diffopt.file = fp;\n \trev_info.diffopt.close_file = 1;\n \tadd_pending_object(&rev_info, &commit->object, \"\");\n@@ -1441,7 +1441,7 @@ static void write_index_patch(const struct am_state *state)\n \trev_info.disable_stdin = 1;\n \trev_info.no_commit_id = 1;\n \trev_info.diffopt.output_format = DIFF_FORMAT_PATCH;\n-\trev_info.diffopt.use_color = 0;\n+\trev_info.diffopt.use_color = GIT_COLOR_NEVER;\n \trev_info.diffopt.file = fp;\n \trev_info.diffopt.close_file = 1;\n \tadd_pending_object(&rev_info, &tree->object, \"\");\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex fa5ced452e..029223df7b 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -46,7 +46,7 @@ static struct object_id head_oid;\n static int recurse_submodules = 0;\n static int submodule_propagate_branches = 0;\n \n-static int branch_use_color = -1;\n+static int branch_use_color = GIT_COLOR_UNKNOWN;\n static char branch_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n \tGIT_COLOR_NORMAL,       /* PLAIN */\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 38b67923a6..0ac90a3feb 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -64,7 +64,7 @@ static const char *color_interactive_slots[] = {\n \t[CLEAN_COLOR_RESET]  = \"reset\",\n };\n \n-static int clean_use_color = -1;\n+static int clean_use_color = GIT_COLOR_UNKNOWN;\n static char clean_colors[][COLOR_MAXLEN] = {\n \t[CLEAN_COLOR_ERROR] = GIT_COLOR_BOLD_RED,\n \t[CLEAN_COLOR_HEADER] = GIT_COLOR_BOLD,\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 8a5dee384d..544603a9c7 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -1016,7 +1016,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \t\tstatus_printf_ln(s, GIT_COLOR_NORMAL, \"%s\", \"\"); /* Add new line for clarity */\n \n \t\tsaved_color_setting = s->use_color;\n-\t\ts->use_color = 0;\n+\t\ts->use_color = GIT_COLOR_NEVER;\n \t\tcommittable = run_status(s->fp, index_file, prefix, 1, s);\n \t\ts->use_color = saved_color_setting;\n \t\tstring_list_clear_func(&s->change, change_data_free);\ndiff --git a/builtin/config.c b/builtin/config.c\nindex 59fb113b07..c3da3ae210 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -594,23 +594,23 @@ static int get_colorbool(const struct config_location_options *opts,\n {\n \tstruct get_colorbool_config_data data = {\n \t\t.get_colorbool_slot = var,\n-\t\t.get_colorbool_found = -1,\n-\t\t.get_diff_color_found = -1,\n-\t\t.get_color_ui_found = -1,\n+\t\t.get_colorbool_found = GIT_COLOR_UNKNOWN,\n+\t\t.get_diff_color_found = GIT_COLOR_UNKNOWN,\n+\t\t.get_color_ui_found = GIT_COLOR_UNKNOWN,\n \t};\n \n \tconfig_with_options(git_get_colorbool_config, &data,\n \t\t\t    &opts->source, the_repository,\n \t\t\t    &opts->options);\n \n-\tif (data.get_colorbool_found < 0) {\n+\tif (data.get_colorbool_found == GIT_COLOR_UNKNOWN) {\n \t\tif (!strcmp(data.get_colorbool_slot, \"color.diff\"))\n \t\t\tdata.get_colorbool_found = data.get_diff_color_found;\n-\t\tif (data.get_colorbool_found < 0)\n+\t\tif (data.get_colorbool_found == GIT_COLOR_UNKNOWN)\n \t\t\tdata.get_colorbool_found = data.get_color_ui_found;\n \t}\n \n-\tif (data.get_colorbool_found < 0)\n+\tif (data.get_colorbool_found == GIT_COLOR_UNKNOWN)\n \t\t/* default value if none found in config */\n \t\tdata.get_colorbool_found = GIT_COLOR_AUTO;\n \ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 5df6537333..1d97eb2a2a 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -1091,7 +1091,7 @@ int cmd_grep(int argc,\n \tif (show_in_pager == default_pager)\n \t\tshow_in_pager = git_pager(the_repository, 1);\n \tif (show_in_pager) {\n-\t\topt.color = 0;\n+\t\topt.color = GIT_COLOR_NEVER;\n \t\topt.name_only = 1;\n \t\topt.null_following_name = 1;\n \t\topt.output_priv = &path_list;\ndiff --git a/builtin/push.c b/builtin/push.c\nindex d0794b7b30..0962b122c7 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -27,7 +27,7 @@ static const char * const push_usage[] = {\n \tNULL,\n };\n \n-static int push_use_color = -1;\n+static int push_use_color = GIT_COLOR_UNKNOWN;\n static char push_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n \tGIT_COLOR_RED,\t/* ERROR */\ndiff --git a/builtin/range-diff.c b/builtin/range-diff.c\nindex a563abff5f..0d51ddd623 100644\n--- a/builtin/range-diff.c\n+++ b/builtin/range-diff.c\n@@ -6,6 +6,7 @@\n #include \"parse-options.h\"\n #include \"range-diff.h\"\n #include \"config.h\"\n+#include \"color.h\"\n \n \n static const char * const builtin_range_diff_usage[] = {\n@@ -66,7 +67,7 @@ int cmd_range_diff(int argc,\n \n \t/* force color when --dual-color was used */\n \tif (!simple_color)\n-\t\tdiffopt.use_color = 1;\n+\t\tdiffopt.use_color = GIT_COLOR_ALWAYS;\n \n \t/* If `--diff-merges` was specified, imply `--merges` */\n \tif (diff_merges_arg.nr) {\ndiff --git a/builtin/show-branch.c b/builtin/show-branch.c\nindex 1ab7db9d2c..970e78bc2d 100644\n--- a/builtin/show-branch.c\n+++ b/builtin/show-branch.c\n@@ -29,7 +29,7 @@ static const char*const show_branch_usage[] = {\n     NULL\n };\n \n-static int showbranch_use_color = -1;\n+static int showbranch_use_color = GIT_COLOR_UNKNOWN;\n \n static struct strvec default_args = STRVEC_INIT;\n \ndiff --git a/color.c b/color.c\nindex 7df8862c71..22aa453fef 100644\n--- a/color.c\n+++ b/color.c\n@@ -373,19 +373,19 @@ int git_config_colorbool(const char *var, const char *value)\n {\n \tif (value) {\n \t\tif (!strcasecmp(value, \"never\"))\n-\t\t\treturn 0;\n+\t\t\treturn GIT_COLOR_NEVER;\n \t\tif (!strcasecmp(value, \"always\"))\n-\t\t\treturn 1;\n+\t\t\treturn GIT_COLOR_ALWAYS;\n \t\tif (!strcasecmp(value, \"auto\"))\n \t\t\treturn GIT_COLOR_AUTO;\n \t}\n \n \tif (!var)\n-\t\treturn -1;\n+\t\treturn GIT_COLOR_UNKNOWN;\n \n \t/* Missing or explicit false to turn off colorization */\n \tif (!git_config_bool(var, value))\n-\t\treturn 0;\n+\t\treturn GIT_COLOR_NEVER;\n \n \t/* any normal truth value defaults to 'auto' */\n \treturn GIT_COLOR_AUTO;\n@@ -418,15 +418,15 @@ int want_color_fd(int fd, int var)\n \tif (fd < 1 || fd >= ARRAY_SIZE(want_auto))\n \t\tBUG(\"file descriptor out of range: %d\", fd);\n \n-\tif (var < 0)\n+\tif (var == GIT_COLOR_UNKNOWN)\n \t\tvar = git_use_color_default;\n \n \tif (var == GIT_COLOR_AUTO) {\n \t\tif (want_auto[fd] < 0)\n \t\t\twant_auto[fd] = check_auto_color(fd);\n \t\treturn want_auto[fd];\n \t}\n-\treturn var;\n+\treturn var == GIT_COLOR_ALWAYS;\n }\n \n int git_color_config(const char *var, const char *value, void *cb UNUSED)\ndiff --git a/diff.c b/diff.c\nindex 51603117a9..64a4bd23ea 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -57,7 +57,7 @@ static int diff_detect_rename_default;\n static int diff_indent_heuristic = 1;\n static int diff_rename_limit_default = 1000;\n static int diff_suppress_blank_empty;\n-static int diff_use_color_default = -1;\n+static int diff_use_color_default = GIT_COLOR_UNKNOWN;\n static int diff_color_moved_default;\n static int diff_color_moved_ws_default;\n static int diff_context_default = 3;\n@@ -5278,7 +5278,7 @@ static int diff_opt_color_words(const struct option *opt,\n \tstruct diff_options *options = opt->value;\n \n \tBUG_ON_OPT_NEG(unset);\n-\toptions->use_color = 1;\n+\toptions->use_color = GIT_COLOR_ALWAYS;\n \toptions->word_diff = DIFF_WORDS_COLOR;\n \toptions->word_regex = arg;\n \treturn 0;\n@@ -5600,7 +5600,7 @@ static int diff_opt_word_diff(const struct option *opt,\n \t\tif (!strcmp(arg, \"plain\"))\n \t\t\toptions->word_diff = DIFF_WORDS_PLAIN;\n \t\telse if (!strcmp(arg, \"color\")) {\n-\t\t\toptions->use_color = 1;\n+\t\t\toptions->use_color = GIT_COLOR_ALWAYS;\n \t\t\toptions->word_diff = DIFF_WORDS_COLOR;\n \t\t}\n \t\telse if (!strcmp(arg, \"porcelain\"))\ndiff --git a/grep.h b/grep.h\nindex 926c0875c4..43195baab3 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -198,7 +198,7 @@ struct grep_opt {\n \t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \\\n \t}, \\\n \t.only_matching = 0, \\\n-\t.color = -1, \\\n+\t.color = GIT_COLOR_UNKNOWN, \\\n \t.output = std_output, \\\n }\n \ndiff --git a/parse-options-cb.c b/parse-options-cb.c\nindex 50c8afe412..e13e0a9e33 100644\n--- a/parse-options-cb.c\n+++ b/parse-options-cb.c\n@@ -55,7 +55,7 @@ int parse_opt_color_flag_cb(const struct option *opt, const char *arg,\n \tif (!arg)\n \t\targ = unset ? \"never\" : (const char *)opt->defval;\n \tvalue = git_config_colorbool(NULL, arg);\n-\tif (value < 0)\n+\tif (value == GIT_COLOR_UNKNOWN)\n \t\treturn error(_(\"option `%s' expects \\\"always\\\", \\\"auto\\\", or \\\"never\\\"\"),\n \t\t\t     opt->long_name);\n \t*(int *)opt->value = value;\ndiff --git a/pretty.c b/pretty.c\nindex cee96b9d94..0521deadc0 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -1462,7 +1462,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */\n \t\t} else {\n \t\t\tint ret = parse_color(sb, placeholder, c);\n \t\t\tif (ret)\n-\t\t\t\tc->auto_color = 0;\n+\t\t\t\tc->auto_color = GIT_COLOR_NEVER;\n \t\t\t/*\n \t\t\t * Otherwise, we decided to treat %C<unknown>\n \t\t\t * as a literal string, and the previous\ndiff --git a/ref-filter.h b/ref-filter.h\nindex f22ca94b49..644f5c567c 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -111,7 +111,7 @@ struct ref_format {\n \t.exclude = STRVEC_INIT, \\\n }\n #define REF_FORMAT_INIT {             \\\n-\t.use_color = -1,              \\\n+\t.use_color = GIT_COLOR_UNKNOWN, \\\n }\n \n /*  Macros for checking --merged and --no-merged options */\ndiff --git a/sideband.c b/sideband.c\nindex 8f15b98a65..3ac87148b9 100644\n--- a/sideband.c\n+++ b/sideband.c\n@@ -29,14 +29,14 @@ static struct keyword_entry keywords[] = {\n /* Returns a color setting (GIT_COLOR_NEVER, etc). */\n static int use_sideband_colors(void)\n {\n-\tstatic int use_sideband_colors_cached = -1;\n+\tstatic int use_sideband_colors_cached = GIT_COLOR_UNKNOWN;\n \n \tconst char *key = \"color.remote\";\n \tstruct strbuf sb = STRBUF_INIT;\n \tconst char *value;\n \tint i;\n \n-\tif (use_sideband_colors_cached >= 0)\n+\tif (use_sideband_colors_cached != GIT_COLOR_UNKNOWN)\n \t\treturn use_sideband_colors_cached;\n \n \tif (!repo_config_get_string_tmp(the_repository, key, &value))\ndiff --git a/transport.c b/transport.c\nindex 6ac8aa402b..ea0be4503c 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -30,7 +30,7 @@\n #include \"color.h\"\n #include \"bundle-uri.h\"\n \n-static int transport_use_color = -1;\n+static int transport_use_color = GIT_COLOR_UNKNOWN;\n static char transport_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n \tGIT_COLOR_RED\t\t/* REJECTED */\ndiff --git a/wt-status.c b/wt-status.c\nindex 21dabab77d..8ffe6d3988 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -148,7 +148,7 @@ void wt_status_prepare(struct repository *r, struct wt_status *s)\n \tmemcpy(s->color_palette, default_wt_status_colors,\n \t       sizeof(default_wt_status_colors));\n \ts->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;\n-\ts->use_color = -1;\n+\ts->use_color = GIT_COLOR_UNKNOWN;\n \ts->relative_paths = 1;\n \ts->branch = refs_resolve_refdup(get_main_ref_store(the_repository),\n \t\t\t\t\t\"HEAD\", 0, NULL, NULL);\n@@ -1165,7 +1165,7 @@ static void wt_longstatus_print_verbose(struct wt_status *s)\n \t * before.\n \t */\n \tif (s->fp != stdout) {\n-\t\trev.diffopt.use_color = 0;\n+\t\trev.diffopt.use_color = GIT_COLOR_NEVER;\n \t\twt_status_add_cut_line(s);\n \t}\n \tif (s->verbose > 1 && s->committable) {\n@@ -2155,7 +2155,7 @@ static void wt_shortstatus_print(struct wt_status *s)\n \n static void wt_porcelain_print(struct wt_status *s)\n {\n-\ts->use_color = 0;\n+\ts->use_color = GIT_COLOR_NEVER;\n \ts->relative_paths = 0;\n \ts->prefix = NULL;\n \ts->no_gettext = 1;\n-- \n2.51.0.527.g34bc42dacd\n\n"},{"id":"526479","messageId":"20250916201407.GB612873@coredump.intra.peff.net","threadId":"64153","inReplyTo":"20250916201036.GA612463@coredump.intra.peff.net","subject":"[PATCH 02/13] color: return enum from git_config_colorbool()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-16T20:14:07Z","receivedAt":"2025-09-16T20:14:08Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"The git_config_colorbool() function returns an integer which is always\none of the GIT_COLOR_* constants UNKNOWN, NEVER, ALWAYS, or AUTO. We\ndefine these constants with macros, but let's switch to using an enum.\nEven though the compiler does not strictly enforce enum/int conversions,\nthis should make the intent clearer to human readers. And as a bonus,\nenum names are typically available to debuggers, making it more pleasant\nto step through the code there.\n\nThis patch updates the return type of git_config_colorbool(), but holds\noff on updating all of the callers. There's some trickiness to some of\nthem, and in the meantime it's perfectly fine to assign an enum into an\nint.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n color.c |  2 +-\n color.h | 12 +++++++-----\n 2 files changed, 8 insertions(+), 6 deletions(-)\n\ndiff --git a/color.c b/color.c\nindex 22aa453fef..f3adce0141 100644\n--- a/color.c\n+++ b/color.c\n@@ -369,7 +369,7 @@ int color_parse_mem(const char *value, int value_len, char *dst)\n #undef OUT\n }\n \n-int git_config_colorbool(const char *var, const char *value)\n+enum git_colorbool git_config_colorbool(const char *var, const char *value)\n {\n \tif (value) {\n \t\tif (!strcasecmp(value, \"never\"))\ndiff --git a/color.h b/color.h\nindex 7ed259a35b..303e2c9a6d 100644\n--- a/color.h\n+++ b/color.h\n@@ -73,10 +73,12 @@ struct strbuf;\n  * returned from git_config_colorbool. The \"auto\" value can be returned from\n  * config_colorbool, and will be converted by want_color() into either 0 or 1.\n  */\n-#define GIT_COLOR_UNKNOWN -1\n-#define GIT_COLOR_NEVER  0\n-#define GIT_COLOR_ALWAYS 1\n-#define GIT_COLOR_AUTO   2\n+enum git_colorbool {\n+\tGIT_COLOR_UNKNOWN = -1,\n+\tGIT_COLOR_NEVER = 0,\n+\tGIT_COLOR_ALWAYS = 1,\n+\tGIT_COLOR_AUTO = 2,\n+};\n \n /* A default list of colors to use for commit graphs and show-branch output */\n extern const char *column_colors_ansi[];\n@@ -98,7 +100,7 @@ int git_color_config(const char *var, const char *value, void *cb);\n  * GIT_COLOR_ALWAYS for \"always\" or a positive boolean,\n  * and GIT_COLOR_AUTO for \"auto\".\n  */\n-int git_config_colorbool(const char *var, const char *value);\n+enum git_colorbool git_config_colorbool(const char *var, const char *value);\n \n /*\n  * Return a boolean whether to use color, where the argument 'var' is\n-- \n2.51.0.527.g34bc42dacd\n\n"},{"id":"526480","messageId":"20250916201600.GC612873@coredump.intra.peff.net","threadId":"64153","inReplyTo":"20250916201036.GA612463@coredump.intra.peff.net","subject":"[PATCH 03/13] grep: don't treat grep_opt.color as a strict bool","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-16T20:16:00Z","receivedAt":"2025-09-16T20:16:01Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"In show_line(), we check to see if colors are desired with just:\n\n  if (opt->color)\n     ...we want colors...\n\nBut this is incorrect. The color field here is really a git_colorbool,\nso it may be \"true\" for GIT_COLOR_UNKNOWN or GIT_COLOR_AUTO. Either of\nthose _might_ end up true eventually (once we apply default fallbacks\nand check stdout's tty), but they may not. E.g.:\n\n  git grep foo | cat\n\nwill enter the conditional even though we're not going to show colors.\nWe should collapse it into a true boolean by calling want_color().\n\nIt turns out that this does not produce a user-visible bug. We do some\nextra processing to isolate the matched portion of the line in order to\ncolorize it, but ultimately we pass it to our output_color() helper,\nwhich does correctly check want_color(). So we end up with no colors.\n\nBut dropping the extra processing saves a measurable amount of time. For\nexample, running under hyperfine (which redirects to /dev/null, and thus\ndoes not colorize):\n\n  Benchmark 1: ./git.old grep a\n    Time (mean ± σ):      58.7 ms ±   3.5 ms    [User: 580.6 ms, System: 74.3 ms]\n    Range (min … max):    53.5 ms …  67.1 ms    48 runs\n\n  Benchmark 2: ./git.new grep a\n    Time (mean ± σ):      35.5 ms ±   0.9 ms    [User: 276.8 ms, System: 73.8 ms]\n    Range (min … max):    34.3 ms …  39.3 ms    79 runs\n\n  Summary\n    ./git.new grep a ran\n      1.65 ± 0.11 times faster than ./git.old grep a\n\nThat's a fairly extreme benchmark, just because it will come up with a\nton of small matches, but it shows that this really does matter.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nIf you really want to cheat on the benchmark, grep for a single space,\nwhich is even more common.\n\n grep.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/grep.c b/grep.c\nindex 932647e4a6..c7e1dc1e0e 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -1263,12 +1263,12 @@ static void show_line(struct grep_opt *opt,\n \t\t */\n \t\tshow_line_header(opt, name, lno, cno, sign);\n \t}\n-\tif (opt->color || opt->only_matching) {\n+\tif (want_color(opt->color) || opt->only_matching) {\n \t\tregmatch_t match;\n \t\tenum grep_context ctx = GREP_CONTEXT_BODY;\n \t\tint eflags = 0;\n \n-\t\tif (opt->color) {\n+\t\tif (want_color(opt->color)) {\n \t\t\tif (sign == ':')\n \t\t\t\tmatch_color = opt->colors[GREP_COLOR_MATCH_SELECTED];\n \t\t\telse\n-- \n2.51.0.527.g34bc42dacd\n\n"},{"id":"526481","messageId":"20250916201719.GD612873@coredump.intra.peff.net","threadId":"64153","inReplyTo":"20250916201036.GA612463@coredump.intra.peff.net","subject":"[PATCH 04/13] diff: simplify color_moved check when flushing","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-16T20:17:19Z","receivedAt":"2025-09-16T20:17:20Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"In diff_flush_patch_all_file_pairs(), we set o->emitted_symbols if and\nonly if o->color_moved is true. That causes the lower-level routines to\nfill up o->emitted_symbols, which we then analyze in order to do the\nactual colorizing.\n\nBut in that final step, we do:\n\n  if (o->emitted_symbols) {\n          if (o->color_moved) {\n\t     ...actual coloring...\n\t  }\n\t  ...clean up of emitted_symbols...\n  }\n\nThe inner \"if\" will always trigger, since we set emitted_symbols only\nwhen doing color_moved (it is a little confusing that it is set inside\nthe diff_options struct, but that is for convenience of passing it to\nthe lower-level routines; we always clear it at the end of flushing,\nsince 48edf3a02a (diff: clear emitted_symbols flag after use,\n2019-01-24)).\n\nLet's simplify the code a bit by just dropping the inner \"if\" and\nrunning its block unconditionally.\n\nIn theory the current code might be useful if another feature besides\ncolor_moved setup and used emitted_symbols, but it would be easy to\nrefactor later to handle that. And in the meantime, this makes further\nwork in this area easier.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n diff.c | 25 +++++++++++--------------\n 1 file changed, 11 insertions(+), 14 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 64a4bd23ea..e6c85c8491 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -6746,20 +6746,17 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o)\n \t}\n \n \tif (o->emitted_symbols) {\n-\t\tif (o->color_moved) {\n-\t\t\tstruct mem_pool entry_pool;\n-\t\t\tstruct moved_entry_list *entry_list;\n-\n-\t\t\tmem_pool_init(&entry_pool, 1024 * 1024);\n-\t\t\tentry_list = add_lines_to_move_detection(o,\n-\t\t\t\t\t\t\t\t &entry_pool);\n-\t\t\tmark_color_as_moved(o, entry_list);\n-\t\t\tif (o->color_moved == COLOR_MOVED_ZEBRA_DIM)\n-\t\t\t\tdim_moved_lines(o);\n-\n-\t\t\tmem_pool_discard(&entry_pool, 0);\n-\t\t\tfree(entry_list);\n-\t\t}\n+\t\tstruct mem_pool entry_pool;\n+\t\tstruct moved_entry_list *entry_list;\n+\n+\t\tmem_pool_init(&entry_pool, 1024 * 1024);\n+\t\tentry_list = add_lines_to_move_detection(o, &entry_pool);\n+\t\tmark_color_as_moved(o, entry_list);\n+\t\tif (o->color_moved == COLOR_MOVED_ZEBRA_DIM)\n+\t\t\tdim_moved_lines(o);\n+\n+\t\tmem_pool_discard(&entry_pool, 0);\n+\t\tfree(entry_list);\n \n \t\tfor (i = 0; i < esm.nr; i++)\n \t\t\temit_diff_symbol_from_struct(o, &esm.buf[i]);\n-- \n2.51.0.527.g34bc42dacd\n\n"},{"id":"526482","messageId":"20250916201933.GE612873@coredump.intra.peff.net","threadId":"64153","inReplyTo":"20250916201036.GA612463@coredump.intra.peff.net","subject":"[PATCH 05/13] diff: don't use diff_options.use_color as a strict bool","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-16T20:19:33Z","receivedAt":"2025-09-16T20:19:34Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We disable --color-moved if color is not in use at all. This happens in\ndiff_setup_done(), where we set options->color_moved to 0 if\noptions->use_color is not true. But a strict boolean check here is not\ncorrect; use_color could be GIT_COLOR_UNKNOWN or GIT_COLOR_AUTO, both of\nwhich evaluate to true, even though we may later decide not to show\ncolors.\n\nWe should be using want_color() to convert that git_colorbool into a\ntrue boolean. As it turns out, this does not produce wrong output. Even\nthough we go to the trouble to detect the moved lines, ultimately we get\nthe color values from diff_get_color(), which does check want_color().\nAnd so it returns the empty string for each color, and we \"color\" the\nresult with nothing.\n\nSo the output is correct, but there is a small but measurable\nperformance cost to doing the line detection. E.g., in git.git before\nand after this patch (there are no colors shown because hyperfine\nredirects output to /dev/null):\n\n  Benchmark 1: ./git.old log --no-merges -p --color-moved -1000\n    Time (mean ± σ):      1.019 s ±  0.013 s    [User: 0.955 s, System: 0.064 s]\n    Range (min … max):    1.005 s …  1.045 s    10 runs\n\n  Benchmark 2: ./git.new log --no-merges -p --color-moved -1000\n    Time (mean ± σ):     982.9 ms ±  14.5 ms    [User: 925.8 ms, System: 57.1 ms]\n    Range (min … max):   965.1 ms … 1003.2 ms    10 runs\n\n  Summary\n    ./git.new log --no-merges -p --color-moved -1000 ran\n      1.04 ± 0.02 times faster than ./git.old log --no-merges -p --color-moved -1000\n\nNote that the fix is not quite as simple as just calling want_color()\nfrom diff_setup_done(). There's a subtle timing issue that goes back to\ndaa0c3d971 (color: delay auto-color decision until point of use,\n2011-08-17), the commit that adds want_color() in the first place.  As\ndiscussed there, we must delay evaluating the colorbool value until all\npager setup is complete.\n\nSo instead, we'll leave the \"color_moved\" field intact in diff_setup_done(),\nand modify the point where it is evaluated. Fortunately there is only\none such spot that controls whether we run any of the color-moved code\nat all.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n diff.c | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex e6c85c8491..cc3542e7f4 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -4995,8 +4995,7 @@ void diff_setup_done(struct diff_options *options)\n \tif (options->flags.follow_renames)\n \t\tdiff_check_follow_pathspec(&options->pathspec, 1);\n \n-\tif (!options->use_color ||\n-\t    (options->flags.allow_external && external_diff()))\n+\tif (options->flags.allow_external && external_diff())\n \t\toptions->color_moved = 0;\n \n \tif (options->filter_not) {\n@@ -6733,7 +6732,7 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o)\n \tif (WSEH_NEW & WS_RULE_MASK)\n \t\tBUG(\"WS rules bit mask overlaps with diff symbol flags\");\n \n-\tif (o->color_moved)\n+\tif (o->color_moved && want_color(o->use_color))\n \t\to->emitted_symbols = &esm;\n \n \tif (o->additional_path_headers)\n-- \n2.51.0.527.g34bc42dacd\n\n"},{"id":"526483","messageId":"20250916202026.GF612873@coredump.intra.peff.net","threadId":"64153","inReplyTo":"20250916201036.GA612463@coredump.intra.peff.net","subject":"[PATCH 06/13] diff: pass o->use_color directly to fill_metainfo()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-16T20:20:26Z","receivedAt":"2025-09-16T20:20:27Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We pass the use_color parameter of fill_metainfo() as a strict boolean,\nusing:\n\n  want_color(o->use_color) && !pgm\n\nto derive its value. But then inside the function, we pass it to\ndiff_get_color(), which expects one of the git_colorbool enum values,\nand so feeds it to want_color() again.\n\nEven though want_color() produces a strict 0/1 boolean, this doesn't\nproduce wrong results because want_color() is idempotent. Since\nGIT_COLOR_ALWAYS and NEVER are defined as 1 and 0, and because\nwant_color() passes through those values, evaluating \"want_color(foo)\"\nand \"want_color(want_color(foo))\" will return the same result.\n\nBut as part of a longer strategy to align the types we use for storing\nthese values, let's pass through the colorbool directly. To handle the\n\"&&\" case here, we'll convert the presence of \"pgm\" into \"NEVER\", which\narguably makes the intent of the code more clear anyway.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n diff.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/diff.c b/diff.c\nindex cc3542e7f4..6b12596642 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -4596,7 +4596,7 @@ static void run_diff_cmd(const struct external_diff *pgm,\n \t\t */\n \t\tfill_metainfo(msg, name, other, one, two, o, p,\n \t\t\t      &must_show_header,\n-\t\t\t      want_color(o->use_color) && !pgm);\n+\t\t\t      pgm ? GIT_COLOR_NEVER : o->use_color);\n \t\txfrm_msg = msg->len ? msg->buf : NULL;\n \t}\n \n-- \n2.51.0.527.g34bc42dacd\n\n"},{"id":"526484","messageId":"20250916202120.GG612873@coredump.intra.peff.net","threadId":"64153","inReplyTo":"20250916201036.GA612463@coredump.intra.peff.net","subject":"[PATCH 07/13] diff: stop passing ecbdata->use_color as boolean","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-16T20:21:20Z","receivedAt":"2025-09-16T20:21:21Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"In emit_hunk_header(), we evaluate ecbdata->color_diff both as a\ngit_colorbool, passing it to diff_get_color():\n\n  const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);\n\nand as a strict boolean:\n\n  const char *reverse = ecbdata->color_diff ? GIT_COLOR_REVERSE : \"\";\n\nAt first glance this seems wrong. Usually we store the color decision as\na git_colorbool, so the second line would get confused by GIT_COLOR_AUTO\n(which is boolean true, but may still mean we do not produce color).\n\nHowever, the second line is correct because our caller sets color_diff\nusing want_color(), which collapses the colorbool to a strict true/false\nboolean. The first line is _also_ correct because of the idempotence of\nwant_color(). Even though diff_get_color() will pass our true/false\nvalue through want_color() again, the result will be left untouched.\n\nBut let's pass through the colorbool itself, which makes it more\nconsistent with the rest of the diff code. We'll need to then call\nwant_color() whenever we treat it as a boolean, but there is only such\nspot (the one quoted above).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n diff.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 6b12596642..926429d55b 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1672,7 +1672,7 @@ static void emit_hunk_header(struct emit_callback *ecbdata,\n \tconst char *frag = diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO);\n \tconst char *func = diff_get_color(ecbdata->color_diff, DIFF_FUNCINFO);\n \tconst char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);\n-\tconst char *reverse = ecbdata->color_diff ? GIT_COLOR_REVERSE : \"\";\n+\tconst char *reverse = want_color(ecbdata->color_diff) ? GIT_COLOR_REVERSE : \"\";\n \tstatic const char atat[2] = { '@', '@' };\n \tconst char *cp, *ep;\n \tstruct strbuf msgbuf = STRBUF_INIT;\n@@ -1826,7 +1826,7 @@ static void emit_rewrite_diff(const char *name_a,\n \tsize_two = fill_textconv(o->repo, textconv_two, two, &data_two);\n \n \tmemset(&ecbdata, 0, sizeof(ecbdata));\n-\tecbdata.color_diff = want_color(o->use_color);\n+\tecbdata.color_diff = o->use_color;\n \tecbdata.ws_rule = whitespace_rule(o->repo->index, name_b);\n \tecbdata.opt = o;\n \tif (ecbdata.ws_rule & WS_BLANK_AT_EOF) {\n@@ -3732,7 +3732,7 @@ static void builtin_diff(const char *name_a,\n \t\tif (o->flags.suppress_diff_headers)\n \t\t\tlbl[0] = NULL;\n \t\tecbdata.label_path = lbl;\n-\t\tecbdata.color_diff = want_color(o->use_color);\n+\t\tecbdata.color_diff = o->use_color;\n \t\tecbdata.ws_rule = whitespace_rule(o->repo->index, name_b);\n \t\tif (ecbdata.ws_rule & WS_BLANK_AT_EOF)\n \t\t\tcheck_blank_at_eof(&mf1, &mf2, &ecbdata);\n-- \n2.51.0.527.g34bc42dacd\n\n"},{"id":"526485","messageId":"20250916202226.GH612873@coredump.intra.peff.net","threadId":"64153","inReplyTo":"20250916201036.GA612463@coredump.intra.peff.net","subject":"[PATCH 08/13] pretty: use format_commit_context.auto_color as colorbool","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-16T20:22:26Z","receivedAt":"2025-09-16T20:22:27Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"When we see \"%C(auto)\" as a format placeholder, we evaluate the \"color\"\nfield of our pretty_print_context to decide whether we want color. The\nauto_color field of format_commit_context then stores the boolean result\nof want_color(), telling us the yes/no of whether we want color.\n\nBut the resulting field is passed to various functions which expect a\ngit_colorbool, like diff_get_color(), that will then pass it to\nwant_color() again. It's not wrong to do so, since want_color() is\nidempotent. But it makes it harder to reason about the types, since we\nsometimes confuse colorbools and strict booleans.\n\nLet's instead store auto_color as the original colorbool itself. We'll\nhave to make sure it is passed through want_color() when it is\nevaluated, but there is only one such spot (right next to where we\nassign it!). Every other caller just ends up passing it to get\ndiff_get_color() either directly or through another helper.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n pretty.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/pretty.c b/pretty.c\nindex 0521deadc0..86d69bf877 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -1455,8 +1455,8 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */\n \tswitch (placeholder[0]) {\n \tcase 'C':\n \t\tif (starts_with(placeholder + 1, \"(auto)\")) {\n-\t\t\tc->auto_color = want_color(c->pretty_ctx->color);\n-\t\t\tif (c->auto_color && sb->len)\n+\t\t\tc->auto_color = c->pretty_ctx->color;\n+\t\t\tif (want_color(c->auto_color) && sb->len)\n \t\t\t\tstrbuf_addstr(sb, GIT_COLOR_RESET);\n \t\t\treturn 7; /* consumed 7 bytes, \"C(auto)\" */\n \t\t} else {\n-- \n2.51.0.527.g34bc42dacd\n\n"},{"id":"526486","messageId":"20250916202408.GI612873@coredump.intra.peff.net","threadId":"64153","inReplyTo":"20250916201036.GA612463@coredump.intra.peff.net","subject":"[PATCH 09/13] color: use git_colorbool enum to type to store colorbools","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-16T20:24:08Z","receivedAt":"2025-09-16T20:24:10Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We traditionally used \"int\" to store and pass around the values defined\nby \"enum git_colorbool\" (which were originally just #define macros).\nUsing an int doesn't produce incorrect results, but using the actual\nenum makes the intent of the code more clear.\n\nIt would be nice if the compiler could catch cases where we used the\nenum and an int interchangeably, since it's very easy to accidentally\ncheck the boolean true/false of a colorbool like:\n\n  if (branch_use_color)\n\nThis is wrong because GIT_COLOR_UNKNOWN and GIT_COLOR_AUTO evaluate to\ntrue in C, even though we may ultimately decide not to use color. But C\nis pretty happy to convert between ints and enums (even with various\n-Wenum-* warnings). So this sadly doesn't protect us from such mistakes,\nbut it hopefully does make the code easier to read.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nThis actually could come sooner in the series, since the compiler will\nnot complain about conversions either way. But I thought it made sense to\nclean up the weird spots first.\n\n add-interactive.c     | 2 +-\n advice.c              | 2 +-\n builtin/branch.c      | 2 +-\n builtin/clean.c       | 2 +-\n builtin/commit.c      | 2 +-\n builtin/config.c      | 6 +++---\n builtin/push.c        | 2 +-\n builtin/show-branch.c | 2 +-\n color.c               | 4 ++--\n color.h               | 2 +-\n combine-diff.c        | 2 +-\n diff.c                | 6 +++---\n diff.h                | 5 +++--\n grep.h                | 2 +-\n log-tree.c            | 4 ++--\n log-tree.h            | 2 +-\n parse-options-cb.c    | 2 +-\n pretty.c              | 6 +++---\n pretty.h              | 3 ++-\n ref-filter.h          | 2 +-\n sideband.c            | 4 ++--\n transport.c           | 2 +-\n wt-status.h           | 2 +-\n 23 files changed, 35 insertions(+), 33 deletions(-)\n\ndiff --git a/add-interactive.c b/add-interactive.c\nindex 34c020673e..000315971e 100644\n--- a/add-interactive.c\n+++ b/add-interactive.c\n@@ -39,7 +39,7 @@ static void init_color(struct repository *r, int use_color,\n static int check_color_config(struct repository *r, const char *var)\n {\n \tconst char *value;\n-\tint ret;\n+\tenum git_colorbool ret;\n \n \tif (repo_config_get_value(r, var, &value))\n \t\tret = GIT_COLOR_UNKNOWN;\ndiff --git a/advice.c b/advice.c\nindex a00aaad9de..0018501b7b 100644\n--- a/advice.c\n+++ b/advice.c\n@@ -7,7 +7,7 @@\n #include \"help.h\"\n #include \"string-list.h\"\n \n-static int advice_use_color = GIT_COLOR_UNKNOWN;\n+static enum git_colorbool advice_use_color = GIT_COLOR_UNKNOWN;\n static char advice_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n \tGIT_COLOR_YELLOW,\t/* HINT */\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 029223df7b..9fcf04bebb 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -46,7 +46,7 @@ static struct object_id head_oid;\n static int recurse_submodules = 0;\n static int submodule_propagate_branches = 0;\n \n-static int branch_use_color = GIT_COLOR_UNKNOWN;\n+static enum git_colorbool branch_use_color = GIT_COLOR_UNKNOWN;\n static char branch_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n \tGIT_COLOR_NORMAL,       /* PLAIN */\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 0ac90a3feb..1d5e7e5366 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -64,7 +64,7 @@ static const char *color_interactive_slots[] = {\n \t[CLEAN_COLOR_RESET]  = \"reset\",\n };\n \n-static int clean_use_color = GIT_COLOR_UNKNOWN;\n+static enum git_colorbool clean_use_color = GIT_COLOR_UNKNOWN;\n static char clean_colors[][COLOR_MAXLEN] = {\n \t[CLEAN_COLOR_ERROR] = GIT_COLOR_BOLD_RED,\n \t[CLEAN_COLOR_HEADER] = GIT_COLOR_BOLD,\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 544603a9c7..d8f21a4c62 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -936,7 +936,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \tstrbuf_addstr(&committer_ident, git_committer_info(IDENT_STRICT));\n \tif (use_editor && include_status) {\n \t\tint ident_shown = 0;\n-\t\tint saved_color_setting;\n+\t\tenum git_colorbool saved_color_setting;\n \t\tstruct ident_split ci, ai;\n \t\tconst char *hint_cleanup_all = allow_empty_message ?\n \t\t\t_(\"Please enter the commit message for your changes.\"\ndiff --git a/builtin/config.c b/builtin/config.c\nindex c3da3ae210..9e4e4eb2f1 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -568,9 +568,9 @@ static void get_color(const struct config_location_options *opts,\n }\n \n struct get_colorbool_config_data {\n-\tint get_colorbool_found;\n-\tint get_diff_color_found;\n-\tint get_color_ui_found;\n+\tenum git_colorbool get_colorbool_found;\n+\tenum git_colorbool get_diff_color_found;\n+\tenum git_colorbool get_color_ui_found;\n \tconst char *get_colorbool_slot;\n };\n \ndiff --git a/builtin/push.c b/builtin/push.c\nindex 0962b122c7..5b6cebbb85 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -27,7 +27,7 @@ static const char * const push_usage[] = {\n \tNULL,\n };\n \n-static int push_use_color = GIT_COLOR_UNKNOWN;\n+static enum git_colorbool push_use_color = GIT_COLOR_UNKNOWN;\n static char push_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n \tGIT_COLOR_RED,\t/* ERROR */\ndiff --git a/builtin/show-branch.c b/builtin/show-branch.c\nindex 970e78bc2d..441babf2e3 100644\n--- a/builtin/show-branch.c\n+++ b/builtin/show-branch.c\n@@ -29,7 +29,7 @@ static const char*const show_branch_usage[] = {\n     NULL\n };\n \n-static int showbranch_use_color = GIT_COLOR_UNKNOWN;\n+static enum git_colorbool showbranch_use_color = GIT_COLOR_UNKNOWN;\n \n static struct strvec default_args = STRVEC_INIT;\n \ndiff --git a/color.c b/color.c\nindex f3adce0141..3348ead534 100644\n--- a/color.c\n+++ b/color.c\n@@ -9,7 +9,7 @@\n #include \"pager.h\"\n #include \"strbuf.h\"\n \n-static int git_use_color_default = GIT_COLOR_AUTO;\n+static enum git_colorbool git_use_color_default = GIT_COLOR_AUTO;\n int color_stdout_is_tty = -1;\n \n /*\n@@ -404,7 +404,7 @@ static int check_auto_color(int fd)\n \treturn 0;\n }\n \n-int want_color_fd(int fd, int var)\n+int want_color_fd(int fd, enum git_colorbool var)\n {\n \t/*\n \t * NEEDSWORK: This function is sometimes used from multiple threads, and\ndiff --git a/color.h b/color.h\nindex 303e2c9a6d..fcb38c5562 100644\n--- a/color.h\n+++ b/color.h\n@@ -106,7 +106,7 @@ enum git_colorbool git_config_colorbool(const char *var, const char *value);\n  * Return a boolean whether to use color, where the argument 'var' is\n  * one of GIT_COLOR_UNKNOWN, GIT_COLOR_NEVER, GIT_COLOR_ALWAYS, GIT_COLOR_AUTO.\n  */\n-int want_color_fd(int fd, int var);\n+int want_color_fd(int fd, enum git_colorbool var);\n #define want_color(colorbool) want_color_fd(1, (colorbool))\n #define want_color_stderr(colorbool) want_color_fd(2, (colorbool))\n \ndiff --git a/combine-diff.c b/combine-diff.c\nindex 3878faabe7..21b7fdfff4 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -749,7 +749,7 @@ static void show_line_to_eol(const char *line, int len, const char *reset)\n \n static void dump_sline(struct sline *sline, const char *line_prefix,\n \t\t       unsigned long cnt, int num_parent,\n-\t\t       int use_color, int result_deleted)\n+\t\t       enum git_colorbool use_color, int result_deleted)\n {\n \tunsigned long mark = (1UL<<num_parent);\n \tunsigned long no_pre_delete = (2UL<<num_parent);\ndiff --git a/diff.c b/diff.c\nindex 926429d55b..87fa16b730 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -57,7 +57,7 @@ static int diff_detect_rename_default;\n static int diff_indent_heuristic = 1;\n static int diff_rename_limit_default = 1000;\n static int diff_suppress_blank_empty;\n-static int diff_use_color_default = GIT_COLOR_UNKNOWN;\n+static enum git_colorbool diff_use_color_default = GIT_COLOR_UNKNOWN;\n static int diff_color_moved_default;\n static int diff_color_moved_ws_default;\n static int diff_context_default = 3;\n@@ -2303,7 +2303,7 @@ static void free_diff_words_data(struct emit_callback *ecbdata)\n \t}\n }\n \n-const char *diff_get_color(int diff_use_color, enum color_diff ix)\n+const char *diff_get_color(enum git_colorbool diff_use_color, enum color_diff ix)\n {\n \tif (want_color(diff_use_color))\n \t\treturn diff_colors[ix];\n@@ -4497,7 +4497,7 @@ static void fill_metainfo(struct strbuf *msg,\n \t\t\t  struct diff_options *o,\n \t\t\t  struct diff_filepair *p,\n \t\t\t  int *must_show_header,\n-\t\t\t  int use_color)\n+\t\t\t  enum git_colorbool use_color)\n {\n \tconst char *set = diff_get_color(use_color, DIFF_METAINFO);\n \tconst char *reset = diff_get_color(use_color, DIFF_RESET);\ndiff --git a/diff.h b/diff.h\nindex 9bb939a4f1..bccd86a748 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -7,6 +7,7 @@\n #include \"hash.h\"\n #include \"pathspec.h\"\n #include \"strbuf.h\"\n+#include \"color.h\"\n \n struct oidset;\n \n@@ -283,7 +284,7 @@ struct diff_options {\n \t/* diff-filter bits */\n \tunsigned int filter, filter_not;\n \n-\tint use_color;\n+\tenum git_colorbool use_color;\n \n \t/* Number of context lines to generate in patch output. */\n \tint context;\n@@ -469,7 +470,7 @@ enum color_diff {\n \tDIFF_FILE_NEW_BOLD = 22,\n };\n \n-const char *diff_get_color(int diff_use_color, enum color_diff ix);\n+const char *diff_get_color(enum git_colorbool diff_use_color, enum color_diff ix);\n #define diff_get_color_opt(o, ix) \\\n \tdiff_get_color((o)->use_color, ix)\n \ndiff --git a/grep.h b/grep.h\nindex 43195baab3..13e26a9318 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -159,7 +159,7 @@ struct grep_opt {\n \tint pathname;\n \tint null_following_name;\n \tint only_matching;\n-\tint color;\n+\tenum git_colorbool color;\n \tint max_depth;\n \tint funcname;\n \tint funcbody;\ndiff --git a/log-tree.c b/log-tree.c\nindex 233bf9f227..a2cd5c587b 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -57,7 +57,7 @@ static const char *color_decorate_slots[] = {\n \t[DECORATION_GRAFTED]\t= \"grafted\",\n };\n \n-static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix)\n+static const char *decorate_get_color(enum git_colorbool decorate_use_color, enum decoration_type ix)\n {\n \tif (want_color(decorate_use_color))\n \t\treturn decoration_colors[ix];\n@@ -341,7 +341,7 @@ static void show_name(struct strbuf *sb, const struct name_decoration *decoratio\n  */\n void format_decorations(struct strbuf *sb,\n \t\t\tconst struct commit *commit,\n-\t\t\tint use_color,\n+\t\t\tenum git_colorbool use_color,\n \t\t\tconst struct decoration_options *opts)\n {\n \tconst struct name_decoration *decoration;\ndiff --git a/log-tree.h b/log-tree.h\nindex ebe491c543..1c82380d95 100644\n--- a/log-tree.h\n+++ b/log-tree.h\n@@ -26,7 +26,7 @@ int log_tree_diff_flush(struct rev_info *);\n int log_tree_commit(struct rev_info *, struct commit *);\n void show_log(struct rev_info *opt);\n void format_decorations(struct strbuf *sb, const struct commit *commit,\n-\t\t\tint use_color, const struct decoration_options *opts);\n+\t\t\tenum git_colorbool use_color, const struct decoration_options *opts);\n void show_decorations(struct rev_info *opt, struct commit *commit);\n void log_write_email_headers(struct rev_info *opt, struct commit *commit,\n \t\t\t     char **extra_headers_p,\ndiff --git a/parse-options-cb.c b/parse-options-cb.c\nindex e13e0a9e33..976cc86385 100644\n--- a/parse-options-cb.c\n+++ b/parse-options-cb.c\n@@ -50,7 +50,7 @@ int parse_opt_expiry_date_cb(const struct option *opt, const char *arg,\n int parse_opt_color_flag_cb(const struct option *opt, const char *arg,\n \t\t\t    int unset)\n {\n-\tint value;\n+\tenum git_colorbool value;\n \n \tif (!arg)\n \t\targ = unset ? \"never\" : (const char *)opt->defval;\ndiff --git a/pretty.c b/pretty.c\nindex 86d69bf877..e0646bbc5d 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -470,7 +470,7 @@ static inline void strbuf_add_with_color(struct strbuf *sb, const char *color,\n \n static void append_line_with_color(struct strbuf *sb, struct grep_opt *opt,\n \t\t\t\t   const char *line, size_t linelen,\n-\t\t\t\t   int color, enum grep_context ctx,\n+\t\t\t\t   enum git_colorbool color, enum grep_context ctx,\n \t\t\t\t   enum grep_header_field field)\n {\n \tconst char *buf, *eol, *line_color, *match_color;\n@@ -899,7 +899,7 @@ struct format_commit_context {\n \tconst char *message;\n \tchar *commit_encoding;\n \tsize_t width, indent1, indent2;\n-\tint auto_color;\n+\tenum git_colorbool auto_color;\n \tint padding;\n \n \t/* These offsets are relative to the start of the commit message. */\n@@ -2167,7 +2167,7 @@ static int pp_utf8_width(const char *start, const char *end)\n }\n \n static void strbuf_add_tabexpand(struct strbuf *sb, struct grep_opt *opt,\n-\t\t\t\t int color, int tabwidth, const char *line,\n+\t\t\t\t enum git_colorbool color, int tabwidth, const char *line,\n \t\t\t\t int linelen)\n {\n \tconst char *tab;\ndiff --git a/pretty.h b/pretty.h\nindex df267afe4a..fac699033e 100644\n--- a/pretty.h\n+++ b/pretty.h\n@@ -3,6 +3,7 @@\n \n #include \"date.h\"\n #include \"string-list.h\"\n+#include \"color.h\"\n \n struct commit;\n struct repository;\n@@ -46,7 +47,7 @@ struct pretty_print_context {\n \tstruct rev_info *rev;\n \tconst char *output_encoding;\n \tstruct string_list *mailmap;\n-\tint color;\n+\tenum git_colorbool color;\n \tstruct ident_split *from_ident;\n \tunsigned encode_email_headers:1;\n \tstruct pretty_print_describe_status *describe_status;\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 644f5c567c..81f2c229a9 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -95,7 +95,7 @@ struct ref_format {\n \tconst char *format;\n \tconst char *rest;\n \tint quote_style;\n-\tint use_color;\n+\tenum git_colorbool use_color;\n \n \t/* Internal state to ref-filter */\n \tint need_color_reset_at_eol;\ndiff --git a/sideband.c b/sideband.c\nindex 3ac87148b9..ea7c25211e 100644\n--- a/sideband.c\n+++ b/sideband.c\n@@ -27,9 +27,9 @@ static struct keyword_entry keywords[] = {\n };\n \n /* Returns a color setting (GIT_COLOR_NEVER, etc). */\n-static int use_sideband_colors(void)\n+static enum git_colorbool use_sideband_colors(void)\n {\n-\tstatic int use_sideband_colors_cached = GIT_COLOR_UNKNOWN;\n+\tstatic enum git_colorbool use_sideband_colors_cached = GIT_COLOR_UNKNOWN;\n \n \tconst char *key = \"color.remote\";\n \tstruct strbuf sb = STRBUF_INIT;\ndiff --git a/transport.c b/transport.c\nindex ea0be4503c..c7f06a7382 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -30,7 +30,7 @@\n #include \"color.h\"\n #include \"bundle-uri.h\"\n \n-static int transport_use_color = GIT_COLOR_UNKNOWN;\n+static enum git_colorbool transport_use_color = GIT_COLOR_UNKNOWN;\n static char transport_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n \tGIT_COLOR_RED\t\t/* REJECTED */\ndiff --git a/wt-status.h b/wt-status.h\nindex 4e377ce62b..e40a27214a 100644\n--- a/wt-status.h\n+++ b/wt-status.h\n@@ -111,7 +111,7 @@ struct wt_status {\n \tint amend;\n \tenum commit_whence whence;\n \tint nowarn;\n-\tint use_color;\n+\tenum git_colorbool use_color;\n \tint no_gettext;\n \tint display_comment_prefix;\n \tint relative_paths;\n-- \n2.51.0.527.g34bc42dacd\n\n"},{"id":"526487","messageId":"20250916202526.GJ612873@coredump.intra.peff.net","threadId":"64153","inReplyTo":"20250916201036.GA612463@coredump.intra.peff.net","subject":"[PATCH 10/13] color: return bool from want_color()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-16T20:25:26Z","receivedAt":"2025-09-16T20:25:27Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"The point of want_color() is to take in a git_colorbool enum value and\ncollapse it down to a single true/false boolean, letting UNKNOWN fall\nback to the color.ui default and checking isatty() for AUTO.\n\nLet's make that more clear in the type system by returning a bool rather\nthan an integer.\n\nThis sadly still does not help us much with compiler warnings for using\nthe two types interchangeably. But it helps make the intent more clear\nto a human reader.\n\nWe still retain the idempotency of want_color(), because in C a bool\ntrue/false converts to 1/0 when converted to an integer, which\ncorresponds to GIT_COLOR_ALWAYS and GIT_COLOR_NEVER. So you can store\nthe bool in a git_colorbool and get the right result (something a few\npieces of code still do, but which we'll clean up in further patches).\n\nNote that we rely on this same bool/int conversion for\ncheck_auto_color(). We cache its results in a tristate int with \"-1\" as\n\"not yet set\", but we can assign to it (and return it) with implicit\nconversions to/from bool.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n color.c | 8 ++++----\n color.h | 2 +-\n 2 files changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/color.c b/color.c\nindex 3348ead534..07ac8c9d40 100644\n--- a/color.c\n+++ b/color.c\n@@ -391,20 +391,20 @@ enum git_colorbool git_config_colorbool(const char *var, const char *value)\n \treturn GIT_COLOR_AUTO;\n }\n \n-static int check_auto_color(int fd)\n+static bool check_auto_color(int fd)\n {\n \tstatic int color_stderr_is_tty = -1;\n \tint *is_tty_p = fd == 1 ? &color_stdout_is_tty : &color_stderr_is_tty;\n \tif (*is_tty_p < 0)\n \t\t*is_tty_p = isatty(fd);\n \tif (*is_tty_p || (fd == 1 && pager_in_use() && pager_use_color)) {\n \t\tif (!is_terminal_dumb())\n-\t\t\treturn 1;\n+\t\t\treturn true;\n \t}\n-\treturn 0;\n+\treturn false;\n }\n \n-int want_color_fd(int fd, enum git_colorbool var)\n+bool want_color_fd(int fd, enum git_colorbool var)\n {\n \t/*\n \t * NEEDSWORK: This function is sometimes used from multiple threads, and\ndiff --git a/color.h b/color.h\nindex fcb38c5562..43e6c9ad09 100644\n--- a/color.h\n+++ b/color.h\n@@ -106,7 +106,7 @@ enum git_colorbool git_config_colorbool(const char *var, const char *value);\n  * Return a boolean whether to use color, where the argument 'var' is\n  * one of GIT_COLOR_UNKNOWN, GIT_COLOR_NEVER, GIT_COLOR_ALWAYS, GIT_COLOR_AUTO.\n  */\n-int want_color_fd(int fd, enum git_colorbool var);\n+bool want_color_fd(int fd, enum git_colorbool var);\n #define want_color(colorbool) want_color_fd(1, (colorbool))\n #define want_color_stderr(colorbool) want_color_fd(2, (colorbool))\n \n-- \n2.51.0.527.g34bc42dacd\n\n"},{"id":"526488","messageId":"20250916202624.GK612873@coredump.intra.peff.net","threadId":"64153","inReplyTo":"20250916201036.GA612463@coredump.intra.peff.net","subject":"[PATCH 11/13] add-interactive: retain colorbool values longer","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-16T20:26:24Z","receivedAt":"2025-09-16T20:26:25Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Most of the diff code stores the decision about whether to show color as\na git_colorbool, and evaluates it at point-of-use with want_color().\nThis timing is important for reasons explained in daa0c3d971 (color:\ndelay auto-color decision until point of use, 2011-08-17).\n\nThe add-interactive code instead converts immediately to strict boolean\nvalues using want_color(), and then evaluates those. This isn't wrong.\nEven though we pass the bool values to diff_use_color(), which expects a\ncolorbool, the values are compatible. But it is unlike the rest of the\ncolor code, and is questionable from a type-system perspective (but C's\ntyping between enums, ints, and bools is weak enough that the compiler\ndoes not complain).\n\nLet's switch it to the more usual way of calling want_color() at the\npoint of use.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nI guess this could also come earlier in the series, but I found it\neasier to understand the conversion if we start using the git_colorbool\nvalue.\n\n add-interactive.c | 14 +++++++-------\n add-interactive.h |  4 ++--\n 2 files changed, 9 insertions(+), 9 deletions(-)\n\ndiff --git a/add-interactive.c b/add-interactive.c\nindex 000315971e..6ffe64c38d 100644\n--- a/add-interactive.c\n+++ b/add-interactive.c\n@@ -20,14 +20,14 @@\n #include \"prompt.h\"\n #include \"tree.h\"\n \n-static void init_color(struct repository *r, int use_color,\n+static void init_color(struct repository *r, enum git_colorbool use_color,\n \t\t       const char *section_and_slot, char *dst,\n \t\t       const char *default_color)\n {\n \tchar *key = xstrfmt(\"color.%s\", section_and_slot);\n \tconst char *value;\n \n-\tif (!use_color)\n+\tif (!want_color(use_color))\n \t\tdst[0] = '\\0';\n \telse if (repo_config_get_value(r, key, &value) ||\n \t\t color_parse(value, dst))\n@@ -36,7 +36,7 @@ static void init_color(struct repository *r, int use_color,\n \tfree(key);\n }\n \n-static int check_color_config(struct repository *r, const char *var)\n+static enum git_colorbool check_color_config(struct repository *r, const char *var)\n {\n \tconst char *value;\n \tenum git_colorbool ret;\n@@ -55,7 +55,7 @@ static int check_color_config(struct repository *r, const char *var)\n \t    !repo_config_get_value(r, \"color.ui\", &value))\n \t\tret = git_config_colorbool(\"color.ui\", value);\n \n-\treturn want_color(ret);\n+\treturn ret;\n }\n \n void init_add_i_state(struct add_i_state *s, struct repository *r,\n@@ -76,7 +76,7 @@ void init_add_i_state(struct add_i_state *s, struct repository *r,\n \tinit_color(r, s->use_color_interactive, \"interactive.error\",\n \t\t   s->error_color, GIT_COLOR_BOLD_RED);\n \tstrlcpy(s->reset_color_interactive,\n-\t\ts->use_color_interactive ? GIT_COLOR_RESET : \"\", COLOR_MAXLEN);\n+\t\twant_color(s->use_color_interactive) ? GIT_COLOR_RESET : \"\", COLOR_MAXLEN);\n \n \ts->use_color_diff = check_color_config(r, \"color.diff\");\n \n@@ -93,7 +93,7 @@ void init_add_i_state(struct add_i_state *s, struct repository *r,\n \tinit_color(r, s->use_color_diff, \"diff.new\", s->file_new_color,\n \t\t   diff_get_color(s->use_color_diff, DIFF_FILE_NEW));\n \tstrlcpy(s->reset_color_diff,\n-\t\ts->use_color_diff ? GIT_COLOR_RESET : \"\", COLOR_MAXLEN);\n+\t\twant_color(s->use_color_diff) ? GIT_COLOR_RESET : \"\", COLOR_MAXLEN);\n \n \tFREE_AND_NULL(s->interactive_diff_filter);\n \trepo_config_get_string(r, \"interactive.difffilter\",\n@@ -1211,7 +1211,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps,\n \t * When color was asked for, use the prompt color for\n \t * highlighting, otherwise use square brackets.\n \t */\n-\tif (s.use_color_interactive) {\n+\tif (want_color(s.use_color_interactive)) {\n \t\tdata.color = s.prompt_color;\n \t\tdata.reset = s.reset_color_interactive;\n \t}\ndiff --git a/add-interactive.h b/add-interactive.h\nindex ceadfa6bb6..da49502b76 100644\n--- a/add-interactive.h\n+++ b/add-interactive.h\n@@ -12,8 +12,8 @@ struct add_p_opt {\n \n struct add_i_state {\n \tstruct repository *r;\n-\tint use_color_interactive;\n-\tint use_color_diff;\n+\tenum git_colorbool use_color_interactive;\n+\tenum git_colorbool use_color_diff;\n \tchar header_color[COLOR_MAXLEN];\n \tchar help_color[COLOR_MAXLEN];\n \tchar prompt_color[COLOR_MAXLEN];\n-- \n2.51.0.527.g34bc42dacd\n\n"},{"id":"526489","messageId":"20250916202637.GL612873@coredump.intra.peff.net","threadId":"64153","inReplyTo":"20250916201036.GA612463@coredump.intra.peff.net","subject":"[PATCH 12/13] config: store want_color() result in a separate bool","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-16T20:26:37Z","receivedAt":"2025-09-16T20:26:38Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"The \"git config --get-colorbool foo.bar\" command not only digs in the\nconfig to find the value of foo.bar, it evaluates the result using\nwant_color() to check the tty-ness of stdout.\n\nBut it stores the bool result of want_color() in the same git_colorbool\nthat we found in the config. This works in practice because the\ngit_colorbool enum is a superset of the bool values. But it is an oddity\nfrom a type system perspective.\n\nLet's instead store the result in a separate bool and use that.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/config.c | 7 ++++---\n 1 file changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/config.c b/builtin/config.c\nindex 9e4e4eb2f1..2348a99dd4 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -598,6 +598,7 @@ static int get_colorbool(const struct config_location_options *opts,\n \t\t.get_diff_color_found = GIT_COLOR_UNKNOWN,\n \t\t.get_color_ui_found = GIT_COLOR_UNKNOWN,\n \t};\n+\tbool result;\n \n \tconfig_with_options(git_get_colorbool_config, &data,\n \t\t\t    &opts->source, the_repository,\n@@ -614,13 +615,13 @@ static int get_colorbool(const struct config_location_options *opts,\n \t\t/* default value if none found in config */\n \t\tdata.get_colorbool_found = GIT_COLOR_AUTO;\n \n-\tdata.get_colorbool_found = want_color(data.get_colorbool_found);\n+\tresult = want_color(data.get_colorbool_found);\n \n \tif (print) {\n-\t\tprintf(\"%s\\n\", data.get_colorbool_found ? \"true\" : \"false\");\n+\t\tprintf(\"%s\\n\", result ? \"true\" : \"false\");\n \t\treturn 0;\n \t} else\n-\t\treturn data.get_colorbool_found ? 0 : 1;\n+\t\treturn result ? 0 : 1;\n }\n \n static void check_write(const struct git_config_source *source)\n-- \n2.51.0.527.g34bc42dacd\n\n"},{"id":"526490","messageId":"20250916202748.GM612873@coredump.intra.peff.net","threadId":"64153","inReplyTo":"20250916201036.GA612463@coredump.intra.peff.net","subject":"[PATCH 13/13 DO NOT APPLY] color: convert git_colorbool into a struct","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-16T20:27:48Z","receivedAt":"2025-09-16T20:27:50Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"There were a few minor bugs fixed earlier in this series that were\ncaused by confusion between an \"enum git_colorbool\" (which has four\nvalues) and a real true/false bool. It would be nice if the compiler\nalerted us to such problems, but C's weak typing allows implicit\nconversions between bool, int, and enums (and even with more recent\n-Wenum-* warnings, I couldn't get either gcc or clang to complain about\nthe buggy constructs).\n\nBut there is one way we can bend C's type system to our will: turning\nthe colorbool variables into structs, which cannot be implicitly\nconverted to a bool.\n\nUnfortunately, doing so is rather invasive and ugly. Ideally we could\njust do this in color.h:\n\n  struct git_colorbool {\n          enum git_colorbool f;\n  };\n  typedef struct git_colorbool git_colorbool;\n  #define GIT_COLOR_AUTO (git_colorbool){GIT_COLOR_AUTO}\n  /* ...etc... */\n\nand then most calling code would be happy. But:\n\n  - We don't use typedefs for enums in our project (so even with that\n    typedef, we have to drop the \"enum\" from \"enum git_colorbool\"\n    everywhere).\n\n  - The anonymous struct syntax above works for assigning and returning\n    values, but not for initializers. You have to use {GIT_COLOR_AUTO}\n    without the fake-typecast there.\n\n  - Likewise, C does not allow direct struct comparison at all! So for\n    \"foo == GIT_COLOR_AUTO\", you must actually dereference foo.f to get\n    to the field.\n\nSo this patch just makes all of the necessary changes throughout the\ncode base. This is not something we should apply, but it was useful for\nflushing out all of the funny spots earlier in the series.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n add-interactive.c     | 14 +++++++-------\n add-interactive.h     |  4 ++--\n advice.c              |  2 +-\n builtin/add.c         |  2 +-\n builtin/am.c          |  4 ++--\n builtin/branch.c      |  2 +-\n builtin/clean.c       |  2 +-\n builtin/commit.c      |  4 ++--\n builtin/config.c      | 20 ++++++++++----------\n builtin/grep.c        |  2 +-\n builtin/log.c         |  4 ++--\n builtin/push.c        |  2 +-\n builtin/range-diff.c  |  2 +-\n builtin/show-branch.c |  2 +-\n color.c               | 24 ++++++++++++------------\n color.h               |  7 ++++---\n combine-diff.c        |  2 +-\n diff.c                | 18 +++++++++---------\n diff.h                |  4 ++--\n grep.h                |  4 ++--\n log-tree.c            |  4 ++--\n log-tree.h            |  2 +-\n parse-options-cb.c    |  6 +++---\n pretty.c              |  8 ++++----\n pretty.h              |  2 +-\n ref-filter.h          |  4 ++--\n sequencer.c           |  2 +-\n sideband.c            |  8 ++++----\n transport.c           |  2 +-\n wt-status.c           |  6 +++---\n wt-status.h           |  2 +-\n 31 files changed, 86 insertions(+), 85 deletions(-)\n\ndiff --git a/add-interactive.c b/add-interactive.c\nindex 6ffe64c38d..c16270dd60 100644\n--- a/add-interactive.c\n+++ b/add-interactive.c\n@@ -20,7 +20,7 @@\n #include \"prompt.h\"\n #include \"tree.h\"\n \n-static void init_color(struct repository *r, enum git_colorbool use_color,\n+static void init_color(struct repository *r, git_colorbool use_color,\n \t\t       const char *section_and_slot, char *dst,\n \t\t       const char *default_color)\n {\n@@ -36,13 +36,13 @@ static void init_color(struct repository *r, enum git_colorbool use_color,\n \tfree(key);\n }\n \n-static enum git_colorbool check_color_config(struct repository *r, const char *var)\n+static git_colorbool check_color_config(struct repository *r, const char *var)\n {\n \tconst char *value;\n-\tenum git_colorbool ret;\n+\tgit_colorbool ret;\n \n \tif (repo_config_get_value(r, var, &value))\n-\t\tret = GIT_COLOR_UNKNOWN;\n+\t\tret.f = GIT_COLOR_UNKNOWN;\n \telse\n \t\tret = git_config_colorbool(var, value);\n \n@@ -51,7 +51,7 @@ static enum git_colorbool check_color_config(struct repository *r, const char *v\n \t * the value parsed by git_color_config(), which may not have been\n \t * called by the main command.\n \t */\n-\tif (ret == GIT_COLOR_UNKNOWN &&\n+\tif (ret.f == GIT_COLOR_UNKNOWN &&\n \t    !repo_config_get_value(r, \"color.ui\", &value))\n \t\tret = git_config_colorbool(\"color.ui\", value);\n \n@@ -131,8 +131,8 @@ void clear_add_i_state(struct add_i_state *s)\n \tFREE_AND_NULL(s->interactive_diff_filter);\n \tFREE_AND_NULL(s->interactive_diff_algorithm);\n \tmemset(s, 0, sizeof(*s));\n-\ts->use_color_interactive = GIT_COLOR_UNKNOWN;\n-\ts->use_color_diff = GIT_COLOR_UNKNOWN;\n+\ts->use_color_interactive = (git_colorbool){GIT_COLOR_UNKNOWN};\n+\ts->use_color_diff = (git_colorbool){GIT_COLOR_UNKNOWN};\n }\n \n /*\ndiff --git a/add-interactive.h b/add-interactive.h\nindex da49502b76..7016ea2d2f 100644\n--- a/add-interactive.h\n+++ b/add-interactive.h\n@@ -12,8 +12,8 @@ struct add_p_opt {\n \n struct add_i_state {\n \tstruct repository *r;\n-\tenum git_colorbool use_color_interactive;\n-\tenum git_colorbool use_color_diff;\n+\tgit_colorbool use_color_interactive;\n+\tgit_colorbool use_color_diff;\n \tchar header_color[COLOR_MAXLEN];\n \tchar help_color[COLOR_MAXLEN];\n \tchar prompt_color[COLOR_MAXLEN];\ndiff --git a/advice.c b/advice.c\nindex 0018501b7b..21fa17d6a8 100644\n--- a/advice.c\n+++ b/advice.c\n@@ -7,7 +7,7 @@\n #include \"help.h\"\n #include \"string-list.h\"\n \n-static enum git_colorbool advice_use_color = GIT_COLOR_UNKNOWN;\n+static git_colorbool advice_use_color = {GIT_COLOR_UNKNOWN};\n static char advice_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n \tGIT_COLOR_YELLOW,\t/* HINT */\ndiff --git a/builtin/add.c b/builtin/add.c\nindex 4cd3d183f9..c9ca3466a3 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -200,7 +200,7 @@ static int edit_patch(struct repository *repo,\n \n \targc = setup_revisions(argc, argv, &rev, NULL);\n \trev.diffopt.output_format = DIFF_FORMAT_PATCH;\n-\trev.diffopt.use_color = GIT_COLOR_NEVER;\n+\trev.diffopt.use_color = (git_colorbool){GIT_COLOR_NEVER};\n \trev.diffopt.flags.ignore_dirty_submodules = 1;\n \tout = xopen(file, O_CREAT | O_WRONLY | O_TRUNC, 0666);\n \trev.diffopt.file = xfdopen(out, \"w\");\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 277c2e7937..4c06b44607 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -1408,7 +1408,7 @@ static void write_commit_patch(const struct am_state *state, struct commit *comm\n \trev_info.no_commit_id = 1;\n \trev_info.diffopt.flags.binary = 1;\n \trev_info.diffopt.flags.full_index = 1;\n-\trev_info.diffopt.use_color = GIT_COLOR_NEVER;\n+\trev_info.diffopt.use_color = (git_colorbool){GIT_COLOR_NEVER};\n \trev_info.diffopt.file = fp;\n \trev_info.diffopt.close_file = 1;\n \tadd_pending_object(&rev_info, &commit->object, \"\");\n@@ -1441,7 +1441,7 @@ static void write_index_patch(const struct am_state *state)\n \trev_info.disable_stdin = 1;\n \trev_info.no_commit_id = 1;\n \trev_info.diffopt.output_format = DIFF_FORMAT_PATCH;\n-\trev_info.diffopt.use_color = GIT_COLOR_NEVER;\n+\trev_info.diffopt.use_color = (git_colorbool){GIT_COLOR_NEVER};\n \trev_info.diffopt.file = fp;\n \trev_info.diffopt.close_file = 1;\n \tadd_pending_object(&rev_info, &tree->object, \"\");\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 9fcf04bebb..f5dd0e00be 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -46,7 +46,7 @@ static struct object_id head_oid;\n static int recurse_submodules = 0;\n static int submodule_propagate_branches = 0;\n \n-static enum git_colorbool branch_use_color = GIT_COLOR_UNKNOWN;\n+static git_colorbool branch_use_color = {GIT_COLOR_UNKNOWN};\n static char branch_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n \tGIT_COLOR_NORMAL,       /* PLAIN */\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 1d5e7e5366..7f025aaea1 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -64,7 +64,7 @@ static const char *color_interactive_slots[] = {\n \t[CLEAN_COLOR_RESET]  = \"reset\",\n };\n \n-static enum git_colorbool clean_use_color = GIT_COLOR_UNKNOWN;\n+static git_colorbool clean_use_color = {GIT_COLOR_UNKNOWN};\n static char clean_colors[][COLOR_MAXLEN] = {\n \t[CLEAN_COLOR_ERROR] = GIT_COLOR_BOLD_RED,\n \t[CLEAN_COLOR_HEADER] = GIT_COLOR_BOLD,\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex d8f21a4c62..3c1c12845a 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -936,7 +936,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \tstrbuf_addstr(&committer_ident, git_committer_info(IDENT_STRICT));\n \tif (use_editor && include_status) {\n \t\tint ident_shown = 0;\n-\t\tenum git_colorbool saved_color_setting;\n+\t\tgit_colorbool saved_color_setting;\n \t\tstruct ident_split ci, ai;\n \t\tconst char *hint_cleanup_all = allow_empty_message ?\n \t\t\t_(\"Please enter the commit message for your changes.\"\n@@ -1016,7 +1016,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \t\tstatus_printf_ln(s, GIT_COLOR_NORMAL, \"%s\", \"\"); /* Add new line for clarity */\n \n \t\tsaved_color_setting = s->use_color;\n-\t\ts->use_color = GIT_COLOR_NEVER;\n+\t\ts->use_color = (git_colorbool){GIT_COLOR_NEVER};\n \t\tcommittable = run_status(s->fp, index_file, prefix, 1, s);\n \t\ts->use_color = saved_color_setting;\n \t\tstring_list_clear_func(&s->change, change_data_free);\ndiff --git a/builtin/config.c b/builtin/config.c\nindex 2348a99dd4..4105c4c812 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -568,9 +568,9 @@ static void get_color(const struct config_location_options *opts,\n }\n \n struct get_colorbool_config_data {\n-\tenum git_colorbool get_colorbool_found;\n-\tenum git_colorbool get_diff_color_found;\n-\tenum git_colorbool get_color_ui_found;\n+\tgit_colorbool get_colorbool_found;\n+\tgit_colorbool get_diff_color_found;\n+\tgit_colorbool get_color_ui_found;\n \tconst char *get_colorbool_slot;\n };\n \n@@ -594,26 +594,26 @@ static int get_colorbool(const struct config_location_options *opts,\n {\n \tstruct get_colorbool_config_data data = {\n \t\t.get_colorbool_slot = var,\n-\t\t.get_colorbool_found = GIT_COLOR_UNKNOWN,\n-\t\t.get_diff_color_found = GIT_COLOR_UNKNOWN,\n-\t\t.get_color_ui_found = GIT_COLOR_UNKNOWN,\n+\t\t.get_colorbool_found = {GIT_COLOR_UNKNOWN},\n+\t\t.get_diff_color_found = {GIT_COLOR_UNKNOWN},\n+\t\t.get_color_ui_found = {GIT_COLOR_UNKNOWN},\n \t};\n \tbool result;\n \n \tconfig_with_options(git_get_colorbool_config, &data,\n \t\t\t    &opts->source, the_repository,\n \t\t\t    &opts->options);\n \n-\tif (data.get_colorbool_found == GIT_COLOR_UNKNOWN) {\n+\tif (data.get_colorbool_found.f == GIT_COLOR_UNKNOWN) {\n \t\tif (!strcmp(data.get_colorbool_slot, \"color.diff\"))\n \t\t\tdata.get_colorbool_found = data.get_diff_color_found;\n-\t\tif (data.get_colorbool_found == GIT_COLOR_UNKNOWN)\n+\t\tif (data.get_colorbool_found.f == GIT_COLOR_UNKNOWN)\n \t\t\tdata.get_colorbool_found = data.get_color_ui_found;\n \t}\n \n-\tif (data.get_colorbool_found == GIT_COLOR_UNKNOWN)\n+\tif (data.get_colorbool_found.f == GIT_COLOR_UNKNOWN)\n \t\t/* default value if none found in config */\n-\t\tdata.get_colorbool_found = GIT_COLOR_AUTO;\n+\t\tdata.get_colorbool_found = (git_colorbool){GIT_COLOR_AUTO};\n \n \tresult = want_color(data.get_colorbool_found);\n \ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 1d97eb2a2a..3a6cdf9220 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -1091,7 +1091,7 @@ int cmd_grep(int argc,\n \tif (show_in_pager == default_pager)\n \t\tshow_in_pager = git_pager(the_repository, 1);\n \tif (show_in_pager) {\n-\t\topt.color = GIT_COLOR_NEVER;\n+\t\topt.color = (git_colorbool){GIT_COLOR_NEVER};\n \t\topt.name_only = 1;\n \t\topt.null_following_name = 1;\n \t\topt.output_priv = &path_list;\ndiff --git a/builtin/log.c b/builtin/log.c\nindex c2f8bbf863..960482c2f1 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -2193,8 +2193,8 @@ int cmd_format_patch(int argc,\n \t\t\toutput_directory = cfg.config_output_directory;\n \t\toutput_directory = set_outdir(prefix, output_directory);\n \n-\t\tif (rev.diffopt.use_color != GIT_COLOR_ALWAYS)\n-\t\t\trev.diffopt.use_color = GIT_COLOR_NEVER;\n+\t\tif (rev.diffopt.use_color.f != GIT_COLOR_ALWAYS)\n+\t\t\trev.diffopt.use_color = (git_colorbool){GIT_COLOR_NEVER};\n \t\t/*\n \t\t * We consider <outdir> as 'outside of gitdir', therefore avoid\n \t\t * applying adjust_shared_perm in s-c-l-d.\ndiff --git a/builtin/push.c b/builtin/push.c\nindex 5b6cebbb85..2c84eaac7b 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -27,7 +27,7 @@ static const char * const push_usage[] = {\n \tNULL,\n };\n \n-static enum git_colorbool push_use_color = GIT_COLOR_UNKNOWN;\n+static git_colorbool push_use_color = {GIT_COLOR_UNKNOWN};\n static char push_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n \tGIT_COLOR_RED,\t/* ERROR */\ndiff --git a/builtin/range-diff.c b/builtin/range-diff.c\nindex 0d51ddd623..94ceaffac2 100644\n--- a/builtin/range-diff.c\n+++ b/builtin/range-diff.c\n@@ -67,7 +67,7 @@ int cmd_range_diff(int argc,\n \n \t/* force color when --dual-color was used */\n \tif (!simple_color)\n-\t\tdiffopt.use_color = GIT_COLOR_ALWAYS;\n+\t\tdiffopt.use_color = (git_colorbool){GIT_COLOR_ALWAYS};\n \n \t/* If `--diff-merges` was specified, imply `--merges` */\n \tif (diff_merges_arg.nr) {\ndiff --git a/builtin/show-branch.c b/builtin/show-branch.c\nindex 441babf2e3..d5e9eb399a 100644\n--- a/builtin/show-branch.c\n+++ b/builtin/show-branch.c\n@@ -29,7 +29,7 @@ static const char*const show_branch_usage[] = {\n     NULL\n };\n \n-static enum git_colorbool showbranch_use_color = GIT_COLOR_UNKNOWN;\n+static git_colorbool showbranch_use_color = {GIT_COLOR_UNKNOWN};\n \n static struct strvec default_args = STRVEC_INIT;\n \ndiff --git a/color.c b/color.c\nindex 07ac8c9d40..14e994ab19 100644\n--- a/color.c\n+++ b/color.c\n@@ -9,7 +9,7 @@\n #include \"pager.h\"\n #include \"strbuf.h\"\n \n-static enum git_colorbool git_use_color_default = GIT_COLOR_AUTO;\n+static git_colorbool git_use_color_default = {GIT_COLOR_AUTO};\n int color_stdout_is_tty = -1;\n \n /*\n@@ -369,26 +369,26 @@ int color_parse_mem(const char *value, int value_len, char *dst)\n #undef OUT\n }\n \n-enum git_colorbool git_config_colorbool(const char *var, const char *value)\n+git_colorbool git_config_colorbool(const char *var, const char *value)\n {\n \tif (value) {\n \t\tif (!strcasecmp(value, \"never\"))\n-\t\t\treturn GIT_COLOR_NEVER;\n+\t\t\treturn (git_colorbool){GIT_COLOR_NEVER};\n \t\tif (!strcasecmp(value, \"always\"))\n-\t\t\treturn GIT_COLOR_ALWAYS;\n+\t\t\treturn (git_colorbool){GIT_COLOR_ALWAYS};\n \t\tif (!strcasecmp(value, \"auto\"))\n-\t\t\treturn GIT_COLOR_AUTO;\n+\t\t\treturn (git_colorbool){GIT_COLOR_AUTO};\n \t}\n \n \tif (!var)\n-\t\treturn GIT_COLOR_UNKNOWN;\n+\t\treturn (git_colorbool){GIT_COLOR_UNKNOWN};\n \n \t/* Missing or explicit false to turn off colorization */\n \tif (!git_config_bool(var, value))\n-\t\treturn GIT_COLOR_NEVER;\n+\t\treturn (git_colorbool){GIT_COLOR_NEVER};\n \n \t/* any normal truth value defaults to 'auto' */\n-\treturn GIT_COLOR_AUTO;\n+\treturn (git_colorbool){GIT_COLOR_AUTO};\n }\n \n static bool check_auto_color(int fd)\n@@ -404,7 +404,7 @@ static bool check_auto_color(int fd)\n \treturn false;\n }\n \n-bool want_color_fd(int fd, enum git_colorbool var)\n+bool want_color_fd(int fd, git_colorbool var)\n {\n \t/*\n \t * NEEDSWORK: This function is sometimes used from multiple threads, and\n@@ -418,15 +418,15 @@ bool want_color_fd(int fd, enum git_colorbool var)\n \tif (fd < 1 || fd >= ARRAY_SIZE(want_auto))\n \t\tBUG(\"file descriptor out of range: %d\", fd);\n \n-\tif (var == GIT_COLOR_UNKNOWN)\n+\tif (var.f == GIT_COLOR_UNKNOWN)\n \t\tvar = git_use_color_default;\n \n-\tif (var == GIT_COLOR_AUTO) {\n+\tif (var.f == GIT_COLOR_AUTO) {\n \t\tif (want_auto[fd] < 0)\n \t\t\twant_auto[fd] = check_auto_color(fd);\n \t\treturn want_auto[fd];\n \t}\n-\treturn var == GIT_COLOR_ALWAYS;\n+\treturn var.f == GIT_COLOR_ALWAYS;\n }\n \n int git_color_config(const char *var, const char *value, void *cb UNUSED)\ndiff --git a/color.h b/color.h\nindex 43e6c9ad09..5e735ce827 100644\n--- a/color.h\n+++ b/color.h\n@@ -73,12 +73,13 @@ struct strbuf;\n  * returned from git_config_colorbool. The \"auto\" value can be returned from\n  * config_colorbool, and will be converted by want_color() into either 0 or 1.\n  */\n-enum git_colorbool {\n+enum git_colorbool_f {\n \tGIT_COLOR_UNKNOWN = -1,\n \tGIT_COLOR_NEVER = 0,\n \tGIT_COLOR_ALWAYS = 1,\n \tGIT_COLOR_AUTO = 2,\n };\n+typedef struct { enum git_colorbool_f f; } git_colorbool;\n \n /* A default list of colors to use for commit graphs and show-branch output */\n extern const char *column_colors_ansi[];\n@@ -100,13 +101,13 @@ int git_color_config(const char *var, const char *value, void *cb);\n  * GIT_COLOR_ALWAYS for \"always\" or a positive boolean,\n  * and GIT_COLOR_AUTO for \"auto\".\n  */\n-enum git_colorbool git_config_colorbool(const char *var, const char *value);\n+git_colorbool git_config_colorbool(const char *var, const char *value);\n \n /*\n  * Return a boolean whether to use color, where the argument 'var' is\n  * one of GIT_COLOR_UNKNOWN, GIT_COLOR_NEVER, GIT_COLOR_ALWAYS, GIT_COLOR_AUTO.\n  */\n-bool want_color_fd(int fd, enum git_colorbool var);\n+bool want_color_fd(int fd, git_colorbool var);\n #define want_color(colorbool) want_color_fd(1, (colorbool))\n #define want_color_stderr(colorbool) want_color_fd(2, (colorbool))\n \ndiff --git a/combine-diff.c b/combine-diff.c\nindex 21b7fdfff4..d70939ed71 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -749,7 +749,7 @@ static void show_line_to_eol(const char *line, int len, const char *reset)\n \n static void dump_sline(struct sline *sline, const char *line_prefix,\n \t\t       unsigned long cnt, int num_parent,\n-\t\t       enum git_colorbool use_color, int result_deleted)\n+\t\t       git_colorbool use_color, int result_deleted)\n {\n \tunsigned long mark = (1UL<<num_parent);\n \tunsigned long no_pre_delete = (2UL<<num_parent);\ndiff --git a/diff.c b/diff.c\nindex 87fa16b730..59a9286aea 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -57,7 +57,7 @@ static int diff_detect_rename_default;\n static int diff_indent_heuristic = 1;\n static int diff_rename_limit_default = 1000;\n static int diff_suppress_blank_empty;\n-static enum git_colorbool diff_use_color_default = GIT_COLOR_UNKNOWN;\n+static git_colorbool diff_use_color_default = {GIT_COLOR_UNKNOWN};\n static int diff_color_moved_default;\n static int diff_color_moved_ws_default;\n static int diff_context_default = 3;\n@@ -595,7 +595,7 @@ static struct diff_tempfile {\n } diff_temp[2];\n \n struct emit_callback {\n-\tint color_diff;\n+\tgit_colorbool color_diff;\n \tunsigned ws_rule;\n \tint blank_at_eof_in_preimage;\n \tint blank_at_eof_in_postimage;\n@@ -2303,7 +2303,7 @@ static void free_diff_words_data(struct emit_callback *ecbdata)\n \t}\n }\n \n-const char *diff_get_color(enum git_colorbool diff_use_color, enum color_diff ix)\n+const char *diff_get_color(git_colorbool diff_use_color, enum color_diff ix)\n {\n \tif (want_color(diff_use_color))\n \t\treturn diff_colors[ix];\n@@ -4497,7 +4497,7 @@ static void fill_metainfo(struct strbuf *msg,\n \t\t\t  struct diff_options *o,\n \t\t\t  struct diff_filepair *p,\n \t\t\t  int *must_show_header,\n-\t\t\t  enum git_colorbool use_color)\n+\t\t\t  git_colorbool use_color)\n {\n \tconst char *set = diff_get_color(use_color, DIFF_METAINFO);\n \tconst char *reset = diff_get_color(use_color, DIFF_RESET);\n@@ -4596,7 +4596,7 @@ static void run_diff_cmd(const struct external_diff *pgm,\n \t\t */\n \t\tfill_metainfo(msg, name, other, one, two, o, p,\n \t\t\t      &must_show_header,\n-\t\t\t      pgm ? GIT_COLOR_NEVER : o->use_color);\n+\t\t\t      pgm ? (git_colorbool){GIT_COLOR_NEVER} : o->use_color);\n \t\txfrm_msg = msg->len ? msg->buf : NULL;\n \t}\n \n@@ -5277,7 +5277,7 @@ static int diff_opt_color_words(const struct option *opt,\n \tstruct diff_options *options = opt->value;\n \n \tBUG_ON_OPT_NEG(unset);\n-\toptions->use_color = GIT_COLOR_ALWAYS;\n+\toptions->use_color = (git_colorbool){GIT_COLOR_ALWAYS};\n \toptions->word_diff = DIFF_WORDS_COLOR;\n \toptions->word_regex = arg;\n \treturn 0;\n@@ -5458,8 +5458,8 @@ static enum parse_opt_result diff_opt_output(struct parse_opt_ctx_t *ctx,\n \tpath = prefix_filename(ctx->prefix, arg);\n \toptions->file = xfopen(path, \"w\");\n \toptions->close_file = 1;\n-\tif (options->use_color != GIT_COLOR_ALWAYS)\n-\t\toptions->use_color = GIT_COLOR_NEVER;\n+\tif (options->use_color.f != GIT_COLOR_ALWAYS)\n+\t\toptions->use_color = (git_colorbool){GIT_COLOR_NEVER};\n \tfree(path);\n \treturn 0;\n }\n@@ -5599,7 +5599,7 @@ static int diff_opt_word_diff(const struct option *opt,\n \t\tif (!strcmp(arg, \"plain\"))\n \t\t\toptions->word_diff = DIFF_WORDS_PLAIN;\n \t\telse if (!strcmp(arg, \"color\")) {\n-\t\t\toptions->use_color = GIT_COLOR_ALWAYS;\n+\t\t\toptions->use_color = (git_colorbool){GIT_COLOR_ALWAYS};\n \t\t\toptions->word_diff = DIFF_WORDS_COLOR;\n \t\t}\n \t\telse if (!strcmp(arg, \"porcelain\"))\ndiff --git a/diff.h b/diff.h\nindex bccd86a748..197dcb997f 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -284,7 +284,7 @@ struct diff_options {\n \t/* diff-filter bits */\n \tunsigned int filter, filter_not;\n \n-\tenum git_colorbool use_color;\n+\tgit_colorbool use_color;\n \n \t/* Number of context lines to generate in patch output. */\n \tint context;\n@@ -470,7 +470,7 @@ enum color_diff {\n \tDIFF_FILE_NEW_BOLD = 22,\n };\n \n-const char *diff_get_color(enum git_colorbool diff_use_color, enum color_diff ix);\n+const char *diff_get_color(git_colorbool diff_use_color, enum color_diff ix);\n #define diff_get_color_opt(o, ix) \\\n \tdiff_get_color((o)->use_color, ix)\n \ndiff --git a/grep.h b/grep.h\nindex 13e26a9318..0cc2806cae 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -159,7 +159,7 @@ struct grep_opt {\n \tint pathname;\n \tint null_following_name;\n \tint only_matching;\n-\tenum git_colorbool color;\n+\tgit_colorbool color;\n \tint max_depth;\n \tint funcname;\n \tint funcbody;\n@@ -198,7 +198,7 @@ struct grep_opt {\n \t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \\\n \t}, \\\n \t.only_matching = 0, \\\n-\t.color = GIT_COLOR_UNKNOWN, \\\n+\t.color = {GIT_COLOR_UNKNOWN}, \\\n \t.output = std_output, \\\n }\n \ndiff --git a/log-tree.c b/log-tree.c\nindex a2cd5c587b..df41c5c963 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -57,7 +57,7 @@ static const char *color_decorate_slots[] = {\n \t[DECORATION_GRAFTED]\t= \"grafted\",\n };\n \n-static const char *decorate_get_color(enum git_colorbool decorate_use_color, enum decoration_type ix)\n+static const char *decorate_get_color(git_colorbool decorate_use_color, enum decoration_type ix)\n {\n \tif (want_color(decorate_use_color))\n \t\treturn decoration_colors[ix];\n@@ -341,7 +341,7 @@ static void show_name(struct strbuf *sb, const struct name_decoration *decoratio\n  */\n void format_decorations(struct strbuf *sb,\n \t\t\tconst struct commit *commit,\n-\t\t\tenum git_colorbool use_color,\n+\t\t\tgit_colorbool use_color,\n \t\t\tconst struct decoration_options *opts)\n {\n \tconst struct name_decoration *decoration;\ndiff --git a/log-tree.h b/log-tree.h\nindex 1c82380d95..43ab208a7d 100644\n--- a/log-tree.h\n+++ b/log-tree.h\n@@ -26,7 +26,7 @@ int log_tree_diff_flush(struct rev_info *);\n int log_tree_commit(struct rev_info *, struct commit *);\n void show_log(struct rev_info *opt);\n void format_decorations(struct strbuf *sb, const struct commit *commit,\n-\t\t\tenum git_colorbool use_color, const struct decoration_options *opts);\n+\t\t\tgit_colorbool use_color, const struct decoration_options *opts);\n void show_decorations(struct rev_info *opt, struct commit *commit);\n void log_write_email_headers(struct rev_info *opt, struct commit *commit,\n \t\t\t     char **extra_headers_p,\ndiff --git a/parse-options-cb.c b/parse-options-cb.c\nindex 976cc86385..5f0e027139 100644\n--- a/parse-options-cb.c\n+++ b/parse-options-cb.c\n@@ -50,15 +50,15 @@ int parse_opt_expiry_date_cb(const struct option *opt, const char *arg,\n int parse_opt_color_flag_cb(const struct option *opt, const char *arg,\n \t\t\t    int unset)\n {\n-\tenum git_colorbool value;\n+\tgit_colorbool value;\n \n \tif (!arg)\n \t\targ = unset ? \"never\" : (const char *)opt->defval;\n \tvalue = git_config_colorbool(NULL, arg);\n-\tif (value == GIT_COLOR_UNKNOWN)\n+\tif (value.f == GIT_COLOR_UNKNOWN)\n \t\treturn error(_(\"option `%s' expects \\\"always\\\", \\\"auto\\\", or \\\"never\\\"\"),\n \t\t\t     opt->long_name);\n-\t*(int *)opt->value = value;\n+\t*(git_colorbool *)opt->value = value;\n \treturn 0;\n }\n \ndiff --git a/pretty.c b/pretty.c\nindex e0646bbc5d..fcf7ee3d78 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -470,7 +470,7 @@ static inline void strbuf_add_with_color(struct strbuf *sb, const char *color,\n \n static void append_line_with_color(struct strbuf *sb, struct grep_opt *opt,\n \t\t\t\t   const char *line, size_t linelen,\n-\t\t\t\t   enum git_colorbool color, enum grep_context ctx,\n+\t\t\t\t   git_colorbool color, enum grep_context ctx,\n \t\t\t\t   enum grep_header_field field)\n {\n \tconst char *buf, *eol, *line_color, *match_color;\n@@ -899,7 +899,7 @@ struct format_commit_context {\n \tconst char *message;\n \tchar *commit_encoding;\n \tsize_t width, indent1, indent2;\n-\tenum git_colorbool auto_color;\n+\tgit_colorbool auto_color;\n \tint padding;\n \n \t/* These offsets are relative to the start of the commit message. */\n@@ -1462,7 +1462,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */\n \t\t} else {\n \t\t\tint ret = parse_color(sb, placeholder, c);\n \t\t\tif (ret)\n-\t\t\t\tc->auto_color = GIT_COLOR_NEVER;\n+\t\t\t\tc->auto_color = (git_colorbool){GIT_COLOR_NEVER};\n \t\t\t/*\n \t\t\t * Otherwise, we decided to treat %C<unknown>\n \t\t\t * as a literal string, and the previous\n@@ -2167,7 +2167,7 @@ static int pp_utf8_width(const char *start, const char *end)\n }\n \n static void strbuf_add_tabexpand(struct strbuf *sb, struct grep_opt *opt,\n-\t\t\t\t enum git_colorbool color, int tabwidth, const char *line,\n+\t\t\t\t git_colorbool color, int tabwidth, const char *line,\n \t\t\t\t int linelen)\n {\n \tconst char *tab;\ndiff --git a/pretty.h b/pretty.h\nindex fac699033e..915c866c53 100644\n--- a/pretty.h\n+++ b/pretty.h\n@@ -47,7 +47,7 @@ struct pretty_print_context {\n \tstruct rev_info *rev;\n \tconst char *output_encoding;\n \tstruct string_list *mailmap;\n-\tenum git_colorbool color;\n+\tgit_colorbool color;\n \tstruct ident_split *from_ident;\n \tunsigned encode_email_headers:1;\n \tstruct pretty_print_describe_status *describe_status;\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 81f2c229a9..66f96a330a 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -95,7 +95,7 @@ struct ref_format {\n \tconst char *format;\n \tconst char *rest;\n \tint quote_style;\n-\tenum git_colorbool use_color;\n+\tgit_colorbool use_color;\n \n \t/* Internal state to ref-filter */\n \tint need_color_reset_at_eol;\n@@ -111,7 +111,7 @@ struct ref_format {\n \t.exclude = STRVEC_INIT, \\\n }\n #define REF_FORMAT_INIT {             \\\n-\t.use_color = GIT_COLOR_UNKNOWN, \\\n+\t.use_color = {GIT_COLOR_UNKNOWN}, \\\n }\n \n /*  Macros for checking --merged and --no-merged options */\ndiff --git a/sequencer.c b/sequencer.c\nindex 9ae40a91b2..56999de1ec 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3732,7 +3732,7 @@ static int make_patch(struct repository *r,\n \tlog_tree_opt.disable_stdin = 1;\n \tlog_tree_opt.no_commit_id = 1;\n \tlog_tree_opt.diffopt.file = fopen(rebase_path_patch(), \"w\");\n-\tlog_tree_opt.diffopt.use_color = GIT_COLOR_NEVER;\n+\tlog_tree_opt.diffopt.use_color = (git_colorbool){GIT_COLOR_NEVER};\n \tif (!log_tree_opt.diffopt.file)\n \t\tres |= error_errno(_(\"could not open '%s'\"),\n \t\t\t\t   rebase_path_patch());\ndiff --git a/sideband.c b/sideband.c\nindex ea7c25211e..fb7b6a7e46 100644\n--- a/sideband.c\n+++ b/sideband.c\n@@ -27,24 +27,24 @@ static struct keyword_entry keywords[] = {\n };\n \n /* Returns a color setting (GIT_COLOR_NEVER, etc). */\n-static enum git_colorbool use_sideband_colors(void)\n+static git_colorbool use_sideband_colors(void)\n {\n-\tstatic enum git_colorbool use_sideband_colors_cached = GIT_COLOR_UNKNOWN;\n+\tstatic git_colorbool use_sideband_colors_cached = {GIT_COLOR_UNKNOWN};\n \n \tconst char *key = \"color.remote\";\n \tstruct strbuf sb = STRBUF_INIT;\n \tconst char *value;\n \tint i;\n \n-\tif (use_sideband_colors_cached != GIT_COLOR_UNKNOWN)\n+\tif (use_sideband_colors_cached.f != GIT_COLOR_UNKNOWN)\n \t\treturn use_sideband_colors_cached;\n \n \tif (!repo_config_get_string_tmp(the_repository, key, &value))\n \t\tuse_sideband_colors_cached = git_config_colorbool(key, value);\n \telse if (!repo_config_get_string_tmp(the_repository, \"color.ui\", &value))\n \t\tuse_sideband_colors_cached = git_config_colorbool(\"color.ui\", value);\n \telse\n-\t\tuse_sideband_colors_cached = GIT_COLOR_AUTO;\n+\t\tuse_sideband_colors_cached = (git_colorbool){GIT_COLOR_AUTO};\n \n \tfor (i = 0; i < ARRAY_SIZE(keywords); i++) {\n \t\tstrbuf_reset(&sb);\ndiff --git a/transport.c b/transport.c\nindex c7f06a7382..a5f98ba6b6 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -30,7 +30,7 @@\n #include \"color.h\"\n #include \"bundle-uri.h\"\n \n-static enum git_colorbool transport_use_color = GIT_COLOR_UNKNOWN;\n+static git_colorbool transport_use_color = {GIT_COLOR_UNKNOWN};\n static char transport_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n \tGIT_COLOR_RED\t\t/* REJECTED */\ndiff --git a/wt-status.c b/wt-status.c\nindex 8ffe6d3988..0927b88734 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -148,7 +148,7 @@ void wt_status_prepare(struct repository *r, struct wt_status *s)\n \tmemcpy(s->color_palette, default_wt_status_colors,\n \t       sizeof(default_wt_status_colors));\n \ts->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;\n-\ts->use_color = GIT_COLOR_UNKNOWN;\n+\ts->use_color = (git_colorbool){GIT_COLOR_UNKNOWN};\n \ts->relative_paths = 1;\n \ts->branch = refs_resolve_refdup(get_main_ref_store(the_repository),\n \t\t\t\t\t\"HEAD\", 0, NULL, NULL);\n@@ -1165,7 +1165,7 @@ static void wt_longstatus_print_verbose(struct wt_status *s)\n \t * before.\n \t */\n \tif (s->fp != stdout) {\n-\t\trev.diffopt.use_color = GIT_COLOR_NEVER;\n+\t\trev.diffopt.use_color = (git_colorbool){GIT_COLOR_NEVER};\n \t\twt_status_add_cut_line(s);\n \t}\n \tif (s->verbose > 1 && s->committable) {\n@@ -2155,7 +2155,7 @@ static void wt_shortstatus_print(struct wt_status *s)\n \n static void wt_porcelain_print(struct wt_status *s)\n {\n-\ts->use_color = GIT_COLOR_NEVER;\n+\ts->use_color = (git_colorbool){GIT_COLOR_NEVER};\n \ts->relative_paths = 0;\n \ts->prefix = NULL;\n \ts->no_gettext = 1;\ndiff --git a/wt-status.h b/wt-status.h\nindex e40a27214a..5364eaa1f8 100644\n--- a/wt-status.h\n+++ b/wt-status.h\n@@ -111,7 +111,7 @@ struct wt_status {\n \tint amend;\n \tenum commit_whence whence;\n \tint nowarn;\n-\tenum git_colorbool use_color;\n+\tgit_colorbool use_color;\n \tint no_gettext;\n \tint display_comment_prefix;\n \tint relative_paths;\n-- \n2.51.0.527.g34bc42dacd\n"},{"id":"526491","messageId":"20250916202832.GA613002@coredump.intra.peff.net","threadId":"64153","inReplyTo":"20250916201036.GA612463@coredump.intra.peff.net","subject":"Re: [PATCH 0/13] unraveling the mysteries of color variables","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-16T20:28:32Z","receivedAt":"2025-09-16T20:28:33Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Sep 16, 2025 at 04:10:37PM -0400, Jeff King wrote:\n\n> The good news is that my digging did uncover two minor bugs, which are\n> fixed here in patches 2 and 3. And the series should improve the\n> readability of the code by using named constants and appropriate types\n> more consistently.\n\nEither counting is hard, or my brain is fried from looking at this color\ncode. At any rate, the fixes are in patches 3 and 5:\n\n>   [03/13]: grep: don't treat grep_opt.color as a strict bool\n>   [05/13]: diff: don't use diff_options.use_color as a strict bool\n\n-Peff\n"},{"id":"526495","messageId":"xmqqplbqm8yu.fsf@gitster.g","threadId":"64153","inReplyTo":"20250916202748.GM612873@coredump.intra.peff.net","subject":"Re: [PATCH 13/13 DO NOT APPLY] color: convert git_colorbool into a struct","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-09-16T20:35:37Z","receivedAt":"2025-09-16T20:35:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> and then most calling code would be happy. But:\n>\n>   - We don't use typedefs for enums in our project (so even with that\n>     typedef, we have to drop the \"enum\" from \"enum git_colorbool\"\n>     everywhere).\n>\n>   - The anonymous struct syntax above works for assigning and returning\n>     values, but not for initializers. You have to use {GIT_COLOR_AUTO}\n>     without the fake-typecast there.\n>\n>   - Likewise, C does not allow direct struct comparison at all! So for\n>     \"foo == GIT_COLOR_AUTO\", you must actually dereference foo.f to get\n>     to the field.\n>\n> So this patch just makes all of the necessary changes throughout the\n> code base. This is not something we should apply, but it was useful for\n> flushing out all of the funny spots earlier in the series.\n\nGreat show of technique to help others.  It is somewhat surprising\nthat the patch can be this *small*, given the above ;-)\n\nAmused, but as requested, will not apply.\n\nThanks.\n\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n>  add-interactive.c     | 14 +++++++-------\n>  add-interactive.h     |  4 ++--\n>  advice.c              |  2 +-\n>  builtin/add.c         |  2 +-\n>  builtin/am.c          |  4 ++--\n>  builtin/branch.c      |  2 +-\n>  builtin/clean.c       |  2 +-\n>  builtin/commit.c      |  4 ++--\n>  builtin/config.c      | 20 ++++++++++----------\n>  builtin/grep.c        |  2 +-\n>  builtin/log.c         |  4 ++--\n>  builtin/push.c        |  2 +-\n>  builtin/range-diff.c  |  2 +-\n>  builtin/show-branch.c |  2 +-\n>  color.c               | 24 ++++++++++++------------\n>  color.h               |  7 ++++---\n>  combine-diff.c        |  2 +-\n>  diff.c                | 18 +++++++++---------\n>  diff.h                |  4 ++--\n>  grep.h                |  4 ++--\n>  log-tree.c            |  4 ++--\n>  log-tree.h            |  2 +-\n>  parse-options-cb.c    |  6 +++---\n>  pretty.c              |  8 ++++----\n>  pretty.h              |  2 +-\n>  ref-filter.h          |  4 ++--\n>  sequencer.c           |  2 +-\n>  sideband.c            |  8 ++++----\n>  transport.c           |  2 +-\n>  wt-status.c           |  6 +++---\n>  wt-status.h           |  2 +-\n>  31 files changed, 86 insertions(+), 85 deletions(-)\n>\n> diff --git a/add-interactive.c b/add-interactive.c\n> index 6ffe64c38d..c16270dd60 100644\n> --- a/add-interactive.c\n> +++ b/add-interactive.c\n> @@ -20,7 +20,7 @@\n>  #include \"prompt.h\"\n>  #include \"tree.h\"\n>  \n> -static void init_color(struct repository *r, enum git_colorbool use_color,\n> +static void init_color(struct repository *r, git_colorbool use_color,\n>  \t\t       const char *section_and_slot, char *dst,\n>  \t\t       const char *default_color)\n>  {\n> @@ -36,13 +36,13 @@ static void init_color(struct repository *r, enum git_colorbool use_color,\n>  \tfree(key);\n>  }\n>  \n> -static enum git_colorbool check_color_config(struct repository *r, const char *var)\n> +static git_colorbool check_color_config(struct repository *r, const char *var)\n>  {\n>  \tconst char *value;\n> -\tenum git_colorbool ret;\n> +\tgit_colorbool ret;\n>  \n>  \tif (repo_config_get_value(r, var, &value))\n> -\t\tret = GIT_COLOR_UNKNOWN;\n> +\t\tret.f = GIT_COLOR_UNKNOWN;\n>  \telse\n>  \t\tret = git_config_colorbool(var, value);\n>  \n> @@ -51,7 +51,7 @@ static enum git_colorbool check_color_config(struct repository *r, const char *v\n>  \t * the value parsed by git_color_config(), which may not have been\n>  \t * called by the main command.\n>  \t */\n> -\tif (ret == GIT_COLOR_UNKNOWN &&\n> +\tif (ret.f == GIT_COLOR_UNKNOWN &&\n>  \t    !repo_config_get_value(r, \"color.ui\", &value))\n>  \t\tret = git_config_colorbool(\"color.ui\", value);\n>  \n> @@ -131,8 +131,8 @@ void clear_add_i_state(struct add_i_state *s)\n>  \tFREE_AND_NULL(s->interactive_diff_filter);\n>  \tFREE_AND_NULL(s->interactive_diff_algorithm);\n>  \tmemset(s, 0, sizeof(*s));\n> -\ts->use_color_interactive = GIT_COLOR_UNKNOWN;\n> -\ts->use_color_diff = GIT_COLOR_UNKNOWN;\n> +\ts->use_color_interactive = (git_colorbool){GIT_COLOR_UNKNOWN};\n> +\ts->use_color_diff = (git_colorbool){GIT_COLOR_UNKNOWN};\n>  }\n>  \n>  /*\n> diff --git a/add-interactive.h b/add-interactive.h\n> index da49502b76..7016ea2d2f 100644\n> --- a/add-interactive.h\n> +++ b/add-interactive.h\n> @@ -12,8 +12,8 @@ struct add_p_opt {\n>  \n>  struct add_i_state {\n>  \tstruct repository *r;\n> -\tenum git_colorbool use_color_interactive;\n> -\tenum git_colorbool use_color_diff;\n> +\tgit_colorbool use_color_interactive;\n> +\tgit_colorbool use_color_diff;\n>  \tchar header_color[COLOR_MAXLEN];\n>  \tchar help_color[COLOR_MAXLEN];\n>  \tchar prompt_color[COLOR_MAXLEN];\n> diff --git a/advice.c b/advice.c\n> index 0018501b7b..21fa17d6a8 100644\n> --- a/advice.c\n> +++ b/advice.c\n> @@ -7,7 +7,7 @@\n>  #include \"help.h\"\n>  #include \"string-list.h\"\n>  \n> -static enum git_colorbool advice_use_color = GIT_COLOR_UNKNOWN;\n> +static git_colorbool advice_use_color = {GIT_COLOR_UNKNOWN};\n>  static char advice_colors[][COLOR_MAXLEN] = {\n>  \tGIT_COLOR_RESET,\n>  \tGIT_COLOR_YELLOW,\t/* HINT */\n> diff --git a/builtin/add.c b/builtin/add.c\n> index 4cd3d183f9..c9ca3466a3 100644\n> --- a/builtin/add.c\n> +++ b/builtin/add.c\n> @@ -200,7 +200,7 @@ static int edit_patch(struct repository *repo,\n>  \n>  \targc = setup_revisions(argc, argv, &rev, NULL);\n>  \trev.diffopt.output_format = DIFF_FORMAT_PATCH;\n> -\trev.diffopt.use_color = GIT_COLOR_NEVER;\n> +\trev.diffopt.use_color = (git_colorbool){GIT_COLOR_NEVER};\n>  \trev.diffopt.flags.ignore_dirty_submodules = 1;\n>  \tout = xopen(file, O_CREAT | O_WRONLY | O_TRUNC, 0666);\n>  \trev.diffopt.file = xfdopen(out, \"w\");\n> diff --git a/builtin/am.c b/builtin/am.c\n> index 277c2e7937..4c06b44607 100644\n> --- a/builtin/am.c\n> +++ b/builtin/am.c\n> @@ -1408,7 +1408,7 @@ static void write_commit_patch(const struct am_state *state, struct commit *comm\n>  \trev_info.no_commit_id = 1;\n>  \trev_info.diffopt.flags.binary = 1;\n>  \trev_info.diffopt.flags.full_index = 1;\n> -\trev_info.diffopt.use_color = GIT_COLOR_NEVER;\n> +\trev_info.diffopt.use_color = (git_colorbool){GIT_COLOR_NEVER};\n>  \trev_info.diffopt.file = fp;\n>  \trev_info.diffopt.close_file = 1;\n>  \tadd_pending_object(&rev_info, &commit->object, \"\");\n> @@ -1441,7 +1441,7 @@ static void write_index_patch(const struct am_state *state)\n>  \trev_info.disable_stdin = 1;\n>  \trev_info.no_commit_id = 1;\n>  \trev_info.diffopt.output_format = DIFF_FORMAT_PATCH;\n> -\trev_info.diffopt.use_color = GIT_COLOR_NEVER;\n> +\trev_info.diffopt.use_color = (git_colorbool){GIT_COLOR_NEVER};\n>  \trev_info.diffopt.file = fp;\n>  \trev_info.diffopt.close_file = 1;\n>  \tadd_pending_object(&rev_info, &tree->object, \"\");\n> diff --git a/builtin/branch.c b/builtin/branch.c\n> index 9fcf04bebb..f5dd0e00be 100644\n> --- a/builtin/branch.c\n> +++ b/builtin/branch.c\n> @@ -46,7 +46,7 @@ static struct object_id head_oid;\n>  static int recurse_submodules = 0;\n>  static int submodule_propagate_branches = 0;\n>  \n> -static enum git_colorbool branch_use_color = GIT_COLOR_UNKNOWN;\n> +static git_colorbool branch_use_color = {GIT_COLOR_UNKNOWN};\n>  static char branch_colors[][COLOR_MAXLEN] = {\n>  \tGIT_COLOR_RESET,\n>  \tGIT_COLOR_NORMAL,       /* PLAIN */\n> diff --git a/builtin/clean.c b/builtin/clean.c\n> index 1d5e7e5366..7f025aaea1 100644\n> --- a/builtin/clean.c\n> +++ b/builtin/clean.c\n> @@ -64,7 +64,7 @@ static const char *color_interactive_slots[] = {\n>  \t[CLEAN_COLOR_RESET]  = \"reset\",\n>  };\n>  \n> -static enum git_colorbool clean_use_color = GIT_COLOR_UNKNOWN;\n> +static git_colorbool clean_use_color = {GIT_COLOR_UNKNOWN};\n>  static char clean_colors[][COLOR_MAXLEN] = {\n>  \t[CLEAN_COLOR_ERROR] = GIT_COLOR_BOLD_RED,\n>  \t[CLEAN_COLOR_HEADER] = GIT_COLOR_BOLD,\n> diff --git a/builtin/commit.c b/builtin/commit.c\n> index d8f21a4c62..3c1c12845a 100644\n> --- a/builtin/commit.c\n> +++ b/builtin/commit.c\n> @@ -936,7 +936,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n>  \tstrbuf_addstr(&committer_ident, git_committer_info(IDENT_STRICT));\n>  \tif (use_editor && include_status) {\n>  \t\tint ident_shown = 0;\n> -\t\tenum git_colorbool saved_color_setting;\n> +\t\tgit_colorbool saved_color_setting;\n>  \t\tstruct ident_split ci, ai;\n>  \t\tconst char *hint_cleanup_all = allow_empty_message ?\n>  \t\t\t_(\"Please enter the commit message for your changes.\"\n> @@ -1016,7 +1016,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n>  \t\tstatus_printf_ln(s, GIT_COLOR_NORMAL, \"%s\", \"\"); /* Add new line for clarity */\n>  \n>  \t\tsaved_color_setting = s->use_color;\n> -\t\ts->use_color = GIT_COLOR_NEVER;\n> +\t\ts->use_color = (git_colorbool){GIT_COLOR_NEVER};\n>  \t\tcommittable = run_status(s->fp, index_file, prefix, 1, s);\n>  \t\ts->use_color = saved_color_setting;\n>  \t\tstring_list_clear_func(&s->change, change_data_free);\n> diff --git a/builtin/config.c b/builtin/config.c\n> index 2348a99dd4..4105c4c812 100644\n> --- a/builtin/config.c\n> +++ b/builtin/config.c\n> @@ -568,9 +568,9 @@ static void get_color(const struct config_location_options *opts,\n>  }\n>  \n>  struct get_colorbool_config_data {\n> -\tenum git_colorbool get_colorbool_found;\n> -\tenum git_colorbool get_diff_color_found;\n> -\tenum git_colorbool get_color_ui_found;\n> +\tgit_colorbool get_colorbool_found;\n> +\tgit_colorbool get_diff_color_found;\n> +\tgit_colorbool get_color_ui_found;\n>  \tconst char *get_colorbool_slot;\n>  };\n>  \n> @@ -594,26 +594,26 @@ static int get_colorbool(const struct config_location_options *opts,\n>  {\n>  \tstruct get_colorbool_config_data data = {\n>  \t\t.get_colorbool_slot = var,\n> -\t\t.get_colorbool_found = GIT_COLOR_UNKNOWN,\n> -\t\t.get_diff_color_found = GIT_COLOR_UNKNOWN,\n> -\t\t.get_color_ui_found = GIT_COLOR_UNKNOWN,\n> +\t\t.get_colorbool_found = {GIT_COLOR_UNKNOWN},\n> +\t\t.get_diff_color_found = {GIT_COLOR_UNKNOWN},\n> +\t\t.get_color_ui_found = {GIT_COLOR_UNKNOWN},\n>  \t};\n>  \tbool result;\n>  \n>  \tconfig_with_options(git_get_colorbool_config, &data,\n>  \t\t\t    &opts->source, the_repository,\n>  \t\t\t    &opts->options);\n>  \n> -\tif (data.get_colorbool_found == GIT_COLOR_UNKNOWN) {\n> +\tif (data.get_colorbool_found.f == GIT_COLOR_UNKNOWN) {\n>  \t\tif (!strcmp(data.get_colorbool_slot, \"color.diff\"))\n>  \t\t\tdata.get_colorbool_found = data.get_diff_color_found;\n> -\t\tif (data.get_colorbool_found == GIT_COLOR_UNKNOWN)\n> +\t\tif (data.get_colorbool_found.f == GIT_COLOR_UNKNOWN)\n>  \t\t\tdata.get_colorbool_found = data.get_color_ui_found;\n>  \t}\n>  \n> -\tif (data.get_colorbool_found == GIT_COLOR_UNKNOWN)\n> +\tif (data.get_colorbool_found.f == GIT_COLOR_UNKNOWN)\n>  \t\t/* default value if none found in config */\n> -\t\tdata.get_colorbool_found = GIT_COLOR_AUTO;\n> +\t\tdata.get_colorbool_found = (git_colorbool){GIT_COLOR_AUTO};\n>  \n>  \tresult = want_color(data.get_colorbool_found);\n>  \n> diff --git a/builtin/grep.c b/builtin/grep.c\n> index 1d97eb2a2a..3a6cdf9220 100644\n> --- a/builtin/grep.c\n> +++ b/builtin/grep.c\n> @@ -1091,7 +1091,7 @@ int cmd_grep(int argc,\n>  \tif (show_in_pager == default_pager)\n>  \t\tshow_in_pager = git_pager(the_repository, 1);\n>  \tif (show_in_pager) {\n> -\t\topt.color = GIT_COLOR_NEVER;\n> +\t\topt.color = (git_colorbool){GIT_COLOR_NEVER};\n>  \t\topt.name_only = 1;\n>  \t\topt.null_following_name = 1;\n>  \t\topt.output_priv = &path_list;\n> diff --git a/builtin/log.c b/builtin/log.c\n> index c2f8bbf863..960482c2f1 100644\n> --- a/builtin/log.c\n> +++ b/builtin/log.c\n> @@ -2193,8 +2193,8 @@ int cmd_format_patch(int argc,\n>  \t\t\toutput_directory = cfg.config_output_directory;\n>  \t\toutput_directory = set_outdir(prefix, output_directory);\n>  \n> -\t\tif (rev.diffopt.use_color != GIT_COLOR_ALWAYS)\n> -\t\t\trev.diffopt.use_color = GIT_COLOR_NEVER;\n> +\t\tif (rev.diffopt.use_color.f != GIT_COLOR_ALWAYS)\n> +\t\t\trev.diffopt.use_color = (git_colorbool){GIT_COLOR_NEVER};\n>  \t\t/*\n>  \t\t * We consider <outdir> as 'outside of gitdir', therefore avoid\n>  \t\t * applying adjust_shared_perm in s-c-l-d.\n> diff --git a/builtin/push.c b/builtin/push.c\n> index 5b6cebbb85..2c84eaac7b 100644\n> --- a/builtin/push.c\n> +++ b/builtin/push.c\n> @@ -27,7 +27,7 @@ static const char * const push_usage[] = {\n>  \tNULL,\n>  };\n>  \n> -static enum git_colorbool push_use_color = GIT_COLOR_UNKNOWN;\n> +static git_colorbool push_use_color = {GIT_COLOR_UNKNOWN};\n>  static char push_colors[][COLOR_MAXLEN] = {\n>  \tGIT_COLOR_RESET,\n>  \tGIT_COLOR_RED,\t/* ERROR */\n> diff --git a/builtin/range-diff.c b/builtin/range-diff.c\n> index 0d51ddd623..94ceaffac2 100644\n> --- a/builtin/range-diff.c\n> +++ b/builtin/range-diff.c\n> @@ -67,7 +67,7 @@ int cmd_range_diff(int argc,\n>  \n>  \t/* force color when --dual-color was used */\n>  \tif (!simple_color)\n> -\t\tdiffopt.use_color = GIT_COLOR_ALWAYS;\n> +\t\tdiffopt.use_color = (git_colorbool){GIT_COLOR_ALWAYS};\n>  \n>  \t/* If `--diff-merges` was specified, imply `--merges` */\n>  \tif (diff_merges_arg.nr) {\n> diff --git a/builtin/show-branch.c b/builtin/show-branch.c\n> index 441babf2e3..d5e9eb399a 100644\n> --- a/builtin/show-branch.c\n> +++ b/builtin/show-branch.c\n> @@ -29,7 +29,7 @@ static const char*const show_branch_usage[] = {\n>      NULL\n>  };\n>  \n> -static enum git_colorbool showbranch_use_color = GIT_COLOR_UNKNOWN;\n> +static git_colorbool showbranch_use_color = {GIT_COLOR_UNKNOWN};\n>  \n>  static struct strvec default_args = STRVEC_INIT;\n>  \n> diff --git a/color.c b/color.c\n> index 07ac8c9d40..14e994ab19 100644\n> --- a/color.c\n> +++ b/color.c\n> @@ -9,7 +9,7 @@\n>  #include \"pager.h\"\n>  #include \"strbuf.h\"\n>  \n> -static enum git_colorbool git_use_color_default = GIT_COLOR_AUTO;\n> +static git_colorbool git_use_color_default = {GIT_COLOR_AUTO};\n>  int color_stdout_is_tty = -1;\n>  \n>  /*\n> @@ -369,26 +369,26 @@ int color_parse_mem(const char *value, int value_len, char *dst)\n>  #undef OUT\n>  }\n>  \n> -enum git_colorbool git_config_colorbool(const char *var, const char *value)\n> +git_colorbool git_config_colorbool(const char *var, const char *value)\n>  {\n>  \tif (value) {\n>  \t\tif (!strcasecmp(value, \"never\"))\n> -\t\t\treturn GIT_COLOR_NEVER;\n> +\t\t\treturn (git_colorbool){GIT_COLOR_NEVER};\n>  \t\tif (!strcasecmp(value, \"always\"))\n> -\t\t\treturn GIT_COLOR_ALWAYS;\n> +\t\t\treturn (git_colorbool){GIT_COLOR_ALWAYS};\n>  \t\tif (!strcasecmp(value, \"auto\"))\n> -\t\t\treturn GIT_COLOR_AUTO;\n> +\t\t\treturn (git_colorbool){GIT_COLOR_AUTO};\n>  \t}\n>  \n>  \tif (!var)\n> -\t\treturn GIT_COLOR_UNKNOWN;\n> +\t\treturn (git_colorbool){GIT_COLOR_UNKNOWN};\n>  \n>  \t/* Missing or explicit false to turn off colorization */\n>  \tif (!git_config_bool(var, value))\n> -\t\treturn GIT_COLOR_NEVER;\n> +\t\treturn (git_colorbool){GIT_COLOR_NEVER};\n>  \n>  \t/* any normal truth value defaults to 'auto' */\n> -\treturn GIT_COLOR_AUTO;\n> +\treturn (git_colorbool){GIT_COLOR_AUTO};\n>  }\n>  \n>  static bool check_auto_color(int fd)\n> @@ -404,7 +404,7 @@ static bool check_auto_color(int fd)\n>  \treturn false;\n>  }\n>  \n> -bool want_color_fd(int fd, enum git_colorbool var)\n> +bool want_color_fd(int fd, git_colorbool var)\n>  {\n>  \t/*\n>  \t * NEEDSWORK: This function is sometimes used from multiple threads, and\n> @@ -418,15 +418,15 @@ bool want_color_fd(int fd, enum git_colorbool var)\n>  \tif (fd < 1 || fd >= ARRAY_SIZE(want_auto))\n>  \t\tBUG(\"file descriptor out of range: %d\", fd);\n>  \n> -\tif (var == GIT_COLOR_UNKNOWN)\n> +\tif (var.f == GIT_COLOR_UNKNOWN)\n>  \t\tvar = git_use_color_default;\n>  \n> -\tif (var == GIT_COLOR_AUTO) {\n> +\tif (var.f == GIT_COLOR_AUTO) {\n>  \t\tif (want_auto[fd] < 0)\n>  \t\t\twant_auto[fd] = check_auto_color(fd);\n>  \t\treturn want_auto[fd];\n>  \t}\n> -\treturn var == GIT_COLOR_ALWAYS;\n> +\treturn var.f == GIT_COLOR_ALWAYS;\n>  }\n>  \n>  int git_color_config(const char *var, const char *value, void *cb UNUSED)\n> diff --git a/color.h b/color.h\n> index 43e6c9ad09..5e735ce827 100644\n> --- a/color.h\n> +++ b/color.h\n> @@ -73,12 +73,13 @@ struct strbuf;\n>   * returned from git_config_colorbool. The \"auto\" value can be returned from\n>   * config_colorbool, and will be converted by want_color() into either 0 or 1.\n>   */\n> -enum git_colorbool {\n> +enum git_colorbool_f {\n>  \tGIT_COLOR_UNKNOWN = -1,\n>  \tGIT_COLOR_NEVER = 0,\n>  \tGIT_COLOR_ALWAYS = 1,\n>  \tGIT_COLOR_AUTO = 2,\n>  };\n> +typedef struct { enum git_colorbool_f f; } git_colorbool;\n>  \n>  /* A default list of colors to use for commit graphs and show-branch output */\n>  extern const char *column_colors_ansi[];\n> @@ -100,13 +101,13 @@ int git_color_config(const char *var, const char *value, void *cb);\n>   * GIT_COLOR_ALWAYS for \"always\" or a positive boolean,\n>   * and GIT_COLOR_AUTO for \"auto\".\n>   */\n> -enum git_colorbool git_config_colorbool(const char *var, const char *value);\n> +git_colorbool git_config_colorbool(const char *var, const char *value);\n>  \n>  /*\n>   * Return a boolean whether to use color, where the argument 'var' is\n>   * one of GIT_COLOR_UNKNOWN, GIT_COLOR_NEVER, GIT_COLOR_ALWAYS, GIT_COLOR_AUTO.\n>   */\n> -bool want_color_fd(int fd, enum git_colorbool var);\n> +bool want_color_fd(int fd, git_colorbool var);\n>  #define want_color(colorbool) want_color_fd(1, (colorbool))\n>  #define want_color_stderr(colorbool) want_color_fd(2, (colorbool))\n>  \n> diff --git a/combine-diff.c b/combine-diff.c\n> index 21b7fdfff4..d70939ed71 100644\n> --- a/combine-diff.c\n> +++ b/combine-diff.c\n> @@ -749,7 +749,7 @@ static void show_line_to_eol(const char *line, int len, const char *reset)\n>  \n>  static void dump_sline(struct sline *sline, const char *line_prefix,\n>  \t\t       unsigned long cnt, int num_parent,\n> -\t\t       enum git_colorbool use_color, int result_deleted)\n> +\t\t       git_colorbool use_color, int result_deleted)\n>  {\n>  \tunsigned long mark = (1UL<<num_parent);\n>  \tunsigned long no_pre_delete = (2UL<<num_parent);\n> diff --git a/diff.c b/diff.c\n> index 87fa16b730..59a9286aea 100644\n> --- a/diff.c\n> +++ b/diff.c\n> @@ -57,7 +57,7 @@ static int diff_detect_rename_default;\n>  static int diff_indent_heuristic = 1;\n>  static int diff_rename_limit_default = 1000;\n>  static int diff_suppress_blank_empty;\n> -static enum git_colorbool diff_use_color_default = GIT_COLOR_UNKNOWN;\n> +static git_colorbool diff_use_color_default = {GIT_COLOR_UNKNOWN};\n>  static int diff_color_moved_default;\n>  static int diff_color_moved_ws_default;\n>  static int diff_context_default = 3;\n> @@ -595,7 +595,7 @@ static struct diff_tempfile {\n>  } diff_temp[2];\n>  \n>  struct emit_callback {\n> -\tint color_diff;\n> +\tgit_colorbool color_diff;\n>  \tunsigned ws_rule;\n>  \tint blank_at_eof_in_preimage;\n>  \tint blank_at_eof_in_postimage;\n> @@ -2303,7 +2303,7 @@ static void free_diff_words_data(struct emit_callback *ecbdata)\n>  \t}\n>  }\n>  \n> -const char *diff_get_color(enum git_colorbool diff_use_color, enum color_diff ix)\n> +const char *diff_get_color(git_colorbool diff_use_color, enum color_diff ix)\n>  {\n>  \tif (want_color(diff_use_color))\n>  \t\treturn diff_colors[ix];\n> @@ -4497,7 +4497,7 @@ static void fill_metainfo(struct strbuf *msg,\n>  \t\t\t  struct diff_options *o,\n>  \t\t\t  struct diff_filepair *p,\n>  \t\t\t  int *must_show_header,\n> -\t\t\t  enum git_colorbool use_color)\n> +\t\t\t  git_colorbool use_color)\n>  {\n>  \tconst char *set = diff_get_color(use_color, DIFF_METAINFO);\n>  \tconst char *reset = diff_get_color(use_color, DIFF_RESET);\n> @@ -4596,7 +4596,7 @@ static void run_diff_cmd(const struct external_diff *pgm,\n>  \t\t */\n>  \t\tfill_metainfo(msg, name, other, one, two, o, p,\n>  \t\t\t      &must_show_header,\n> -\t\t\t      pgm ? GIT_COLOR_NEVER : o->use_color);\n> +\t\t\t      pgm ? (git_colorbool){GIT_COLOR_NEVER} : o->use_color);\n>  \t\txfrm_msg = msg->len ? msg->buf : NULL;\n>  \t}\n>  \n> @@ -5277,7 +5277,7 @@ static int diff_opt_color_words(const struct option *opt,\n>  \tstruct diff_options *options = opt->value;\n>  \n>  \tBUG_ON_OPT_NEG(unset);\n> -\toptions->use_color = GIT_COLOR_ALWAYS;\n> +\toptions->use_color = (git_colorbool){GIT_COLOR_ALWAYS};\n>  \toptions->word_diff = DIFF_WORDS_COLOR;\n>  \toptions->word_regex = arg;\n>  \treturn 0;\n> @@ -5458,8 +5458,8 @@ static enum parse_opt_result diff_opt_output(struct parse_opt_ctx_t *ctx,\n>  \tpath = prefix_filename(ctx->prefix, arg);\n>  \toptions->file = xfopen(path, \"w\");\n>  \toptions->close_file = 1;\n> -\tif (options->use_color != GIT_COLOR_ALWAYS)\n> -\t\toptions->use_color = GIT_COLOR_NEVER;\n> +\tif (options->use_color.f != GIT_COLOR_ALWAYS)\n> +\t\toptions->use_color = (git_colorbool){GIT_COLOR_NEVER};\n>  \tfree(path);\n>  \treturn 0;\n>  }\n> @@ -5599,7 +5599,7 @@ static int diff_opt_word_diff(const struct option *opt,\n>  \t\tif (!strcmp(arg, \"plain\"))\n>  \t\t\toptions->word_diff = DIFF_WORDS_PLAIN;\n>  \t\telse if (!strcmp(arg, \"color\")) {\n> -\t\t\toptions->use_color = GIT_COLOR_ALWAYS;\n> +\t\t\toptions->use_color = (git_colorbool){GIT_COLOR_ALWAYS};\n>  \t\t\toptions->word_diff = DIFF_WORDS_COLOR;\n>  \t\t}\n>  \t\telse if (!strcmp(arg, \"porcelain\"))\n> diff --git a/diff.h b/diff.h\n> index bccd86a748..197dcb997f 100644\n> --- a/diff.h\n> +++ b/diff.h\n> @@ -284,7 +284,7 @@ struct diff_options {\n>  \t/* diff-filter bits */\n>  \tunsigned int filter, filter_not;\n>  \n> -\tenum git_colorbool use_color;\n> +\tgit_colorbool use_color;\n>  \n>  \t/* Number of context lines to generate in patch output. */\n>  \tint context;\n> @@ -470,7 +470,7 @@ enum color_diff {\n>  \tDIFF_FILE_NEW_BOLD = 22,\n>  };\n>  \n> -const char *diff_get_color(enum git_colorbool diff_use_color, enum color_diff ix);\n> +const char *diff_get_color(git_colorbool diff_use_color, enum color_diff ix);\n>  #define diff_get_color_opt(o, ix) \\\n>  \tdiff_get_color((o)->use_color, ix)\n>  \n> diff --git a/grep.h b/grep.h\n> index 13e26a9318..0cc2806cae 100644\n> --- a/grep.h\n> +++ b/grep.h\n> @@ -159,7 +159,7 @@ struct grep_opt {\n>  \tint pathname;\n>  \tint null_following_name;\n>  \tint only_matching;\n> -\tenum git_colorbool color;\n> +\tgit_colorbool color;\n>  \tint max_depth;\n>  \tint funcname;\n>  \tint funcbody;\n> @@ -198,7 +198,7 @@ struct grep_opt {\n>  \t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \\\n>  \t}, \\\n>  \t.only_matching = 0, \\\n> -\t.color = GIT_COLOR_UNKNOWN, \\\n> +\t.color = {GIT_COLOR_UNKNOWN}, \\\n>  \t.output = std_output, \\\n>  }\n>  \n> diff --git a/log-tree.c b/log-tree.c\n> index a2cd5c587b..df41c5c963 100644\n> --- a/log-tree.c\n> +++ b/log-tree.c\n> @@ -57,7 +57,7 @@ static const char *color_decorate_slots[] = {\n>  \t[DECORATION_GRAFTED]\t= \"grafted\",\n>  };\n>  \n> -static const char *decorate_get_color(enum git_colorbool decorate_use_color, enum decoration_type ix)\n> +static const char *decorate_get_color(git_colorbool decorate_use_color, enum decoration_type ix)\n>  {\n>  \tif (want_color(decorate_use_color))\n>  \t\treturn decoration_colors[ix];\n> @@ -341,7 +341,7 @@ static void show_name(struct strbuf *sb, const struct name_decoration *decoratio\n>   */\n>  void format_decorations(struct strbuf *sb,\n>  \t\t\tconst struct commit *commit,\n> -\t\t\tenum git_colorbool use_color,\n> +\t\t\tgit_colorbool use_color,\n>  \t\t\tconst struct decoration_options *opts)\n>  {\n>  \tconst struct name_decoration *decoration;\n> diff --git a/log-tree.h b/log-tree.h\n> index 1c82380d95..43ab208a7d 100644\n> --- a/log-tree.h\n> +++ b/log-tree.h\n> @@ -26,7 +26,7 @@ int log_tree_diff_flush(struct rev_info *);\n>  int log_tree_commit(struct rev_info *, struct commit *);\n>  void show_log(struct rev_info *opt);\n>  void format_decorations(struct strbuf *sb, const struct commit *commit,\n> -\t\t\tenum git_colorbool use_color, const struct decoration_options *opts);\n> +\t\t\tgit_colorbool use_color, const struct decoration_options *opts);\n>  void show_decorations(struct rev_info *opt, struct commit *commit);\n>  void log_write_email_headers(struct rev_info *opt, struct commit *commit,\n>  \t\t\t     char **extra_headers_p,\n> diff --git a/parse-options-cb.c b/parse-options-cb.c\n> index 976cc86385..5f0e027139 100644\n> --- a/parse-options-cb.c\n> +++ b/parse-options-cb.c\n> @@ -50,15 +50,15 @@ int parse_opt_expiry_date_cb(const struct option *opt, const char *arg,\n>  int parse_opt_color_flag_cb(const struct option *opt, const char *arg,\n>  \t\t\t    int unset)\n>  {\n> -\tenum git_colorbool value;\n> +\tgit_colorbool value;\n>  \n>  \tif (!arg)\n>  \t\targ = unset ? \"never\" : (const char *)opt->defval;\n>  \tvalue = git_config_colorbool(NULL, arg);\n> -\tif (value == GIT_COLOR_UNKNOWN)\n> +\tif (value.f == GIT_COLOR_UNKNOWN)\n>  \t\treturn error(_(\"option `%s' expects \\\"always\\\", \\\"auto\\\", or \\\"never\\\"\"),\n>  \t\t\t     opt->long_name);\n> -\t*(int *)opt->value = value;\n> +\t*(git_colorbool *)opt->value = value;\n>  \treturn 0;\n>  }\n>  \n> diff --git a/pretty.c b/pretty.c\n> index e0646bbc5d..fcf7ee3d78 100644\n> --- a/pretty.c\n> +++ b/pretty.c\n> @@ -470,7 +470,7 @@ static inline void strbuf_add_with_color(struct strbuf *sb, const char *color,\n>  \n>  static void append_line_with_color(struct strbuf *sb, struct grep_opt *opt,\n>  \t\t\t\t   const char *line, size_t linelen,\n> -\t\t\t\t   enum git_colorbool color, enum grep_context ctx,\n> +\t\t\t\t   git_colorbool color, enum grep_context ctx,\n>  \t\t\t\t   enum grep_header_field field)\n>  {\n>  \tconst char *buf, *eol, *line_color, *match_color;\n> @@ -899,7 +899,7 @@ struct format_commit_context {\n>  \tconst char *message;\n>  \tchar *commit_encoding;\n>  \tsize_t width, indent1, indent2;\n> -\tenum git_colorbool auto_color;\n> +\tgit_colorbool auto_color;\n>  \tint padding;\n>  \n>  \t/* These offsets are relative to the start of the commit message. */\n> @@ -1462,7 +1462,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */\n>  \t\t} else {\n>  \t\t\tint ret = parse_color(sb, placeholder, c);\n>  \t\t\tif (ret)\n> -\t\t\t\tc->auto_color = GIT_COLOR_NEVER;\n> +\t\t\t\tc->auto_color = (git_colorbool){GIT_COLOR_NEVER};\n>  \t\t\t/*\n>  \t\t\t * Otherwise, we decided to treat %C<unknown>\n>  \t\t\t * as a literal string, and the previous\n> @@ -2167,7 +2167,7 @@ static int pp_utf8_width(const char *start, const char *end)\n>  }\n>  \n>  static void strbuf_add_tabexpand(struct strbuf *sb, struct grep_opt *opt,\n> -\t\t\t\t enum git_colorbool color, int tabwidth, const char *line,\n> +\t\t\t\t git_colorbool color, int tabwidth, const char *line,\n>  \t\t\t\t int linelen)\n>  {\n>  \tconst char *tab;\n> diff --git a/pretty.h b/pretty.h\n> index fac699033e..915c866c53 100644\n> --- a/pretty.h\n> +++ b/pretty.h\n> @@ -47,7 +47,7 @@ struct pretty_print_context {\n>  \tstruct rev_info *rev;\n>  \tconst char *output_encoding;\n>  \tstruct string_list *mailmap;\n> -\tenum git_colorbool color;\n> +\tgit_colorbool color;\n>  \tstruct ident_split *from_ident;\n>  \tunsigned encode_email_headers:1;\n>  \tstruct pretty_print_describe_status *describe_status;\n> diff --git a/ref-filter.h b/ref-filter.h\n> index 81f2c229a9..66f96a330a 100644\n> --- a/ref-filter.h\n> +++ b/ref-filter.h\n> @@ -95,7 +95,7 @@ struct ref_format {\n>  \tconst char *format;\n>  \tconst char *rest;\n>  \tint quote_style;\n> -\tenum git_colorbool use_color;\n> +\tgit_colorbool use_color;\n>  \n>  \t/* Internal state to ref-filter */\n>  \tint need_color_reset_at_eol;\n> @@ -111,7 +111,7 @@ struct ref_format {\n>  \t.exclude = STRVEC_INIT, \\\n>  }\n>  #define REF_FORMAT_INIT {             \\\n> -\t.use_color = GIT_COLOR_UNKNOWN, \\\n> +\t.use_color = {GIT_COLOR_UNKNOWN}, \\\n>  }\n>  \n>  /*  Macros for checking --merged and --no-merged options */\n> diff --git a/sequencer.c b/sequencer.c\n> index 9ae40a91b2..56999de1ec 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -3732,7 +3732,7 @@ static int make_patch(struct repository *r,\n>  \tlog_tree_opt.disable_stdin = 1;\n>  \tlog_tree_opt.no_commit_id = 1;\n>  \tlog_tree_opt.diffopt.file = fopen(rebase_path_patch(), \"w\");\n> -\tlog_tree_opt.diffopt.use_color = GIT_COLOR_NEVER;\n> +\tlog_tree_opt.diffopt.use_color = (git_colorbool){GIT_COLOR_NEVER};\n>  \tif (!log_tree_opt.diffopt.file)\n>  \t\tres |= error_errno(_(\"could not open '%s'\"),\n>  \t\t\t\t   rebase_path_patch());\n> diff --git a/sideband.c b/sideband.c\n> index ea7c25211e..fb7b6a7e46 100644\n> --- a/sideband.c\n> +++ b/sideband.c\n> @@ -27,24 +27,24 @@ static struct keyword_entry keywords[] = {\n>  };\n>  \n>  /* Returns a color setting (GIT_COLOR_NEVER, etc). */\n> -static enum git_colorbool use_sideband_colors(void)\n> +static git_colorbool use_sideband_colors(void)\n>  {\n> -\tstatic enum git_colorbool use_sideband_colors_cached = GIT_COLOR_UNKNOWN;\n> +\tstatic git_colorbool use_sideband_colors_cached = {GIT_COLOR_UNKNOWN};\n>  \n>  \tconst char *key = \"color.remote\";\n>  \tstruct strbuf sb = STRBUF_INIT;\n>  \tconst char *value;\n>  \tint i;\n>  \n> -\tif (use_sideband_colors_cached != GIT_COLOR_UNKNOWN)\n> +\tif (use_sideband_colors_cached.f != GIT_COLOR_UNKNOWN)\n>  \t\treturn use_sideband_colors_cached;\n>  \n>  \tif (!repo_config_get_string_tmp(the_repository, key, &value))\n>  \t\tuse_sideband_colors_cached = git_config_colorbool(key, value);\n>  \telse if (!repo_config_get_string_tmp(the_repository, \"color.ui\", &value))\n>  \t\tuse_sideband_colors_cached = git_config_colorbool(\"color.ui\", value);\n>  \telse\n> -\t\tuse_sideband_colors_cached = GIT_COLOR_AUTO;\n> +\t\tuse_sideband_colors_cached = (git_colorbool){GIT_COLOR_AUTO};\n>  \n>  \tfor (i = 0; i < ARRAY_SIZE(keywords); i++) {\n>  \t\tstrbuf_reset(&sb);\n> diff --git a/transport.c b/transport.c\n> index c7f06a7382..a5f98ba6b6 100644\n> --- a/transport.c\n> +++ b/transport.c\n> @@ -30,7 +30,7 @@\n>  #include \"color.h\"\n>  #include \"bundle-uri.h\"\n>  \n> -static enum git_colorbool transport_use_color = GIT_COLOR_UNKNOWN;\n> +static git_colorbool transport_use_color = {GIT_COLOR_UNKNOWN};\n>  static char transport_colors[][COLOR_MAXLEN] = {\n>  \tGIT_COLOR_RESET,\n>  \tGIT_COLOR_RED\t\t/* REJECTED */\n> diff --git a/wt-status.c b/wt-status.c\n> index 8ffe6d3988..0927b88734 100644\n> --- a/wt-status.c\n> +++ b/wt-status.c\n> @@ -148,7 +148,7 @@ void wt_status_prepare(struct repository *r, struct wt_status *s)\n>  \tmemcpy(s->color_palette, default_wt_status_colors,\n>  \t       sizeof(default_wt_status_colors));\n>  \ts->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;\n> -\ts->use_color = GIT_COLOR_UNKNOWN;\n> +\ts->use_color = (git_colorbool){GIT_COLOR_UNKNOWN};\n>  \ts->relative_paths = 1;\n>  \ts->branch = refs_resolve_refdup(get_main_ref_store(the_repository),\n>  \t\t\t\t\t\"HEAD\", 0, NULL, NULL);\n> @@ -1165,7 +1165,7 @@ static void wt_longstatus_print_verbose(struct wt_status *s)\n>  \t * before.\n>  \t */\n>  \tif (s->fp != stdout) {\n> -\t\trev.diffopt.use_color = GIT_COLOR_NEVER;\n> +\t\trev.diffopt.use_color = (git_colorbool){GIT_COLOR_NEVER};\n>  \t\twt_status_add_cut_line(s);\n>  \t}\n>  \tif (s->verbose > 1 && s->committable) {\n> @@ -2155,7 +2155,7 @@ static void wt_shortstatus_print(struct wt_status *s)\n>  \n>  static void wt_porcelain_print(struct wt_status *s)\n>  {\n> -\ts->use_color = GIT_COLOR_NEVER;\n> +\ts->use_color = (git_colorbool){GIT_COLOR_NEVER};\n>  \ts->relative_paths = 0;\n>  \ts->prefix = NULL;\n>  \ts->no_gettext = 1;\n> diff --git a/wt-status.h b/wt-status.h\n> index e40a27214a..5364eaa1f8 100644\n> --- a/wt-status.h\n> +++ b/wt-status.h\n> @@ -111,7 +111,7 @@ struct wt_status {\n>  \tint amend;\n>  \tenum commit_whence whence;\n>  \tint nowarn;\n> -\tenum git_colorbool use_color;\n> +\tgit_colorbool use_color;\n>  \tint no_gettext;\n>  \tint display_comment_prefix;\n>  \tint relative_paths;\n"},{"id":"526515","messageId":"20250916231359.GA1186207@coredump.intra.peff.net","threadId":"64153","inReplyTo":"20250916202408.GI612873@coredump.intra.peff.net","subject":"[PATCH v1.5 9/13] color: use git_colorbool enum type to store colorbools","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2025-09-16T23:13:59Z","receivedAt":"2025-09-16T23:14:00Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Sep 16, 2025 at 04:24:09PM -0400, Jeff King wrote:\n\n> Subject: Re: [PATCH 09/13] color: use git_colorbool enum to type to store colorbools\n\nI missed a typo in the subject (I do my final proofread in my MUA as I send them\nout, so it's easy to glance past the subject).\n\nAlso, I belatedly noticed a CI failure here: \"make hdr-check\" complains\nand we need to squash this in to get the enum definition (I don't think\nwe can forward declare it because the compiler needs to know what values\nit takes to compute the size):\n\n    diff --git a/log-tree.h b/log-tree.h\n    index 1c82380d95..07924be8bc 100644\n    --- a/log-tree.h\n    +++ b/log-tree.h\n    @@ -1,6 +1,8 @@\n     #ifndef LOG_TREE_H\n     #define LOG_TREE_H\n     \n    +#include \"color.h\"\n    +\n     struct rev_info;\n     \n     struct log_info {\n\nSo here's a quick re-roll of just patch 9 here. Fingers crossed that I\nwon't need to re-send the whole thing as a v2 as soon as I get some\nreview. ;)\n\n-- >8 --\nSubject: color: use git_colorbool enum type to store colorbools\n\nWe traditionally used \"int\" to store and pass around the values defined\nby \"enum git_colorbool\" (which were originally just #define macros).\nUsing an int doesn't produce incorrect results, but using the actual\nenum makes the intent of the code more clear.\n\nIt would be nice if the compiler could catch cases where we used the\nenum and an int interchangeably, since it's very easy to accidentally\ncheck the boolean true/false of a colorbool like:\n\n  if (branch_use_color)\n\nThis is wrong because GIT_COLOR_UNKNOWN and GIT_COLOR_AUTO evaluate to\ntrue in C, even though we may ultimately decide not to use color. But C\nis pretty happy to convert between ints and enums (even with various\n-Wenum-* warnings). So this sadly doesn't protect us from such mistakes,\nbut it hopefully does make the code easier to read.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n add-interactive.c     | 2 +-\n advice.c              | 2 +-\n builtin/branch.c      | 2 +-\n builtin/clean.c       | 2 +-\n builtin/commit.c      | 2 +-\n builtin/config.c      | 6 +++---\n builtin/push.c        | 2 +-\n builtin/show-branch.c | 2 +-\n color.c               | 4 ++--\n color.h               | 2 +-\n combine-diff.c        | 2 +-\n diff.c                | 6 +++---\n diff.h                | 5 +++--\n grep.h                | 2 +-\n log-tree.c            | 4 ++--\n log-tree.h            | 4 +++-\n parse-options-cb.c    | 2 +-\n pretty.c              | 6 +++---\n pretty.h              | 3 ++-\n ref-filter.h          | 2 +-\n sideband.c            | 4 ++--\n transport.c           | 2 +-\n wt-status.h           | 2 +-\n 23 files changed, 37 insertions(+), 33 deletions(-)\n\ndiff --git a/add-interactive.c b/add-interactive.c\nindex 34c020673e..000315971e 100644\n--- a/add-interactive.c\n+++ b/add-interactive.c\n@@ -39,7 +39,7 @@ static void init_color(struct repository *r, int use_color,\n static int check_color_config(struct repository *r, const char *var)\n {\n \tconst char *value;\n-\tint ret;\n+\tenum git_colorbool ret;\n \n \tif (repo_config_get_value(r, var, &value))\n \t\tret = GIT_COLOR_UNKNOWN;\ndiff --git a/advice.c b/advice.c\nindex a00aaad9de..0018501b7b 100644\n--- a/advice.c\n+++ b/advice.c\n@@ -7,7 +7,7 @@\n #include \"help.h\"\n #include \"string-list.h\"\n \n-static int advice_use_color = GIT_COLOR_UNKNOWN;\n+static enum git_colorbool advice_use_color = GIT_COLOR_UNKNOWN;\n static char advice_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n \tGIT_COLOR_YELLOW,\t/* HINT */\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 029223df7b..9fcf04bebb 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -46,7 +46,7 @@ static struct object_id head_oid;\n static int recurse_submodules = 0;\n static int submodule_propagate_branches = 0;\n \n-static int branch_use_color = GIT_COLOR_UNKNOWN;\n+static enum git_colorbool branch_use_color = GIT_COLOR_UNKNOWN;\n static char branch_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n \tGIT_COLOR_NORMAL,       /* PLAIN */\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 0ac90a3feb..1d5e7e5366 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -64,7 +64,7 @@ static const char *color_interactive_slots[] = {\n \t[CLEAN_COLOR_RESET]  = \"reset\",\n };\n \n-static int clean_use_color = GIT_COLOR_UNKNOWN;\n+static enum git_colorbool clean_use_color = GIT_COLOR_UNKNOWN;\n static char clean_colors[][COLOR_MAXLEN] = {\n \t[CLEAN_COLOR_ERROR] = GIT_COLOR_BOLD_RED,\n \t[CLEAN_COLOR_HEADER] = GIT_COLOR_BOLD,\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 544603a9c7..d8f21a4c62 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -936,7 +936,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \tstrbuf_addstr(&committer_ident, git_committer_info(IDENT_STRICT));\n \tif (use_editor && include_status) {\n \t\tint ident_shown = 0;\n-\t\tint saved_color_setting;\n+\t\tenum git_colorbool saved_color_setting;\n \t\tstruct ident_split ci, ai;\n \t\tconst char *hint_cleanup_all = allow_empty_message ?\n \t\t\t_(\"Please enter the commit message for your changes.\"\ndiff --git a/builtin/config.c b/builtin/config.c\nindex c3da3ae210..9e4e4eb2f1 100644\n--- a/builtin/config.c\n+++ b/builtin/config.c\n@@ -568,9 +568,9 @@ static void get_color(const struct config_location_options *opts,\n }\n \n struct get_colorbool_config_data {\n-\tint get_colorbool_found;\n-\tint get_diff_color_found;\n-\tint get_color_ui_found;\n+\tenum git_colorbool get_colorbool_found;\n+\tenum git_colorbool get_diff_color_found;\n+\tenum git_colorbool get_color_ui_found;\n \tconst char *get_colorbool_slot;\n };\n \ndiff --git a/builtin/push.c b/builtin/push.c\nindex 0962b122c7..5b6cebbb85 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -27,7 +27,7 @@ static const char * const push_usage[] = {\n \tNULL,\n };\n \n-static int push_use_color = GIT_COLOR_UNKNOWN;\n+static enum git_colorbool push_use_color = GIT_COLOR_UNKNOWN;\n static char push_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n \tGIT_COLOR_RED,\t/* ERROR */\ndiff --git a/builtin/show-branch.c b/builtin/show-branch.c\nindex 970e78bc2d..441babf2e3 100644\n--- a/builtin/show-branch.c\n+++ b/builtin/show-branch.c\n@@ -29,7 +29,7 @@ static const char*const show_branch_usage[] = {\n     NULL\n };\n \n-static int showbranch_use_color = GIT_COLOR_UNKNOWN;\n+static enum git_colorbool showbranch_use_color = GIT_COLOR_UNKNOWN;\n \n static struct strvec default_args = STRVEC_INIT;\n \ndiff --git a/color.c b/color.c\nindex f3adce0141..3348ead534 100644\n--- a/color.c\n+++ b/color.c\n@@ -9,7 +9,7 @@\n #include \"pager.h\"\n #include \"strbuf.h\"\n \n-static int git_use_color_default = GIT_COLOR_AUTO;\n+static enum git_colorbool git_use_color_default = GIT_COLOR_AUTO;\n int color_stdout_is_tty = -1;\n \n /*\n@@ -404,7 +404,7 @@ static int check_auto_color(int fd)\n \treturn 0;\n }\n \n-int want_color_fd(int fd, int var)\n+int want_color_fd(int fd, enum git_colorbool var)\n {\n \t/*\n \t * NEEDSWORK: This function is sometimes used from multiple threads, and\ndiff --git a/color.h b/color.h\nindex 303e2c9a6d..fcb38c5562 100644\n--- a/color.h\n+++ b/color.h\n@@ -106,7 +106,7 @@ enum git_colorbool git_config_colorbool(const char *var, const char *value);\n  * Return a boolean whether to use color, where the argument 'var' is\n  * one of GIT_COLOR_UNKNOWN, GIT_COLOR_NEVER, GIT_COLOR_ALWAYS, GIT_COLOR_AUTO.\n  */\n-int want_color_fd(int fd, int var);\n+int want_color_fd(int fd, enum git_colorbool var);\n #define want_color(colorbool) want_color_fd(1, (colorbool))\n #define want_color_stderr(colorbool) want_color_fd(2, (colorbool))\n \ndiff --git a/combine-diff.c b/combine-diff.c\nindex 3878faabe7..21b7fdfff4 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -749,7 +749,7 @@ static void show_line_to_eol(const char *line, int len, const char *reset)\n \n static void dump_sline(struct sline *sline, const char *line_prefix,\n \t\t       unsigned long cnt, int num_parent,\n-\t\t       int use_color, int result_deleted)\n+\t\t       enum git_colorbool use_color, int result_deleted)\n {\n \tunsigned long mark = (1UL<<num_parent);\n \tunsigned long no_pre_delete = (2UL<<num_parent);\ndiff --git a/diff.c b/diff.c\nindex 926429d55b..87fa16b730 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -57,7 +57,7 @@ static int diff_detect_rename_default;\n static int diff_indent_heuristic = 1;\n static int diff_rename_limit_default = 1000;\n static int diff_suppress_blank_empty;\n-static int diff_use_color_default = GIT_COLOR_UNKNOWN;\n+static enum git_colorbool diff_use_color_default = GIT_COLOR_UNKNOWN;\n static int diff_color_moved_default;\n static int diff_color_moved_ws_default;\n static int diff_context_default = 3;\n@@ -2303,7 +2303,7 @@ static void free_diff_words_data(struct emit_callback *ecbdata)\n \t}\n }\n \n-const char *diff_get_color(int diff_use_color, enum color_diff ix)\n+const char *diff_get_color(enum git_colorbool diff_use_color, enum color_diff ix)\n {\n \tif (want_color(diff_use_color))\n \t\treturn diff_colors[ix];\n@@ -4497,7 +4497,7 @@ static void fill_metainfo(struct strbuf *msg,\n \t\t\t  struct diff_options *o,\n \t\t\t  struct diff_filepair *p,\n \t\t\t  int *must_show_header,\n-\t\t\t  int use_color)\n+\t\t\t  enum git_colorbool use_color)\n {\n \tconst char *set = diff_get_color(use_color, DIFF_METAINFO);\n \tconst char *reset = diff_get_color(use_color, DIFF_RESET);\ndiff --git a/diff.h b/diff.h\nindex 9bb939a4f1..bccd86a748 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -7,6 +7,7 @@\n #include \"hash.h\"\n #include \"pathspec.h\"\n #include \"strbuf.h\"\n+#include \"color.h\"\n \n struct oidset;\n \n@@ -283,7 +284,7 @@ struct diff_options {\n \t/* diff-filter bits */\n \tunsigned int filter, filter_not;\n \n-\tint use_color;\n+\tenum git_colorbool use_color;\n \n \t/* Number of context lines to generate in patch output. */\n \tint context;\n@@ -469,7 +470,7 @@ enum color_diff {\n \tDIFF_FILE_NEW_BOLD = 22,\n };\n \n-const char *diff_get_color(int diff_use_color, enum color_diff ix);\n+const char *diff_get_color(enum git_colorbool diff_use_color, enum color_diff ix);\n #define diff_get_color_opt(o, ix) \\\n \tdiff_get_color((o)->use_color, ix)\n \ndiff --git a/grep.h b/grep.h\nindex 43195baab3..13e26a9318 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -159,7 +159,7 @@ struct grep_opt {\n \tint pathname;\n \tint null_following_name;\n \tint only_matching;\n-\tint color;\n+\tenum git_colorbool color;\n \tint max_depth;\n \tint funcname;\n \tint funcbody;\ndiff --git a/log-tree.c b/log-tree.c\nindex 233bf9f227..a2cd5c587b 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -57,7 +57,7 @@ static const char *color_decorate_slots[] = {\n \t[DECORATION_GRAFTED]\t= \"grafted\",\n };\n \n-static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix)\n+static const char *decorate_get_color(enum git_colorbool decorate_use_color, enum decoration_type ix)\n {\n \tif (want_color(decorate_use_color))\n \t\treturn decoration_colors[ix];\n@@ -341,7 +341,7 @@ static void show_name(struct strbuf *sb, const struct name_decoration *decoratio\n  */\n void format_decorations(struct strbuf *sb,\n \t\t\tconst struct commit *commit,\n-\t\t\tint use_color,\n+\t\t\tenum git_colorbool use_color,\n \t\t\tconst struct decoration_options *opts)\n {\n \tconst struct name_decoration *decoration;\ndiff --git a/log-tree.h b/log-tree.h\nindex ebe491c543..07924be8bc 100644\n--- a/log-tree.h\n+++ b/log-tree.h\n@@ -1,6 +1,8 @@\n #ifndef LOG_TREE_H\n #define LOG_TREE_H\n \n+#include \"color.h\"\n+\n struct rev_info;\n \n struct log_info {\n@@ -26,7 +28,7 @@ int log_tree_diff_flush(struct rev_info *);\n int log_tree_commit(struct rev_info *, struct commit *);\n void show_log(struct rev_info *opt);\n void format_decorations(struct strbuf *sb, const struct commit *commit,\n-\t\t\tint use_color, const struct decoration_options *opts);\n+\t\t\tenum git_colorbool use_color, const struct decoration_options *opts);\n void show_decorations(struct rev_info *opt, struct commit *commit);\n void log_write_email_headers(struct rev_info *opt, struct commit *commit,\n \t\t\t     char **extra_headers_p,\ndiff --git a/parse-options-cb.c b/parse-options-cb.c\nindex e13e0a9e33..976cc86385 100644\n--- a/parse-options-cb.c\n+++ b/parse-options-cb.c\n@@ -50,7 +50,7 @@ int parse_opt_expiry_date_cb(const struct option *opt, const char *arg,\n int parse_opt_color_flag_cb(const struct option *opt, const char *arg,\n \t\t\t    int unset)\n {\n-\tint value;\n+\tenum git_colorbool value;\n \n \tif (!arg)\n \t\targ = unset ? \"never\" : (const char *)opt->defval;\ndiff --git a/pretty.c b/pretty.c\nindex 86d69bf877..e0646bbc5d 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -470,7 +470,7 @@ static inline void strbuf_add_with_color(struct strbuf *sb, const char *color,\n \n static void append_line_with_color(struct strbuf *sb, struct grep_opt *opt,\n \t\t\t\t   const char *line, size_t linelen,\n-\t\t\t\t   int color, enum grep_context ctx,\n+\t\t\t\t   enum git_colorbool color, enum grep_context ctx,\n \t\t\t\t   enum grep_header_field field)\n {\n \tconst char *buf, *eol, *line_color, *match_color;\n@@ -899,7 +899,7 @@ struct format_commit_context {\n \tconst char *message;\n \tchar *commit_encoding;\n \tsize_t width, indent1, indent2;\n-\tint auto_color;\n+\tenum git_colorbool auto_color;\n \tint padding;\n \n \t/* These offsets are relative to the start of the commit message. */\n@@ -2167,7 +2167,7 @@ static int pp_utf8_width(const char *start, const char *end)\n }\n \n static void strbuf_add_tabexpand(struct strbuf *sb, struct grep_opt *opt,\n-\t\t\t\t int color, int tabwidth, const char *line,\n+\t\t\t\t enum git_colorbool color, int tabwidth, const char *line,\n \t\t\t\t int linelen)\n {\n \tconst char *tab;\ndiff --git a/pretty.h b/pretty.h\nindex df267afe4a..fac699033e 100644\n--- a/pretty.h\n+++ b/pretty.h\n@@ -3,6 +3,7 @@\n \n #include \"date.h\"\n #include \"string-list.h\"\n+#include \"color.h\"\n \n struct commit;\n struct repository;\n@@ -46,7 +47,7 @@ struct pretty_print_context {\n \tstruct rev_info *rev;\n \tconst char *output_encoding;\n \tstruct string_list *mailmap;\n-\tint color;\n+\tenum git_colorbool color;\n \tstruct ident_split *from_ident;\n \tunsigned encode_email_headers:1;\n \tstruct pretty_print_describe_status *describe_status;\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 644f5c567c..81f2c229a9 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -95,7 +95,7 @@ struct ref_format {\n \tconst char *format;\n \tconst char *rest;\n \tint quote_style;\n-\tint use_color;\n+\tenum git_colorbool use_color;\n \n \t/* Internal state to ref-filter */\n \tint need_color_reset_at_eol;\ndiff --git a/sideband.c b/sideband.c\nindex 3ac87148b9..ea7c25211e 100644\n--- a/sideband.c\n+++ b/sideband.c\n@@ -27,9 +27,9 @@ static struct keyword_entry keywords[] = {\n };\n \n /* Returns a color setting (GIT_COLOR_NEVER, etc). */\n-static int use_sideband_colors(void)\n+static enum git_colorbool use_sideband_colors(void)\n {\n-\tstatic int use_sideband_colors_cached = GIT_COLOR_UNKNOWN;\n+\tstatic enum git_colorbool use_sideband_colors_cached = GIT_COLOR_UNKNOWN;\n \n \tconst char *key = \"color.remote\";\n \tstruct strbuf sb = STRBUF_INIT;\ndiff --git a/transport.c b/transport.c\nindex ea0be4503c..c7f06a7382 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -30,7 +30,7 @@\n #include \"color.h\"\n #include \"bundle-uri.h\"\n \n-static int transport_use_color = GIT_COLOR_UNKNOWN;\n+static enum git_colorbool transport_use_color = GIT_COLOR_UNKNOWN;\n static char transport_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n \tGIT_COLOR_RED\t\t/* REJECTED */\ndiff --git a/wt-status.h b/wt-status.h\nindex 4e377ce62b..e40a27214a 100644\n--- a/wt-status.h\n+++ b/wt-status.h\n@@ -111,7 +111,7 @@ struct wt_status {\n \tint amend;\n \tenum commit_whence whence;\n \tint nowarn;\n-\tint use_color;\n+\tenum git_colorbool use_color;\n \tint no_gettext;\n \tint display_comment_prefix;\n \tint relative_paths;\n-- \n2.51.0.526.gbfd906bacc\n\n"}]}