@@ -172,7 +172,10 @@ impl<T: Change> Tracker<T> {
172172 . relation ( )
173173 . filter ( |_| matches ! ( change_kind, ChangeKind :: Addition | ChangeKind :: Deletion ) ) ;
174174 let entry_kind = change. entry_mode ( ) . kind ( ) ;
175- if let ( None | Some ( Relation :: ChildOfParent ( _) ) , EntryKind :: Commit | EntryKind :: Tree ) = ( relation, entry_kind) {
175+ if entry_kind == EntryKind :: Commit {
176+ return Some ( change) ;
177+ }
178+ if let ( None , EntryKind :: Tree ) = ( relation, entry_kind) {
176179 return Some ( change) ;
177180 } ;
178181
@@ -221,27 +224,46 @@ impl<T: Change> Tracker<T> {
221224 PushSourceTreeFn : FnMut ( & mut dyn FnMut ( T , & BStr ) ) -> Result < ( ) , E > ,
222225 E : std:: error:: Error + Send + Sync + ' static ,
223226 {
227+ fn is_parent ( change : & impl Change ) -> bool {
228+ matches ! ( change. relation( ) , Some ( Relation :: Parent ( _) ) )
229+ }
224230 diff_cache. options . skip_internal_diff_if_external_is_configured = false ;
225231
232+ // The point of this is to optimize for identity-based lookups, which should be easy to find
233+ // by partitioning.
226234 fn by_id_and_location < T : Change > ( a : & Item < T > , b : & Item < T > ) -> std:: cmp:: Ordering {
227235 a. change
228236 . id ( )
229237 . cmp ( b. change . id ( ) )
230238 . then_with ( || a. path . start . cmp ( & b. path . start ) . then ( a. path . end . cmp ( & b. path . end ) ) )
231239 }
232- self . items . sort_by ( by_id_and_location) ;
233240
234241 let mut out = Outcome {
235242 options : self . rewrites ,
236243 ..Default :: default ( )
237244 } ;
245+ self . items . sort_by ( by_id_and_location) ;
246+
247+ // Rewrites by directory can be pruned out quickly, quickly pruning candidates
248+ // for the following per-item steps.
249+ self . match_pairs_of_kind (
250+ visit:: SourceKind :: Rename ,
251+ & mut cb,
252+ None , /* by identity for parents */
253+ & mut out,
254+ diff_cache,
255+ objects,
256+ Some ( is_parent) ,
257+ ) ?;
258+
238259 self . match_pairs_of_kind (
239260 visit:: SourceKind :: Rename ,
240261 & mut cb,
241262 self . rewrites . percentage ,
242263 & mut out,
243264 diff_cache,
244265 objects,
266+ None ,
245267 ) ?;
246268
247269 if let Some ( copies) = self . rewrites . copies {
@@ -252,6 +274,7 @@ impl<T: Change> Tracker<T> {
252274 & mut out,
253275 diff_cache,
254276 objects,
277+ None ,
255278 ) ?;
256279
257280 match copies. source {
@@ -275,6 +298,7 @@ impl<T: Change> Tracker<T> {
275298 & mut out,
276299 diff_cache,
277300 objects,
301+ None ,
278302 ) ?;
279303 }
280304 }
@@ -299,6 +323,7 @@ impl<T: Change> Tracker<T> {
299323}
300324
301325impl < T : Change > Tracker < T > {
326+ #[ allow( clippy:: too_many_arguments) ]
302327 fn match_pairs_of_kind (
303328 & mut self ,
304329 kind : visit:: SourceKind ,
@@ -307,10 +332,11 @@ impl<T: Change> Tracker<T> {
307332 out : & mut Outcome ,
308333 diff_cache : & mut crate :: blob:: Platform ,
309334 objects : & impl gix_object:: FindObjectOrHeader ,
335+ filter : Option < fn ( & T ) -> bool > ,
310336 ) -> Result < ( ) , emit:: Error > {
311337 // we try to cheaply reduce the set of possibilities first, before possibly looking more exhaustively.
312338 let needs_second_pass = !needs_exact_match ( percentage) ;
313- if self . match_pairs ( cb, None /* by identity */ , kind, out, diff_cache, objects) ? == Action :: Cancel {
339+ if self . match_pairs ( cb, None /* by identity */ , kind, out, diff_cache, objects, filter ) ? == Action :: Cancel {
314340 return Ok ( ( ) ) ;
315341 }
316342 if needs_second_pass {
@@ -335,12 +361,13 @@ impl<T: Change> Tracker<T> {
335361 }
336362 } ;
337363 if !is_limited {
338- self . match_pairs ( cb, percentage, kind, out, diff_cache, objects) ?;
364+ self . match_pairs ( cb, percentage, kind, out, diff_cache, objects, None ) ?;
339365 }
340366 }
341367 Ok ( ( ) )
342368 }
343369
370+ #[ allow( clippy:: too_many_arguments) ]
344371 fn match_pairs (
345372 & mut self ,
346373 cb : & mut impl FnMut ( visit:: Destination < ' _ , T > , Option < visit:: Source < ' _ , T > > ) -> Action ,
@@ -349,10 +376,14 @@ impl<T: Change> Tracker<T> {
349376 stats : & mut Outcome ,
350377 diff_cache : & mut crate :: blob:: Platform ,
351378 objects : & impl gix_object:: FindObjectOrHeader ,
379+ filter : Option < fn ( & T ) -> bool > ,
352380 ) -> Result < Action , emit:: Error > {
353381 let mut dest_ofs = 0 ;
354382 while let Some ( ( mut dest_idx, dest) ) = self . items [ dest_ofs..] . iter ( ) . enumerate ( ) . find_map ( |( idx, item) | {
355- ( !item. emitted && matches ! ( item. change. kind( ) , ChangeKind :: Addition ) ) . then_some ( ( idx, item) )
383+ ( !item. emitted
384+ && matches ! ( item. change. kind( ) , ChangeKind :: Addition )
385+ && filter. map_or ( true , |f| f ( & item. change ) ) )
386+ . then_some ( ( idx, item) )
356387 } ) {
357388 dest_idx += dest_ofs;
358389 dest_ofs = dest_idx + 1 ;
0 commit comments