diff-tree.con commit diff --abbrev=<n> option fix. (6b1ddbd)
   1#include "cache.h"
   2#include "diff.h"
   3#include "commit.h"
   4
   5static int show_root_diff = 0;
   6static int no_commit_id = 0;
   7static int verbose_header = 0;
   8static int ignore_merges = 1;
   9static int read_stdin = 0;
  10
  11static const char *header = NULL;
  12static const char *header_prefix = "";
  13static enum cmit_fmt commit_format = CMIT_FMT_RAW;
  14
  15static struct diff_options diff_options;
  16
  17static int call_diff_flush(void)
  18{
  19        diffcore_std(&diff_options);
  20        if (diff_queue_is_empty()) {
  21                int saved_fmt = diff_options.output_format;
  22                diff_options.output_format = DIFF_FORMAT_NO_OUTPUT;
  23                diff_flush(&diff_options);
  24                diff_options.output_format = saved_fmt;
  25                return 0;
  26        }
  27        if (header) {
  28                if (!no_commit_id)
  29                        printf("%s%c", header, diff_options.line_termination);
  30                header = NULL;
  31        }
  32        diff_flush(&diff_options);
  33        return 1;
  34}
  35
  36static int diff_tree_sha1_top(const unsigned char *old,
  37                              const unsigned char *new, const char *base)
  38{
  39        int ret;
  40
  41        ret = diff_tree_sha1(old, new, base, &diff_options);
  42        call_diff_flush();
  43        return ret;
  44}
  45
  46static int diff_root_tree(const unsigned char *new, const char *base)
  47{
  48        int retval;
  49        void *tree;
  50        struct tree_desc empty, real;
  51
  52        tree = read_object_with_reference(new, "tree", &real.size, NULL);
  53        if (!tree)
  54                die("unable to read root tree (%s)", sha1_to_hex(new));
  55        real.buf = tree;
  56
  57        empty.buf = "";
  58        empty.size = 0;
  59        retval = diff_tree(&empty, &real, base, &diff_options);
  60        free(tree);
  61        call_diff_flush();
  62        return retval;
  63}
  64
  65static const char *generate_header(const unsigned char *commit_sha1,
  66                                   const unsigned char *parent_sha1,
  67                                   const struct commit *commit)
  68{
  69        static char this_header[16384];
  70        int offset;
  71        unsigned long len;
  72        int abbrev = diff_options.abbrev;
  73        const char *msg = commit->buffer;
  74
  75        if (!verbose_header)
  76                return sha1_to_hex(commit_sha1);
  77
  78        len = strlen(msg);
  79
  80        offset = sprintf(this_header, "%s%s ",
  81                         header_prefix,
  82                         diff_unique_abbrev(commit_sha1, abbrev));
  83        offset += sprintf(this_header + offset, "(from %s)\n",
  84                         parent_sha1 ?
  85                         diff_unique_abbrev(parent_sha1, abbrev) : "root");
  86        offset += pretty_print_commit(commit_format, commit, len,
  87                                      this_header + offset,
  88                                      sizeof(this_header) - offset, abbrev);
  89        return this_header;
  90}
  91
  92static int diff_tree_commit(const unsigned char *commit_sha1)
  93{
  94        struct commit *commit;
  95        struct commit_list *parents;
  96        char name[50];
  97        unsigned char sha1[20];
  98
  99        sprintf(name, "%s^0", sha1_to_hex(commit_sha1));
 100        if (get_sha1(name, sha1))
 101                return -1;
 102        name[40] = 0;
 103        commit = lookup_commit(sha1);
 104        
 105        /* Root commit? */
 106        if (show_root_diff && !commit->parents) {
 107                header = generate_header(sha1, NULL, commit);
 108                diff_root_tree(commit_sha1, "");
 109        }
 110
 111        /* More than one parent? */
 112        if (ignore_merges && commit->parents && commit->parents->next)
 113                return 0;
 114
 115        for (parents = commit->parents; parents; parents = parents->next) {
 116                struct commit *parent = parents->item;
 117                header = generate_header(sha1, parent->object.sha1, commit);
 118                diff_tree_sha1_top(parent->object.sha1, commit_sha1, "");
 119                if (!header && verbose_header) {
 120                        header_prefix = "\ndiff-tree ";
 121                        /*
 122                         * Don't print multiple merge entries if we
 123                         * don't print the diffs.
 124                         */
 125                }
 126        }
 127        return 0;
 128}
 129
 130static int diff_tree_stdin(char *line)
 131{
 132        int len = strlen(line);
 133        unsigned char commit[20], parent[20];
 134        static char this_header[1000];
 135        int abbrev = diff_options.abbrev;
 136
 137        if (!len || line[len-1] != '\n')
 138                return -1;
 139        line[len-1] = 0;
 140        if (get_sha1_hex(line, commit))
 141                return -1;
 142        if (isspace(line[40]) && !get_sha1_hex(line+41, parent)) {
 143                line[40] = 0;
 144                line[81] = 0;
 145                sprintf(this_header, "%s (from %s)\n",
 146                        diff_unique_abbrev(commit, abbrev),
 147                        diff_unique_abbrev(parent, abbrev));
 148                header = this_header;
 149                return diff_tree_sha1_top(parent, commit, "");
 150        }
 151        line[40] = 0;
 152        return diff_tree_commit(commit);
 153}
 154
 155static const char diff_tree_usage[] =
 156"git-diff-tree [--stdin] [-m] [-s] [-v] [--pretty] [-t] [-r] [--root] "
 157"[<common diff options>] <tree-ish> [<tree-ish>] [<path>...]\n"
 158"  -r            diff recursively\n"
 159"  --root        include the initial commit as diff against /dev/null\n"
 160COMMON_DIFF_OPTIONS_HELP;
 161
 162int main(int argc, const char **argv)
 163{
 164        int nr_sha1;
 165        char line[1000];
 166        unsigned char sha1[2][20];
 167        const char *prefix = setup_git_directory();
 168
 169        git_config(git_diff_config);
 170        nr_sha1 = 0;
 171        diff_setup(&diff_options);
 172
 173        for (;;) {
 174                int diff_opt_cnt;
 175                const char *arg;
 176
 177                argv++;
 178                argc--;
 179                arg = *argv;
 180                if (!arg)
 181                        break;
 182
 183                if (*arg != '-') {
 184                        if (nr_sha1 < 2 && !get_sha1(arg, sha1[nr_sha1])) {
 185                                nr_sha1++;
 186                                continue;
 187                        }
 188                        break;
 189                }
 190
 191                diff_opt_cnt = diff_opt_parse(&diff_options, argv, argc);
 192                if (diff_opt_cnt < 0)
 193                        usage(diff_tree_usage);
 194                else if (diff_opt_cnt) {
 195                        argv += diff_opt_cnt - 1;
 196                        argc -= diff_opt_cnt - 1;
 197                        continue;
 198                }
 199
 200
 201                if (!strcmp(arg, "--")) {
 202                        argv++;
 203                        argc--;
 204                        break;
 205                }
 206                if (!strcmp(arg, "-r")) {
 207                        diff_options.recursive = 1;
 208                        continue;
 209                }
 210                if (!strcmp(arg, "-t")) {
 211                        diff_options.recursive = 1;
 212                        diff_options.tree_in_recursive = 1;
 213                        continue;
 214                }
 215                if (!strcmp(arg, "-m")) {
 216                        ignore_merges = 0;
 217                        continue;
 218                }
 219                if (!strcmp(arg, "-v")) {
 220                        verbose_header = 1;
 221                        header_prefix = "diff-tree ";
 222                        continue;
 223                }
 224                if (!strncmp(arg, "--pretty", 8)) {
 225                        verbose_header = 1;
 226                        header_prefix = "diff-tree ";
 227                        commit_format = get_commit_format(arg+8);
 228                        continue;
 229                }
 230                if (!strcmp(arg, "--stdin")) {
 231                        read_stdin = 1;
 232                        continue;
 233                }
 234                if (!strcmp(arg, "--root")) {
 235                        show_root_diff = 1;
 236                        continue;
 237                }
 238                if (!strcmp(arg, "--no-commit-id")) {
 239                        no_commit_id = 1;
 240                        continue;
 241                }
 242                usage(diff_tree_usage);
 243        }
 244        if (diff_options.output_format == DIFF_FORMAT_PATCH)
 245                diff_options.recursive = 1;
 246
 247        diff_tree_setup_paths(get_pathspec(prefix, argv));
 248        diff_setup_done(&diff_options);
 249
 250        switch (nr_sha1) {
 251        case 0:
 252                if (!read_stdin)
 253                        usage(diff_tree_usage);
 254                break;
 255        case 1:
 256                diff_tree_commit(sha1[0]);
 257                break;
 258        case 2:
 259                diff_tree_sha1_top(sha1[0], sha1[1], "");
 260                break;
 261        }
 262
 263        if (!read_stdin)
 264                return 0;
 265
 266        if (diff_options.detect_rename)
 267                diff_options.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
 268                                       DIFF_SETUP_USE_CACHE);
 269        while (fgets(line, sizeof(line), stdin))
 270                diff_tree_stdin(line);
 271
 272        return 0;
 273}