gitweb: Remove git_to_hash function
[git] / diff-lib.c
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
11 /*
12  * diff-files
13  */
14
15 int run_diff_files(struct rev_info *revs, int silent_on_removed)
16 {
17         int entries, i;
18         int diff_unmerged_stage = revs->max_count;
19
20         if (diff_unmerged_stage < 0)
21                 diff_unmerged_stage = 2;
22         entries = read_cache();
23         if (entries < 0) {
24                 perror("read_cache");
25                 return -1;
26         }
27         for (i = 0; i < entries; i++) {
28                 struct stat st;
29                 unsigned int oldmode, newmode;
30                 struct cache_entry *ce = active_cache[i];
31                 int changed;
32
33                 if (!ce_path_match(ce, revs->prune_data))
34                         continue;
35
36                 if (ce_stage(ce)) {
37                         struct combine_diff_path *dpath;
38                         int num_compare_stages = 0;
39                         size_t path_len;
40
41                         path_len = ce_namelen(ce);
42
43                         dpath = xmalloc (combine_diff_path_size (5, path_len));
44                         dpath->path = (char *) &(dpath->parent[5]);
45
46                         dpath->next = NULL;
47                         dpath->len = path_len;
48                         memcpy(dpath->path, ce->name, path_len);
49                         dpath->path[path_len] = '\0';
50                         dpath->mode = 0;
51                         hashclr(dpath->sha1);
52                         memset(&(dpath->parent[0]), 0,
53                                         sizeof(struct combine_diff_parent)*5);
54
55                         while (i < entries) {
56                                 struct cache_entry *nce = active_cache[i];
57                                 int stage;
58
59                                 if (strcmp(ce->name, nce->name))
60                                         break;
61
62                                 /* Stage #2 (ours) is the first parent,
63                                  * stage #3 (theirs) is the second.
64                                  */
65                                 stage = ce_stage(nce);
66                                 if (2 <= stage) {
67                                         int mode = ntohl(nce->ce_mode);
68                                         num_compare_stages++;
69                                         hashcpy(dpath->parent[stage-2].sha1, nce->sha1);
70                                         dpath->parent[stage-2].mode =
71                                                 canon_mode(mode);
72                                         dpath->parent[stage-2].status =
73                                                 DIFF_STATUS_MODIFIED;
74                                 }
75
76                                 /* diff against the proper unmerged stage */
77                                 if (stage == diff_unmerged_stage)
78                                         ce = nce;
79                                 i++;
80                         }
81                         /*
82                          * Compensate for loop update
83                          */
84                         i--;
85
86                         if (revs->combine_merges && num_compare_stages == 2) {
87                                 show_combined_diff(dpath, 2,
88                                                    revs->dense_combined_merges,
89                                                    revs);
90                                 free(dpath);
91                                 continue;
92                         }
93                         free(dpath);
94                         dpath = NULL;
95
96                         /*
97                          * Show the diff for the 'ce' if we found the one
98                          * from the desired stage.
99                          */
100                         diff_unmerge(&revs->diffopt, ce->name);
101                         if (ce_stage(ce) != diff_unmerged_stage)
102                                 continue;
103                 }
104
105                 if (lstat(ce->name, &st) < 0) {
106                         if (errno != ENOENT && errno != ENOTDIR) {
107                                 perror(ce->name);
108                                 continue;
109                         }
110                         if (silent_on_removed)
111                                 continue;
112                         diff_addremove(&revs->diffopt, '-', ntohl(ce->ce_mode),
113                                        ce->sha1, ce->name, NULL);
114                         continue;
115                 }
116                 changed = ce_match_stat(ce, &st, 0);
117                 if (!changed && !revs->diffopt.find_copies_harder)
118                         continue;
119                 oldmode = ntohl(ce->ce_mode);
120
121                 newmode = canon_mode(st.st_mode);
122                 if (!trust_executable_bit &&
123                     S_ISREG(newmode) && S_ISREG(oldmode) &&
124                     ((newmode ^ oldmode) == 0111))
125                         newmode = oldmode;
126                 diff_change(&revs->diffopt, oldmode, newmode,
127                             ce->sha1, (changed ? null_sha1 : ce->sha1),
128                             ce->name, NULL);
129
130         }
131         diffcore_std(&revs->diffopt);
132         diff_flush(&revs->diffopt);
133         return 0;
134 }
135
136 /*
137  * diff-index
138  */
139
140 /* A file entry went away or appeared */
141 static void diff_index_show_file(struct rev_info *revs,
142                                  const char *prefix,
143                                  struct cache_entry *ce,
144                                  unsigned char *sha1, unsigned int mode)
145 {
146         diff_addremove(&revs->diffopt, prefix[0], ntohl(mode),
147                        sha1, ce->name, NULL);
148 }
149
150 static int get_stat_data(struct cache_entry *ce,
151                          unsigned char **sha1p,
152                          unsigned int *modep,
153                          int cached, int match_missing)
154 {
155         unsigned char *sha1 = ce->sha1;
156         unsigned int mode = ce->ce_mode;
157
158         if (!cached) {
159                 static unsigned char no_sha1[20];
160                 int changed;
161                 struct stat st;
162                 if (lstat(ce->name, &st) < 0) {
163                         if (errno == ENOENT && match_missing) {
164                                 *sha1p = sha1;
165                                 *modep = mode;
166                                 return 0;
167                         }
168                         return -1;
169                 }
170                 changed = ce_match_stat(ce, &st, 0);
171                 if (changed) {
172                         mode = create_ce_mode(st.st_mode);
173                         if (!trust_executable_bit && S_ISREG(st.st_mode))
174                                 mode = ce->ce_mode;
175                         sha1 = no_sha1;
176                 }
177         }
178
179         *sha1p = sha1;
180         *modep = mode;
181         return 0;
182 }
183
184 static void show_new_file(struct rev_info *revs,
185                           struct cache_entry *new,
186                           int cached, int match_missing)
187 {
188         unsigned char *sha1;
189         unsigned int mode;
190
191         /* New file in the index: it might actually be different in
192          * the working copy.
193          */
194         if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0)
195                 return;
196
197         diff_index_show_file(revs, "+", new, sha1, mode);
198 }
199
200 static int show_modified(struct rev_info *revs,
201                          struct cache_entry *old,
202                          struct cache_entry *new,
203                          int report_missing,
204                          int cached, int match_missing)
205 {
206         unsigned int mode, oldmode;
207         unsigned char *sha1;
208
209         if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0) {
210                 if (report_missing)
211                         diff_index_show_file(revs, "-", old,
212                                              old->sha1, old->ce_mode);
213                 return -1;
214         }
215
216         oldmode = old->ce_mode;
217         if (mode == oldmode && !hashcmp(sha1, old->sha1) &&
218             !revs->diffopt.find_copies_harder)
219                 return 0;
220
221         mode = ntohl(mode);
222         oldmode = ntohl(oldmode);
223
224         diff_change(&revs->diffopt, oldmode, mode,
225                     old->sha1, sha1, old->name, NULL);
226         return 0;
227 }
228
229 static int diff_cache(struct rev_info *revs,
230                       struct cache_entry **ac, int entries,
231                       const char **pathspec,
232                       int cached, int match_missing)
233 {
234         while (entries) {
235                 struct cache_entry *ce = *ac;
236                 int same = (entries > 1) && ce_same_name(ce, ac[1]);
237
238                 if (!ce_path_match(ce, pathspec))
239                         goto skip_entry;
240
241                 switch (ce_stage(ce)) {
242                 case 0:
243                         /* No stage 1 entry? That means it's a new file */
244                         if (!same) {
245                                 show_new_file(revs, ce, cached, match_missing);
246                                 break;
247                         }
248                         /* Show difference between old and new */
249                         show_modified(revs,ac[1], ce, 1,
250                                       cached, match_missing);
251                         break;
252                 case 1:
253                         /* No stage 3 (merge) entry?
254                          * That means it's been deleted.
255                          */
256                         if (!same) {
257                                 diff_index_show_file(revs, "-", ce,
258                                                      ce->sha1, ce->ce_mode);
259                                 break;
260                         }
261                         /* We come here with ce pointing at stage 1
262                          * (original tree) and ac[1] pointing at stage
263                          * 3 (unmerged).  show-modified with
264                          * report-missing set to false does not say the
265                          * file is deleted but reports true if work
266                          * tree does not have it, in which case we
267                          * fall through to report the unmerged state.
268                          * Otherwise, we show the differences between
269                          * the original tree and the work tree.
270                          */
271                         if (!cached &&
272                             !show_modified(revs, ce, ac[1], 0,
273                                            cached, match_missing))
274                                 break;
275                         /* fallthru */
276                 case 3:
277                         diff_unmerge(&revs->diffopt, ce->name);
278                         break;
279
280                 default:
281                         die("impossible cache entry stage");
282                 }
283
284 skip_entry:
285                 /*
286                  * Ignore all the different stages for this file,
287                  * we've handled the relevant cases now.
288                  */
289                 do {
290                         ac++;
291                         entries--;
292                 } while (entries && ce_same_name(ce, ac[0]));
293         }
294         return 0;
295 }
296
297 /*
298  * This turns all merge entries into "stage 3". That guarantees that
299  * when we read in the new tree (into "stage 1"), we won't lose sight
300  * of the fact that we had unmerged entries.
301  */
302 static void mark_merge_entries(void)
303 {
304         int i;
305         for (i = 0; i < active_nr; i++) {
306                 struct cache_entry *ce = active_cache[i];
307                 if (!ce_stage(ce))
308                         continue;
309                 ce->ce_flags |= htons(CE_STAGEMASK);
310         }
311 }
312
313 int run_diff_index(struct rev_info *revs, int cached)
314 {
315         int ret;
316         struct object *ent;
317         struct tree *tree;
318         const char *tree_name;
319         int match_missing = 0;
320
321         /* 
322          * Backward compatibility wart - "diff-index -m" does
323          * not mean "do not ignore merges", but totally different.
324          */
325         if (!revs->ignore_merges)
326                 match_missing = 1;
327
328         if (read_cache() < 0) {
329                 perror("read_cache");
330                 return -1;
331         }
332         mark_merge_entries();
333
334         ent = revs->pending.objects[0].item;
335         tree_name = revs->pending.objects[0].name;
336         tree = parse_tree_indirect(ent->sha1);
337         if (!tree)
338                 return error("bad tree object %s", tree_name);
339         if (read_tree(tree, 1, revs->prune_data))
340                 return error("unable to read tree object %s", tree_name);
341         ret = diff_cache(revs, active_cache, active_nr, revs->prune_data,
342                          cached, match_missing);
343         diffcore_std(&revs->diffopt);
344         diff_flush(&revs->diffopt);
345         return ret;
346 }