"\n"
" git commit --amend --author='Your Name <you@example.com>'\n";
+static const char empty_amend_advice[] =
+"You asked to amend the most recent commit, but doing so would make\n"
+"it empty. You can repeat your command with --allow-empty, or you can\n"
+"remove the commit entirely with \"git reset HEAD^\".\n";
+
static unsigned char head_sha1[20];
static char *use_message_buffer;
static enum {
COMMIT_AS_IS = 1,
COMMIT_NORMAL,
- COMMIT_PARTIAL,
+ COMMIT_PARTIAL
} commit_style;
static const char *logfile, *force_author;
static char *author_name, *author_email, *author_date;
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;
-static char *untracked_files_arg, *force_date;
+static int no_post_rewrite, allow_empty_message;
+static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
/*
* The default commit message cleanup mode will remove the lines
* beginning with # (shell comments) and leading and trailing
static enum {
CLEANUP_SPACE,
CLEANUP_NONE,
- CLEANUP_ALL,
+ CLEANUP_ALL
} cleanup_mode;
static char *cleanup_arg;
static int use_editor = 1, initial_commit, in_merge, include_status = 1;
+static int show_ignored_in_status;
static const char *only_include_assumed;
static struct strbuf message;
static enum {
STATUS_FORMAT_LONG,
STATUS_FORMAT_SHORT,
- STATUS_FORMAT_PORCELAIN,
+ STATUS_FORMAT_PORCELAIN
} status_format = STATUS_FORMAT_LONG;
+static int status_show_branch;
static int opt_parse_m(const struct option *opt, const char *arg, int unset)
{
OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"),
OPT_SET_INT(0, "short", &status_format, "show status concisely",
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),
OPT_BOOLEAN('z', "null", &null_termination,
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" },
- OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"),
/* end commit contents options */
+ { OPTION_BOOLEAN, 0, "allow-empty", &allow_empty, NULL,
+ "ok to record an empty change",
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
+ { OPTION_BOOLEAN, 0, "allow-empty-message", &allow_empty_message, NULL,
+ "ok to record a change with an empty message",
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
+
OPT_END()
};
continue;
if (!match_pathspec(pattern, ce->name, ce_namelen(ce), 0, m))
continue;
- item = string_list_insert(ce->name, list);
+ item = string_list_insert(list, ce->name);
if (ce_skip_worktree(ce))
item->util = item; /* better a valid pointer than a fake one */
}
switch (status_format) {
case STATUS_FORMAT_SHORT:
- wt_shortstatus_print(s, null_termination);
+ wt_shortstatus_print(s, null_termination, status_show_branch);
break;
case STATUS_FORMAT_PORCELAIN:
wt_porcelain_print(s, null_termination);
if (!a)
die("invalid commit: %s", use_message);
- lb = strstr(a + 8, " <");
- rb = strstr(a + 8, "> ");
- eol = strchr(a + 8, '\n');
- if (!lb || !rb || !eol)
+ lb = strchrnul(a + strlen("\nauthor "), '<');
+ rb = strchrnul(lb, '>');
+ eol = strchrnul(rb, '\n');
+ if (!*lb || !*rb || !*eol)
die("invalid commit: %s", use_message);
- name = xstrndup(a + 8, lb - (a + 8));
- email = xstrndup(lb + 2, rb - (lb + 2));
- date = xstrndup(rb + 2, eol - (rb + 2));
+ if (lb == a + strlen("\nauthor "))
+ /* \nauthor <foo@example.com> */
+ name = xcalloc(1, 1);
+ else
+ name = xmemdupz(a + strlen("\nauthor "),
+ (lb - strlen(" ") -
+ (a + strlen("\nauthor "))));
+ email = xmemdupz(lb + strlen("<"), rb - (lb + strlen("<")));
+ date = xmemdupz(rb + strlen("> "), eol - (rb + strlen("> ")));
}
if (force_author) {
if (!commitable && !in_merge && !allow_empty &&
!(amend && is_a_merge(head_sha1))) {
run_status(stdout, index_file, prefix, 0, s);
+ if (amend)
+ fputs(empty_amend_advice, stderr);
return 0;
}
if (use_editor) {
char index[PATH_MAX];
- const char *env[2] = { index, NULL };
+ const char *env[2] = { NULL };
+ env[0] = index;
snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
if (launch_editor(git_path(commit_editmsg), NULL, env)) {
fprintf(stderr,
OPT__VERBOSE(&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",
STATUS_FORMAT_PORCELAIN),
"mode",
"show untracked files, optional modes: all, normal, no. (Default: all)",
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
+ OPT_BOOLEAN(0, "ignored", &show_ignored_in_status,
+ "show ignored files"),
+ { OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, "when",
+ "ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)",
+ PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
OPT_END(),
};
builtin_status_options,
builtin_status_usage, 0);
handle_untracked_files_arg(&s);
-
+ if (show_ignored_in_status)
+ s.show_ignored_files = 1;
if (*argv)
s.pathspec = get_pathspec(prefix, argv);
s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;
s.in_merge = in_merge;
+ s.ignore_submodule_arg = ignore_submodule_arg;
wt_status_collect(&s);
if (s.relative_paths)
switch (status_format) {
case STATUS_FORMAT_SHORT:
- wt_shortstatus_print(&s, null_termination);
+ wt_shortstatus_print(&s, null_termination, status_show_branch);
break;
case STATUS_FORMAT_PORCELAIN:
wt_porcelain_print(&s, null_termination);
break;
case STATUS_FORMAT_LONG:
s.verbose = verbose;
+ s.ignore_submodule_arg = ignore_submodule_arg;
wt_status_print(&s);
break;
}
initial_commit ? " (root-commit)" : "");
if (!log_tree_commit(&rev, commit)) {
- struct pretty_print_context ctx = {0};
- struct strbuf buf = STRBUF_INIT;
- ctx.date_mode = DATE_NORMAL;
- format_commit_message(commit, format.buf + 7, &buf, &ctx);
- printf("%s\n", buf.buf);
- strbuf_release(&buf);
+ rev.always_show_header = 1;
+ rev.use_terminator = 1;
+ log_tree_commit(&rev, commit);
}
+
strbuf_release(&format);
}
}
/* Determine parents */
+ reflog_msg = getenv("GIT_REFLOG_ACTION");
if (initial_commit) {
- reflog_msg = "commit (initial)";
+ if (!reflog_msg)
+ reflog_msg = "commit (initial)";
} else if (amend) {
struct commit_list *c;
struct commit *commit;
- reflog_msg = "commit (amend)";
+ if (!reflog_msg)
+ reflog_msg = "commit (amend)";
commit = lookup_commit(head_sha1);
if (!commit || parse_commit(commit))
die("could not parse HEAD commit");
struct strbuf m = STRBUF_INIT;
FILE *fp;
- reflog_msg = "commit (merge)";
+ if (!reflog_msg)
+ reflog_msg = "commit (merge)";
pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next;
fp = fopen(git_path("MERGE_HEAD"), "r");
if (fp == NULL)
if (allow_fast_forward)
parents = reduce_heads(parents);
} else {
- reflog_msg = "commit";
+ if (!reflog_msg)
+ reflog_msg = "commit";
pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next;
}
if (cleanup_mode != CLEANUP_NONE)
stripspace(&sb, cleanup_mode == CLEANUP_ALL);
- if (message_is_empty(&sb)) {
+ if (message_is_empty(&sb) && !allow_empty_message) {
rollback_index_files();
fprintf(stderr, "Aborting commit due to empty commit message.\n");
exit(1);