rev-parse: fix "--" detection when it is an option value

`cmd_rev_parse()` walks its arguments twice. The second loop actually
parses the options, and it knows that `--default`, `--prefix` and
`--resolve-git-dir` take their value as a separate argument, so it skips
that value.

The first loop, which only looks for the "--" separating revisions from
paths, doesn't know about these options. So when such an option is given
"--" as its value, that "--" is mistaken for the separator and
`has_dashdash` is wrongly set.

This matters because `has_dashdash` makes the second loop die with a
"bad revision" error on an argument that is neither a revision nor an
existing file, instead of reporting that the argument is ambiguous and
telling how to disambiguate it. So:

  $ git rev-parse --default -- notarev
  fatal: bad revision 'notarev'

while the very same command line with any other default value gives the
usual, much more helpful, "ambiguous argument" error.

Let's fix this the same way as in a previous commit, by using
early_scan_options() and telling it about the options taking their value
as a separate argument.

Signed-off-by: Christian Couder <christian.couder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
seen
Christian Couder 2026-09-02 18:10:44 +02:00 committed by Junio C Hamano
parent 3c79502506
commit 28c803e36e
2 changed files with 25 additions and 6 deletions

View File

@ -695,6 +695,17 @@ static void print_path(const char *path, const char *prefix,
strbuf_release(&sb);
}

/*
* The options taking their value as a separate argument, which the scan
* looking for "--" below has to skip along with their value.
*/
static const struct early_scan_option rev_parse_early_options[] = {
EARLY_SCAN_SKIP_VALUE("default"),
EARLY_SCAN_SKIP_VALUE("prefix"),
EARLY_SCAN_SKIP_VALUE("resolve-git-dir"),
EARLY_SCAN_END()
};

int cmd_rev_parse(int argc,
const char **argv,
const char *prefix,
@ -724,12 +735,15 @@ int cmd_rev_parse(int argc,
if (argc > 1 && !strcmp("-h", argv[1]))
usage(builtin_rev_parse_usage);

for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--")) {
has_dashdash = 1;
break;
}
}
/*
* The scan below has to know about the options taking their value
* as a separate argument, or such a value that happens to be "--"
* would be mistaken for the "--" separating revisions from paths.
*/
i = early_scan_options(argc - 1, argv + 1, rev_parse_early_options,
EARLY_SCAN_STOP_AT_DASHDASH, NULL, NULL);
if (i < argc - 1)
has_dashdash = 1;

/* No options; just report on whether we're in a git repo or not. */
if (argc == 1) {

View File

@ -383,4 +383,9 @@ test_expect_success ':/ and HEAD^{/} favor more recent matching commits' '
)
'

test_expect_success 'rev-parse with "--" as an option value' '
test_must_fail git rev-parse --default -- notarev 2>err &&
test_grep "ambiguous argument .notarev." err
'

test_done