Merge branch 'jk/eoo'
authorJunio C Hamano <gitster@pobox.com>
Mon, 9 Sep 2019 19:26:35 +0000 (12:26 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 9 Sep 2019 19:26:36 +0000 (12:26 -0700)
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

Documentation/gitcli.txt
parse-options.c
revision.c
t/t0040-parse-options.sh
t/t4202-log.sh
t/t6000-rev-list-misc.sh
index 1ed3ca33b7a94ad8187d7fa490cc212711fd578e..4b32876b6e912b528ee0e00399719576a12b1990 100644 (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
index 87b26a1d922e8905fe369b164ae5cad7ea372426..b42f54d48b96c05a207ffb02eac8c235c2b723b0 100644 (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++;
index 07412297f0248aae886eeb77c3a1cab13c93039c..51690e480d5b626224e919f04dbfb8d1c3426f3e 100644 (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) {
index cebc77fab0b254fc2e6f63e7eb68956b2b3dec9c..705a136ed92c99cda688f5e267204e59b0e532a9 100755 (executable)
@@ -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
index c20209324c8e71c677b70ce2217cf6439385024b..e88ccb04a9715b92e47976e66753c38c2547babf 100755 (executable)
@@ -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
index 52a9e38d66f3222f4c02f7d067a9509db685f875..b8cf82349b1d6d0405342cf98ead948d2e81c2a5 100755 (executable)
@@ -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