log-tree.con commit Merge branch 'tb/blame-resurrect-convert-to-git' into maint (1d93ec9)
   1#include "cache.h"
   2#include "diff.h"
   3#include "commit.h"
   4#include "tag.h"
   5#include "graph.h"
   6#include "log-tree.h"
   7#include "reflog-walk.h"
   8#include "refs.h"
   9#include "string-list.h"
  10#include "color.h"
  11#include "gpg-interface.h"
  12#include "sequencer.h"
  13#include "line-log.h"
  14
  15static struct decoration name_decoration = { "object names" };
  16
  17static char decoration_colors[][COLOR_MAXLEN] = {
  18        GIT_COLOR_RESET,
  19        GIT_COLOR_BOLD_GREEN,   /* REF_LOCAL */
  20        GIT_COLOR_BOLD_RED,     /* REF_REMOTE */
  21        GIT_COLOR_BOLD_YELLOW,  /* REF_TAG */
  22        GIT_COLOR_BOLD_MAGENTA, /* REF_STASH */
  23        GIT_COLOR_BOLD_CYAN,    /* REF_HEAD */
  24        GIT_COLOR_BOLD_BLUE,    /* GRAFTED */
  25};
  26
  27static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix)
  28{
  29        if (want_color(decorate_use_color))
  30                return decoration_colors[ix];
  31        return "";
  32}
  33
  34static int parse_decorate_color_slot(const char *slot)
  35{
  36        /*
  37         * We're comparing with 'ignore-case' on
  38         * (because config.c sets them all tolower),
  39         * but let's match the letters in the literal
  40         * string values here with how they are
  41         * documented in Documentation/config.txt, for
  42         * consistency.
  43         *
  44         * We love being consistent, don't we?
  45         */
  46        if (!strcasecmp(slot, "branch"))
  47                return DECORATION_REF_LOCAL;
  48        if (!strcasecmp(slot, "remoteBranch"))
  49                return DECORATION_REF_REMOTE;
  50        if (!strcasecmp(slot, "tag"))
  51                return DECORATION_REF_TAG;
  52        if (!strcasecmp(slot, "stash"))
  53                return DECORATION_REF_STASH;
  54        if (!strcasecmp(slot, "HEAD"))
  55                return DECORATION_REF_HEAD;
  56        return -1;
  57}
  58
  59int parse_decorate_color_config(const char *var, const char *slot_name, const char *value)
  60{
  61        int slot = parse_decorate_color_slot(slot_name);
  62        if (slot < 0)
  63                return 0;
  64        if (!value)
  65                return config_error_nonbool(var);
  66        return color_parse(value, decoration_colors[slot]);
  67}
  68
  69/*
  70 * log-tree.c uses DIFF_OPT_TST for determining whether to use color
  71 * for showing the commit sha1, use the same check for --decorate
  72 */
  73#define decorate_get_color_opt(o, ix) \
  74        decorate_get_color((o)->use_color, ix)
  75
  76void add_name_decoration(enum decoration_type type, const char *name, struct object *obj)
  77{
  78        int nlen = strlen(name);
  79        struct name_decoration *res = xmalloc(sizeof(*res) + nlen + 1);
  80        memcpy(res->name, name, nlen + 1);
  81        res->type = type;
  82        res->next = add_decoration(&name_decoration, obj, res);
  83}
  84
  85const struct name_decoration *get_name_decoration(const struct object *obj)
  86{
  87        return lookup_decoration(&name_decoration, obj);
  88}
  89
  90static int add_ref_decoration(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
  91{
  92        struct object *obj;
  93        enum decoration_type type = DECORATION_NONE;
  94
  95        if (starts_with(refname, "refs/replace/")) {
  96                unsigned char original_sha1[20];
  97                if (!check_replace_refs)
  98                        return 0;
  99                if (get_sha1_hex(refname + 13, original_sha1)) {
 100                        warning("invalid replace ref %s", refname);
 101                        return 0;
 102                }
 103                obj = parse_object(original_sha1);
 104                if (obj)
 105                        add_name_decoration(DECORATION_GRAFTED, "replaced", obj);
 106                return 0;
 107        }
 108
 109        obj = parse_object(sha1);
 110        if (!obj)
 111                return 0;
 112
 113        if (starts_with(refname, "refs/heads/"))
 114                type = DECORATION_REF_LOCAL;
 115        else if (starts_with(refname, "refs/remotes/"))
 116                type = DECORATION_REF_REMOTE;
 117        else if (starts_with(refname, "refs/tags/"))
 118                type = DECORATION_REF_TAG;
 119        else if (!strcmp(refname, "refs/stash"))
 120                type = DECORATION_REF_STASH;
 121        else if (!strcmp(refname, "HEAD"))
 122                type = DECORATION_REF_HEAD;
 123
 124        if (!cb_data || *(int *)cb_data == DECORATE_SHORT_REFS)
 125                refname = prettify_refname(refname);
 126        add_name_decoration(type, refname, obj);
 127        while (obj->type == OBJ_TAG) {
 128                obj = ((struct tag *)obj)->tagged;
 129                if (!obj)
 130                        break;
 131                if (!obj->parsed)
 132                        parse_object(obj->sha1);
 133                add_name_decoration(DECORATION_REF_TAG, refname, obj);
 134        }
 135        return 0;
 136}
 137
 138static int add_graft_decoration(const struct commit_graft *graft, void *cb_data)
 139{
 140        struct commit *commit = lookup_commit(graft->sha1);
 141        if (!commit)
 142                return 0;
 143        add_name_decoration(DECORATION_GRAFTED, "grafted", &commit->object);
 144        return 0;
 145}
 146
 147void load_ref_decorations(int flags)
 148{
 149        static int loaded;
 150        if (!loaded) {
 151                loaded = 1;
 152                for_each_ref(add_ref_decoration, &flags);
 153                head_ref(add_ref_decoration, &flags);
 154                for_each_commit_graft(add_graft_decoration, NULL);
 155        }
 156}
 157
 158static void show_parents(struct commit *commit, int abbrev)
 159{
 160        struct commit_list *p;
 161        for (p = commit->parents; p ; p = p->next) {
 162                struct commit *parent = p->item;
 163                printf(" %s", find_unique_abbrev(parent->object.sha1, abbrev));
 164        }
 165}
 166
 167static void show_children(struct rev_info *opt, struct commit *commit, int abbrev)
 168{
 169        struct commit_list *p = lookup_decoration(&opt->children, &commit->object);
 170        for ( ; p; p = p->next) {
 171                printf(" %s", find_unique_abbrev(p->item->object.sha1, abbrev));
 172        }
 173}
 174
 175/*
 176 * Do we have HEAD in the output, and also the branch it points at?
 177 * If so, find that decoration entry for that current branch.
 178 */
 179static const struct name_decoration *current_pointed_by_HEAD(const struct name_decoration *decoration)
 180{
 181        const struct name_decoration *list, *head = NULL;
 182        const char *branch_name = NULL;
 183        unsigned char unused[20];
 184        int rru_flags;
 185
 186        /* First find HEAD */
 187        for (list = decoration; list; list = list->next)
 188                if (list->type == DECORATION_REF_HEAD) {
 189                        head = list;
 190                        break;
 191                }
 192        if (!head)
 193                return NULL;
 194
 195        /* Now resolve and find the matching current branch */
 196        branch_name = resolve_ref_unsafe("HEAD", 0, unused, &rru_flags);
 197        if (!(rru_flags & REF_ISSYMREF))
 198                return NULL;
 199        if (!skip_prefix(branch_name, "refs/heads/", &branch_name))
 200                return NULL;
 201
 202        /* OK, do we have that ref in the list? */
 203        for (list = decoration; list; list = list->next)
 204                if ((list->type == DECORATION_REF_LOCAL) &&
 205                    !strcmp(branch_name, list->name)) {
 206                        return list;
 207                }
 208
 209        return NULL;
 210}
 211
 212/*
 213 * The caller makes sure there is no funny color before calling.
 214 * format_decorations_extended makes sure the same after return.
 215 */
 216void format_decorations_extended(struct strbuf *sb,
 217                        const struct commit *commit,
 218                        int use_color,
 219                        const char *prefix,
 220                        const char *separator,
 221                        const char *suffix)
 222{
 223        const struct name_decoration *decoration;
 224        const struct name_decoration *current_and_HEAD;
 225        const char *color_commit =
 226                diff_get_color(use_color, DIFF_COMMIT);
 227        const char *color_reset =
 228                decorate_get_color(use_color, DECORATION_NONE);
 229
 230        decoration = get_name_decoration(&commit->object);
 231        if (!decoration)
 232                return;
 233
 234        current_and_HEAD = current_pointed_by_HEAD(decoration);
 235        while (decoration) {
 236                /*
 237                 * When both current and HEAD are there, only
 238                 * show HEAD->current where HEAD would have
 239                 * appeared, skipping the entry for current.
 240                 */
 241                if (decoration != current_and_HEAD) {
 242                        strbuf_addstr(sb, color_commit);
 243                        strbuf_addstr(sb, prefix);
 244                        strbuf_addstr(sb, color_reset);
 245                        strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
 246                        if (decoration->type == DECORATION_REF_TAG)
 247                                strbuf_addstr(sb, "tag: ");
 248
 249                        strbuf_addstr(sb, decoration->name);
 250
 251                        if (current_and_HEAD &&
 252                            decoration->type == DECORATION_REF_HEAD) {
 253                                strbuf_addstr(sb, color_reset);
 254                                strbuf_addstr(sb, color_commit);
 255                                strbuf_addstr(sb, " -> ");
 256                                strbuf_addstr(sb, color_reset);
 257                                strbuf_addstr(sb, decorate_get_color(use_color, current_and_HEAD->type));
 258                                strbuf_addstr(sb, current_and_HEAD->name);
 259                        }
 260                        strbuf_addstr(sb, color_reset);
 261
 262                        prefix = separator;
 263                }
 264                decoration = decoration->next;
 265        }
 266        strbuf_addstr(sb, color_commit);
 267        strbuf_addstr(sb, suffix);
 268        strbuf_addstr(sb, color_reset);
 269}
 270
 271void show_decorations(struct rev_info *opt, struct commit *commit)
 272{
 273        struct strbuf sb = STRBUF_INIT;
 274
 275        if (opt->show_source && commit->util)
 276                printf("\t%s", (char *) commit->util);
 277        if (!opt->show_decorations)
 278                return;
 279        format_decorations(&sb, commit, opt->diffopt.use_color);
 280        fputs(sb.buf, stdout);
 281        strbuf_release(&sb);
 282}
 283
 284static unsigned int digits_in_number(unsigned int number)
 285{
 286        unsigned int i = 10, result = 1;
 287        while (i <= number) {
 288                i *= 10;
 289                result++;
 290        }
 291        return result;
 292}
 293
 294void fmt_output_subject(struct strbuf *filename,
 295                        const char *subject,
 296                        struct rev_info *info)
 297{
 298        const char *suffix = info->patch_suffix;
 299        int nr = info->nr;
 300        int start_len = filename->len;
 301        int max_len = start_len + FORMAT_PATCH_NAME_MAX - (strlen(suffix) + 1);
 302
 303        if (0 < info->reroll_count)
 304                strbuf_addf(filename, "v%d-", info->reroll_count);
 305        strbuf_addf(filename, "%04d-%s", nr, subject);
 306
 307        if (max_len < filename->len)
 308                strbuf_setlen(filename, max_len);
 309        strbuf_addstr(filename, suffix);
 310}
 311
 312void fmt_output_commit(struct strbuf *filename,
 313                       struct commit *commit,
 314                       struct rev_info *info)
 315{
 316        struct pretty_print_context ctx = {0};
 317        struct strbuf subject = STRBUF_INIT;
 318
 319        format_commit_message(commit, "%f", &subject, &ctx);
 320        fmt_output_subject(filename, subject.buf, info);
 321        strbuf_release(&subject);
 322}
 323
 324void log_write_email_headers(struct rev_info *opt, struct commit *commit,
 325                             const char **subject_p,
 326                             const char **extra_headers_p,
 327                             int *need_8bit_cte_p)
 328{
 329        const char *subject = NULL;
 330        const char *extra_headers = opt->extra_headers;
 331        const char *name = sha1_to_hex(commit->object.sha1);
 332
 333        *need_8bit_cte_p = 0; /* unknown */
 334        if (opt->total > 0) {
 335                static char buffer[64];
 336                snprintf(buffer, sizeof(buffer),
 337                         "Subject: [%s%s%0*d/%d] ",
 338                         opt->subject_prefix,
 339                         *opt->subject_prefix ? " " : "",
 340                         digits_in_number(opt->total),
 341                         opt->nr, opt->total);
 342                subject = buffer;
 343        } else if (opt->total == 0 && opt->subject_prefix && *opt->subject_prefix) {
 344                static char buffer[256];
 345                snprintf(buffer, sizeof(buffer),
 346                         "Subject: [%s] ",
 347                         opt->subject_prefix);
 348                subject = buffer;
 349        } else {
 350                subject = "Subject: ";
 351        }
 352
 353        printf("From %s Mon Sep 17 00:00:00 2001\n", name);
 354        graph_show_oneline(opt->graph);
 355        if (opt->message_id) {
 356                printf("Message-Id: <%s>\n", opt->message_id);
 357                graph_show_oneline(opt->graph);
 358        }
 359        if (opt->ref_message_ids && opt->ref_message_ids->nr > 0) {
 360                int i, n;
 361                n = opt->ref_message_ids->nr;
 362                printf("In-Reply-To: <%s>\n", opt->ref_message_ids->items[n-1].string);
 363                for (i = 0; i < n; i++)
 364                        printf("%s<%s>\n", (i > 0 ? "\t" : "References: "),
 365                               opt->ref_message_ids->items[i].string);
 366                graph_show_oneline(opt->graph);
 367        }
 368        if (opt->mime_boundary) {
 369                static char subject_buffer[1024];
 370                static char buffer[1024];
 371                struct strbuf filename =  STRBUF_INIT;
 372                *need_8bit_cte_p = -1; /* NEVER */
 373                snprintf(subject_buffer, sizeof(subject_buffer) - 1,
 374                         "%s"
 375                         "MIME-Version: 1.0\n"
 376                         "Content-Type: multipart/mixed;"
 377                         " boundary=\"%s%s\"\n"
 378                         "\n"
 379                         "This is a multi-part message in MIME "
 380                         "format.\n"
 381                         "--%s%s\n"
 382                         "Content-Type: text/plain; "
 383                         "charset=UTF-8; format=fixed\n"
 384                         "Content-Transfer-Encoding: 8bit\n\n",
 385                         extra_headers ? extra_headers : "",
 386                         mime_boundary_leader, opt->mime_boundary,
 387                         mime_boundary_leader, opt->mime_boundary);
 388                extra_headers = subject_buffer;
 389
 390                if (opt->numbered_files)
 391                        strbuf_addf(&filename, "%d", opt->nr);
 392                else
 393                        fmt_output_commit(&filename, commit, opt);
 394                snprintf(buffer, sizeof(buffer) - 1,
 395                         "\n--%s%s\n"
 396                         "Content-Type: text/x-patch;"
 397                         " name=\"%s\"\n"
 398                         "Content-Transfer-Encoding: 8bit\n"
 399                         "Content-Disposition: %s;"
 400                         " filename=\"%s\"\n\n",
 401                         mime_boundary_leader, opt->mime_boundary,
 402                         filename.buf,
 403                         opt->no_inline ? "attachment" : "inline",
 404                         filename.buf);
 405                opt->diffopt.stat_sep = buffer;
 406                strbuf_release(&filename);
 407        }
 408        *subject_p = subject;
 409        *extra_headers_p = extra_headers;
 410}
 411
 412static void show_sig_lines(struct rev_info *opt, int status, const char *bol)
 413{
 414        const char *color, *reset, *eol;
 415
 416        color = diff_get_color_opt(&opt->diffopt,
 417                                   status ? DIFF_WHITESPACE : DIFF_FRAGINFO);
 418        reset = diff_get_color_opt(&opt->diffopt, DIFF_RESET);
 419        while (*bol) {
 420                eol = strchrnul(bol, '\n');
 421                printf("%s%.*s%s%s", color, (int)(eol - bol), bol, reset,
 422                       *eol ? "\n" : "");
 423                graph_show_oneline(opt->graph);
 424                bol = (*eol) ? (eol + 1) : eol;
 425        }
 426}
 427
 428static void show_signature(struct rev_info *opt, struct commit *commit)
 429{
 430        struct strbuf payload = STRBUF_INIT;
 431        struct strbuf signature = STRBUF_INIT;
 432        struct strbuf gpg_output = STRBUF_INIT;
 433        int status;
 434
 435        if (parse_signed_commit(commit, &payload, &signature) <= 0)
 436                goto out;
 437
 438        status = verify_signed_buffer(payload.buf, payload.len,
 439                                      signature.buf, signature.len,
 440                                      &gpg_output, NULL);
 441        if (status && !gpg_output.len)
 442                strbuf_addstr(&gpg_output, "No signature\n");
 443
 444        show_sig_lines(opt, status, gpg_output.buf);
 445
 446 out:
 447        strbuf_release(&gpg_output);
 448        strbuf_release(&payload);
 449        strbuf_release(&signature);
 450}
 451
 452static int which_parent(const unsigned char *sha1, const struct commit *commit)
 453{
 454        int nth;
 455        const struct commit_list *parent;
 456
 457        for (nth = 0, parent = commit->parents; parent; parent = parent->next) {
 458                if (!hashcmp(parent->item->object.sha1, sha1))
 459                        return nth;
 460                nth++;
 461        }
 462        return -1;
 463}
 464
 465static int is_common_merge(const struct commit *commit)
 466{
 467        return (commit->parents
 468                && commit->parents->next
 469                && !commit->parents->next->next);
 470}
 471
 472static void show_one_mergetag(struct commit *commit,
 473                              struct commit_extra_header *extra,
 474                              void *data)
 475{
 476        struct rev_info *opt = (struct rev_info *)data;
 477        unsigned char sha1[20];
 478        struct tag *tag;
 479        struct strbuf verify_message;
 480        int status, nth;
 481        size_t payload_size, gpg_message_offset;
 482
 483        hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), sha1);
 484        tag = lookup_tag(sha1);
 485        if (!tag)
 486                return; /* error message already given */
 487
 488        strbuf_init(&verify_message, 256);
 489        if (parse_tag_buffer(tag, extra->value, extra->len))
 490                strbuf_addstr(&verify_message, "malformed mergetag\n");
 491        else if (is_common_merge(commit) &&
 492                 !hashcmp(tag->tagged->sha1,
 493                          commit->parents->next->item->object.sha1))
 494                strbuf_addf(&verify_message,
 495                            "merged tag '%s'\n", tag->tag);
 496        else if ((nth = which_parent(tag->tagged->sha1, commit)) < 0)
 497                strbuf_addf(&verify_message, "tag %s names a non-parent %s\n",
 498                                    tag->tag, tag->tagged->sha1);
 499        else
 500                strbuf_addf(&verify_message,
 501                            "parent #%d, tagged '%s'\n", nth + 1, tag->tag);
 502        gpg_message_offset = verify_message.len;
 503
 504        payload_size = parse_signature(extra->value, extra->len);
 505        status = -1;
 506        if (extra->len > payload_size) {
 507                /* could have a good signature */
 508                if (!verify_signed_buffer(extra->value, payload_size,
 509                                          extra->value + payload_size,
 510                                          extra->len - payload_size,
 511                                          &verify_message, NULL))
 512                        status = 0; /* good */
 513                else if (verify_message.len <= gpg_message_offset)
 514                        strbuf_addstr(&verify_message, "No signature\n");
 515                /* otherwise we couldn't verify, which is shown as bad */
 516        }
 517
 518        show_sig_lines(opt, status, verify_message.buf);
 519        strbuf_release(&verify_message);
 520}
 521
 522static void show_mergetag(struct rev_info *opt, struct commit *commit)
 523{
 524        for_each_mergetag(show_one_mergetag, commit, opt);
 525}
 526
 527void show_log(struct rev_info *opt)
 528{
 529        struct strbuf msgbuf = STRBUF_INIT;
 530        struct log_info *log = opt->loginfo;
 531        struct commit *commit = log->commit, *parent = log->parent;
 532        int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40;
 533        const char *extra_headers = opt->extra_headers;
 534        struct pretty_print_context ctx = {0};
 535
 536        opt->loginfo = NULL;
 537        if (!opt->verbose_header) {
 538                graph_show_commit(opt->graph);
 539
 540                if (!opt->graph)
 541                        put_revision_mark(opt, commit);
 542                fputs(find_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
 543                if (opt->print_parents)
 544                        show_parents(commit, abbrev_commit);
 545                if (opt->children.name)
 546                        show_children(opt, commit, abbrev_commit);
 547                show_decorations(opt, commit);
 548                if (opt->graph && !graph_is_commit_finished(opt->graph)) {
 549                        putchar('\n');
 550                        graph_show_remainder(opt->graph);
 551                }
 552                putchar(opt->diffopt.line_termination);
 553                return;
 554        }
 555
 556        /*
 557         * If use_terminator is set, we already handled any record termination
 558         * at the end of the last record.
 559         * Otherwise, add a diffopt.line_termination character before all
 560         * entries but the first.  (IOW, as a separator between entries)
 561         */
 562        if (opt->shown_one && !opt->use_terminator) {
 563                /*
 564                 * If entries are separated by a newline, the output
 565                 * should look human-readable.  If the last entry ended
 566                 * with a newline, print the graph output before this
 567                 * newline.  Otherwise it will end up as a completely blank
 568                 * line and will look like a gap in the graph.
 569                 *
 570                 * If the entry separator is not a newline, the output is
 571                 * primarily intended for programmatic consumption, and we
 572                 * never want the extra graph output before the entry
 573                 * separator.
 574                 */
 575                if (opt->diffopt.line_termination == '\n' &&
 576                    !opt->missing_newline)
 577                        graph_show_padding(opt->graph);
 578                putchar(opt->diffopt.line_termination);
 579        }
 580        opt->shown_one = 1;
 581
 582        /*
 583         * If the history graph was requested,
 584         * print the graph, up to this commit's line
 585         */
 586        graph_show_commit(opt->graph);
 587
 588        /*
 589         * Print header line of header..
 590         */
 591
 592        if (opt->commit_format == CMIT_FMT_EMAIL) {
 593                log_write_email_headers(opt, commit, &ctx.subject, &extra_headers,
 594                                        &ctx.need_8bit_cte);
 595        } else if (opt->commit_format != CMIT_FMT_USERFORMAT) {
 596                fputs(diff_get_color_opt(&opt->diffopt, DIFF_COMMIT), stdout);
 597                if (opt->commit_format != CMIT_FMT_ONELINE)
 598                        fputs("commit ", stdout);
 599
 600                if (!opt->graph)
 601                        put_revision_mark(opt, commit);
 602                fputs(find_unique_abbrev(commit->object.sha1, abbrev_commit),
 603                      stdout);
 604                if (opt->print_parents)
 605                        show_parents(commit, abbrev_commit);
 606                if (opt->children.name)
 607                        show_children(opt, commit, abbrev_commit);
 608                if (parent)
 609                        printf(" (from %s)",
 610                               find_unique_abbrev(parent->object.sha1,
 611                                                  abbrev_commit));
 612                fputs(diff_get_color_opt(&opt->diffopt, DIFF_RESET), stdout);
 613                show_decorations(opt, commit);
 614                if (opt->commit_format == CMIT_FMT_ONELINE) {
 615                        putchar(' ');
 616                } else {
 617                        putchar('\n');
 618                        graph_show_oneline(opt->graph);
 619                }
 620                if (opt->reflog_info) {
 621                        /*
 622                         * setup_revisions() ensures that opt->reflog_info
 623                         * and opt->graph cannot both be set,
 624                         * so we don't need to worry about printing the
 625                         * graph info here.
 626                         */
 627                        show_reflog_message(opt->reflog_info,
 628                                            opt->commit_format == CMIT_FMT_ONELINE,
 629                                            opt->date_mode,
 630                                            opt->date_mode_explicit);
 631                        if (opt->commit_format == CMIT_FMT_ONELINE)
 632                                return;
 633                }
 634        }
 635
 636        if (opt->show_signature) {
 637                show_signature(opt, commit);
 638                show_mergetag(opt, commit);
 639        }
 640
 641        if (!get_cached_commit_buffer(commit, NULL))
 642                return;
 643
 644        if (opt->show_notes) {
 645                int raw;
 646                struct strbuf notebuf = STRBUF_INIT;
 647
 648                raw = (opt->commit_format == CMIT_FMT_USERFORMAT);
 649                format_display_notes(commit->object.sha1, &notebuf,
 650                                     get_log_output_encoding(), raw);
 651                ctx.notes_message = notebuf.len
 652                        ? strbuf_detach(&notebuf, NULL)
 653                        : xcalloc(1, 1);
 654        }
 655
 656        /*
 657         * And then the pretty-printed message itself
 658         */
 659        if (ctx.need_8bit_cte >= 0 && opt->add_signoff)
 660                ctx.need_8bit_cte =
 661                        has_non_ascii(fmt_name(getenv("GIT_COMMITTER_NAME"),
 662                                               getenv("GIT_COMMITTER_EMAIL")));
 663        ctx.date_mode = opt->date_mode;
 664        ctx.date_mode_explicit = opt->date_mode_explicit;
 665        ctx.abbrev = opt->diffopt.abbrev;
 666        ctx.after_subject = extra_headers;
 667        ctx.preserve_subject = opt->preserve_subject;
 668        ctx.reflog_info = opt->reflog_info;
 669        ctx.fmt = opt->commit_format;
 670        ctx.mailmap = opt->mailmap;
 671        ctx.color = opt->diffopt.use_color;
 672        ctx.output_encoding = get_log_output_encoding();
 673        if (opt->from_ident.mail_begin && opt->from_ident.name_begin)
 674                ctx.from_ident = &opt->from_ident;
 675        pretty_print_commit(&ctx, commit, &msgbuf);
 676
 677        if (opt->add_signoff)
 678                append_signoff(&msgbuf, 0, APPEND_SIGNOFF_DEDUP);
 679
 680        if ((ctx.fmt != CMIT_FMT_USERFORMAT) &&
 681            ctx.notes_message && *ctx.notes_message) {
 682                if (ctx.fmt == CMIT_FMT_EMAIL) {
 683                        strbuf_addstr(&msgbuf, "---\n");
 684                        opt->shown_dashes = 1;
 685                }
 686                strbuf_addstr(&msgbuf, ctx.notes_message);
 687        }
 688
 689        if (opt->show_log_size) {
 690                printf("log size %i\n", (int)msgbuf.len);
 691                graph_show_oneline(opt->graph);
 692        }
 693
 694        /*
 695         * Set opt->missing_newline if msgbuf doesn't
 696         * end in a newline (including if it is empty)
 697         */
 698        if (!msgbuf.len || msgbuf.buf[msgbuf.len - 1] != '\n')
 699                opt->missing_newline = 1;
 700        else
 701                opt->missing_newline = 0;
 702
 703        if (opt->graph)
 704                graph_show_commit_msg(opt->graph, &msgbuf);
 705        else
 706                fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
 707        if (opt->use_terminator && !commit_format_is_empty(opt->commit_format)) {
 708                if (!opt->missing_newline)
 709                        graph_show_padding(opt->graph);
 710                putchar(opt->diffopt.line_termination);
 711        }
 712
 713        strbuf_release(&msgbuf);
 714        free(ctx.notes_message);
 715}
 716
 717int log_tree_diff_flush(struct rev_info *opt)
 718{
 719        opt->shown_dashes = 0;
 720        diffcore_std(&opt->diffopt);
 721
 722        if (diff_queue_is_empty()) {
 723                int saved_fmt = opt->diffopt.output_format;
 724                opt->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT;
 725                diff_flush(&opt->diffopt);
 726                opt->diffopt.output_format = saved_fmt;
 727                return 0;
 728        }
 729
 730        if (opt->loginfo && !opt->no_commit_id) {
 731                show_log(opt);
 732                if ((opt->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT) &&
 733                    opt->verbose_header &&
 734                    opt->commit_format != CMIT_FMT_ONELINE &&
 735                    !commit_format_is_empty(opt->commit_format)) {
 736                        /*
 737                         * When showing a verbose header (i.e. log message),
 738                         * and not in --pretty=oneline format, we would want
 739                         * an extra newline between the end of log and the
 740                         * diff/diffstat output for readability.
 741                         */
 742                        int pch = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH;
 743                        if (opt->diffopt.output_prefix) {
 744                                struct strbuf *msg = NULL;
 745                                msg = opt->diffopt.output_prefix(&opt->diffopt,
 746                                        opt->diffopt.output_prefix_data);
 747                                fwrite(msg->buf, msg->len, 1, stdout);
 748                        }
 749
 750                        /*
 751                         * We may have shown three-dashes line early
 752                         * between notes and the log message, in which
 753                         * case we only want a blank line after the
 754                         * notes without (an extra) three-dashes line.
 755                         * Otherwise, we show the three-dashes line if
 756                         * we are showing the patch with diffstat, but
 757                         * in that case, there is no extra blank line
 758                         * after the three-dashes line.
 759                         */
 760                        if (!opt->shown_dashes &&
 761                            (pch & opt->diffopt.output_format) == pch)
 762                                printf("---");
 763                        putchar('\n');
 764                }
 765        }
 766        diff_flush(&opt->diffopt);
 767        return 1;
 768}
 769
 770static int do_diff_combined(struct rev_info *opt, struct commit *commit)
 771{
 772        diff_tree_combined_merge(commit, opt->dense_combined_merges, opt);
 773        return !opt->loginfo;
 774}
 775
 776/*
 777 * Show the diff of a commit.
 778 *
 779 * Return true if we printed any log info messages
 780 */
 781static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log_info *log)
 782{
 783        int showed_log;
 784        struct commit_list *parents;
 785        unsigned const char *sha1;
 786
 787        if (!opt->diff && !DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS))
 788                return 0;
 789
 790        parse_commit_or_die(commit);
 791        sha1 = commit->tree->object.sha1;
 792
 793        /* Root commit? */
 794        parents = get_saved_parents(opt, commit);
 795        if (!parents) {
 796                if (opt->show_root_diff) {
 797                        diff_root_tree_sha1(sha1, "", &opt->diffopt);
 798                        log_tree_diff_flush(opt);
 799                }
 800                return !opt->loginfo;
 801        }
 802
 803        /* More than one parent? */
 804        if (parents && parents->next) {
 805                if (opt->ignore_merges)
 806                        return 0;
 807                else if (opt->combine_merges)
 808                        return do_diff_combined(opt, commit);
 809                else if (opt->first_parent_only) {
 810                        /*
 811                         * Generate merge log entry only for the first
 812                         * parent, showing summary diff of the others
 813                         * we merged _in_.
 814                         */
 815                        parse_commit_or_die(parents->item);
 816                        diff_tree_sha1(parents->item->tree->object.sha1,
 817                                       sha1, "", &opt->diffopt);
 818                        log_tree_diff_flush(opt);
 819                        return !opt->loginfo;
 820                }
 821
 822                /* If we show individual diffs, show the parent info */
 823                log->parent = parents->item;
 824        }
 825
 826        showed_log = 0;
 827        for (;;) {
 828                struct commit *parent = parents->item;
 829
 830                parse_commit_or_die(parent);
 831                diff_tree_sha1(parent->tree->object.sha1,
 832                               sha1, "", &opt->diffopt);
 833                log_tree_diff_flush(opt);
 834
 835                showed_log |= !opt->loginfo;
 836
 837                /* Set up the log info for the next parent, if any.. */
 838                parents = parents->next;
 839                if (!parents)
 840                        break;
 841                log->parent = parents->item;
 842                opt->loginfo = log;
 843        }
 844        return showed_log;
 845}
 846
 847int log_tree_commit(struct rev_info *opt, struct commit *commit)
 848{
 849        struct log_info log;
 850        int shown;
 851
 852        log.commit = commit;
 853        log.parent = NULL;
 854        opt->loginfo = &log;
 855
 856        if (opt->line_level_traverse)
 857                return line_log_print(opt, commit);
 858
 859        if (opt->track_linear && !opt->linear && !opt->reverse_output_stage)
 860                printf("\n%s\n", opt->break_bar);
 861        shown = log_tree_diff(opt, commit, &log);
 862        if (!shown && opt->loginfo && opt->always_show_header) {
 863                log.parent = NULL;
 864                show_log(opt);
 865                shown = 1;
 866        }
 867        if (opt->track_linear && !opt->linear && opt->reverse_output_stage)
 868                printf("\n%s\n", opt->break_bar);
 869        opt->loginfo = NULL;
 870        maybe_flush_or_die(stdout, "stdout");
 871        return shown;
 872}