Mercurial > hg
comparison mercurial/phases.py @ 51580:b70628a9aa7e
phases: use revision number in new_heads
All graph operations will be done using revision numbers, so passing nodes only
means they will eventually get converted to revision numbers internally.
As part of an effort to align the code on using revision number we make the
`phases.newheads` function operated on revision number, taking them as input
and using them in returns, instead of the node-id it used to consume and
produce.
This is part of multiple changesets effort to translate more part of the logic,
but is done step by step to facilitate the identification of issue that might
arise in mercurial core and extensions.
To make the change simpler to handle for third party extensions, we also rename
the function, using a more modern form. This will help detecting the different
between the node-id version and the rev-num version.
I also take this as an opportunity to add some comment about possible
performance improvement for the future. They don't matter too much now, but they
are worse exploring in a while.
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Fri, 05 Apr 2024 11:33:47 +0200 |
parents | 87655e6dc108 |
children | e0194b3ea312 |
comparison
equal
deleted
inserted
replaced
51579:87655e6dc108 | 51580:b70628a9aa7e |
---|---|
107 import weakref | 107 import weakref |
108 | 108 |
109 from typing import ( | 109 from typing import ( |
110 Any, | 110 Any, |
111 Callable, | 111 Callable, |
112 Collection, | |
112 Dict, | 113 Dict, |
113 Iterable, | 114 Iterable, |
114 List, | 115 List, |
115 Optional, | 116 Optional, |
116 Set, | 117 Set, |
125 short, | 126 short, |
126 wdirrev, | 127 wdirrev, |
127 ) | 128 ) |
128 from . import ( | 129 from . import ( |
129 error, | 130 error, |
130 pycompat, | |
131 requirements, | 131 requirements, |
132 smartset, | 132 smartset, |
133 txnutil, | 133 txnutil, |
134 util, | 134 util, |
135 ) | 135 ) |
1123 draft_roots.append(rev) | 1123 draft_roots.append(rev) |
1124 else: | 1124 else: |
1125 msg = _(b'ignoring unexpected root from remote: %i %s\n') | 1125 msg = _(b'ignoring unexpected root from remote: %i %s\n') |
1126 repo.ui.warn(msg % (phase, nhex)) | 1126 repo.ui.warn(msg % (phase, nhex)) |
1127 # compute heads | 1127 # compute heads |
1128 subset_revs = [to_rev(n) for n in subset] | |
1129 public_heads = new_heads(repo, subset_revs, draft_roots) | |
1128 draft_nodes = [to_node(r) for r in draft_roots] | 1130 draft_nodes = [to_node(r) for r in draft_roots] |
1129 publicheads = newheads(repo, subset, draft_nodes) | 1131 public_nodes = [to_node(r) for r in public_heads] |
1130 return publicheads, draft_nodes | 1132 return public_nodes, draft_nodes |
1131 | 1133 |
1132 | 1134 |
1133 class remotephasessummary: | 1135 class remotephasessummary: |
1134 """summarize phase information on the remote side | 1136 """summarize phase information on the remote side |
1135 | 1137 |
1150 # Get the list of all "heads" revs draft on remote | 1152 # Get the list of all "heads" revs draft on remote |
1151 dheads = unfi.set(b'heads(%ln::%ln)', self.draftroots, remotesubset) | 1153 dheads = unfi.set(b'heads(%ln::%ln)', self.draftroots, remotesubset) |
1152 self.draftheads = [c.node() for c in dheads] | 1154 self.draftheads = [c.node() for c in dheads] |
1153 | 1155 |
1154 | 1156 |
1155 def newheads(repo, heads, roots): | 1157 def new_heads( |
1158 repo, | |
1159 heads: Collection[int], | |
1160 roots: Collection[int], | |
1161 ) -> Collection[int]: | |
1156 """compute new head of a subset minus another | 1162 """compute new head of a subset minus another |
1157 | 1163 |
1158 * `heads`: define the first subset | 1164 * `heads`: define the first subset |
1159 * `roots`: define the second we subtract from the first""" | 1165 * `roots`: define the second we subtract from the first""" |
1160 # prevent an import cycle | 1166 # prevent an import cycle |
1161 # phases > dagop > patch > copies > scmutil > obsolete > obsutil > phases | 1167 # phases > dagop > patch > copies > scmutil > obsolete > obsutil > phases |
1162 from . import dagop | 1168 from . import dagop |
1163 | 1169 |
1164 repo = repo.unfiltered() | |
1165 cl = repo.changelog | |
1166 rev = cl.index.get_rev | |
1167 if not roots: | 1170 if not roots: |
1168 return heads | 1171 return heads |
1169 if not heads or heads == [repo.nullid]: | 1172 if not heads or heads == [nullrev]: |
1170 return [] | 1173 return [] |
1171 # The logic operated on revisions, convert arguments early for convenience | 1174 # The logic operated on revisions, convert arguments early for convenience |
1172 new_heads = {rev(n) for n in heads if n != repo.nullid} | 1175 # PERF-XXX: maybe heads could directly comes as a set without impacting |
1173 roots = [rev(n) for n in roots] | 1176 # other user of that value |
1177 new_heads = set(heads) | |
1178 new_heads.discard(nullrev) | |
1174 # compute the area we need to remove | 1179 # compute the area we need to remove |
1175 affected_zone = repo.revs(b"(%ld::%ld)", roots, new_heads) | 1180 affected_zone = repo.revs(b"(%ld::%ld)", roots, new_heads) |
1176 # heads in the area are no longer heads | 1181 # heads in the area are no longer heads |
1177 new_heads.difference_update(affected_zone) | 1182 new_heads.difference_update(affected_zone) |
1178 # revisions in the area have children outside of it, | 1183 # revisions in the area have children outside of it, |
1186 new_heads.update(candidates) | 1191 new_heads.update(candidates) |
1187 prunestart = repo.revs(b"parents(%ld) and not null", new_heads) | 1192 prunestart = repo.revs(b"parents(%ld) and not null", new_heads) |
1188 pruned = dagop.reachableroots(repo, candidates, prunestart) | 1193 pruned = dagop.reachableroots(repo, candidates, prunestart) |
1189 new_heads.difference_update(pruned) | 1194 new_heads.difference_update(pruned) |
1190 | 1195 |
1191 return pycompat.maplist(cl.node, sorted(new_heads)) | 1196 # PERF-XXX: do we actually need a sorted list here? Could we simply return |
1197 # a set? | |
1198 return sorted(new_heads) | |
1192 | 1199 |
1193 | 1200 |
1194 def newcommitphase(ui: "uimod.ui") -> int: | 1201 def newcommitphase(ui: "uimod.ui") -> int: |
1195 """helper to get the target phase of new commit | 1202 """helper to get the target phase of new commit |
1196 | 1203 |