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