diff options
Diffstat (limited to 'builtin/commit.c')
-rw-r--r-- | builtin/commit.c | 327 |
1 files changed, 189 insertions, 138 deletions
diff --git a/builtin/commit.c b/builtin/commit.c index 0d9828e29e..505fe60956 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -5,6 +5,7 @@ * Based on git-commit.sh by Junio C Hamano and Linus Torvalds */ +#define USE_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" #include "config.h" #include "lockfile.h" @@ -33,6 +34,8 @@ #include "sequencer.h" #include "mailmap.h" #include "help.h" +#include "commit-reach.h" +#include "commit-graph.h" static const char * const builtin_commit_usage[] = { N_("git commit [<options>] [--] <pathspec>..."), @@ -56,16 +59,22 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\ " git commit --allow-empty\n" "\n"); +static const char empty_rebase_pick_advice[] = +N_("Otherwise, please use 'git rebase --skip'\n"); + static const char empty_cherry_pick_advice_single[] = -N_("Otherwise, please use 'git reset'\n"); +N_("Otherwise, please use 'git cherry-pick --skip'\n"); static const char empty_cherry_pick_advice_multi[] = -N_("If you wish to skip this commit, use:\n" +N_("and then use:\n" +"\n" +" git cherry-pick --continue\n" "\n" -" git reset\n" +"to resume cherry-picking the remaining commits.\n" +"If you wish to skip this commit, use:\n" "\n" -"Then \"git cherry-pick --continue\" will resume cherry-picking\n" -"the remaining commits.\n"); +" git cherry-pick --skip\n" +"\n"); static const char *color_status_slots[] = { [WT_STATUS_HEADER] = "header", @@ -101,9 +110,9 @@ static int all, also, interactive, patch_interactive, only, amend, signoff; static int edit_flag = -1; /* unspecified */ static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship; static int config_commit_verbose = -1; /* unspecified */ -static int no_post_rewrite, allow_empty_message; +static int no_post_rewrite, allow_empty_message, pathspec_file_nul; static char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg; -static char *sign_commit; +static char *sign_commit, *pathspec_from_file; /* * The default commit message cleanup mode will remove the lines @@ -116,7 +125,6 @@ static enum commit_msg_cleanup_mode cleanup_mode; static const char *cleanup_arg; static enum commit_whence whence; -static int sequencer_in_use; static int use_editor = 1, include_status = 1; static int have_option_m; static struct strbuf message = STRBUF_INIT; @@ -159,6 +167,9 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset) static int opt_parse_rename_score(const struct option *opt, const char *arg, int unset) { const char **value = opt->value; + + BUG_ON_OPT_NEG(unset); + if (arg != NULL && *arg == '=') arg = arg + 1; @@ -170,12 +181,7 @@ static void determine_whence(struct wt_status *s) { if (file_exists(git_path_merge_head(the_repository))) whence = FROM_MERGE; - else if (file_exists(git_path_cherry_pick_head(the_repository))) { - whence = FROM_CHERRY_PICK; - if (file_exists(git_path_seq_dir())) - sequencer_in_use = 1; - } - else + else if (!sequencer_determine_whence(the_repository, &whence)) whence = FROM_COMMIT; if (s) s->whence = whence; @@ -183,7 +189,7 @@ static void determine_whence(struct wt_status *s) static void status_init_config(struct wt_status *s, config_fn_t fn) { - wt_status_prepare(s); + wt_status_prepare(the_repository, s); init_diff_ui_defaults(); git_config(fn, s); determine_whence(s); @@ -229,7 +235,7 @@ static int commit_index_files(void) * and return the paths that match the given pattern in list. */ static int list_paths(struct string_list *list, const char *with_tree, - const char *prefix, const struct pathspec *pattern) + const struct pathspec *pattern) { int i, ret; char *m; @@ -258,7 +264,7 @@ static int list_paths(struct string_list *list, const char *with_tree, item->util = item; /* better a valid pointer than a fake one */ } - ret = report_path_error(m, pattern, prefix); + ret = report_path_error(m, pattern); free(m); return ret; } @@ -320,7 +326,7 @@ static void refresh_cache_or_die(int refresh_flags) die_resolve_conflict("commit"); } -static const char *prepare_index(int argc, const char **argv, const char *prefix, +static const char *prepare_index(const char **argv, const char *prefix, const struct commit *current_head, int is_status) { struct string_list partial = STRING_LIST_INIT_DUP; @@ -334,11 +340,31 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix PATHSPEC_PREFER_FULL, prefix, argv); + if (pathspec_from_file) { + if (interactive) + die(_("--pathspec-from-file is incompatible with --interactive/--patch")); + + if (all) + die(_("--pathspec-from-file with -a does not make sense")); + + if (pathspec.nr) + die(_("--pathspec-from-file is incompatible with pathspec arguments")); + + parse_pathspec_file(&pathspec, 0, + PATHSPEC_PREFER_FULL, + prefix, pathspec_from_file, pathspec_file_nul); + } else if (pathspec_file_nul) { + die(_("--pathspec-file-nul requires --pathspec-from-file")); + } + + if (!pathspec.nr && (also || (only && !amend && !allow_empty))) + die(_("No paths with --include/--only does not make sense.")); + if (read_cache_preload(&pathspec) < 0) die(_("index file corrupt")); if (interactive) { - char *old_index_env = NULL; + char *old_index_env = NULL, *old_repo_index_file; hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR); refresh_cache_or_die(refresh_flags); @@ -346,16 +372,21 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix if (write_locked_index(&the_index, &index_lock, 0)) die(_("unable to create temporary index")); - old_index_env = getenv(INDEX_ENVIRONMENT); - setenv(INDEX_ENVIRONMENT, get_lock_file_path(&index_lock), 1); + old_repo_index_file = the_repository->index_file; + the_repository->index_file = + (char *)get_lock_file_path(&index_lock); + old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT)); + setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1); - if (interactive_add(argc, argv, prefix, patch_interactive) != 0) + if (interactive_add(argv, prefix, patch_interactive) != 0) die(_("interactive add failed")); + the_repository->index_file = old_repo_index_file; if (old_index_env && *old_index_env) setenv(INDEX_ENVIRONMENT, old_index_env, 1); else unsetenv(INDEX_ENVIRONMENT); + FREE_AND_NULL(old_index_env); discard_cache(); read_cache_from(get_lock_file_path(&index_lock)); @@ -443,11 +474,13 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix if (whence != FROM_COMMIT) { if (whence == FROM_MERGE) die(_("cannot do a partial commit during a merge.")); - else if (whence == FROM_CHERRY_PICK) + else if (is_from_cherry_pick(whence)) die(_("cannot do a partial commit during a cherry-pick.")); + else if (is_from_rebase(whence)) + die(_("cannot do a partial commit during a rebase.")); } - if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, &pathspec)) + if (list_paths(&partial, !current_head ? NULL : "HEAD", &pathspec)) exit(1); discard_cache(); @@ -500,14 +533,15 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int s->nowarn = nowarn; s->is_initial = get_oid(s->reference, &oid) ? 1 : 0; if (!s->is_initial) - hashcpy(s->sha1_commit, oid.hash); + oidcpy(&s->oid_commit, &oid); s->status_format = status_format; s->ignore_submodule_arg = ignore_submodule_arg; wt_status_collect(s); wt_status_print(s); + wt_status_collect_free_buffers(s); - return s->commitable; + return s->committable; } static int is_a_merge(const struct commit *current_head) @@ -526,7 +560,7 @@ static void export_one(const char *var, const char *s, const char *e, int hack) struct strbuf buf = STRBUF_INIT; if (hack) strbuf_addch(&buf, hack); - strbuf_addf(&buf, "%.*s", (int)(e - s), s); + strbuf_add(&buf, s, e - s); setenv(var, buf.buf, 1); strbuf_release(&buf); } @@ -601,7 +635,8 @@ static void determine_author_info(struct strbuf *author_ident) set_ident_var(&date, strbuf_detach(&date_buf, NULL)); } - strbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT)); + strbuf_addstr(author_ident, fmt_ident(name, email, WANT_AUTHOR_IDENT, date, + IDENT_STRICT)); assert_split_ident(&author, author_ident); export_one("GIT_AUTHOR_NAME", author.name_begin, author.name_end, 0); export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0); @@ -653,12 +688,13 @@ static int prepare_to_commit(const char *index_file, const char *prefix, { struct stat statbuf; struct strbuf committer_ident = STRBUF_INIT; - int commitable; + int committable; struct strbuf sb = STRBUF_INIT; const char *hook_arg1 = NULL; const char *hook_arg2 = NULL; int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE); int old_display_comment_prefix; + int merge_contains_scissors = 0; /* This checks and barfs if author is badly specified */ determine_author_info(author_ident); @@ -719,6 +755,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix, strbuf_addbuf(&sb, &message); hook_arg1 = "message"; } else if (!stat(git_path_merge_msg(the_repository), &statbuf)) { + size_t merge_msg_start; + /* * prepend SQUASH_MSG here if it exists and a * "merge --squash" was originally performed @@ -729,8 +767,16 @@ static int prepare_to_commit(const char *index_file, const char *prefix, hook_arg1 = "squash"; } else hook_arg1 = "merge"; + + merge_msg_start = sb.len; if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0) die_errno(_("could not read MERGE_MSG")); + + if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS && + wt_status_locate_end(sb.buf + merge_msg_start, + sb.len - merge_msg_start) < + sb.len - merge_msg_start) + merge_contains_scissors = 1; } else if (!stat(git_path_squash_msg(the_repository), &statbuf)) { if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0) die_errno(_("could not read SQUASH_MSG")); @@ -748,7 +794,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, */ else if (whence == FROM_MERGE) hook_arg1 = "merge"; - else if (whence == FROM_CHERRY_PICK) { + else if (is_from_cherry_pick(whence) || whence == FROM_REBASE_PICK) { hook_arg1 = "commit"; hook_arg2 = "CHERRY_PICK_HEAD"; } @@ -798,23 +844,22 @@ static int prepare_to_commit(const char *index_file, const char *prefix, struct ident_split ci, ai; if (whence != FROM_COMMIT) { - if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) + if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS && + !merge_contains_scissors) wt_status_add_cut_line(s->fp); - status_printf_ln(s, GIT_COLOR_NORMAL, - whence == FROM_MERGE - ? _("\n" - "It looks like you may be committing a merge.\n" - "If this is not correct, please remove the file\n" - " %s\n" - "and try again.\n") - : _("\n" - "It looks like you may be committing a cherry-pick.\n" - "If this is not correct, please remove the file\n" - " %s\n" - "and try again.\n"), + status_printf_ln( + s, GIT_COLOR_NORMAL, whence == FROM_MERGE ? - git_path_merge_head(the_repository) : - git_path_cherry_pick_head(the_repository)); + _("\n" + "It looks like you may be committing a merge.\n" + "If this is not correct, please run\n" + " git update-ref -d MERGE_HEAD\n" + "and try again.\n") : + _("\n" + "It looks like you may be committing a cherry-pick.\n" + "If this is not correct, please run\n" + " git update-ref -d CHERRY_PICK_HEAD\n" + "and try again.\n")); } fprintf(s->fp, "\n"); @@ -823,10 +868,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix, _("Please enter the commit message for your changes." " Lines starting\nwith '%c' will be ignored, and an empty" " message aborts the commit.\n"), comment_line_char); - else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS && - whence == FROM_COMMIT) - wt_status_add_cut_line(s->fp); - else /* COMMIT_MSG_CLEANUP_SPACE, that is. */ + else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) { + if (whence == FROM_COMMIT && !merge_contains_scissors) + wt_status_add_cut_line(s->fp); + } else /* COMMIT_MSG_CLEANUP_SPACE, that is. */ status_printf(s, GIT_COLOR_NORMAL, _("Please enter the commit message for your changes." " Lines starting\n" @@ -870,8 +915,9 @@ static int prepare_to_commit(const char *index_file, const char *prefix, saved_color_setting = s->use_color; s->use_color = 0; - commitable = run_status(s->fp, index_file, prefix, 1, s); + committable = run_status(s->fp, index_file, prefix, 1, s); s->use_color = saved_color_setting; + string_list_clear(&s->change, 1); } else { struct object_id oid; const char *parent = "HEAD"; @@ -888,7 +934,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, for (i = 0; i < active_nr; i++) if (ce_intent_to_add(active_cache[i])) ita_nr++; - commitable = active_nr - ita_nr > 0; + committable = active_nr - ita_nr > 0; } else { /* * Unless the user did explicitly request a submodule @@ -904,7 +950,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix, if (ignore_submodule_arg && !strcmp(ignore_submodule_arg, "all")) flags.ignore_submodules = 1; - commitable = index_differs_from(parent, &flags, 1); + committable = index_differs_from(the_repository, + parent, &flags, 1); } } strbuf_release(&committer_ident); @@ -916,18 +963,22 @@ static int prepare_to_commit(const char *index_file, const char *prefix, * explicit --allow-empty. In the cherry-pick case, it may be * empty due to conflict resolution, which the user should okay. */ - if (!commitable && whence != FROM_MERGE && !allow_empty && + if (!committable && whence != FROM_MERGE && !allow_empty && !(amend && is_a_merge(current_head))) { + s->hints = advice_status_hints; s->display_comment_prefix = old_display_comment_prefix; run_status(stdout, index_file, prefix, 0, s); if (amend) fputs(_(empty_amend_advice), stderr); - else if (whence == FROM_CHERRY_PICK) { + else if (is_from_cherry_pick(whence) || + whence == FROM_REBASE_PICK) { fputs(_(empty_cherry_pick_advice), stderr); - if (!sequencer_in_use) + if (whence == FROM_CHERRY_PICK_SINGLE) fputs(_(empty_cherry_pick_advice_single), stderr); - else + else if (whence == FROM_CHERRY_PICK_MULTI) fputs(_(empty_cherry_pick_advice_multi), stderr); + else + fputs(_(empty_rebase_pick_advice), stderr); } return 0; } @@ -952,15 +1003,15 @@ static int prepare_to_commit(const char *index_file, const char *prefix, return 0; if (use_editor) { - struct argv_array env = ARGV_ARRAY_INIT; + struct strvec env = STRVEC_INIT; - argv_array_pushf(&env, "GIT_INDEX_FILE=%s", index_file); - if (launch_editor(git_path_commit_editmsg(), NULL, env.argv)) { + strvec_pushf(&env, "GIT_INDEX_FILE=%s", index_file); + if (launch_editor(git_path_commit_editmsg(), NULL, env.v)) { fprintf(stderr, _("Please supply the message using either -m or -F option.\n")); exit(1); } - argv_array_clear(&env); + strvec_clear(&env); } if (!no_verify && @@ -980,7 +1031,7 @@ static const char *find_author_by_nickname(const char *name) const char *av[20]; int ac = 0; - init_revisions(&revs, NULL); + repo_init_revisions(the_repository, &revs, NULL); strbuf_addf(&buf, "--author=%s", name); av[++ac] = "--all"; av[++ac] = "-i"; @@ -1028,6 +1079,10 @@ static void handle_untracked_files_arg(struct wt_status *s) s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; else if (!strcmp(untracked_files_arg, "all")) s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES; + /* + * Please update $__git_untracked_file_modes in + * git-completion.bash when you add new options + */ else die(_("Invalid untracked files mode '%s'"), untracked_files_arg); } @@ -1051,9 +1106,11 @@ static const char *read_commit_message(const char *name) static struct status_deferred_config { enum wt_status_format status_format; int show_branch; + enum ahead_behind_flags ahead_behind; } status_deferred_config = { STATUS_FORMAT_UNSPECIFIED, - -1 /* unspecified */ + -1, /* unspecified */ + AHEAD_BEHIND_UNSPECIFIED, }; static void finalize_deferred_config(struct wt_status *s) @@ -1080,6 +1137,17 @@ static void finalize_deferred_config(struct wt_status *s) if (s->show_branch < 0) s->show_branch = 0; + /* + * If the user did not give a "--[no]-ahead-behind" command + * line argument *AND* we will print in a human-readable format + * (short, long etc.) then we inherit from the status.aheadbehind + * config setting. In all other cases (and porcelain V[12] formats + * in particular), we inherit _FULL for backwards compatibility. + */ + if (use_deferred_config && + s->ahead_behind_flags == AHEAD_BEHIND_UNSPECIFIED) + s->ahead_behind_flags = status_deferred_config.ahead_behind; + if (s->ahead_behind_flags == AHEAD_BEHIND_UNSPECIFIED) s->ahead_behind_flags = AHEAD_BEHIND_FULL; } @@ -1113,8 +1181,10 @@ static int parse_and_validate_options(int argc, const char *argv[], if (amend && whence != FROM_COMMIT) { if (whence == FROM_MERGE) die(_("You are in the middle of a merge -- cannot amend.")); - else if (whence == FROM_CHERRY_PICK) + else if (is_from_cherry_pick(whence)) die(_("You are in the middle of a cherry-pick -- cannot amend.")); + else if (whence == FROM_REBASE_PICK) + die(_("You are in the middle of a rebase -- cannot amend.")); } if (fixup_message && squash_message) die(_("Options --squash and --fixup cannot be used together")); @@ -1136,7 +1206,8 @@ static int parse_and_validate_options(int argc, const char *argv[], use_message = edit_message; if (amend && !use_message && !fixup_message) use_message = "HEAD"; - if (!use_message && whence != FROM_CHERRY_PICK && renew_authorship) + if (!use_message && !is_from_cherry_pick(whence) && + !is_from_rebase(whence) && renew_authorship) die(_("--reset-author can be used only with -C, -c or --amend.")); if (use_message) { use_message_buffer = read_commit_message(use_message); @@ -1145,7 +1216,8 @@ static int parse_and_validate_options(int argc, const char *argv[], author_message_buffer = use_message_buffer; } } - if (whence == FROM_CHERRY_PICK && !renew_authorship) { + if ((is_from_cherry_pick(whence) || whence == FROM_REBASE_PICK) && + !renew_authorship) { author_message = "CHERRY_PICK_HEAD"; author_message_buffer = read_commit_message(author_message); } @@ -1155,27 +1227,13 @@ static int parse_and_validate_options(int argc, const char *argv[], if (also + only + all + interactive > 1) die(_("Only one of --include/--only/--all/--interactive/--patch can be used.")); - if (argc == 0 && (also || (only && !amend && !allow_empty))) - die(_("No paths with --include/--only does not make sense.")); - if (!cleanup_arg || !strcmp(cleanup_arg, "default")) - cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_ALL : - COMMIT_MSG_CLEANUP_SPACE; - else if (!strcmp(cleanup_arg, "verbatim")) - cleanup_mode = COMMIT_MSG_CLEANUP_NONE; - else if (!strcmp(cleanup_arg, "whitespace")) - cleanup_mode = COMMIT_MSG_CLEANUP_SPACE; - else if (!strcmp(cleanup_arg, "strip")) - cleanup_mode = COMMIT_MSG_CLEANUP_ALL; - else if (!strcmp(cleanup_arg, "scissors")) - cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_SCISSORS : - COMMIT_MSG_CLEANUP_SPACE; - else - die(_("Invalid cleanup mode %s"), cleanup_arg); + cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor); handle_untracked_files_arg(s); if (all && argc > 0) - die(_("Paths with -a does not make sense.")); + die(_("paths '%s ...' with -a does not make sense"), + argv[0]); if (status_format != STATUS_FORMAT_NONE) dry_run = 1; @@ -1183,17 +1241,17 @@ static int parse_and_validate_options(int argc, const char *argv[], return argc; } -static int dry_run_commit(int argc, const char **argv, const char *prefix, +static int dry_run_commit(const char **argv, const char *prefix, const struct commit *current_head, struct wt_status *s) { - int commitable; + int committable; const char *index_file; - index_file = prepare_index(argc, argv, prefix, current_head, 1); - commitable = run_status(stdout, index_file, prefix, 0, s); + index_file = prepare_index(argv, prefix, current_head, 1); + committable = run_status(stdout, index_file, prefix, 0, s); rollback_index_files(); - return commitable ? 0 : 1; + return committable ? 0 : 1; } define_list_config_array_extra(color_status_slots, {"added"}); @@ -1231,6 +1289,10 @@ static int git_status_config(const char *k, const char *v, void *cb) status_deferred_config.show_branch = git_config_bool(k, v); return 0; } + if (!strcmp(k, "status.aheadbehind")) { + status_deferred_config.ahead_behind = git_config_bool(k, v); + return 0; + } if (!strcmp(k, "status.showstash")) { s->show_stash = git_config_bool(k, v); return 0; @@ -1295,6 +1357,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) static int no_renames = -1; static const char *rename_score_arg = (const char *)-1; static struct wt_status s; + unsigned int progress_flag = 0; int fd; struct object_id oid; static struct option builtin_status_options[] = { @@ -1307,9 +1370,9 @@ int cmd_status(int argc, const char **argv, const char *prefix) N_("show stash information")), OPT_BOOL(0, "ahead-behind", &s.ahead_behind_flags, N_("compute full ahead/behind values")), - { OPTION_CALLBACK, 0, "porcelain", &status_format, + OPT_CALLBACK_F(0, "porcelain", &status_format, N_("version"), N_("machine-readable output"), - PARSE_OPT_OPTARG, opt_parse_porcelain }, + PARSE_OPT_OPTARG, opt_parse_porcelain), OPT_SET_INT(0, "long", &status_format, N_("show status in long format (default)"), STATUS_FORMAT_LONG), @@ -1328,9 +1391,9 @@ int cmd_status(int argc, const char **argv, const char *prefix) PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, OPT_COLUMN(0, "column", &s.colopts, N_("list untracked files in columns")), OPT_BOOL(0, "no-renames", &no_renames, N_("do not detect renames")), - { OPTION_CALLBACK, 'M', "find-renames", &rename_score_arg, + OPT_CALLBACK_F('M', "find-renames", &rename_score_arg, N_("n"), N_("detect renames, optionally set similarity index"), - PARSE_OPT_OPTARG, opt_parse_rename_score }, + PARSE_OPT_OPTARG | PARSE_OPT_NONEG, opt_parse_rename_score), OPT_END(), }; @@ -1355,8 +1418,13 @@ int cmd_status(int argc, const char **argv, const char *prefix) PATHSPEC_PREFER_FULL, prefix, argv); - read_cache_preload(&s.pathspec); - refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &s.pathspec, NULL, NULL); + if (status_format != STATUS_FORMAT_PORCELAIN && + status_format != STATUS_FORMAT_PORCELAIN_V2) + progress_flag = REFRESH_PROGRESS; + repo_read_index(the_repository); + refresh_index(&the_index, + REFRESH_QUIET|REFRESH_UNMERGED|progress_flag, + &s.pathspec, NULL, NULL); if (use_optional_locks()) fd = hold_locked_index(&index_lock, 0); @@ -1365,7 +1433,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) s.is_initial = get_oid(s.reference, &oid) ? 1 : 0; if (!s.is_initial) - hashcpy(s.sha1_commit, oid.hash); + oidcpy(&s.oid_commit, &oid); s.ignore_submodule_arg = ignore_submodule_arg; s.status_format = status_format; @@ -1382,12 +1450,14 @@ int cmd_status(int argc, const char **argv, const char *prefix) wt_status_collect(&s); if (0 <= fd) - update_index_if_able(&the_index, &index_lock); + repo_update_index_if_able(the_repository, &index_lock); if (s.relative_paths) s.prefix = prefix; wt_status_print(&s); + wt_status_collect_free_buffers(&s); + return 0; } @@ -1420,31 +1490,8 @@ static int git_commit_config(const char *k, const char *v, void *cb) return git_status_config(k, v, s); } -int run_commit_hook(int editor_is_used, const char *index_file, const char *name, ...) -{ - struct argv_array hook_env = ARGV_ARRAY_INIT; - va_list args; - int ret; - - argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", index_file); - - /* - * Let the hook know that no editor will be launched. - */ - if (!editor_is_used) - argv_array_push(&hook_env, "GIT_EDITOR=:"); - - va_start(args, name); - ret = run_hook_ve(hook_env.argv,name, args); - va_end(args); - argv_array_clear(&hook_env); - - return ret; -} - int cmd_commit(int argc, const char **argv, const char *prefix) { - const char *argv_gc_auto[] = {"gc", "--auto", NULL}; static struct wt_status s; static struct option builtin_commit_options[] = { OPT__QUIET(&quiet, N_("suppress summary after successful commit")), @@ -1460,10 +1507,10 @@ int cmd_commit(int argc, const char **argv, const char *prefix) OPT_STRING(0, "fixup", &fixup_message, N_("commit"), N_("use autosquash formatted message to fixup specified commit")), OPT_STRING(0, "squash", &squash_message, N_("commit"), N_("use autosquash formatted message to squash specified commit")), OPT_BOOL(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")), - OPT_BOOL('s', "signoff", &signoff, N_("add Signed-off-by:")), + OPT_BOOL('s', "signoff", &signoff, N_("add a Signed-off-by trailer")), OPT_FILENAME('t', "template", &template_file, N_("use specified template file")), OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")), - OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")), + OPT_CLEANUP(&cleanup_arg), OPT_BOOL(0, "status", &include_status, N_("include status in commit message template")), { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"), N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, @@ -1492,6 +1539,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "amend", &amend, N_("amend previous commit")), OPT_BOOL(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")), { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, N_("mode"), N_("show untracked files, optional modes: all, normal, no. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, + OPT_PATHSPEC_FROM_FILE(&pathspec_from_file), + OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul), /* end commit contents options */ OPT_HIDDEN_BOOL(0, "allow-empty", &allow_empty, @@ -1535,8 +1584,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) verbose = (config_commit_verbose < 0) ? 0 : config_commit_verbose; if (dry_run) - return dry_run_commit(argc, argv, prefix, current_head, &s); - index_file = prepare_index(argc, argv, prefix, current_head, 0); + return dry_run_commit(argv, prefix, current_head, &s); + index_file = prepare_index(argv, prefix, current_head, 0); /* Set up everything for writing the commit object. This includes running hooks, writing the trees, and interacting with the user. */ @@ -1585,8 +1634,10 @@ int cmd_commit(int argc, const char **argv, const char *prefix) reduce_heads_replace(&parents); } else { if (!reflog_msg) - reflog_msg = (whence == FROM_CHERRY_PICK) + reflog_msg = is_from_cherry_pick(whence) ? "commit (cherry-pick)" + : is_from_rebase(whence) + ? "commit (rebase)" : "commit"; commit_list_insert(current_head, &parents); } @@ -1599,11 +1650,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) die(_("could not read commit message: %s"), strerror(saved_errno)); } - if (verbose || /* Truncate the message just before the diff, if any. */ - cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) - strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len)); - if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE) - strbuf_stripspace(&sb, cleanup_mode == COMMIT_MSG_CLEANUP_ALL); + cleanup_message(&sb, cleanup_mode, verbose); if (message_is_empty(&sb, cleanup_mode) && !allow_empty_message) { rollback_index_files(); @@ -1617,7 +1664,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) } if (amend) { - const char *exclude_gpgsig[2] = { "gpgsig", NULL }; + const char *exclude_gpgsig[3] = { "gpgsig", "gpgsig-sha256", NULL }; extra = read_commit_extra_headers(current_head, exclude_gpgsig); } else { struct commit_extra_header **tail = &extra; @@ -1625,8 +1672,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) } if (commit_tree_extended(sb.buf, sb.len, &active_cache_tree->oid, - parents, &oid, author_ident.buf, sign_commit, - extra)) { + parents, &oid, author_ident.buf, NULL, + sign_commit, extra)) { rollback_index_files(); die(_("failed to write commit object")); } @@ -1639,8 +1686,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) die("%s", err.buf); } - unlink(git_path_cherry_pick_head(the_repository)); - unlink(git_path_revert_head(the_repository)); + sequencer_post_commit_cleanup(the_repository, 0); unlink(git_path_merge_head(the_repository)); unlink(git_path_merge_msg(the_repository)); unlink(git_path_merge_mode(the_repository)); @@ -1649,13 +1695,15 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (commit_index_files()) die(_("repository has been updated, but unable to write\n" "new_index file. Check that disk is not full and quota is\n" - "not exceeded, and then \"git reset HEAD\" to recover.")); + "not exceeded, and then \"git restore --staged :/\" to recover.")); - rerere(0); - run_command_v_opt(argv_gc_auto, RUN_GIT_CMD); + git_test_write_commit_graph_or_die(); + + repo_rerere(the_repository, 0); + run_auto_maintenance(quiet); run_commit_hook(use_editor, get_index_file(), "post-commit", NULL); if (amend && !no_post_rewrite) { - commit_post_rewrite(current_head, &oid); + commit_post_rewrite(the_repository, current_head, &oid); } if (!quiet) { unsigned int flags = 0; @@ -1664,9 +1712,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix) flags |= SUMMARY_INITIAL_COMMIT; if (author_date_is_interesting()) flags |= SUMMARY_SHOW_AUTHOR_DATE; - print_commit_summary(prefix, &oid, flags); + print_commit_summary(the_repository, prefix, + &oid, flags); } + apply_autostash(git_path_merge_autostash(the_repository)); + UNLEAK(err); UNLEAK(sb); return 0; |