Merge branch 'ps/contains-id-error-message'
authorJunio C Hamano <gitster@pobox.com>
Tue, 10 Apr 2018 07:28:20 +0000 (16:28 +0900)
committerJunio C Hamano <gitster@pobox.com>
Tue, 10 Apr 2018 07:28:20 +0000 (16:28 +0900)
"git tag --contains no-such-commit" gave a full list of options
after giving an error message.

* ps/contains-id-error-message:
parse-options: do not show usage upon invalid option value

1  2 
builtin/blame.c
builtin/shortlog.c
builtin/update-index.c
parse-options.c
parse-options.h
t/t3404-rebase-interactive.sh
diff --combined builtin/blame.c
index f1a2fd67029e6980d317da5136aece233ba192f1,9803ddc0e7fad0a72891045a1526d7884f395e1a..db38c0b307c5719ab3bd5e6b8597ec8810c0de3d
@@@ -499,7 -499,7 +499,7 @@@ static int read_ancestry(const char *gr
  
  static int update_auto_abbrev(int auto_abbrev, struct blame_origin *suspect)
  {
 -      const char *uniq = find_unique_abbrev(suspect->commit->object.oid.hash,
 +      const char *uniq = find_unique_abbrev(&suspect->commit->object.oid,
                                              auto_abbrev);
        int len = strlen(uniq);
        if (auto_abbrev < len)
@@@ -649,15 -649,6 +649,15 @@@ static int blame_move_callback(const st
        return 0;
  }
  
 +static int is_a_rev(const char *name)
 +{
 +      struct object_id oid;
 +
 +      if (get_oid(name, &oid))
 +              return 0;
 +      return OBJ_NONE < oid_object_info(&oid, NULL);
 +}
 +
  int cmd_blame(int argc, const char **argv, const char *prefix)
  {
        struct rev_info revs;
        for (;;) {
                switch (parse_options_step(&ctx, options, blame_opt_usage)) {
                case PARSE_OPT_HELP:
+               case PARSE_OPT_ERROR:
                        exit(129);
                case PARSE_OPT_DONE:
                        if (ctx.argv[0])
@@@ -854,15 -846,16 +855,15 @@@ parse_done
        } else {
                if (argc < 2)
                        usage_with_options(blame_opt_usage, options);
 -              path = add_prefix(prefix, argv[argc - 1]);
 -              if (argc == 3 && !file_exists(path)) { /* (2b) */
 +              if (argc == 3 && is_a_rev(argv[argc - 1])) { /* (2b) */
                        path = add_prefix(prefix, argv[1]);
                        argv[1] = argv[2];
 +              } else {        /* (2a) */
 +                      if (argc == 2 && is_a_rev(argv[1]) && !get_git_work_tree())
 +                              die("missing <path> to blame");
 +                      path = add_prefix(prefix, argv[argc - 1]);
                }
                argv[argc - 1] = "--";
 -
 -              setup_work_tree();
 -              if (!file_exists(path))
 -                      die_errno("cannot stat path '%s'", path);
        }
  
        revs.disable_stdin = 1;
diff --combined builtin/shortlog.c
index 3a823b3128259c8f9ee92dbbfaacb492a90e7d6e,be4df6a037fce46dd5af321025a898dd1d5fab87..608d6ba77bdfb4673513444651053d0e8e789020
@@@ -11,8 -11,7 +11,8 @@@
  #include "parse-options.h"
  
  static char const * const shortlog_usage[] = {
 -      N_("git shortlog [<options>] [<revision-range>] [[--] [<path>...]]"),
 +      N_("git shortlog [<options>] [<revision-range>] [[--] <path>...]"),
 +      N_("git log --pretty=short | git shortlog [<options>]"),
        NULL
  };
  
@@@ -284,6 -283,7 +284,7 @@@ int cmd_shortlog(int argc, const char *
        for (;;) {
                switch (parse_options_step(&ctx, options, shortlog_usage)) {
                case PARSE_OPT_HELP:
+               case PARSE_OPT_ERROR:
                        exit(129);
                case PARSE_OPT_DONE:
                        goto parse_done;
  parse_done:
        argc = parse_options_end(&ctx);
  
 +      if (nongit && argc > 1) {
 +              error(_("too many arguments given outside repository"));
 +              usage_with_options(shortlog_usage, options);
 +      }
 +
        if (setup_revisions(argc, argv, &rev, NULL) != 1) {
                error(_("unrecognized argument: %s"), argv[1]);
                usage_with_options(shortlog_usage, options);
diff --combined builtin/update-index.c
index 9625d1e10a691c1dbd2ec2aa5d10a6c8a6ca7885,34adf55a719915c6e69f8983a37851ca99e9b60b..10d070a76fb1b0b94c058f60934bb05db37a4164
@@@ -592,7 -592,7 +592,7 @@@ static struct cache_entry *read_one_ent
        int size;
        struct cache_entry *ce;
  
 -      if (get_tree_entry(ent->hash, path, oid.hash, &mode)) {
 +      if (get_tree_entry(ent, path, &oid, &mode)) {
                if (which)
                        error("%s: not in %s branch.", path, which);
                return NULL;
@@@ -1059,6 -1059,7 +1059,7 @@@ int cmd_update_index(int argc, const ch
                        break;
                switch (parseopt_state) {
                case PARSE_OPT_HELP:
+               case PARSE_OPT_ERROR:
                        exit(129);
                case PARSE_OPT_NON_OPTION:
                case PARSE_OPT_DONE:
diff --combined parse-options.c
index 125e84f98451b4eb12e9d8a6cb4da58b2d8db51e,a0bae92b0cacc4fe4d1beb58dc5af890ff72fd56..0f7059a8ab32a624775026d7dc2289245c87c192
@@@ -317,14 -317,16 +317,16 @@@ is_abbreviated
                return get_value(p, options, all_opts, flags ^ opt_flags);
        }
  
-       if (ambiguous_option)
-               return error("Ambiguous option: %s "
+       if (ambiguous_option) {
+               error("Ambiguous option: %s "
                        "(could be --%s%s or --%s%s)",
                        arg,
                        (ambiguous_flags & OPT_UNSET) ?  "no-" : "",
                        ambiguous_option->long_name,
                        (abbrev_flags & OPT_UNSET) ?  "no-" : "",
                        abbrev_option->long_name);
+               return -3;
+       }
        if (abbrev_option)
                return get_value(p, abbrev_option, all_opts, abbrev_flags);
        return -2;
@@@ -425,48 -427,6 +427,48 @@@ void parse_options_start(struct parse_o
        parse_options_check(options);
  }
  
 +/*
 + * TODO: we are not completing the --no-XXX form yet because there are
 + * many options that do not suppress it properly.
 + */
 +static int show_gitcomp(struct parse_opt_ctx_t *ctx,
 +                      const struct option *opts)
 +{
 +      for (; opts->type != OPTION_END; opts++) {
 +              const char *suffix = "";
 +
 +              if (!opts->long_name)
 +                      continue;
 +              if (opts->flags & (PARSE_OPT_HIDDEN | PARSE_OPT_NOCOMPLETE))
 +                      continue;
 +
 +              switch (opts->type) {
 +              case OPTION_GROUP:
 +                      continue;
 +              case OPTION_STRING:
 +              case OPTION_FILENAME:
 +              case OPTION_INTEGER:
 +              case OPTION_MAGNITUDE:
 +              case OPTION_CALLBACK:
 +                      if (opts->flags & PARSE_OPT_NOARG)
 +                              break;
 +                      if (opts->flags & PARSE_OPT_OPTARG)
 +                              break;
 +                      if (opts->flags & PARSE_OPT_LASTARG_DEFAULT)
 +                              break;
 +                      suffix = "=";
 +                      break;
 +              default:
 +                      break;
 +              }
 +              if (opts->flags & PARSE_OPT_COMP_ARG)
 +                      suffix = "=";
 +              printf(" --%s%s", opts->long_name, suffix);
 +      }
 +      fputc('\n', stdout);
 +      exit(0);
 +}
 +
  static int usage_with_options_internal(struct parse_opt_ctx_t *,
                                       const char * const *,
                                       const struct option *, int, int);
@@@ -476,7 -436,6 +478,6 @@@ int parse_options_step(struct parse_opt
                       const char * const usagestr[])
  {
        int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
-       int err = 0;
  
        /* we must reset ->opt, unknown short option leave it dangling */
        ctx->opt = NULL;
                if (internal_help && ctx->total == 1 && !strcmp(arg + 1, "h"))
                        goto show_usage;
  
 +              /* lone --git-completion-helper is asked by git-completion.bash */
 +              if (ctx->total == 1 && !strcmp(arg + 1, "-git-completion-helper"))
 +                      return show_gitcomp(ctx, options);
 +
                if (arg[1] != '-') {
                        ctx->opt = arg + 1;
                        switch (parse_short_opt(ctx, options)) {
                        case -1:
-                               goto show_usage_error;
+                               return PARSE_OPT_ERROR;
                        case -2:
                                if (ctx->opt)
                                        check_typos(arg + 1, options);
                        while (ctx->opt) {
                                switch (parse_short_opt(ctx, options)) {
                                case -1:
-                                       goto show_usage_error;
+                                       return PARSE_OPT_ERROR;
                                case -2:
                                        if (internal_help && *ctx->opt == 'h')
                                                goto show_usage;
                        goto show_usage;
                switch (parse_long_opt(ctx, arg + 2, options)) {
                case -1:
-                       goto show_usage_error;
+                       return PARSE_OPT_ERROR;
                case -2:
                        goto unknown;
+               case -3:
+                       goto show_usage;
                }
                continue;
  unknown:
        }
        return PARSE_OPT_DONE;
  
-  show_usage_error:
-       err = 1;
   show_usage:
-       return usage_with_options_internal(ctx, usagestr, options, 0, err);
+       return usage_with_options_internal(ctx, usagestr, options, 0, 0);
  }
  
  int parse_options_end(struct parse_opt_ctx_t *ctx)
  {
 -      memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
 +      MOVE_ARRAY(ctx->out + ctx->cpidx, ctx->argv, ctx->argc);
        ctx->out[ctx->cpidx + ctx->argc] = NULL;
        return ctx->cpidx + ctx->argc;
  }
@@@ -585,6 -540,7 +586,7 @@@ int parse_options(int argc, const char 
        parse_options_start(&ctx, argc, argv, prefix, options, flags);
        switch (parse_options_step(&ctx, options, usagestr)) {
        case PARSE_OPT_HELP:
+       case PARSE_OPT_ERROR:
                exit(129);
        case PARSE_OPT_NON_OPTION:
        case PARSE_OPT_DONE:
diff --combined parse-options.h
index ab1cc362bf2918c28a14dd851c1b1a13dfa0c863,c77bb3b4f8d9342178b8caa68190b02f50ea4274..dd14911a297a5b10705ecb31243c55a7dc2f193c
@@@ -38,9 -38,7 +38,9 @@@ enum parse_opt_option_flags 
        PARSE_OPT_LASTARG_DEFAULT = 16,
        PARSE_OPT_NODASH = 32,
        PARSE_OPT_LITERAL_ARGHELP = 64,
 -      PARSE_OPT_SHELL_EVAL = 256
 +      PARSE_OPT_SHELL_EVAL = 256,
 +      PARSE_OPT_NOCOMPLETE = 512,
 +      PARSE_OPT_COMP_ARG = 1024
  };
  
  struct option;
@@@ -91,11 -89,6 +91,11 @@@ typedef int parse_opt_ll_cb(struct pars
   *   PARSE_OPT_LITERAL_ARGHELP: says that argh shouldn't be enclosed in brackets
   *                            (i.e. '<argh>') in the help message.
   *                            Useful for options with multiple parameters.
 + *   PARSE_OPT_NOCOMPLETE: by default all visible options are completable
 + *                       by git-completion.bash. This option suppresses that.
 + *   PARSE_OPT_COMP_ARG: this option forces to git-completion.bash to
 + *                     complete an option as --name= not --name even if
 + *                     the option takes optional argument.
   *
   * `callback`::
   *   pointer to the callback to use for OPTION_CALLBACK or
@@@ -119,24 -112,19 +119,24 @@@ struct option 
        intptr_t defval;
  };
  
 +#define OPT_BIT_F(s, l, v, h, b, f) { OPTION_BIT, (s), (l), (v), NULL, (h), \
 +                                    PARSE_OPT_NOARG|(f), NULL, (b) }
 +#define OPT_COUNTUP_F(s, l, v, h, f) { OPTION_COUNTUP, (s), (l), (v), NULL, \
 +                                     (h), PARSE_OPT_NOARG|(f) }
 +#define OPT_SET_INT_F(s, l, v, h, i, f) { OPTION_SET_INT, (s), (l), (v), NULL, \
 +                                        (h), PARSE_OPT_NOARG | (f), NULL, (i) }
 +#define OPT_BOOL_F(s, l, v, h, f)   OPT_SET_INT_F(s, l, v, h, 1, f)
 +
  #define OPT_END()                   { OPTION_END }
  #define OPT_ARGUMENT(l, h)          { OPTION_ARGUMENT, 0, (l), NULL, NULL, \
                                      (h), PARSE_OPT_NOARG}
  #define OPT_GROUP(h)                { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
 -#define OPT_BIT(s, l, v, h, b)      { OPTION_BIT, (s), (l), (v), NULL, (h), \
 -                                    PARSE_OPT_NOARG, NULL, (b) }
 +#define OPT_BIT(s, l, v, h, b)      OPT_BIT_F(s, l, v, h, b, 0)
  #define OPT_NEGBIT(s, l, v, h, b)   { OPTION_NEGBIT, (s), (l), (v), NULL, \
                                      (h), PARSE_OPT_NOARG, NULL, (b) }
 -#define OPT_COUNTUP(s, l, v, h)     { OPTION_COUNTUP, (s), (l), (v), NULL, \
 -                                    (h), PARSE_OPT_NOARG }
 -#define OPT_SET_INT(s, l, v, h, i)  { OPTION_SET_INT, (s), (l), (v), NULL, \
 -                                    (h), PARSE_OPT_NOARG, NULL, (i) }
 -#define OPT_BOOL(s, l, v, h)        OPT_SET_INT(s, l, v, h, 1)
 +#define OPT_COUNTUP(s, l, v, h)     OPT_COUNTUP_F(s, l, v, h, 0)
 +#define OPT_SET_INT(s, l, v, h, i)  OPT_SET_INT_F(s, l, v, h, i, 0)
 +#define OPT_BOOL(s, l, v, h)        OPT_BOOL_F(s, l, v, h, 0)
  #define OPT_HIDDEN_BOOL(s, l, v, h) { OPTION_SET_INT, (s), (l), (v), NULL, \
                                      (h), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1}
  #define OPT_CMDMODE(s, l, v, h, i)  { OPTION_CMDMODE, (s), (l), (v), NULL, \
@@@ -200,6 -188,7 +200,7 @@@ enum 
        PARSE_OPT_HELP = -1,
        PARSE_OPT_DONE,
        PARSE_OPT_NON_OPTION,
+       PARSE_OPT_ERROR,
        PARSE_OPT_UNKNOWN
  };
  
@@@ -252,7 -241,7 +253,7 @@@ extern int parse_opt_passthru_argv(cons
        { OPTION_CALLBACK, 'q', "quiet", (var), NULL, N_("be more quiet"), \
          PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }
  #define OPT__DRY_RUN(var, h)  OPT_BOOL('n', "dry-run", (var), (h))
 -#define OPT__FORCE(var, h)    OPT_COUNTUP('f', "force",   (var), (h))
 +#define OPT__FORCE(var, h, f) OPT_COUNTUP_F('f', "force",   (var), (h), (f))
  #define OPT__ABBREV(var)  \
        { OPTION_CALLBACK, 0, "abbrev", (var), N_("n"), \
          N_("use <n> digits to display SHA-1s"),       \
index 3b905406df79187f70c828f72e9e2dc187f1be57,3216707df77deaf8c6657e945b5bdabea17ac9be..c59d0384fd6f797ae30df9c157dbdf4b0307fa02
@@@ -225,14 -225,6 +225,14 @@@ test_expect_success 'stop on conflictin
        test 0 = $(grep -c "^[^#]" < .git/rebase-merge/git-rebase-todo)
  '
  
 +test_expect_success 'show conflicted patch' '
 +      GIT_TRACE=1 git rebase --show-current-patch >/dev/null 2>stderr &&
 +      grep "show.*REBASE_HEAD" stderr &&
 +      # the original stopped-sha1 is abbreviated
 +      stopped_sha1="$(git rev-parse $(cat ".git/rebase-merge/stopped-sha"))" &&
 +      test "$(git rev-parse REBASE_HEAD)" = "$stopped_sha1"
 +'
 +
  test_expect_success 'abort' '
        git rebase --abort &&
        test $(git rev-parse new-branch1) = $(git rev-parse HEAD) &&
@@@ -461,10 -453,6 +461,10 @@@ test_expect_success C_LOCALE_OUTPUT 'sq
                git rebase -i $base &&
        git cat-file commit HEAD | sed -e 1,/^\$/d > actual-squash-fixup &&
        test_cmp expect-squash-fixup actual-squash-fixup &&
 +      git cat-file commit HEAD@{2} |
 +              grep "^# This is a combination of 3 commits\."  &&
 +      git cat-file commit HEAD@{3} |
 +              grep "^# This is a combination of 2 commits\."  &&
        git checkout to-be-rebased &&
        git branch -D squash-fixup
  '
@@@ -927,10 -915,8 +927,8 @@@ test_expect_success 'rebase --exec work
  test_expect_success 'rebase -i --exec without <CMD>' '
        git reset --hard execute &&
        set_fake_editor &&
-       test_must_fail git rebase -i --exec 2>tmp &&
-       sed -e "1d" tmp >actual &&
-       test_must_fail git rebase -h >expected &&
-       test_cmp expected actual &&
+       test_must_fail git rebase -i --exec 2>actual &&
+       test_i18ngrep "requires a value" actual &&
        git checkout master
  '
  
@@@ -1348,16 -1334,6 +1346,16 @@@ test_expect_success 'editor saves as CR
  
  SQ="'"
  test_expect_success 'rebase -i --gpg-sign=<key-id>' '
 +      test_when_finished "test_might_fail git rebase --abort" &&
 +      set_fake_editor &&
 +      FAKE_LINES="edit 1" git rebase -i --gpg-sign="\"S I Gner\"" HEAD^ \
 +              >out 2>err &&
 +      test_i18ngrep "$SQ-S\"S I Gner\"$SQ" err
 +'
 +
 +test_expect_success 'rebase -i --gpg-sign=<key-id> overrides commit.gpgSign' '
 +      test_when_finished "test_might_fail git rebase --abort" &&
 +      test_config commit.gpgsign true &&
        set_fake_editor &&
        FAKE_LINES="edit 1" git rebase -i --gpg-sign="\"S I Gner\"" HEAD^ \
                >out 2>err &&