From: Junio C Hamano Date: Wed, 2 May 2012 04:11:40 +0000 (-0700) Subject: Merge branch 'lp/maint-diff-three-dash-with-graph' into maint X-Git-Tag: v1.7.10.1~5 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/35977f2316d68faa850222e19d4baec407511756?ds=inline;hp=-c Merge branch 'lp/maint-diff-three-dash-with-graph' into maint "log -p --graph" used with "--stat" had a few formatting error. By Lucian Poston * lp/maint-diff-three-dash-with-graph: t4202: add test for "log --graph --stat -p" separator lines log --graph: fix break in graph lines log --graph --stat: three-dash separator should come after graph lines --- 35977f2316d68faa850222e19d4baec407511756 diff --combined diff.c index 0dea484ee8,7d5b7ecf14..cd029b33d5 --- a/diff.c +++ b/diff.c @@@ -31,7 -31,6 +31,7 @@@ static const char *external_diff_cmd_cf int diff_auto_refresh_index = 1; static int diff_mnemonic_prefix; static int diff_no_prefix; +static int diff_stat_graph_width; static int diff_dirstat_permille_default = 30; static struct diff_options default_diff_options; @@@ -157,10 -156,6 +157,10 @@@ int git_diff_ui_config(const char *var diff_no_prefix = git_config_bool(var, value); return 0; } + if (!strcmp(var, "diff.statgraphwidth")) { + diff_stat_graph_width = git_config_int(var, value); + return 0; + } if (!strcmp(var, "diff.external")) return git_config_string(&external_diff_cmd_cfg, var, value); if (!strcmp(var, "diff.wordregex")) @@@ -182,8 -177,11 +182,8 @@@ int git_diff_basic_config(const char *v return 0; } - switch (userdiff_config(var, value)) { - case 0: break; - case -1: return -1; - default: return 0; - } + if (userdiff_config(var, value) < 0) + return -1; if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) { int slot = parse_diff_color_slot(var, 11); @@@ -989,74 -987,10 +989,74 @@@ static void diff_words_flush(struct emi diff_words_show(ecbdata->diff_words); } +static void diff_filespec_load_driver(struct diff_filespec *one) +{ + /* Use already-loaded driver */ + if (one->driver) + return; + + if (S_ISREG(one->mode)) + one->driver = userdiff_find_by_path(one->path); + + /* Fallback to default settings */ + if (!one->driver) + one->driver = userdiff_find_by_name("default"); +} + +static const char *userdiff_word_regex(struct diff_filespec *one) +{ + diff_filespec_load_driver(one); + return one->driver->word_regex; +} + +static void init_diff_words_data(struct emit_callback *ecbdata, + struct diff_options *orig_opts, + struct diff_filespec *one, + struct diff_filespec *two) +{ + int i; + struct diff_options *o = xmalloc(sizeof(struct diff_options)); + memcpy(o, orig_opts, sizeof(struct diff_options)); + + ecbdata->diff_words = + xcalloc(1, sizeof(struct diff_words_data)); + ecbdata->diff_words->type = o->word_diff; + ecbdata->diff_words->opt = o; + if (!o->word_regex) + o->word_regex = userdiff_word_regex(one); + if (!o->word_regex) + o->word_regex = userdiff_word_regex(two); + if (!o->word_regex) + o->word_regex = diff_word_regex_cfg; + if (o->word_regex) { + ecbdata->diff_words->word_regex = (regex_t *) + xmalloc(sizeof(regex_t)); + if (regcomp(ecbdata->diff_words->word_regex, + o->word_regex, + REG_EXTENDED | REG_NEWLINE)) + die ("Invalid regular expression: %s", + o->word_regex); + } + for (i = 0; i < ARRAY_SIZE(diff_words_styles); i++) { + if (o->word_diff == diff_words_styles[i].type) { + ecbdata->diff_words->style = + &diff_words_styles[i]; + break; + } + } + if (want_color(o->use_color)) { + struct diff_words_style *st = ecbdata->diff_words->style; + st->old.color = diff_get_color_opt(o, DIFF_FILE_OLD); + st->new.color = diff_get_color_opt(o, DIFF_FILE_NEW); + st->ctx.color = diff_get_color_opt(o, DIFF_PLAIN); + } +} + static void free_diff_words_data(struct emit_callback *ecbdata) { if (ecbdata->diff_words) { diff_words_flush(ecbdata); + free (ecbdata->diff_words->opt); free (ecbdata->diff_words->minus.text.ptr); free (ecbdata->diff_words->minus.orig); free (ecbdata->diff_words->plus.text.ptr); @@@ -1179,15 -1113,6 +1179,15 @@@ static void fn_out_consume(void *priv, diff_words_append(line, len, &ecbdata->diff_words->plus); return; + } else if (!prefixcmp(line, "\\ ")) { + /* + * Eat the "no newline at eof" marker as if we + * saw a "+" or "-" line with nothing on it, + * and return without diff_words_flush() to + * defer processing. If this is the end of + * preimage, more "+" lines may come after it. + */ + return; } diff_words_flush(ecbdata); if (ecbdata->diff_words->type == DIFF_WORDS_PORCELAIN) { @@@ -1342,15 -1267,13 +1342,15 @@@ const char mime_boundary_leader[] = "-- static int scale_linear(int it, int width, int max_change) { + if (!it) + return 0; /* - * make sure that at least one '-' is printed if there were deletions, - * and likewise for '+'. + * make sure that at least one '-' or '+' is printed if + * there is any change to this path. The easiest way is to + * scale linearly as if the alloted width is one column shorter + * than it is, and then add 1 to the result. */ - if (max_change < 2) - return it; - return ((it - 1) * (width - 1) + max_change - 1) / (max_change - 1); + return 1 + (it * (width - 1) / max_change); } static void show_name(FILE *file, @@@ -1390,61 -1313,12 +1390,61 @@@ static void fill_print_name(struct diff file->print_name = pname; } +int print_stat_summary(FILE *fp, int files, int insertions, int deletions) +{ + struct strbuf sb = STRBUF_INIT; + int ret; + + if (!files) { + assert(insertions == 0 && deletions == 0); + return fputs(_(" 0 files changed\n"), fp); + } + + strbuf_addf(&sb, + Q_(" %d file changed", " %d files changed", files), + files); + + /* + * For binary diff, the caller may want to print "x files + * changed" with insertions == 0 && deletions == 0. + * + * Not omitting "0 insertions(+), 0 deletions(-)" in this case + * is probably less confusing (i.e skip over "2 files changed + * but nothing about added/removed lines? Is this a bug in Git?"). + */ + if (insertions || deletions == 0) { + /* + * TRANSLATORS: "+" in (+) is a line addition marker; + * do not translate it. + */ + strbuf_addf(&sb, + Q_(", %d insertion(+)", ", %d insertions(+)", + insertions), + insertions); + } + + if (deletions || insertions == 0) { + /* + * TRANSLATORS: "-" in (-) is a line removal marker; + * do not translate it. + */ + strbuf_addf(&sb, + Q_(", %d deletion(-)", ", %d deletions(-)", + deletions), + deletions); + } + strbuf_addch(&sb, '\n'); + ret = fputs(sb.buf, fp); + strbuf_release(&sb); + return ret; +} + static void show_stats(struct diffstat_t *data, struct diff_options *options) { int i, len, add, del, adds = 0, dels = 0; uintmax_t max_change = 0, max_len = 0; int total_files = data->nr; - int width, name_width, count; + int width, name_width, graph_width, number_width = 4, count; const char *reset, *add_c, *del_c; const char *line_prefix = ""; int extra_shown = 0; @@@ -1458,15 -1332,25 +1458,15 @@@ line_prefix = msg->buf; } - width = options->stat_width ? options->stat_width : 80; - name_width = options->stat_name_width ? options->stat_name_width : 50; count = options->stat_count ? options->stat_count : data->nr; - /* Sanity: give at least 5 columns to the graph, - * but leave at least 10 columns for the name. - */ - if (width < 25) - width = 25; - if (name_width < 10) - name_width = 10; - else if (width < name_width + 15) - name_width = width - 15; - - /* Find the longest filename and max number of changes */ reset = diff_get_color_opt(options, DIFF_RESET); add_c = diff_get_color_opt(options, DIFF_FILE_NEW); del_c = diff_get_color_opt(options, DIFF_FILE_OLD); + /* + * Find the longest filename and max number of changes + */ for (i = 0; (i < count) && (i < data->nr); i++) { struct diffstat_file *file = data->files[i]; uintmax_t change = file->added + file->deleted; @@@ -1487,72 -1371,19 +1487,72 @@@ } count = i; /* min(count, data->nr) */ - /* Compute the width of the graph part; - * 10 is for one blank at the beginning of the line plus - * " | count " between the name and the graph. + /* + * We have width = stat_width or term_columns() columns total. + * We want a maximum of min(max_len, stat_name_width) for the name part. + * We want a maximum of min(max_change, stat_graph_width) for the +- part. + * We also need 1 for " " and 4 + decimal_width(max_change) + * for " | NNNN " and one the empty column at the end, altogether + * 6 + decimal_width(max_change). * - * From here on, name_width is the width of the name area, - * and width is the width of the graph area. + * If there's not enough space, we will use the smaller of + * stat_name_width (if set) and 5/8*width for the filename, + * and the rest for constant elements + graph part, but no more + * than stat_graph_width for the graph part. + * (5/8 gives 50 for filename and 30 for the constant parts + graph + * for the standard terminal size). + * + * In other words: stat_width limits the maximum width, and + * stat_name_width fixes the maximum width of the filename, + * and is also used to divide available columns if there + * aren't enough. */ - name_width = (name_width < max_len) ? name_width : max_len; - if (width < (name_width + 10) + max_change) - width = width - (name_width + 10); + + if (options->stat_width == -1) + width = term_columns(); else - width = max_change; + width = options->stat_width ? options->stat_width : 80; + + if (options->stat_graph_width == -1) + options->stat_graph_width = diff_stat_graph_width; + /* + * Guarantee 3/8*16==6 for the graph part + * and 5/8*16==10 for the filename part + */ + if (width < 16 + 6 + number_width) + width = 16 + 6 + number_width; + + /* + * First assign sizes that are wanted, ignoring available width. + */ + graph_width = (options->stat_graph_width && + options->stat_graph_width < max_change) ? + options->stat_graph_width : max_change; + name_width = (options->stat_name_width > 0 && + options->stat_name_width < max_len) ? + options->stat_name_width : max_len; + + /* + * Adjust adjustable widths not to exceed maximum width + */ + if (name_width + number_width + 6 + graph_width > width) { + if (graph_width > width * 3/8 - number_width - 6) + graph_width = width * 3/8 - number_width - 6; + if (options->stat_graph_width && + graph_width > options->stat_graph_width) + graph_width = options->stat_graph_width; + if (name_width > width - number_width - 6 - graph_width) + name_width = width - number_width - 6 - graph_width; + else + graph_width = width - number_width - 6 - name_width; + } + + /* + * From here name_width is the width of the name area, + * and graph_width is the width of the graph area. + * max_change is used to scale graph properly. + */ for (i = 0; i < count; i++) { const char *prefix = ""; char *name = data->files[i]->print_name; @@@ -1608,20 -1439,9 +1608,20 @@@ adds += add; dels += del; - if (width <= max_change) { - add = scale_linear(add, width, max_change); - del = scale_linear(del, width, max_change); + if (graph_width <= max_change) { + int total = add + del; + + total = scale_linear(add + del, graph_width, max_change); + if (total < 2 && add && del) + /* width >= 2 due to the sanity check */ + total = 2; + if (add < del) { + add = scale_linear(add, graph_width, max_change); + del = total - add; + } else { + del = scale_linear(del, graph_width, max_change); + add = total - del; + } } fprintf(options->file, "%s", line_prefix); show_name(options->file, prefix, name, len); @@@ -1646,7 -1466,9 +1646,7 @@@ extra_shown = 1; } fprintf(options->file, "%s", line_prefix); - fprintf(options->file, - " %d files changed, %d insertions(+), %d deletions(-)\n", - total_files, adds, dels); + print_stat_summary(options->file, total_files, adds, dels); } static void show_shortstats(struct diffstat_t *data, struct diff_options *options) @@@ -1676,7 -1498,8 +1676,7 @@@ options->output_prefix_data); fprintf(options->file, "%s", msg->buf); } - fprintf(options->file, " %d files changed, %d insertions(+), %d deletions(-)\n", - total_files, adds, dels); + print_stat_summary(options->file, total_files, adds, dels); } static void show_numstat(struct diffstat_t *data, struct diff_options *options) @@@ -2125,6 -1948,20 +2125,6 @@@ static void emit_binary_diff(FILE *file emit_binary_diff_body(file, two, one, prefix); } -static void diff_filespec_load_driver(struct diff_filespec *one) -{ - /* Use already-loaded driver */ - if (one->driver) - return; - - if (S_ISREG(one->mode)) - one->driver = userdiff_find_by_path(one->path); - - /* Fallback to default settings */ - if (!one->driver) - one->driver = userdiff_find_by_name("default"); -} - int diff_filespec_is_binary(struct diff_filespec *one) { if (one->is_binary == -1) { @@@ -2150,6 -1987,12 +2150,6 @@@ static const struct userdiff_funcname * return one->driver->funcname.pattern ? &one->driver->funcname : NULL; } -static const char *userdiff_word_regex(struct diff_filespec *one) -{ - diff_filespec_load_driver(one); - return one->driver->word_regex; -} - void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b) { if (!options->a_prefix) @@@ -2299,7 -2142,7 +2299,7 @@@ static void builtin_diff(const char *na struct emit_callback ecbdata; const struct userdiff_funcname *pe; - if (!DIFF_XDL_TST(o, WHITESPACE_FLAGS) || must_show_header) { + if (must_show_header) { fprintf(o->file, "%s", header.buf); strbuf_reset(&header); } @@@ -2326,8 -2169,6 +2326,8 @@@ xecfg.ctxlen = o->context; xecfg.interhunkctxlen = o->interhunkcontext; xecfg.flags = XDL_EMIT_FUNCNAMES; + if (DIFF_OPT_TST(o, FUNCCONTEXT)) + xecfg.flags |= XDL_EMIT_FUNCCONTEXT; if (pe) xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags); if (!diffopts) @@@ -2336,8 -2177,42 +2336,8 @@@ xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10); else if (!prefixcmp(diffopts, "-u")) xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10); - if (o->word_diff) { - int i; - - ecbdata.diff_words = - xcalloc(1, sizeof(struct diff_words_data)); - ecbdata.diff_words->type = o->word_diff; - ecbdata.diff_words->opt = o; - if (!o->word_regex) - o->word_regex = userdiff_word_regex(one); - if (!o->word_regex) - o->word_regex = userdiff_word_regex(two); - if (!o->word_regex) - o->word_regex = diff_word_regex_cfg; - if (o->word_regex) { - ecbdata.diff_words->word_regex = (regex_t *) - xmalloc(sizeof(regex_t)); - if (regcomp(ecbdata.diff_words->word_regex, - o->word_regex, - REG_EXTENDED | REG_NEWLINE)) - die ("Invalid regular expression: %s", - o->word_regex); - } - for (i = 0; i < ARRAY_SIZE(diff_words_styles); i++) { - if (o->word_diff == diff_words_styles[i].type) { - ecbdata.diff_words->style = - &diff_words_styles[i]; - break; - } - } - if (want_color(o->use_color)) { - struct diff_words_style *st = ecbdata.diff_words->style; - st->old.color = diff_get_color_opt(o, DIFF_FILE_OLD); - st->new.color = diff_get_color_opt(o, DIFF_FILE_NEW); - st->ctx.color = diff_get_color_opt(o, DIFF_PLAIN); - } - } + if (o->word_diff) + init_diff_words_data(&ecbdata, o, one, two); xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata, &xpp, &xecfg); if (o->word_diff) @@@ -3146,7 -3021,6 +3146,7 @@@ void diff_setup(struct diff_options *op options->rename_limit = -1; options->dirstat_permille = diff_dirstat_permille_default; options->context = 3; + DIFF_OPT_SET(options, RENAME_EMPTY); options->change = diff_change; options->add_remove = diff_addremove; @@@ -3358,7 -3232,6 +3358,7 @@@ static int stat_opt(struct diff_option char *end; int width = options->stat_width; int name_width = options->stat_name_width; + int graph_width = options->stat_graph_width; int count = options->stat_count; int argcount = 1; @@@ -3387,16 -3260,6 +3387,16 @@@ name_width = strtoul(av[1], &end, 10); argcount = 2; } + } else if (!prefixcmp(arg, "-graph-width")) { + arg += strlen("-graph-width"); + if (*arg == '=') + graph_width = strtoul(arg + 1, &end, 10); + else if (!*arg && !av[1]) + die("Option '--stat-graph-width' requires a value"); + else if (!*arg) { + graph_width = strtoul(av[1], &end, 10); + argcount = 2; + } } else if (!prefixcmp(arg, "-count")) { arg += strlen("-count"); if (*arg == '=') @@@ -3422,7 -3285,6 +3422,7 @@@ return 0; options->output_format |= DIFF_FORMAT_DIFFSTAT; options->stat_name_width = name_width; + options->stat_graph_width = graph_width; options->stat_width = width; options->stat_count = count; return argcount; @@@ -3517,10 -3379,6 +3517,10 @@@ int diff_opt_parse(struct diff_options } else if (!strcmp(arg, "--no-renames")) options->detect_rename = 0; + else if (!strcmp(arg, "--rename-empty")) + DIFF_OPT_SET(options, RENAME_EMPTY); + else if (!strcmp(arg, "--no-rename-empty")) + DIFF_OPT_CLR(options, RENAME_EMPTY); else if (!strcmp(arg, "--relative")) DIFF_OPT_SET(options, RELATIVE_NAME); else if (!prefixcmp(arg, "--relative=")) { @@@ -3678,12 -3536,6 +3678,12 @@@ else if (opt_arg(arg, '\0', "inter-hunk-context", &options->interhunkcontext)) ; + else if (!strcmp(arg, "-W")) + DIFF_OPT_SET(options, FUNCCONTEXT); + else if (!strcmp(arg, "--function-context")) + DIFF_OPT_SET(options, FUNCCONTEXT); + else if (!strcmp(arg, "--no-function-context")) + DIFF_OPT_CLR(options, FUNCCONTEXT); else if ((argcount = parse_long_opt("output", av, &optarg))) { options->file = fopen(optarg, "w"); if (!options->file) @@@ -4414,6 -4266,12 +4414,12 @@@ void diff_flush(struct diff_options *op if (output_format & DIFF_FORMAT_PATCH) { if (separator) { + if (options->output_prefix) { + struct strbuf *msg = NULL; + msg = options->output_prefix(options, + options->output_prefix_data); + fwrite(msg->buf, msg->len, 1, stdout); + } putc(options->line_termination, options->file); if (options->stat_sep) { /* attach patch instead of inline */ diff --combined log-tree.c index cea8756866,f962203ec5..34c49e7b33 --- a/log-tree.c +++ b/log-tree.c @@@ -8,7 -8,6 +8,7 @@@ #include "refs.h" #include "string-list.h" #include "color.h" +#include "gpg-interface.h" struct decoration name_decoration = { "object names" }; @@@ -120,9 -119,9 +120,9 @@@ static int add_ref_decoration(const cha type = DECORATION_REF_REMOTE; else if (!prefixcmp(refname, "refs/tags/")) type = DECORATION_REF_TAG; - else if (!prefixcmp(refname, "refs/stash")) + else if (!strcmp(refname, "refs/stash")) type = DECORATION_REF_STASH; - else if (!prefixcmp(refname, "HEAD")) + else if (!strcmp(refname, "HEAD")) type = DECORATION_REF_HEAD; if (!cb_data || *(int *)cb_data == DECORATE_SHORT_REFS) @@@ -166,14 -165,6 +166,14 @@@ static void show_parents(struct commit } } +static void show_children(struct rev_info *opt, struct commit *commit, int abbrev) +{ + struct commit_list *p = lookup_decoration(&opt->children, &commit->object); + for ( ; p; p = p->next) { + printf(" %s", find_unique_abbrev(p->item->object.sha1, abbrev)); + } +} + void show_decorations(struct rev_info *opt, struct commit *commit) { const char *prefix; @@@ -404,129 -395,6 +404,129 @@@ void log_write_email_headers(struct rev *extra_headers_p = extra_headers; } +static void show_sig_lines(struct rev_info *opt, int status, const char *bol) +{ + const char *color, *reset, *eol; + + color = diff_get_color_opt(&opt->diffopt, + status ? DIFF_WHITESPACE : DIFF_FRAGINFO); + reset = diff_get_color_opt(&opt->diffopt, DIFF_RESET); + while (*bol) { + eol = strchrnul(bol, '\n'); + printf("%s%.*s%s%s", color, (int)(eol - bol), bol, reset, + *eol ? "\n" : ""); + bol = (*eol) ? (eol + 1) : eol; + } +} + +static void show_signature(struct rev_info *opt, struct commit *commit) +{ + struct strbuf payload = STRBUF_INIT; + struct strbuf signature = STRBUF_INIT; + struct strbuf gpg_output = STRBUF_INIT; + int status; + + if (parse_signed_commit(commit->object.sha1, &payload, &signature) <= 0) + goto out; + + status = verify_signed_buffer(payload.buf, payload.len, + signature.buf, signature.len, + &gpg_output); + if (status && !gpg_output.len) + strbuf_addstr(&gpg_output, "No signature\n"); + + show_sig_lines(opt, status, gpg_output.buf); + + out: + strbuf_release(&gpg_output); + strbuf_release(&payload); + strbuf_release(&signature); +} + +static int which_parent(const unsigned char *sha1, const struct commit *commit) +{ + int nth; + const struct commit_list *parent; + + for (nth = 0, parent = commit->parents; parent; parent = parent->next) { + if (!hashcmp(parent->item->object.sha1, sha1)) + return nth; + nth++; + } + return -1; +} + +static int is_common_merge(const struct commit *commit) +{ + return (commit->parents + && commit->parents->next + && !commit->parents->next->next); +} + +static void show_one_mergetag(struct rev_info *opt, + struct commit_extra_header *extra, + struct commit *commit) +{ + unsigned char sha1[20]; + struct tag *tag; + struct strbuf verify_message; + int status, nth; + size_t payload_size, gpg_message_offset; + + hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), sha1); + tag = lookup_tag(sha1); + if (!tag) + return; /* error message already given */ + + strbuf_init(&verify_message, 256); + if (parse_tag_buffer(tag, extra->value, extra->len)) + strbuf_addstr(&verify_message, "malformed mergetag\n"); + else if (is_common_merge(commit) && + !hashcmp(tag->tagged->sha1, + commit->parents->next->item->object.sha1)) + strbuf_addf(&verify_message, + "merged tag '%s'\n", tag->tag); + else if ((nth = which_parent(tag->tagged->sha1, commit)) < 0) + strbuf_addf(&verify_message, "tag %s names a non-parent %s\n", + tag->tag, tag->tagged->sha1); + else + strbuf_addf(&verify_message, + "parent #%d, tagged '%s'\n", nth + 1, tag->tag); + gpg_message_offset = verify_message.len; + + payload_size = parse_signature(extra->value, extra->len); + if ((extra->len <= payload_size) || + (verify_signed_buffer(extra->value, payload_size, + extra->value + payload_size, + extra->len - payload_size, + &verify_message) && + verify_message.len <= gpg_message_offset)) { + strbuf_addstr(&verify_message, "No signature\n"); + status = -1; + } + else if (strstr(verify_message.buf + gpg_message_offset, + ": Good signature from ")) + status = 0; + else + status = -1; + + show_sig_lines(opt, status, verify_message.buf); + strbuf_release(&verify_message); +} + +static void show_mergetag(struct rev_info *opt, struct commit *commit) +{ + struct commit_extra_header *extra, *to_free; + + to_free = read_commit_extra_headers(commit, NULL); + for (extra = to_free; extra; extra = extra->next) { + if (strcmp(extra->key, "mergetag")) + continue; /* not a merge tag */ + show_one_mergetag(opt, extra, commit); + } + free_commit_extra_headers(to_free); +} + void show_log(struct rev_info *opt) { struct strbuf msgbuf = STRBUF_INIT; @@@ -546,8 -414,6 +546,8 @@@ 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'); @@@ -607,8 -473,6 +607,8 @@@ 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, @@@ -638,11 -502,6 +638,11 @@@ } } + if (opt->show_signature) { + show_signature(opt, commit); + show_mergetag(opt, commit); + } + if (!commit->buffer) return; @@@ -711,14 -570,15 +711,15 @@@ int log_tree_diff_flush(struct rev_inf opt->verbose_header && opt->commit_format != CMIT_FMT_ONELINE) { int pch = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH; - if ((pch & opt->diffopt.output_format) == pch) - printf("---"); if (opt->diffopt.output_prefix) { struct strbuf *msg = NULL; msg = opt->diffopt.output_prefix(&opt->diffopt, opt->diffopt.output_prefix_data); fwrite(msg->buf, msg->len, 1, stdout); } + if ((pch & opt->diffopt.output_format) == pch) { + printf("---"); + } putchar('\n'); } } @@@ -728,7 -588,9 +729,7 @@@ static int do_diff_combined(struct rev_info *opt, struct commit *commit) { - unsigned const char *sha1 = commit->object.sha1; - - diff_tree_combined_merge(sha1, opt->dense_combined_merges, opt); + diff_tree_combined_merge(commit, opt->dense_combined_merges, opt); return !opt->loginfo; } diff --combined t/t4202-log.sh index 222f7559e9,19a0851e7a..32cf0bd218 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@@ -346,11 -346,11 +346,11 @@@ test_expect_success 'set up more tangle ' cat > expect <<\EOF -* Merge commit 'reach' +* Merge tag 'reach' |\ | \ | \ -*-. \ Merge commit 'octopus-a'; commit 'octopus-b' +*-. \ Merge tags 'octopus-a' and 'octopus-b' |\ \ \ * | | | seventh | | * | octopus-b @@@ -516,4 -516,294 +516,294 @@@ test_expect_success 'show added path un ) ' + cat >expect <<\EOF + * commit COMMIT_OBJECT_NAME + |\ Merge: MERGE_PARENTS + | | Author: A U Thor + | | + | | Merge HEADS DESCRIPTION + | | + | * commit COMMIT_OBJECT_NAME + | | Author: A U Thor + | | + | | reach + | | --- + | | reach.t | 1 + + | | 1 file changed, 1 insertion(+) + | | + | | diff --git a/reach.t b/reach.t + | | new file mode 100644 + | | index 0000000..10c9591 + | | --- /dev/null + | | +++ b/reach.t + | | @@ -0,0 +1 @@ + | | +reach + | | + | \ + *-. \ commit COMMIT_OBJECT_NAME + |\ \ \ Merge: MERGE_PARENTS + | | | | Author: A U Thor + | | | | + | | | | Merge HEADS DESCRIPTION + | | | | + | | * | commit COMMIT_OBJECT_NAME + | | |/ Author: A U Thor + | | | + | | | octopus-b + | | | --- + | | | octopus-b.t | 1 + + | | | 1 file changed, 1 insertion(+) + | | | + | | | diff --git a/octopus-b.t b/octopus-b.t + | | | new file mode 100644 + | | | index 0000000..d5fcad0 + | | | --- /dev/null + | | | +++ b/octopus-b.t + | | | @@ -0,0 +1 @@ + | | | +octopus-b + | | | + | * | commit COMMIT_OBJECT_NAME + | |/ Author: A U Thor + | | + | | octopus-a + | | --- + | | octopus-a.t | 1 + + | | 1 file changed, 1 insertion(+) + | | + | | diff --git a/octopus-a.t b/octopus-a.t + | | new file mode 100644 + | | index 0000000..11ee015 + | | --- /dev/null + | | +++ b/octopus-a.t + | | @@ -0,0 +1 @@ + | | +octopus-a + | | + * | commit COMMIT_OBJECT_NAME + |/ Author: A U Thor + | + | seventh + | --- + | seventh.t | 1 + + | 1 file changed, 1 insertion(+) + | + | diff --git a/seventh.t b/seventh.t + | new file mode 100644 + | index 0000000..9744ffc + | --- /dev/null + | +++ b/seventh.t + | @@ -0,0 +1 @@ + | +seventh + | + * commit COMMIT_OBJECT_NAME + |\ Merge: MERGE_PARENTS + | | Author: A U Thor + | | + | | Merge branch 'tangle' + | | + | * commit COMMIT_OBJECT_NAME + | |\ Merge: MERGE_PARENTS + | | | Author: A U Thor + | | | + | | | Merge branch 'side' (early part) into tangle + | | | + | * | commit COMMIT_OBJECT_NAME + | |\ \ Merge: MERGE_PARENTS + | | | | Author: A U Thor + | | | | + | | | | Merge branch 'master' (early part) into tangle + | | | | + | * | | commit COMMIT_OBJECT_NAME + | | | | Author: A U Thor + | | | | + | | | | tangle-a + | | | | --- + | | | | tangle-a | 1 + + | | | | 1 file changed, 1 insertion(+) + | | | | + | | | | diff --git a/tangle-a b/tangle-a + | | | | new file mode 100644 + | | | | index 0000000..7898192 + | | | | --- /dev/null + | | | | +++ b/tangle-a + | | | | @@ -0,0 +1 @@ + | | | | +a + | | | | + * | | | commit COMMIT_OBJECT_NAME + |\ \ \ \ Merge: MERGE_PARENTS + | | | | | Author: A U Thor + | | | | | + | | | | | Merge branch 'side' + | | | | | + | * | | | commit COMMIT_OBJECT_NAME + | | |_|/ Author: A U Thor + | |/| | + | | | | side-2 + | | | | --- + | | | | 2 | 1 + + | | | | 1 file changed, 1 insertion(+) + | | | | + | | | | diff --git a/2 b/2 + | | | | new file mode 100644 + | | | | index 0000000..0cfbf08 + | | | | --- /dev/null + | | | | +++ b/2 + | | | | @@ -0,0 +1 @@ + | | | | +2 + | | | | + | * | | commit COMMIT_OBJECT_NAME + | | | | Author: A U Thor + | | | | + | | | | side-1 + | | | | --- + | | | | 1 | 1 + + | | | | 1 file changed, 1 insertion(+) + | | | | + | | | | diff --git a/1 b/1 + | | | | new file mode 100644 + | | | | index 0000000..d00491f + | | | | --- /dev/null + | | | | +++ b/1 + | | | | @@ -0,0 +1 @@ + | | | | +1 + | | | | + * | | | commit COMMIT_OBJECT_NAME + | | | | Author: A U Thor + | | | | + | | | | Second + | | | | --- + | | | | one | 1 + + | | | | 1 file changed, 1 insertion(+) + | | | | + | | | | diff --git a/one b/one + | | | | new file mode 100644 + | | | | index 0000000..9a33383 + | | | | --- /dev/null + | | | | +++ b/one + | | | | @@ -0,0 +1 @@ + | | | | +case + | | | | + * | | | commit COMMIT_OBJECT_NAME + | |_|/ Author: A U Thor + |/| | + | | | sixth + | | | --- + | | | a/two | 1 - + | | | 1 file changed, 1 deletion(-) + | | | + | | | diff --git a/a/two b/a/two + | | | deleted file mode 100644 + | | | index 9245af5..0000000 + | | | --- a/a/two + | | | +++ /dev/null + | | | @@ -1 +0,0 @@ + | | | -ni + | | | + * | | commit COMMIT_OBJECT_NAME + | | | Author: A U Thor + | | | + | | | fifth + | | | --- + | | | a/two | 1 + + | | | 1 file changed, 1 insertion(+) + | | | + | | | diff --git a/a/two b/a/two + | | | new file mode 100644 + | | | index 0000000..9245af5 + | | | --- /dev/null + | | | +++ b/a/two + | | | @@ -0,0 +1 @@ + | | | +ni + | | | + * | | commit COMMIT_OBJECT_NAME + |/ / Author: A U Thor + | | + | | fourth + | | --- + | | ein | 1 + + | | 1 file changed, 1 insertion(+) + | | + | | diff --git a/ein b/ein + | | new file mode 100644 + | | index 0000000..9d7e69f + | | --- /dev/null + | | +++ b/ein + | | @@ -0,0 +1 @@ + | | +ichi + | | + * | commit COMMIT_OBJECT_NAME + |/ Author: A U Thor + | + | third + | --- + | ichi | 1 + + | one | 1 - + | 2 files changed, 1 insertion(+), 1 deletion(-) + | + | diff --git a/ichi b/ichi + | new file mode 100644 + | index 0000000..9d7e69f + | --- /dev/null + | +++ b/ichi + | @@ -0,0 +1 @@ + | +ichi + | diff --git a/one b/one + | deleted file mode 100644 + | index 9d7e69f..0000000 + | --- a/one + | +++ /dev/null + | @@ -1 +0,0 @@ + | -ichi + | + * commit COMMIT_OBJECT_NAME + | Author: A U Thor + | + | second + | --- + | one | 2 +- + | 1 file changed, 1 insertion(+), 1 deletion(-) + | + | diff --git a/one b/one + | index 5626abf..9d7e69f 100644 + | --- a/one + | +++ b/one + | @@ -1 +1 @@ + | -one + | +ichi + | + * commit COMMIT_OBJECT_NAME + Author: A U Thor + + initial + --- + one | 1 + + 1 file changed, 1 insertion(+) + + diff --git a/one b/one + new file mode 100644 + index 0000000..5626abf + --- /dev/null + +++ b/one + @@ -0,0 +1 @@ + +one + EOF + + sanitize_output () { + sed -e 's/ *$//' \ + -e 's/commit [0-9a-f]*$/commit COMMIT_OBJECT_NAME/' \ + -e 's/Merge: [ 0-9a-f]*$/Merge: MERGE_PARENTS/' \ + -e 's/Merge tag.*/Merge HEADS DESCRIPTION/' \ + -e 's/Merge commit.*/Merge HEADS DESCRIPTION/' \ + -e 's/, 0 deletions(-)//' \ + -e 's/, 0 insertions(+)//' \ + -e 's/ 1 files changed, / 1 file changed, /' \ + -e 's/, 1 deletions(-)/, 1 deletion(-)/' \ + -e 's/, 1 insertions(+)/, 1 insertion(+)/' + } + + test_expect_success 'log --graph with diff and stats' ' + git log --graph --pretty=short --stat -p >actual && + sanitize_output >actual.sanitized