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>

René Scharfe committed Mar 3, 2024 at 13:19 UTC 289cb15541874e5c1599fee2e145a7af39085069
2 files changed +19 -2
parse-options.c
+3 -2
@@ -391,7 +391,7 @@ is_abbreviated:
391 ambiguous_option = abbrev_option;
392 ambiguous_flags = abbrev_flags;
393 }
394 - if (!(flags & OPT_UNSET) && *arg_end)
394 + if (*arg_end)
395 p->opt = arg_end + 1;
396 abbrev_option = options;
397 abbrev_flags = flags ^ opt_flags;
@@ -412,7 +412,8 @@ is_abbreviated:
412 if (!skip_prefix(arg + 3, long_name, &rest)) {
413 /* abbreviated and negated? */
414 if (allow_abbrev &&
415 - starts_with(long_name, arg + 3))
415 + !strncmp(long_name, arg + 3,
416 + arg_end - arg - 3))
417 goto is_abbreviated;
418 else
419 continue;
t/t0040-parse-options.sh
+16
@@ -210,6 +210,22 @@ test_expect_success 'superfluous value provided: boolean' '
210 test_cmp expect actual
211 '
212
213 +test_expect_success 'superfluous value provided: boolean, abbreviated' '
214 + cat >expect <<-\EOF &&
215 + error: option `yes'\'' takes no value
216 + EOF
217 + test_expect_code 129 env GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \
218 + test-tool parse-options --ye=hi 2>actual &&
219 + test_cmp expect actual &&
220 +
221 + cat >expect <<-\EOF &&
222 + error: option `no-yes'\'' takes no value
223 + EOF
224 + test_expect_code 129 env GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \
225 + test-tool parse-options --no-ye=hi 2>actual &&
226 + test_cmp expect actual
227 +'
228 +
229 test_expect_success 'superfluous value provided: cmdmode' '
230 cat >expect <<-\EOF &&
231 error: option `mode1'\'' takes no value