diff options
Diffstat (limited to 'builtin/commit.c')
-rw-r--r-- | builtin/commit.c | 163 |
1 files changed, 89 insertions, 74 deletions
diff --git a/builtin/commit.c b/builtin/commit.c index 883c16256c..06b1330346 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -37,14 +37,22 @@ #include "help.h" #include "commit-reach.h" #include "commit-graph.h" +#include "pretty.h" static const char * const builtin_commit_usage[] = { - N_("git commit [<options>] [--] <pathspec>..."), + N_("git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]\n" + " [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>)]\n" + " [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n" + " [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n" + " [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n" + " [-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]\n" + " [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n" + " [--] [<pathspec>...]"), NULL }; static const char * const builtin_status_usage[] = { - N_("git status [<options>] [--] <pathspec>..."), + N_("git status [<options>] [--] [<pathspec>...]"), NULL }; @@ -138,7 +146,7 @@ static int opt_pass_trailer(const struct option *opt, const char *arg, int unset { BUG_ON_OPT_NEG(unset); - strvec_pushl(&trailer_args, "--trailer", arg, NULL); + strvec_pushl(opt->value, "--trailer", arg, NULL); return 0; } @@ -264,8 +272,8 @@ static int list_paths(struct string_list *list, const char *with_tree, /* TODO: audit for interaction with sparse-index. */ ensure_full_index(&the_index); - for (i = 0; i < active_nr; i++) { - const struct cache_entry *ce = active_cache[i]; + for (i = 0; i < the_index.cache_nr; i++) { + const struct cache_entry *ce = the_index.cache[i]; struct string_list_item *item; if (ce->ce_flags & CE_UPDATE) @@ -294,10 +302,10 @@ static void add_remove_files(struct string_list *list) continue; if (!lstat(p->string, &st)) { - if (add_to_cache(p->string, &st, 0)) + if (add_to_index(&the_index, p->string, &st, 0)) die(_("updating files failed")); } else - remove_file_from_cache(p->string); + remove_file_from_index(&the_index, p->string); } } @@ -308,7 +316,7 @@ static void create_base_index(const struct commit *current_head) struct tree_desc t; if (!current_head) { - discard_cache(); + discard_index(&the_index); return; } @@ -335,7 +343,7 @@ static void refresh_cache_or_die(int refresh_flags) * refresh_flags contains REFRESH_QUIET, so the only errors * are for unmerged entries. */ - if (refresh_cache(refresh_flags | REFRESH_IN_PORCELAIN)) + if (refresh_index(&the_index, refresh_flags | REFRESH_IN_PORCELAIN, NULL, NULL, NULL)) die_resolve_conflict("commit"); } @@ -355,31 +363,32 @@ static const char *prepare_index(const char **argv, const char *prefix, if (pathspec_from_file) { if (interactive) - die(_("--pathspec-from-file is incompatible with --interactive/--patch")); + die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--interactive/--patch"); if (all) - die(_("--pathspec-from-file with -a does not make sense")); + die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "-a"); if (pathspec.nr) - die(_("--pathspec-from-file is incompatible with pathspec arguments")); + die(_("'%s' and pathspec arguments cannot be used together"), "--pathspec-from-file"); 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")); + die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file"); } if (!pathspec.nr && (also || (only && !allow_empty && (!amend || (fixup_message && strcmp(fixup_prefix, "amend")))))) die(_("No paths with --include/--only does not make sense.")); - if (read_cache_preload(&pathspec) < 0) + if (repo_read_index_preload(the_repository, &pathspec, 0) < 0) die(_("index file corrupt")); if (interactive) { char *old_index_env = NULL, *old_repo_index_file; - hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR); + repo_hold_locked_index(the_repository, &index_lock, + LOCK_DIE_ON_ERROR); refresh_cache_or_die(refresh_flags); @@ -402,8 +411,9 @@ static const char *prepare_index(const char **argv, const char *prefix, unsetenv(INDEX_ENVIRONMENT); FREE_AND_NULL(old_index_env); - discard_cache(); - read_cache_from(get_lock_file_path(&index_lock)); + discard_index(&the_index); + read_index_from(&the_index, get_lock_file_path(&index_lock), + get_git_dir()); if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) { if (reopen_lock_file(&index_lock) < 0) die(_("unable to write index file")); @@ -430,7 +440,8 @@ static const char *prepare_index(const char **argv, const char *prefix, * (B) on failure, rollback the real index. */ if (all || (also && pathspec.nr)) { - hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR); + repo_hold_locked_index(the_repository, &index_lock, + LOCK_DIE_ON_ERROR); add_files_to_cache(also ? prefix : NULL, &pathspec, 0); refresh_cache_or_die(refresh_flags); update_main_cache_tree(WRITE_TREE_SILENT); @@ -451,10 +462,11 @@ static const char *prepare_index(const char **argv, const char *prefix, * We still need to refresh the index here. */ if (!only && !pathspec.nr) { - hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR); + repo_hold_locked_index(the_repository, &index_lock, + LOCK_DIE_ON_ERROR); refresh_cache_or_die(refresh_flags); - if (active_cache_changed - || !cache_tree_fully_valid(active_cache_tree)) + if (the_index.cache_changed + || !cache_tree_fully_valid(the_index.cache_tree)) update_main_cache_tree(WRITE_TREE_SILENT); if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK | SKIP_IF_UNCHANGED)) @@ -497,13 +509,13 @@ static const char *prepare_index(const char **argv, const char *prefix, if (list_paths(&partial, !current_head ? NULL : "HEAD", &pathspec)) exit(1); - discard_cache(); - if (read_cache() < 0) + discard_index(&the_index); + if (repo_read_index(the_repository) < 0) die(_("cannot read the index")); - hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR); + repo_hold_locked_index(the_repository, &index_lock, LOCK_DIE_ON_ERROR); add_remove_files(&partial); - refresh_cache(REFRESH_QUIET); + refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL); update_main_cache_tree(WRITE_TREE_SILENT); if (write_locked_index(&the_index, &index_lock, 0)) die(_("unable to write new_index file")); @@ -515,14 +527,14 @@ static const char *prepare_index(const char **argv, const char *prefix, create_base_index(current_head); add_remove_files(&partial); - refresh_cache(REFRESH_QUIET); + refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL); if (write_locked_index(&the_index, &false_lock, 0)) die(_("unable to write temporary index file")); - discard_cache(); + discard_index(&the_index); ret = get_lock_file_path(&false_lock); - read_cache_from(ret); + read_index_from(&the_index, ret, get_git_dir()); out: string_list_clear(&partial, 0); clear_pathspec(&pathspec); @@ -725,11 +737,13 @@ static int prepare_to_commit(const char *index_file, const char *prefix, int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE); int old_display_comment_prefix; int merge_contains_scissors = 0; + int invoked_hook; /* This checks and barfs if author is badly specified */ determine_author_info(author_ident); - if (!no_verify && run_commit_hook(use_editor, index_file, "pre-commit", NULL)) + if (!no_verify && run_commit_hook(use_editor, index_file, &invoked_hook, + "pre-commit", NULL)) return 0; if (squash_message) { @@ -799,7 +813,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, if (!strcmp(fixup_prefix, "amend")) { if (have_option_m) - die(_("cannot combine -m with --fixup:%s"), fixup_message); + die(_("options '%s' and '%s:%s' cannot be used together"), "-m", "--fixup", fixup_message); prepare_amend_commit(commit, &sb, &ctx); } } else if (!stat(git_path_merge_msg(the_repository), &statbuf)) { @@ -858,7 +872,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, } s->fp = fopen_for_writing(git_path_commit_editmsg()); - if (s->fp == NULL) + if (!s->fp) die_errno(_("could not open '%s'"), git_path_commit_editmsg()); /* Ignore status.displayCommentPrefix: we do need comments in COMMIT_EDITMSG. */ @@ -988,10 +1002,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix, /* TODO: audit for interaction with sparse-index. */ ensure_full_index(&the_index); - for (i = 0; i < active_nr; i++) - if (ce_intent_to_add(active_cache[i])) + for (i = 0; i < the_index.cache_nr; i++) + if (ce_intent_to_add(the_index.cache[i])) ita_nr++; - committable = active_nr - ita_nr > 0; + committable = the_index.cache_nr - ita_nr > 0; } else { /* * Unless the user did explicitly request a submodule @@ -1052,22 +1066,22 @@ static int prepare_to_commit(const char *index_file, const char *prefix, return 0; } - if (!no_verify && hook_exists("pre-commit")) { + if (!no_verify && invoked_hook) { /* - * Re-read the index as pre-commit hook could have updated it, - * and write it out as a tree. We must do this before we invoke + * Re-read the index as the pre-commit-commit hook was invoked + * and could have updated it. We must do this before we invoke * the editor and after we invoke run_status above. */ - discard_cache(); + discard_index(&the_index); } - read_cache_from(index_file); + read_index_from(&the_index, index_file, get_git_dir()); if (update_main_cache_tree(0)) { error(_("Error building trees")); return 0; } - if (run_commit_hook(use_editor, index_file, "prepare-commit-msg", + if (run_commit_hook(use_editor, index_file, NULL, "prepare-commit-msg", git_path_commit_editmsg(), hook_arg1, hook_arg2, NULL)) return 0; @@ -1084,7 +1098,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix, } if (!no_verify && - run_commit_hook(use_editor, index_file, "commit-msg", git_path_commit_editmsg(), NULL)) { + run_commit_hook(use_editor, index_file, NULL, "commit-msg", + git_path_commit_editmsg(), NULL)) { return 0; } @@ -1096,7 +1111,6 @@ static const char *find_author_by_nickname(const char *name) struct rev_info revs; struct commit *commit; struct strbuf buf = STRBUF_INIT; - struct string_list mailmap = STRING_LIST_INIT_NODUP; const char *av[20]; int ac = 0; @@ -1107,7 +1121,8 @@ static const char *find_author_by_nickname(const char *name) av[++ac] = buf.buf; av[++ac] = NULL; setup_revisions(ac, av, &revs, NULL); - revs.mailmap = &mailmap; + revs.mailmap = xmalloc(sizeof(struct string_list)); + string_list_init_nodup(revs.mailmap); read_mailmap(revs.mailmap); if (prepare_revision_walk(&revs)) @@ -1118,7 +1133,7 @@ static const char *find_author_by_nickname(const char *name) ctx.date_mode.type = DATE_NORMAL; strbuf_release(&buf); format_commit_message(commit, "%aN <%aE>", &buf, &ctx); - clear_mailmap(&mailmap); + release_revisions(&revs); return strbuf_detach(&buf, NULL); } die(_("--author '%s' is not 'Name <email>' and matches no existing author"), name); @@ -1193,7 +1208,7 @@ static void finalize_deferred_config(struct wt_status *s) status_format == STATUS_FORMAT_UNSPECIFIED) status_format = STATUS_FORMAT_PORCELAIN; else if (status_format == STATUS_FORMAT_LONG) - die(_("--long and -z are incompatible")); + die(_("options '%s' and '%s' cannot be used together"), "--long", "-z"); } if (use_deferred_config && status_format == STATUS_FORMAT_UNSPECIFIED) @@ -1229,9 +1244,10 @@ static void check_fixup_reword_options(int argc, const char *argv[]) { die(_("You are in the middle of a cherry-pick -- cannot reword.")); } if (argc) - die(_("cannot combine reword option of --fixup with path '%s'"), *argv); + die(_("reword option of '%s' and path '%s' cannot be used together"), "--fixup", *argv); if (patch_interactive || interactive || all || also || only) - die(_("reword option of --fixup is mutually exclusive with --patch/--interactive/--all/--include/--only")); + die(_("reword option of '%s' and '%s' cannot be used together"), + "--fixup", "--patch/--interactive/--all/--include/--only"); } static int parse_and_validate_options(int argc, const char *argv[], @@ -1241,8 +1257,6 @@ static int parse_and_validate_options(int argc, const char *argv[], struct commit *current_head, struct wt_status *s) { - int f = 0; - argc = parse_options(argc, argv, prefix, options, usage, 0); finalize_deferred_config(s); @@ -1250,7 +1264,7 @@ static int parse_and_validate_options(int argc, const char *argv[], force_author = find_author_by_nickname(force_author); if (force_author && renew_authorship) - die(_("Using both --reset-author and --author does not make sense")); + die(_("options '%s' and '%s' cannot be used together"), "--reset-author", "--author"); if (logfile || have_option_m || use_message) use_editor = 0; @@ -1267,20 +1281,16 @@ static int parse_and_validate_options(int argc, const char *argv[], 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")); - if (use_message) - f++; - if (edit_message) - f++; - if (fixup_message) - f++; - if (logfile) - f++; - if (f > 1) - die(_("Only one of -c/-C/-F/--fixup can be used.")); - if (have_option_m && (edit_message || use_message || logfile)) - die((_("Option -m cannot be combined with -c/-C/-F."))); - if (f || have_option_m) + die(_("options '%s' and '%s' cannot be used together"), "--squash", "--fixup"); + die_for_incompatible_opt4(!!use_message, "-C", + !!edit_message, "-c", + !!logfile, "-F", + !!fixup_message, "--fixup"); + die_for_incompatible_opt4(have_option_m, "-m", + !!edit_message, "-c", + !!use_message, "-C", + !!logfile, "-F"); + if (use_message || edit_message || logfile ||fixup_message || have_option_m) template_file = NULL; if (edit_message) use_message = edit_message; @@ -1305,9 +1315,10 @@ static int parse_and_validate_options(int argc, const char *argv[], if (patch_interactive) interactive = 1; - if (also + only + all + interactive > 1) - die(_("Only one of --include/--only/--all/--interactive/--patch can be used.")); - + die_for_incompatible_opt4(also, "-i/--include", + only, "-o/--only", + all, "-a/--all", + interactive, "--interactive/-p/--patch"); if (fixup_message) { /* * We limit --fixup's suboptions to only alpha characters. @@ -1549,7 +1560,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) &s.pathspec, NULL, NULL); if (use_optional_locks()) - fd = hold_locked_index(&index_lock, 0); + fd = repo_hold_locked_index(the_repository, &index_lock, 0); else fd = -1; @@ -1633,7 +1644,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) OPT_STRING(0, "fixup", &fixup_message, N_("[(amend|reword):]commit"), N_("use autosquash formatted message to fixup or amend/reword 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_CALLBACK_F(0, "trailer", NULL, N_("trailer"), N_("add custom trailer(s)"), PARSE_OPT_NONEG, opt_pass_trailer), + OPT_CALLBACK_F(0, "trailer", &trailer_args, N_("trailer"), N_("add custom trailer(s)"), PARSE_OPT_NONEG, opt_pass_trailer), 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")), @@ -1687,6 +1698,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) struct commit *current_head = NULL; struct commit_extra_header *extra = NULL; struct strbuf err = STRBUF_INIT; + int ret = 0; if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(builtin_commit_usage, builtin_commit_options); @@ -1721,8 +1733,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix) running hooks, writing the trees, and interacting with the user. */ if (!prepare_to_commit(index_file, prefix, current_head, &s, &author_ident)) { + ret = 1; rollback_index_files(); - return 1; + goto cleanup; } /* Determine parents */ @@ -1814,13 +1827,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix) append_merge_tag_headers(parents, &tail); } - if (commit_tree_extended(sb.buf, sb.len, &active_cache_tree->oid, + if (commit_tree_extended(sb.buf, sb.len, &the_index.cache_tree->oid, parents, &oid, author_ident.buf, NULL, sign_commit, extra)) { rollback_index_files(); die(_("failed to write commit object")); } - strbuf_release(&author_ident); free_commit_extra_headers(extra); if (update_head_with_reflog(current_head, &oid, reflog_msg, &sb, @@ -1844,7 +1856,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) repo_rerere(the_repository, 0); run_auto_maintenance(quiet); - run_commit_hook(use_editor, get_index_file(), "post-commit", NULL); + run_commit_hook(use_editor, get_index_file(), NULL, "post-commit", + NULL); if (amend && !no_post_rewrite) { commit_post_rewrite(the_repository, current_head, &oid); } @@ -1861,7 +1874,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix) apply_autostash(git_path_merge_autostash(the_repository)); +cleanup: + UNLEAK(author_ident); UNLEAK(err); UNLEAK(sb); - return 0; + return ret; } |