Merge branch 'cc/fast-import-usage' into seen

The usage string of 'git fast-import' has been updated to use the
parse_options() API for displaying help, and its SYNOPSIS in the
documentation has been standardized to match.

* cc/fast-import-usage:
  fast-import: remove useless from_stream argument
  fast-import: use parse_options() for command line options
  fast-import: use callbacks to parse some options
  fast-import: use struct option for usage string
  fast-import: move command state globals into 'struct fast_import_state'
  fast-import: introduce 'struct fast_import_state'
  fast-import: factor out option_*() functions
  fast-import: use int for some bool flags
  fast-import: localize 'i' into the 'for' loops using it
  api-parse-options.adoc: document hidden and OPT_*_F option macros
  api-parse-options.adoc: document per-option flags
  parse-options: introduce OPT_HIDDEN_GROUP
This commit is contained in:
Junio C Hamano
2026-08-07 14:48:26 -07:00
9 changed files with 519 additions and 189 deletions

View File

@@ -9,7 +9,7 @@ git-fast-import - Backend for fast Git data importers
SYNOPSIS
--------
[verse]
frontend | 'git fast-import' [<options>]
'git fast-import' [<options>]
DESCRIPTION
-----------

View File

@@ -150,8 +150,76 @@ Data Structure
The main data structure is an array of the `option` struct,
say `static struct option builtin_add_options[]`.
Option flags
~~~~~~~~~~~~
Each option can carry flags in the `flags` field of its `option`
struct. These are per-option flags and are distinct from the
`parse_options()` flags described above; they are usually set through
the `OPT_*_F()` macro variants (see below) rather than by hand. They
are the bitwise-or of:
`PARSE_OPT_OPTARG`::
The option's argument is optional, i.e. both `--option` and
`--option=<value>` are accepted.
`PARSE_OPT_NOARG`::
The option takes no argument at all. Using `--option=<value>`
is rejected.
`PARSE_OPT_NONEG`::
Disable the automatically generated negated `--no-option`
form.
`PARSE_OPT_HIDDEN`::
Hide the option: it is omitted from the usage shown by
`git <cmd> -h`, but is still shown by `git <cmd> --help-all`.
The option is parsed as usual either way. This is meant for
deprecated, advanced or otherwise uncommon options.
`PARSE_OPT_LASTARG_DEFAULT`::
Use the default value (`defval`) when the option is used
without an argument, even for an option that normally requires
one. Only the last argument on the command line takes effect.
`PARSE_OPT_NODASH`::
The option is a single character without a leading dash, such
as the `+` used by some commands.
`PARSE_OPT_LITERAL_ARGHELP`::
Use the argument help string (`argh`) verbatim in the usage
output instead of surrounding it with `<>` or `[]`. Useful when
`argh` already contains a hand-formatted description.
`PARSE_OPT_FROM_ALIAS`::
Internal flag, set on options that were expanded from a
configured alias. It should not be set by callers.
`PARSE_OPT_NOCOMPLETE`::
Do not offer this option for completion.
`PARSE_OPT_COMP_ARG`::
The option's argument, rather than the option itself, is what
should be completed.
`PARSE_OPT_CMDMODE`::
The option is one of several mutually exclusive "command mode"
options that share the same variable. Using more than one of
them at once is rejected.
Macros
~~~~~~
There are some macros to easily define options:
Many of the macros below have an `_F` variant (for example `OPT_BOOL_F`,
`OPT_STRING_F`, `OPT_INTEGER_F`, `OPT_SET_INT_F`, `OPT_BIT_F` and
`OPT_CALLBACK_F`) that takes an additional trailing `flags` argument.
That argument is the bitwise-or of the per-option flags described in the
"Option flags" section above; the non-`_F` macros are simply defined
with `flags` set to `0`.
`OPT__ABBREV(&int_var)`::
Add `--abbrev[=<n>]`.
@@ -175,10 +243,21 @@ There are some macros to easily define options:
describes the group or an empty string.
Start the description with an upper-case letter.
`OPT_HIDDEN_GROUP(description)`::
Like `OPT_GROUP()`, but the group header carries
`PARSE_OPT_HIDDEN`, so it is only shown by `--help-all` and not
by `-h`. Use it to label a group that contains only hidden
options, which would otherwise show an empty header under `-h`.
`OPT_BOOL(short, long, &int_var, description)`::
Introduce a boolean option. `int_var` is set to one with
`--option` and set to zero with `--no-option`.
`OPT_HIDDEN_BOOL(short, long, &int_var, description)`::
Like `OPT_BOOL()`, but the option carries `PARSE_OPT_HIDDEN`,
so it is hidden from `-h` while still being shown by
`--help-all`.
`OPT_COUNTUP(short, long, &int_var, description)`::
Introduce a count-up option.
Each use of `--option` increments `int_var`, starting from zero

