{"thread":{"id":"12024","subject":"[PATCH] config: deprecate using \"\" as boolean value false.","startedAt":"2008-02-11T07:22:16Z","lastAt":"2008-02-11T09:22:12Z","messageCount":4,"participants":["Christian Couder","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"68331","messageId":"20080211082216.e9212310.chriscool@tuxfamily.org","threadId":"12024","inReplyTo":null,"subject":"[PATCH] config: deprecate using \"\" as boolean value false.","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2008-02-11T07:22:16Z","receivedAt":"2008-02-11T07:22:16Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Signed-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n config.c |   13 ++++++++++++-\n 1 files changed, 12 insertions(+), 1 deletions(-)\n\ndiff --git a/config.c b/config.c\nindex 526a3f4..b5f1a11 100644\n--- a/config.c\n+++ b/config.c\n@@ -300,8 +300,19 @@ int git_config_bool(const char *name, const char *value)\n {\n \tif (!value)\n \t\treturn 1;\n-\tif (!*value)\n+\tif (!*value) {\n+\t\tfprintf(stderr,\n+\t\t\t\"Warning: using an empty value for boolean config \"\n+\t\t\t\"variables is deprecated.\\n\"\n+\t\t\t\"An empty value currently means 'false' as a \"\n+\t\t\t\"boolean, but may very well means 'true' in the \"\n+\t\t\t\"future!\\n\"\n+\t\t\t\"Please consider using a 'false' value explicitely \"\n+\t\t\t\"for variable '%s', so that your config is future \"\n+\t\t\t\"proof. You can do that using:\\n\"\n+\t\t\t\"\\tgit config %s false\\n\", name, name);\n \t\treturn 0;\n+\t}\n \tif (!strcasecmp(value, \"true\") || !strcasecmp(value, \"yes\"))\n \t\treturn 1;\n \tif (!strcasecmp(value, \"false\") || !strcasecmp(value, \"no\"))\n-- \n1.5.4.20.gc135a-dirty\n"},{"id":"68339","messageId":"7vskzzaoop.fsf@gitster.siamese.dyndns.org","threadId":"12024","inReplyTo":"20080211082216.e9212310.chriscool@tuxfamily.org","subject":"Re: [PATCH] config: deprecate using \"\" as boolean value false.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-02-11T08:21:26Z","receivedAt":"2008-02-11T08:21:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Why do you call this a \"fix\", when the only effect of it is\nbreaking people's existing setups?  Wouldn't a set of proper\nfixes to the config parsing callback functions solve all the\nissues without having any downsides?\n\nI think you are wasting both of our times.  You could be doing\nthe real fix instead.  Or I could be spending time on it,\ninstead of repeating to you how mistaken this approach is.\n\nSo far I've seen and queued only two usable fixes since that\n[Janitor] request.  Maybe I should have ignored all this\ndiscussion in this thread and spent my time on doing the\nJanitorial work.  The reason I joined the thread was that I\nhoped that I could save people like _you_ from wasting _your_\ntime in the discussion, instead of making better use of it by\ndoing audits and fixes.\n\nGrrr.\n"},{"id":"68342","messageId":"7vmyq7anji.fsf@gitster.siamese.dyndns.org","threadId":"12024","inReplyTo":"7vskzzaoop.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] config: deprecate using \"\" as boolean value false.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-02-11T08:46:09Z","receivedAt":"2008-02-11T08:46:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> So far I've seen and queued only two usable fixes since that\n> [Janitor] request.  Maybe I should have ignored all this\n> discussion in this thread and spent my time on doing the\n> Janitorial work.\n\nIn the thread I mentioned erroring out when a value we expect is\nmissing instead of silently ignoring such a misconfiguration,\nand I showed an incorrect example of doing so using die().\n\nThe caller of the callback reports the line number and the\nfilename upon error.  So we should just return an error and let\nthe caller do the more detailed reporting.\n\nWith this patch, a misconfiguration:\n\n\t[apply]\n        \twhitespace\n\nwill result in:\n\n\t$ git apply\n        error: Missing value for 'apply.whitespace'\n        fatal: bad config file line 29 in .git/config\n\nwhich is much nicer.\n\n---\n\n cache.h         |    1 +\n config.c        |    9 +++++++++\n builtin-apply.c |    2 ++\n 3 files changed, 12 insertions(+), 0 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 549f4bb..6abcee4 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -589,6 +589,7 @@ extern int git_config_set_multivar(const char *, const char *, const char *, int\n extern int git_config_rename_section(const char *, const char *);\n extern const char *git_etc_gitconfig(void);\n extern int check_repository_format_version(const char *var, const char *value);\n+extern int config_error_nonbool(const char *);\n \n #define MAX_GITNAME (1000)\n extern char git_default_email[MAX_GITNAME];\ndiff --git a/config.c b/config.c\nindex 498259e..e9a9a6f 100644\n--- a/config.c\n+++ b/config.c\n@@ -1074,3 +1074,12 @@ int git_config_rename_section(const char *old_name, const char *new_name)\n \tfree(config_filename);\n \treturn ret;\n }\n+\n+/*\n+ * Call this to report error for your variable that should not\n+ * get a boolean value (i.e. \"[my] var\" means \"true\").\n+ */\n+int config_error_nonbool(const char *var)\n+{\n+\treturn error(\"Missing value for '%s'\", var);\n+}\ndiff --git a/builtin-apply.c b/builtin-apply.c\nindex 15432b6..a11b1bb 100644\n--- a/builtin-apply.c\n+++ b/builtin-apply.c\n@@ -2746,6 +2746,8 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)\n static int git_apply_config(const char *var, const char *value)\n {\n \tif (!strcmp(var, \"apply.whitespace\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n \t\tapply_default_whitespace = xstrdup(value);\n \t\treturn 0;\n \t}\n"},{"id":"68347","messageId":"7v3arzalvf.fsf_-_@gitster.siamese.dyndns.org","threadId":"12024","inReplyTo":"7vmyq7anji.fsf@gitster.siamese.dyndns.org","subject":"[PATCH] teach config parsers to diagnose missing values","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-02-11T09:22:12Z","receivedAt":"2008-02-11T09:22:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"I really hate to do this.\n\nI announced an opportunity for new people to start hacking, and\nI really wanted to stay out of their way.  It was a relatively\neasy way for people to get their hands dirty.\n\nBut then I somehow was trapped in a discussion that suggested to\nintroduce a needless regression that breaks people's existing\nrepositories, and had to argue against the insanity, because the\nsuggestion would have discouraged new people from actually\nlooking at the code and futzing with it.\n\nSomehow I ended up doing this myself, which meant that the easy\nentrance opportunity was robbed from them.  I am really unhappy\nabout this, not about the resulting code, but about the process.\n\nAnyway, here it is.  I think I've caught all of them (except the\none in builtin-gc that Miklos Vajna earlier sent in, and the one\nin archive-tar.c that I demonstrated in my original message).\n\n---\n\n builtin-apply.c       |    2 ++\n builtin-branch.c      |    9 ++++++---\n builtin-clean.c       |    1 +\n builtin-commit.c      |    2 ++\n builtin-config.c      |    2 ++\n builtin-log.c         |    2 +-\n builtin-reflog.c      |   16 +++++++++++-----\n builtin-show-branch.c |    2 ++\n builtin-tag.c         |    2 +-\n cache.h               |    1 +\n config.c              |    9 +++++++++\n connect.c             |    2 ++\n convert.c             |    4 ++--\n diff.c                |   14 ++++++++++++--\n git.c                 |    2 ++\n help.c                |    2 ++\n http.c                |   25 +++++++++++++++----------\n merge-recursive.c     |   11 ++++++-----\n remote.c              |    9 ++++++---\n setup.c               |    2 ++\n wt-status.c           |    2 ++\n 21 files changed, 89 insertions(+), 32 deletions(-)\n\ndiff --git a/builtin-apply.c b/builtin-apply.c\nindex 15432b6..a11b1bb 100644\n--- a/builtin-apply.c\n+++ b/builtin-apply.c\n@@ -2746,6 +2746,8 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)\n static int git_apply_config(const char *var, const char *value)\n {\n \tif (!strcmp(var, \"apply.whitespace\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n \t\tapply_default_whitespace = xstrdup(value);\n \t\treturn 0;\n \t}\ndiff --git a/builtin-branch.c b/builtin-branch.c\nindex 089cae5..e414c88 100644\n--- a/builtin-branch.c\n+++ b/builtin-branch.c\n@@ -70,12 +70,15 @@ static int git_branch_config(const char *var, const char *value)\n \t}\n \tif (!prefixcmp(var, \"color.branch.\")) {\n \t\tint slot = parse_branch_color_slot(var, 13);\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n \t\tcolor_parse(value, var, branch_colors[slot]);\n \t\treturn 0;\n \t}\n-\tif (!strcmp(var, \"branch.autosetupmerge\"))\n-\t\t\tbranch_track = git_config_bool(var, value);\n-\n+\tif (!strcmp(var, \"branch.autosetupmerge\")) {\n+\t\tbranch_track = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n \treturn git_default_config(var, value);\n }\n \ndiff --git a/builtin-clean.c b/builtin-clean.c\nindex eb853a3..99739a6 100644\n--- a/builtin-clean.c\n+++ b/builtin-clean.c\n@@ -20,6 +20,7 @@ static const char *const builtin_clean_usage[] = {\n \n static int git_clean_config(const char *var, const char *value)\n {\n+\t/* This is value=NULL safe */\n \tif (!strcmp(var, \"clean.requireforce\"))\n \t\tforce = !git_config_bool(var, value);\n \treturn git_default_config(var, value);\ndiff --git a/builtin-commit.c b/builtin-commit.c\nindex c787bed..06e8a34 100644\n--- a/builtin-commit.c\n+++ b/builtin-commit.c\n@@ -743,6 +743,8 @@ static void print_summary(const char *prefix, const unsigned char *sha1)\n int git_commit_config(const char *k, const char *v)\n {\n \tif (!strcmp(k, \"commit.template\")) {\n+\t\tif (!v)\n+\t\t\treturn config_error_nonbool(v);\n \t\ttemplate_file = xstrdup(v);\n \t\treturn 0;\n \t}\ndiff --git a/builtin-config.c b/builtin-config.c\nindex e4a12e3..077d8ef 100644\n--- a/builtin-config.c\n+++ b/builtin-config.c\n@@ -168,6 +168,8 @@ static char parsed_color[COLOR_MAXLEN];\n static int git_get_color_config(const char *var, const char *value)\n {\n \tif (!strcmp(var, get_color_slot)) {\n+\t\tif (!value)\n+\t\t\tconfig_error_nonbool(var);\n \t\tcolor_parse(value, var, parsed_color);\n \t\tget_color_found = 1;\n \t}\ndiff --git a/builtin-log.c b/builtin-log.c\nindex dcc9f81..9458428 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -219,7 +219,7 @@ static int git_log_config(const char *var, const char *value)\n {\n \tif (!strcmp(var, \"format.subjectprefix\")) {\n \t\tif (!value)\n-\t\t\tdie(\"format.subjectprefix without value\");\n+\t\t\tconfig_error_nonbool(var);\n \t\tfmt_patch_subject_prefix = xstrdup(value);\n \t\treturn 0;\n \t}\ndiff --git a/builtin-reflog.c b/builtin-reflog.c\nindex e6834dd..4836ec9 100644\n--- a/builtin-reflog.c\n+++ b/builtin-reflog.c\n@@ -307,13 +307,19 @@ static int collect_reflog(const char *ref, const unsigned char *sha1, int unused\n \n static int reflog_expire_config(const char *var, const char *value)\n {\n-\tif (!strcmp(var, \"gc.reflogexpire\"))\n+\tif (!strcmp(var, \"gc.reflogexpire\")) {\n+\t\tif (!value)\n+\t\t\tconfig_error_nonbool(var);\n \t\tdefault_reflog_expire = approxidate(value);\n-\telse if (!strcmp(var, \"gc.reflogexpireunreachable\"))\n+\t\treturn 0;\n+\t}\n+\tif (!strcmp(var, \"gc.reflogexpireunreachable\")) {\n+\t\tif (!value)\n+\t\t\tconfig_error_nonbool(var);\n \t\tdefault_reflog_expire_unreachable = approxidate(value);\n-\telse\n-\t\treturn git_default_config(var, value);\n-\treturn 0;\n+\t\treturn 0;\n+\t}\n+\treturn git_default_config(var, value);\n }\n \n static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)\ndiff --git a/builtin-show-branch.c b/builtin-show-branch.c\nindex 6dc835d..019abd3 100644\n--- a/builtin-show-branch.c\n+++ b/builtin-show-branch.c\n@@ -536,6 +536,8 @@ static void append_one_rev(const char *av)\n static int git_show_branch_config(const char *var, const char *value)\n {\n \tif (!strcmp(var, \"showbranch.default\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n \t\tif (default_alloc <= default_num + 1) {\n \t\t\tdefault_alloc = default_alloc * 3 / 2 + 20;\n \t\t\tdefault_arg = xrealloc(default_arg, sizeof *default_arg * default_alloc);\ndiff --git a/builtin-tag.c b/builtin-tag.c\nindex 03e7015..4a4a88c 100644\n--- a/builtin-tag.c\n+++ b/builtin-tag.c\n@@ -258,7 +258,7 @@ static int git_tag_config(const char *var, const char *value)\n {\n \tif (!strcmp(var, \"user.signingkey\")) {\n \t\tif (!value)\n-\t\t\tdie(\"user.signingkey without value\");\n+\t\t\treturn config_error_nonbool(value);\n \t\tset_signingkey(value);\n \t\treturn 0;\n \t}\ndiff --git a/cache.h b/cache.h\nindex 549f4bb..6abcee4 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -589,6 +589,7 @@ extern int git_config_set_multivar(const char *, const char *, const char *, int\n extern int git_config_rename_section(const char *, const char *);\n extern const char *git_etc_gitconfig(void);\n extern int check_repository_format_version(const char *var, const char *value);\n+extern int config_error_nonbool(const char *);\n \n #define MAX_GITNAME (1000)\n extern char git_default_email[MAX_GITNAME];\ndiff --git a/config.c b/config.c\nindex 498259e..e9a9a6f 100644\n--- a/config.c\n+++ b/config.c\n@@ -1074,3 +1074,12 @@ int git_config_rename_section(const char *old_name, const char *new_name)\n \tfree(config_filename);\n \treturn ret;\n }\n+\n+/*\n+ * Call this to report error for your variable that should not\n+ * get a boolean value (i.e. \"[my] var\" means \"true\").\n+ */\n+int config_error_nonbool(const char *var)\n+{\n+\treturn error(\"Missing value for '%s'\", var);\n+}\ndiff --git a/connect.c b/connect.c\nindex 3aefd4a..71597d4 100644\n--- a/connect.c\n+++ b/connect.c\n@@ -370,6 +370,8 @@ static int git_proxy_command_options(const char *var, const char *value)\n \n \t\tif (git_proxy_command)\n \t\t\treturn 0;\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n \t\t/* [core]\n \t\t * ;# matches www.kernel.org as well\n \t\t * gitproxy = netcatter-1 for kernel.org\ndiff --git a/convert.c b/convert.c\nindex 80f114b..552707e 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -326,14 +326,14 @@ static int read_convert_config(const char *var, const char *value)\n \n \tif (!strcmp(\"smudge\", ep)) {\n \t\tif (!value)\n-\t\t\treturn error(\"%s: lacks value\", var);\n+\t\t\treturn config_error_nonbool(var);\n \t\tdrv->smudge = strdup(value);\n \t\treturn 0;\n \t}\n \n \tif (!strcmp(\"clean\", ep)) {\n \t\tif (!value)\n-\t\t\treturn error(\"%s: lacks value\", var);\n+\t\t\treturn config_error_nonbool(var);\n \t\tdrv->clean = strdup(value);\n \t\treturn 0;\n \t}\ndiff --git a/diff.c b/diff.c\nindex 5b8afdc..4d2e23a 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -158,6 +158,8 @@ int git_diff_ui_config(const char *var, const char *value)\n \t\treturn 0;\n \t}\n \tif (!strcmp(var, \"diff.external\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n \t\texternal_diff_cmd_cfg = xstrdup(value);\n \t\treturn 0;\n \t}\n@@ -165,8 +167,11 @@ int git_diff_ui_config(const char *var, const char *value)\n \t\tconst char *ep = strrchr(var, '.');\n \n \t\tif (ep != var + 4) {\n-\t\t\tif (!strcmp(ep, \".command\"))\n+\t\t\tif (!strcmp(ep, \".command\")) {\n+\t\t\t\tif (!value)\n+\t\t\t\t\treturn config_error_nonbool(var);\n \t\t\t\treturn parse_lldiff_command(var, ep, value);\n+\t\t\t}\n \t\t}\n \t}\n \n@@ -177,6 +182,8 @@ int git_diff_basic_config(const char *var, const char *value)\n {\n \tif (!prefixcmp(var, \"diff.color.\") || !prefixcmp(var, \"color.diff.\")) {\n \t\tint slot = parse_diff_color_slot(var, 11);\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n \t\tcolor_parse(value, var, diff_colors[slot]);\n \t\treturn 0;\n \t}\n@@ -184,8 +191,11 @@ int git_diff_basic_config(const char *var, const char *value)\n \tif (!prefixcmp(var, \"diff.\")) {\n \t\tconst char *ep = strrchr(var, '.');\n \t\tif (ep != var + 4) {\n-\t\t\tif (!strcmp(ep, \".funcname\"))\n+\t\t\tif (!strcmp(ep, \".funcname\")) {\n+\t\t\t\tif (!value)\n+\t\t\t\t\treturn config_error_nonbool(var);\n \t\t\t\treturn parse_funcname_pattern(var, ep, value);\n+\t\t\t}\n \t\t}\n \t}\n \ndiff --git a/git.c b/git.c\nindex 15fec89..0cb8688 100644\n--- a/git.c\n+++ b/git.c\n@@ -93,6 +93,8 @@ static char *alias_string;\n static int git_alias_config(const char *var, const char *value)\n {\n \tif (!prefixcmp(var, \"alias.\") && !strcmp(var + 6, alias_command)) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n \t\talias_string = xstrdup(value);\n \t}\n \treturn 0;\ndiff --git a/help.c b/help.c\nindex 1302a61..95e7640 100644\n--- a/help.c\n+++ b/help.c\n@@ -40,6 +40,8 @@ static void parse_help_format(const char *format)\n static int git_help_config(const char *var, const char *value)\n {\n \tif (!strcmp(var, \"help.format\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n \t\thelp_default_format = xstrdup(value);\n \t\treturn 0;\n \t}\ndiff --git a/http.c b/http.c\nindex d2c11ae..5925d07 100644\n--- a/http.c\n+++ b/http.c\n@@ -101,16 +101,18 @@ static int http_options(const char *var, const char *value)\n \n \tif (!strcmp(\"http.sslcert\", var)) {\n \t\tif (ssl_cert == NULL) {\n-\t\t\tssl_cert = xmalloc(strlen(value)+1);\n-\t\t\tstrcpy(ssl_cert, value);\n+\t\t\tif (!value)\n+\t\t\t\treturn config_error_nonbool(var);\n+\t\t\tssl_cert = xstrdup(value);\n \t\t}\n \t\treturn 0;\n \t}\n #if LIBCURL_VERSION_NUM >= 0x070902\n \tif (!strcmp(\"http.sslkey\", var)) {\n \t\tif (ssl_key == NULL) {\n-\t\t\tssl_key = xmalloc(strlen(value)+1);\n-\t\t\tstrcpy(ssl_key, value);\n+\t\t\tif (!value)\n+\t\t\t\treturn config_error_nonbool(var);\n+\t\t\tssl_key = xstrdup(value);\n \t\t}\n \t\treturn 0;\n \t}\n@@ -118,16 +120,18 @@ static int http_options(const char *var, const char *value)\n #if LIBCURL_VERSION_NUM >= 0x070908\n \tif (!strcmp(\"http.sslcapath\", var)) {\n \t\tif (ssl_capath == NULL) {\n-\t\t\tssl_capath = xmalloc(strlen(value)+1);\n-\t\t\tstrcpy(ssl_capath, value);\n+\t\t\tif (!value)\n+\t\t\t\treturn config_error_nonbool(var);\n+\t\t\tssl_capath = xstrdup(value);\n \t\t}\n \t\treturn 0;\n \t}\n #endif\n \tif (!strcmp(\"http.sslcainfo\", var)) {\n \t\tif (ssl_cainfo == NULL) {\n-\t\t\tssl_cainfo = xmalloc(strlen(value)+1);\n-\t\t\tstrcpy(ssl_cainfo, value);\n+\t\t\tif (!value)\n+\t\t\t\treturn config_error_nonbool(var);\n+\t\t\tssl_cainfo = xstrdup(value);\n \t\t}\n \t\treturn 0;\n \t}\n@@ -157,8 +161,9 @@ static int http_options(const char *var, const char *value)\n \t}\n \tif (!strcmp(\"http.proxy\", var)) {\n \t\tif (curl_http_proxy == NULL) {\n-\t\t\tcurl_http_proxy = xmalloc(strlen(value)+1);\n-\t\t\tstrcpy(curl_http_proxy, value);\n+\t\t\tif (!value)\n+\t\t\t\treturn config_error_nonbool(var);\n+\t\t\tcurl_http_proxy = xstrdup(value);\n \t\t}\n \t\treturn 0;\n \t}\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex c292a77..34e3167 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -844,8 +844,9 @@ static int read_merge_config(const char *var, const char *value)\n \tint namelen;\n \n \tif (!strcmp(var, \"merge.default\")) {\n-\t\tif (value)\n-\t\t\tdefault_ll_merge = strdup(value);\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\tdefault_ll_merge = strdup(value);\n \t\treturn 0;\n \t}\n \n@@ -878,14 +879,14 @@ static int read_merge_config(const char *var, const char *value)\n \n \tif (!strcmp(\"name\", ep)) {\n \t\tif (!value)\n-\t\t\treturn error(\"%s: lacks value\", var);\n+\t\t\treturn config_error_nonbool(var);\n \t\tfn->description = strdup(value);\n \t\treturn 0;\n \t}\n \n \tif (!strcmp(\"driver\", ep)) {\n \t\tif (!value)\n-\t\t\treturn error(\"%s: lacks value\", var);\n+\t\t\treturn config_error_nonbool(var);\n \t\t/*\n \t\t * merge.<name>.driver specifies the command line:\n \t\t *\n@@ -908,7 +909,7 @@ static int read_merge_config(const char *var, const char *value)\n \n \tif (!strcmp(\"recursive\", ep)) {\n \t\tif (!value)\n-\t\t\treturn error(\"%s: lacks value\", var);\n+\t\t\treturn config_error_nonbool(var);\n \t\tfn->recursive = strdup(value);\n \t\treturn 0;\n \t}\ndiff --git a/remote.c b/remote.c\nindex 0e00680..20abbc0 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -222,15 +222,18 @@ static int handle_config(const char *key, const char *value)\n \t\tsubkey = strrchr(name, '.');\n \t\tif (!subkey)\n \t\t\treturn 0;\n-\t\tif (!value)\n-\t\t\treturn 0;\n \t\tbranch = make_branch(name, subkey - name);\n \t\tif (!strcmp(subkey, \".remote\")) {\n+\t\t\tif (!value)\n+\t\t\t\treturn config_error_nonbool(key);\n \t\t\tbranch->remote_name = xstrdup(value);\n \t\t\tif (branch == current_branch)\n \t\t\t\tdefault_remote_name = branch->remote_name;\n-\t\t} else if (!strcmp(subkey, \".merge\"))\n+\t\t} else if (!strcmp(subkey, \".merge\")) {\n+\t\t\tif (!value)\n+\t\t\t\treturn config_error_nonbool(key);\n \t\t\tadd_merge(branch, xstrdup(value));\n+\t\t}\n \t\treturn 0;\n \t}\n \tif (prefixcmp(key,  \"remote.\"))\ndiff --git a/setup.c b/setup.c\nindex adede16..4509598 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -372,6 +372,8 @@ int check_repository_format_version(const char *var, const char *value)\n \t\tif (is_bare_repository_cfg == 1)\n \t\t\tinside_work_tree = -1;\n \t} else if (strcmp(var, \"core.worktree\") == 0) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n \t\tif (git_work_tree_cfg)\n \t\t\tfree(git_work_tree_cfg);\n \t\tgit_work_tree_cfg = xstrdup(value);\ndiff --git a/wt-status.c b/wt-status.c\nindex c0c2472..bfd1b0f 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -402,6 +402,8 @@ int git_status_config(const char *k, const char *v)\n \t}\n \tif (!prefixcmp(k, \"status.color.\") || !prefixcmp(k, \"color.status.\")) {\n \t\tint slot = parse_status_slot(k, 13);\n+\t\tif (!v)\n+\t\t\treturn config_error_nonbool(k);\n \t\tcolor_parse(v, k, wt_status_colors[slot]);\n \t\treturn 0;\n \t}\n"}]}