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>

Phillip Wood committed Nov 24, 2017 at 11:07 UTC e47c6cafcb5a2223ea3de3d0b65f668f717cb2ab
3 files changed +133 -119
builtin/commit.c
+9 -119
@@ -43,31 +43,6 @@ static const char * const builtin_status_usage[] = {
43 NULL
44 };
45
46 -static const char implicit_ident_advice_noconfig[] =
47 -N_("Your name and email address were configured automatically based\n"
48 -"on your username and hostname. Please check that they are accurate.\n"
49 -"You can suppress this message by setting them explicitly. Run the\n"
50 -"following command and follow the instructions in your editor to edit\n"
51 -"your configuration file:\n"
52 -"\n"
53 -" git config --global --edit\n"
54 -"\n"
55 -"After doing this, you may fix the identity used for this commit with:\n"
56 -"\n"
57 -" git commit --amend --reset-author\n");
58 -
59 -static const char implicit_ident_advice_config[] =
60 -N_("Your name and email address were configured automatically based\n"
61 -"on your username and hostname. Please check that they are accurate.\n"
62 -"You can suppress this message by setting them explicitly:\n"
63 -"\n"
64 -" git config --global user.name \"Your Name\"\n"
65 -" git config --global user.email you@example.com\n"
66 -"\n"
67 -"After doing this, you may fix the identity used for this commit with:\n"
68 -"\n"
69 -" git commit --amend --reset-author\n");
70 -
46 static const char empty_amend_advice[] =
47 N_("You asked to amend the most recent commit, but doing so would make\n"
48 "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)
1330 return 0;
1331 }
1332
1358 -static const char *implicit_ident_advice(void)
1359 -{
1360 - char *user_config = expand_user_path("~/.gitconfig", 0);
1361 - char *xdg_config = xdg_config_home("config");
1362 - int config_exists = file_exists(user_config) || file_exists(xdg_config);
1363 -
1364 - free(user_config);
1365 - free(xdg_config);
1366 -
1367 - if (config_exists)
1368 - return _(implicit_ident_advice_config);
1369 - else
1370 - return _(implicit_ident_advice_noconfig);
1371 -
1372 -}
1373 -
1374 -static void print_summary(const char *prefix, const struct object_id *oid,
1375 - int initial_commit)
1376 -{
1377 - struct rev_info rev;
1378 - struct commit *commit;
1379 - struct strbuf format = STRBUF_INIT;
1380 - const char *head;
1381 - struct pretty_print_context pctx = {0};
1382 - struct strbuf author_ident = STRBUF_INIT;
1383 - struct strbuf committer_ident = STRBUF_INIT;
1384 -
1385 - commit = lookup_commit(oid);
1386 - if (!commit)
1387 - die(_("couldn't look up newly created commit"));
1388 - if (parse_commit(commit))
1389 - die(_("could not parse newly created commit"));
1390 -
1391 - strbuf_addstr(&format, "format:%h] %s");
1392 -
1393 - format_commit_message(commit, "%an <%ae>", &author_ident, &pctx);
1394 - format_commit_message(commit, "%cn <%ce>", &committer_ident, &pctx);
1395 - if (strbuf_cmp(&author_ident, &committer_ident)) {
1396 - strbuf_addstr(&format, "\n Author: ");
1397 - strbuf_addbuf_percentquote(&format, &author_ident);
1398 - }
1399 - if (author_date_is_interesting()) {
1400 - struct strbuf date = STRBUF_INIT;
1401 - format_commit_message(commit, "%ad", &date, &pctx);
1402 - strbuf_addstr(&format, "\n Date: ");
1403 - strbuf_addbuf_percentquote(&format, &date);
1404 - strbuf_release(&date);
1405 - }
1406 - if (!committer_ident_sufficiently_given()) {
1407 - strbuf_addstr(&format, "\n Committer: ");
1408 - strbuf_addbuf_percentquote(&format, &committer_ident);
1409 - if (advice_implicit_identity) {
1410 - strbuf_addch(&format, '\n');
1411 - strbuf_addstr(&format, implicit_ident_advice());
1412 - }
1413 - }
1414 - strbuf_release(&author_ident);
1415 - strbuf_release(&committer_ident);
1416 -
1417 - init_revisions(&rev, prefix);
1418 - setup_revisions(0, NULL, &rev, NULL);
1419 -
1420 - rev.diff = 1;
1421 - rev.diffopt.output_format =
1422 - DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
1423 -
1424 - rev.verbose_header = 1;
1425 - rev.show_root_diff = 1;
1426 - get_commit_format(format.buf, &rev);
1427 - rev.always_show_header = 0;
1428 - rev.diffopt.detect_rename = 1;
1429 - rev.diffopt.break_opt = 0;
1430 - diff_setup_done(&rev.diffopt);
1431 -
1432 - head = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
1433 - if (!head)
1434 - die_errno(_("unable to resolve HEAD after creating commit"));
1435 - if (!strcmp(head, "HEAD"))
1436 - head = _("detached HEAD");
1437 - else
1438 - skip_prefix(head, "refs/heads/", &head);
1439 - printf("[%s%s ", head, initial_commit ? _(" (root-commit)") : "");
1440 -
1441 - if (!log_tree_commit(&rev, commit)) {
1442 - rev.always_show_header = 1;
1443 - rev.use_terminator = 1;
1444 - log_tree_commit(&rev, commit);
1445 - }
1446 -
1447 - strbuf_release(&format);
1448 -}
1449 -
1333 static int git_commit_config(const char *k, const char *v, void *cb)
1334 {
1335 struct wt_status *s = cb;
@@ -1708,8 +1591,15 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
1591 if (amend && !no_post_rewrite) {
1592 commit_post_rewrite(current_head, &oid);
1593 }
1711 - if (!quiet)
1712 - print_summary(prefix, &oid, !current_head);
1594 + if (!quiet) {
1595 + unsigned int flags = 0;
1596 +
1597 + if (!current_head)
1598 + flags |= SUMMARY_INITIAL_COMMIT;
1599 + if (author_date_is_interesting())
1600 + flags |= SUMMARY_SHOW_AUTHOR_DATE;
1601 + print_commit_summary(prefix, &oid, flags);
1602 + }
1603
1604 UNLEAK(err);
1605 UNLEAK(sb);
sequencer.c
+119
@@ -836,6 +836,125 @@ void commit_post_rewrite(const struct commit *old_head,
836 run_rewrite_hook(&old_head->object.oid, new_head);
837 }
838
839 +static const char implicit_ident_advice_noconfig[] =
840 +N_("Your name and email address were configured automatically based\n"
841 +"on your username and hostname. Please check that they are accurate.\n"
842 +"You can suppress this message by setting them explicitly. Run the\n"
843 +"following command and follow the instructions in your editor to edit\n"
844 +"your configuration file:\n"
845 +"\n"
846 +" git config --global --edit\n"
847 +"\n"
848 +"After doing this, you may fix the identity used for this commit with:\n"
849 +"\n"
850 +" git commit --amend --reset-author\n");
851 +
852 +static const char implicit_ident_advice_config[] =
853 +N_("Your name and email address were configured automatically based\n"
854 +"on your username and hostname. Please check that they are accurate.\n"
855 +"You can suppress this message by setting them explicitly:\n"
856 +"\n"
857 +" git config --global user.name \"Your Name\"\n"
858 +" git config --global user.email you@example.com\n"
859 +"\n"
860 +"After doing this, you may fix the identity used for this commit with:\n"
861 +"\n"
862 +" git commit --amend --reset-author\n");
863 +
864 +static const char *implicit_ident_advice(void)
865 +{
866 + char *user_config = expand_user_path("~/.gitconfig", 0);
867 + char *xdg_config = xdg_config_home("config");
868 + int config_exists = file_exists(user_config) || file_exists(xdg_config);
869 +
870 + free(user_config);
871 + free(xdg_config);
872 +
873 + if (config_exists)
874 + return _(implicit_ident_advice_config);
875 + else
876 + return _(implicit_ident_advice_noconfig);
877 +
878 +}
879 +
880 +void print_commit_summary(const char *prefix, const struct object_id *oid,
881 + unsigned int flags)
882 +{
883 + struct rev_info rev;
884 + struct commit *commit;
885 + struct strbuf format = STRBUF_INIT;
886 + const char *head;
887 + struct pretty_print_context pctx = {0};
888 + struct strbuf author_ident = STRBUF_INIT;
889 + struct strbuf committer_ident = STRBUF_INIT;
890 +
891 + commit = lookup_commit(oid);
892 + if (!commit)
893 + die(_("couldn't look up newly created commit"));
894 + if (parse_commit(commit))
895 + die(_("could not parse newly created commit"));
896 +
897 + strbuf_addstr(&format, "format:%h] %s");
898 +
899 + format_commit_message(commit, "%an <%ae>", &author_ident, &pctx);
900 + format_commit_message(commit, "%cn <%ce>", &committer_ident, &pctx);
901 + if (strbuf_cmp(&author_ident, &committer_ident)) {
902 + strbuf_addstr(&format, "\n Author: ");
903 + strbuf_addbuf_percentquote(&format, &author_ident);
904 + }
905 + if (flags & SUMMARY_SHOW_AUTHOR_DATE) {
906 + struct strbuf date = STRBUF_INIT;
907 +
908 + format_commit_message(commit, "%ad", &date, &pctx);
909 + strbuf_addstr(&format, "\n Date: ");
910 + strbuf_addbuf_percentquote(&format, &date);
911 + strbuf_release(&date);
912 + }
913 + if (!committer_ident_sufficiently_given()) {
914 + strbuf_addstr(&format, "\n Committer: ");
915 + strbuf_addbuf_percentquote(&format, &committer_ident);
916 + if (advice_implicit_identity) {
917 + strbuf_addch(&format, '\n');
918 + strbuf_addstr(&format, implicit_ident_advice());
919 + }
920 + }
921 + strbuf_release(&author_ident);
922 + strbuf_release(&committer_ident);
923 +
924 + init_revisions(&rev, prefix);
925 + setup_revisions(0, NULL, &rev, NULL);
926 +
927 + rev.diff = 1;
928 + rev.diffopt.output_format =
929 + DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
930 +
931 + rev.verbose_header = 1;
932 + rev.show_root_diff = 1;
933 + get_commit_format(format.buf, &rev);
934 + rev.always_show_header = 0;
935 + rev.diffopt.detect_rename = 1;
936 + rev.diffopt.break_opt = 0;
937 + diff_setup_done(&rev.diffopt);
938 +
939 + head = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
940 + if (!head)
941 + die_errno(_("unable to resolve HEAD after creating commit"));
942 + if (!strcmp(head, "HEAD"))
943 + head = _("detached HEAD");
944 + else
945 + skip_prefix(head, "refs/heads/", &head);
946 + printf("[%s%s ", head, (flags & SUMMARY_INITIAL_COMMIT) ?
947 + _(" (root-commit)") : "");
948 +
949 + if (!log_tree_commit(&rev, commit)) {
950 + rev.always_show_header = 1;
951 + rev.use_terminator = 1;
952 + log_tree_commit(&rev, commit);
953 + }
954 +
955 + strbuf_release(&format);
956 +}
957 +
958 static int is_original_commit_empty(struct commit *commit)
959 {
960 const struct object_id *ptree_oid;
sequencer.h
+5
@@ -75,4 +75,9 @@ int update_head_with_reflog(const struct commit *old_head,
75 struct strbuf *err);
76 void commit_post_rewrite(const struct commit *current_head,
77 const struct object_id *new_head);
78 +
79 +#define SUMMARY_INITIAL_COMMIT (1 << 0)
80 +#define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)
81 +void print_commit_summary(const char *prefix, const struct object_id *oid,
82 + unsigned int flags);
83 #endif