Show More
@@ -101,6 +101,7 b' Note: old client behave as a publishing ' | |||||
101 | """ |
|
101 | """ | |
102 |
|
102 | |||
103 |
|
103 | |||
|
104 | import heapq | |||
104 | import struct |
|
105 | import struct | |
105 | import typing |
|
106 | import typing | |
106 | import weakref |
|
107 | import weakref | |
@@ -685,46 +686,104 b' class phasecache:' | |||||
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 |
|
696 | for phase in affectable_phases: | |
691 | if phase <= targetphase: |
|
697 | found = candidates & self._phasesets[phase] | |
692 |
|
|
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} | |
|
714 | new_target_roots = set() | |||
|
715 | # revision to walk down | |||
|
716 | revs = [-r for r in new_revs] | |||
|
717 | heapq.heapify(revs) | |||
|
718 | while revs: | |||
|
719 | current = -pop(revs) | |||
|
720 | current_phase = get_phase(repo, current) | |||
|
721 | changed[current] = current_phase | |||
|
722 | p1, p2 = parents(current) | |||
|
723 | if p1 == nullrev: | |||
|
724 | p1_phase = public | |||
|
725 | else: | |||
|
726 | p1_phase = get_phase(repo, p1) | |||
|
727 | if p2 == nullrev: | |||
|
728 | p2_phase = public | |||
|
729 | else: | |||
|
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) | |||
705 |
|
744 | |||
706 | olds = self._phaseroots[phase] |
|
745 | # the last iteration was done with the smallest value | |
707 |
|
746 | min_current = current | ||
708 | affected = repo.revs(b'%ld::%ld', olds, revs) |
|
747 | # do we have unwalked children that might be new roots | |
709 | changes.update(affected) |
|
748 | if (min_current + len(changed)) < len(cl): | |
710 | if dryrun: |
|
749 | for r in range(min_current, len(cl)): | |
|
750 | if r in changed: | |||
711 | continue |
|
751 | continue | |
712 | for r in affected: |
|
752 | phase = get_phase(repo, r) | |
713 |
|
|
753 | if phase <= targetphase: | |
714 | phasetracking, r, self.phase(repo, r), targetphase |
|
754 | continue | |
715 | ) |
|
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) | |||
716 |
|
767 | |||
717 | roots = set(repo.revs(b'roots((%ld::) - %ld)', olds, affected)) |
|
768 | # apply the changes | |
718 | if olds != roots: |
|
|||
719 | self._updateroots(repo, phase, roots, tr) |
|
|||
720 | # some roots may need to be declared for lower phases |
|
|||
721 | delroots.extend(olds - roots) |
|
|||
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 change |
|
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: |
@@ -705,6 +705,23 b' test partial failure' | |||||
705 | test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde: draft -> public |
|
705 | test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde: draft -> public | |
706 | test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519: draft -> public |
|
706 | test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519: draft -> public | |
707 | test-hook-close-phase: 17a481b3bccb796c0521ae97903d81c52bfee4af: secret -> public |
|
707 | test-hook-close-phase: 17a481b3bccb796c0521ae97903d81c52bfee4af: secret -> public | |
|
708 | $ hg log -G --template "{rev} {phase} {desc}\n" | |||
|
709 | @ 7 public merge B' and E | |||
|
710 | |\ | |||
|
711 | | o 6 public B' | |||
|
712 | | | | |||
|
713 | +---o 5 secret H | |||
|
714 | | | | |||
|
715 | o | 4 public E | |||
|
716 | | | | |||
|
717 | o | 3 public D | |||
|
718 | | | | |||
|
719 | o | 2 public C | |||
|
720 | |/ | |||
|
721 | o 1 public B | |||
|
722 | | | |||
|
723 | o 0 public A | |||
|
724 | ||||
708 | $ hg phase --draft '5 or 7' |
|
725 | $ hg phase --draft '5 or 7' | |
709 | test-debug-phase: move rev 5: 2 -> 1 |
|
726 | test-debug-phase: move rev 5: 2 -> 1 | |
710 | test-hook-close-phase: a030c6be5127abc010fcbff1851536552e6951a8: secret -> draft |
|
727 | test-hook-close-phase: a030c6be5127abc010fcbff1851536552e6951a8: secret -> draft |
General Comments 0
You need to be logged in to leave comments.
Login now