git-diff-cache: add "-m" flag to match all non-checked-out files with the index.
[git/git.git] / diff-cache.c
CommitLineData
e74f8f6a 1#include "cache.h"
f92a4465 2#include "diff.h"
e74f8f6a
LT
3
4static int cached_only = 0;
f92a4465 5static int generate_patch = 0;
160c8433 6static int match_nonexisting = 0;
e74f8f6a
LT
7static int line_termination = '\n';
8
e74f8f6a 9/* A file entry went away or appeared */
c9cddabe 10static void show_file(const char *prefix, struct cache_entry *ce, unsigned char *sha1, unsigned int mode)
e74f8f6a 11{
f92a4465 12 if (generate_patch)
c9cddabe 13 diff_addremove(prefix[0], ntohl(mode), sha1, ce->name, NULL);
f92a4465 14 else
c9cddabe
LT
15 printf("%s%06o\tblob\t%s\t%s%c", prefix, ntohl(mode),
16 sha1_to_hex(sha1), ce->name, line_termination);
e74f8f6a
LT
17}
18
c9cddabe 19static int get_stat_data(struct cache_entry *ce, unsigned char **sha1p, unsigned int *modep)
e74f8f6a 20{
c9cddabe
LT
21 unsigned char *sha1 = ce->sha1;
22 unsigned int mode = ce->ce_mode;
e74f8f6a
LT
23
24 if (!cached_only) {
25 static unsigned char no_sha1[20];
b5af9107 26 int changed;
e74f8f6a 27 struct stat st;
160c8433
LT
28 if (lstat(ce->name, &st) < 0) {
29 if (errno == ENOENT && match_nonexisting) {
30 *sha1p = sha1;
31 *modep = mode;
32 return 0;
33 }
e74f8f6a 34 return -1;
160c8433 35 }
c9cddabe 36 changed = cache_match_stat(ce, &st);
e74f8f6a 37 if (changed) {
c9cddabe 38 mode = create_ce_mode(st.st_mode);
b5af9107 39 sha1 = no_sha1;
e74f8f6a
LT
40 }
41 }
42
c9cddabe
LT
43 *sha1p = sha1;
44 *modep = mode;
45 return 0;
46}
47
b836825b 48static void show_new_file(struct cache_entry *new)
c9cddabe
LT
49{
50 unsigned char *sha1;
51 unsigned int mode;
52
53 /* New file in the index: it might actually be different in the working copy */
54 if (get_stat_data(new, &sha1, &mode) < 0)
b836825b 55 return;
c9cddabe
LT
56
57 show_file("+", new, sha1, mode);
58}
59
60static int show_modified(struct cache_entry *old, struct cache_entry *new)
61{
62 unsigned int mode, oldmode;
63 unsigned char *sha1;
64 unsigned char old_sha1_hex[60];
65
66 if (get_stat_data(new, &sha1, &mode) < 0) {
67 show_file("-", old, old->sha1, old->ce_mode);
68 return -1;
69 }
70
71 oldmode = old->ce_mode;
b5af9107 72 if (mode == oldmode && !memcmp(sha1, old->sha1, 20))
e74f8f6a
LT
73 return 0;
74
c9cddabe
LT
75 mode = ntohl(mode);
76 oldmode = ntohl(oldmode);
77
f92a4465
JH
78 if (generate_patch)
79 diff_change(oldmode, mode,
80 old->sha1, sha1, old->name, NULL);
81 else {
82 strcpy(old_sha1_hex, sha1_to_hex(old->sha1));
83 printf("*%06o->%06o\tblob\t%s->%s\t%s%c", oldmode, mode,
84 old_sha1_hex, sha1_to_hex(sha1),
85 old->name, line_termination);
86 }
e74f8f6a
LT
87 return 0;
88}
89
b5af9107 90static int diff_cache(struct cache_entry **ac, int entries)
e74f8f6a 91{
b5af9107
LT
92 while (entries) {
93 struct cache_entry *ce = *ac;
b0fe89ca 94 int same = (entries > 1) && same_name(ce, ac[1]);
e74f8f6a 95
b0fe89ca
LT
96 switch (ce_stage(ce)) {
97 case 0:
98 /* No stage 1 entry? That means it's a new file */
99 if (!same) {
c9cddabe 100 show_new_file(ce);
b0fe89ca
LT
101 break;
102 }
103 /* Show difference between old and new */
104 show_modified(ac[1], ce);
105 break;
106 case 1:
107 /* No stage 3 (merge) entry? That means it's been deleted */
108 if (!same) {
c9cddabe 109 show_file("-", ce, ce->sha1, ce->ce_mode);
b0fe89ca
LT
110 break;
111 }
112 /* Otherwise we fall through to the "unmerged" case */
113 case 3:
f92a4465
JH
114 if (generate_patch)
115 diff_unmerge(ce->name);
116 else
117 printf("U %s%c", ce->name, line_termination);
b0fe89ca
LT
118 break;
119
120 default:
121 die("impossible cache entry stage");
e74f8f6a 122 }
b0fe89ca
LT
123
124 /*
125 * Ignore all the different stages for this file,
126 * we've handled the relevant cases now.
127 */
128 do {
e74f8f6a
LT
129 ac++;
130 entries--;
b0fe89ca 131 } while (entries && same_name(ce, ac[0]));
e74f8f6a
LT
132 }
133 return 0;
134}
135
b0fe89ca
LT
136/*
137 * This turns all merge entries into "stage 3". That guarantees that
138 * when we read in the new tree (into "stage 1"), we won't lose sight
139 * of the fact that we had unmerged entries.
140 */
141static void mark_merge_entries(void)
b5af9107
LT
142{
143 int i;
144 for (i = 0; i < active_nr; i++) {
145 struct cache_entry *ce = active_cache[i];
146 if (!ce_stage(ce))
5697ecc7 147 continue;
b0fe89ca 148 ce->ce_flags |= htons(CE_STAGEMASK);
b5af9107
LT
149 }
150}
151
f92a4465 152static char *diff_cache_usage =
160c8433 153"diff-cache [-r] [-z] [-p] [-i] [--cached] <tree sha1>";
c5bac17a 154
e74f8f6a
LT
155int main(int argc, char **argv)
156{
157 unsigned char tree_sha1[20];
158 void *tree;
159 unsigned long size;
e74f8f6a
LT
160
161 read_cache();
162 while (argc > 2) {
163 char *arg = argv[1];
164 argv++;
165 argc--;
166 if (!strcmp(arg, "-r")) {
b5af9107 167 /* We accept the -r flag just to look like diff-tree */
e74f8f6a
LT
168 continue;
169 }
f92a4465
JH
170 if (!strcmp(arg, "-p")) {
171 generate_patch = 1;
172 continue;
173 }
e74f8f6a
LT
174 if (!strcmp(arg, "-z")) {
175 line_termination = '\0';
176 continue;
177 }
160c8433
LT
178 if (!strcmp(arg, "-m")) {
179 match_nonexisting = 1;
180 continue;
181 }
e74f8f6a
LT
182 if (!strcmp(arg, "--cached")) {
183 cached_only = 1;
184 continue;
185 }
c5bac17a 186 usage(diff_cache_usage);
e74f8f6a
LT
187 }
188
3c249c95 189 if (argc != 2 || get_sha1(argv[1], tree_sha1))
c5bac17a 190 usage(diff_cache_usage);
e74f8f6a 191
b0fe89ca 192 mark_merge_entries();
b5af9107 193
40469ee9 194 tree = read_object_with_reference(tree_sha1, "tree", &size, 0);
e74f8f6a
LT
195 if (!tree)
196 die("bad tree object %s", argv[1]);
b5af9107
LT
197 if (read_tree(tree, size, 1))
198 die("unable to read tree object %s", argv[1]);
e74f8f6a 199
b5af9107 200 return diff_cache(active_cache, active_nr);
e74f8f6a 201}