]> git.ipfire.org Git - thirdparty/git.git/commitdiff
parse-options: detect ambiguous self-negation
authorRené Scharfe <l.s.r@web.de>
Sun, 3 Mar 2024 12:19:41 +0000 (13:19 +0100)
committerJunio C Hamano <gitster@pobox.com>
Sun, 3 Mar 2024 17:49:21 +0000 (09:49 -0800)
Git currently does not detect the ambiguity of an option that starts
with "no" like --notes and its negated form if given just --n or --no.
All Git commands with such options have other negatable options, and
we detect the ambiguity with them, so that's currently only a potential
problem for scripts that use git rev-parse --parseopt.

Let's fix it nevertheless, as there's no need for that confusion.  To
detect the ambiguity we have to loosen the check in register_abbrev(),
as an option is considered an alias of itself.  Add non-matching
negation flags as a criterion to recognize an option being ambiguous
with its negated form.

And we need to keep going after finding a non-negated option as an
abbreviated candidate and perform the negation checks in the same
loop.

Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
parse-options.c
t/t1502-rev-parse-parseopt.sh

index 398ebaef1492f0fa4b645792633ca10fc6356325..008c0f32cfb3a72fbfb2218fe9ad97d0530b11b6 100644 (file)
@@ -363,7 +363,7 @@ static void register_abbrev(struct parse_opt_ctx_t *p,
        if (p->flags & PARSE_OPT_KEEP_UNKNOWN_OPT)
                return;
        if (abbrev->option &&
-           !is_alias(p, abbrev->option, option)) {
+           !(abbrev->flags == flags && is_alias(p, abbrev->option, option))) {
                /*
                 * If this is abbreviated, it is
                 * ambiguous. So when there is no
@@ -406,7 +406,6 @@ static enum parse_opt_result parse_long_opt(
                        if (!strncmp(long_name, arg, arg_end - arg)) {
                                register_abbrev(p, options, flags ^ opt_flags,
                                                &abbrev, &ambiguous);
-                               continue;
                        }
                        /* negation allowed? */
                        if (options->flags & PARSE_OPT_NONEG)
index f0737593c3fda734060fa9509d1b9561086a7376..b754b9fd74bd17e7a969026a93cd6e70c8771cb8 100755 (executable)
@@ -322,4 +322,15 @@ check_invalid_long_option optionspec-neg --no-positive-only
 check_invalid_long_option optionspec-neg --negative
 check_invalid_long_option optionspec-neg --no-no-negative
 
+test_expect_success 'ambiguous: --no matches both --noble and --no-noble' '
+       cat >spec <<-\EOF &&
+       some-command [options]
+       --
+       noble The feudal switch.
+       EOF
+       test_expect_code 129 env GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \
+       git rev-parse --parseopt -- <spec 2>err --no &&
+       grep "error: ambiguous option: no (could be --noble or --no-noble)" err
+'
+
 test_done