parse-options: recognize abbreviated negated option with arg

Giving an argument to an option that doesn't take one causes Git to
report that error specifically:

   $ git rm --dry-run=bogus
   error: option `dry-run' takes no value

The same is true when the option is negated or abbreviated:

   $ git rm --no-dry-run=bogus
   error: option `no-dry-run' takes no value

   $ git rm --dry=bogus
   error: option `dry-run' takes no value

Not so when doing both, though:

   $ git rm --no-dry=bogus
   error: unknown option `no-dry=bogus'
   usage: git rm [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch]

(Rest of the usage message omitted.)

Improve consistency and usefulness of the error message by recognizing
abbreviated negated options even if they have a (most likely bogus)
argument.  With this patch we get:

   $ git rm --no-dry=bogus
   error: option `no-dry-run' takes no value

Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
René Scharfe 2024-03-03 13:19:38 +01:00 committed by Junio C Hamano
parent 3c2a3fdc38
commit 289cb15541
2 changed files with 19 additions and 2 deletions

View File

@ -391,7 +391,7 @@ static enum parse_opt_result parse_long_opt(
ambiguous_option = abbrev_option;
ambiguous_flags = abbrev_flags;
}
if (!(flags & OPT_UNSET) && *arg_end)
if (*arg_end)
p->opt = arg_end + 1;
abbrev_option = options;
abbrev_flags = flags ^ opt_flags;
@ -412,7 +412,8 @@ static enum parse_opt_result parse_long_opt(
if (!skip_prefix(arg + 3, long_name, &rest)) {
/* abbreviated and negated? */
if (allow_abbrev &&
starts_with(long_name, arg + 3))
!strncmp(long_name, arg + 3,
arg_end - arg - 3))
goto is_abbreviated;
else
continue;

View File

@ -210,6 +210,22 @@ test_expect_success 'superfluous value provided: boolean' '
test_cmp expect actual
'
test_expect_success 'superfluous value provided: boolean, abbreviated' '
cat >expect <<-\EOF &&
error: option `yes'\'' takes no value
EOF
test_expect_code 129 env GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \
test-tool parse-options --ye=hi 2>actual &&
test_cmp expect actual &&
cat >expect <<-\EOF &&
error: option `no-yes'\'' takes no value
EOF
test_expect_code 129 env GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \
test-tool parse-options --no-ye=hi 2>actual &&
test_cmp expect actual
'
test_expect_success 'superfluous value provided: cmdmode' '
cat >expect <<-\EOF &&
error: option `mode1'\'' takes no value