diff-lib.con commit git-p4: Unset P4DIFF environment variable when using 'p4 -du diff' (67abd41)
   1/*
   2 * Copyright (C) 2005 Junio C Hamano
   3 */
   4#include "cache.h"
   5#include "quote.h"
   6#include "commit.h"
   7#include "diff.h"
   8#include "diffcore.h"
   9#include "revision.h"
  10#include "cache-tree.h"
  11#include "path-list.h"
  12#include "unpack-trees.h"
  13
  14/*
  15 * diff-files
  16 */
  17
  18static int read_directory(const char *path, struct path_list *list)
  19{
  20        DIR *dir;
  21        struct dirent *e;
  22
  23        if (!(dir = opendir(path)))
  24                return error("Could not open directory %s", path);
  25
  26        while ((e = readdir(dir)))
  27                if (strcmp(".", e->d_name) && strcmp("..", e->d_name))
  28                        path_list_insert(e->d_name, list);
  29
  30        closedir(dir);
  31        return 0;
  32}
  33
  34static int get_mode(const char *path, int *mode)
  35{
  36        struct stat st;
  37
  38        if (!path || !strcmp(path, "/dev/null"))
  39                *mode = 0;
  40        else if (!strcmp(path, "-"))
  41                *mode = create_ce_mode(0666);
  42        else if (stat(path, &st))
  43                return error("Could not access '%s'", path);
  44        else
  45                *mode = st.st_mode;
  46        return 0;
  47}
  48
  49static int queue_diff(struct diff_options *o,
  50                const char *name1, const char *name2)
  51{
  52        int mode1 = 0, mode2 = 0;
  53
  54        if (get_mode(name1, &mode1) || get_mode(name2, &mode2))
  55                return -1;
  56
  57        if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2))
  58                return error("file/directory conflict: %s, %s", name1, name2);
  59
  60        if (S_ISDIR(mode1) || S_ISDIR(mode2)) {
  61                char buffer1[PATH_MAX], buffer2[PATH_MAX];
  62                struct path_list p1 = {NULL, 0, 0, 1}, p2 = {NULL, 0, 0, 1};
  63                int len1 = 0, len2 = 0, i1, i2, ret = 0;
  64
  65                if (name1 && read_directory(name1, &p1))
  66                        return -1;
  67                if (name2 && read_directory(name2, &p2)) {
  68                        path_list_clear(&p1, 0);
  69                        return -1;
  70                }
  71
  72                if (name1) {
  73                        len1 = strlen(name1);
  74                        if (len1 > 0 && name1[len1 - 1] == '/')
  75                                len1--;
  76                        memcpy(buffer1, name1, len1);
  77                        buffer1[len1++] = '/';
  78                }
  79
  80                if (name2) {
  81                        len2 = strlen(name2);
  82                        if (len2 > 0 && name2[len2 - 1] == '/')
  83                                len2--;
  84                        memcpy(buffer2, name2, len2);
  85                        buffer2[len2++] = '/';
  86                }
  87
  88                for (i1 = i2 = 0; !ret && (i1 < p1.nr || i2 < p2.nr); ) {
  89                        const char *n1, *n2;
  90                        int comp;
  91
  92                        if (i1 == p1.nr)
  93                                comp = 1;
  94                        else if (i2 == p2.nr)
  95                                comp = -1;
  96                        else
  97                                comp = strcmp(p1.items[i1].path,
  98                                        p2.items[i2].path);
  99
 100                        if (comp > 0)
 101                                n1 = NULL;
 102                        else {
 103                                n1 = buffer1;
 104                                strncpy(buffer1 + len1, p1.items[i1++].path,
 105                                                PATH_MAX - len1);
 106                        }
 107
 108                        if (comp < 0)
 109                                n2 = NULL;
 110                        else {
 111                                n2 = buffer2;
 112                                strncpy(buffer2 + len2, p2.items[i2++].path,
 113                                                PATH_MAX - len2);
 114                        }
 115
 116                        ret = queue_diff(o, n1, n2);
 117                }
 118                path_list_clear(&p1, 0);
 119                path_list_clear(&p2, 0);
 120
 121                return ret;
 122        } else {
 123                struct diff_filespec *d1, *d2;
 124
 125                if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
 126                        unsigned tmp;
 127                        const char *tmp_c;
 128                        tmp = mode1; mode1 = mode2; mode2 = tmp;
 129                        tmp_c = name1; name1 = name2; name2 = tmp_c;
 130                }
 131
 132                if (!name1)
 133                        name1 = "/dev/null";
 134                if (!name2)
 135                        name2 = "/dev/null";
 136                d1 = alloc_filespec(name1);
 137                d2 = alloc_filespec(name2);
 138                fill_filespec(d1, null_sha1, mode1);
 139                fill_filespec(d2, null_sha1, mode2);
 140
 141                diff_queue(&diff_queued_diff, d1, d2);
 142                return 0;
 143        }
 144}
 145
 146/*
 147 * Does the path name a blob in the working tree, or a directory
 148 * in the working tree?
 149 */
 150static int is_in_index(const char *path)
 151{
 152        int len, pos;
 153        struct cache_entry *ce;
 154
 155        len = strlen(path);
 156        while (path[len-1] == '/')
 157                len--;
 158        if (!len)
 159                return 1; /* "." */
 160        pos = cache_name_pos(path, len);
 161        if (0 <= pos)
 162                return 1;
 163        pos = -1 - pos;
 164        while (pos < active_nr) {
 165                ce = active_cache[pos++];
 166                if (ce_namelen(ce) <= len ||
 167                    strncmp(ce->name, path, len) ||
 168                    (ce->name[len] > '/'))
 169                        break; /* path cannot be a prefix */
 170                if (ce->name[len] == '/')
 171                        return 1;
 172        }
 173        return 0;
 174}
 175
 176static int handle_diff_files_args(struct rev_info *revs,
 177                                  int argc, const char **argv,
 178                                  unsigned int *options)
 179{
 180        *options = 0;
 181
 182        /* revs->max_count == -2 means --no-index */
 183        while (1 < argc && argv[1][0] == '-') {
 184                if (!strcmp(argv[1], "--base"))
 185                        revs->max_count = 1;
 186                else if (!strcmp(argv[1], "--ours"))
 187                        revs->max_count = 2;
 188                else if (!strcmp(argv[1], "--theirs"))
 189                        revs->max_count = 3;
 190                else if (!strcmp(argv[1], "-n") ||
 191                                !strcmp(argv[1], "--no-index")) {
 192                        revs->max_count = -2;
 193                        DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
 194                        DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
 195                }
 196                else if (!strcmp(argv[1], "-q"))
 197                        *options |= DIFF_SILENT_ON_REMOVED;
 198                else
 199                        return error("invalid option: %s", argv[1]);
 200                argv++; argc--;
 201        }
 202
 203        if (revs->max_count == -1 && revs->diffopt.nr_paths == 2) {
 204                /*
 205                 * If two files are specified, and at least one is untracked,
 206                 * default to no-index.
 207                 */
 208                read_cache();
 209                if (!is_in_index(revs->diffopt.paths[0]) ||
 210                                        !is_in_index(revs->diffopt.paths[1])) {
 211                        revs->max_count = -2;
 212                        DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
 213                }
 214        }
 215
 216        /*
 217         * Make sure there are NO revision (i.e. pending object) parameter,
 218         * rev.max_count is reasonable (0 <= n <= 3),
 219         * there is no other revision filtering parameters.
 220         */
 221        if (revs->pending.nr || revs->max_count > 3 ||
 222            revs->min_age != -1 || revs->max_age != -1)
 223                return error("no revision allowed with diff-files");
 224
 225        if (revs->max_count == -1 &&
 226            (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
 227                revs->combine_merges = revs->dense_combined_merges = 1;
 228
 229        return 0;
 230}
 231
 232static int is_outside_repo(const char *path, int nongit, const char *prefix)
 233{
 234        int i;
 235        if (nongit || !strcmp(path, "-") || is_absolute_path(path))
 236                return 1;
 237        if (prefixcmp(path, "../"))
 238                return 0;
 239        if (!prefix)
 240                return 1;
 241        for (i = strlen(prefix); !prefixcmp(path, "../"); ) {
 242                while (i > 0 && prefix[i - 1] != '/')
 243                        i--;
 244                if (--i < 0)
 245                        return 1;
 246                path += 3;
 247        }
 248        return 0;
 249}
 250
 251int setup_diff_no_index(struct rev_info *revs,
 252                int argc, const char ** argv, int nongit, const char *prefix)
 253{
 254        int i;
 255        for (i = 1; i < argc; i++)
 256                if (argv[i][0] != '-' || argv[i][1] == '\0')
 257                        break;
 258                else if (!strcmp(argv[i], "--")) {
 259                        i++;
 260                        break;
 261                } else if (i < argc - 3 && !strcmp(argv[i], "--no-index")) {
 262                        i = argc - 3;
 263                        DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
 264                        break;
 265                }
 266        if (argc != i + 2 || (!is_outside_repo(argv[i + 1], nongit, prefix) &&
 267                                !is_outside_repo(argv[i], nongit, prefix)))
 268                return -1;
 269
 270        diff_setup(&revs->diffopt);
 271        for (i = 1; i < argc - 2; )
 272                if (!strcmp(argv[i], "--no-index"))
 273                        i++;
 274                else {
 275                        int j = diff_opt_parse(&revs->diffopt,
 276                                        argv + i, argc - i);
 277                        if (!j)
 278                                die("invalid diff option/value: %s", argv[i]);
 279                        i += j;
 280                }
 281
 282        if (prefix) {
 283                int len = strlen(prefix);
 284
 285                revs->diffopt.paths = xcalloc(2, sizeof(char*));
 286                for (i = 0; i < 2; i++) {
 287                        const char *p = argv[argc - 2 + i];
 288                        /*
 289                         * stdin should be spelled as '-'; if you have
 290                         * path that is '-', spell it as ./-.
 291                         */
 292                        p = (strcmp(p, "-")
 293                             ? xstrdup(prefix_filename(prefix, len, p))
 294                             : p);
 295                        revs->diffopt.paths[i] = p;
 296                }
 297        }
 298        else
 299                revs->diffopt.paths = argv + argc - 2;
 300        revs->diffopt.nr_paths = 2;
 301        DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
 302        revs->max_count = -2;
 303        if (diff_setup_done(&revs->diffopt) < 0)
 304                die("diff_setup_done failed");
 305        return 0;
 306}
 307
 308int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
 309{
 310        unsigned int options;
 311
 312        if (handle_diff_files_args(revs, argc, argv, &options))
 313                return -1;
 314
 315        if (DIFF_OPT_TST(&revs->diffopt, NO_INDEX)) {
 316                if (revs->diffopt.nr_paths != 2)
 317                        return error("need two files/directories with --no-index");
 318                if (queue_diff(&revs->diffopt, revs->diffopt.paths[0],
 319                                revs->diffopt.paths[1]))
 320                        return -1;
 321                diffcore_std(&revs->diffopt);
 322                diff_flush(&revs->diffopt);
 323                /*
 324                 * The return code for --no-index imitates diff(1):
 325                 * 0 = no changes, 1 = changes, else error
 326                 */
 327                return revs->diffopt.found_changes;
 328        }
 329
 330        if (read_cache() < 0) {
 331                perror("read_cache");
 332                return -1;
 333        }
 334        return run_diff_files(revs, options);
 335}
 336
 337int run_diff_files(struct rev_info *revs, unsigned int option)
 338{
 339        int entries, i;
 340        int diff_unmerged_stage = revs->max_count;
 341        int silent_on_removed = option & DIFF_SILENT_ON_REMOVED;
 342        unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
 343                              ? CE_MATCH_RACY_IS_DIRTY : 0);
 344
 345        if (diff_unmerged_stage < 0)
 346                diff_unmerged_stage = 2;
 347        entries = active_nr;
 348        for (i = 0; i < entries; i++) {
 349                struct stat st;
 350                unsigned int oldmode, newmode;
 351                struct cache_entry *ce = active_cache[i];
 352                int changed;
 353
 354                if (DIFF_OPT_TST(&revs->diffopt, QUIET) &&
 355                        DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))
 356                        break;
 357
 358                if (!ce_path_match(ce, revs->prune_data))
 359                        continue;
 360
 361                if (ce_stage(ce)) {
 362                        struct combine_diff_path *dpath;
 363                        int num_compare_stages = 0;
 364                        size_t path_len;
 365
 366                        path_len = ce_namelen(ce);
 367
 368                        dpath = xmalloc(combine_diff_path_size(5, path_len));
 369                        dpath->path = (char *) &(dpath->parent[5]);
 370
 371                        dpath->next = NULL;
 372                        dpath->len = path_len;
 373                        memcpy(dpath->path, ce->name, path_len);
 374                        dpath->path[path_len] = '\0';
 375                        hashclr(dpath->sha1);
 376                        memset(&(dpath->parent[0]), 0,
 377                               sizeof(struct combine_diff_parent)*5);
 378
 379                        if (lstat(ce->name, &st) < 0) {
 380                                if (errno != ENOENT && errno != ENOTDIR) {
 381                                        perror(ce->name);
 382                                        continue;
 383                                }
 384                                if (silent_on_removed)
 385                                        continue;
 386                        }
 387                        else
 388                                dpath->mode = ce_mode_from_stat(ce, st.st_mode);
 389
 390                        while (i < entries) {
 391                                struct cache_entry *nce = active_cache[i];
 392                                int stage;
 393
 394                                if (strcmp(ce->name, nce->name))
 395                                        break;
 396
 397                                /* Stage #2 (ours) is the first parent,
 398                                 * stage #3 (theirs) is the second.
 399                                 */
 400                                stage = ce_stage(nce);
 401                                if (2 <= stage) {
 402                                        int mode = nce->ce_mode;
 403                                        num_compare_stages++;
 404                                        hashcpy(dpath->parent[stage-2].sha1, nce->sha1);
 405                                        dpath->parent[stage-2].mode = ce_mode_from_stat(nce, mode);
 406                                        dpath->parent[stage-2].status =
 407                                                DIFF_STATUS_MODIFIED;
 408                                }
 409
 410                                /* diff against the proper unmerged stage */
 411                                if (stage == diff_unmerged_stage)
 412                                        ce = nce;
 413                                i++;
 414                        }
 415                        /*
 416                         * Compensate for loop update
 417                         */
 418                        i--;
 419
 420                        if (revs->combine_merges && num_compare_stages == 2) {
 421                                show_combined_diff(dpath, 2,
 422                                                   revs->dense_combined_merges,
 423                                                   revs);
 424                                free(dpath);
 425                                continue;
 426                        }
 427                        free(dpath);
 428                        dpath = NULL;
 429
 430                        /*
 431                         * Show the diff for the 'ce' if we found the one
 432                         * from the desired stage.
 433                         */
 434                        diff_unmerge(&revs->diffopt, ce->name, 0, null_sha1);
 435                        if (ce_stage(ce) != diff_unmerged_stage)
 436                                continue;
 437                }
 438
 439                if (ce_uptodate(ce))
 440                        continue;
 441                if (lstat(ce->name, &st) < 0) {
 442                        if (errno != ENOENT && errno != ENOTDIR) {
 443                                perror(ce->name);
 444                                continue;
 445                        }
 446                        if (silent_on_removed)
 447                                continue;
 448                        diff_addremove(&revs->diffopt, '-', ce->ce_mode,
 449                                       ce->sha1, ce->name, NULL);
 450                        continue;
 451                }
 452                changed = ce_match_stat(ce, &st, ce_option);
 453                if (!changed && !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
 454                        continue;
 455                oldmode = ce->ce_mode;
 456                newmode = ce_mode_from_stat(ce, st.st_mode);
 457                diff_change(&revs->diffopt, oldmode, newmode,
 458                            ce->sha1, (changed ? null_sha1 : ce->sha1),
 459                            ce->name, NULL);
 460
 461        }
 462        diffcore_std(&revs->diffopt);
 463        diff_flush(&revs->diffopt);
 464        return 0;
 465}
 466
 467/*
 468 * diff-index
 469 */
 470
 471/* A file entry went away or appeared */
 472static void diff_index_show_file(struct rev_info *revs,
 473                                 const char *prefix,
 474                                 struct cache_entry *ce,
 475                                 const unsigned char *sha1, unsigned int mode)
 476{
 477        diff_addremove(&revs->diffopt, prefix[0], mode,
 478                       sha1, ce->name, NULL);
 479}
 480
 481static int get_stat_data(struct cache_entry *ce,
 482                         const unsigned char **sha1p,
 483                         unsigned int *modep,
 484                         int cached, int match_missing)
 485{
 486        const unsigned char *sha1 = ce->sha1;
 487        unsigned int mode = ce->ce_mode;
 488
 489        if (!cached) {
 490                int changed;
 491                struct stat st;
 492                if (lstat(ce->name, &st) < 0) {
 493                        if (errno == ENOENT && match_missing) {
 494                                *sha1p = sha1;
 495                                *modep = mode;
 496                                return 0;
 497                        }
 498                        return -1;
 499                }
 500                changed = ce_match_stat(ce, &st, 0);
 501                if (changed) {
 502                        mode = ce_mode_from_stat(ce, st.st_mode);
 503                        sha1 = null_sha1;
 504                }
 505        }
 506
 507        *sha1p = sha1;
 508        *modep = mode;
 509        return 0;
 510}
 511
 512static void show_new_file(struct rev_info *revs,
 513                          struct cache_entry *new,
 514                          int cached, int match_missing)
 515{
 516        const unsigned char *sha1;
 517        unsigned int mode;
 518
 519        /* New file in the index: it might actually be different in
 520         * the working copy.
 521         */
 522        if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0)
 523                return;
 524
 525        diff_index_show_file(revs, "+", new, sha1, mode);
 526}
 527
 528static int show_modified(struct rev_info *revs,
 529                         struct cache_entry *old,
 530                         struct cache_entry *new,
 531                         int report_missing,
 532                         int cached, int match_missing)
 533{
 534        unsigned int mode, oldmode;
 535        const unsigned char *sha1;
 536
 537        if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0) {
 538                if (report_missing)
 539                        diff_index_show_file(revs, "-", old,
 540                                             old->sha1, old->ce_mode);
 541                return -1;
 542        }
 543
 544        if (revs->combine_merges && !cached &&
 545            (hashcmp(sha1, old->sha1) || hashcmp(old->sha1, new->sha1))) {
 546                struct combine_diff_path *p;
 547                int pathlen = ce_namelen(new);
 548
 549                p = xmalloc(combine_diff_path_size(2, pathlen));
 550                p->path = (char *) &p->parent[2];
 551                p->next = NULL;
 552                p->len = pathlen;
 553                memcpy(p->path, new->name, pathlen);
 554                p->path[pathlen] = 0;
 555                p->mode = mode;
 556                hashclr(p->sha1);
 557                memset(p->parent, 0, 2 * sizeof(struct combine_diff_parent));
 558                p->parent[0].status = DIFF_STATUS_MODIFIED;
 559                p->parent[0].mode = new->ce_mode;
 560                hashcpy(p->parent[0].sha1, new->sha1);
 561                p->parent[1].status = DIFF_STATUS_MODIFIED;
 562                p->parent[1].mode = old->ce_mode;
 563                hashcpy(p->parent[1].sha1, old->sha1);
 564                show_combined_diff(p, 2, revs->dense_combined_merges, revs);
 565                free(p);
 566                return 0;
 567        }
 568
 569        oldmode = old->ce_mode;
 570        if (mode == oldmode && !hashcmp(sha1, old->sha1) &&
 571            !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
 572                return 0;
 573
 574        diff_change(&revs->diffopt, oldmode, mode,
 575                    old->sha1, sha1, old->name, NULL);
 576        return 0;
 577}
 578
 579/*
 580 * This turns all merge entries into "stage 3". That guarantees that
 581 * when we read in the new tree (into "stage 1"), we won't lose sight
 582 * of the fact that we had unmerged entries.
 583 */
 584static void mark_merge_entries(void)
 585{
 586        int i;
 587        for (i = 0; i < active_nr; i++) {
 588                struct cache_entry *ce = active_cache[i];
 589                if (!ce_stage(ce))
 590                        continue;
 591                ce->ce_flags |= CE_STAGEMASK;
 592        }
 593}
 594
 595/*
 596 * This gets a mix of an existing index and a tree, one pathname entry
 597 * at a time. The index entry may be a single stage-0 one, but it could
 598 * also be multiple unmerged entries (in which case idx_pos/idx_nr will
 599 * give you the position and number of entries in the index).
 600 */
 601static void do_oneway_diff(struct unpack_trees_options *o,
 602        struct cache_entry *idx,
 603        struct cache_entry *tree)
 604{
 605        struct rev_info *revs = o->unpack_data;
 606        int match_missing, cached;
 607
 608        /*
 609         * Backward compatibility wart - "diff-index -m" does
 610         * not mean "do not ignore merges", but "match_missing".
 611         *
 612         * But with the revision flag parsing, that's found in
 613         * "!revs->ignore_merges".
 614         */
 615        cached = o->index_only;
 616        match_missing = !revs->ignore_merges;
 617
 618        if (cached && idx && ce_stage(idx)) {
 619                if (tree)
 620                        diff_unmerge(&revs->diffopt, idx->name, idx->ce_mode, idx->sha1);
 621                return;
 622        }
 623
 624        /*
 625         * Something added to the tree?
 626         */
 627        if (!tree) {
 628                show_new_file(revs, idx, cached, match_missing);
 629                return;
 630        }
 631
 632        /*
 633         * Something removed from the tree?
 634         */
 635        if (!idx) {
 636                diff_index_show_file(revs, "-", tree, tree->sha1, tree->ce_mode);
 637                return;
 638        }
 639
 640        /* Show difference between old and new */
 641        show_modified(revs, tree, idx, 1, cached, match_missing);
 642}
 643
 644static inline void skip_same_name(struct cache_entry *ce, struct unpack_trees_options *o)
 645{
 646        int len = ce_namelen(ce);
 647        const struct index_state *index = o->src_index;
 648
 649        while (o->pos < index->cache_nr) {
 650                struct cache_entry *next = index->cache[o->pos];
 651                if (len != ce_namelen(next))
 652                        break;
 653                if (memcmp(ce->name, next->name, len))
 654                        break;
 655                o->pos++;
 656        }
 657}
 658
 659/*
 660 * The unpack_trees() interface is designed for merging, so
 661 * the different source entries are designed primarily for
 662 * the source trees, with the old index being really mainly
 663 * used for being replaced by the result.
 664 *
 665 * For diffing, the index is more important, and we only have a
 666 * single tree.
 667 *
 668 * We're supposed to return how many index entries we want to skip.
 669 *
 670 * This wrapper makes it all more readable, and takes care of all
 671 * the fairly complex unpack_trees() semantic requirements, including
 672 * the skipping, the path matching, the type conflict cases etc.
 673 */
 674static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o)
 675{
 676        struct cache_entry *idx = src[0];
 677        struct cache_entry *tree = src[1];
 678        struct rev_info *revs = o->unpack_data;
 679
 680        if (idx && ce_stage(idx))
 681                skip_same_name(idx, o);
 682
 683        /*
 684         * Unpack-trees generates a DF/conflict entry if
 685         * there was a directory in the index and a tree
 686         * in the tree. From a diff standpoint, that's a
 687         * delete of the tree and a create of the file.
 688         */
 689        if (tree == o->df_conflict_entry)
 690                tree = NULL;
 691
 692        if (ce_path_match(idx ? idx : tree, revs->prune_data))
 693                do_oneway_diff(o, idx, tree);
 694
 695        return 0;
 696}
 697
 698int run_diff_index(struct rev_info *revs, int cached)
 699{
 700        struct object *ent;
 701        struct tree *tree;
 702        const char *tree_name;
 703        struct unpack_trees_options opts;
 704        struct tree_desc t;
 705
 706        mark_merge_entries();
 707
 708        ent = revs->pending.objects[0].item;
 709        tree_name = revs->pending.objects[0].name;
 710        tree = parse_tree_indirect(ent->sha1);
 711        if (!tree)
 712                return error("bad tree object %s", tree_name);
 713
 714        memset(&opts, 0, sizeof(opts));
 715        opts.head_idx = 1;
 716        opts.index_only = cached;
 717        opts.merge = 1;
 718        opts.fn = oneway_diff;
 719        opts.unpack_data = revs;
 720        opts.src_index = &the_index;
 721        opts.dst_index = NULL;
 722
 723        init_tree_desc(&t, tree->buffer, tree->size);
 724        if (unpack_trees(1, &t, &opts))
 725                exit(128);
 726
 727        diffcore_std(&revs->diffopt);
 728        diff_flush(&revs->diffopt);
 729        return 0;
 730}
 731
 732int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
 733{
 734        struct tree *tree;
 735        struct rev_info revs;
 736        int i;
 737        struct cache_entry **dst;
 738        struct cache_entry *last = NULL;
 739        struct unpack_trees_options opts;
 740        struct tree_desc t;
 741
 742        /*
 743         * This is used by git-blame to run diff-cache internally;
 744         * it potentially needs to repeatedly run this, so we will
 745         * start by removing the higher order entries the last round
 746         * left behind.
 747         */
 748        dst = active_cache;
 749        for (i = 0; i < active_nr; i++) {
 750                struct cache_entry *ce = active_cache[i];
 751                if (ce_stage(ce)) {
 752                        if (last && !strcmp(ce->name, last->name))
 753                                continue;
 754                        cache_tree_invalidate_path(active_cache_tree,
 755                                                   ce->name);
 756                        last = ce;
 757                        ce->ce_flags |= CE_REMOVE;
 758                }
 759                *dst++ = ce;
 760        }
 761        active_nr = dst - active_cache;
 762
 763        init_revisions(&revs, NULL);
 764        revs.prune_data = opt->paths;
 765        tree = parse_tree_indirect(tree_sha1);
 766        if (!tree)
 767                die("bad tree object %s", sha1_to_hex(tree_sha1));
 768
 769        memset(&opts, 0, sizeof(opts));
 770        opts.head_idx = 1;
 771        opts.index_only = 1;
 772        opts.merge = 1;
 773        opts.fn = oneway_diff;
 774        opts.unpack_data = &revs;
 775        opts.src_index = &the_index;
 776        opts.dst_index = &the_index;
 777
 778        init_tree_desc(&t, tree->buffer, tree->size);
 779        if (unpack_trees(1, &t, &opts))
 780                exit(128);
 781        return 0;
 782}