File diff suppressed because it is too large Load Diff

View File

@@ -1414,6 +1414,8 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
if (opts->type == OPTION_SUBCOMMAND)
continue;
if (!full && (opts->flags & PARSE_OPT_HIDDEN))
continue;
if (opts->type == OPTION_GROUP) {
fputc('\n', outfile);
need_newline = 0;
@@ -1421,8 +1423,6 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
fprintf(outfile, "%s\n", _(opts->help));
continue;
}
if (!full && (opts->flags & PARSE_OPT_HIDDEN))
continue;
if (need_newline) {
fputc('\n', outfile);

View File

@@ -237,6 +237,11 @@ struct option {
.type = OPTION_GROUP, \
.help = (h), \
}
#define OPT_HIDDEN_GROUP(h) { \
.type = OPTION_GROUP, \
.help = (h), \
.flags = PARSE_OPT_HIDDEN, \
}
#define OPT_BIT(s, l, v, h, b) OPT_BIT_F(s, l, v, h, b, 0)
#define OPT_BITOP(s, l, v, h, set, clear) { \
.type = OPTION_BITOP, \

View File

@@ -209,6 +209,10 @@ int cmd__parse_options(int argc, const char **argv)
OPT_GROUP("Alias"),
OPT_STRING('A', "alias-source", &string, "string", "get a string"),
OPT_ALIAS('Z', "alias-target", "alias-source"),
OPT_HIDDEN_GROUP("Hidden options"),
OPT_HIDDEN_BOOL(0, "hidden-bool", &boolean, "get a boolean"),
OPT_INTEGER_F('k', "hidden-integer", &integer, "get a integer",
PARSE_OPT_HIDDEN),
OPT_END(),
};
int ret = 0;

View File

@@ -7,7 +7,7 @@ test_description='our own option parser'
. ./test-lib.sh
cat >expect <<\EOF
cat >expect-part1 <<\EOF
usage: test-tool parse-options <options>
A helper function for the parse-options API.
@@ -41,6 +41,9 @@ String options
--[no-]string2 <str> get another string
--[no-]st <st> get another string (pervert ordering)
-o <str> get another string
EOF
cat >expect-part2 <<\EOF
--longhelp help text of this entry
spans multiple lines
--[no-]list <str> add str to list
@@ -67,12 +70,32 @@ Alias
EOF
cat >expect-noop <<\EOF
--[no-]obsolete no-op (backward compatibility)
EOF
cat >expect-hidden <<\EOF
Hidden options
--[no-]hidden-bool get a boolean
-k, --[no-]hidden-integer <n>
get a integer
EOF
test_expect_success 'test help' '
cat expect-part1 expect-part2 >expect &&
test-tool parse-options -h >output 2>output.err &&
test_must_be_empty output.err &&
test_cmp expect output
'
test_expect_success 'test --help-all shows hidden group and options' '
cat expect-part1 expect-noop expect-part2 expect-hidden >expect-help-all &&
test-tool parse-options --help-all >output 2>output.err &&
test_must_be_empty output.err &&
test_cmp expect-help-all output
'
mv expect expect.err
check () {

View File

@@ -12,7 +12,6 @@ column
credential
credential-cache
credential-store
fast-import
fetch-pack
fmt-merge-msg
format-patch

View File

@@ -2827,6 +2827,13 @@ test_expect_success 'R: unknown commandline options are rejected' '\
test_must_fail git fast-import --non-existing-option < /dev/null
'
test_expect_success 'R: feature-only names are rejected on the command line' '
for opt in --alias --get-mark --ls --notes
do
test_must_fail git fast-import "$opt" </dev/null || return 1
done
'
test_expect_success 'R: die on invalid option argument' '
echo "option git active-branches=-5" |
test_must_fail git fast-import &&