git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v2] parse-options: don't emit "ambiguous option" for aliases

From
Junio C Hamano <gitster@pobox.com>
Date
Apr 19, 2019, 04:39 UTC
Message-ID
<xmqq1s1yfw24.fsf@gitster-ct.c.googlers.com>
In-Reply-To
<20190418092940.GA13484@ash>
Duy Nguyen <pclouds@gmail.com> writes:
> So an alternative is simply outsource the ambiguity decision back to
> git-clone. If the same situation appears again elsewhere, we'll need
> to sit back and fix it for real. But this way we don't potentially
> introduce any new traps.
Sounds like a sensibly safe approach.
Show 9 quoted lines
> +/*
> + * Avoid ambiguation error between --recursive and --recurse-submodule
> + * because they are the same. --recurs can be expanded to any of them
> + * and it still works.
> + */
> +static int is_abbrev_ambiguous(const struct option *prev,
> +			       const struct option *next)
> +{
> +	const struct option *opts[] = { prev, next };

By looking at its caller, I think the caller keeps track of the candidate it saw so far, and ask this function to see if the one it is looking at right now (i.e. "this one") should be flagged as conflicting with the other one (or "the other one"). So it probably makes more sense to call them <it, the_other> or <it, prev> [*1*].

	Side note: *1* I would have used "this" instead of "it", but
	I vaguely recall there are those who want to use C++ aware
	static checkers and avoiding the identifier "this" is easy
	enough so ...
Show 13 quoted lines
> +	int i, found = 0;
> +
> +	for (i = 0; i < ARRAY_SIZE(opts); i++) {
> +		if (!opts[i]->long_name)
> +			continue;
> +		if (!strcmp(opts[i]->long_name, "recursive"))
> +			found |= 1 << 0;
> +		if (!strcmp(opts[i]->long_name, "recurse-submodules"))
> +			found |= 1 << 1;
> +	}
> +
> +	return found != 3;
> +}

For any two options that share the prefix, unless they are "recursive" and "recurse-submodules" pair, we say "that's ambiguous". But when they are these two specifically singled out, we say it is OK. Makes sense.

The above may be sufficient for this purpose, but I would have expected that these groups of aliases would be the ones in the table, not the <it, the_other> pair. IOW, with helpers like these:

	static const char *recurse_submodules[] = {
		"recurse-submodules", "recursive", NULL,
	};
	static struct {
		const char **aliases;
	} disamb[] = {
		recurse_submodules,
	};
		
	static int has_string(const char *it, const char **array)
	{
		while (*array)
			if (!strcmp(it, *(array++)))
				return 1;
		return 0;
	}
the body would look something like:
	int j;
	for (j = 0; j < ARRAY_SIZE(disamb); j++) {
		/* it and other are from the same family? */
		if (it->long_name &&
		    has_string(it->long_name, disamb[j].aliases) &&
		    other->long_name &&
		    has_string(other->long_name, disamb[j].aliases))
			return 0;
	}
	return 1;
Perhaps?

I suspect that renaming the function (and the field in the context struct) to .is_alias() and reverse the polarity of its return value may make the flow of the logic at the caller side easier to follow?

