Merge branch 'jk/consistent-h'
authorJunio C Hamano <gitster@pobox.com>
Mon, 19 Jun 2017 19:38:45 +0000 (12:38 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 19 Jun 2017 19:38:45 +0000 (12:38 -0700)
"git $cmd -h" for builtin commands calls the implementation of the
command (i.e. cmd_$cmd() function) without doing any repository
set-up, and the commands that expect RUN_SETUP is done by the Git
potty needs to be prepared to show the help text without barfing.

* jk/consistent-h:
t0012: test "-h" with builtins
git: add hidden --list-builtins option
version: convert to parse-options
diff- and log- family: handle "git cmd -h" early
submodule--helper: show usage for "-h"
remote-{ext,fd}: print usage message on invalid arguments
upload-archive: handle "-h" option early
credential: handle invalid arguments earlier

1  2 
builtin/diff-files.c
builtin/diff-index.c
builtin/diff-tree.c
builtin/rev-list.c
builtin/submodule--helper.c
help.c
diff --combined builtin/diff-files.c
index a572da9d5152ddf541f71e1aaf8abdb3c98f8ffe,6be1df684a8459d7d2226faf9b28fbc55ea443b5..c97069a714e42a1737b5dfa223fe39c26ad9aa67
@@@ -20,9 -20,12 +20,12 @@@ int cmd_diff_files(int argc, const cha
        int result;
        unsigned options = 0;
  
+       if (argc == 2 && !strcmp(argv[1], "-h"))
+               usage(diff_files_usage);
 +      git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        init_revisions(&rev, prefix);
        gitmodules_config();
 -      git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        rev.abbrev = 0;
        precompose_argv(argc, argv);
  
diff --combined builtin/diff-index.c
index f084826a293f96870d0cf6be05e3e346672fc5dc,02dd35ba456ed4e0d12d4a1fe8fd58f0c4d406a1..d59bf6cf5f8da394251532765f27a044c14a572d
@@@ -17,9 -17,12 +17,12 @@@ int cmd_diff_index(int argc, const cha
        int i;
        int result;
  
+       if (argc == 2 && !strcmp(argv[1], "-h"))
+               usage(diff_cache_usage);
 +      git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        init_revisions(&rev, prefix);
        gitmodules_config();
 -      git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        rev.abbrev = 0;
        precompose_argv(argc, argv);
  
diff --combined builtin/diff-tree.c
index 1fd06eac4b9b56dc2f3e21ef3045ff66507cdaf3,773cc254b5909713b2838db4ba52e7b6f9e88e60..7e15d01f36396fdc6b630eb43a5f36d462fb78e6
@@@ -7,9 -7,9 +7,9 @@@
  
  static struct rev_info log_tree_opt;
  
 -static int diff_tree_commit_sha1(const struct object_id *oid)
 +static int diff_tree_commit_oid(const struct object_id *oid)
  {
 -      struct commit *commit = lookup_commit_reference(oid->hash);
 +      struct commit *commit = lookup_commit_reference(oid);
        if (!commit)
                return -1;
        return log_tree_commit(&log_tree_opt, commit);
@@@ -23,7 -23,7 +23,7 @@@ static int stdin_diff_commit(struct com
  
        /* Graft the fake parents locally to the commit */
        while (isspace(*p++) && !parse_oid_hex(p, &oid, &p)) {
 -              struct commit *parent = lookup_commit(oid.hash);
 +              struct commit *parent = lookup_commit(&oid);
                if (!pptr) {
                        /* Free the real parent list */
                        free_commit_list(commit->parents);
@@@ -44,13 -44,13 +44,13 @@@ static int stdin_diff_trees(struct tre
        struct tree *tree2;
        if (!isspace(*p++) || parse_oid_hex(p, &oid, &p) || *p)
                return error("Need exactly two trees, separated by a space");
 -      tree2 = lookup_tree(oid.hash);
 +      tree2 = lookup_tree(&oid);
        if (!tree2 || parse_tree(tree2))
                return -1;
        printf("%s %s\n", oid_to_hex(&tree1->object.oid),
                          oid_to_hex(&tree2->object.oid));
 -      diff_tree_sha1(tree1->object.oid.hash, tree2->object.oid.hash,
 -                     "", &log_tree_opt.diffopt);
 +      diff_tree_oid(&tree1->object.oid, &tree2->object.oid,
 +                    "", &log_tree_opt.diffopt);
        log_tree_diff_flush(&log_tree_opt);
        return 0;
  }
@@@ -67,7 -67,7 +67,7 @@@ static int diff_tree_stdin(char *line
        line[len-1] = 0;
        if (parse_oid_hex(line, &oid, &p))
                return -1;
 -      obj = parse_object(oid.hash);
 +      obj = parse_object(&oid);
        if (!obj)
                return -1;
        if (obj->type == OBJ_COMMIT)
@@@ -98,15 -98,19 +98,18 @@@ static void diff_tree_tweak_rev(struct 
  
  int cmd_diff_tree(int argc, const char **argv, const char *prefix)
  {
 -      int nr_sha1;
        char line[1000];
        struct object *tree1, *tree2;
        static struct rev_info *opt = &log_tree_opt;
        struct setup_revision_opt s_r_opt;
        int read_stdin = 0;
  
+       if (argc == 2 && !strcmp(argv[1], "-h"))
+               usage(diff_tree_usage);
 +      git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        init_revisions(opt, prefix);
        gitmodules_config();
 -      git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        opt->abbrev = 0;
        opt->diff = 1;
        opt->disable_stdin = 1;
        }
  
        /*
 -       * NOTE! We expect "a ^b" to be equal to "a..b", so we
 -       * reverse the order of the objects if the second one
 -       * is marked UNINTERESTING.
 +       * NOTE!  We expect "a..b" to expand to "^a b" but it is
 +       * perfectly valid for revision range parser to yield "b ^a",
 +       * which means the same thing. If we get the latter, i.e. the
 +       * second one is marked UNINTERESTING, we recover the original
 +       * order the user gave, i.e. "a..b", by swapping the trees.
         */
 -      nr_sha1 = opt->pending.nr;
 -      switch (nr_sha1) {
 +      switch (opt->pending.nr) {
        case 0:
                if (!read_stdin)
                        usage(diff_tree_usage);
                break;
        case 1:
                tree1 = opt->pending.objects[0].item;
 -              diff_tree_commit_sha1(&tree1->oid);
 +              diff_tree_commit_oid(&tree1->oid);
                break;
        case 2:
                tree1 = opt->pending.objects[0].item;
                if (tree2->flags & UNINTERESTING) {
                        SWAP(tree2, tree1);
                }
 -              diff_tree_sha1(tree1->oid.hash,
 -                             tree2->oid.hash,
 -                             "", &opt->diffopt);
 +              diff_tree_oid(&tree1->oid, &tree2->oid, "", &opt->diffopt);
                log_tree_diff_flush(opt);
                break;
        }
diff --combined builtin/rev-list.c
index 718c6059c9f570d94b0bdba46d33ed1b065a34f7,2951e0efd7e315dd7ec93f37142a730e2c27fb6a..b250c515b1aecab2b43aebe591ad7a22d5829271
@@@ -80,7 -80,7 +80,7 @@@ static void show_commit(struct commit *
        }
  
        if (info->show_timestamp)
 -              printf("%lu ", commit->date);
 +              printf("%"PRItime" ", commit->date);
        if (info->header_prefix)
                fputs(info->header_prefix, stdout);
  
@@@ -181,7 -181,7 +181,7 @@@ static void finish_object(struct objec
        if (obj->type == OBJ_BLOB && !has_object_file(&obj->oid))
                die("missing blob object '%s'", oid_to_hex(&obj->oid));
        if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT)
 -              parse_object(obj->oid.hash);
 +              parse_object(&obj->oid);
  }
  
  static void show_object(struct object *obj, const char *name, void *cb_data)
@@@ -277,6 -277,9 +277,9 @@@ int cmd_rev_list(int argc, const char *
        int use_bitmap_index = 0;
        const char *show_progress = NULL;
  
+       if (argc == 2 && !strcmp(argv[1], "-h"))
+               usage(rev_list_usage);
        git_config(git_default_config, NULL);
        init_revisions(&revs, prefix);
        revs.abbrev = DEFAULT_ABBREV;
index 8cc648d85b586752d39079e75cf81a4ee685b622,a78b003c25ba95a4030499d21dac6b5f6a43dec9..1b4d2b346762af8e6150d88fed87409e877ca676
@@@ -233,7 -233,8 +233,7 @@@ static int module_list_compute(int argc
        int i, result = 0;
        char *ps_matched = NULL;
        parse_pathspec(pathspec, 0,
 -                     PATHSPEC_PREFER_FULL |
 -                     PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
 +                     PATHSPEC_PREFER_FULL,
                       prefix, argv);
  
        if (pathspec->nr)
@@@ -1221,9 -1222,8 +1221,8 @@@ static struct cmd_struct commands[] = 
  int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
  {
        int i;
-       if (argc < 2)
-               die(_("submodule--helper subcommand must be "
-                     "called with a subcommand"));
+       if (argc < 2 || !strcmp(argv[1], "-h"))
+               usage("git submodule--helper <command>");
  
        for (i = 0; i < ARRAY_SIZE(commands); i++) {
                if (!strcmp(argv[1], commands[i].cmd)) {
diff --combined help.c
index db7f3d79a016881639a8c0640451afe35b011e5e,1064363cd5f70aa69c97192e13fd2ca15d8e3b6f..f637fc80062094784d5734df91523642933ddcfc
--- 1/help.c
--- 2/help.c
+++ b/help.c
@@@ -1,7 -1,6 +1,7 @@@
  #include "cache.h"
  #include "builtin.h"
  #include "exec_cmd.h"
 +#include "run-command.h"
  #include "levenshtein.h"
  #include "help.h"
  #include "common-cmds.h"
@@@ -9,6 -8,7 +9,7 @@@
  #include "column.h"
  #include "version.h"
  #include "refs.h"
+ #include "parse-options.h"
  
  void add_cmdname(struct cmdnames *cmds, const char *name, int len)
  {
@@@ -97,6 -97,48 +98,6 @@@ static void pretty_print_cmdnames(struc
        string_list_clear(&list, 0);
  }
  
 -static int is_executable(const char *name)
 -{
 -      struct stat st;
 -
 -      if (stat(name, &st) || /* stat, not lstat */
 -          !S_ISREG(st.st_mode))
 -              return 0;
 -
 -#if defined(GIT_WINDOWS_NATIVE)
 -      /*
 -       * On Windows there is no executable bit. The file extension
 -       * indicates whether it can be run as an executable, and Git
 -       * has special-handling to detect scripts and launch them
 -       * through the indicated script interpreter. We test for the
 -       * file extension first because virus scanners may make
 -       * it quite expensive to open many files.
 -       */
 -      if (ends_with(name, ".exe"))
 -              return S_IXUSR;
 -
 -{
 -      /*
 -       * Now that we know it does not have an executable extension,
 -       * peek into the file instead.
 -       */
 -      char buf[3] = { 0 };
 -      int n;
 -      int fd = open(name, O_RDONLY);
 -      st.st_mode &= ~S_IXUSR;
 -      if (fd >= 0) {
 -              n = read(fd, buf, 2);
 -              if (n == 2)
 -                      /* look for a she-bang */
 -                      if (!strcmp(buf, "#!"))
 -                              st.st_mode |= S_IXUSR;
 -              close(fd);
 -      }
 -}
 -#endif
 -      return st.st_mode & S_IXUSR;
 -}
 -
  static void list_commands_in_dir(struct cmdnames *cmds,
                                         const char *path,
                                         const char *prefix)
@@@ -370,8 -412,8 +371,8 @@@ const char *help_unknown_cmd(const cha
  
        if (SIMILAR_ENOUGH(best_similarity)) {
                fprintf_ln(stderr,
 -                         Q_("\nDid you mean this?",
 -                            "\nDid you mean one of these?",
 +                         Q_("\nThe most similar command is",
 +                            "\nThe most similar commands are",
                           n));
  
                for (i = 0; i < n; i++)
  
  int cmd_version(int argc, const char **argv, const char *prefix)
  {
+       int build_options = 0;
+       const char * const usage[] = {
+               N_("git version [<options>]"),
+               NULL
+       };
+       struct option options[] = {
+               OPT_BOOL(0, "build-options", &build_options,
+                        "also print build options"),
+               OPT_END()
+       };
+       argc = parse_options(argc, argv, prefix, options, usage, 0);
        /*
         * The format of this string should be kept stable for compatibility
         * with external projects that rely on the output of "git version".
+        *
+        * Always show the version, even if other options are given.
         */
        printf("git version %s\n", git_version_string);
-       while (*++argv) {
-               if (!strcmp(*argv, "--build-options")) {
-                       printf("sizeof-long: %d\n", (int)sizeof(long));
-                       /* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
-               }
+       if (build_options) {
+               printf("sizeof-long: %d\n", (int)sizeof(long));
+               /* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
        }
        return 0;
  }