@@ -527,14 +527,15 @@ static void update_dir_rename_counts(struct dir_rename_info *info,
527
527
}
528
528
529
529
static void initialize_dir_rename_info (struct dir_rename_info * info ,
530
+ struct strset * relevant_sources ,
530
531
struct strset * dirs_removed ,
531
532
struct strmap * dir_rename_count )
532
533
{
533
534
struct hashmap_iter iter ;
534
535
struct strmap_entry * entry ;
535
536
int i ;
536
537
537
- if (!dirs_removed ) {
538
+ if (!dirs_removed && ! relevant_sources ) {
538
539
info -> setup = 0 ;
539
540
return ;
540
541
}
@@ -549,7 +550,20 @@ static void initialize_dir_rename_info(struct dir_rename_info *info,
549
550
strmap_init_with_options (& info -> dir_rename_guess , NULL , 0 );
550
551
551
552
/* Setup info->relevant_source_dirs */
552
- info -> relevant_source_dirs = dirs_removed ;
553
+ info -> relevant_source_dirs = NULL ;
554
+ if (dirs_removed || !relevant_sources ) {
555
+ info -> relevant_source_dirs = dirs_removed ; /* might be NULL */
556
+ } else {
557
+ info -> relevant_source_dirs = xmalloc (sizeof (struct strintmap ));
558
+ strset_init (info -> relevant_source_dirs );
559
+ strset_for_each_entry (relevant_sources , & iter , entry ) {
560
+ char * dirname = get_dirname (entry -> key );
561
+ if (!dirs_removed ||
562
+ strset_contains (dirs_removed , dirname ))
563
+ strset_add (info -> relevant_source_dirs , dirname );
564
+ free (dirname );
565
+ }
566
+ }
553
567
554
568
/*
555
569
* Loop setting up both info->idx_map, and doing setup of
@@ -627,6 +641,13 @@ static void cleanup_dir_rename_info(struct dir_rename_info *info,
627
641
/* dir_rename_guess */
628
642
strmap_clear (& info -> dir_rename_guess , 1 );
629
643
644
+ /* relevant_source_dirs */
645
+ if (info -> relevant_source_dirs &&
646
+ info -> relevant_source_dirs != dirs_removed ) {
647
+ strset_clear (info -> relevant_source_dirs );
648
+ FREE_AND_NULL (info -> relevant_source_dirs );
649
+ }
650
+
630
651
/* dir_rename_count */
631
652
if (!keep_dir_rename_count ) {
632
653
partial_clear_dir_rename_count (info -> dir_rename_count );
@@ -749,6 +770,7 @@ static int idx_possible_rename(char *filename, struct dir_rename_info *info)
749
770
static int find_basename_matches (struct diff_options * options ,
750
771
int minimum_score ,
751
772
struct dir_rename_info * info ,
773
+ struct strset * relevant_sources ,
752
774
struct strset * dirs_removed )
753
775
{
754
776
/*
@@ -839,6 +861,11 @@ static int find_basename_matches(struct diff_options *options,
839
861
intptr_t src_index ;
840
862
intptr_t dst_index ;
841
863
864
+ /* Skip irrelevant sources */
865
+ if (relevant_sources &&
866
+ !strset_contains (relevant_sources , filename ))
867
+ continue ;
868
+
842
869
/*
843
870
* If the basename is unique among remaining sources, then
844
871
* src_index will equal 'i' and we can attempt to match it
@@ -991,11 +1018,12 @@ static int find_renames(struct diff_score *mx,
991
1018
return count ;
992
1019
}
993
1020
994
- static void remove_unneeded_paths_from_src (int detecting_copies )
1021
+ static void remove_unneeded_paths_from_src (int detecting_copies ,
1022
+ struct strset * interesting )
995
1023
{
996
1024
int i , new_num_src ;
997
1025
998
- if (detecting_copies )
1026
+ if (detecting_copies && ! interesting )
999
1027
return ; /* nothing to remove */
1000
1028
if (break_idx )
1001
1029
return ; /* culling incompatible with break detection */
@@ -1022,12 +1050,18 @@ static void remove_unneeded_paths_from_src(int detecting_copies)
1022
1050
* from rename_src here.
1023
1051
*/
1024
1052
for (i = 0 , new_num_src = 0 ; i < rename_src_nr ; i ++ ) {
1053
+ struct diff_filespec * one = rename_src [i ].p -> one ;
1054
+
1025
1055
/*
1026
1056
* renames are stored in rename_dst, so if a rename has
1027
1057
* already been detected using this source, we can just
1028
1058
* remove the source knowing rename_dst has its info.
1029
1059
*/
1030
- if (rename_src [i ].p -> one -> rename_used )
1060
+ if (!detecting_copies && one -> rename_used )
1061
+ continue ;
1062
+
1063
+ /* If we don't care about the source path, skip it */
1064
+ if (interesting && !strset_contains (interesting , one -> path ))
1031
1065
continue ;
1032
1066
1033
1067
if (new_num_src < i )
@@ -1040,6 +1074,7 @@ static void remove_unneeded_paths_from_src(int detecting_copies)
1040
1074
}
1041
1075
1042
1076
void diffcore_rename_extended (struct diff_options * options ,
1077
+ struct strset * relevant_sources ,
1043
1078
struct strset * dirs_removed ,
1044
1079
struct strmap * dir_rename_count )
1045
1080
{
@@ -1060,6 +1095,8 @@ void diffcore_rename_extended(struct diff_options *options,
1060
1095
want_copies = (detect_rename == DIFF_DETECT_COPY );
1061
1096
if (dirs_removed && (break_idx || want_copies ))
1062
1097
BUG ("dirs_removed incompatible with break/copy detection" );
1098
+ if (break_idx && relevant_sources )
1099
+ BUG ("break detection incompatible with source specification" );
1063
1100
if (!minimum_score )
1064
1101
minimum_score = DEFAULT_RENAME_SCORE ;
1065
1102
@@ -1127,9 +1164,10 @@ void diffcore_rename_extended(struct diff_options *options,
1127
1164
/*
1128
1165
* Cull sources:
1129
1166
* - remove ones corresponding to exact renames
1167
+ * - remove ones not found in relevant_sources
1130
1168
*/
1131
1169
trace2_region_enter ("diff" , "cull after exact" , options -> repo );
1132
- remove_unneeded_paths_from_src (want_copies );
1170
+ remove_unneeded_paths_from_src (want_copies , relevant_sources );
1133
1171
trace2_region_leave ("diff" , "cull after exact" , options -> repo );
1134
1172
} else {
1135
1173
/* Determine minimum score to match basenames */
@@ -1148,28 +1186,31 @@ void diffcore_rename_extended(struct diff_options *options,
1148
1186
* - remove ones involved in renames (found via exact match)
1149
1187
*/
1150
1188
trace2_region_enter ("diff" , "cull after exact" , options -> repo );
1151
- remove_unneeded_paths_from_src (want_copies );
1189
+ remove_unneeded_paths_from_src (want_copies , NULL );
1152
1190
trace2_region_leave ("diff" , "cull after exact" , options -> repo );
1153
1191
1154
1192
/* Preparation for basename-driven matching. */
1155
1193
trace2_region_enter ("diff" , "dir rename setup" , options -> repo );
1156
- initialize_dir_rename_info (& info ,
1194
+ initialize_dir_rename_info (& info , relevant_sources ,
1157
1195
dirs_removed , dir_rename_count );
1158
1196
trace2_region_leave ("diff" , "dir rename setup" , options -> repo );
1159
1197
1160
1198
/* Utilize file basenames to quickly find renames. */
1161
1199
trace2_region_enter ("diff" , "basename matches" , options -> repo );
1162
1200
rename_count += find_basename_matches (options ,
1163
1201
min_basename_score ,
1164
- & info , dirs_removed );
1202
+ & info ,
1203
+ relevant_sources ,
1204
+ dirs_removed );
1165
1205
trace2_region_leave ("diff" , "basename matches" , options -> repo );
1166
1206
1167
1207
/*
1168
1208
* Cull sources, again:
1169
1209
* - remove ones involved in renames (found via basenames)
1210
+ * - remove ones not found in relevant_sources
1170
1211
*/
1171
1212
trace2_region_enter ("diff" , "cull basename" , options -> repo );
1172
- remove_unneeded_paths_from_src (want_copies );
1213
+ remove_unneeded_paths_from_src (want_copies , relevant_sources );
1173
1214
trace2_region_leave ("diff" , "cull basename" , options -> repo );
1174
1215
}
1175
1216
@@ -1341,5 +1382,5 @@ void diffcore_rename_extended(struct diff_options *options,
1341
1382
1342
1383
void diffcore_rename (struct diff_options * options )
1343
1384
{
1344
- diffcore_rename_extended (options , NULL , NULL );
1385
+ diffcore_rename_extended (options , NULL , NULL , NULL );
1345
1386
}
0 commit comments