Show 11 quoted lines
> diff --git a/parse-options.c b/parse-options.c
> index cec74522e5..c0354e5a92 100644
> --- a/parse-options.c
> +++ b/parse-options.c
> @@ -294,7 +294,8 @@ static enum parse_opt_result parse_long_opt(
>  			if (!(p->flags & PARSE_OPT_KEEP_UNKNOWN) &&
>  			    !strncmp(long_name, arg, arg_end - arg)) {
>  is_abbreviated:
> -				if (abbrev_option) {
> +				if (abbrev_option &&
> +				    p->is_abbrev_ambiguous(abbrev_option, options)) {
The above suggestion would make the guard here to
			if (abbrev_option &&
			    !p->is_alias(abbrev_option, options)) {

That is, at this point, we know that the user may have used the given string to name the "abbrev_option" we earlier saw (and made sure it prefix matches the string), and now we are looking at another one, options[0], that also prefix matches the string. We usually flag this case as a problematic ambiguity inside the body of this if statement, but if one is an alias to the other, we do not do so.

>  					/*
>  					 * If this is abbreviated, it is
>  					 * ambiguous. So when there is no
Previous: Duy NguyenNext: Nguyễn Thái Ngọc Duy
Message 31 of 52 in “Do not use abbreviated options in tests”
  1. 0/8 Do not use abbreviated options in testsJohannes Schindelin via GitGitGadget, Mar 25, 2019
  2. 1/8 tests (rebase): spell out the `--keep-empty` optionJohannes Schindelin via GitGitGadget, Mar 25, 2019
  3. 3/8 t7810: do not abbreviate `--no-exclude-standard` nor `--invert-match`Johannes Schindelin via GitGitGadget, Mar 25, 2019
  4. 5/8 tests (push): do not abbreviate the `--follow-tags` optionJohannes Schindelin via GitGitGadget, Mar 25, 2019
  5. 4/8 t5531: avoid using an abbreviated optionJohannes Schindelin via GitGitGadget, Mar 25, 2019
  6. 2/8 tests (rebase): spell out the `--force-rebase` optionJohannes Schindelin via GitGitGadget, Mar 25, 2019
  7. 8/8 tests: disallow the use of abbreviated options (by default)Johannes Schindelin via GitGitGadget, Mar 25, 2019
  8. Denton LiuMar 25, 2019
  9. Ævar Arnfjörð BjarmasonMar 25, 2019
  10. Johannes SchindelinApr 12, 2019
  11. Johannes SchindelinApr 12, 2019
  12. Ævar Arnfjörð BjarmasonMar 25, 2019
  13. Johannes SchindelinApr 12, 2019
  14. 6/8 tests (status): spell out the `--find-renames` option in fullJohannes Schindelin via GitGitGadget, Mar 25, 2019
  15. 7/8 tests (pack-objects): use the full, unabbreviated `--revs` optionJohannes Schindelin via GitGitGadget, Mar 25, 2019
  16. 0/2 allow for configuring option abbreviation + fixÆvar Arnfjörð Bjarmason, Mar 25, 2019
  17. 1/2 parse-options: allow for configuring option abbreviationÆvar Arnfjörð Bjarmason, Mar 25, 2019
  18. Eric SunshineMar 25, 2019
  19. Ævar Arnfjörð BjarmasonMar 25, 2019
  20. Duy NguyenMar 26, 2019
  21. Ævar Arnfjörð BjarmasonMar 26, 2019
  22. Duy NguyenMar 26, 2019
  23. Ævar Arnfjörð BjarmasonMar 26, 2019
  24. Junio C HamanoApr 1, 2019
  25. Johannes SchindelinApr 12, 2019
  26. 2/2 parse-options: don't emit "ambiguous option" for aliasesÆvar Arnfjörð Bjarmason, Mar 25, 2019
  27. parse-options: don't emit "ambiguous option" for aliasesÆvar Arnfjörð Bjarmason, Apr 17, 2019
  28. Duy NguyenApr 17, 2019
  29. Junio C HamanoApr 18, 2019
  30. Duy NguyenApr 18, 2019
  31. Junio C HamanoApr 19, 2019
  32. parse-options: don't emit "ambiguous option" for aliasesNguyễn Thái Ngọc Duy, Apr 22, 2019
  33. Duy NguyenApr 22, 2019
  34. parse-options: don't emit "ambiguous option" for aliasesNguyễn Thái Ngọc Duy, Apr 29, 2019
  35. Junio C HamanoMay 7, 2019
  36. Duy NguyenMay 7, 2019
  37. Junio C HamanoApr 2, 2019
  38. 0/8 Do not use abbreviated options in testsJohannes Schindelin via GitGitGadget, Apr 12, 2019
  39. 2/8 tests (rebase): spell out the `--force-rebase` optionJohannes Schindelin via GitGitGadget, Apr 12, 2019
  40. 4/8 t5531: avoid using an abbreviated optionJohannes Schindelin via GitGitGadget, Apr 12, 2019
  41. 6/8 tests (status): spell out the `--find-renames` option in fullJohannes Schindelin via GitGitGadget, Apr 12, 2019
  42. 5/8 tests (push): do not abbreviate the `--follow-tags` optionJohannes Schindelin via GitGitGadget, Apr 12, 2019
  43. 1/8 tests (rebase): spell out the `--keep-empty` optionJohannes Schindelin via GitGitGadget, Apr 12, 2019
  44. 3/8 t7810: do not abbreviate `--no-exclude-standard` nor `--invert-match`Johannes Schindelin via GitGitGadget, Apr 12, 2019
  45. 8/8 tests: disallow the use of abbreviated options (by default)Johannes Schindelin via GitGitGadget, Apr 12, 2019
  46. Junio C HamanoApr 14, 2019
  47. Junio C HamanoApr 15, 2019
  48. Johannes SchindelinApr 15, 2019
  49. Junio C HamanoApr 15, 2019
  50. Johannes SchindelinApr 17, 2019
  51. Johannes SchindelinApr 15, 2019
  52. 7/8 tests (pack-objects): use the full, unabbreviated `--revs` optionJohannes Schindelin via GitGitGadget, Apr 12, 2019

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.