diff options
Diffstat (limited to 'builtin')
60 files changed, 7685 insertions, 1223 deletions
diff --git a/builtin/add.c b/builtin/add.c index 298e0114f9..26b6ced09e 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -18,7 +18,7 @@ #include "diffcore.h" #include "revision.h" #include "bulk-checkin.h" -#include "argv-array.h" +#include "strvec.h" #include "submodule.h" #include "add-interactive.h" @@ -188,13 +188,19 @@ int run_add_interactive(const char *revision, const char *patch_mode, const struct pathspec *pathspec) { int status, i; - struct argv_array argv = ARGV_ARRAY_INIT; + struct strvec argv = STRVEC_INIT; int use_builtin_add_i = git_env_bool("GIT_TEST_ADD_I_USE_BUILTIN", -1); - if (use_builtin_add_i < 0) - git_config_get_bool("add.interactive.usebuiltin", - &use_builtin_add_i); + if (use_builtin_add_i < 0) { + int experimental; + if (!git_config_get_bool("add.interactive.usebuiltin", + &use_builtin_add_i)) + ; /* ok */ + else if (!git_config_get_bool("feature.experimental", &experimental) && + experimental) + use_builtin_add_i = 1; + } if (use_builtin_add_i == 1) { enum add_p_mode mode; @@ -218,18 +224,18 @@ int run_add_interactive(const char *revision, const char *patch_mode, return !!run_add_p(the_repository, mode, revision, pathspec); } - argv_array_push(&argv, "add--interactive"); + strvec_push(&argv, "add--interactive"); if (patch_mode) - argv_array_push(&argv, patch_mode); + strvec_push(&argv, patch_mode); if (revision) - argv_array_push(&argv, revision); - argv_array_push(&argv, "--"); + strvec_push(&argv, revision); + strvec_push(&argv, "--"); for (i = 0; i < pathspec->nr; i++) /* pass original pathspec, to be re-parsed */ - argv_array_push(&argv, pathspec->items[i].original); + strvec_push(&argv, pathspec->items[i].original); - status = run_command_v_opt(argv.argv, RUN_GIT_CMD); - argv_array_clear(&argv); + status = run_command_v_opt(argv.v, RUN_GIT_CMD); + strvec_clear(&argv); return status; } @@ -534,11 +540,11 @@ int cmd_add(int argc, const char **argv, const char *prefix) die_in_unpopulated_submodule(&the_index, prefix); die_path_inside_submodule(&the_index, &pathspec); + dir_init(&dir); if (add_new_files) { int baselen; /* Set up the default git porcelain excludes */ - memset(&dir, 0, sizeof(dir)); if (!ignored_too) { dir.flags |= DIR_COLLECT_IGNORED; setup_standard_excludes(&dir); @@ -611,7 +617,7 @@ finish: COMMIT_LOCK | SKIP_IF_UNCHANGED)) die(_("Unable to write new index file")); + dir_clear(&dir); UNLEAK(pathspec); - UNLEAK(dir); return exit_status; } diff --git a/builtin/am.c b/builtin/am.c index 69e50de018..7259186408 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -98,6 +98,8 @@ struct am_state { char *author_name; char *author_email; char *author_date; + char *committer_name; + char *committer_email; char *msg; size_t msg_len; @@ -116,7 +118,7 @@ struct am_state { int keep; /* enum keep_type */ int message_id; int scissors; /* enum scissors_type */ - struct argv_array git_apply_opts; + struct strvec git_apply_opts; const char *resolvemsg; int committer_date_is_author_date; int ignore_date; @@ -130,6 +132,8 @@ struct am_state { */ static void am_state_init(struct am_state *state) { + const char *committer; + struct ident_split id; int gpgsign; memset(state, 0, sizeof(*state)); @@ -146,10 +150,18 @@ static void am_state_init(struct am_state *state) state->scissors = SCISSORS_UNSET; - argv_array_init(&state->git_apply_opts); + strvec_init(&state->git_apply_opts); if (!git_config_get_bool("commit.gpgsign", &gpgsign)) state->sign_commit = gpgsign ? "" : NULL; + + committer = git_committer_info(IDENT_STRICT); + if (split_ident_line(&id, committer, strlen(committer)) < 0) + die(_("invalid committer: %s"), committer); + state->committer_name = + xmemdupz(id.name_begin, id.name_end - id.name_begin); + state->committer_email = + xmemdupz(id.mail_begin, id.mail_end - id.mail_end); } /** @@ -161,8 +173,10 @@ static void am_state_release(struct am_state *state) free(state->author_name); free(state->author_email); free(state->author_date); + free(state->committer_name); + free(state->committer_email); free(state->msg); - argv_array_clear(&state->git_apply_opts); + strvec_clear(&state->git_apply_opts); } /** @@ -398,8 +412,8 @@ static void am_load(struct am_state *state) state->scissors = SCISSORS_UNSET; read_state_file(&sb, state, "apply-opt", 1); - argv_array_clear(&state->git_apply_opts); - if (sq_dequote_to_argv_array(sb.buf, &state->git_apply_opts) < 0) + strvec_clear(&state->git_apply_opts); + if (sq_dequote_to_strvec(sb.buf, &state->git_apply_opts) < 0) die(_("could not parse %s"), am_path(state, "apply-opt")); state->rebasing = !!file_exists(am_path(state, "rebasing")); @@ -452,8 +466,8 @@ static int run_post_rewrite_hook(const struct am_state *state) if (!hook) return 0; - argv_array_push(&cp.args, hook); - argv_array_push(&cp.args, "rebase"); + strvec_push(&cp.args, hook); + strvec_push(&cp.args, "rebase"); cp.in = xopen(am_path(state, "rewritten"), O_RDONLY); cp.stdout_to_stderr = 1; @@ -651,16 +665,16 @@ static int split_mail_mbox(struct am_state *state, const char **paths, int ret; cp.git_cmd = 1; - argv_array_push(&cp.args, "mailsplit"); - argv_array_pushf(&cp.args, "-d%d", state->prec); - argv_array_pushf(&cp.args, "-o%s", state->dir); - argv_array_push(&cp.args, "-b"); + strvec_push(&cp.args, "mailsplit"); + strvec_pushf(&cp.args, "-d%d", state->prec); + strvec_pushf(&cp.args, "-o%s", state->dir); + strvec_push(&cp.args, "-b"); if (keep_cr) - argv_array_push(&cp.args, "--keep-cr"); + strvec_push(&cp.args, "--keep-cr"); if (mboxrd) - argv_array_push(&cp.args, "--mboxrd"); - argv_array_push(&cp.args, "--"); - argv_array_pushv(&cp.args, paths); + strvec_push(&cp.args, "--mboxrd"); + strvec_push(&cp.args, "--"); + strvec_pushv(&cp.args, paths); ret = capture_command(&cp, &last, 8); if (ret) @@ -787,7 +801,7 @@ static int split_mail_stgit_series(struct am_state *state, const char **paths, const char *series_dir; char *series_dir_buf; FILE *fp; - struct argv_array patches = ARGV_ARRAY_INIT; + struct strvec patches = STRVEC_INIT; struct strbuf sb = STRBUF_INIT; int ret; @@ -805,16 +819,16 @@ static int split_mail_stgit_series(struct am_state *state, const char **paths, if (*sb.buf == '#') continue; /* skip comment lines */ - argv_array_push(&patches, mkpath("%s/%s", series_dir, sb.buf)); + strvec_push(&patches, mkpath("%s/%s", series_dir, sb.buf)); } fclose(fp); strbuf_release(&sb); free(series_dir_buf); - ret = split_mail_conv(stgit_patch_to_mail, state, patches.argv, keep_cr); + ret = split_mail_conv(stgit_patch_to_mail, state, patches.v, keep_cr); - argv_array_clear(&patches); + strvec_clear(&patches); return ret; } @@ -1002,7 +1016,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format, } write_state_text(state, "scissors", str); - sq_quote_argv(&sb, state->git_apply_opts.argv); + sq_quote_argv(&sb, state->git_apply_opts.v); write_state_text(state, "apply-opt", sb.buf); if (state->rebasing) @@ -1390,8 +1404,8 @@ static int parse_mail_rebase(struct am_state *state, const char *mail) */ static int run_apply(const struct am_state *state, const char *index_file) { - struct argv_array apply_paths = ARGV_ARRAY_INIT; - struct argv_array apply_opts = ARGV_ARRAY_INIT; + struct strvec apply_paths = STRVEC_INIT; + struct strvec apply_opts = STRVEC_INIT; struct apply_state apply_state; int res, opts_left; int force_apply = 0; @@ -1400,10 +1414,10 @@ static int run_apply(const struct am_state *state, const char *index_file) if (init_apply_state(&apply_state, the_repository, NULL)) BUG("init_apply_state() failed"); - argv_array_push(&apply_opts, "apply"); - argv_array_pushv(&apply_opts, state->git_apply_opts.argv); + strvec_push(&apply_opts, "apply"); + strvec_pushv(&apply_opts, state->git_apply_opts.v); - opts_left = apply_parse_options(apply_opts.argc, apply_opts.argv, + opts_left = apply_parse_options(apply_opts.nr, apply_opts.v, &apply_state, &force_apply, &options, NULL); @@ -1426,12 +1440,12 @@ static int run_apply(const struct am_state *state, const char *index_file) if (check_apply_state(&apply_state, force_apply)) BUG("check_apply_state() failed"); - argv_array_push(&apply_paths, am_path(state, "patch")); + strvec_push(&apply_paths, am_path(state, "patch")); - res = apply_all_patches(&apply_state, apply_paths.argc, apply_paths.argv, options); + res = apply_all_patches(&apply_state, apply_paths.nr, apply_paths.v, options); - argv_array_clear(&apply_paths); - argv_array_clear(&apply_opts); + strvec_clear(&apply_paths); + strvec_clear(&apply_opts); clear_apply_state(&apply_state); if (res) @@ -1454,10 +1468,10 @@ static int build_fake_ancestor(const struct am_state *state, const char *index_f struct child_process cp = CHILD_PROCESS_INIT; cp.git_cmd = 1; - argv_array_push(&cp.args, "apply"); - argv_array_pushv(&cp.args, state->git_apply_opts.argv); - argv_array_pushf(&cp.args, "--build-fake-ancestor=%s", index_file); - argv_array_push(&cp.args, am_path(state, "patch")); + strvec_push(&cp.args, "apply"); + strvec_pushv(&cp.args, state->git_apply_opts.v); + strvec_pushf(&cp.args, "--build-fake-ancestor=%s", index_file); + strvec_push(&cp.args, am_path(state, "patch")); if (run_command(&cp)) return -1; @@ -1556,7 +1570,7 @@ static void do_commit(const struct am_state *state) struct object_id tree, parent, commit; const struct object_id *old_oid; struct commit_list *parents = NULL; - const char *reflog_msg, *author; + const char *reflog_msg, *author, *committer = NULL; struct strbuf sb = STRBUF_INIT; if (run_hook_le(NULL, "pre-applypatch", NULL)) @@ -1580,11 +1594,15 @@ static void do_commit(const struct am_state *state) IDENT_STRICT); if (state->committer_date_is_author_date) - setenv("GIT_COMMITTER_DATE", - state->ignore_date ? "" : state->author_date, 1); - - if (commit_tree(state->msg, state->msg_len, &tree, parents, &commit, - author, state->sign_commit)) + committer = fmt_ident(state->committer_name, + state->author_email, WANT_COMMITTER_IDENT, + state->ignore_date ? NULL + : state->author_date, + IDENT_STRICT); + + if (commit_tree_extended(state->msg, state->msg_len, &tree, parents, + &commit, author, committer, state->sign_commit, + NULL)) die(_("failed to write commit object")); reflog_msg = getenv("GIT_REFLOG_ACTION"); @@ -1676,7 +1694,7 @@ static int do_interactive(struct am_state *state) if (!pager) pager = "cat"; prepare_pager_args(&cp, pager); - argv_array_push(&cp.args, am_path(state, "patch")); + strvec_push(&cp.args, am_path(state, "patch")); run_command(&cp); } } @@ -1795,7 +1813,7 @@ next: if (!state->rebasing) { am_destroy(state); close_object_store(the_repository->objects); - run_auto_gc(state->quiet); + run_auto_maintenance(state->quiet); } } @@ -2346,7 +2364,7 @@ int cmd_am(int argc, const char **argv, const char *prefix) if (state.signoff == SIGNOFF_EXPLICIT) am_append_signoff(&state); } else { - struct argv_array paths = ARGV_ARRAY_INIT; + struct strvec paths = STRVEC_INIT; int i; /* @@ -2371,17 +2389,17 @@ int cmd_am(int argc, const char **argv, const char *prefix) for (i = 0; i < argc; i++) { if (is_absolute_path(argv[i]) || !prefix) - argv_array_push(&paths, argv[i]); + strvec_push(&paths, argv[i]); else - argv_array_push(&paths, mkpath("%s/%s", prefix, argv[i])); + strvec_push(&paths, mkpath("%s/%s", prefix, argv[i])); } - if (state.interactive && !paths.argc) + if (state.interactive && !paths.nr) die(_("interactive mode requires patches on the command line")); - am_setup(&state, patch_format, paths.argv, keep_cr); + am_setup(&state, patch_format, paths.v, keep_cr); - argv_array_clear(&paths); + strvec_clear(&paths); } switch (resume.mode) { diff --git a/builtin/annotate.c b/builtin/annotate.c index da413ae0d1..58ff977a23 100644 --- a/builtin/annotate.c +++ b/builtin/annotate.c @@ -5,18 +5,18 @@ */ #include "git-compat-util.h" #include "builtin.h" -#include "argv-array.h" +#include "strvec.h" int cmd_annotate(int argc, const char **argv, const char *prefix) { - struct argv_array args = ARGV_ARRAY_INIT; + struct strvec args = STRVEC_INIT; int i; - argv_array_pushl(&args, "annotate", "-c", NULL); + strvec_pushl(&args, "annotate", "-c", NULL); for (i = 1; i < argc; i++) { - argv_array_push(&args, argv[i]); + strvec_push(&args, argv[i]); } - return cmd_blame(args.argc, args.argv, prefix); + return cmd_blame(args.nr, args.v, prefix); } diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c index ec4996282e..7512b880f0 100644 --- a/builtin/bisect--helper.c +++ b/builtin/bisect--helper.c @@ -4,22 +4,23 @@ #include "bisect.h" #include "refs.h" #include "dir.h" -#include "argv-array.h" +#include "strvec.h" #include "run-command.h" #include "prompt.h" #include "quote.h" +#include "revision.h" static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS") static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV") static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK") static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START") -static GIT_PATH_FUNC(git_path_bisect_head, "BISECT_HEAD") static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG") static GIT_PATH_FUNC(git_path_head_name, "head-name") static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES") +static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT") static const char * const git_bisect_helper_usage[] = { - N_("git bisect--helper --next-all [--no-checkout]"), + N_("git bisect--helper --next-all"), N_("git bisect--helper --write-terms <bad_term> <good_term>"), N_("git bisect--helper --bisect-clean-state"), N_("git bisect--helper --bisect-reset [<commit>]"), @@ -27,11 +28,19 @@ static const char * const git_bisect_helper_usage[] = { N_("git bisect--helper --bisect-check-and-set-terms <command> <good_term> <bad_term>"), N_("git bisect--helper --bisect-next-check <good_term> <bad_term> [<term>]"), N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"), - N_("git bisect--helper --bisect-start [--term-{old,good}=<term> --term-{new,bad}=<term>]" - "[--no-checkout] [<bad> [<good>...]] [--] [<paths>...]"), + N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]" + " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"), + N_("git bisect--helper --bisect-next"), + N_("git bisect--helper --bisect-auto-next"), + N_("git bisect--helper --bisect-autostart"), NULL }; +struct add_bisect_ref_data { + struct rev_info *revs; + unsigned int object_flags; +}; + struct bisect_terms { char *term_good; char *term_bad; @@ -55,6 +64,8 @@ static void set_terms(struct bisect_terms *terms, const char *bad, static const char vocab_bad[] = "bad|new"; static const char vocab_good[] = "good|old"; +static int bisect_autostart(struct bisect_terms *terms); + /* * Check whether the string `term` belongs to the set of strings * included in the variable arguments. @@ -74,6 +85,52 @@ static int one_of(const char *term, ...) return res; } +static int write_in_file(const char *path, const char *mode, const char *format, va_list args) +{ + FILE *fp = NULL; + int res = 0; + + if (strcmp(mode, "w") && strcmp(mode, "a")) + BUG("write-in-file does not support '%s' mode", mode); + fp = fopen(path, mode); + if (!fp) + return error_errno(_("cannot open file '%s' in mode '%s'"), path, mode); + res = vfprintf(fp, format, args); + + if (res < 0) { + int saved_errno = errno; + fclose(fp); + errno = saved_errno; + return error_errno(_("could not write to file '%s'"), path); + } + + return fclose(fp); +} + +static int write_to_file(const char *path, const char *format, ...) +{ + int res; + va_list args; + + va_start(args, format); + res = write_in_file(path, "w", format, args); + va_end(args); + + return res; +} + +static int append_to_file(const char *path, const char *format, ...) +{ + int res; + va_list args; + + va_start(args, format); + res = write_in_file(path, "a", format, args); + va_end(args); + + return res; +} + static int check_term_format(const char *term, const char *orig_term) { int res; @@ -104,7 +161,6 @@ static int check_term_format(const char *term, const char *orig_term) static int write_terms(const char *bad, const char *good) { - FILE *fp = NULL; int res; if (!strcmp(bad, good)) @@ -113,13 +169,9 @@ static int write_terms(const char *bad, const char *good) if (check_term_format(bad, "bad") || check_term_format(good, "good")) return -1; - fp = fopen(git_path_bisect_terms(), "w"); - if (!fp) - return error_errno(_("could not open the file BISECT_TERMS")); + res = write_to_file(git_path_bisect_terms(), "%s\n%s\n", bad, good); - res = fprintf(fp, "%s\n%s\n", bad, good); - res |= fclose(fp); - return (res < 0) ? -1 : 0; + return res; } static int is_expected_rev(const char *expected_hex) @@ -164,19 +216,19 @@ static int bisect_reset(const char *commit) strbuf_addstr(&branch, commit); } - if (!file_exists(git_path_bisect_head())) { - struct argv_array argv = ARGV_ARRAY_INIT; + if (!ref_exists("BISECT_HEAD")) { + struct strvec argv = STRVEC_INIT; - argv_array_pushl(&argv, "checkout", branch.buf, "--", NULL); - if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) { + strvec_pushl(&argv, "checkout", branch.buf, "--", NULL); + if (run_command_v_opt(argv.v, RUN_GIT_CMD)) { error(_("could not check out original" " HEAD '%s'. Try 'git bisect" " reset <commit>'."), branch.buf); strbuf_release(&branch); - argv_array_clear(&argv); + strvec_clear(&argv); return -1; } - argv_array_clear(&argv); + strvec_clear(&argv); } strbuf_release(&branch); @@ -421,9 +473,146 @@ finish: return res; } -static int bisect_start(struct bisect_terms *terms, int no_checkout, - const char **argv, int argc) +static int add_bisect_ref(const char *refname, const struct object_id *oid, + int flags, void *cb) +{ + struct add_bisect_ref_data *data = cb; + + add_pending_oid(data->revs, refname, oid, data->object_flags); + + return 0; +} + +static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs) +{ + int res = 0; + struct add_bisect_ref_data cb = { revs }; + char *good = xstrfmt("%s-*", terms->term_good); + + /* + * We cannot use terms- |