static void print_submodule_summary(struct rev_info *rev, FILE *f, const char *line_prefix, 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; ctx.output_encoding = get_log_output_encoding(); strbuf_setlen(&sb, 0); strbuf_addstr(&sb, line_prefix); 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 int show_http_message(struct strbuf *type, struct strbuf *charset, struct strbuf *msg) { const char *p, *eol; /* * We only show text/plain parts, as other types are likely * to be ugly to look at on the user's terminal. */ if (strcmp(type->buf, "text/plain")) return -1; if (charset->len) strbuf_reencode(msg, charset->buf, get_log_output_encoding()); strbuf_trim(msg); if (!msg->len) return -1; p = msg->buf; do { eol = strchrnul(p, '\n'); fprintf(stderr, "remote: %.*s\n", (int)(eol - p), p); p = eol + 1; } while(*eol); return 0; }
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 get_commit_info(struct commit *commit, struct commit_info *ret, int detailed) { int len; const char *subject, *encoding; const char *message; commit_info_init(ret); encoding = get_log_output_encoding(); message = logmsg_reencode(commit, NULL, encoding); get_ac_line(message, "\nauthor ", &ret->author, &ret->author_mail, &ret->author_time, &ret->author_tz); if (!detailed) { unuse_commit_buffer(commit, message); return; } get_ac_line(message, "\ncommitter ", &ret->committer, &ret->committer_mail, &ret->committer_time, &ret->committer_tz); len = find_commit_subject(message, &subject); if (len) strbuf_add(&ret->summary, subject, len); else strbuf_addf(&ret->summary, "(%s)", oid_to_hex(&commit->object.oid)); unuse_commit_buffer(commit, message); }
static void show_tagger(char *buf, int len, struct rev_info *rev) { struct strbuf out = STRBUF_INIT; pp_user_info("Tagger", rev->commit_format, &out, buf, rev->date_mode, get_log_output_encoding()); printf("%s", out.buf); strbuf_release(&out); }
char *reencode_commit_message(const struct commit *commit, const char **encoding_p) { const char *encoding; encoding = get_log_output_encoding(); if (encoding_p) *encoding_p = encoding; return logmsg_reencode(commit, encoding); }
static void show_tagger(char *buf, int len, struct rev_info *rev) { struct strbuf out = STRBUF_INIT; struct pretty_print_context pp = {0}; pp.fmt = rev->commit_format; pp.date_mode = rev->date_mode; pp_user_info(&pp, "Tagger", &out, buf, get_log_output_encoding()); printf("%s", out.buf); strbuf_release(&out); }
void shortlog_add_commit(struct shortlog *log, struct commit *commit) { const char *author = NULL, *buffer; struct strbuf buf = STRBUF_INIT; struct strbuf ufbuf = STRBUF_INIT; pp_commit_easy(CMIT_FMT_RAW, commit, &buf); buffer = buf.buf; while (*buffer && *buffer != '\n') { const char *eol = strchr(buffer, '\n'); if (eol == NULL) eol = buffer + strlen(buffer); else eol++; if (starts_with(buffer, "author ")) author = buffer + 7; buffer = eol; } if (!author) { warning(_("Missing author: %s"), sha1_to_hex(commit->object.sha1)); return; } if (log->user_format) { struct pretty_print_context ctx = {0}; ctx.fmt = CMIT_FMT_USERFORMAT; ctx.abbrev = log->abbrev; ctx.subject = ""; ctx.after_subject = ""; ctx.date_mode = DATE_NORMAL; ctx.output_encoding = get_log_output_encoding(); pretty_print_commit(&ctx, commit, &ufbuf); buffer = ufbuf.buf; } else if (*buffer) { buffer++; } shortlog_insert_one_record(log, author, !*buffer ? "<none>" : buffer); strbuf_release(&ufbuf); strbuf_release(&buf); }
static void print_new_head_line(struct commit *commit) { const char *hex, *body; char *msg; hex = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV); printf(_("HEAD is now at %s"), hex); msg = logmsg_reencode(commit, NULL, get_log_output_encoding()); body = strstr(msg, "\n\n"); if (body) { const char *eol; size_t len; body += 2; eol = strchr(body, '\n'); len = eol ? eol - body : strlen(body); printf(" %.*s\n", (int) len, body); } else printf("\n"); logmsg_free(msg, commit); }
static void show_commit(struct commit *commit, void *data) { struct rev_list_info *info = data; struct rev_info *revs = info->revs; display_progress(progress, ++progress_counter); if (info->flags & REV_LIST_QUIET) { finish_commit(commit, data); return; } graph_show_commit(revs->graph); if (revs->count) { if (commit->object.flags & PATCHSAME) revs->count_same++; else if (commit->object.flags & SYMMETRIC_LEFT) revs->count_left++; else revs->count_right++; finish_commit(commit, data); return; } if (info->show_timestamp) printf("%"PRItime" ", commit->date); if (info->header_prefix) fputs(info->header_prefix, stdout); if (!revs->graph) fputs(get_revision_mark(revs, commit), stdout); if (revs->abbrev_commit && revs->abbrev) fputs(find_unique_abbrev(commit->object.oid.hash, revs->abbrev), stdout); else fputs(oid_to_hex(&commit->object.oid), stdout); if (revs->print_parents) { struct commit_list *parents = commit->parents; while (parents) { printf(" %s", oid_to_hex(&parents->item->object.oid)); parents = parents->next; } } if (revs->children.name) { struct commit_list *children; children = lookup_decoration(&revs->children, &commit->object); while (children) { printf(" %s", oid_to_hex(&children->item->object.oid)); children = children->next; } } show_decorations(revs, commit); if (revs->commit_format == CMIT_FMT_ONELINE) putchar(' '); else putchar('\n'); if (revs->verbose_header && get_cached_commit_buffer(commit, NULL)) { struct strbuf buf = STRBUF_INIT; struct pretty_print_context ctx = {0}; ctx.abbrev = revs->abbrev; ctx.date_mode = revs->date_mode; ctx.date_mode_explicit = revs->date_mode_explicit; ctx.fmt = revs->commit_format; ctx.output_encoding = get_log_output_encoding(); ctx.color = revs->diffopt.use_color; pretty_print_commit(&ctx, commit, &buf); if (buf.len) { if (revs->commit_format != CMIT_FMT_ONELINE) graph_show_oneline(revs->graph); graph_show_commit_msg(revs->graph, stdout, &buf); /* * Add a newline after the commit message. * * Usually, this newline produces a blank * padding line between entries, in which case * we need to add graph padding on this line. * * However, the commit message may not end in a * newline. In this case the newline simply * ends the last line of the commit message, * and we don't need any graph output. (This * always happens with CMIT_FMT_ONELINE, and it * happens with CMIT_FMT_USERFORMAT when the * format doesn't explicitly end in a newline.) */ if (buf.len && buf.buf[buf.len - 1] == '\n') graph_show_padding(revs->graph); putchar(info->hdr_termination); } else { /* * If the message buffer is empty, just show * the rest of the graph output for this * commit. */ if (graph_show_remainder(revs->graph)) putchar('\n'); if (revs->commit_format == CMIT_FMT_ONELINE) putchar('\n'); } strbuf_release(&buf); } else { if (graph_show_remainder(revs->graph)) putchar('\n'); } maybe_flush_or_die(stdout, "stdout"); finish_commit(commit, data); }
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); }
static size_t format_commit_one(struct strbuf *sb, const char *placeholder, void *context) { struct format_commit_context *c = context; const struct commit *commit = c->commit; const char *msg = c->message; struct commit_list *p; int h1, h2; /* these are independent of the commit */ switch (placeholder[0]) { case 'C': if (placeholder[1] == '(') { const char *end = strchr(placeholder + 2, ')'); char color[COLOR_MAXLEN]; if (!end) return 0; color_parse_mem(placeholder + 2, end - (placeholder + 2), "--pretty format", color); strbuf_addstr(sb, color); return end - placeholder + 1; } if (!prefixcmp(placeholder + 1, "red")) { strbuf_addstr(sb, GIT_COLOR_RED); return 4; } else if (!prefixcmp(placeholder + 1, "green")) { strbuf_addstr(sb, GIT_COLOR_GREEN); return 6; } else if (!prefixcmp(placeholder + 1, "blue")) { strbuf_addstr(sb, GIT_COLOR_BLUE); return 5; } else if (!prefixcmp(placeholder + 1, "reset")) { strbuf_addstr(sb, GIT_COLOR_RESET); return 6; } else return 0; case 'n': /* newline */ strbuf_addch(sb, '\n'); return 1; case 'x': /* %x00 == NUL, %x0a == LF, etc. */ if (0 <= (h1 = hexval_table[0xff & placeholder[1]]) && h1 <= 16 && 0 <= (h2 = hexval_table[0xff & placeholder[2]]) && h2 <= 16) { strbuf_addch(sb, (h1<<4)|h2); return 3; } else return 0; case 'w': if (placeholder[1] == '(') { unsigned long width = 0, indent1 = 0, indent2 = 0; char *next; const char *start = placeholder + 2; const char *end = strchr(start, ')'); if (!end) return 0; if (end > start) { width = strtoul(start, &next, 10); if (*next == ',') { indent1 = strtoul(next + 1, &next, 10); if (*next == ',') { indent2 = strtoul(next + 1, &next, 10); } } if (*next != ')') return 0; } rewrap_message_tail(sb, c, width, indent1, indent2); return end - placeholder + 1; } else return 0; } /* these depend on the commit */ if (!commit->object.parsed) parse_object(commit->object.sha1); switch (placeholder[0]) { case 'H': /* commit hash */ strbuf_addstr(sb, sha1_to_hex(commit->object.sha1)); return 1; case 'h': /* abbreviated commit hash */ if (add_again(sb, &c->abbrev_commit_hash)) return 1; strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1, c->pretty_ctx->abbrev)); c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off; return 1; case 'T': /* tree hash */ strbuf_addstr(sb, sha1_to_hex(commit->tree->object.sha1)); return 1; case 't': /* abbreviated tree hash */ if (add_again(sb, &c->abbrev_tree_hash)) return 1; strbuf_addstr(sb, find_unique_abbrev(commit->tree->object.sha1, c->pretty_ctx->abbrev)); c->abbrev_tree_hash.len = sb->len - c->abbrev_tree_hash.off; return 1; case 'P': /* parent hashes */ for (p = commit->parents; p; p = p->next) { if (p != commit->parents) strbuf_addch(sb, ' '); strbuf_addstr(sb, sha1_to_hex(p->item->object.sha1)); } return 1; case 'p': /* abbreviated parent hashes */ if (add_again(sb, &c->abbrev_parent_hashes)) return 1; for (p = commit->parents; p; p = p->next) { if (p != commit->parents) strbuf_addch(sb, ' '); strbuf_addstr(sb, find_unique_abbrev( p->item->object.sha1, c->pretty_ctx->abbrev)); } c->abbrev_parent_hashes.len = sb->len - c->abbrev_parent_hashes.off; return 1; case 'm': /* left/right/bottom */ strbuf_addstr(sb, get_revision_mark(NULL, commit)); return 1; case 'd': format_decoration(sb, commit); return 1; case 'g': /* reflog info */ switch(placeholder[1]) { case 'd': /* reflog selector */ case 'D': if (c->pretty_ctx->reflog_info) get_reflog_selector(sb, c->pretty_ctx->reflog_info, c->pretty_ctx->date_mode, (placeholder[1] == 'd')); return 2; case 's': /* reflog message */ if (c->pretty_ctx->reflog_info) get_reflog_message(sb, c->pretty_ctx->reflog_info); return 2; } return 0; /* unknown %g placeholder */ case 'N': if (c->pretty_ctx->show_notes) { format_display_notes(commit->object.sha1, sb, get_log_output_encoding(), 0); return 1; } return 0; } /* For the rest we have to parse the commit header. */ if (!c->commit_header_parsed) parse_commit_header(c); switch (placeholder[0]) { case 'a': /* author ... */ return format_person_part(sb, placeholder[1], msg + c->author.off, c->author.len, c->pretty_ctx->date_mode); case 'c': /* committer ... */ return format_person_part(sb, placeholder[1], msg + c->committer.off, c->committer.len, c->pretty_ctx->date_mode); case 'e': /* encoding */ strbuf_add(sb, msg + c->encoding.off, c->encoding.len); return 1; case 'B': /* raw body */ /* message_off is always left at the initial newline */ strbuf_addstr(sb, msg + c->message_off + 1); return 1; } /* Now we need to parse the commit message. */ if (!c->commit_message_parsed) parse_commit_message(c); switch (placeholder[0]) { case 's': /* subject */ format_subject(sb, msg + c->subject_off, " "); return 1; case 'f': /* sanitized subject */ format_sanitized_subject(sb, msg + c->subject_off); return 1; case 'b': /* body */ strbuf_addstr(sb, msg + c->body_off); return 1; } return 0; /* unknown placeholder */ }
void show_log(struct rev_info *opt) { struct strbuf msgbuf = STRBUF_INIT; struct log_info *log = opt->loginfo; struct commit *commit = log->commit, *parent = log->parent; int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40; const char *extra_headers = opt->extra_headers; struct pretty_print_context ctx = {0}; opt->loginfo = NULL; if (!opt->verbose_header) { graph_show_commit(opt->graph); if (!opt->graph) put_revision_mark(opt, commit); fputs(find_unique_abbrev(commit->object.sha1, abbrev_commit), stdout); if (opt->print_parents) show_parents(commit, abbrev_commit); if (opt->children.name) show_children(opt, commit, abbrev_commit); show_decorations(opt, commit); if (opt->graph && !graph_is_commit_finished(opt->graph)) { putchar('\n'); graph_show_remainder(opt->graph); } putchar(opt->diffopt.line_termination); return; } /* * If use_terminator is set, we already handled any record termination * at the end of the last record. * Otherwise, add a diffopt.line_termination character before all * entries but the first. (IOW, as a separator between entries) */ if (opt->shown_one && !opt->use_terminator) { /* * If entries are separated by a newline, the output * should look human-readable. If the last entry ended * with a newline, print the graph output before this * newline. Otherwise it will end up as a completely blank * line and will look like a gap in the graph. * * If the entry separator is not a newline, the output is * primarily intended for programmatic consumption, and we * never want the extra graph output before the entry * separator. */ if (opt->diffopt.line_termination == '\n' && !opt->missing_newline) graph_show_padding(opt->graph); putchar(opt->diffopt.line_termination); } opt->shown_one = 1; /* * If the history graph was requested, * print the graph, up to this commit's line */ graph_show_commit(opt->graph); /* * Print header line of header.. */ if (opt->commit_format == CMIT_FMT_EMAIL) { log_write_email_headers(opt, commit, &ctx.subject, &extra_headers, &ctx.need_8bit_cte); } else if (opt->commit_format != CMIT_FMT_USERFORMAT) { fputs(diff_get_color_opt(&opt->diffopt, DIFF_COMMIT), stdout); if (opt->commit_format != CMIT_FMT_ONELINE) fputs("commit ", stdout); if (!opt->graph) put_revision_mark(opt, commit); fputs(find_unique_abbrev(commit->object.sha1, abbrev_commit), stdout); if (opt->print_parents) show_parents(commit, abbrev_commit); if (opt->children.name) show_children(opt, commit, abbrev_commit); if (parent) printf(" (from %s)", find_unique_abbrev(parent->object.sha1, abbrev_commit)); show_decorations(opt, commit); printf("%s", diff_get_color_opt(&opt->diffopt, DIFF_RESET)); if (opt->commit_format == CMIT_FMT_ONELINE) { putchar(' '); } else { putchar('\n'); graph_show_oneline(opt->graph); } if (opt->reflog_info) { /* * setup_revisions() ensures that opt->reflog_info * and opt->graph cannot both be set, * so we don't need to worry about printing the * graph info here. */ show_reflog_message(opt->reflog_info, opt->commit_format == CMIT_FMT_ONELINE, opt->date_mode, opt->date_mode_explicit); if (opt->commit_format == CMIT_FMT_ONELINE) return; } } if (opt->show_signature) { show_signature(opt, commit); show_mergetag(opt, commit); } if (!commit->buffer) return; if (opt->show_notes) { int raw; struct strbuf notebuf = STRBUF_INIT; raw = (opt->commit_format == CMIT_FMT_USERFORMAT); format_display_notes(commit->object.sha1, ¬ebuf, get_log_output_encoding(), raw); ctx.notes_message = notebuf.len ? strbuf_detach(¬ebuf, NULL) : xcalloc(1, 1); } /* * And then the pretty-printed message itself */ if (ctx.need_8bit_cte >= 0) ctx.need_8bit_cte = has_non_ascii(opt->add_signoff); ctx.date_mode = opt->date_mode; ctx.date_mode_explicit = opt->date_mode_explicit; ctx.abbrev = opt->diffopt.abbrev; ctx.after_subject = extra_headers; ctx.preserve_subject = opt->preserve_subject; ctx.reflog_info = opt->reflog_info; ctx.fmt = opt->commit_format; ctx.mailmap = opt->mailmap; ctx.color = opt->diffopt.use_color; pretty_print_commit(&ctx, commit, &msgbuf); if (opt->add_signoff) append_signoff(&msgbuf, opt->add_signoff); if ((ctx.fmt != CMIT_FMT_USERFORMAT) && ctx.notes_message && *ctx.notes_message) { if (ctx.fmt == CMIT_FMT_EMAIL) { strbuf_addstr(&msgbuf, "---\n"); opt->shown_dashes = 1; } strbuf_addstr(&msgbuf, ctx.notes_message); } if (opt->show_log_size) { printf("log size %i\n", (int)msgbuf.len); graph_show_oneline(opt->graph); } /* * Set opt->missing_newline if msgbuf doesn't * end in a newline (including if it is empty) */ if (!msgbuf.len || msgbuf.buf[msgbuf.len - 1] != '\n') opt->missing_newline = 1; else opt->missing_newline = 0; if (opt->graph) graph_show_commit_msg(opt->graph, &msgbuf); else fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); if (opt->use_terminator) { if (!opt->missing_newline) graph_show_padding(opt->graph); putchar(opt->diffopt.line_termination); } strbuf_release(&msgbuf); free(ctx.notes_message); }