@@ -344,6 +344,7 @@ static void show_filemodify(struct diff_queue_struct *q,
344344 struct diff_options * options , void * data )
345345{
346346 int i ;
347+ struct string_list * changed = data ;
347348
348349 /*
349350 * Handle files below a directory first, in case they are all deleted
@@ -359,20 +360,31 @@ static void show_filemodify(struct diff_queue_struct *q,
359360 case DIFF_STATUS_DELETED :
360361 printf ("D " );
361362 print_path (spec -> path );
363+ string_list_insert (changed , spec -> path );
362364 putchar ('\n' );
363365 break ;
364366
365367 case DIFF_STATUS_COPIED :
366368 case DIFF_STATUS_RENAMED :
367- printf ("%c " , q -> queue [i ]-> status );
368- print_path (ospec -> path );
369- putchar (' ' );
370- print_path (spec -> path );
371- putchar ('\n' );
372-
373- if (!oidcmp (& ospec -> oid , & spec -> oid ) &&
374- ospec -> mode == spec -> mode )
375- break ;
369+ /*
370+ * If a change in the file corresponding to ospec->path
371+ * has been observed, we cannot trust its contents
372+ * because the diff is calculated based on the prior
373+ * contents, not the current contents. So, declare a
374+ * copy or rename only if there was no change observed.
375+ */
376+ if (!string_list_has_string (changed , ospec -> path )) {
377+ printf ("%c " , q -> queue [i ]-> status );
378+ print_path (ospec -> path );
379+ putchar (' ' );
380+ print_path (spec -> path );
381+ string_list_insert (changed , spec -> path );
382+ putchar ('\n' );
383+
384+ if (!oidcmp (& ospec -> oid , & spec -> oid ) &&
385+ ospec -> mode == spec -> mode )
386+ break ;
387+ }
376388 /* fallthrough */
377389
378390 case DIFF_STATUS_TYPE_CHANGED :
@@ -393,6 +405,7 @@ static void show_filemodify(struct diff_queue_struct *q,
393405 get_object_mark (object ));
394406 }
395407 print_path (spec -> path );
408+ string_list_insert (changed , spec -> path );
396409 putchar ('\n' );
397410 break ;
398411
@@ -528,7 +541,8 @@ static void anonymize_ident_line(const char **beg, const char **end)
528541 * end = out -> buf + out -> len ;
529542}
530543
531- static void handle_commit (struct commit * commit , struct rev_info * rev )
544+ static void handle_commit (struct commit * commit , struct rev_info * rev ,
545+ struct string_list * paths_of_changed_objects )
532546{
533547 int saved_output_format = rev -> diffopt .output_format ;
534548 const char * commit_buffer ;
@@ -615,6 +629,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
615629 if (full_tree )
616630 printf ("deleteall\n" );
617631 log_tree_diff_flush (rev );
632+ string_list_clear (paths_of_changed_objects , 0 );
618633 rev -> diffopt .output_format = saved_output_format ;
619634
620635 printf ("\n" );
@@ -630,14 +645,15 @@ static void *anonymize_tag(const void *old, size_t *len)
630645 return strbuf_detach (& out , len );
631646}
632647
633- static void handle_tail (struct object_array * commits , struct rev_info * revs )
648+ static void handle_tail (struct object_array * commits , struct rev_info * revs ,
649+ struct string_list * paths_of_changed_objects )
634650{
635651 struct commit * commit ;
636652 while (commits -> nr ) {
637653 commit = (struct commit * )commits -> objects [commits -> nr - 1 ].item ;
638654 if (has_unshown_parent (commit ))
639655 return ;
640- handle_commit (commit , revs );
656+ handle_commit (commit , revs , paths_of_changed_objects );
641657 commits -> nr -- ;
642658 }
643659}
@@ -977,6 +993,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
977993 char * export_filename = NULL , * import_filename = NULL ;
978994 uint32_t lastimportid ;
979995 struct string_list refspecs_list = STRING_LIST_INIT_NODUP ;
996+ struct string_list paths_of_changed_objects = STRING_LIST_INIT_DUP ;
980997 struct option options [] = {
981998 OPT_INTEGER (0 , "progress" , & progress ,
982999 N_ ("show progress after <n> objects" )),
@@ -1049,14 +1066,15 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
10491066 if (prepare_revision_walk (& revs ))
10501067 die ("revision walk setup failed" );
10511068 revs .diffopt .format_callback = show_filemodify ;
1069+ revs .diffopt .format_callback_data = & paths_of_changed_objects ;
10521070 DIFF_OPT_SET (& revs .diffopt , RECURSIVE );
10531071 while ((commit = get_revision (& revs ))) {
10541072 if (has_unshown_parent (commit )) {
10551073 add_object_array (& commit -> object , NULL , & commits );
10561074 }
10571075 else {
1058- handle_commit (commit , & revs );
1059- handle_tail (& commits , & revs );
1076+ handle_commit (commit , & revs , & paths_of_changed_objects );
1077+ handle_tail (& commits , & revs , & paths_of_changed_objects );
10601078 }
10611079 }
10621080
0 commit comments