commit: move print_commit_summary() to libgit

Move print_commit_summary() from builtin/commit.c to sequencer.c so it
can be shared with other commands. The function is modified by
changing the last argument to a flag so callers can specify whether
they want to show the author date in addition to specifying if this is
an initial commit.

If the sequencer dies in print_commit_summary() (which can only happen
when cherry-picking or reverting) then neither the todo list nor the
abort safety file are updated to reflect the commit that was just
made. print_commit_summary() can die if:

 - The commit that was just created cannot be found or parsed.

 - HEAD cannot be resolved either because some other process is
   updating it (which is bad news in the middle of a cherry-pick) or
   because it is corrupt.

 - log_tree_commit() cannot read some objects.

In all those cases dying will leave the sequencer in a sane state for
aborting; 'git cherry-pick --abort' will rewind HEAD to the last
successful commit before there was a problem with HEAD or the object
database. If the user somehow fixes the problem and runs 'git
cherry-pick --continue' then the sequencer will try and pick the same
commit again which may or may not be what the user wants depending on
what caused print_commit_summary() to die. If print_commit_summary()
returned an error instead then update_abort_safety_file() would try to
resolve HEAD which may or may not be successful. If it is successful
then running 'git rebase --abort' would not rewind HEAD to the last
successful commit which is not what we want.

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Phillip Wood 2017-11-24 11:07:54 +00:00 committed by Junio C Hamano
parent a87a6f3c98
commit e47c6cafcb
3 changed files with 133 additions and 119 deletions

View file

