Skip to content

Commit f37a7e6

Browse files
committed
Merge branch 'hn/config-typo-advice' into seen
"git config foo.bar=baz" is not likely to be a request to read the value of such a variable with '=' in its name; rather it is plausible that the user meant "git config set foo.bar baz". Give advice when giving an error message. Comments? * hn/config-typo-advice: config: suggest the correct form when key contains "=" in set context
2 parents 4b48622 + 85f48f5 commit f37a7e6

2 files changed

Lines changed: 77 additions & 0 deletions

File tree

builtin/config.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#define USE_THE_REPOSITORY_VARIABLE
22
#include "builtin.h"
33
#include "abspath.h"
4+
#include "advice.h"
45
#include "config.h"
56
#include "color.h"
67
#include "date.h"
@@ -210,6 +211,22 @@ static void check_argc(int argc, int min, int max)
210211
exit(129);
211212
}
212213

214+
static void advise_setting_with_equals(const char *key, const char *value)
215+
{
216+
const char *last_dot = strrchr(key, '.');
217+
const char *eq;
218+
219+
if (!last_dot)
220+
return;
221+
eq = strchr(last_dot + 1, '=');
222+
if (!eq)
223+
return;
224+
if (!value)
225+
value = eq + 1;
226+
advise(_("did you mean \"git config set %.*s %s\"?"),
227+
(int)(eq - key), key, value);
228+
}
229+
213230
static void show_config_origin(const struct config_display_options *opts,
214231
const struct key_value_info *kvi,
215232
struct strbuf *buf)
@@ -1133,6 +1150,11 @@ static int cmd_config_set(int argc, const char **argv, const char *prefix,
11331150

11341151
argc = parse_options(argc, argv, prefix, opts, builtin_config_set_usage,
11351152
PARSE_OPT_STOP_AT_NON_OPTION);
1153+
if (argc == 1 && strchr(argv[0], '=')) {
1154+
error(_("wrong number of arguments, should be 2"));
1155+
advise_setting_with_equals(argv[0], NULL);
1156+
exit(129);
1157+
}
11361158
check_argc(argc, 2, 2);
11371159

11381160
if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern)
@@ -1160,6 +1182,8 @@ static int cmd_config_set(int argc, const char **argv, const char *prefix,
11601182
error(_("cannot overwrite multiple values with a single value\n"
11611183
" Use --value=<pattern>, --append or --all to change %s."), argv[0]);
11621184
}
1185+
if (ret == CONFIG_INVALID_KEY)
1186+
advise_setting_with_equals(argv[0], argv[1]);
11631187

11641188
location_options_release(&location_opts);
11651189
free(comment);
@@ -1371,6 +1395,7 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
13711395
};
13721396
char *value = NULL, *comment = NULL;
13731397
int ret = 0;
1398+
int actions_implicit;
13741399
struct key_value_info default_kvi = KVI_INIT;
13751400

13761401
argc = parse_options(argc, argv, prefix, opts,
@@ -1385,6 +1410,7 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
13851410
exit(129);
13861411
}
13871412

1413+
actions_implicit = (actions == 0);
13881414
if (actions == 0)
13891415
switch (argc) {
13901416
case 1: actions = ACTION_GET; break;
@@ -1485,6 +1511,8 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
14851511
if (ret == CONFIG_NOTHING_SET)
14861512
error(_("cannot overwrite multiple values with a single value\n"
14871513
" Use a regexp, --add or --replace-all to change %s."), argv[0]);
1514+
else if (ret == CONFIG_INVALID_KEY)
1515+
advise_setting_with_equals(argv[0], argv[1]);
14881516
}
14891517
else if (actions == ACTION_SET_ALL) {
14901518
check_write(&location_opts.source);
@@ -1515,6 +1543,8 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
15151543
check_argc(argc, 1, 2);
15161544
ret = get_value(&location_opts, &display_opts, argv[0], argv[1],
15171545
0, flags);
1546+
if (ret == CONFIG_INVALID_KEY && actions_implicit)
1547+
advise_setting_with_equals(argv[0], NULL);
15181548
}
15191549
else if (actions == ACTION_GET_ALL) {
15201550
check_argc(argc, 1, 2);

t/t1300-config.sh

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,53 @@ test_expect_success 'invalid key' '
469469
test_must_fail git config inval.2key blabla
470470
'
471471

472+
test_expect_success 'misplaced "=" in key: bare 1-arg form hints' '
473+
test_must_fail git config pull.rebase=false 2>err &&
474+
test_grep "invalid key: pull\\.rebase=false" err &&
475+
test_grep "did you mean .git config set pull\\.rebase false." err
476+
'
477+
478+
test_expect_success 'misplaced "=" in key: bare 2-arg form uses given value' '
479+
test_must_fail git config pull.rebase=false true 2>err &&
480+
test_grep "did you mean .git config set pull\\.rebase true." err
481+
'
482+
483+
test_expect_success 'misplaced "=" in key: set subcommand uses given value' '
484+
test_must_fail git config set pull.rebase=false true 2>err &&
485+
test_grep "did you mean .git config set pull\\.rebase true." err
486+
'
487+
488+
test_expect_success 'misplaced "=" in key: set with single arg hints' '
489+
test_must_fail git config set pull.rebase=false 2>err &&
490+
test_grep "wrong number of arguments" err &&
491+
test_grep "did you mean .git config set pull\\.rebase false." err
492+
'
493+
494+
test_expect_success 'misplaced "=" in key: explicit --get does not hint' '
495+
test_must_fail git config --get pull.rebase=false 2>err &&
496+
test_grep "invalid key: pull\\.rebase=false" err &&
497+
test_grep ! "did you mean" err
498+
'
499+
500+
test_expect_success 'misplaced "=" in key: get subcommand does not hint' '
501+
test_must_fail git config get pull.rebase=false 2>err &&
502+
test_grep ! "did you mean" err
503+
'
504+
505+
test_expect_success 'misplaced "=" in key: unset subcommand does not hint' '
506+
test_must_fail git config unset pull.rebase=false 2>err &&
507+
test_grep ! "did you mean" err
508+
'
509+
510+
test_expect_success '"=" inside subsection is valid, no hint' '
511+
test_when_finished "rm -f subsection.cfg" &&
512+
git config set -f subsection.cfg foo.bar=baz.boo qux 2>err &&
513+
test_grep ! "did you mean" err &&
514+
echo qux >expect &&
515+
git config get -f subsection.cfg foo.bar=baz.boo >actual &&
516+
test_cmp expect actual
517+
'
518+
472519
test_expect_success 'correct key' '
473520
git config 123456.a123 987
474521
'

0 commit comments

Comments
 (0)