mercurial/phases.py
changeset 51423 23950e39281f
parent 51422 709525b26cf5
child 51424 3cee8706f53b
equal deleted inserted replaced
51422:709525b26cf5 51423:23950e39281f
    99 - content is pushed as draft
    99 - content is pushed as draft
   100 
   100 
   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
   107 
   108 
   108 from typing import (
   109 from typing import (
   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: