683 if tr is None: |
684 if tr is None: |
684 phasetracking = None |
685 phasetracking = None |
685 else: |
686 else: |
686 phasetracking = tr.changes.get(b'phases') |
687 phasetracking = tr.changes.get(b'phases') |
687 |
688 |
688 # filter revision already in the right phase |
689 affectable_phases = sorted( |
|
690 p for p in allphases if p > targetphase and self._phaseroots[p] |
|
691 ) |
|
692 # filter revision already in the right phases |
|
693 candidates = new_revs |
|
694 new_revs = set() |
689 self._ensure_phase_sets(repo) |
695 self._ensure_phase_sets(repo) |
690 for phase, revs in self._phasesets.items(): |
696 for phase in affectable_phases: |
691 if phase <= targetphase: |
697 found = candidates & self._phasesets[phase] |
692 new_revs -= revs |
698 new_revs |= found |
|
699 candidates -= found |
|
700 if not candidates: |
|
701 break |
693 if not new_revs: |
702 if not new_revs: |
694 return set() |
703 return set() |
695 |
704 |
696 # search for affected high phase changesets and roots |
705 # search for affected high phase changesets and roots |
697 revs = new_revs |
706 push = heapq.heappush |
698 changes = set() # set of revisions to be changed |
707 pop = heapq.heappop |
699 delroots = [] # set of root deleted by this path |
708 parents = cl.parentrevs |
700 for phase in (phase for phase in allphases if phase > targetphase): |
709 get_phase = self.phase |
701 # filter nodes that are not in a compatible phase already |
710 changed = {} # set of revisions to be changed |
702 revs = [rev for rev in revs if self.phase(repo, rev) >= phase] |
711 # set of root deleted by this path |
703 if not revs: |
712 delroots = set() |
704 break # no roots to move anymore |
713 new_roots = {p: set() for p in affectable_phases} |
705 |
714 new_target_roots = set() |
706 olds = self._phaseroots[phase] |
715 # revision to walk down |
707 |
716 revs = [-r for r in new_revs] |
708 affected = repo.revs(b'%ld::%ld', olds, revs) |
717 heapq.heapify(revs) |
709 changes.update(affected) |
718 while revs: |
710 if dryrun: |
719 current = -pop(revs) |
711 continue |
720 current_phase = get_phase(repo, current) |
712 for r in affected: |
721 changed[current] = current_phase |
713 _trackphasechange( |
722 p1, p2 = parents(current) |
714 phasetracking, r, self.phase(repo, r), targetphase |
723 if p1 == nullrev: |
715 ) |
724 p1_phase = public |
716 |
725 else: |
717 roots = set(repo.revs(b'roots((%ld::) - %ld)', olds, affected)) |
726 p1_phase = get_phase(repo, p1) |
718 if olds != roots: |
727 if p2 == nullrev: |
719 self._updateroots(repo, phase, roots, tr) |
728 p2_phase = public |
720 # some roots may need to be declared for lower phases |
729 else: |
721 delroots.extend(olds - roots) |
730 p2_phase = get_phase(repo, p2) |
|
731 # do we have a root ? |
|
732 if current_phase != p1_phase and current_phase != p2_phase: |
|
733 # do not record phase, because we could have "duplicated" |
|
734 # roots, were one root is shadowed by the very same roots of an |
|
735 # higher phases |
|
736 delroots.add(current) |
|
737 # schedule a walk down if needed |
|
738 if p1_phase > targetphase: |
|
739 push(revs, -p1) |
|
740 if p2_phase > targetphase: |
|
741 push(revs, -p2) |
|
742 if p1_phase < targetphase and p2_phase < targetphase: |
|
743 new_target_roots.add(current) |
|
744 |
|
745 # the last iteration was done with the smallest value |
|
746 min_current = current |
|
747 # do we have unwalked children that might be new roots |
|
748 if (min_current + len(changed)) < len(cl): |
|
749 for r in range(min_current, len(cl)): |
|
750 if r in changed: |
|
751 continue |
|
752 phase = get_phase(repo, r) |
|
753 if phase <= targetphase: |
|
754 continue |
|
755 p1, p2 = parents(r) |
|
756 if not (p1 in changed or p2 in changed): |
|
757 continue # not affected |
|
758 if p1 != nullrev and p1 not in changed: |
|
759 p1_phase = get_phase(repo, p1) |
|
760 if p1_phase == phase: |
|
761 continue # not a root |
|
762 if p2 != nullrev and p2 not in changed: |
|
763 p2_phase = get_phase(repo, p2) |
|
764 if p2_phase == phase: |
|
765 continue # not a root |
|
766 new_roots[phase].add(r) |
|
767 |
|
768 # apply the changes |
722 if not dryrun: |
769 if not dryrun: |
723 # declare deleted root in the target phase |
770 for r, p in changed.items(): |
724 if targetphase != 0: |
771 _trackphasechange(phasetracking, r, p, targetphase) |
725 self._retractboundary(repo, tr, targetphase, revs=delroots) |
772 for phase in affectable_phases: |
|
773 roots = self._phaseroots[phase] |
|
774 removed = roots & delroots |
|
775 if removed or new_roots[phase]: |
|
776 # Be careful to preserve shallow-copied values: do not |
|
777 # update phaseroots values, replace them. |
|
778 final_roots = roots - delroots | new_roots[phase] |
|
779 self._updateroots(repo, phase, final_roots, tr) |
|
780 if new_target_roots: |
|
781 # Thanks for previous filtering, we can't replace existing |
|
782 # roots |
|
783 new_target_roots |= self._phaseroots[targetphase] |
|
784 self._updateroots(repo, targetphase, new_target_roots, tr) |
726 repo.invalidatevolatilesets() |
785 repo.invalidatevolatilesets() |
727 return changes |
786 return changed |
728 |
787 |
729 def retractboundary(self, repo, tr, targetphase, nodes): |
788 def retractboundary(self, repo, tr, targetphase, nodes): |
730 if tr is None: |
789 if tr is None: |
731 phasetracking = None |
790 phasetracking = None |
732 else: |
791 else: |