2 * Helper functions for tree diff generation
10 static int ll_diff_tree_sha1(const unsigned char *old
, const unsigned char *new,
11 const char *base_str
, struct diff_options
*opt
);
14 * Compare two tree entries, taking into account only path/S_ISDIR(mode),
15 * but not their sha1's.
17 * NOTE files and directories *always* compare differently, even when having
18 * the same name - thanks to base_name_compare().
20 * NOTE empty (=invalid) descriptor(s) take part in comparison as +infty,
21 * so that they sort *after* valid tree entries.
23 * Due to this convention, if trees are scanned in sorted order, all
24 * non-empty descriptors will be processed first.
26 static int tree_entry_pathcmp(struct tree_desc
*t1
, struct tree_desc
*t2
)
28 struct name_entry
*e1
, *e2
;
31 /* empty descriptors sort after valid tree entries */
33 return t2
->size
? 1 : 0;
39 cmp
= base_name_compare(e1
->path
, tree_entry_len(e1
), e1
->mode
,
40 e2
->path
, tree_entry_len(e2
), e2
->mode
);
45 /* convert path, t1/t2 -> opt->diff_*() callbacks */
46 static void emit_diff(struct diff_options
*opt
, struct strbuf
*path
,
47 struct tree_desc
*t1
, struct tree_desc
*t2
)
49 unsigned int mode1
= t1
? t1
->entry
.mode
: 0;
50 unsigned int mode2
= t2
? t2
->entry
.mode
: 0;
53 opt
->change(opt
, mode1
, mode2
, t1
->entry
.sha1
, t2
->entry
.sha1
,
54 1, 1, path
->buf
, 0, 0);
57 const unsigned char *sha1
;
63 sha1
= t2
->entry
.sha1
;
67 sha1
= t1
->entry
.sha1
;
71 opt
->add_remove(opt
, addremove
, mode
, sha1
, 1, path
->buf
, 0);
76 /* new path should be added to diff
78 * 3 cases on how/when it should be called and behaves:
80 * !t1, t2 -> path added, parent lacks it
81 * t1, !t2 -> path removed from parent
82 * t1, t2 -> path modified
84 static void show_path(struct strbuf
*base
, struct diff_options
*opt
,
85 struct tree_desc
*t1
, struct tree_desc
*t2
)
90 int old_baselen
= base
->len
;
91 int isdir
, recurse
= 0, emitthis
= 1;
93 /* at least something has to be valid */
97 /* path present in resulting tree */
98 tree_entry_extract(t2
, &path
, &mode
);
99 pathlen
= tree_entry_len(&t2
->entry
);
100 isdir
= S_ISDIR(mode
);
103 * a path was removed - take path from parent. Also take
104 * mode from parent, to decide on recursion.
106 tree_entry_extract(t1
, &path
, &mode
);
107 pathlen
= tree_entry_len(&t1
->entry
);
109 isdir
= S_ISDIR(mode
);
113 if (DIFF_OPT_TST(opt
, RECURSIVE
) && isdir
) {
115 emitthis
= DIFF_OPT_TST(opt
, TREE_IN_RECURSIVE
);
118 strbuf_add(base
, path
, pathlen
);
121 emit_diff(opt
, base
, t1
, t2
);
124 strbuf_addch(base
, '/');
125 ll_diff_tree_sha1(t1
? t1
->entry
.sha1
: NULL
,
126 t2
? t2
->entry
.sha1
: NULL
, base
->buf
, opt
);
129 strbuf_setlen(base
, old_baselen
);
132 static void skip_uninteresting(struct tree_desc
*t
, struct strbuf
*base
,
133 struct diff_options
*opt
)
135 enum interesting match
;
138 match
= tree_entry_interesting(&t
->entry
, base
, 0, &opt
->pathspec
);
140 if (match
== all_entries_not_interesting
)
144 update_tree_entry(t
);
148 static int ll_diff_tree_sha1(const unsigned char *old
, const unsigned char *new,
149 const char *base_str
, struct diff_options
*opt
)
151 struct tree_desc t1
, t2
;
152 void *t1tree
, *t2tree
;
154 int baselen
= strlen(base_str
);
156 t1tree
= fill_tree_descriptor(&t1
, old
);
157 t2tree
= fill_tree_descriptor(&t2
, new);
159 /* Enable recursion indefinitely */
160 opt
->pathspec
.recursive
= DIFF_OPT_TST(opt
, RECURSIVE
);
162 strbuf_init(&base
, PATH_MAX
);
163 strbuf_add(&base
, base_str
, baselen
);
168 if (diff_can_quit_early(opt
))
170 if (opt
->pathspec
.nr
) {
171 skip_uninteresting(&t1
, &base
, opt
);
172 skip_uninteresting(&t2
, &base
, opt
);
174 if (!t1
.size
&& !t2
.size
)
177 cmp
= tree_entry_pathcmp(&t1
, &t2
);
181 if (DIFF_OPT_TST(opt
, FIND_COPIES_HARDER
) ||
182 hashcmp(t1
.entry
.sha1
, t2
.entry
.sha1
) ||
183 (t1
.entry
.mode
!= t2
.entry
.mode
))
184 show_path(&base
, opt
, &t1
, &t2
);
186 update_tree_entry(&t1
);
187 update_tree_entry(&t2
);
192 show_path(&base
, opt
, &t1
, /*t2=*/NULL
);
193 update_tree_entry(&t1
);
198 show_path(&base
, opt
, /*t1=*/NULL
, &t2
);
199 update_tree_entry(&t2
);
203 strbuf_release(&base
);
210 * Does it look like the resulting diff might be due to a rename?
212 * - not a valid previous file
214 static inline int diff_might_be_rename(void)
216 return diff_queued_diff
.nr
== 1 &&
217 !DIFF_FILE_VALID(diff_queued_diff
.queue
[0]->one
);
220 static void try_to_follow_renames(const unsigned char *old
, const unsigned char *new, const char *base
, struct diff_options
*opt
)
222 struct diff_options diff_opts
;
223 struct diff_queue_struct
*q
= &diff_queued_diff
;
224 struct diff_filepair
*choice
;
228 * follow-rename code is very specific, we need exactly one
229 * path. Magic that matches more than one path is not
232 GUARD_PATHSPEC(&opt
->pathspec
, PATHSPEC_FROMTOP
| PATHSPEC_LITERAL
);
235 * We should reject wildcards as well. Unfortunately we
236 * haven't got a reliable way to detect that 'foo\*bar' in
237 * fact has no wildcards. nowildcard_len is merely a hint for
238 * optimization. Let it slip for now until wildmatch is taught
239 * about dry-run mode and returns wildcard info.
241 if (opt
->pathspec
.has_wildcard
)
242 die("BUG:%s:%d: wildcards are not supported",
246 /* Remove the file creation entry from the diff queue, and remember it */
247 choice
= q
->queue
[0];
250 diff_setup(&diff_opts
);
251 DIFF_OPT_SET(&diff_opts
, RECURSIVE
);
252 DIFF_OPT_SET(&diff_opts
, FIND_COPIES_HARDER
);
253 diff_opts
.output_format
= DIFF_FORMAT_NO_OUTPUT
;
254 diff_opts
.single_follow
= opt
->pathspec
.items
[0].match
;
255 diff_opts
.break_opt
= opt
->break_opt
;
256 diff_opts
.rename_score
= opt
->rename_score
;
257 diff_setup_done(&diff_opts
);
258 ll_diff_tree_sha1(old
, new, base
, &diff_opts
);
259 diffcore_std(&diff_opts
);
260 free_pathspec(&diff_opts
.pathspec
);
262 /* Go through the new set of filepairing, and see if we find a more interesting one */
263 opt
->found_follow
= 0;
264 for (i
= 0; i
< q
->nr
; i
++) {
265 struct diff_filepair
*p
= q
->queue
[i
];
268 * Found a source? Not only do we use that for the new
269 * diff_queued_diff, we will also use that as the path in
272 if ((p
->status
== 'R' || p
->status
== 'C') &&
273 !strcmp(p
->two
->path
, opt
->pathspec
.items
[0].match
)) {
276 /* Switch the file-pairs around */
277 q
->queue
[i
] = choice
;
280 /* Update the path we use from now on.. */
281 path
[0] = p
->one
->path
;
283 free_pathspec(&opt
->pathspec
);
284 parse_pathspec(&opt
->pathspec
,
285 PATHSPEC_ALL_MAGIC
& ~PATHSPEC_LITERAL
,
286 PATHSPEC_LITERAL_PATH
, "", path
);
289 * The caller expects us to return a set of vanilla
290 * filepairs to let a later call to diffcore_std()
291 * it makes to sort the renames out (among other
292 * things), but we already have found renames
293 * ourselves; signal diffcore_std() not to muck with
294 * rename information.
296 opt
->found_follow
= 1;
302 * Then, discard all the non-relevant file pairs...
304 for (i
= 0; i
< q
->nr
; i
++) {
305 struct diff_filepair
*p
= q
->queue
[i
];
306 diff_free_filepair(p
);
310 * .. and re-instate the one we want (which might be either the
311 * original one, or the rename/copy we found)
313 q
->queue
[0] = choice
;
317 int diff_tree_sha1(const unsigned char *old
, const unsigned char *new, const char *base
, struct diff_options
*opt
)
321 retval
= ll_diff_tree_sha1(old
, new, base
, opt
);
322 if (!*base
&& DIFF_OPT_TST(opt
, FOLLOW_RENAMES
) && diff_might_be_rename())
323 try_to_follow_renames(old
, new, base
, opt
);
328 int diff_root_tree_sha1(const unsigned char *new, const char *base
, struct diff_options
*opt
)
330 return diff_tree_sha1(NULL
, new, base
, opt
);