2 * Copyright (C) 2005 Junio C Hamano
15 int run_diff_files(struct rev_info
*revs
, int silent_on_removed
)
18 int diff_unmerged_stage
= revs
->max_count
;
20 if (diff_unmerged_stage
< 0)
21 diff_unmerged_stage
= 2;
22 entries
= read_cache();
27 for (i
= 0; i
< entries
; i
++) {
29 unsigned int oldmode
, newmode
;
30 struct cache_entry
*ce
= active_cache
[i
];
33 if (!ce_path_match(ce
, revs
->prune_data
))
38 struct combine_diff_path p
;
39 struct combine_diff_parent filler
[5];
41 int num_compare_stages
= 0;
43 combine
.p
.next
= NULL
;
44 combine
.p
.len
= ce_namelen(ce
);
45 combine
.p
.path
= xmalloc(combine
.p
.len
+ 1);
46 memcpy(combine
.p
.path
, ce
->name
, combine
.p
.len
);
47 combine
.p
.path
[combine
.p
.len
] = 0;
49 memset(combine
.p
.sha1
, 0, 20);
50 memset(&combine
.p
.parent
[0], 0,
51 sizeof(combine
.filler
));
54 struct cache_entry
*nce
= active_cache
[i
];
57 if (strcmp(ce
->name
, nce
->name
))
60 /* Stage #2 (ours) is the first parent,
61 * stage #3 (theirs) is the second.
63 stage
= ce_stage(nce
);
65 int mode
= ntohl(nce
->ce_mode
);
67 memcpy(combine
.p
.parent
[stage
-2].sha1
,
69 combine
.p
.parent
[stage
-2].mode
=
71 combine
.p
.parent
[stage
-2].status
=
75 /* diff against the proper unmerged stage */
76 if (stage
== diff_unmerged_stage
)
81 * Compensate for loop update
85 if (revs
->combine_merges
&& num_compare_stages
== 2) {
86 show_combined_diff(&combine
.p
, 2,
87 revs
->dense_combined_merges
,
95 * Show the diff for the 'ce' if we found the one
96 * from the desired stage.
98 diff_unmerge(&revs
->diffopt
, ce
->name
);
99 if (ce_stage(ce
) != diff_unmerged_stage
)
103 if (lstat(ce
->name
, &st
) < 0) {
104 if (errno
!= ENOENT
&& errno
!= ENOTDIR
) {
108 if (silent_on_removed
)
110 diff_addremove(&revs
->diffopt
, '-', ntohl(ce
->ce_mode
),
111 ce
->sha1
, ce
->name
, NULL
);
114 changed
= ce_match_stat(ce
, &st
, 0);
115 if (!changed
&& !revs
->diffopt
.find_copies_harder
)
117 oldmode
= ntohl(ce
->ce_mode
);
119 newmode
= canon_mode(st
.st_mode
);
120 if (!trust_executable_bit
&&
121 S_ISREG(newmode
) && S_ISREG(oldmode
) &&
122 ((newmode
^ oldmode
) == 0111))
124 diff_change(&revs
->diffopt
, oldmode
, newmode
,
125 ce
->sha1
, (changed
? null_sha1
: ce
->sha1
),
129 diffcore_std(&revs
->diffopt
);
130 diff_flush(&revs
->diffopt
);
138 /* A file entry went away or appeared */
139 static void diff_index_show_file(struct rev_info
*revs
,
141 struct cache_entry
*ce
,
142 unsigned char *sha1
, unsigned int mode
)
144 diff_addremove(&revs
->diffopt
, prefix
[0], ntohl(mode
),
145 sha1
, ce
->name
, NULL
);
148 static int get_stat_data(struct cache_entry
*ce
,
149 unsigned char **sha1p
,
151 int cached
, int match_missing
)
153 unsigned char *sha1
= ce
->sha1
;
154 unsigned int mode
= ce
->ce_mode
;
157 static unsigned char no_sha1
[20];
160 if (lstat(ce
->name
, &st
) < 0) {
161 if (errno
== ENOENT
&& match_missing
) {
168 changed
= ce_match_stat(ce
, &st
, 0);
170 mode
= create_ce_mode(st
.st_mode
);
171 if (!trust_executable_bit
&& S_ISREG(st
.st_mode
))
182 static void show_new_file(struct rev_info
*revs
,
183 struct cache_entry
*new,
184 int cached
, int match_missing
)
189 /* New file in the index: it might actually be different in
192 if (get_stat_data(new, &sha1
, &mode
, cached
, match_missing
) < 0)
195 diff_index_show_file(revs
, "+", new, sha1
, mode
);
198 static int show_modified(struct rev_info
*revs
,
199 struct cache_entry
*old
,
200 struct cache_entry
*new,
202 int cached
, int match_missing
)
204 unsigned int mode
, oldmode
;
207 if (get_stat_data(new, &sha1
, &mode
, cached
, match_missing
) < 0) {
209 diff_index_show_file(revs
, "-", old
,
210 old
->sha1
, old
->ce_mode
);
214 oldmode
= old
->ce_mode
;
215 if (mode
== oldmode
&& !memcmp(sha1
, old
->sha1
, 20) &&
216 !revs
->diffopt
.find_copies_harder
)
220 oldmode
= ntohl(oldmode
);
222 diff_change(&revs
->diffopt
, oldmode
, mode
,
223 old
->sha1
, sha1
, old
->name
, NULL
);
227 static int diff_cache(struct rev_info
*revs
,
228 struct cache_entry
**ac
, int entries
,
229 const char **pathspec
,
230 int cached
, int match_missing
)
233 struct cache_entry
*ce
= *ac
;
234 int same
= (entries
> 1) && ce_same_name(ce
, ac
[1]);
236 if (!ce_path_match(ce
, pathspec
))
239 switch (ce_stage(ce
)) {
241 /* No stage 1 entry? That means it's a new file */
243 show_new_file(revs
, ce
, cached
, match_missing
);
246 /* Show difference between old and new */
247 show_modified(revs
,ac
[1], ce
, 1,
248 cached
, match_missing
);
251 /* No stage 3 (merge) entry?
252 * That means it's been deleted.
255 diff_index_show_file(revs
, "-", ce
,
256 ce
->sha1
, ce
->ce_mode
);
259 /* We come here with ce pointing at stage 1
260 * (original tree) and ac[1] pointing at stage
261 * 3 (unmerged). show-modified with
262 * report-missing set to false does not say the
263 * file is deleted but reports true if work
264 * tree does not have it, in which case we
265 * fall through to report the unmerged state.
266 * Otherwise, we show the differences between
267 * the original tree and the work tree.
270 !show_modified(revs
, ce
, ac
[1], 0,
271 cached
, match_missing
))
275 diff_unmerge(&revs
->diffopt
, ce
->name
);
279 die("impossible cache entry stage");
284 * Ignore all the different stages for this file,
285 * we've handled the relevant cases now.
290 } while (entries
&& ce_same_name(ce
, ac
[0]));
296 * This turns all merge entries into "stage 3". That guarantees that
297 * when we read in the new tree (into "stage 1"), we won't lose sight
298 * of the fact that we had unmerged entries.
300 static void mark_merge_entries(void)
303 for (i
= 0; i
< active_nr
; i
++) {
304 struct cache_entry
*ce
= active_cache
[i
];
307 ce
->ce_flags
|= htons(CE_STAGEMASK
);
311 int run_diff_index(struct rev_info
*revs
, int cached
)
316 const char *tree_name
;
317 int match_missing
= 0;
320 * Backward compatibility wart - "diff-index -m" does
321 * not mean "do not ignore merges", but totally different.
323 if (!revs
->ignore_merges
)
326 if (read_cache() < 0) {
327 perror("read_cache");
330 mark_merge_entries();
332 ent
= revs
->pending_objects
->item
;
333 tree_name
= revs
->pending_objects
->name
;
334 tree
= parse_tree_indirect(ent
->sha1
);
336 return error("bad tree object %s", tree_name
);
337 if (read_tree(tree
, 1, revs
->prune_data
))
338 return error("unable to read tree object %s", tree_name
);
339 ret
= diff_cache(revs
, active_cache
, active_nr
, revs
->prune_data
,
340 cached
, match_missing
);
341 diffcore_std(&revs
->diffopt
);
342 diff_flush(&revs
->diffopt
);