]> git.ipfire.org Git - thirdparty/git.git/blobdiff - git.c
Sync with maint
[thirdparty/git.git] / git.c
diff --git a/git.c b/git.c
index c2f48d53dd4aaba0752aa5f2e6633242d320b248..7be7ad34bd053884ec48923706e70c81719a8660 100644 (file)
--- a/git.c
+++ b/git.c
@@ -33,7 +33,8 @@ const char git_usage_string[] =
 const char git_more_info_string[] =
        N_("'git help -a' and 'git help -g' list available subcommands and some\n"
           "concept guides. See 'git help <command>' or 'git help <concept>'\n"
-          "to read about a specific subcommand or concept.");
+          "to read about a specific subcommand or concept.\n"
+          "See 'git help git' for an overview of the system.");
 
 static int use_pager = -1;
 
@@ -62,6 +63,13 @@ static int list_cmds(const char *spec)
 {
        struct string_list list = STRING_LIST_INIT_DUP;
        int i;
+       int nongit;
+
+       /*
+       * Set up the repository so we can pick up any repo-level config (like
+       * completion.commands).
+       */
+       setup_git_directory_gently(&nongit);
 
        while (*spec) {
                const char *sep = strchrnul(spec, ',');
@@ -98,7 +106,8 @@ static int list_cmds(const char *spec)
        return 0;
 }
 
-static void commit_pager_choice(void) {
+static void commit_pager_choice(void)
+{
        switch (use_pager) {
        case 0:
                setenv("GIT_PAGER", "cat", 1);
@@ -146,16 +155,20 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
                                git_set_exec_path(cmd + 1);
                        else {
                                puts(git_exec_path());
+                               trace2_cmd_name("_query_");
                                exit(0);
                        }
                } else if (!strcmp(cmd, "--html-path")) {
                        puts(system_path(GIT_HTML_PATH));
+                       trace2_cmd_name("_query_");
                        exit(0);
                } else if (!strcmp(cmd, "--man-path")) {
                        puts(system_path(GIT_MAN_PATH));
+                       trace2_cmd_name("_query_");
                        exit(0);
                } else if (!strcmp(cmd, "--info-path")) {
                        puts(system_path(GIT_INFO_PATH));
+                       trace2_cmd_name("_query_");
                        exit(0);
                } else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
                        use_pager = 1;
@@ -164,7 +177,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
                        if (envchanged)
                                *envchanged = 1;
                } else if (!strcmp(cmd, "--no-replace-objects")) {
-                       check_replace_refs = 0;
+                       read_replace_refs = 0;
                        setenv(NO_REPLACE_OBJECTS_ENVIRONMENT, "1", 1);
                        if (envchanged)
                                *envchanged = 1;
@@ -267,7 +280,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
                } else if (!strcmp(cmd, "--shallow-file")) {
                        (*argv)++;
                        (*argc)--;
-                       set_alternate_shallow_file((*argv)[0], 1);
+                       set_alternate_shallow_file(the_repository, (*argv)[0], 1);
                        if (envchanged)
                                *envchanged = 1;
                } else if (!strcmp(cmd, "-C")) {
@@ -284,6 +297,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
                        (*argv)++;
                        (*argc)--;
                } else if (skip_prefix(cmd, "--list-cmds=", &cmd)) {
+                       trace2_cmd_name("_query_");
                        if (!strcmp(cmd, "parseopt")) {
                                struct string_list list = STRING_LIST_INIT_DUP;
                                int i;
@@ -318,6 +332,9 @@ static int handle_alias(int *argcp, const char ***argv)
        alias_command = (*argv)[0];
        alias_string = alias_lookup(alias_command);
        if (alias_string) {
+               if (*argcp > 1 && !strcmp((*argv)[1], "-h"))
+                       fprintf_ln(stderr, _("'%s' is aliased to '%s'"),
+                                  alias_command, alias_string);
                if (alias_string[0] == '!') {
                        struct child_process child = CHILD_PROCESS_INIT;
                        int nongit_ok;
@@ -328,34 +345,38 @@ static int handle_alias(int *argcp, const char ***argv)
                        commit_pager_choice();
 
                        child.use_shell = 1;
+                       child.trace2_child_class = "shell_alias";
                        argv_array_push(&child.args, alias_string + 1);
                        argv_array_pushv(&child.args, (*argv) + 1);
 
+                       trace2_cmd_alias(alias_command, child.args.argv);
+                       trace2_cmd_list_config();
+                       trace2_cmd_name("_run_shell_alias_");
+
                        ret = run_command(&child);
                        if (ret >= 0)   /* normal exit */
                                exit(ret);
 
-                       die_errno("while expanding alias '%s': '%s'",
-                           alias_command, alias_string + 1);
+                       die_errno(_("while expanding alias '%s': '%s'"),
+                                 alias_command, alias_string + 1);
                }
                count = split_cmdline(alias_string, &new_argv);
                if (count < 0)
-                       die("Bad alias.%s string: %s", alias_command,
-                           split_cmdline_strerror(count));
+                       die(_("bad alias.%s string: %s"), alias_command,
+                           _(split_cmdline_strerror(count)));
                option_count = handle_options(&new_argv, &count, &envchanged);
                if (envchanged)
-                       die("alias '%s' changes environment variables.\n"
-                                "You can use '!git' in the alias to do this",
-                                alias_command);
-               memmove(new_argv - option_count, new_argv,
-                               count * sizeof(char *));
+                       die(_("alias '%s' changes environment variables.\n"
+                             "You can use '!git' in the alias to do this"),
+                           alias_command);
+               MOVE_ARRAY(new_argv - option_count, new_argv, count);
                new_argv -= option_count;
 
                if (count < 1)
-                       die("empty alias for %s", alias_command);
+                       die(_("empty alias for %s"), alias_command);
 
                if (!strcmp(alias_command, new_argv[0]))
-                       die("recursive alias: %s", alias_command);
+                       die(_("recursive alias: %s"), alias_command);
 
                trace_argv_printf(new_argv,
                                  "trace: alias expansion: %s =>",
@@ -363,7 +384,10 @@ static int handle_alias(int *argcp, const char ***argv)
 
                REALLOC_ARRAY(new_argv, count + *argcp);
                /* insert after command name */
-               memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
+               COPY_ARRAY(new_argv + count, *argv + 1, *argcp);
+
+               trace2_cmd_alias(alias_command, new_argv);
+               trace2_cmd_list_config();
 
                *argv = new_argv;
                *argcp += count - 1;
@@ -406,15 +430,20 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
 
        if (!help && get_super_prefix()) {
                if (!(p->option & SUPPORT_SUPER_PREFIX))
-                       die("%s doesn't support --super-prefix", p->cmd);
+                       die(_("%s doesn't support --super-prefix"), p->cmd);
        }
 
        if (!help && p->option & NEED_WORK_TREE)
                setup_work_tree();
 
        trace_argv_printf(argv, "trace: built-in: git");
+       trace2_cmd_name(p->cmd);
+       trace2_cmd_list_config();
 
+       validate_cache_entries(the_repository->index);
        status = p->fn(argc, argv, prefix);
+       validate_cache_entries(the_repository->index);
+
        if (status)
                return status;
 
@@ -427,11 +456,11 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
 
        /* Check for ENOSPC and EIO errors.. */
        if (fflush(stdout))
-               die_errno("write failure on standard output");
+               die_errno(_("write failure on standard output"));
        if (ferror(stdout))
-               die("unknown write failure on standard output");
+               die(_("unknown write failure on standard output"));
        if (fclose(stdout))
-               die_errno("close failed on standard output");
+               die_errno(_("close failed on standard output"));
        return 0;
 }
 
@@ -469,7 +498,8 @@ static struct cmd_struct commands[] = {
        { "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT },
        { "diff-index", cmd_diff_index, RUN_SETUP | NO_PARSEOPT },
        { "diff-tree", cmd_diff_tree, RUN_SETUP | NO_PARSEOPT },
-       { "difftool", cmd_difftool, RUN_SETUP | NEED_WORK_TREE },
+       { "difftool", cmd_difftool, RUN_SETUP_GENTLY },
+       { "env--helper", cmd_env__helper },
        { "fast-export", cmd_fast_export, RUN_SETUP },
        { "fetch", cmd_fetch, RUN_SETUP },
        { "fetch-pack", cmd_fetch_pack, RUN_SETUP | NO_PARSEOPT },
@@ -505,6 +535,7 @@ static struct cmd_struct commands[] = {
        { "merge-tree", cmd_merge_tree, RUN_SETUP | NO_PARSEOPT },
        { "mktag", cmd_mktag, RUN_SETUP | NO_PARSEOPT },
        { "mktree", cmd_mktree, RUN_SETUP },
+       { "multi-pack-index", cmd_multi_pack_index, RUN_SETUP_GENTLY },
        { "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
        { "name-rev", cmd_name_rev, RUN_SETUP },
        { "notes", cmd_notes, RUN_SETUP },
@@ -517,8 +548,10 @@ static struct cmd_struct commands[] = {
        { "prune-packed", cmd_prune_packed, RUN_SETUP },
        { "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
        { "push", cmd_push, RUN_SETUP },
+       { "range-diff", cmd_range_diff, RUN_SETUP | USE_PAGER },
        { "read-tree", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},
-       { "rebase--helper", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },
+       { "rebase", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },
+       { "rebase--interactive", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },
        { "receive-pack", cmd_receive_pack },
        { "reflog", cmd_reflog, RUN_SETUP },
        { "remote", cmd_remote, RUN_SETUP },
@@ -528,20 +561,29 @@ static struct cmd_struct commands[] = {
        { "replace", cmd_replace, RUN_SETUP },
        { "rerere", cmd_rerere, RUN_SETUP },
        { "reset", cmd_reset, RUN_SETUP },
+       { "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
        { "rev-list", cmd_rev_list, RUN_SETUP | NO_PARSEOPT },
        { "rev-parse", cmd_rev_parse, NO_PARSEOPT },
        { "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
        { "rm", cmd_rm, RUN_SETUP },
        { "send-pack", cmd_send_pack, RUN_SETUP },
-       { "serve", cmd_serve, RUN_SETUP },
        { "shortlog", cmd_shortlog, RUN_SETUP_GENTLY | USE_PAGER },
        { "show", cmd_show, RUN_SETUP },
        { "show-branch", cmd_show_branch, RUN_SETUP },
+       { "show-index", cmd_show_index },
        { "show-ref", cmd_show_ref, RUN_SETUP },
+       { "sparse-checkout", cmd_sparse_checkout, RUN_SETUP | NEED_WORK_TREE },
        { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
+       /*
+        * NEEDSWORK: Until the builtin stash is thoroughly robust and no
+        * longer needs redirection to the stash shell script this is kept as
+        * is, then should be changed to RUN_SETUP | NEED_WORK_TREE
+        */
+       { "stash", cmd_stash },
        { "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
        { "stripspace", cmd_stripspace },
        { "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX | NO_PARSEOPT },
+       { "switch", cmd_switch, RUN_SETUP | NEED_WORK_TREE },
        { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
        { "tag", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },
        { "unpack-file", cmd_unpack_file, RUN_SETUP | NO_PARSEOPT },
@@ -639,7 +681,7 @@ static void execv_dashed_external(const char **argv)
        int status;
 
        if (get_super_prefix())
-               die("%s doesn't support --super-prefix", argv[0]);
+               die(_("%s doesn't support --super-prefix"), argv[0]);
 
        if (use_pager == -1 && !is_builtin(argv[0]))
                use_pager = check_pager_config(argv[0]);
@@ -650,7 +692,14 @@ static void execv_dashed_external(const char **argv)
        cmd.clean_on_exit = 1;
        cmd.wait_after_clean = 1;
        cmd.silent_exec_failure = 1;
+       cmd.trace2_child_class = "dashed";
+
+       trace2_cmd_name("_run_dashed_");
 
+       /*
+        * The code in run_command() logs trace2 child_start/child_exit
+        * events, so we do not need to report exec/exec_result events here.
+        */
        trace_argv_printf(cmd.args.argv, "trace: exec:");
 
        /*
@@ -660,6 +709,12 @@ static void execv_dashed_external(const char **argv)
         * the program.
         */
        status = run_command(&cmd);
+
+       /*
+        * If the child process ran and we are now going to exit, emit a
+        * generic string as our trace2 command verb to indicate that we
+        * launched a dashed command.
+        */
        if (status >= 0)
                exit(status);
        else if (errno != ENOENT)
@@ -669,6 +724,8 @@ static void execv_dashed_external(const char **argv)
 static int run_argv(int *argcp, const char ***argv)
 {
        int done_alias = 0;
+       struct string_list cmd_list = STRING_LIST_INIT_NODUP;
+       struct string_list_item *seen;
 
        while (1) {
                /*
@@ -682,21 +739,75 @@ static int run_argv(int *argcp, const char ***argv)
                 */
                if (!done_alias)
                        handle_builtin(*argcp, *argv);
+               else if (get_builtin(**argv)) {
+                       struct argv_array args = ARGV_ARRAY_INIT;
+                       int i;
+
+                       /*
+                        * The current process is committed to launching a
+                        * child process to run the command named in (**argv)
+                        * and exiting.  Log a generic string as the trace2
+                        * command verb to indicate this.  Note that the child
+                        * process will log the actual verb when it runs.
+                        */
+                       trace2_cmd_name("_run_git_alias_");
+
+                       if (get_super_prefix())
+                               die("%s doesn't support --super-prefix", **argv);
+
+                       commit_pager_choice();
+
+                       argv_array_push(&args, "git");
+                       for (i = 0; i < *argcp; i++)
+                               argv_array_push(&args, (*argv)[i]);
+
+                       trace_argv_printf(args.argv, "trace: exec:");
+
+                       /*
+                        * if we fail because the command is not found, it is
+                        * OK to return. Otherwise, we just pass along the status code.
+                        */
+                       i = run_command_v_opt_tr2(args.argv, RUN_SILENT_EXEC_FAILURE |
+                                                 RUN_CLEAN_ON_EXIT, "git_alias");
+                       if (i >= 0 || errno != ENOENT)
+                               exit(i);
+                       die("could not execute builtin %s", **argv);
+               }
 
                /* .. then try the external ones */
                execv_dashed_external(*argv);
 
-               /* It could be an alias -- this works around the insanity
+               seen = unsorted_string_list_lookup(&cmd_list, *argv[0]);
+               if (seen) {
+                       int i;
+                       struct strbuf sb = STRBUF_INIT;
+                       for (i = 0; i < cmd_list.nr; i++) {
+                               struct string_list_item *item = &cmd_list.items[i];
+
+                               strbuf_addf(&sb, "\n  %s", item->string);
+                               if (item == seen)
+                                       strbuf_addstr(&sb, " <==");
+                               else if (i == cmd_list.nr - 1)
+                                       strbuf_addstr(&sb, " ==>");
+                       }
+                       die(_("alias loop detected: expansion of '%s' does"
+                             " not terminate:%s"), cmd_list.items[0].string, sb.buf);
+               }
+
+               string_list_append(&cmd_list, *argv[0]);
+
+               /*
+                * It could be an alias -- this works around the insanity
                 * of overriding "git log" with "git show" by having
                 * alias.log = show
                 */
-               if (done_alias)
-                       break;
                if (!handle_alias(argcp, argv))
                        break;
                done_alias = 1;
        }
 
+       string_list_clear(&cmd_list, 0);
+
        return done_alias;
 }
 
@@ -729,7 +840,7 @@ int cmd_main(int argc, const char **argv)
        if (skip_prefix(cmd, "git-", &cmd)) {
                argv[0] = cmd;
                handle_builtin(argc, argv);
-               die("cannot handle %s as a builtin", cmd);
+               die(_("cannot handle %s as a builtin"), cmd);
        }
 
        /* Look for flags.. */
@@ -742,7 +853,7 @@ int cmd_main(int argc, const char **argv)
        } else {
                /* The user didn't specify a command; give them help */
                commit_pager_choice();
-               printf("usage: %s\n\n", git_usage_string);
+               printf(_("usage: %s\n\n"), git_usage_string);
                list_common_cmds_help();
                printf("\n%s\n", _(git_more_info_string));
                exit(1);