Merge branch 'jk/eoo'

The command line parser learned "--end-of-options" notation; the
standard convention for scripters to have hardcoded set of options
first on the command line, and force the command to treat end-user
input as non-options, has been to use "--" as the delimiter, but
that would not work for commands that use "--" as a delimiter
between revs and pathspec.

* jk/eoo:
  gitcli: document --end-of-options
  parse-options: allow --end-of-options as a synonym for "--"
  revision: allow --end-of-options to end option parsing
This commit is contained in:
Junio C Hamano 2019-09-09 12:26:35 -07:00
commit 4a12f89865
6 changed files with 37 additions and 2 deletions

View File

@ -37,6 +37,12 @@ arguments. Here are the rules:
file called HEAD in your work tree, `git diff HEAD` is ambiguous, and
you have to say either `git diff HEAD --` or `git diff -- HEAD` to
disambiguate.
* Because `--` disambiguates revisions and paths in some commands, it
cannot be used for those commands to separate options and revisions.
You can use `--end-of-options` for this (it also works for commands
that do not distinguish between revisions in paths, in which case it
is simply an alias for `--`).
+
When writing a script that is expected to handle random user-input, it is
a good practice to make it explicit which arguments are which by placing

View File

@ -780,7 +780,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
continue;
}
if (!arg[2]) { /* "--" */
if (!arg[2] /* "--" */ ||
!strcmp(arg + 2, "end-of-options")) {
if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
ctx->argc--;
ctx->argv++;

View File

@ -2523,6 +2523,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
int i, flags, left, seen_dashdash, got_rev_arg = 0, revarg_opt;
struct argv_array prune_data = ARGV_ARRAY_INIT;
const char *submodule = NULL;
int seen_end_of_options = 0;
if (opt)
submodule = opt->submodule;
@ -2552,7 +2553,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
revarg_opt |= REVARG_CANNOT_BE_FILENAME;
for (left = i = 1; i < argc; i++) {
const char *arg = argv[i];
if (*arg == '-') {
if (!seen_end_of_options && *arg == '-') {
int opts;
opts = handle_revision_pseudo_opt(submodule,
@ -2574,6 +2575,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
continue;
}
if (!strcmp(arg, "--end-of-options")) {
seen_end_of_options = 1;
continue;
}
opts = handle_revision_opt(revs, argc - i, argv + i,
&left, argv, opt);
if (opts > 0) {

View File

@ -399,4 +399,11 @@ test_expect_success 'GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS works' '
test-tool parse-options --ye
'
test_expect_success '--end-of-options treats remainder as args' '
test-tool parse-options \
--expect="verbose: -1" \
--expect="arg 00: --verbose" \
--end-of-options --verbose
'
test_done

View File

@ -1707,4 +1707,11 @@ test_expect_success '--exclude-promisor-objects does not BUG-crash' '
test_must_fail git log --exclude-promisor-objects source-a
'
test_expect_success 'log --end-of-options' '
git update-ref refs/heads/--source HEAD &&
git log --end-of-options --source >actual &&
git log >expect &&
test_cmp expect actual
'
test_done

View File

@ -140,4 +140,12 @@ test_expect_success '--header shows a NUL after each commit' '
test_cmp expect actual
'
test_expect_success 'rev-list --end-of-options' '
git update-ref refs/heads/--output=yikes HEAD &&
git rev-list --end-of-options --output=yikes >actual &&
test_path_is_missing yikes &&
git rev-list HEAD >expect &&
test_cmp expect actual
'
test_done