c0a44320223a4d868f397c1a2338f6a44a64fffb
   1
   2#include "cache.h"
   3#include "diff.h"
   4#include "commit.h"
   5#include "log-tree.h"
   6
   7void show_log(struct rev_info *opt, struct log_info *log, const char *sep)
   8{
   9        static char this_header[16384];
  10        struct commit *commit = log->commit, *parent = log->parent;
  11        int abbrev = opt->diffopt.abbrev;
  12        int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40;
  13        int len;
  14
  15        opt->loginfo = NULL;
  16        if (!opt->verbose_header) {
  17                puts(sha1_to_hex(commit->object.sha1));
  18                return;
  19        }
  20
  21        /*
  22         * Whitespace between commit messages, unless we are oneline
  23         */
  24        if (opt->shown_one && opt->commit_format != CMIT_FMT_ONELINE)
  25                putchar('\n');
  26        opt->shown_one = 1;
  27
  28        /*
  29         * Print header line of header..
  30         */
  31        printf("%s%s",
  32                opt->commit_format == CMIT_FMT_ONELINE ? "" : "commit ",
  33                diff_unique_abbrev(commit->object.sha1, abbrev_commit));
  34        if (parent) 
  35                printf(" (from %s)", diff_unique_abbrev(parent->object.sha1, abbrev_commit));
  36        putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n');
  37
  38        /*
  39         * And then the pretty-printed message itself
  40         */
  41        len = pretty_print_commit(opt->commit_format, commit, ~0u, this_header, sizeof(this_header), abbrev);
  42        printf("%s%s", this_header, sep);
  43}
  44
  45int log_tree_diff_flush(struct rev_info *opt)
  46{
  47        diffcore_std(&opt->diffopt);
  48
  49        if (diff_queue_is_empty()) {
  50                int saved_fmt = opt->diffopt.output_format;
  51                opt->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT;
  52                diff_flush(&opt->diffopt);
  53                opt->diffopt.output_format = saved_fmt;
  54                return 0;
  55        }
  56
  57        if (opt->loginfo && !opt->no_commit_id)
  58                show_log(opt, opt->loginfo, "\n");
  59        diff_flush(&opt->diffopt);
  60        return 1;
  61}
  62
  63static int diff_root_tree(struct rev_info *opt,
  64                          const unsigned char *new, const char *base)
  65{
  66        int retval;
  67        void *tree;
  68        struct tree_desc empty, real;
  69
  70        tree = read_object_with_reference(new, tree_type, &real.size, NULL);
  71        if (!tree)
  72                die("unable to read root tree (%s)", sha1_to_hex(new));
  73        real.buf = tree;
  74
  75        empty.buf = "";
  76        empty.size = 0;
  77        retval = diff_tree(&empty, &real, base, &opt->diffopt);
  78        free(tree);
  79        log_tree_diff_flush(opt);
  80        return retval;
  81}
  82
  83static int do_diff_combined(struct rev_info *opt, struct commit *commit)
  84{
  85        unsigned const char *sha1 = commit->object.sha1;
  86
  87        diff_tree_combined_merge(sha1, opt->dense_combined_merges, opt);
  88        return !opt->loginfo;
  89}
  90
  91/*
  92 * Show the diff of a commit.
  93 *
  94 * Return true if we printed any log info messages
  95 */
  96static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log_info *log)
  97{
  98        int showed_log;
  99        struct commit_list *parents;
 100        unsigned const char *sha1 = commit->object.sha1;
 101
 102        if (!opt->diff)
 103                return 0;
 104
 105        /* Root commit? */
 106        parents = commit->parents;
 107        if (!parents) {
 108                if (opt->show_root_diff)
 109                        diff_root_tree(opt, sha1, "");
 110                return !opt->loginfo;
 111        }
 112
 113        /* More than one parent? */
 114        if (parents && parents->next) {
 115                if (opt->ignore_merges)
 116                        return 0;
 117                else if (opt->combine_merges)
 118                        return do_diff_combined(opt, commit);
 119
 120                /* If we show individual diffs, show the parent info */
 121                log->parent = parents->item;
 122        }
 123
 124        showed_log = 0;
 125        for (;;) {
 126                struct commit *parent = parents->item;
 127
 128                diff_tree_sha1(parent->object.sha1, sha1, "", &opt->diffopt);
 129                log_tree_diff_flush(opt);
 130
 131                showed_log |= !opt->loginfo;
 132
 133                /* Set up the log info for the next parent, if any.. */
 134                parents = parents->next;
 135                if (!parents)
 136                        break;
 137                log->parent = parents->item;
 138                opt->loginfo = log;
 139        }
 140        return showed_log;
 141}
 142
 143int log_tree_commit(struct rev_info *opt, struct commit *commit)
 144{
 145        struct log_info log;
 146
 147        log.commit = commit;
 148        log.parent = NULL;
 149        opt->loginfo = &log;
 150
 151        if (!log_tree_diff(opt, commit, &log) && opt->loginfo && opt->always_show_header) {
 152                log.parent = NULL;
 153                show_log(opt, opt->loginfo, "");
 154        }
 155        opt->loginfo = NULL;
 156        return 0;
 157}