void shortlog_add_commit(struct shortlog *log, struct commit *commit) { struct strbuf author = STRBUF_INIT; struct strbuf oneline = STRBUF_INIT; struct pretty_print_context ctx = {0}; const char *fmt; ctx.fmt = CMIT_FMT_USERFORMAT; ctx.abbrev = log->abbrev; ctx.print_email_subject = 1; ctx.date_mode.type = DATE_NORMAL; ctx.output_encoding = get_log_output_encoding(); fmt = log->committer ? (log->email ? "%cN <%cE>" : "%cN") : (log->email ? "%aN <%aE>" : "%aN"); format_commit_message(commit, fmt, &author, &ctx); if (!log->summary) { if (log->user_format) pretty_print_commit(&ctx, commit, &oneline); else format_commit_message(commit, "%s", &oneline, &ctx); } insert_one_record(log, author.buf, oneline.len ? oneline.buf : "<none>"); strbuf_release(&author); strbuf_release(&oneline); }
static void format_subst(const struct commit *commit, const char *src, size_t len, struct strbuf *buf) { char *to_free = NULL; struct strbuf fmt; if (src == buf->buf) to_free = strbuf_detach(buf, NULL); strbuf_init(&fmt, 0); for (;;) { const char *b, *c; b = memmem(src, len, "$Format:", 8); if (!b) break; c = memchr(b + 8, '$', (src + len) - b - 8); if (!c) break; strbuf_reset(&fmt); strbuf_add(&fmt, b + 8, c - b - 8); strbuf_add(buf, src, b - src); format_commit_message(commit, fmt.buf, buf); len -= c + 1 - src; src = c + 1; } strbuf_add(buf, src, len); strbuf_release(&fmt); free(to_free); }
static void print_submodule_summary(struct rev_info *rev, FILE *f, const char *del, const char *add, const char *reset) { static const char format[] = " %m %s"; struct strbuf sb = STRBUF_INIT; struct commit *commit; while ((commit = get_revision(rev))) { struct pretty_print_context ctx = {0}; ctx.date_mode = rev->date_mode; strbuf_setlen(&sb, 0); if (commit->object.flags & SYMMETRIC_LEFT) { if (del) strbuf_addstr(&sb, del); } else if (add) strbuf_addstr(&sb, add); format_commit_message(commit, format, &sb, &ctx); if (reset) strbuf_addstr(&sb, reset); strbuf_addch(&sb, '\n'); fprintf(f, "%s", sb.buf); } strbuf_release(&sb); }
static void format_subst(const struct commit *commit, const char *src, size_t len, struct strbuf *buf) { char *to_free = NULL; struct strbuf fmt = STRBUF_INIT; struct pretty_print_context ctx = {0}; ctx.date_mode = DATE_NORMAL; ctx.abbrev = DEFAULT_ABBREV; if (src == buf->buf) to_free = strbuf_detach(buf, NULL); for (;;) { const char *b, *c; b = memmem(src, len, "$Format:", 8); if (!b) break; c = memchr(b + 8, '$', (src + len) - b - 8); if (!c) break; strbuf_reset(&fmt); strbuf_add(&fmt, b + 8, c - b - 8); strbuf_add(buf, src, b - src); format_commit_message(commit, fmt.buf, buf, &ctx); len -= c + 1 - src; src = c + 1; } strbuf_add(buf, src, len); strbuf_release(&fmt); free(to_free); }
static const char *find_author_by_nickname(const char *name) { struct rev_info revs; struct commit *commit; struct strbuf buf = STRBUF_INIT; struct string_list mailmap = STRING_LIST_INIT_NODUP; const char *av[20]; int ac = 0; init_revisions(&revs, NULL); strbuf_addf(&buf, "--author=%s", name); av[++ac] = "--all"; av[++ac] = "-i"; av[++ac] = buf.buf; av[++ac] = NULL; setup_revisions(ac, av, &revs, NULL); revs.mailmap = &mailmap; read_mailmap(revs.mailmap, NULL); prepare_revision_walk(&revs); commit = get_revision(&revs); if (commit) { struct pretty_print_context ctx = {0}; ctx.date_mode = DATE_NORMAL; strbuf_release(&buf); format_commit_message(commit, "%aN <%aE>", &buf, &ctx); clear_mailmap(&mailmap); return strbuf_detach(&buf, NULL); } die(_("No existing author found with '%s'"), name); }
static int notes_cache_match_validity(struct repository *r, const char *ref, const char *validity) { struct object_id oid; struct commit *commit; struct pretty_print_context pretty_ctx; struct strbuf msg = STRBUF_INIT; int ret; if (read_ref(ref, &oid) < 0) return 0; commit = lookup_commit_reference_gently(r, &oid, 1); if (!commit) return 0; memset(&pretty_ctx, 0, sizeof(pretty_ctx)); format_commit_message(commit, "%s", &msg, &pretty_ctx); strbuf_trim(&msg); ret = !strcmp(msg.buf, validity); strbuf_release(&msg); return ret; }
static void print_commit(struct commit *commit) { struct strbuf sb = STRBUF_INIT; struct pretty_print_context ctx = {0}; ctx.date_mode = DATE_NORMAL; format_commit_message(commit, " %h: %m %s", &sb, &ctx); fprintf(stderr, "%s\n", sb.buf); strbuf_release(&sb); }
void fmt_output_commit(struct strbuf *filename, struct commit *commit, struct rev_info *info) { struct pretty_print_context ctx = {0}; struct strbuf subject = STRBUF_INIT; format_commit_message(commit, "%f", &subject, &ctx); fmt_output_subject(filename, subject.buf, info); strbuf_release(&subject); }
static int merge_commit(struct notes_merge_options *o) { struct strbuf msg = STRBUF_INIT; unsigned char sha1[20], parent_sha1[20]; struct notes_tree *t; struct commit *partial; struct pretty_print_context pretty_ctx; void *local_ref_to_free; int ret; /* * Read partial merge result from .git/NOTES_MERGE_PARTIAL, * and target notes ref from .git/NOTES_MERGE_REF. */ if (get_sha1("NOTES_MERGE_PARTIAL", sha1)) die("Failed to read ref NOTES_MERGE_PARTIAL"); else if (!(partial = lookup_commit_reference(sha1))) die("Could not find commit from NOTES_MERGE_PARTIAL."); else if (parse_commit(partial)) die("Could not parse commit from NOTES_MERGE_PARTIAL."); if (partial->parents) hashcpy(parent_sha1, partial->parents->item->object.sha1); else hashclr(parent_sha1); t = xcalloc(1, sizeof(struct notes_tree)); init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0); o->local_ref = local_ref_to_free = resolve_refdup("NOTES_MERGE_REF", 0, sha1, NULL); if (!o->local_ref) die("Failed to resolve NOTES_MERGE_REF"); if (notes_merge_commit(o, t, partial, sha1)) die("Failed to finalize notes merge"); /* Reuse existing commit message in reflog message */ memset(&pretty_ctx, 0, sizeof(pretty_ctx)); format_commit_message(partial, "%s", &msg, &pretty_ctx); strbuf_trim(&msg); strbuf_insert(&msg, 0, "notes: ", 7); update_ref(msg.buf, o->local_ref, sha1, is_null_sha1(parent_sha1) ? NULL : parent_sha1, 0, UPDATE_REFS_DIE_ON_ERR); free_notes(t); strbuf_release(&msg); ret = merge_abort(o); free(local_ref_to_free); return ret; }
static void log_commit(FILE *fp, char *fmt, const char *state, struct commit *commit) { struct pretty_print_context pp = {0}; struct strbuf commit_msg = STRBUF_INIT; char *label = xstrfmt(fmt, state); format_commit_message(commit, "%s", &commit_msg, &pp); fprintf(fp, "# %s: [%s] %s\n", label, oid_to_hex(&commit->object.oid), commit_msg.buf); strbuf_release(&commit_msg); free(label); }
void get_patch_filename(struct commit *commit, int nr, const char *suffix, struct strbuf *buf) { int suffix_len = strlen(suffix) + 1; int start_len = buf->len; strbuf_addf(buf, commit ? "%04d-" : "%d", nr); if (commit) { int max_len = start_len + FORMAT_PATCH_NAME_MAX - suffix_len; format_commit_message(commit, "%f", buf, DATE_NORMAL); if (max_len < buf->len) strbuf_setlen(buf, max_len); strbuf_addstr(buf, suffix); } }
static void print_summary(const char *prefix, const unsigned char *sha1) { struct rev_info rev; struct commit *commit; static const char *format = "format:%h: \"%s\""; unsigned char junk_sha1[20]; const char *head = resolve_ref("HEAD", junk_sha1, 0, NULL); commit = lookup_commit(sha1); if (!commit) die("couldn't look up newly created commit"); if (!commit || parse_commit(commit)) die("could not parse newly created commit"); init_revisions(&rev, prefix); setup_revisions(0, NULL, &rev, NULL); rev.abbrev = 0; 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, &rev); rev.always_show_header = 0; rev.diffopt.detect_rename = 1; rev.diffopt.rename_limit = 100; rev.diffopt.break_opt = 0; diff_setup_done(&rev.diffopt); printf("[%s%s]: created ", !prefixcmp(head, "refs/heads/") ? head + 11 : !strcmp(head, "HEAD") ? "detached HEAD" : head, initial_commit ? " (root-commit)" : ""); if (!log_tree_commit(&rev, commit)) { struct strbuf buf = STRBUF_INIT; format_commit_message(commit, format + 7, &buf, DATE_NORMAL); printf("%s\n", buf.buf); strbuf_release(&buf); } }
void get_patch_filename(struct commit *commit, const char *subject, int nr, const char *suffix, struct strbuf *buf) { int suffix_len = strlen(suffix) + 1; int start_len = buf->len; strbuf_addf(buf, commit || subject ? "%04d-" : "%d", nr); if (commit || subject) { int max_len = start_len + FORMAT_PATCH_NAME_MAX - suffix_len; struct pretty_print_context ctx = {0}; if (subject) strbuf_addstr(buf, subject); else if (commit) format_commit_message(commit, "%f", buf, &ctx); if (max_len < buf->len) strbuf_setlen(buf, max_len); strbuf_addstr(buf, suffix); } }
static void print_summary(const char *prefix, const unsigned char *sha1) { struct rev_info rev; struct commit *commit; commit = lookup_commit(sha1); if (!commit) die("couldn't look up newly created commit"); if (!commit || parse_commit(commit)) die("could not parse newly created commit"); init_revisions(&rev, prefix); setup_revisions(0, NULL, &rev, NULL); rev.abbrev = 0; 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:%h: %s", &rev); rev.always_show_header = 0; rev.diffopt.detect_rename = 1; rev.diffopt.rename_limit = 100; rev.diffopt.break_opt = 0; diff_setup_done(&rev.diffopt); printf("Created %scommit ", initial_commit ? "initial " : ""); if (!log_tree_commit(&rev, commit)) { struct strbuf buf = STRBUF_INIT; format_commit_message(commit, "%h: %s", &buf); printf("%s\n", buf.buf); strbuf_release(&buf); } }
static int notes_cache_match_validity(const char *ref, const char *validity) { unsigned char sha1[20]; struct commit *commit; struct pretty_print_context pretty_ctx; struct strbuf msg = STRBUF_INIT; int ret; if (read_ref(ref, sha1) < 0) return 0; commit = lookup_commit_reference_gently(sha1, 1); if (!commit) return 0; memset(&pretty_ctx, 0, sizeof(pretty_ctx)); format_commit_message(commit, "%s", &msg, &pretty_ctx); strbuf_trim(&msg); ret = !strcmp(msg.buf, validity); strbuf_release(&msg); return ret; }
static const char *find_author_by_nickname(const char *name) { struct rev_info revs; struct commit *commit; struct strbuf buf = STRBUF_INIT; const char *av[20]; int ac = 0; init_revisions(&revs, NULL); strbuf_addf(&buf, "--author=%s", name); av[++ac] = "--all"; av[++ac] = "-i"; av[++ac] = buf.buf; av[++ac] = NULL; setup_revisions(ac, av, &revs, NULL); prepare_revision_walk(&revs); commit = get_revision(&revs); if (commit) { strbuf_release(&buf); format_commit_message(commit, "%an <%ae>", &buf, DATE_NORMAL); return strbuf_detach(&buf, NULL); } die("No existing author found with '%s'", name); }
static int prepare_to_commit(const char *index_file, const char *prefix, struct commit *current_head, struct wt_status *s, struct strbuf *author_ident) { struct stat statbuf; struct strbuf committer_ident = STRBUF_INIT; int commitable; struct strbuf sb = STRBUF_INIT; const char *hook_arg1 = NULL; const char *hook_arg2 = NULL; int clean_message_contents = (cleanup_mode != CLEANUP_NONE); int old_display_comment_prefix; /* This checks and barfs if author is badly specified */ determine_author_info(author_ident); if (!no_verify && run_hook(index_file, "pre-commit", NULL)) return 0; if (squash_message) { /* * Insert the proper subject line before other commit * message options add their content. */ if (use_message && !strcmp(use_message, squash_message)) strbuf_addstr(&sb, "squash! "); else { struct pretty_print_context ctx = {0}; struct commit *c; c = lookup_commit_reference_by_name(squash_message); if (!c) die(_("could not lookup commit %s"), squash_message); ctx.output_encoding = get_commit_output_encoding(); format_commit_message(c, "squash! %s\n\n", &sb, &ctx); } } if (message.len) { strbuf_addbuf(&sb, &message); hook_arg1 = "message"; } else if (logfile && !strcmp(logfile, "-")) { if (isatty(0)) fprintf(stderr, _("(reading log message from standard input)\n")); if (strbuf_read(&sb, 0, 0) < 0) die_errno(_("could not read log from standard input")); hook_arg1 = "message"; } else if (logfile) { if (strbuf_read_file(&sb, logfile, 0) < 0) die_errno(_("could not read log file '%s'"), logfile); hook_arg1 = "message"; } else if (use_message) { char *buffer; buffer = strstr(use_message_buffer, "\n\n"); if (!use_editor && (!buffer || buffer[2] == '\0')) die(_("commit has empty message")); strbuf_add(&sb, buffer + 2, strlen(buffer + 2)); hook_arg1 = "commit"; hook_arg2 = use_message; } else if (fixup_message) { struct pretty_print_context ctx = {0}; struct commit *commit; commit = lookup_commit_reference_by_name(fixup_message); if (!commit) die(_("could not lookup commit %s"), fixup_message); ctx.output_encoding = get_commit_output_encoding(); format_commit_message(commit, "fixup! %s\n\n", &sb, &ctx); hook_arg1 = "message"; } else if (!stat(git_path("MERGE_MSG"), &statbuf)) { 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_arg1 = "squash"; } else if (template_file) { if (strbuf_read_file(&sb, template_file, 0) < 0) die_errno(_("could not read '%s'"), template_file); hook_arg1 = "template"; clean_message_contents = 0; } /* * The remaining cases don't modify the template message, but * just set the argument(s) to the prepare-commit-msg hook. */ else if (whence == FROM_MERGE) hook_arg1 = "merge"; else if (whence == FROM_CHERRY_PICK) { hook_arg1 = "commit"; hook_arg2 = "CHERRY_PICK_HEAD"; } if (squash_message) { /* * If squash_commit was used for the commit subject, * then we're possibly hijacking other commit log options. * Reset the hook args to tell the real story. */ hook_arg1 = "message"; hook_arg2 = ""; } s->fp = fopen(git_path(commit_editmsg), "w"); if (s->fp == NULL) 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; s->display_comment_prefix = 1; /* * Most hints are counter-productive when the commit has * already started. */ s->hints = 0; if (clean_message_contents) stripspace(&sb, 0); if (signoff) { /* * See if we have a Conflicts: block at the end. If yes, count * its size, so we can ignore it. */ int ignore_footer = 0; int i, eol, previous = 0; const char *nl; for (i = 0; i < sb.len; i++) { nl = memchr(sb.buf + i, '\n', sb.len - i); if (nl) eol = nl - sb.buf; else eol = sb.len; if (starts_with(sb.buf + previous, "\nConflicts:\n")) { ignore_footer = sb.len - previous; break; } while (i < eol) i++; previous = eol; } append_signoff(&sb, ignore_footer, 0); } if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len) die_errno(_("could not write commit template")); strbuf_release(&sb); /* This checks if committer ident is explicitly given */ strbuf_addstr(&committer_ident, git_committer_info(IDENT_STRICT)); if (use_editor && include_status) { int ident_shown = 0; int saved_color_setting; char *ai_tmp, *ci_tmp; if (whence != FROM_COMMIT) status_printf_ln(s, GIT_COLOR_NORMAL, whence == FROM_MERGE ? _("\n" "It looks like you may be committing a merge.\n" "If this is not correct, please remove the file\n" " %s\n" "and try again.\n") : _("\n" "It looks like you may be committing a cherry-pick.\n" "If this is not correct, please remove the file\n" " %s\n" "and try again.\n"), git_path(whence == FROM_MERGE ? "MERGE_HEAD" : "CHERRY_PICK_HEAD")); fprintf(s->fp, "\n"); if (cleanup_mode == CLEANUP_ALL) status_printf(s, GIT_COLOR_NORMAL, _("Please enter the commit message for your changes." " Lines starting\nwith '%c' will be ignored, and an empty" " message aborts the commit.\n"), comment_line_char); else /* CLEANUP_SPACE, that is. */ status_printf(s, GIT_COLOR_NORMAL, _("Please enter the commit message for your changes." " Lines starting\n" "with '%c' will be kept; you may remove them" " yourself if you want to.\n" "An empty message aborts the commit.\n"), comment_line_char); if (only_include_assumed) status_printf_ln(s, GIT_COLOR_NORMAL, "%s", only_include_assumed); ai_tmp = cut_ident_timestamp_part(author_ident->buf); ci_tmp = cut_ident_timestamp_part(committer_ident.buf); if (strcmp(author_ident->buf, committer_ident.buf)) status_printf_ln(s, GIT_COLOR_NORMAL, _("%s" "Author: %s"), ident_shown++ ? "" : "\n", author_ident->buf); if (!committer_ident_sufficiently_given()) status_printf_ln(s, GIT_COLOR_NORMAL, _("%s" "Committer: %s"), ident_shown++ ? "" : "\n", committer_ident.buf); if (ident_shown) status_printf_ln(s, GIT_COLOR_NORMAL, ""); saved_color_setting = s->use_color; s->use_color = 0; commitable = run_status(s->fp, index_file, prefix, 1, s); s->use_color = saved_color_setting; *ai_tmp = ' '; *ci_tmp = ' '; } else { unsigned char sha1[20]; const char *parent = "HEAD"; if (!active_nr && read_cache() < 0) die(_("Cannot read index")); if (amend) parent = "HEAD^1"; if (get_sha1(parent, sha1)) commitable = !!active_nr; else commitable = index_differs_from(parent, 0); } strbuf_release(&committer_ident); fclose(s->fp); /* * Reject an attempt to record a non-merge empty commit without * explicit --allow-empty. In the cherry-pick case, it may be * empty due to conflict resolution, which the user should okay. */ if (!commitable && whence != FROM_MERGE && !allow_empty && !(amend && is_a_merge(current_head))) { s->display_comment_prefix = old_display_comment_prefix; run_status(stdout, index_file, prefix, 0, s); if (amend) fputs(_(empty_amend_advice), stderr); else if (whence == FROM_CHERRY_PICK) { fputs(_(empty_cherry_pick_advice), stderr); if (!sequencer_in_use) fputs(_(empty_cherry_pick_advice_single), stderr); else fputs(_(empty_cherry_pick_advice_multi), stderr); } return 0; } /* * Re-read the index as pre-commit hook could have updated it, * and write it out as a tree. We must do this before we invoke * the editor and after we invoke run_status above. */ discard_cache(); read_cache_from(index_file); if (update_main_cache_tree(0)) { error(_("Error building trees")); return 0; } if (run_hook(index_file, "prepare-commit-msg", 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)) { fprintf(stderr, _("Please supply the message using either -m or -F option.\n")); exit(1); } } if (!no_verify && run_hook(index_file, "commit-msg", git_path(commit_editmsg), NULL)) { return 0; } return 1; }
static void print_summary(const char *prefix, const unsigned char *sha1, int initial_commit) { struct rev_info rev; struct commit *commit; struct strbuf format = STRBUF_INIT; unsigned char junk_sha1[20]; const char *head; struct pretty_print_context pctx = {0}; struct strbuf author_ident = STRBUF_INIT; struct strbuf committer_ident = STRBUF_INIT; commit = lookup_commit(sha1); 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 (!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", junk_sha1, 0, NULL); printf("[%s%s ", starts_with(head, "refs/heads/") ? head + 11 : !strcmp(head, "HEAD") ? _("detached HEAD") : 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 void shortlog(const char *name, struct origin_data *origin_data, struct commit *head, struct rev_info *rev, int limit, struct strbuf *out) { int i, count = 0; struct commit *commit; struct object *branch; struct string_list subjects = STRING_LIST_INIT_DUP; struct string_list authors = STRING_LIST_INIT_DUP; struct string_list committers = STRING_LIST_INIT_DUP; int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED; struct strbuf sb = STRBUF_INIT; const unsigned char *sha1 = origin_data->sha1; branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40); if (!branch || branch->type != OBJ_COMMIT) return; setup_revisions(0, NULL, rev, NULL); add_pending_object(rev, branch, name); add_pending_object(rev, &head->object, "^HEAD"); head->object.flags |= UNINTERESTING; if (prepare_revision_walk(rev)) die("revision walk setup failed"); while ((commit = get_revision(rev)) != NULL) { struct pretty_print_context ctx = {0}; if (commit->parents && commit->parents->next) { /* do not list a merge but count committer */ record_person('c', &committers, commit); continue; } if (!count) /* the 'tip' committer */ record_person('c', &committers, commit); record_person('a', &authors, commit); count++; if (subjects.nr > limit) continue; format_commit_message(commit, "%s", &sb, &ctx); strbuf_ltrim(&sb); if (!sb.len) string_list_append(&subjects, sha1_to_hex(commit->object.sha1)); else string_list_append(&subjects, strbuf_detach(&sb, NULL)); } add_people_info(out, &authors, &committers); if (count > limit) strbuf_addf(out, "\n* %s: (%d commits)\n", name, count); else strbuf_addf(out, "\n* %s:\n", name); if (origin_data->is_local_branch && use_branch_desc) add_branch_desc(out, name); for (i = 0; i < subjects.nr; i++) if (i >= limit) strbuf_addf(out, " ...\n"); else strbuf_addf(out, " %s\n", subjects.items[i].string); clear_commit_marks((struct commit *)branch, flags); clear_commit_marks(head, flags); free_commit_list(rev->commits); rev->commits = NULL; rev->pending.nr = 0; string_list_clear(&authors, 0); string_list_clear(&committers, 0); string_list_clear(&subjects, 0); }
static int prepare_to_commit(const char *index_file, const char *prefix, struct wt_status *s) { struct stat statbuf; int commitable, saved_color_setting; struct strbuf sb = STRBUF_INIT; char *buffer; FILE *fp; const char *hook_arg1 = NULL; const char *hook_arg2 = NULL; int ident_shown = 0; if (!no_verify && run_hook(index_file, "pre-commit", NULL)) return 0; if (squash_message) { /* * Insert the proper subject line before other commit * message options add their content. */ if (use_message && !strcmp(use_message, squash_message)) strbuf_addstr(&sb, "squash! "); else { struct pretty_print_context ctx = {0}; struct commit *c; c = lookup_commit_reference_by_name(squash_message); if (!c) die("could not lookup commit %s", squash_message); ctx.output_encoding = get_commit_output_encoding(); format_commit_message(c, "squash! %s\n\n", &sb, &ctx); } } if (message.len) { strbuf_addbuf(&sb, &message); hook_arg1 = "message"; } else if (logfile && !strcmp(logfile, "-")) { if (isatty(0)) fprintf(stderr, "(reading log message from standard input)\n"); if (strbuf_read(&sb, 0, 0) < 0) die_errno("could not read log from standard input"); hook_arg1 = "message"; } else if (logfile) { if (strbuf_read_file(&sb, logfile, 0) < 0) die_errno("could not read log file '%s'", logfile); hook_arg1 = "message"; } else if (use_message) { buffer = strstr(use_message_buffer, "\n\n"); if (!buffer || buffer[2] == '\0') die("commit has empty message"); strbuf_add(&sb, buffer + 2, strlen(buffer + 2)); hook_arg1 = "commit"; hook_arg2 = use_message; } else if (fixup_message) { struct pretty_print_context ctx = {0}; struct commit *commit; commit = lookup_commit_reference_by_name(fixup_message); if (!commit) die("could not lookup commit %s", fixup_message); ctx.output_encoding = get_commit_output_encoding(); format_commit_message(commit, "fixup! %s\n\n", &sb, &ctx); hook_arg1 = "message"; } else if (!stat(git_path("MERGE_MSG"), &statbuf)) { 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_arg1 = "squash"; } else if (template_file && !stat(template_file, &statbuf)) { if (strbuf_read_file(&sb, template_file, 0) < 0) die_errno("could not read '%s'", template_file); hook_arg1 = "template"; } /* * This final case does not modify the template message, * it just sets the argument to the prepare-commit-msg hook. */ else if (in_merge) hook_arg1 = "merge"; if (squash_message) { /* * If squash_commit was used for the commit subject, * then we're possibly hijacking other commit log options. * Reset the hook args to tell the real story. */ hook_arg1 = "message"; hook_arg2 = ""; } fp = fopen(git_path(commit_editmsg), "w"); if (fp == NULL) die_errno("could not open '%s'", git_path(commit_editmsg)); if (cleanup_mode != CLEANUP_NONE) stripspace(&sb, 0); if (signoff) { struct strbuf sob = STRBUF_INIT; int i; strbuf_addstr(&sob, sign_off_header); strbuf_addstr(&sob, fmt_name(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL"))); strbuf_addch(&sob, '\n'); for (i = sb.len - 1; i > 0 && sb.buf[i - 1] != '\n'; i--) ; /* do nothing */ if (prefixcmp(sb.buf + i, sob.buf)) { if (!i || !ends_rfc2822_footer(&sb)) strbuf_addch(&sb, '\n'); strbuf_addbuf(&sb, &sob); } strbuf_release(&sob); } if (fwrite(sb.buf, 1, sb.len, fp) < sb.len) die_errno("could not write commit template"); strbuf_release(&sb); determine_author_info(); /* This checks if committer ident is explicitly given */ git_committer_info(0); if (use_editor && include_status) { char *author_ident; const char *committer_ident; if (in_merge) fprintf(fp, "#\n" "# It looks like you may be committing a MERGE.\n" "# If this is not correct, please remove the file\n" "# %s\n" "# and try again.\n" "#\n", git_path("MERGE_HEAD")); fprintf(fp, "\n" "# Please enter the commit message for your changes."); if (cleanup_mode == CLEANUP_ALL) fprintf(fp, " Lines starting\n" "# with '#' will be ignored, and an empty" " message aborts the commit.\n"); else /* CLEANUP_SPACE, that is. */ fprintf(fp, " Lines starting\n" "# with '#' will be kept; you may remove them" " yourself if you want to.\n" "# An empty message aborts the commit.\n"); if (only_include_assumed) fprintf(fp, "# %s\n", only_include_assumed); author_ident = xstrdup(fmt_name(author_name, author_email)); committer_ident = fmt_name(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL")); if (strcmp(author_ident, committer_ident)) fprintf(fp, "%s" "# Author: %s\n", ident_shown++ ? "" : "#\n", author_ident); free(author_ident); if (!user_ident_sufficiently_given()) fprintf(fp, "%s" "# Committer: %s\n", ident_shown++ ? "" : "#\n", committer_ident); if (ident_shown) fprintf(fp, "#\n"); saved_color_setting = s->use_color; s->use_color = 0; commitable = run_status(fp, index_file, prefix, 1, s); s->use_color = saved_color_setting; } else { unsigned char sha1[20]; const char *parent = "HEAD"; if (!active_nr && read_cache() < 0) die("Cannot read index"); if (amend) parent = "HEAD^1"; if (get_sha1(parent, sha1)) commitable = !!active_nr; else commitable = index_differs_from(parent, 0); } fclose(fp); 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; } /* * Re-read the index as pre-commit hook could have updated it, * and write it out as a tree. We must do this before we invoke * the editor and after we invoke run_status above. */ discard_cache(); read_cache_from(index_file); if (!active_cache_tree) active_cache_tree = cache_tree(); if (cache_tree_update(active_cache_tree, active_cache, active_nr, 0, 0) < 0) { error("Error building trees"); return 0; } if (run_hook(index_file, "prepare-commit-msg", 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)) { fprintf(stderr, "Please supply the message using either -m or -F option.\n"); exit(1); } } if (!no_verify && run_hook(index_file, "commit-msg", git_path(commit_editmsg), NULL)) { return 0; } return 1; }
void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, struct strbuf *sb, int abbrev, const char *subject, const char *after_subject, enum date_mode dmode, int need_8bit_cte) { unsigned long beginning_of_body; int indent = 4; const char *msg = commit->buffer; char *reencoded; const char *encoding; if (fmt == CMIT_FMT_USERFORMAT) { format_commit_message(commit, user_format, sb); return; } encoding = (git_log_output_encoding ? git_log_output_encoding : git_commit_encoding); if (!encoding) encoding = "utf-8"; reencoded = logmsg_reencode(commit, encoding); if (reencoded) { msg = reencoded; } if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) indent = 0; /* * We need to check and emit Content-type: to mark it * as 8-bit if we haven't done so. */ if (fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) { int i, ch, in_body; for (in_body = i = 0; (ch = msg[i]); i++) { if (!in_body) { /* author could be non 7-bit ASCII but * the log may be so; skip over the * header part first. */ if (ch == '\n' && msg[i+1] == '\n') in_body = 1; } else if (non_ascii(ch)) { need_8bit_cte = 1; break; } } } pp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb); if (fmt != CMIT_FMT_ONELINE && !subject) { strbuf_addch(sb, '\n'); } /* Skip excess blank lines at the beginning of body, if any... */ for (;;) { int linelen = get_one_line(msg); int ll = linelen; if (!linelen) break; if (!is_empty_line(msg, &ll)) break; msg += linelen; } /* These formats treat the title line specially. */ if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) pp_title_line(fmt, &msg, sb, subject, after_subject, encoding, need_8bit_cte); beginning_of_body = sb->len; if (fmt != CMIT_FMT_ONELINE) pp_remainder(fmt, &msg, sb, indent); strbuf_rtrim(sb); /* Make sure there is an EOLN for the non-oneline case */ if (fmt != CMIT_FMT_ONELINE) strbuf_addch(sb, '\n'); /* * The caller may append additional body text in e-mail * format. Make sure we did not strip the blank line * between the header and the body. */ if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body) strbuf_addch(sb, '\n'); free(reencoded); }
void show_submodule_summary(FILE *f, const char *path, unsigned char one[20], unsigned char two[20], unsigned dirty_submodule, const char *del, const char *add, const char *reset) { struct rev_info rev; struct commit *commit, *left = left, *right = right; struct commit_list *merge_bases, *list; const char *message = NULL; struct strbuf sb = STRBUF_INIT; static const char *format = " %m %s"; int fast_forward = 0, fast_backward = 0; if (is_null_sha1(two)) message = "(submodule deleted)"; else if (add_submodule_odb(path)) message = "(not checked out)"; else if (is_null_sha1(one)) message = "(new submodule)"; else if (!(left = lookup_commit_reference(one)) || !(right = lookup_commit_reference(two))) message = "(commits not present)"; if (!message) { init_revisions(&rev, NULL); setup_revisions(0, NULL, &rev, NULL); rev.left_right = 1; rev.first_parent_only = 1; left->object.flags |= SYMMETRIC_LEFT; add_pending_object(&rev, &left->object, path); add_pending_object(&rev, &right->object, path); merge_bases = get_merge_bases(left, right, 1); if (merge_bases) { if (merge_bases->item == left) fast_forward = 1; else if (merge_bases->item == right) fast_backward = 1; } for (list = merge_bases; list; list = list->next) { list->item->object.flags |= UNINTERESTING; add_pending_object(&rev, &list->item->object, sha1_to_hex(list->item->object.sha1)); } if (prepare_revision_walk(&rev)) message = "(revision walker failed)"; } strbuf_addf(&sb, "Submodule %s %s..", path, find_unique_abbrev(one, DEFAULT_ABBREV)); if (!fast_backward && !fast_forward) strbuf_addch(&sb, '.'); strbuf_addf(&sb, "%s", find_unique_abbrev(two, DEFAULT_ABBREV)); if (dirty_submodule) strbuf_add(&sb, "-dirty", 6); if (message) strbuf_addf(&sb, " %s\n", message); else strbuf_addf(&sb, "%s:\n", fast_backward ? " (rewind)" : ""); fwrite(sb.buf, sb.len, 1, f); if (!message) { while ((commit = get_revision(&rev))) { struct pretty_print_context ctx = {0}; ctx.date_mode = rev.date_mode; strbuf_setlen(&sb, 0); if (commit->object.flags & SYMMETRIC_LEFT) { if (del) strbuf_addstr(&sb, del); } else if (add) strbuf_addstr(&sb, add); format_commit_message(commit, format, &sb, &ctx); if (reset) strbuf_addstr(&sb, reset); strbuf_addch(&sb, '\n'); fprintf(f, "%s", sb.buf); } clear_commit_marks(left, ~0); clear_commit_marks(right, ~0); } strbuf_release(&sb); }
void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, struct strbuf *sb, const struct pretty_print_context *context) { unsigned long beginning_of_body; int indent = 4; const char *msg = commit->buffer; char *reencoded; const char *encoding; int need_8bit_cte = context->need_8bit_cte; if (fmt == CMIT_FMT_USERFORMAT) { format_commit_message(commit, user_format, sb, context); return; } reencoded = reencode_commit_message(commit, &encoding); if (reencoded) { msg = reencoded; } if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) indent = 0; /* * We need to check and emit Content-type: to mark it * as 8-bit if we haven't done so. */ if (fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) { int i, ch, in_body; for (in_body = i = 0; (ch = msg[i]); i++) { if (!in_body) { /* author could be non 7-bit ASCII but * the log may be so; skip over the * header part first. */ if (ch == '\n' && msg[i+1] == '\n') in_body = 1; } else if (non_ascii(ch)) { need_8bit_cte = 1; break; } } } pp_header(fmt, context->abbrev, context->date_mode, encoding, commit, &msg, sb); if (fmt != CMIT_FMT_ONELINE && !context->subject) { strbuf_addch(sb, '\n'); } /* Skip excess blank lines at the beginning of body, if any... */ msg = skip_empty_lines(msg); /* These formats treat the title line specially. */ if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) pp_title_line(fmt, &msg, sb, context->subject, context->after_subject, encoding, need_8bit_cte); beginning_of_body = sb->len; if (fmt != CMIT_FMT_ONELINE) pp_remainder(fmt, &msg, sb, indent); strbuf_rtrim(sb); /* Make sure there is an EOLN for the non-oneline case */ if (fmt != CMIT_FMT_ONELINE) strbuf_addch(sb, '\n'); /* * The caller may append additional body text in e-mail * format. Make sure we did not strip the blank line * between the header and the body. */ if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body) strbuf_addch(sb, '\n'); if (context->show_notes) format_display_notes(commit->object.sha1, sb, encoding, NOTES_SHOW_HEADER | NOTES_INDENT); free(reencoded); }
void pretty_print_commit(struct pretty_print_context *pp, const struct commit *commit, struct strbuf *sb) { unsigned long beginning_of_body; int indent = 4; const char *msg; const char *reencoded; const char *encoding; int need_8bit_cte = pp->need_8bit_cte; if (pp->fmt == CMIT_FMT_USERFORMAT) { format_commit_message(commit, user_format, sb, pp); return; } encoding = get_log_output_encoding(); msg = reencoded = logmsg_reencode(commit, NULL, encoding); if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL) indent = 0; /* * We need to check and emit Content-type: to mark it * as 8-bit if we haven't done so. */ if (pp->fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) { int i, ch, in_body; for (in_body = i = 0; (ch = msg[i]); i++) { if (!in_body) { /* author could be non 7-bit ASCII but * the log may be so; skip over the * header part first. */ if (ch == '\n' && msg[i+1] == '\n') in_body = 1; } else if (non_ascii(ch)) { need_8bit_cte = 1; break; } } } pp_header(pp, encoding, commit, &msg, sb); if (pp->fmt != CMIT_FMT_ONELINE && !pp->subject) { strbuf_addch(sb, '\n'); } /* Skip excess blank lines at the beginning of body, if any... */ msg = skip_empty_lines(msg); /* These formats treat the title line specially. */ if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL) pp_title_line(pp, &msg, sb, encoding, need_8bit_cte); beginning_of_body = sb->len; if (pp->fmt != CMIT_FMT_ONELINE) pp_remainder(pp, &msg, sb, indent); strbuf_rtrim(sb); /* Make sure there is an EOLN for the non-oneline case */ if (pp->fmt != CMIT_FMT_ONELINE) strbuf_addch(sb, '\n'); /* * The caller may append additional body text in e-mail * format. Make sure we did not strip the blank line * between the header and the body. */ if (pp->fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body) strbuf_addch(sb, '\n'); unuse_commit_buffer(commit, reencoded); }