diff --git a/parse-options.c b/parse-options.c index 4ce2b7ca16..63a99dea6e 100644 --- a/parse-options.c +++ b/parse-options.c @@ -357,6 +357,7 @@ static enum parse_opt_result parse_long_opt( const char *arg_end = strchrnul(arg, '='); const struct option *abbrev_option = NULL, *ambiguous_option = NULL; enum opt_parsed abbrev_flags = OPT_LONG, ambiguous_flags = OPT_LONG; + int allow_abbrev = !(p->flags & PARSE_OPT_KEEP_UNKNOWN_OPT); for (; options->type != OPTION_END; options++) { const char *rest, *long_name = options->long_name; @@ -367,12 +368,16 @@ static enum parse_opt_result parse_long_opt( if (!long_name) continue; -again: + if (!starts_with(arg, "no-") && + !(options->flags & PARSE_OPT_NONEG) && + skip_prefix(long_name, "no-", &long_name)) + opt_flags |= OPT_UNSET; + if (!skip_prefix(arg, long_name, &rest)) rest = NULL; if (!rest) { /* abbreviated? */ - if (!(p->flags & PARSE_OPT_KEEP_UNKNOWN_OPT) && + if (allow_abbrev && !strncmp(long_name, arg, arg_end - arg)) { is_abbreviated: if (abbrev_option && @@ -396,22 +401,18 @@ is_abbreviated: if (options->flags & PARSE_OPT_NONEG) continue; /* negated and abbreviated very much? */ - if (starts_with("no-", arg)) { + if (allow_abbrev && starts_with("no-", arg)) { flags |= OPT_UNSET; goto is_abbreviated; } /* negated? */ - if (!starts_with(arg, "no-")) { - if (skip_prefix(long_name, "no-", &long_name)) { - opt_flags |= OPT_UNSET; - goto again; - } + if (!starts_with(arg, "no-")) continue; - } flags |= OPT_UNSET; if (!skip_prefix(arg + 3, long_name, &rest)) { /* abbreviated and negated? */ - if (starts_with(long_name, arg + 3)) + if (allow_abbrev && + starts_with(long_name, arg + 3)) goto is_abbreviated; else continue; diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 76b8619e2e..1a7e2b0bcb 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -663,4 +663,10 @@ test_expect_success 'diff --default-prefix overrides diff.mnemonicprefix' ' check_prefix actual a/file0 b/file0 ' +test_expect_success 'diff --no-renames cannot be abbreviated' ' + test_expect_code 129 git diff --no-rename >actual 2>error && + test_must_be_empty actual && + grep "invalid option: --no-rename" error +' + test_done