packaging: Add contrib installation
[platform/upstream/git.git] / help.c
diff --git a/help.c b/help.c
index a9e451f..3c3bdec 100644 (file)
--- a/help.c
+++ b/help.c
@@ -34,7 +34,7 @@ static struct category_description main_categories[] = {
        { CAT_foreignscminterface, N_("Interacting with Others") },
        { CAT_plumbingmanipulators, N_("Low-level Commands / Manipulators") },
        { CAT_plumbinginterrogators, N_("Low-level Commands / Interrogators") },
-       { CAT_synchingrepositories, N_("Low-level Commands / Synching Repositories") },
+       { CAT_synchingrepositories, N_("Low-level Commands / Syncing Repositories") },
        { CAT_purehelpers, N_("Low-level Commands / Internal Helpers") },
        { 0, NULL }
 };
@@ -263,6 +263,8 @@ void load_command_list(const char *prefix,
        const char *env_path = getenv("PATH");
        const char *exec_path = git_exec_path();
 
+       load_builtin_commands(prefix, main_cmds);
+
        if (exec_path) {
                list_commands_in_dir(main_cmds, exec_path, prefix);
                QSORT(main_cmds->names, main_cmds->cnt, cmdname_compare);
@@ -375,7 +377,7 @@ void list_cmds_by_config(struct string_list *list)
 {
        const char *cmd_list;
 
-       if (git_config_get_string_const("completion.commands", &cmd_list))
+       if (git_config_get_string_tmp("completion.commands", &cmd_list))
                return;
 
        string_list_sort(list);
@@ -397,101 +399,16 @@ void list_cmds_by_config(struct string_list *list)
        }
 }
 
-void list_common_guides_help(void)
+void list_guides_help(void)
 {
        struct category_description catdesc[] = {
-               { CAT_guide, N_("The common Git guides are:") },
+               { CAT_guide, N_("The Git concept guides are:") },
                { 0, NULL }
        };
        print_cmd_by_category(catdesc, NULL);
        putchar('\n');
 }
 
-struct slot_expansion {
-       const char *prefix;
-       const char *placeholder;
-       void (*fn)(struct string_list *list, const char *prefix);
-       int found;
-};
-
-void list_config_help(int for_human)
-{
-       struct slot_expansion slot_expansions[] = {
-               { "advice", "*", list_config_advices },
-               { "color.branch", "<slot>", list_config_color_branch_slots },
-               { "color.decorate", "<slot>", list_config_color_decorate_slots },
-               { "color.diff", "<slot>", list_config_color_diff_slots },
-               { "color.grep", "<slot>", list_config_color_grep_slots },
-               { "color.interactive", "<slot>", list_config_color_interactive_slots },
-               { "color.remote", "<slot>", list_config_color_sideband_slots },
-               { "color.status", "<slot>", list_config_color_status_slots },
-               { "fsck", "<msg-id>", list_config_fsck_msg_ids },
-               { "receive.fsck", "<msg-id>", list_config_fsck_msg_ids },
-               { NULL, NULL, NULL }
-       };
-       const char **p;
-       struct slot_expansion *e;
-       struct string_list keys = STRING_LIST_INIT_DUP;
-       int i;
-
-       for (p = config_name_list; *p; p++) {
-               const char *var = *p;
-               struct strbuf sb = STRBUF_INIT;
-
-               for (e = slot_expansions; e->prefix; e++) {
-
-                       strbuf_reset(&sb);
-                       strbuf_addf(&sb, "%s.%s", e->prefix, e->placeholder);
-                       if (!strcasecmp(var, sb.buf)) {
-                               e->fn(&keys, e->prefix);
-                               e->found++;
-                               break;
-                       }
-               }
-               strbuf_release(&sb);
-               if (!e->prefix)
-                       string_list_append(&keys, var);
-       }
-
-       for (e = slot_expansions; e->prefix; e++)
-               if (!e->found)
-                       BUG("slot_expansion %s.%s is not used",
-                           e->prefix, e->placeholder);
-
-       string_list_sort(&keys);
-       for (i = 0; i < keys.nr; i++) {
-               const char *var = keys.items[i].string;
-               const char *wildcard, *tag, *cut;
-
-               if (for_human) {
-                       puts(var);
-                       continue;
-               }
-
-               wildcard = strchr(var, '*');
-               tag = strchr(var, '<');
-
-               if (!wildcard && !tag) {
-                       puts(var);
-                       continue;
-               }
-
-               if (wildcard && !tag)
-                       cut = wildcard;
-               else if (!wildcard && tag)
-                       cut = tag;
-               else
-                       cut = wildcard < tag ? wildcard : tag;
-
-               /*
-                * We may produce duplicates, but that's up to
-                * git-completion.bash to handle
-                */
-               printf("%.*s\n", (int)(cut - var), var);
-       }
-       string_list_clear(&keys, 0);
-}
-
 static int get_alias(const char *var, const char *value, void *data)
 {
        struct string_list *list = data;
@@ -555,12 +472,26 @@ int is_in_cmdlist(struct cmdnames *c, const char *s)
 static int autocorrect;
 static struct cmdnames aliases;
 
+#define AUTOCORRECT_NEVER (-2)
+#define AUTOCORRECT_IMMEDIATELY (-1)
+
 static int git_unknown_cmd_config(const char *var, const char *value, void *cb)
 {
        const char *p;
 
-       if (!strcmp(var, "help.autocorrect"))
-               autocorrect = git_config_int(var,value);
+       if (!strcmp(var, "help.autocorrect")) {
+               if (!value)
+                       return config_error_nonbool(var);
+               if (!strcmp(value, "never")) {
+                       autocorrect = AUTOCORRECT_NEVER;
+               } else if (!strcmp(value, "immediate")) {
+                       autocorrect = AUTOCORRECT_IMMEDIATELY;
+               } else {
+                       int v = git_config_int(var, value);
+                       autocorrect = (v < 0)
+                               ? AUTOCORRECT_IMMEDIATELY : v;
+               }
+       }
        /* Also use aliases for command lookup */
        if (skip_prefix(var, "alias.", &p))
                add_cmdname(&aliases, p, strlen(p));
@@ -608,6 +539,11 @@ const char *help_unknown_cmd(const char *cmd)
 
        read_early_config(git_unknown_cmd_config, NULL);
 
+       if (autocorrect == AUTOCORRECT_NEVER) {
+               fprintf_ln(stderr, _("git: '%s' is not a git command. See 'git --help'."), cmd);
+               exit(1);
+       }
+
        load_command_list("git-", &main_cmds, &other_cmds);
 
        add_cmd_list(&main_cmds, &aliases);
@@ -677,7 +613,7 @@ const char *help_unknown_cmd(const char *cmd)
                           _("WARNING: You called a Git command named '%s', "
                             "which does not exist."),
                           cmd);
-               if (autocorrect < 0)
+               if (autocorrect == AUTOCORRECT_IMMEDIATELY)
                        fprintf_ln(stderr,
                                   _("Continuing under the assumption that "
                                     "you meant '%s'."),
@@ -707,8 +643,33 @@ const char *help_unknown_cmd(const char *cmd)
        exit(1);
 }
 
+void get_version_info(struct strbuf *buf, int show_build_options)
+{
+       /*
+        * 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.
+        */
+       strbuf_addf(buf, "git version %s\n", git_version_string);
+
+       if (show_build_options) {
+               strbuf_addf(buf, "cpu: %s\n", GIT_HOST_CPU);
+               if (git_built_from_commit_string[0])
+                       strbuf_addf(buf, "built from commit: %s\n",
+                              git_built_from_commit_string);
+               else
+                       strbuf_addstr(buf, "no commit associated with this build\n");
+               strbuf_addf(buf, "sizeof-long: %d\n", (int)sizeof(long));
+               strbuf_addf(buf, "sizeof-size_t: %d\n", (int)sizeof(size_t));
+               strbuf_addf(buf, "shell-path: %s\n", SHELL_PATH);
+               /* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
+       }
+}
+
 int cmd_version(int argc, const char **argv, const char *prefix)
 {
+       struct strbuf buf = STRBUF_INIT;
        int build_options = 0;
        const char * const usage[] = {
                N_("git version [<options>]"),
@@ -722,25 +683,11 @@ int cmd_version(int argc, const char **argv, const char *prefix)
 
        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);
+       get_version_info(&buf, build_options);
+       printf("%s", buf.buf);
+
+       strbuf_release(&buf);
 
-       if (build_options) {
-               printf("cpu: %s\n", GIT_HOST_CPU);
-               if (git_built_from_commit_string[0])
-                       printf("built from commit: %s\n",
-                              git_built_from_commit_string);
-               else
-                       printf("no commit associated with this build\n");
-               printf("sizeof-long: %d\n", (int)sizeof(long));
-               printf("sizeof-size_t: %d\n", (int)sizeof(size_t));
-               /* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
-       }
        return 0;
 }
 
@@ -754,19 +701,19 @@ static int append_similar_ref(const char *refname, const struct object_id *oid,
 {
        struct similar_ref_cb *cb = (struct similar_ref_cb *)(cb_data);
        char *branch = strrchr(refname, '/') + 1;
-       const char *remote;
 
        /* A remote branch of the same name is deemed similar */
-       if (skip_prefix(refname, "refs/remotes/", &remote) &&
+       if (starts_with(refname, "refs/remotes/") &&
            !strcmp(branch, cb->base_ref))
-               string_list_append(cb->similar_refs, remote);
+               string_list_append_nodup(cb->similar_refs,
+                                        shorten_unambiguous_ref(refname, 1));
        return 0;
 }
 
 static struct string_list guess_refs(const char *ref)
 {
        struct similar_ref_cb ref_cb;
-       struct string_list similar_refs = STRING_LIST_INIT_NODUP;
+       struct string_list similar_refs = STRING_LIST_INIT_DUP;
 
        ref_cb.base_ref = ref;
        ref_cb.similar_refs = &similar_refs;
@@ -774,7 +721,8 @@ static struct string_list guess_refs(const char *ref)
        return similar_refs;
 }
 
-void help_unknown_ref(const char *ref, const char *cmd, const char *error)
+NORETURN void help_unknown_ref(const char *ref, const char *cmd,
+                              const char *error)
 {
        int i;
        struct string_list suggested_refs = guess_refs(ref);