"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
"the remaining commits.\n");
+static GIT_PATH_FUNC(git_path_commit_editmsg, "COMMIT_EDITMSG")
+
static const char *use_message_buffer;
-static const char commit_editmsg[] = "COMMIT_EDITMSG";
static struct lock_file index_lock; /* real index */
static struct lock_file false_lock; /* used only for partial commits */
static enum {
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 char *untracked_files_arg, *force_date, *ignore_submodule_arg;
static char *sign_commit;
static const char *only_include_assumed;
static struct strbuf message = STRBUF_INIT;
-static enum status_format {
- STATUS_FORMAT_NONE = 0,
- STATUS_FORMAT_LONG,
- STATUS_FORMAT_SHORT,
- STATUS_FORMAT_PORCELAIN,
+static enum wt_status_format status_format = STATUS_FORMAT_UNSPECIFIED;
- STATUS_FORMAT_UNSPECIFIED
-} status_format = STATUS_FORMAT_UNSPECIFIED;
+static int opt_parse_porcelain(const struct option *opt, const char *arg, int unset)
+{
+ enum wt_status_format *value = (enum wt_status_format *)opt->value;
+ if (unset)
+ *value = STATUS_FORMAT_NONE;
+ else if (!arg)
+ *value = STATUS_FORMAT_PORCELAIN;
+ else if (!strcmp(arg, "v1") || !strcmp(arg, "1"))
+ *value = STATUS_FORMAT_PORCELAIN;
+ else if (!strcmp(arg, "v2") || !strcmp(arg, "2"))
+ *value = STATUS_FORMAT_PORCELAIN_V2;
+ else
+ die("unsupported porcelain version '%s'", arg);
+
+ return 0;
+}
static int opt_parse_m(const struct option *opt, const char *arg, int unset)
{
whence = FROM_MERGE;
else if (file_exists(git_path_cherry_pick_head())) {
whence = FROM_CHERRY_PICK;
- if (file_exists(git_path(SEQ_DIR)))
+ if (file_exists(git_path_seq_dir()))
sequencer_in_use = 1;
}
else
gitmodules_config();
git_config(fn, s);
determine_whence(s);
+ init_diff_ui_defaults();
s->hints = advice_status_hints; /* must come after git_config() */
}
if (interactive) {
char *old_index_env = NULL;
- hold_locked_index(&index_lock, 1);
+ hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
refresh_cache_or_die(refresh_flags);
* (B) on failure, rollback the real index.
*/
if (all || (also && pathspec.nr)) {
- hold_locked_index(&index_lock, 1);
+ hold_locked_index(&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);
* We still need to refresh the index here.
*/
if (!only && !pathspec.nr) {
- hold_locked_index(&index_lock, 1);
+ hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
refresh_cache_or_die(refresh_flags);
if (active_cache_changed
|| !cache_tree_fully_valid(active_cache_tree))
if (read_cache() < 0)
die(_("cannot read the index"));
- hold_locked_index(&index_lock, 1);
+ hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
add_remove_files(&partial);
refresh_cache(REFRESH_QUIET);
update_main_cache_tree(WRITE_TREE_SILENT);
s->fp = fp;
s->nowarn = nowarn;
s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0;
+ if (!s->is_initial)
+ hashcpy(s->sha1_commit, sha1);
+ s->status_format = status_format;
+ s->ignore_submodule_arg = ignore_submodule_arg;
wt_status_collect(s);
-
- switch (status_format) {
- case STATUS_FORMAT_SHORT:
- wt_shortstatus_print(s);
- break;
- case STATUS_FORMAT_PORCELAIN:
- wt_porcelain_print(s);
- break;
- case STATUS_FORMAT_UNSPECIFIED:
- die("BUG: finalize_deferred_config() should have been called");
- break;
- case STATUS_FORMAT_NONE:
- case STATUS_FORMAT_LONG:
- wt_status_print(s);
- break;
- }
+ wt_status_print(s);
return s->commitable;
}
}
}
- if (message.len) {
+ if (have_option_m) {
strbuf_addbuf(&sb, &message);
hook_arg1 = "message";
} else if (logfile && !strcmp(logfile, "-")) {
char *buffer;
buffer = strstr(use_message_buffer, "\n\n");
if (buffer)
- strbuf_addstr(&sb, buffer + 2);
+ strbuf_addstr(&sb, skip_blank_lines(buffer + 2));
hook_arg1 = "commit";
hook_arg2 = use_message;
} else if (fixup_message) {
&sb, &ctx);
hook_arg1 = "message";
} else if (!stat(git_path_merge_msg(), &statbuf)) {
+ /*
+ * prepend SQUASH_MSG here if it exists and a
+ * "merge --squash" was originally performed
+ */
+ if (!stat(git_path_squash_msg(), &statbuf)) {
+ if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0)
+ die_errno(_("could not read SQUASH_MSG"));
+ hook_arg1 = "squash";
+ } else
+ hook_arg1 = "merge";
if (strbuf_read_file(&sb, git_path_merge_msg(), 0) < 0)
die_errno(_("could not read MERGE_MSG"));
- hook_arg1 = "merge";
} else if (!stat(git_path_squash_msg(), &statbuf)) {
if (strbuf_read_file(&sb, git_path_squash_msg(), 0) < 0)
die_errno(_("could not read SQUASH_MSG"));
hook_arg2 = "";
}
- s->fp = fopen_for_writing(git_path(commit_editmsg));
+ s->fp = fopen_for_writing(git_path_commit_editmsg());
if (s->fp == NULL)
- die_errno(_("could not open '%s'"), git_path(commit_editmsg));
+ die_errno(_("could not open '%s'"), git_path_commit_editmsg());
/* Ignore status.displayCommentPrefix: we do need comments in COMMIT_EDITMSG. */
old_display_comment_prefix = s->display_comment_prefix;
strbuf_stripspace(&sb, 0);
if (signoff)
- append_signoff(&sb, ignore_non_trailer(&sb), 0);
+ append_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0);
if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
die_errno(_("could not write commit template"));
if (amend)
parent = "HEAD^1";
- if (get_sha1(parent, sha1))
- commitable = !!active_nr;
- else {
+ if (get_sha1(parent, sha1)) {
+ int i, ita_nr = 0;
+
+ for (i = 0; i < active_nr; i++)
+ if (ce_intent_to_add(active_cache[i]))
+ ita_nr++;
+ commitable = active_nr - ita_nr > 0;
+ } else {
/*
* Unless the user did explicitly request a submodule
* ignore mode by passing a command line option we do
if (ignore_submodule_arg &&
!strcmp(ignore_submodule_arg, "all"))
diff_flags |= DIFF_OPT_IGNORE_SUBMODULES;
- commitable = index_differs_from(parent, diff_flags);
+ commitable = index_differs_from(parent, diff_flags, 1);
}
}
strbuf_release(&committer_ident);
}
if (run_commit_hook(use_editor, index_file, "prepare-commit-msg",
- git_path(commit_editmsg), hook_arg1, hook_arg2, NULL))
+ git_path_commit_editmsg(), hook_arg1, hook_arg2, NULL))
return 0;
if (use_editor) {
- char index[PATH_MAX];
- 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)) {
+ struct argv_array env = ARGV_ARRAY_INIT;
+
+ argv_array_pushf(&env, "GIT_INDEX_FILE=%s", index_file);
+ if (launch_editor(git_path_commit_editmsg(), NULL, env.argv)) {
fprintf(stderr,
_("Please supply the message using either -m or -F option.\n"));
exit(1);
}
+ argv_array_clear(&env);
}
if (!no_verify &&
- run_commit_hook(use_editor, index_file, "commit-msg", git_path(commit_editmsg), NULL)) {
+ run_commit_hook(use_editor, index_file, "commit-msg", git_path_commit_editmsg(), NULL)) {
return 0;
}
* is not in effect here.
*/
static struct status_deferred_config {
- enum status_format status_format;
+ enum wt_status_format status_format;
int show_branch;
} status_deferred_config = {
STATUS_FORMAT_UNSPECIFIED,
static void finalize_deferred_config(struct wt_status *s)
{
int use_deferred_config = (status_format != STATUS_FORMAT_PORCELAIN &&
+ status_format != STATUS_FORMAT_PORCELAIN_V2 &&
!s->null_termination);
if (s->null_termination) {
f++;
if (f > 1)
die(_("Only one of -c/-C/-F/--fixup can be used."));
- if (message.len && f > 0)
+ if (have_option_m && f > 0)
die((_("Option -m cannot be combined with -c/-C/-F/--fixup.")));
- if (f || message.len)
+ if (f || have_option_m)
template_file = NULL;
if (edit_message)
use_message = edit_message;
if (also + only + all + interactive > 1)
die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
- if (argc == 0 && (also || (only && !amend)))
+ if (argc == 0 && (also || (only && !amend && !allow_empty)))
die(_("No paths with --include/--only does not make sense."));
- if (argc == 0 && only && amend)
- only_include_assumed = _("Clever... amending the last one with dirty index.");
if (argc > 0 && !also && !only)
only_include_assumed = _("Explicit paths specified without -i or -o; assuming --only paths...");
if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
N_("show status concisely"), STATUS_FORMAT_SHORT),
OPT_BOOL('b', "branch", &s.show_branch,
N_("show branch information")),
- OPT_SET_INT(0, "porcelain", &status_format,
- N_("machine-readable output"),
- STATUS_FORMAT_PORCELAIN),
+ { OPTION_CALLBACK, 0, "porcelain", &status_format,
+ N_("version"), N_("machine-readable output"),
+ PARSE_OPT_OPTARG, opt_parse_porcelain },
OPT_SET_INT(0, "long", &status_format,
N_("show status in long format (default)"),
STATUS_FORMAT_LONG),
fd = hold_locked_index(&index_lock, 0);
s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;
+ if (!s.is_initial)
+ hashcpy(s.sha1_commit, sha1);
+
s.ignore_submodule_arg = ignore_submodule_arg;
+ s.status_format = status_format;
+ s.verbose = verbose;
+
wt_status_collect(&s);
if (0 <= fd)
if (s.relative_paths)
s.prefix = prefix;
- switch (status_format) {
- case STATUS_FORMAT_SHORT:
- wt_shortstatus_print(&s);
- break;
- case STATUS_FORMAT_PORCELAIN:
- wt_porcelain_print(&s);
- break;
- case STATUS_FORMAT_UNSPECIFIED:
- die("BUG: finalize_deferred_config() should have been called");
- break;
- case STATUS_FORMAT_NONE:
- case STATUS_FORMAT_LONG:
- s.verbose = verbose;
- s.ignore_submodule_arg = ignore_submodule_arg;
- wt_status_print(&s);
- break;
- }
+ wt_status_print(&s);
return 0;
}
sign_commit = git_config_bool(k, v) ? "" : NULL;
return 0;
}
+ if (!strcmp(k, "commit.verbose")) {
+ int is_bool;
+ config_commit_verbose = git_config_bool_or_int(k, v, &is_bool);
+ return 0;
+ }
status = git_gpg_config(k, v, NULL);
if (status)
static int run_rewrite_hook(const unsigned char *oldsha1,
const unsigned char *newsha1)
{
- /* oldsha1 SP newsha1 LF NUL */
- static char buf[2*40 + 3];
struct child_process proc = CHILD_PROCESS_INIT;
const char *argv[3];
int code;
- size_t n;
+ struct strbuf sb = STRBUF_INIT;
argv[0] = find_hook("post-rewrite");
if (!argv[0])
code = start_command(&proc);
if (code)
return code;
- n = snprintf(buf, sizeof(buf), "%s %s\n",
- sha1_to_hex(oldsha1), sha1_to_hex(newsha1));
+ strbuf_addf(&sb, "%s %s\n", sha1_to_hex(oldsha1), sha1_to_hex(newsha1));
sigchain_push(SIGPIPE, SIG_IGN);
- write_in_full(proc.in, buf, n);
+ write_in_full(proc.in, sb.buf, sb.len);
close(proc.in);
+ strbuf_release(&sb);
sigchain_pop(SIGPIPE);
return finish_command(&proc);
}
int run_commit_hook(int editor_is_used, const char *index_file, const char *name, ...)
{
- const char *hook_env[3] = { NULL };
- char index[PATH_MAX];
+ struct argv_array hook_env = ARGV_ARRAY_INIT;
va_list args;
int ret;
- snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
- hook_env[0] = index;
+ 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)
- hook_env[1] = "GIT_EDITOR=:";
+ argv_array_push(&hook_env, "GIT_EDITOR=:");
va_start(args, name);
- ret = run_hook_ve(hook_env, name, args);
+ ret = run_hook_ve(hook_env.argv,name, args);
va_end(args);
+ argv_array_clear(&hook_env);
return ret;
}
OPT_BOOL(0, "interactive", &interactive, N_("interactively add files")),
OPT_BOOL('p', "patch", &patch_interactive, N_("interactively add changes")),
OPT_BOOL('o', "only", &only, N_("commit only specified files")),
- OPT_BOOL('n', "no-verify", &no_verify, N_("bypass pre-commit hook")),
+ OPT_BOOL('n', "no-verify", &no_verify, N_("bypass pre-commit and commit-msg hooks")),
OPT_BOOL(0, "dry-run", &dry_run, N_("show what would be committed")),
OPT_SET_INT(0, "short", &status_format, N_("show status concisely"),
STATUS_FORMAT_SHORT),
const char *index_file, *reflog_msg;
char *nl;
unsigned char sha1[20];
- struct commit_list *parents = NULL, **pptr = &parents;
+ struct commit_list *parents = NULL;
struct stat statbuf;
struct commit *current_head = NULL;
struct commit_extra_header *extra = NULL;
if (parse_commit(current_head))
die(_("could not parse HEAD commit"));
}
+ verbose = -1; /* unspecified */
argc = parse_and_validate_options(argc, argv, builtin_commit_options,
builtin_commit_usage,
prefix, current_head, &s);
+ if (verbose == -1)
+ 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);
if (!reflog_msg)
reflog_msg = "commit (initial)";
} else if (amend) {
- struct commit_list *c;
-
if (!reflog_msg)
reflog_msg = "commit (amend)";
- for (c = current_head->parents; c; c = c->next)
- pptr = &commit_list_insert(c->item, pptr)->next;
+ parents = copy_commit_list(current_head->parents);
} else if (whence == FROM_MERGE) {
struct strbuf m = STRBUF_INIT;
FILE *fp;
int allow_fast_forward = 1;
+ struct commit_list **pptr = &parents;
if (!reflog_msg)
reflog_msg = "commit (merge)";
- pptr = &commit_list_insert(current_head, pptr)->next;
+ pptr = commit_list_append(current_head, pptr);
fp = fopen(git_path_merge_head(), "r");
if (fp == NULL)
die_errno(_("could not open '%s' for reading"),
git_path_merge_head());
- while (strbuf_getline(&m, fp, '\n') != EOF) {
+ while (strbuf_getline_lf(&m, fp) != EOF) {
struct commit *parent;
parent = get_merge_parent(m.buf);
if (!parent)
die(_("Corrupt MERGE_HEAD file (%s)"), m.buf);
- pptr = &commit_list_insert(parent, pptr)->next;
+ pptr = commit_list_append(parent, pptr);
}
fclose(fp);
strbuf_release(&m);
reflog_msg = (whence == FROM_CHERRY_PICK)
? "commit (cherry-pick)"
: "commit";
- pptr = &commit_list_insert(current_head, pptr)->next;
+ commit_list_insert(current_head, &parents);
}
/* Finally, get the commit message */
strbuf_reset(&sb);
- if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) {
+ if (strbuf_read_file(&sb, git_path_commit_editmsg(), 0) < 0) {
int saved_errno = errno;
rollback_index_files();
die(_("could not read commit message: %s"), strerror(saved_errno));