##// 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 return og
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 def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False):
213 def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False):
153 """Check that a push won't add any outgoing head
214 """Check that a push won't add any outgoing head
154
215
155 raise Abort error and display ui message as needed.
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 if remoteheads == [nullid]:
224 if remoteheads == [nullid]:
158 # remote is empty, nothing to check.
225 # remote is empty, nothing to check.
159 return
226 return
160
227
161 cl = repo.changelog
162 if remote.capable('branchmap'):
228 if remote.capable('branchmap'):
163 # Check for each named branch if we're creating new remote heads.
229 bms = _branchmapsummary(repo, remote, outgoing)
164 # To be a remote head after push, node must be either:
230 else:
165 # - unknown locally
231 bms = _oldbranchmapsummary(repo, remoteheads, outgoing, inc)
166 # - a local outgoing head descended from update
232 oldmap, newmap, unsynced, branches, newbranches = bms
167 # - a remote head that's known locally and not
233 # 1. Check for new branches on the remote.
168 # ancestral to an outgoing head
234 if newbranches and not newbranch: # new branch requires --new-branch
169
235 branchnames = ', '.join(sorted(newbranches))
170 # 1. Create set of branches involved in the push.
236 raise util.Abort(_("push creates new remote branches: %s!")
171 branches = set(repo[n].branch() for n in outgoing.missing)
237 % branchnames,
172
238 hint=_("use 'hg push --new-branch' to create"
173 # 2. Check for new branches on the remote.
239 " new remote branches"))
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)
183
240
184 # 3. Construct the initial oldmap and newmap dicts.
241 # 2. Check for new heads.
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.
223 # If there are more heads after the push than before, a suitable
242 # If there are more heads after the push than before, a suitable
224 # error message, depending on unsynced status, is displayed.
243 # error message, depending on unsynced status, is displayed.
225 error = None
244 error = None
General Comments 0
You need to be logged in to leave comments. Login now