@ -43,31 +43,6 @@ static const char * const builtin_status_usage[] = {
NULL
};
static const char implicit_ident_advice_noconfig[] =
N_("Your name and email address were configured automatically based\n"
"on your username and hostname. Please check that they are accurate.\n"
"You can suppress this message by setting them explicitly. Run the\n"
"following command and follow the instructions in your editor to edit\n"
"your configuration file:\n"
"\n"
" git config --global --edit\n"
"\n"
"After doing this, you may fix the identity used for this commit with:\n"
"\n"
" git commit --amend --reset-author\n");
static const char implicit_ident_advice_config[] =
N_("Your name and email address were configured automatically based\n"
"on your username and hostname. Please check that they are accurate.\n"
"You can suppress this message by setting them explicitly:\n"
"\n"
" git config --global user.name \"Your Name\"\n"
" git config --global user.email you@example.com\n"
"\n"
"After doing this, you may fix the identity used for this commit with:\n"
"\n"
" git commit --amend --reset-author\n");
static const char empty_amend_advice[] =
N_("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"
@ -1355,98 +1330,6 @@ int cmd_status(int argc, const char **argv, const char *prefix)
return 0;
}
static const char *implicit_ident_advice(void)
{
char *user_config = expand_user_path("~/.gitconfig", 0);
char *xdg_config = xdg_config_home("config");
int config_exists = file_exists(user_config) || file_exists(xdg_config);
free(user_config);
free(xdg_config);
if (config_exists)
return _(implicit_ident_advice_config);
else
return _(implicit_ident_advice_noconfig);
}
static void print_summary(const char *prefix, const struct object_id *oid,
int initial_commit)
{
struct rev_info rev;
struct commit *commit;
struct strbuf format = STRBUF_INIT;
const char *head;
struct pretty_print_context pctx = {0};
struct strbuf author_ident = STRBUF_INIT;
struct strbuf committer_ident = STRBUF_INIT;
commit = lookup_commit(oid);
if (!commit)
die(_("couldn't look up newly created commit"));
if (parse_commit(commit))
die(_("could not parse newly created commit"));
strbuf_addstr(&format, "format:%h] %s");
format_commit_message(commit, "%an <%ae>", &author_ident, &pctx);
format_commit_message(commit, "%cn <%ce>", &committer_ident, &pctx);
if (strbuf_cmp(&author_ident, &committer_ident)) {
strbuf_addstr(&format, "\n Author: ");
strbuf_addbuf_percentquote(&format, &author_ident);
}
if (author_date_is_interesting()) {
struct strbuf date = STRBUF_INIT;
format_commit_message(commit, "%ad", &date, &pctx);
strbuf_addstr(&format, "\n Date: ");
strbuf_addbuf_percentquote(&format, &date);
strbuf_release(&date);
}
if (!committer_ident_sufficiently_given()) {
strbuf_addstr(&format, "\n Committer: ");
strbuf_addbuf_percentquote(&format, &committer_ident);
if (advice_implicit_identity) {
strbuf_addch(&format, '\n');
strbuf_addstr(&format, implicit_ident_advice());
}
}
strbuf_release(&author_ident);
strbuf_release(&committer_ident);
init_revisions(&rev, prefix);
setup_revisions(0, NULL, &rev, NULL);
rev.diff = 1;
rev.diffopt.output_format =
DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
rev.verbose_header = 1;
rev.show_root_diff = 1;
get_commit_format(format.buf, &rev);
rev.always_show_header = 0;
rev.diffopt.detect_rename = 1;
rev.diffopt.break_opt = 0;
diff_setup_done(&rev.diffopt);
head = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
if (!head)
die_errno(_("unable to resolve HEAD after creating commit"));
if (!strcmp(head, "HEAD"))
head = _("detached HEAD");
else
skip_prefix(head, "refs/heads/", &head);
printf("[%s%s ", head, initial_commit ? _(" (root-commit)") : "");
if (!log_tree_commit(&rev, commit)) {
rev.always_show_header = 1;
rev.use_terminator = 1;
log_tree_commit(&rev, commit);
}
strbuf_release(&format);
}
static int git_commit_config(const char *k, const char *v, void *cb)
{
struct wt_status *s = cb;
@ -1708,8 +1591,15 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (amend && !no_post_rewrite) {
commit_post_rewrite(current_head, &oid);
}
if (!quiet)
print_summary(prefix, &oid, !current_head);
if (!quiet) {
unsigned int flags = 0;
if (!current_head)
flags |= SUMMARY_INITIAL_COMMIT;
if (author_date_is_interesting())
flags |= SUMMARY_SHOW_AUTHOR_DATE;
print_commit_summary(prefix, &oid, flags);
}
UNLEAK(err);
UNLEAK(sb);

View file

@ -836,6 +836,125 @@ void commit_post_rewrite(const struct commit *old_head,
run_rewrite_hook(&old_head->object.oid, new_head);
}
static const char implicit_ident_advice_noconfig[] =
N_("Your name and email address were configured automatically based\n"
"on your username and hostname. Please check that they are accurate.\n"
"You can suppress this message by setting them explicitly. Run the\n"
"following command and follow the instructions in your editor to edit\n"
"your configuration file:\n"
"\n"
" git config --global --edit\n"
"\n"
"After doing this, you may fix the identity used for this commit with:\n"
"\n"
" git commit --amend --reset-author\n");
static const char implicit_ident_advice_config[] =
N_("Your name and email address were configured automatically based\n"
"on your username and hostname. Please check that they are accurate.\n"
"You can suppress this message by setting them explicitly:\n"
"\n"
" git config --global user.name \"Your Name\"\n"
" git config --global user.email you@example.com\n"
"\n"
"After doing this, you may fix the identity used for this commit with:\n"
"\n"
" git commit --amend --reset-author\n");
static const char *implicit_ident_advice(void)
{
char *user_config = expand_user_path("~/.gitconfig", 0);
char *xdg_config = xdg_config_home("config");
int config_exists = file_exists(user_config) || file_exists(xdg_config);
free(user_config);
free(xdg_config);
if (config_exists)
return _(implicit_ident_advice_config);
else
return _(implicit_ident_advice_noconfig);
}
void print_commit_summary(const char *prefix, const struct object_id *oid,
unsigned int flags)
{
struct rev_info rev;
struct commit *commit;
struct strbuf format = STRBUF_INIT;
const char *head;
struct pretty_print_context pctx = {0};
struct strbuf author_ident = STRBUF_INIT;
struct strbuf committer_ident = STRBUF_INIT;
commit = lookup_commit(oid);
if (!commit)
die(_("couldn't look up newly created commit"));
if (parse_commit(commit))
die(_("could not parse newly created commit"));
strbuf_addstr(&format, "format:%h] %s");
format_commit_message(commit, "%an <%ae>", &author_ident, &pctx);
format_commit_message(commit, "%cn <%ce>", &committer_ident, &pctx);
if (strbuf_cmp(&author_ident, &committer_ident)) {
strbuf_addstr(&format, "\n Author: ");
strbuf_addbuf_percentquote(&format, &author_ident);
}
if (flags & SUMMARY_SHOW_AUTHOR_DATE) {
struct strbuf date = STRBUF_INIT;
format_commit_message(commit, "%ad", &date, &pctx);
strbuf_addstr(&format, "\n Date: ");
strbuf_addbuf_percentquote(&format, &date);
strbuf_release(&date);
}
if (!committer_ident_sufficiently_given()) {
strbuf_addstr(&format, "\n Committer: ");
strbuf_addbuf_percentquote(&format, &committer_ident);
if (advice_implicit_identity) {
strbuf_addch(&format, '\n');
strbuf_addstr(&format, implicit_ident_advice());
}
}
strbuf_release(&author_ident);
strbuf_release(&committer_ident);
init_revisions(&rev, prefix);
setup_revisions(0, NULL, &rev, NULL);
rev.diff = 1;
rev.diffopt.output_format =
DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
rev.verbose_header = 1;
rev.show_root_diff = 1;
get_commit_format(format.buf, &rev);
rev.always_show_header = 0;
rev.diffopt.detect_rename = 1;
rev.diffopt.break_opt = 0;
diff_setup_done(&rev.diffopt);
head = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
if (!head)
die_errno(_("unable to resolve HEAD after creating commit"));
if (!strcmp(head, "HEAD"))
head = _("detached HEAD");
else
skip_prefix(head, "refs/heads/", &head);
printf("[%s%s ", head, (flags & SUMMARY_INITIAL_COMMIT) ?
_(" (root-commit)") : "");
if (!log_tree_commit(&rev, commit)) {
rev.always_show_header = 1;
rev.use_terminator = 1;
log_tree_commit(&rev, commit);
}
strbuf_release(&format);
}
static int is_original_commit_empty(struct commit *commit)
{
const struct object_id *ptree_oid;

View file

@ -75,4 +75,9 @@ int update_head_with_reflog(const struct commit *old_head,
struct strbuf *err);
void commit_post_rewrite(const struct commit *current_head,
const struct object_id *new_head);
#define SUMMARY_INITIAL_COMMIT (1 << 0)
#define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)
void print_commit_summary(const char *prefix, const struct object_id *oid,
unsigned int flags);
#endif