Mercurial > public > mercurial-scm > hg
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 |