@@ -344,6 +344,7 @@ static void show_filemodify(struct diff_queue_struct *q,
344
344
struct diff_options * options , void * data )
345
345
{
346
346
int i ;
347
+ struct string_list * changed = data ;
347
348
348
349
/*
349
350
* 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,
359
360
case DIFF_STATUS_DELETED :
360
361
printf ("D " );
361
362
print_path (spec -> path );
363
+ string_list_insert (changed , spec -> path );
362
364
putchar ('\n' );
363
365
break ;
364
366
365
367
case DIFF_STATUS_COPIED :
366
368
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
+ }
376
388
/* fallthrough */
377
389
378
390
case DIFF_STATUS_TYPE_CHANGED :
@@ -393,6 +405,7 @@ static void show_filemodify(struct diff_queue_struct *q,
393
405
get_object_mark (object ));
394
406
}
395
407
print_path (spec -> path );
408
+ string_list_insert (changed , spec -> path );
396
409
putchar ('\n' );
397
410
break ;
398
411
@@ -528,7 +541,8 @@ static void anonymize_ident_line(const char **beg, const char **end)
528
541
* end = out -> buf + out -> len ;
529
542
}
530
543
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 )
532
546
{
533
547
int saved_output_format = rev -> diffopt .output_format ;
534
548
const char * commit_buffer ;
@@ -615,6 +629,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
615
629
if (full_tree )
616
630
printf ("deleteall\n" );
617
631
log_tree_diff_flush (rev );
632
+ string_list_clear (paths_of_changed_objects , 0 );
618
633
rev -> diffopt .output_format = saved_output_format ;
619
634
620
635
printf ("\n" );
@@ -630,14 +645,15 @@ static void *anonymize_tag(const void *old, size_t *len)
630
645
return strbuf_detach (& out , len );
631
646
}
632
647
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 )
634
650
{
635
651
struct commit * commit ;
636
652
while (commits -> nr ) {
637
653
commit = (struct commit * )commits -> objects [commits -> nr - 1 ].item ;
638
654
if (has_unshown_parent (commit ))
639
655
return ;
640
- handle_commit (commit , revs );
656
+ handle_commit (commit , revs , paths_of_changed_objects );
641
657
commits -> nr -- ;
642
658
}
643
659
}
@@ -977,6 +993,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
977
993
char * export_filename = NULL , * import_filename = NULL ;
978
994
uint32_t lastimportid ;
979
995
struct string_list refspecs_list = STRING_LIST_INIT_NODUP ;
996
+ struct string_list paths_of_changed_objects = STRING_LIST_INIT_DUP ;
980
997
struct option options [] = {
981
998
OPT_INTEGER (0 , "progress" , & progress ,
982
999
N_ ("show progress after <n> objects" )),
@@ -1049,14 +1066,15 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
1049
1066
if (prepare_revision_walk (& revs ))
1050
1067
die ("revision walk setup failed" );
1051
1068
revs .diffopt .format_callback = show_filemodify ;
1069
+ revs .diffopt .format_callback_data = & paths_of_changed_objects ;
1052
1070
DIFF_OPT_SET (& revs .diffopt , RECURSIVE );
1053
1071
while ((commit = get_revision (& revs ))) {
1054
1072
if (has_unshown_parent (commit )) {
1055
1073
add_object_array (& commit -> object , NULL , & commits );
1056
1074
}
1057
1075
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 );
1060
1078
}
1061
1079
}
1062
1080
0 commit comments