diff --follow: do call diffcore_std() as necessary

Usually, diff frontends populate the output queue with filepairs without
any rename information and call diffcore_std() to sort the renames out.
When --follow is in effect, however, diff-tree family of frontend has a
hack that looks like this:

    diff-tree frontend
    -> diff_tree_sha1()
       . populate diff_queued_diff
       . if --follow is in effect and there is only one change that
         creates the target path, then
       -> try_to_follow_renames()
	  -> diff_tree_sha1() with no pathspec but with -C
	  -> diffcore_std() to find renames
	  . if rename is found, tweak diff_queued_diff and put a
	    single filepair that records the found rename there
    -> diffcore_std()
       . tweak elements on diff_queued_diff by
       - rename detection
       - path ordering
       - pickaxe filtering

We need to skip parts of the second call to diffcore_std() that is related
to rename detection, and do so only when try_to_follow_renames() did find
a rename.  Earlier 1da6175 (Make diffcore_std only can run once before a
diff_flush, 2010-05-06) tried to deal with this issue incorrectly; it
unconditionally disabled any second call to diffcore_std().

This hopefully fixes the breakage.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Junio C Hamano
2010-08-13 12:17:45 -07:00
parent 39f75d26e2
commit 44c48a909a
4 changed files with 27 additions and 16 deletions

27
diff.c
View File

@ -4064,25 +4064,24 @@ void diffcore_fix_diff_index(struct diff_options *options)
void diffcore_std(struct diff_options *options)
{
/* We never run this function more than one time, because the
* rename/copy detection logic can only run once.
*/
if (diff_queued_diff.run)
return;
if (options->skip_stat_unmatch)
diffcore_skip_stat_unmatch(options);
if (options->break_opt != -1)
diffcore_break(options->break_opt);
if (options->detect_rename)
diffcore_rename(options);
if (options->break_opt != -1)
diffcore_merge_broken();
if (!options->found_follow) {
/* See try_to_follow_renames() in tree-diff.c */
if (options->break_opt != -1)
diffcore_break(options->break_opt);
if (options->detect_rename)
diffcore_rename(options);
if (options->break_opt != -1)
diffcore_merge_broken();
}
if (options->pickaxe)
diffcore_pickaxe(options->pickaxe, options->pickaxe_opts);
if (options->orderfile)
diffcore_order(options->orderfile);
diff_resolve_rename_copy();
if (!options->found_follow)
/* See try_to_follow_renames() in tree-diff.c */
diff_resolve_rename_copy();
diffcore_apply_filter(options->filter);
if (diff_queued_diff.nr && !DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
@ -4090,7 +4089,7 @@ void diffcore_std(struct diff_options *options)
else
DIFF_OPT_CLR(options, HAS_CHANGES);
diff_queued_diff.run = 1;
options->found_follow = 0;
}
int diff_result_code(struct diff_options *opt, int status)