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 (!prefixcmp(buffer, "author ")) author = buffer + 7; buffer = eol; } if (!author) die(_("Missing author: %s"), sha1_to_hex(commit->object.sha1)); 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; pretty_print_commit(&ctx, commit, &ufbuf); buffer = ufbuf.buf; } else if (*buffer) { buffer++; } insert_one_record(log, author, !*buffer ? "<none>" : buffer); strbuf_release(&ufbuf); strbuf_release(&buf); }
static void squash_message(struct commit *commit, struct commit_list *remoteheads) { struct rev_info rev; struct strbuf out = STRBUF_INIT; struct commit_list *j; struct pretty_print_context ctx = {0}; printf(_("Squash commit -- not updating HEAD\n")); init_revisions(&rev, NULL); rev.ignore_merges = 1; rev.commit_format = CMIT_FMT_MEDIUM; commit->object.flags |= UNINTERESTING; add_pending_object(&rev, &commit->object, NULL); for (j = remoteheads; j; j = j->next) add_pending_object(&rev, &j->item->object, NULL); setup_revisions(0, NULL, &rev, NULL); if (prepare_revision_walk(&rev)) die(_("revision walk setup failed")); ctx.abbrev = rev.abbrev; ctx.date_mode = rev.date_mode; ctx.fmt = rev.commit_format; strbuf_addstr(&out, "Squashed commit of the following:\n"); while ((commit = get_revision(&rev)) != NULL) { strbuf_addch(&out, '\n'); strbuf_addf(&out, "commit %s\n", oid_to_hex(&commit->object.oid)); pretty_print_commit(&ctx, commit, &out); } write_file_buf(git_path_squash_msg(), out.buf, out.len); strbuf_release(&out); }
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; ctx.show_notes = opt->show_notes; 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; /* * 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; pretty_print_commit(&ctx, commit, &msgbuf); if (opt->add_signoff) append_signoff(&msgbuf, opt->add_signoff); 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); }
int cmd_cherry(int argc, const char **argv, const char *prefix) { struct rev_info revs; struct patch_ids ids; struct commit *commit; struct commit_list *list = NULL; struct branch *current_branch; const char *upstream; const char *head = "HEAD"; const char *limit = NULL; int verbose = 0; if (argc > 1 && !strcmp(argv[1], "-v")) { verbose = 1; argc--; argv++; } if (argc > 1 && !strcmp(argv[1], "-h")) usage(cherry_usage); switch (argc) { case 4: limit = argv[3]; /* FALLTHROUGH */ case 3: head = argv[2]; /* FALLTHROUGH */ case 2: upstream = argv[1]; break; default: current_branch = branch_get(NULL); if (!current_branch || !current_branch->merge || !current_branch->merge[0] || !current_branch->merge[0]->dst) { fprintf(stderr, "Could not find a tracked" " remote branch, please" " specify <upstream> manually.\n"); usage(cherry_usage); } upstream = current_branch->merge[0]->dst; } init_revisions(&revs, prefix); revs.diff = 1; revs.combine_merges = 0; revs.ignore_merges = 1; DIFF_OPT_SET(&revs.diffopt, RECURSIVE); if (add_pending_commit(head, &revs, 0)) die("Unknown commit %s", head); if (add_pending_commit(upstream, &revs, UNINTERESTING)) die("Unknown commit %s", upstream); /* Don't say anything if head and upstream are the same. */ if (revs.pending.nr == 2) { struct object_array_entry *o = revs.pending.objects; if (hashcmp(o[0].item->sha1, o[1].item->sha1) == 0) return 0; } get_patch_ids(&revs, &ids, prefix); if (limit && add_pending_commit(limit, &revs, UNINTERESTING)) die("Unknown commit %s", limit); /* reverse the list of commits */ if (prepare_revision_walk(&revs)) die("revision walk setup failed"); while ((commit = get_revision(&revs)) != NULL) { /* ignore merges */ if (commit->parents && commit->parents->next) continue; commit_list_insert(commit, &list); } while (list) { char sign = '+'; commit = list->item; if (has_commit_patch_id(commit, &ids)) sign = '-'; if (verbose) { struct strbuf buf = STRBUF_INIT; struct pretty_print_context ctx = {0}; pretty_print_commit(CMIT_FMT_ONELINE, commit, &buf, &ctx); printf("%c %s %s\n", sign, sha1_to_hex(commit->object.sha1), buf.buf); strbuf_release(&buf); } else { printf("%c %s\n", sign, sha1_to_hex(commit->object.sha1)); } list = list->next; } free_patch_ids(&ids); return 0; }
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); }
static void show_commit(struct commit *commit, void *data) { struct rev_list_info *info = data; struct rev_info *revs = info->revs; graph_show_commit(revs->graph); if (info->show_timestamp) printf("%lu ", commit->date); if (info->header_prefix) fputs(info->header_prefix, stdout); if (!revs->graph) { if (commit->object.flags & BOUNDARY) putchar('-'); else if (commit->object.flags & UNINTERESTING) putchar('^'); else if (revs->left_right) { if (commit->object.flags & SYMMETRIC_LEFT) putchar('<'); else putchar('>'); } } if (revs->abbrev_commit && revs->abbrev) fputs(find_unique_abbrev(commit->object.sha1, revs->abbrev), stdout); else fputs(sha1_to_hex(commit->object.sha1), stdout); if (revs->print_parents) { struct commit_list *parents = commit->parents; while (parents) { printf(" %s", sha1_to_hex(parents->item->object.sha1)); parents = parents->next; } } if (revs->children.name) { struct commit_list *children; children = lookup_decoration(&revs->children, &commit->object); while (children) { printf(" %s", sha1_to_hex(children->item->object.sha1)); children = children->next; } } show_decorations(revs, commit); if (revs->commit_format == CMIT_FMT_ONELINE) putchar(' '); else putchar('\n'); if (revs->verbose_header && commit->buffer) { struct strbuf buf = STRBUF_INIT; struct pretty_print_context ctx = {0}; ctx.abbrev = revs->abbrev; ctx.date_mode = revs->date_mode; pretty_print_commit(revs->commit_format, commit, &buf, &ctx); if (revs->graph) { if (buf.len) { if (revs->commit_format != CMIT_FMT_ONELINE) graph_show_oneline(revs->graph); graph_show_commit_msg(revs->graph, &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('\n'); } 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'); } } else { if (buf.len) printf("%s%c", buf.buf, info->hdr_termination); } strbuf_release(&buf); } else { if (graph_show_remainder(revs->graph)) putchar('\n'); } maybe_flush_or_die(stdout, "stdout"); finish_commit(commit, data); }
static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, int abbrev, int current, char *prefix) { char c; int color; struct commit *commit = item->commit; struct strbuf out = STRBUF_INIT, name = STRBUF_INIT; if (!matches_merge_filter(commit)) return; switch (item->kind) { case REF_LOCAL_BRANCH: color = BRANCH_COLOR_LOCAL; break; case REF_REMOTE_BRANCH: color = BRANCH_COLOR_REMOTE; break; default: color = BRANCH_COLOR_PLAIN; break; } c = ' '; if (current) { c = '*'; color = BRANCH_COLOR_CURRENT; } strbuf_addf(&name, "%s%s", prefix, item->name); if (verbose) strbuf_addf(&out, "%c %s%-*s%s", c, branch_get_color(color), maxwidth, name.buf, branch_get_color(BRANCH_COLOR_RESET)); else strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color), name.buf, branch_get_color(BRANCH_COLOR_RESET)); if (item->dest) strbuf_addf(&out, " -> %s", item->dest); else if (verbose) { struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT; const char *sub = " **** invalid ref ****"; commit = item->commit; if (commit && !parse_commit(commit)) { pretty_print_commit(CMIT_FMT_ONELINE, commit, &subject, 0, NULL, NULL, 0, 0); sub = subject.buf; } if (item->kind == REF_LOCAL_BRANCH) fill_tracking_info(&stat, item->name, verbose > 1); strbuf_addf(&out, " %s %s%s", find_unique_abbrev(item->commit->object.sha1, abbrev), stat.buf, sub); strbuf_release(&stat); strbuf_release(&subject); } printf("%s\n", out.buf); strbuf_release(&name); strbuf_release(&out); }
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.oid.hash, abbrev_commit), opt->diffopt.file); if (opt->print_parents) show_parents(commit, abbrev_commit, opt->diffopt.file); if (opt->children.name) show_children(opt, commit, abbrev_commit); show_decorations(opt, commit); if (opt->graph && !graph_is_commit_finished(opt->graph)) { putc('\n', opt->diffopt.file); graph_show_remainder(opt->graph); } putc(opt->diffopt.line_termination, opt->diffopt.file); 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); putc(opt->diffopt.line_termination, opt->diffopt.file); } 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 (cmit_fmt_is_mail(opt->commit_format)) { 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), opt->diffopt.file); if (opt->commit_format != CMIT_FMT_ONELINE) fputs("commit ", opt->diffopt.file); if (!opt->graph) put_revision_mark(opt, commit); fputs(find_unique_abbrev(commit->object.oid.hash, abbrev_commit), opt->diffopt.file); if (opt->print_parents) show_parents(commit, abbrev_commit, opt->diffopt.file); if (opt->children.name) show_children(opt, commit, abbrev_commit); if (parent) fprintf(opt->diffopt.file, " (from %s)", find_unique_abbrev(parent->object.oid.hash, abbrev_commit)); fputs(diff_get_color_opt(&opt->diffopt, DIFF_RESET), opt->diffopt.file); show_decorations(opt, commit); if (opt->commit_format == CMIT_FMT_ONELINE) { putc(' ', opt->diffopt.file); } else { putc('\n', opt->diffopt.file); 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 (!get_cached_commit_buffer(commit, NULL)) return; if (opt->show_notes) { int raw; struct strbuf notebuf = STRBUF_INIT; raw = (opt->commit_format == CMIT_FMT_USERFORMAT); format_display_notes(commit->object.oid.hash, ¬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 && opt->add_signoff) ctx.need_8bit_cte = has_non_ascii(fmt_name(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL"))); 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; ctx.expand_tabs_in_log = opt->expand_tabs_in_log; ctx.output_encoding = get_log_output_encoding(); if (opt->from_ident.mail_begin && opt->from_ident.name_begin) ctx.from_ident = &opt->from_ident; if (opt->graph) ctx.graph_width = graph_width(opt->graph); pretty_print_commit(&ctx, commit, &msgbuf); if (opt->add_signoff) append_signoff(&msgbuf, 0, APPEND_SIGNOFF_DEDUP); if ((ctx.fmt != CMIT_FMT_USERFORMAT) && ctx.notes_message && *ctx.notes_message) { if (cmit_fmt_is_mail(ctx.fmt)) { strbuf_addstr(&msgbuf, "---\n"); opt->shown_dashes = 1; } strbuf_addstr(&msgbuf, ctx.notes_message); } if (opt->show_log_size) { fprintf(opt->diffopt.file, "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; graph_show_commit_msg(opt->graph, opt->diffopt.file, &msgbuf); if (opt->use_terminator && !commit_format_is_empty(opt->commit_format)) { if (!opt->missing_newline) graph_show_padding(opt->graph); putc(opt->diffopt.line_termination, opt->diffopt.file); } strbuf_release(&msgbuf); free(ctx.notes_message); }