diff options
Diffstat (limited to 'builtin/commit.c')
-rw-r--r-- | builtin/commit.c | 119 |
1 files changed, 77 insertions, 42 deletions
diff --git a/builtin/commit.c b/builtin/commit.c index 3bcb4b7ec0..d71e1e0c9c 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -45,9 +45,9 @@ static const char implicit_ident_advice[] = " git config --global user.name \"Your Name\"\n" " git config --global user.email you@example.com\n" "\n" -"If the identity used for this commit is wrong, you can fix it with:\n" +"After doing this, you may fix the identity used for this commit with:\n" "\n" -" git commit --amend --author='Your Name <you@example.com>'\n"; +" git commit --amend --reset-author\n"; static const char empty_amend_advice[] = "You asked to amend the most recent commit, but doing so would make\n" @@ -69,6 +69,7 @@ static enum { static const char *logfile, *force_author; static const char *template_file; static char *edit_message, *use_message; +static char *fixup_message, *squash_message; static int all, edit_flag, also, interactive, only, amend, signoff; static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship; static int no_post_rewrite, allow_empty_message; @@ -113,16 +114,18 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset) } static struct option builtin_commit_options[] = { - OPT__QUIET(&quiet), - OPT__VERBOSE(&verbose), + OPT__QUIET(&quiet, "suppress summary after successful commit"), + OPT__VERBOSE(&verbose, "show diff in commit message template"), OPT_GROUP("Commit message options"), - OPT_FILENAME('F', "file", &logfile, "read log from file"), - OPT_STRING(0, "author", &force_author, "AUTHOR", "override author for commit"), - OPT_STRING(0, "date", &force_date, "DATE", "override date for commit"), - OPT_CALLBACK('m', "message", &message, "MESSAGE", "specify commit message", opt_parse_m), - OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit"), - OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"), + OPT_FILENAME('F', "file", &logfile, "read message from file"), + OPT_STRING(0, "author", &force_author, "author", "override author for commit"), + OPT_STRING(0, "date", &force_date, "date", "override date for commit"), + OPT_CALLBACK('m', "message", &message, "message", "commit message", opt_parse_m), + OPT_STRING('c', "reedit-message", &edit_message, "commit", "reuse and edit message from specified commit"), + OPT_STRING('C', "reuse-message", &use_message, "commit", "reuse message from specified commit"), + OPT_STRING(0, "fixup", &fixup_message, "commit", "use autosquash formatted message to fixup specified commit"), + OPT_STRING(0, "squash", &squash_message, "commit", "use autosquash formatted message to squash specified commit"), OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C-c/--amend)"), OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"), OPT_FILENAME('t', "template", &template_file, "use specified template file"), @@ -142,12 +145,12 @@ static struct option builtin_commit_options[] = { STATUS_FORMAT_SHORT), OPT_BOOLEAN(0, "branch", &status_show_branch, "show branch information"), OPT_SET_INT(0, "porcelain", &status_format, - "show porcelain output format", STATUS_FORMAT_PORCELAIN), + "machine-readable output", STATUS_FORMAT_PORCELAIN), OPT_BOOLEAN('z', "null", &null_termination, "terminate entries with NUL"), OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"), OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, "bypass post-rewrite hook"), - { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, + { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, /* end commit contents options */ { OPTION_BOOLEAN, 0, "allow-empty", &allow_empty, NULL, @@ -573,6 +576,25 @@ static int prepare_to_commit(const char *index_file, const char *prefix, if (!no_verify && run_hook(index_file, "pre-commit", NULL)) return 0; + if (squash_message) { + /* + * Insert the proper subject line before other commit + * message options add their content. + */ + if (use_message && !strcmp(use_message, squash_message)) + strbuf_addstr(&sb, "squash! "); + else { + struct pretty_print_context ctx = {0}; + struct commit *c; + c = lookup_commit_reference_by_name(squash_message); + if (!c) + die("could not lookup commit %s", squash_message); + ctx.output_encoding = get_commit_output_encoding(); + format_commit_message(c, "squash! %s\n\n", &sb, + &ctx); + } + } + if (message.len) { strbuf_addbuf(&sb, &message); hook_arg1 = "message"; @@ -594,6 +616,16 @@ static int prepare_to_commit(const char *index_file, const char *prefix, strbuf_add(&sb, buffer + 2, strlen(buffer + 2)); hook_arg1 = "commit"; hook_arg2 = use_message; + } else if (fixup_message) { + struct pretty_print_context ctx = {0}; + struct commit *commit; + commit = lookup_commit_reference_by_name(fixup_message); + if (!commit) + die("could not lookup commit %s", fixup_message); + ctx.output_encoding = get_commit_output_encoding(); + format_commit_message(commit, "fixup! %s\n\n", + &sb, &ctx); + hook_arg1 = "message"; } else if (!stat(git_path("MERGE_MSG"), &statbuf)) { if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0) die_errno("could not read MERGE_MSG"); @@ -602,7 +634,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0) die_errno("could not read SQUASH_MSG"); hook_arg1 = "squash"; - } else if (template_file && !stat(template_file, &statbuf)) { + } else if (template_file) { if (strbuf_read_file(&sb, template_file, 0) < 0) die_errno("could not read '%s'", template_file); hook_arg1 = "template"; @@ -615,6 +647,16 @@ static int prepare_to_commit(const char *index_file, const char *prefix, else if (in_merge) hook_arg1 = "merge"; + if (squash_message) { + /* + * If squash_commit was used for the commit subject, + * then we're possibly hijacking other commit log options. + * Reset the hook args to tell the real story. + */ + hook_arg1 = "message"; + hook_arg2 = ""; + } + fp = fopen(git_path(commit_editmsg), "w"); if (fp == NULL) die_errno("could not open '%s'", git_path(commit_editmsg)); @@ -872,7 +914,7 @@ static int parse_and_validate_options(int argc, const char *argv[], if (force_author && renew_authorship) die("Using both --reset-author and --author does not make sense"); - if (logfile || message.len || use_message) + if (logfile || message.len || use_message || fixup_message) use_editor = 0; if (edit_flag) use_editor = 1; @@ -887,48 +929,35 @@ static int parse_and_validate_options(int argc, const char *argv[], die("You have nothing to amend."); if (amend && in_merge) die("You are in the middle of a merge -- 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 can be used."); + die("Only one of -c/-C/-F/--fixup can be used."); if (message.len && f > 0) - die("Option -m cannot be combined with -c/-C/-F."); + die("Option -m cannot be combined with -c/-C/-F/--fixup."); if (edit_message) use_message = edit_message; - if (amend && !use_message) + if (amend && !use_message && !fixup_message) use_message = "HEAD"; if (!use_message && renew_authorship) die("--reset-author can be used only with -C, -c or --amend."); if (use_message) { - unsigned char sha1[20]; - static char utf8[] = "UTF-8"; const char *out_enc; - char *enc, *end; struct commit *commit; - if (get_sha1(use_message, sha1)) + commit = lookup_commit_reference_by_name(use_message); + if (!commit) die("could not lookup commit %s", use_message); - commit = lookup_commit_reference(sha1); - if (!commit || parse_commit(commit)) - die("could not parse commit %s", use_message); - - enc = strstr(commit->buffer, "\nencoding"); - if (enc) { - end = strchr(enc + 10, '\n'); - enc = xstrndup(enc + 10, end - (enc + 10)); - } else { - enc = utf8; - } - out_enc = git_commit_encoding ? git_commit_encoding : utf8; - - if (strcmp(out_enc, enc)) - use_message_buffer = - reencode_string(commit->buffer, out_enc, enc); + out_enc = get_commit_output_encoding(); + use_message_buffer = logmsg_reencode(commit, out_enc); /* * If we failed to reencode the buffer, just copy it @@ -938,8 +967,6 @@ static int parse_and_validate_options(int argc, const char *argv[], */ if (use_message_buffer == NULL) use_message_buffer = xstrdup(commit->buffer); - if (enc != utf8) - free(enc); } if (!!also + !!only + !!all + !!interactive > 1) @@ -993,6 +1020,8 @@ static int parse_status_slot(const char *var, int offset) { if (!strcasecmp(var+offset, "header")) return WT_STATUS_HEADER; + if (!strcasecmp(var+offset, "branch")) + return WT_STATUS_ONBRANCH; if (!strcasecmp(var+offset, "updated") || !strcasecmp(var+offset, "added")) return WT_STATUS_UPDATED; @@ -1057,13 +1086,13 @@ int cmd_status(int argc, const char **argv, const char *prefix) int fd; unsigned char sha1[20]; static struct option builtin_status_options[] = { - OPT__VERBOSE(&verbose), + OPT__VERBOSE(&verbose, "be verbose"), OPT_SET_INT('s', "short", &status_format, "show status concisely", STATUS_FORMAT_SHORT), OPT_BOOLEAN('b', "branch", &status_show_branch, "show branch information"), OPT_SET_INT(0, "porcelain", &status_format, - "show porcelain output format", + "machine-readable output", STATUS_FORMAT_PORCELAIN), OPT_BOOLEAN('z', "null", &null_termination, "terminate entries with NUL"), @@ -1079,6 +1108,9 @@ int cmd_status(int argc, const char **argv, const char *prefix) OPT_END(), }; + if (argc == 2 && !strcmp(argv[1], "-h")) + usage_with_options(builtin_status_usage, builtin_status_options); + if (null_termination && status_format == STATUS_FORMAT_LONG) status_format = STATUS_FORMAT_PORCELAIN; @@ -1265,6 +1297,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix) int allow_fast_forward = 1; struct wt_status s; + if (argc == 2 && !strcmp(argv[1], "-h")) + usage_with_options(builtin_commit_usage, builtin_commit_options); + wt_status_prepare(&s); git_config(git_commit_config, &s); in_merge = file_exists(git_path("MERGE_HEAD")); |