02762b90e03c16a6790f518a5431b3bad4c476e4
   1#include "cache.h"
   2
   3static int cached_only = 0;
   4static int line_termination = '\n';
   5
   6/* A file entry went away or appeared */
   7static void show_file(const char *prefix, struct cache_entry *ce)
   8{
   9        printf("%s%o\t%s\t%s\t%s%c", prefix, ntohl(ce->ce_mode), "blob",
  10               sha1_to_hex(ce->sha1), ce->name, line_termination);
  11}
  12
  13static int show_modified(struct cache_entry *old, struct cache_entry *new)
  14{
  15        unsigned int mode = ntohl(new->ce_mode), oldmode;
  16        unsigned char *sha1 = new->sha1;
  17        unsigned char old_sha1_hex[60];
  18
  19        if (!cached_only) {
  20                static unsigned char no_sha1[20];
  21                int changed;
  22                struct stat st;
  23                if (stat(new->name, &st) < 0) {
  24                        show_file("-", old);
  25                        return -1;
  26                }
  27                changed = cache_match_stat(new, &st);
  28                if (changed) {
  29                        mode = st.st_mode;
  30                        sha1 = no_sha1;
  31                }
  32        }
  33
  34        oldmode = ntohl(old->ce_mode);
  35        if (mode == oldmode && !memcmp(sha1, old->sha1, 20))
  36                return 0;
  37
  38        strcpy(old_sha1_hex, sha1_to_hex(old->sha1));
  39        printf("*%o->%o\t%s\t%s->%s\t%s%c", oldmode, mode,
  40               "blob",
  41               old_sha1_hex, sha1_to_hex(sha1),
  42               old->name, line_termination);
  43        return 0;
  44}
  45
  46static int diff_cache(struct cache_entry **ac, int entries)
  47{
  48        while (entries) {
  49                struct cache_entry *ce = *ac;
  50                int same = (entries > 1) && same_name(ce, ac[1]);
  51
  52                switch (ce_stage(ce)) {
  53                case 0:
  54                        /* No stage 1 entry? That means it's a new file */
  55                        if (!same) {
  56                                show_file("+", ce);
  57                                break;
  58                        }
  59                        /* Show difference between old and new */
  60                        show_modified(ac[1], ce);
  61                        break;
  62                case 1:
  63                        /* No stage 3 (merge) entry? That means it's been deleted */
  64                        if (!same) {
  65                                show_file("-", ce);
  66                                break;
  67                        }
  68                        /* Otherwise we fall through to the "unmerged" case */
  69                case 3:
  70                        printf("U %s%c", ce->name, line_termination);
  71                        break;
  72
  73                default:
  74                        die("impossible cache entry stage");
  75                }
  76
  77                /*
  78                 * Ignore all the different stages for this file,
  79                 * we've handled the relevant cases now.
  80                 */
  81                do {
  82                        ac++;
  83                        entries--;
  84                } while (entries && same_name(ce, ac[0]));
  85        }
  86        return 0;
  87}
  88
  89/*
  90 * This turns all merge entries into "stage 3". That guarantees that
  91 * when we read in the new tree (into "stage 1"), we won't lose sight
  92 * of the fact that we had unmerged entries.
  93 */
  94static void mark_merge_entries(void)
  95{
  96        int i;
  97        for (i = 0; i < active_nr; i++) {
  98                struct cache_entry *ce = active_cache[i];
  99                if (!ce_stage(ce))
 100                        continue;
 101                ce->ce_flags |= htons(CE_STAGEMASK);
 102        }
 103}
 104
 105static char *diff_cache_usage = "diff-cache [-r] [-z] [--cached] <tree sha1>";
 106
 107int main(int argc, char **argv)
 108{
 109        unsigned char tree_sha1[20];
 110        void *tree;
 111        unsigned long size;
 112
 113        read_cache();
 114        while (argc > 2) {
 115                char *arg = argv[1];
 116                argv++;
 117                argc--;
 118                if (!strcmp(arg, "-r")) {
 119                        /* We accept the -r flag just to look like diff-tree */
 120                        continue;
 121                }
 122                if (!strcmp(arg, "-z")) {
 123                        line_termination = '\0';
 124                        continue;
 125                }
 126                if (!strcmp(arg, "--cached")) {
 127                        cached_only = 1;
 128                        continue;
 129                }
 130                usage(diff_cache_usage);
 131        }
 132
 133        if (argc != 2 || get_sha1_hex(argv[1], tree_sha1))
 134                usage(diff_cache_usage);
 135
 136        mark_merge_entries();
 137
 138        tree = read_tree_with_tree_or_commit_sha1(tree_sha1, &size, 0);
 139        if (!tree)
 140                die("bad tree object %s", argv[1]);
 141        if (read_tree(tree, size, 1))
 142                die("unable to read tree object %s", argv[1]);
 143
 144        return diff_cache(active_cache, active_nr);
 145}