diff-tree.con commit Merge git://git.kernel.org/pub/scm/gitk/gitk (1a17ee2)
   1#include "cache.h"
   2#include "diff.h"
   3#include "commit.h"
   4#include "log-tree.h"
   5
   6static struct log_tree_opt log_tree_opt;
   7
   8static int diff_tree_commit_sha1(const unsigned char *sha1)
   9{
  10        struct commit *commit = lookup_commit_reference(sha1);
  11        if (!commit)
  12                return -1;
  13        return log_tree_commit(&log_tree_opt, commit);
  14}
  15
  16static int diff_tree_stdin(char *line)
  17{
  18        int len = strlen(line);
  19        unsigned char sha1[20];
  20        struct commit *commit;
  21
  22        if (!len || line[len-1] != '\n')
  23                return -1;
  24        line[len-1] = 0;
  25        if (get_sha1_hex(line, sha1))
  26                return -1;
  27        commit = lookup_commit(sha1);
  28        if (!commit || parse_commit(commit))
  29                return -1;
  30        if (isspace(line[40]) && !get_sha1_hex(line+41, sha1)) {
  31                /* Graft the fake parents locally to the commit */
  32                int pos = 41;
  33                struct commit_list **pptr, *parents;
  34
  35                /* Free the real parent list */
  36                for (parents = commit->parents; parents; ) {
  37                        struct commit_list *tmp = parents->next;
  38                        free(parents);
  39                        parents = tmp;
  40                }
  41                commit->parents = NULL;
  42                pptr = &(commit->parents);
  43                while (line[pos] && !get_sha1_hex(line + pos, sha1)) {
  44                        struct commit *parent = lookup_commit(sha1);
  45                        if (parent) {
  46                                pptr = &commit_list_insert(parent, pptr)->next;
  47                        }
  48                        pos += 41;
  49                }
  50        }
  51        return log_tree_commit(&log_tree_opt, commit);
  52}
  53
  54static const char diff_tree_usage[] =
  55"git-diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] "
  56"[<common diff options>] <tree-ish> [<tree-ish>] [<path>...]\n"
  57"  -r            diff recursively\n"
  58"  --root        include the initial commit as diff against /dev/null\n"
  59COMMON_DIFF_OPTIONS_HELP;
  60
  61int main(int argc, const char **argv)
  62{
  63        int nr_sha1;
  64        char line[1000];
  65        unsigned char sha1[2][20];
  66        const char *prefix = setup_git_directory();
  67        static struct log_tree_opt *opt = &log_tree_opt;
  68        int read_stdin = 0;
  69
  70        git_config(git_diff_config);
  71        nr_sha1 = 0;
  72        init_log_tree_opt(opt);
  73
  74        for (;;) {
  75                int opt_cnt;
  76                const char *arg;
  77
  78                argv++;
  79                argc--;
  80                arg = *argv;
  81                if (!arg)
  82                        break;
  83
  84                if (*arg != '-') {
  85                        if (nr_sha1 < 2 && !get_sha1(arg, sha1[nr_sha1])) {
  86                                nr_sha1++;
  87                                continue;
  88                        }
  89                        break;
  90                }
  91
  92                opt_cnt = log_tree_opt_parse(opt, argv, argc);
  93                if (opt_cnt < 0)
  94                        usage(diff_tree_usage);
  95                else if (opt_cnt) {
  96                        argv += opt_cnt - 1;
  97                        argc -= opt_cnt - 1;
  98                        continue;
  99                }
 100
 101                if (!strcmp(arg, "--")) {
 102                        argv++;
 103                        argc--;
 104                        break;
 105                }
 106                if (!strcmp(arg, "--stdin")) {
 107                        read_stdin = 1;
 108                        continue;
 109                }
 110                usage(diff_tree_usage);
 111        }
 112
 113        if (opt->combine_merges)
 114                opt->ignore_merges = 0;
 115
 116        /* We can only do dense combined merges with diff output */
 117        if (opt->dense_combined_merges)
 118                opt->diffopt.output_format = DIFF_FORMAT_PATCH;
 119
 120        if (opt->diffopt.output_format == DIFF_FORMAT_PATCH)
 121                opt->diffopt.recursive = 1;
 122
 123        diff_tree_setup_paths(get_pathspec(prefix, argv), &opt->diffopt);
 124        diff_setup_done(&opt->diffopt);
 125
 126        switch (nr_sha1) {
 127        case 0:
 128                if (!read_stdin)
 129                        usage(diff_tree_usage);
 130                break;
 131        case 1:
 132                diff_tree_commit_sha1(sha1[0]);
 133                break;
 134        case 2:
 135                diff_tree_sha1(sha1[0], sha1[1], "", &opt->diffopt);
 136                log_tree_diff_flush(opt);
 137                break;
 138        }
 139
 140        if (!read_stdin)
 141                return 0;
 142
 143        if (opt->diffopt.detect_rename)
 144                opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
 145                                       DIFF_SETUP_USE_CACHE);
 146        while (fgets(line, sizeof(line), stdin))
 147                diff_tree_stdin(line);
 148
 149        return 0;
 150}