diff options
Diffstat (limited to 'builtin')
49 files changed, 5435 insertions, 815 deletions
diff --git a/builtin/add.c b/builtin/add.c index 298e0114f9..b36a99eb7c 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,7 +188,7 @@ 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); @@ -218,18 +218,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 +534,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 +611,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..b5c63ddf1d 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); } } @@ -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..cdda279b23 100644 --- a/builtin/bisect--helper.c +++ b/builtin/bisect--helper.c @@ -4,7 +4,7 @@ #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" @@ -13,13 +13,13 @@ 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>]"), @@ -28,7 +28,7 @@ static const char * const git_bisect_helper_usage[] = { 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>...]"), + " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"), NULL }; @@ -164,19 +164,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 +421,10 @@ finish: return res; } -static int bisect_start(struct bisect_terms *terms, int no_checkout, - const char **argv, int argc) +static int bisect_start(struct bisect_terms *terms, const char **argv, int argc) { + int no_checkout = 0; + int first_parent_only = 0; int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0; int flags, pathspec_pos, res = 0; struct string_list revs = STRING_LIST_INIT_DUP; @@ -453,6 +454,8 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout, break; } else if (!strcmp(arg, "--no-checkout")) { no_checkout = 1; + } else if (!strcmp(arg, "--first-parent")) { + first_parent_only = 1; } else if (!strcmp(arg, "--term-good") || !strcmp(arg, "--term-old")) { i++; @@ -526,11 +529,11 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout, strbuf_read_file(&start_head, git_path_bisect_start(), 0); strbuf_trim(&start_head); if (!no_checkout) { - struct argv_array argv = ARGV_ARRAY_INIT; + struct strvec argv = STRVEC_INIT; - argv_array_pushl(&argv, "checkout", start_head.buf, - "--", NULL); - if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) { + strvec_pushl(&argv, "checkout", start_head.buf, + "--", NULL); + if (run_command_v_opt(argv.v, RUN_GIT_CMD)) { res = error(_("checking out '%s' failed." " Try 'git bisect start " "<valid-branch>'."), @@ -577,6 +580,9 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout, */ write_file(git_path_bisect_start(), "%s\n", start_head.buf); + if (first_parent_only) + write_file(git_path_bisect_first_parent(), "\n"); + if (no_checkout) { if (get_oid(start_head.buf, &oid) < 0) { res = error(_("invalid ref: '%s'"), start_head.buf); @@ -632,7 +638,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix) BISECT_TERMS, BISECT_START } cmdmode = 0; - int no_checkout = 0, res = 0, nolog = 0; + int res = 0, nolog = 0; struct option options[] = { OPT_CMDMODE(0, "next-all", &cmdmode, N_("perform 'git bisect next'"), NEXT_ALL), @@ -654,8 +660,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix) N_("print out the bisect terms"), BISECT_TERMS), OPT_CMDMODE(0, "bisect-start", &cmdmode, N_("start the bisect session"), BISECT_START), - OPT_BOOL(0, "no-checkout", &no_checkout, - N_("update BISECT_HEAD instead of checking out the current commit")), OPT_BOOL(0, "no-log", &nolog, N_("no log for BISECT_WRITE")), OPT_END() @@ -671,7 +675,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix) switch (cmdmode) { case NEXT_ALL: - res = bisect_next_all(the_repository, prefix, no_checkout); + res = bisect_next_all(the_repository, prefix); break; case WRITE_TERMS: if (argc != 2) @@ -713,7 +717,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix) break; case BISECT_START: set_terms(&terms, "bad", "good"); - res = bisect_start(&terms, no_checkout, argv, argc); + res = bisect_start(&terms, argv, argc); break; default: return error("BUG: unknown subcommand '%d'", cmdmode); diff --git a/builtin/blame.c b/builtin/blame.c index 94ef57c1cc..eb513fbe60 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -842,7 +842,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) const char *contents_from = NULL; const struct option options[] = { OPT_BOOL(0, "incremental", &incremental, N_("Show blame entries as we find them, incrementally")), - OPT_BOOL('b', NULL, &blank_boundary, N_("Show blank SHA-1 for boundary commits (Default: off)")), + OPT_BOOL('b', NULL, &blank_boundary, N_("Do not show object names of boundary commits (Default: off)")), OPT_BOOL(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")), OPT_BOOL(0, "show-stats", &show_stats, N_("Show work cost statistics")), OPT_BOOL(0, "progress", &show_progress, N_("Force progress reporting")), diff --git a/builtin/bugreport.c b/builtin/bugreport.c new file mode 100644 index 0000000000..3ad4b9b62e --- /dev/null +++ b/builtin/bugreport.c @@ -0,0 +1,194 @@ +#include "builtin.h" +#include "parse-options.h" +#include "strbuf.h" +#include "help.h" +#include "compat/compiler.h" +#include "run-command.h" + + +static void get_system_info(struct strbuf *sys_info) +{ + struct utsname uname_info; + char *shell = NULL; + + /* get git version from native cmd */ + strbuf_addstr(sys_info, _("git version:\n")); + get_version_info(sys_info, 1); + + /* system call for other version info */ + strbuf_addstr(sys_info, "uname: "); + if (uname(&uname_info)) + strbuf_addf(sys_info, _("uname() failed with error '%s' (%d)\n"), + strerror(errno), + errno); + else + strbuf_addf(sys_info, "%s %s %s %s\n", + uname_info.sysname, + uname_info.release, + uname_info.version, + uname_info.machine); + + strbuf_addstr(sys_info, _("compiler info: ")); + get_compiler_info(sys_info); + + strbuf_addstr(sys_info, _("libc info: ")); + get_libc_info(sys_info); + + shell = getenv("SHELL"); + strbuf_addf(sys_info, "$SHELL (typically, interactive shell): %s\n", + shell ? shell : "<unset>"); +} + +static void get_populated_hooks(struct strbuf *hook_info, int nongit) +{ + /* + * NEEDSWORK: Doesn't look like there is a list of all possible hooks; + * so below is a transcription of `git help hooks`. Later, this should + * be replaced with some programmatically generated list (generated from + * doc or else taken from some library which tells us about all the + * hooks) + */ + static const char *hook[] = { + "applypatch-msg", + "pre-applypatch", + "post-applypatch", + "pre-commit", + "pre-merge-commit", + "prepare-commit-msg", + "commit-msg", + "post-commit", + "pre-rebase", + "post-checkout", + "post-merge", + "pre-push", + "pre-receive", + "update", + "post-receive", + "post-update", + "push-to-checkout", + "pre-auto-gc", + "post-rewrite", + "sendemail-validate", + "fsmonitor-watchman", + "p4-pre-submit", + "post-index-change", + }; + int i; + + if (nongit) { + strbuf_addstr(hook_info, + _("not run from a git repository - no hooks to show\n")); + return; + } + + for (i = 0; i < ARRAY_SIZE(hook); i++) + if (find_hook(hook[i])) + strbuf_addf(hook_info, "%s\n", hook[i]); +} + +static const char * const bugreport_usage[] = { + N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"), + NULL +}; + +static int get_bug_template(struct strbuf *template) +{ + const char template_text[] = N_( +"Thank you for filling out a Git bug report!\n" +"Please answer the following questions to help us understand your issue.\n" +"\n" +"What did you do before the bug happened? (Steps to reproduce your issue)\n" +"\n" +"What did you expect to happen? (Expected behavior)\n" +"\n" +"What happened instead? (Actual behavior)\n" +"\n" +"What's different between what you expected and what actually happened?\n" +"\n" +"Anything else you want to add:\n" +"\n" +"Please review the rest of the bug report below.\n" +"You can delete any lines you don't wish to share.\n"); + + strbuf_addstr(template, _(template_text)); + return 0; +} + +static |