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:
parent
a87a6f3c98
commit
e47c6cafcb
128
builtin/commit.c
128
builtin/commit.c
@ -43,31 +43,6 @@ static const char * const builtin_status_usage[] = {
|
|||||||
NULL
|
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[] =
|
static const char empty_amend_advice[] =
|
||||||
N_("You asked to amend the most recent commit, but doing so would make\n"
|
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"
|
"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;
|
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)
|
static int git_commit_config(const char *k, const char *v, void *cb)
|
||||||
{
|
{
|
||||||
struct wt_status *s = 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) {
|
if (amend && !no_post_rewrite) {
|
||||||
commit_post_rewrite(current_head, &oid);
|
commit_post_rewrite(current_head, &oid);
|
||||||
}
|
}
|
||||||
if (!quiet)
|
if (!quiet) {
|
||||||
print_summary(prefix, &oid, !current_head);
|
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(err);
|
||||||
UNLEAK(sb);
|
UNLEAK(sb);
|
||||||
|
119
sequencer.c
119
sequencer.c
@ -836,6 +836,125 @@ void commit_post_rewrite(const struct commit *old_head,
|
|||||||
run_rewrite_hook(&old_head->object.oid, new_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)
|
static int is_original_commit_empty(struct commit *commit)
|
||||||
{
|
{
|
||||||
const struct object_id *ptree_oid;
|
const struct object_id *ptree_oid;
|
||||||
|
@ -75,4 +75,9 @@ int update_head_with_reflog(const struct commit *old_head,
|
|||||||
struct strbuf *err);
|
struct strbuf *err);
|
||||||
void commit_post_rewrite(const struct commit *current_head,
|
void commit_post_rewrite(const struct commit *current_head,
|
||||||
const struct object_id *new_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
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user