comparison mercurial/copies.py @ 46158:1fcfff09cac5

copies: avoid early return in _combine_changeset_copies We have to change how we deal with matching (see next changeset) and that processing is common. So we shuffle things around before doing the semantic change for clarity. Differential Revision: https://phab.mercurial-scm.org/D9584
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Sun, 13 Dec 2020 20:26:27 +0100
parents a132aa5979ec
children 929054848d6c
comparison
equal deleted inserted replaced
46157:021925827c60 46158:1fcfff09cac5
355 """ 355 """
356 356
357 alwaysmatch = match.always() 357 alwaysmatch = match.always()
358 358
359 if rustmod is not None and alwaysmatch: 359 if rustmod is not None and alwaysmatch:
360 return rustmod.combine_changeset_copies( 360 final_copies = rustmod.combine_changeset_copies(
361 list(revs), children_count, targetrev, revinfo, isancestor 361 list(revs), children_count, targetrev, revinfo, isancestor
362 ) 362 )
363 363 else:
364 isancestor = cached_is_ancestor(isancestor) 364 isancestor = cached_is_ancestor(isancestor)
365 365
366 all_copies = {} 366 all_copies = {}
367 # iterate over all the "children" side of copy tracing "edge" 367 # iterate over all the "children" side of copy tracing "edge"
368 for current_rev in revs: 368 for current_rev in revs:
369 p1, p2, changes = revinfo(current_rev) 369 p1, p2, changes = revinfo(current_rev)
370 current_copies = None 370 current_copies = None
371 371 # iterate over all parents to chain the existing data with the
372 # iterate over all parents to chain the existing data with the 372 # data from the parent → child edge.
373 # data from the parent → child edge. 373 for parent, parent_rev in ((1, p1), (2, p2)):
374 for parent, parent_rev in ((1, p1), (2, p2)): 374 if parent_rev == nullrev:
375 if parent_rev == nullrev: 375 continue
376 continue 376 remaining_children = children_count.get(parent_rev)
377 remaining_children = children_count.get(parent_rev) 377 if remaining_children is None:
378 if remaining_children is None: 378 continue
379 continue 379 remaining_children -= 1
380 remaining_children -= 1 380 children_count[parent_rev] = remaining_children
381 children_count[parent_rev] = remaining_children 381 if remaining_children:
382 if remaining_children: 382 copies = all_copies.get(parent_rev, None)
383 copies = all_copies.get(parent_rev, None) 383 else:
384 else: 384 copies = all_copies.pop(parent_rev, None)
385 copies = all_copies.pop(parent_rev, None) 385
386 386 if copies is None:
387 if copies is None: 387 # this is a root
388 # this is a root 388 copies = {}
389 copies = {} 389
390 390 newcopies = copies
391 newcopies = copies 391 # chain the data in the edge with the existing data
392 # chain the data in the edge with the existing data 392 if changes is not None:
393 if changes is not None: 393 childcopies = {}
394 childcopies = {} 394 if parent == 1:
395 if parent == 1: 395 childcopies = changes.copied_from_p1
396 childcopies = changes.copied_from_p1 396 elif parent == 2:
397 elif parent == 2: 397 childcopies = changes.copied_from_p2
398 childcopies = changes.copied_from_p2 398
399 399 if not alwaysmatch:
400 if not alwaysmatch: 400 childcopies = {
401 childcopies = { 401 dst: src
402 dst: src 402 for dst, src in childcopies.items()
403 for dst, src in childcopies.items() 403 if match(dst)
404 if match(dst) 404 }
405 } 405 if childcopies:
406 if childcopies:
407 newcopies = copies.copy()
408 for dest, source in pycompat.iteritems(childcopies):
409 prev = copies.get(source)
410 if prev is not None and prev[1] is not None:
411 source = prev[1]
412 newcopies[dest] = (current_rev, source)
413 assert newcopies is not copies
414 if changes.removed:
415 if newcopies is copies:
416 newcopies = copies.copy() 406 newcopies = copies.copy()
417 for f in changes.removed: 407 for dest, source in pycompat.iteritems(childcopies):
418 if f in newcopies: 408 prev = copies.get(source)
419 if newcopies is copies: 409 if prev is not None and prev[1] is not None:
420 # copy on write to avoid affecting potential other 410 source = prev[1]
421 # branches. when there are no other branches, this 411 newcopies[dest] = (current_rev, source)
422 # could be avoided. 412 assert newcopies is not copies
423 newcopies = copies.copy() 413 if changes.removed:
424 newcopies[f] = (current_rev, None) 414 if newcopies is copies:
425 415 newcopies = copies.copy()
426 # check potential need to combine the data from another parent (for 416 for f in changes.removed:
427 # that child). See comment below for details. 417 if f in newcopies:
428 if current_copies is None: 418 if newcopies is copies:
429 current_copies = newcopies 419 # copy on write to avoid affecting potential other
430 elif current_copies is newcopies: 420 # branches. when there are no other branches, this
431 # nothing to merge: 421 # could be avoided.
432 pass 422 newcopies = copies.copy()
433 else: 423 newcopies[f] = (current_rev, None)
434 # we are the second parent to work on c, we need to merge our 424 # check potential need to combine the data from another parent (for
435 # work with the other. 425 # that child). See comment below for details.
436 # 426 if current_copies is None:
437 # In case of conflict, parent 1 take precedence over parent 2. 427 current_copies = newcopies
438 # This is an arbitrary choice made anew when implementing 428 elif current_copies is newcopies:
439 # changeset based copies. It was made without regards with 429 # nothing to merge:
440 # potential filelog related behavior. 430 pass
441 assert parent == 2 431 else:
442 current_copies = _merge_copies_dict( 432 # we are the second parent to work on c, we need to merge our
443 newcopies, current_copies, isancestor, changes 433 # work with the other.
444 ) 434 #
445 all_copies[current_rev] = current_copies 435 # In case of conflict, parent 1 take precedence over parent 2.
446 436 # This is an arbitrary choice made anew when implementing
447 # filter out internal details and return a {dest: source mapping} 437 # changeset based copies. It was made without regards with
448 final_copies = {} 438 # potential filelog related behavior.
449 for dest, (tt, source) in all_copies[targetrev].items(): 439 assert parent == 2
450 if source is not None: 440 current_copies = _merge_copies_dict(
451 final_copies[dest] = source 441 newcopies, current_copies, isancestor, changes
442 )
443 all_copies[current_rev] = current_copies
444
445 # filter out internal details and return a {dest: source mapping}
446 final_copies = {}
447 for dest, (tt, source) in all_copies[targetrev].items():
448 if source is not None:
449 final_copies[dest] = source
452 return final_copies 450 return final_copies
453 451
454 452
455 def _merge_copies_dict(minor, major, isancestor, changes): 453 def _merge_copies_dict(minor, major, isancestor, changes):
456 """merge two copies-mapping together, minor and major 454 """merge two copies-mapping together, minor and major