summaryrefslogtreecommitdiff
path: root/git.c
diff options
context:
space:
mode:
Diffstat (limited to 'git.c')
-rw-r--r--git.c258
1 files changed, 147 insertions, 111 deletions
diff --git a/git.c b/git.c
index 2a9752c91c..c5fad56813 100644
--- a/git.c
+++ b/git.c
@@ -28,6 +28,7 @@
#define NEED_WORK_TREE (1<<3)
#define DELAY_PAGER_CONFIG (1<<4)
#define NO_PARSEOPT (1<<5) /* parse-options is not used */
+#define DEPRECATED (1<<6)
struct cmd_struct {
const char *cmd;
@@ -51,11 +52,13 @@ const char git_more_info_string[] =
static int use_pager = -1;
-static void list_builtins(struct string_list *list, unsigned int exclude_option);
+static void list_builtins(struct string_list *list,
+ unsigned int include_option,
+ unsigned int exclude_option);
static void exclude_helpers_from_list(struct string_list *list)
{
- int i = 0;
+ size_t i = 0;
while (i < list->nr) {
if (strstr(list->items[i].string, "--"))
@@ -75,7 +78,6 @@ static int match_token(const char *spec, int len, const char *token)
static int list_cmds(const char *spec)
{
struct string_list list = STRING_LIST_INIT_DUP;
- int i;
int nongit;
/*
@@ -89,7 +91,7 @@ static int list_cmds(const char *spec)
int len = sep - spec;
if (match_token(spec, len, "builtins"))
- list_builtins(&list, 0);
+ list_builtins(&list, 0, 0);
else if (match_token(spec, len, "main"))
list_all_main_cmds(&list);
else if (match_token(spec, len, "others"))
@@ -100,6 +102,8 @@ static int list_cmds(const char *spec)
list_aliases(&list);
else if (match_token(spec, len, "config"))
list_cmds_by_config(&list);
+ else if (match_token(spec, len, "deprecated"))
+ list_builtins(&list, DEPRECATED, 0);
else if (len > 5 && !strncmp(spec, "list-", 5)) {
struct strbuf sb = STRBUF_INIT;
@@ -113,7 +117,7 @@ static int list_cmds(const char *spec)
if (*spec == ',')
spec++;
}
- for (i = 0; i < list.nr; i++)
+ for (size_t i = 0; i < list.nr; i++)
puts(list.items[i].string);
string_list_clear(&list, 0);
return 0;
@@ -126,7 +130,7 @@ static void commit_pager_choice(void)
setenv("GIT_PAGER", "cat", 1);
break;
case 1:
- setup_pager();
+ setup_pager(the_repository);
break;
default:
break;
@@ -137,7 +141,7 @@ void setup_auto_pager(const char *cmd, int def)
{
if (use_pager != -1 || pager_in_use())
return;
- use_pager = check_pager_config(cmd);
+ use_pager = check_pager_config(the_repository, cmd);
if (use_pager == -1)
use_pager = def;
commit_pager_choice();
@@ -322,10 +326,9 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
trace2_cmd_name("_query_");
if (!strcmp(cmd, "parseopt")) {
struct string_list list = STRING_LIST_INIT_DUP;
- int i;
- list_builtins(&list, NO_PARSEOPT);
- for (i = 0; i < list.nr; i++)
+ list_builtins(&list, 0, NO_PARSEOPT);
+ for (size_t i = 0; i < list.nr; i++)
printf("%s ", list.items[i].string);
string_list_clear(&list, 0);
exit(0);
@@ -362,7 +365,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
return (*argv) - orig_argv;
}
-static int handle_alias(int *argcp, const char ***argv)
+static int handle_alias(struct strvec *args, struct string_list *expanded_aliases)
{
int envchanged = 0, ret = 0, saved_errno = errno;
int count, option_count;
@@ -370,10 +373,12 @@ static int handle_alias(int *argcp, const char ***argv)
const char *alias_command;
char *alias_string;
- alias_command = (*argv)[0];
+ alias_command = args->v[0];
alias_string = alias_lookup(alias_command);
if (alias_string) {
- if (*argcp > 1 && !strcmp((*argv)[1], "-h"))
+ struct string_list_item *seen;
+
+ if (args->nr == 2 && !strcmp(args->v[1], "-h"))
fprintf_ln(stderr, _("'%s' is aliased to '%s'"),
alias_command, alias_string);
if (alias_string[0] == '!') {
@@ -390,7 +395,7 @@ static int handle_alias(int *argcp, const char ***argv)
child.wait_after_clean = 1;
child.trace2_child_class = "shell_alias";
strvec_push(&child.args, alias_string + 1);
- strvec_pushv(&child.args, (*argv) + 1);
+ strvec_pushv(&child.args, args->v + 1);
trace2_cmd_alias(alias_command, child.args.v);
trace2_cmd_name("_run_shell_alias_");
@@ -420,18 +425,35 @@ static int handle_alias(int *argcp, const char ***argv)
if (!strcmp(alias_command, new_argv[0]))
die(_("recursive alias: %s"), alias_command);
+ string_list_append(expanded_aliases, alias_command);
+ seen = unsorted_string_list_lookup(expanded_aliases,
+ new_argv[0]);
+
+ if (seen) {
+ struct strbuf sb = STRBUF_INIT;
+ for (size_t i = 0; i < expanded_aliases->nr; i++) {
+ struct string_list_item *item = &expanded_aliases->items[i];
+
+ strbuf_addf(&sb, "\n %s", item->string);
+ if (item == seen)
+ strbuf_addstr(&sb, " <==");
+ else if (i == expanded_aliases->nr - 1)
+ strbuf_addstr(&sb, " ==>");
+ }
+ die(_("alias loop detected: expansion of '%s' does"
+ " not terminate:%s"), expanded_aliases->items[0].string, sb.buf);
+ }
+
trace_argv_printf(new_argv,
"trace: alias expansion: %s =>",
alias_command);
-
- REALLOC_ARRAY(new_argv, count + *argcp);
- /* insert after command name */
- COPY_ARRAY(new_argv + count, *argv + 1, *argcp);
-
trace2_cmd_alias(alias_command, new_argv);
- *argv = new_argv;
- *argcp += count - 1;
+ /* Replace the alias with the new arguments. */
+ strvec_splice(args, 0, 1, new_argv, count);
+
+ free(alias_string);
+ free(new_argv);
ret = 1;
}
@@ -444,20 +466,21 @@ static int handle_alias(int *argcp, const char ***argv)
static int run_builtin(struct cmd_struct *p, int argc, const char **argv, struct repository *repo)
{
int status, help;
+ int no_repo = 1;
struct stat st;
const char *prefix;
int run_setup = (p->option & (RUN_SETUP | RUN_SETUP_GENTLY));
- help = argc == 2 && !strcmp(argv[1], "-h");
+ help = argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help-all"));
if (help && (run_setup & RUN_SETUP))
/* demote to GENTLY to allow 'git cmd -h' outside repo */
run_setup = RUN_SETUP_GENTLY;
if (run_setup & RUN_SETUP) {
prefix = setup_git_directory();
+ no_repo = 0;
} else if (run_setup & RUN_SETUP_GENTLY) {
- int nongit_ok;
- prefix = setup_git_directory_gently(&nongit_ok);
+ prefix = setup_git_directory_gently(&no_repo);
} else {
prefix = NULL;
}
@@ -465,12 +488,12 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv, struct
precompose_argv_prefix(argc, argv, NULL);
if (use_pager == -1 && run_setup &&
!(p->option & DELAY_PAGER_CONFIG))
- use_pager = check_pager_config(p->cmd);
+ use_pager = check_pager_config(repo, p->cmd);
if (use_pager == -1 && p->option & USE_PAGER)
use_pager = 1;
if (run_setup && startup_info->have_repository)
/* get_git_dir() may set up repo, avoid that */
- trace_repo_setup();
+ trace_repo_setup(repo);
commit_pager_choice();
if (!help && p->option & NEED_WORK_TREE)
@@ -480,7 +503,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv, struct
trace2_cmd_name(p->cmd);
validate_cache_entries(repo->index);
- status = p->fn(argc, argv, prefix, (p->option & RUN_SETUP)? repo : NULL);
+ status = p->fn(argc, argv, prefix, no_repo ? NULL : repo);
validate_cache_entries(repo->index);
if (status)
@@ -509,6 +532,7 @@ static struct cmd_struct commands[] = {
{ "annotate", cmd_annotate, RUN_SETUP },
{ "apply", cmd_apply, RUN_SETUP_GENTLY },
{ "archive", cmd_archive, RUN_SETUP_GENTLY },
+ { "backfill", cmd_backfill, RUN_SETUP },
{ "bisect", cmd_bisect, RUN_SETUP },
{ "blame", cmd_blame, RUN_SETUP },
{ "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },
@@ -543,6 +567,7 @@ static struct cmd_struct commands[] = {
{ "diff", cmd_diff, NO_PARSEOPT },
{ "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT },
{ "diff-index", cmd_diff_index, RUN_SETUP | NO_PARSEOPT },
+ { "diff-pairs", cmd_diff_pairs, RUN_SETUP | NO_PARSEOPT },
{ "diff-tree", cmd_diff_tree, RUN_SETUP | NO_PARSEOPT },
{ "difftool", cmd_difftool, RUN_SETUP_GENTLY },
{ "fast-export", cmd_fast_export, RUN_SETUP },
@@ -566,6 +591,7 @@ static struct cmd_struct commands[] = {
{ "init", cmd_init_db },
{ "init-db", cmd_init_db },
{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY },
+ { "last-modified", cmd_last_modified, RUN_SETUP },
{ "log", cmd_log, RUN_SETUP },
{ "ls-files", cmd_ls_files, RUN_SETUP },
{ "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
@@ -590,7 +616,9 @@ static struct cmd_struct commands[] = {
{ "name-rev", cmd_name_rev, RUN_SETUP },
{ "notes", cmd_notes, RUN_SETUP },
{ "pack-objects", cmd_pack_objects, RUN_SETUP },
- { "pack-redundant", cmd_pack_redundant, RUN_SETUP | NO_PARSEOPT },
+#ifndef WITH_BREAKING_CHANGES
+ { "pack-redundant", cmd_pack_redundant, RUN_SETUP | NO_PARSEOPT | DEPRECATED },
+#endif
{ "pack-refs", cmd_pack_refs, RUN_SETUP },
{ "patch-id", cmd_patch_id, RUN_SETUP_GENTLY | NO_PARSEOPT },
{ "pickaxe", cmd_blame, RUN_SETUP },
@@ -610,6 +638,7 @@ static struct cmd_struct commands[] = {
{ "repack", cmd_repack, RUN_SETUP },
{ "replace", cmd_replace, RUN_SETUP },
{ "replay", cmd_replay, RUN_SETUP },
+ { "repo", cmd_repo, RUN_SETUP },
{ "rerere", cmd_rerere, RUN_SETUP },
{ "reset", cmd_reset, RUN_SETUP },
{ "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
@@ -645,15 +674,16 @@ static struct cmd_struct commands[] = {
{ "verify-pack", cmd_verify_pack },
{ "verify-tag", cmd_verify_tag, RUN_SETUP },
{ "version", cmd_version },
- { "whatchanged", cmd_whatchanged, RUN_SETUP },
+#ifndef WITH_BREAKING_CHANGES
+ { "whatchanged", cmd_whatchanged, RUN_SETUP | DEPRECATED },
+#endif
{ "worktree", cmd_worktree, RUN_SETUP },
{ "write-tree", cmd_write_tree, RUN_SETUP },
};
static struct cmd_struct *get_builtin(const char *s)
{
- int i;
- for (i = 0; i < ARRAY_SIZE(commands); i++) {
+ for (size_t i = 0; i < ARRAY_SIZE(commands); i++) {
struct cmd_struct *p = commands + i;
if (!strcmp(s, p->cmd))
return p;
@@ -666,12 +696,16 @@ int is_builtin(const char *s)
return !!get_builtin(s);
}
-static void list_builtins(struct string_list *out, unsigned int exclude_option)
+static void list_builtins(struct string_list *out,
+ unsigned int include_option,
+ unsigned int exclude_option)
{
- int i;
- for (i = 0; i < ARRAY_SIZE(commands); i++) {
- if (exclude_option &&
- (commands[i].option & exclude_option))
+ if (include_option && exclude_option)
+ BUG("'include_option' and 'exclude_option' are mutually exclusive");
+ for (size_t i = 0; i < ARRAY_SIZE(commands); i++) {
+ if (include_option && !(commands[i].option & include_option))
+ continue;
+ if (exclude_option && (commands[i].option & exclude_option))
continue;
string_list_append(out, commands[i].cmd);
}
@@ -680,7 +714,6 @@ static void list_builtins(struct string_list *out, unsigned int exclude_option)
void load_builtin_commands(const char *prefix, struct cmdnames *cmds)
{
const char *name;
- int i;
/*
* Callers can ask for a subset of the commands based on a certain
@@ -691,69 +724,63 @@ void load_builtin_commands(const char *prefix, struct cmdnames *cmds)
if (!skip_prefix(prefix, "git-", &prefix))
BUG("prefix '%s' must start with 'git-'", prefix);
- for (i = 0; i < ARRAY_SIZE(commands); i++)
+ for (size_t i = 0; i < ARRAY_SIZE(commands); i++)
if (skip_prefix(commands[i].cmd, prefix, &name))
add_cmdname(cmds, name, strlen(name));
}
#ifdef STRIP_EXTENSION
-static void strip_extension(const char **argv)
+static void strip_extension(struct strvec *args)
{
size_t len;
- if (strip_suffix(argv[0], STRIP_EXTENSION, &len))
- argv[0] = xmemdupz(argv[0], len);
+ if (strip_suffix(args->v[0], STRIP_EXTENSION, &len)) {
+ char *stripped = xmemdupz(args->v[0], len);
+ strvec_replace(args, 0, stripped);
+ free(stripped);
+ }
}
#else
#define strip_extension(cmd)
#endif
-static void handle_builtin(int argc, const char **argv)
+static void handle_builtin(struct strvec *args)
{
- struct strvec args = STRVEC_INIT;
- const char **argv_copy = NULL;
const char *cmd;
struct cmd_struct *builtin;
- strip_extension(argv);
- cmd = argv[0];
+ strip_extension(args);
+ cmd = args->v[0];
/* Turn "git cmd --help" into "git help --exclude-guides cmd" */
- if (argc > 1 && !strcmp(argv[1], "--help")) {
- int i;
-
- argv[1] = argv[0];
- argv[0] = cmd = "help";
-
- for (i = 0; i < argc; i++) {
- strvec_push(&args, argv[i]);
- if (!i)
- strvec_push(&args, "--exclude-guides");
- }
+ if (args->nr > 1 && !strcmp(args->v[1], "--help")) {
+ const char *exclude_guides_arg[] = { "--exclude-guides" };
+
+ strvec_replace(args, 1, args->v[0]);
+ strvec_replace(args, 0, "help");
+ cmd = "help";
+ strvec_splice(args, 2, 0, exclude_guides_arg,
+ ARRAY_SIZE(exclude_guides_arg));
+ }
- argc++;
+ builtin = get_builtin(cmd);
+ if (builtin) {
+ const char **argv_copy = NULL;
+ int ret;
/*
* `run_builtin()` will modify the argv array, so we need to
* create a shallow copy such that we can free all of its
* strings.
*/
- CALLOC_ARRAY(argv_copy, argc + 1);
- COPY_ARRAY(argv_copy, args.v, argc);
-
- argv = argv_copy;
- }
+ if (args->nr)
+ DUP_ARRAY(argv_copy, args->v, args->nr + 1);
- builtin = get_builtin(cmd);
- if (builtin) {
- int ret = run_builtin(builtin, argc, argv, the_repository);
- strvec_clear(&args);
+ ret = run_builtin(builtin, args->nr, argv_copy, the_repository);
+ strvec_clear(args);
free(argv_copy);
exit(ret);
}
-
- strvec_clear(&args);
- free(argv_copy);
}
static void execv_dashed_external(const char **argv)
@@ -762,7 +789,7 @@ static void execv_dashed_external(const char **argv)
int status;
if (use_pager == -1 && !is_builtin(argv[0]))
- use_pager = check_pager_config(argv[0]);
+ use_pager = check_pager_config(the_repository, argv[0]);
commit_pager_choice();
strvec_pushf(&cmd.args, "git-%s", argv[0]);
@@ -799,14 +826,30 @@ static void execv_dashed_external(const char **argv)
exit(128);
}
-static int run_argv(int *argcp, const char ***argv)
+static int is_deprecated_command(const char *cmd)
+{
+ struct cmd_struct *builtin = get_builtin(cmd);
+ return builtin && (builtin->option & DEPRECATED);
+}
+
+static int run_argv(struct strvec *args)
{
int done_alias = 0;
- struct string_list cmd_list = STRING_LIST_INIT_NODUP;
- struct string_list_item *seen;
+ struct string_list expanded_aliases = STRING_LIST_INIT_DUP;
while (1) {
/*
+ * Allow deprecated commands to be overridden by aliases. This
+ * creates a seamless path forward for people who want to keep
+ * using the name after it is gone, but want to skip the
+ * deprecation complaint in the meantime.
+ */
+ if (is_deprecated_command(args->v[0]) &&
+ handle_alias(args, &expanded_aliases)) {
+ done_alias = 1;
+ continue;
+ }
+ /*
* If we tried alias and futzed with our environment,
* it no longer is safe to invoke builtins directly in
* general. We have to spawn them as dashed externals.
@@ -816,10 +859,10 @@ static int run_argv(int *argcp, const char ***argv)
* process.
*/
if (!done_alias)
- handle_builtin(*argcp, *argv);
- else if (get_builtin(**argv)) {
+ handle_builtin(args);
+ else if (get_builtin(args->v[0])) {
struct child_process cmd = CHILD_PROCESS_INIT;
- int i;
+ int err;
/*
* The current process is committed to launching a
@@ -833,8 +876,8 @@ static int run_argv(int *argcp, const char ***argv)
commit_pager_choice();
strvec_push(&cmd.args, "git");
- for (i = 0; i < *argcp; i++)
- strvec_push(&cmd.args, (*argv)[i]);
+ for (size_t i = 0; i < args->nr; i++)
+ strvec_push(&cmd.args, args->v[i]);
trace_argv_printf(cmd.args.v, "trace: exec:");
@@ -846,51 +889,33 @@ static int run_argv(int *argcp, const char ***argv)
cmd.clean_on_exit = 1;
cmd.wait_after_clean = 1;
cmd.trace2_child_class = "git_alias";
- i = run_command(&cmd);
- if (i >= 0 || errno != ENOENT)
- exit(i);
- die("could not execute builtin %s", **argv);
+ err = run_command(&cmd);
+ if (err >= 0 || errno != ENOENT)
+ exit(err);
+ die("could not execute builtin %s", args->v[0]);
}
/* .. then try the external ones */
- execv_dashed_external(*argv);
-
- 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]);
+ execv_dashed_external(args->v);
/*
* It could be an alias -- this works around the insanity
* of overriding "git log" with "git show" by having
* alias.log = show
*/
- if (!handle_alias(argcp, argv))
+ if (!handle_alias(args, &expanded_aliases))
break;
done_alias = 1;
}
- string_list_clear(&cmd_list, 0);
+ string_list_clear(&expanded_aliases, 0);
return done_alias;
}
int cmd_main(int argc, const char **argv)
{
+ struct strvec args = STRVEC_INIT;
const char *cmd;
int done_help = 0;
@@ -916,8 +941,10 @@ int cmd_main(int argc, const char **argv)
* that one cannot handle it.
*/
if (skip_prefix(cmd, "git-", &cmd)) {
- argv[0] = cmd;
- handle_builtin(argc, argv);
+ strvec_push(&args, cmd);
+ strvec_pushv(&args, argv + 1);
+ handle_builtin(&args);
+ strvec_clear(&args);
die(_("cannot handle %s as a builtin"), cmd);
}
@@ -950,25 +977,34 @@ int cmd_main(int argc, const char **argv)
*/
setup_path();
+ for (int i = 0; i < argc; i++)
+ strvec_push(&args, argv[i]);
+
while (1) {
- int was_alias = run_argv(&argc, &argv);
+ int was_alias = run_argv(&args);
if (errno != ENOENT)
break;
if (was_alias) {
fprintf(stderr, _("expansion of alias '%s' failed; "
"'%s' is not a git command\n"),
- cmd, argv[0]);
+ cmd, args.v[0]);
+ strvec_clear(&args);
exit(1);
}
if (!done_help) {
- cmd = argv[0] = help_unknown_cmd(cmd);
+ char *assumed = help_unknown_cmd(cmd);
+ strvec_replace(&args, 0, assumed);
+ free(assumed);
+ cmd = args.v[0];
done_help = 1;
- } else
+ } else {
break;
+ }
}
fprintf(stderr, _("failed to run command '%s': %s\n"),
cmd, strerror(errno));
+ strvec_clear(&args);
return 1;
}