Re: [PATCH v2 11/12] fast-import: use parse_options() for command line options

Elijah Newren <[email protected]>
Newsgroups org.kernel.vger.git
Message-ID <CABPp-BFfF+Vd6RY3pG=FVUH_93YZULfhcXdWCv6zcRSABfGBQQ@mail.gmail.com>
On Tue, Aug 4, 2026 at 3:04 AM Christian Couder
<[email protected]> wrote:
>
> Previous commits have started to use the parse-options API to display
> output from `git fast-import -h` and `git fast-import --help-all` and
> to prepare for parsing the command line options using this API.
>
> Let's now actually use the API to parse command line options.
>
> This brings a number of changes that are mostly beneficial:
>
>   - The `--alias`, `--get-mark`, `--cat-blob`, `--ls` and `--notes`
>     options are no longer accepted on the command line. They were
>     previously accepted as no-ops because parse_argv() fell through to
>     parse_one_feature(). They are not documented in the OPTIONS section
>     and are only meaningful as in-stream feature assertions, so
>     accepting them on the command line was an accident of code sharing
>     dating back to 9c8398f0c9 (fast-import: add option command,
>     2009-12-04).
>
>   - Abbreviated options like `--dep=5` now work since parse_options()
>     allows unambiguous prefixes.
>
>   - As `--cat-blob` is an abbreviation of `--cat-blob-fd`, using the
>     former on the command line will fail with "option `cat-blob-fd'
>     requires a value" unlike the other four options that are not
>     accepted anymore on the command line (see above).
>
>   - The error messages for some options might differ a bit.
>
>   - The code is shorter and more standard.

I think the list might be missing three behavioral changes:

1) A bare "--" (or a trailing "--") is now accepted and the command
reads the stream normally, whereas the base treated it as a usage
error:

        printf '' | git fast-import --   # before: 129 (usage), after: 0

The old parse_argv() broke on "--" and then did "if (i != state->argc)
usage_with_options(...)"; parse_options() instead consumes "--" as the
end-of-options marker and returns just argv0.  Harmless /
conventional, just unlisted.

2) Value-taking options now also accept the space-separated "--opt
value" form (e.g. "--depth 5", "--max-pack-size 1m", "--date-format
raw"), not just "--opt=value".   Also expected parse_options()
behavior and a nice improvement.

3) The handling of "--allow-unsafe-features" has changed and might
trip users up.

Because the "feature" lines at the top of the stream are processed
before parse_argv() runs, cmd_fast_import() does an early scan just to
learn whether unsafe features are permitted:

        for (int i = 1; i < argc; i++) {
                const char *arg = argv[i];
                if (*arg != '-' || !strcmp(arg, "--"))
                        break;
                if (!strcmp(arg, "--allow-unsafe-features"))
                        state.allow_unsafe_features = 1;
        }

That scan (a) matches only the exact spelling and (b) stops at the
first token not starting with '-'.  In the base that was fine, because
the old parse_argv loop was equally strict (exact spelling,
"--opt=value" only).
But now that parse_options() also accepts unambiguous abbreviations
and space-separated values, the two passes disagree.  With an unsafe
feature line in the stream:

    # (A) old-style spelling, still fine:
    printf 'feature import-marks-if-exists=/nope\n' |
      git fast-import --depth=5 --allow-unsafe-features
    # -> exit 0

    # (B) space-separated value, newly accepted by parse_options():
    printf 'feature import-marks-if-exists=/nope\n' |
      git fast-import --depth 5 --allow-unsafe-features
    # -> fatal: feature 'import-marks-if-exists' forbidden ... (128)

    # (C) abbreviation, newly accepted by parse_options():
    printf 'feature import-marks-if-exists=/nope\n' |
      git fast-import --allow-unsafe
    # -> fatal: feature 'import-marks-if-exists' forbidden ... (128)

In (B) the early scan breaks on the bare "5" (it can't tell "5" is
--depth's argument) and never reaches --allow-unsafe-features; in (C)
the abbreviation isn't recognized by the strcmp().  Yet in both cases
parse_options() itself accepts the option ("git fast-import
--allow-unsafe" alone exits 0), so it's only the in-stream feature
that gets rejected.

This errs on the safe side (it refuses an unsafe feature rather than
allowing one), and it's a minor inconsistency, but it might surprise
users.  At a minimum, it should probably be documented as a
shortcoming or TODO or something.  One possible solution is a
dedicated parse_options() pass for just --allow-unsafe-features;
another might be just requiring --allow-unsafe-features to be the
*first* argument.  Thoughts?


Anyway, other than the above list of three additional behavioral
changes, the rest of the patch looks right.  Thanks for tackling
modernizing this command.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.