##// END OF EJS Templates
checkheads: extract branchmap preprocessing...
Pierre-Yves David -
r17209:5cd3e526 default
parent child Browse files
Show More
@@ -149,77 +149,96 b' def findcommonoutgoing(repo, other, only'
149 149
150 150 return og
151 151
152 def _branchmapsummary(repo, remote, outgoing):
153 """compute a summary of branch and heads status before and after push
154
155 - oldmap: {'branch': [heads]} mapping for remote
156 - newmap: {'branch': [heads]} mapping for local
157 - unsynced: set of branch that have unsynced remote changes
158 - branches: set of all common branch pushed
159 - newbranches: list of plain new pushed branch
160 """
161 cl = repo.changelog
162
163 # A. Create set of branches involved in the push.
164 branches = set(repo[n].branch() for n in outgoing.missing)
165 remotemap = remote.branchmap()
166 newbranches = branches - set(remotemap)
167 branches.difference_update(newbranches)
168
169 # B. Construct the initial oldmap and newmap dicts.
170 # They contain information about the remote heads before and
171 # after the push, respectively.
172 # Heads not found locally are not included in either dict,
173 # since they won't be affected by the push.
174 # unsynced contains all branches with incoming changesets.
175 oldmap = {}
176 newmap = {}
177 unsynced = set()
178 for branch in branches:
179 remotebrheads = remotemap[branch]
180
181 prunedbrheads = [h for h in remotebrheads if h in cl.nodemap]
182 oldmap[branch] = prunedbrheads
183 newmap[branch] = list(prunedbrheads)
184 if len(remotebrheads) > len(prunedbrheads):
185 unsynced.add(branch)
186
187 # C. Update newmap with outgoing changes.
188 # This will possibly add new heads and remove existing ones.
189 ctxgen = (repo[n] for n in outgoing.missing)
190 repo._updatebranchcache(newmap, ctxgen)
191 return oldmap, newmap, unsynced, branches, newbranches
192
193 def _oldbranchmapsummary(repo, remoteheads, outgoing, inc=False):
194 """Compute branchmapsummary for repo without branchmap support"""
195
196 cl = repo.changelog
197 # 1-4b. old servers: Check for new topological heads.
198 # Construct {old,new}map with branch = None (topological branch).
199 # (code based on _updatebranchcache)
200 oldheads = set(h for h in remoteheads if h in cl.nodemap)
201 # all nodes in outgoing.missing are children of either:
202 # - an element of oldheads
203 # - another element of outgoing.missing
204 # - nullrev
205 # This explains why the new head are very simple to compute.
206 r = repo.set('heads(%ln + %ln)', oldheads, outgoing.missing)
207 branches = set([None])
208 newmap = {None: list(c.node() for c in r)}
209 oldmap = {None: oldheads}
210 unsynced = inc and branches or set()
211 return oldmap, newmap, unsynced, branches, set()
212
152 213 def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False):
153 214 """Check that a push won't add any outgoing head
154 215
155 216 raise Abort error and display ui message as needed.
156 217 """
218 # Check for each named branch if we're creating new remote heads.
219 # To be a remote head after push, node must be either:
220 # - unknown locally
221 # - a local outgoing head descended from update
222 # - a remote head that's known locally and not
223 # ancestral to an outgoing head
157 224 if remoteheads == [nullid]:
158 225 # remote is empty, nothing to check.
159 226 return
160 227
161 cl = repo.changelog
162 228 if remote.capable('branchmap'):
163 # Check for each named branch if we're creating new remote heads.
164 # To be a remote head after push, node must be either:
165 # - unknown locally
166 # - a local outgoing head descended from update
167 # - a remote head that's known locally and not
168 # ancestral to an outgoing head
169
170 # 1. Create set of branches involved in the push.
171 branches = set(repo[n].branch() for n in outgoing.missing)
172
173 # 2. Check for new branches on the remote.
174 remotemap = remote.branchmap()
175 newbranches = branches - set(remotemap)
176 if newbranches and not newbranch: # new branch requires --new-branch
177 branchnames = ', '.join(sorted(newbranches))
178 raise util.Abort(_("push creates new remote branches: %s!")
179 % branchnames,
180 hint=_("use 'hg push --new-branch' to create"
181 " new remote branches"))
182 branches.difference_update(newbranches)
229 bms = _branchmapsummary(repo, remote, outgoing)
230 else:
231 bms = _oldbranchmapsummary(repo, remoteheads, outgoing, inc)
232 oldmap, newmap, unsynced, branches, newbranches = bms
233 # 1. Check for new branches on the remote.
234 if newbranches and not newbranch: # new branch requires --new-branch
235 branchnames = ', '.join(sorted(newbranches))
236 raise util.Abort(_("push creates new remote branches: %s!")
237 % branchnames,
238 hint=_("use 'hg push --new-branch' to create"
239 " new remote branches"))
183 240
184 # 3. Construct the initial oldmap and newmap dicts.
185 # They contain information about the remote heads before and
186 # after the push, respectively.
187 # Heads not found locally are not included in either dict,
188 # since they won't be affected by the push.
189 # unsynced contains all branches with incoming changesets.
190 oldmap = {}
191 newmap = {}
192 unsynced = set()
193 for branch in branches:
194 remotebrheads = remotemap[branch]
195 prunedbrheads = [h for h in remotebrheads if h in cl.nodemap]
196 oldmap[branch] = prunedbrheads
197 newmap[branch] = list(prunedbrheads)
198 if len(remotebrheads) > len(prunedbrheads):
199 unsynced.add(branch)
200
201 # 4. Update newmap with outgoing changes.
202 # This will possibly add new heads and remove existing ones.
203 ctxgen = (repo[n] for n in outgoing.missing)
204 repo._updatebranchcache(newmap, ctxgen)
205
206 else:
207 # 1-4b. old servers: Check for new topological heads.
208 # Construct {old,new}map with branch = None (topological branch).
209 # (code based on _updatebranchcache)
210 oldheads = set(h for h in remoteheads if h in cl.nodemap)
211 # all nodes in outgoing.missing are children of either:
212 # - an element of oldheads
213 # - another element of outgoing.missing
214 # - nullrev
215 # This explains why the new head are very simple to compute.
216 r = repo.set('heads(%ln + %ln)', oldheads, outgoing.missing)
217 branches = set([None])
218 newmap = {None: list(c.node() for c in r)}
219 oldmap = {None: oldheads}
220 unsynced = inc and branches or set()
221
222 # 5. Check for new heads.
241 # 2. Check for new heads.
223 242 # If there are more heads after the push than before, a suitable
224 243 # error message, depending on unsynced status, is displayed.
225 244 error = None
General Comments 0
You need to be logged in to leave comments. Login now