##// END OF EJS Templates
checkheads: simplify the structure build by preprocessing...
Pierre-Yves David -
r17211:4f321eec default
parent child Browse files
Show More
@@ -149,48 +149,60 b' def findcommonoutgoing(repo, other, only'
149
149
150 return og
150 return og
151
151
152 def _branchmapsummary(repo, remote, outgoing):
152 def _headssummary(repo, remote, outgoing):
153 """compute a summary of branch and heads status before and after push
153 """compute a summary of branch and heads status before and after push
154
154
155 - oldmap: {'branch': [heads]} mapping for remote
155 return {'branch': ([remoteheads], [newheads], [unsyncedheads])} mapping
156 - newmap: {'branch': [heads]} mapping for local
156
157 - unsynced: set of branch that have unsynced remote changes
157 - branch: the branch name
158 - branches: set of all common branch pushed
158 - remoteheads: the list of remote heads known locally
159 - newbranches: list of plain new pushed branch
159 None is the branch is new
160 - newheads: the new remote heads (known locally) with outgoing pushed
161 - unsyncedheads: the list of remote heads unknown locally.
160 """
162 """
161 cl = repo.changelog
163 cl = repo.changelog
162
164 headssum = {}
163 # A. Create set of branches involved in the push.
165 # A. Create set of branches involved in the push.
164 branches = set(repo[n].branch() for n in outgoing.missing)
166 branches = set(repo[n].branch() for n in outgoing.missing)
165 remotemap = remote.branchmap()
167 remotemap = remote.branchmap()
166 newbranches = branches - set(remotemap)
168 newbranches = branches - set(remotemap)
167 branches.difference_update(newbranches)
169 branches.difference_update(newbranches)
168
170
169 # B. Construct the initial oldmap and newmap dicts.
171 # A. register remote heads
170 # They contain information about the remote heads before and
172 remotebranches = set()
171 # after the push, respectively.
173 for branch, heads in remote.branchmap().iteritems():
172 # Heads not found locally are not included in either dict,
174 remotebranches.add(branch)
173 # since they won't be affected by the push.
175 known = []
174 # unsynced contains all branches with incoming changesets.
176 unsynced = []
175 oldmap = {}
177 for h in heads:
176 newmap = {}
178 if h in cl.nodemap:
177 unsynced = set()
179 known.append(h)
178 for branch in branches:
180 else:
179 remotebrheads = remotemap[branch]
181 unsynced.append(h)
182 headssum[branch] = (known, list(known), unsynced)
183 # B. add new branch data
184 missingctx = list(repo[n] for n in outgoing.missing)
185 touchedbranches = set()
186 for ctx in missingctx:
187 branch = ctx.branch()
188 touchedbranches.add(branch)
189 if branch not in headssum:
190 headssum[branch] = (None, [], [])
180
191
181 prunedbrheads = [h for h in remotebrheads if h in cl.nodemap]
192 # C drop data about untouched branches:
182 oldmap[branch] = prunedbrheads
193 for branch in remotebranches - touchedbranches:
183 newmap[branch] = list(prunedbrheads)
194 del headssum[branch]
184 if len(remotebrheads) > len(prunedbrheads):
185 unsynced.add(branch)
186
195
187 # C. Update newmap with outgoing changes.
196 # D. Update newmap with outgoing changes.
188 # This will possibly add new heads and remove existing ones.
197 # This will possibly add new heads and remove existing ones.
189 ctxgen = (repo[n] for n in outgoing.missing)
198 newmap = dict((branch, heads[1]) for branch, heads in headssum.iteritems()
190 repo._updatebranchcache(newmap, ctxgen)
199 if heads[0] is not None)
191 return oldmap, newmap, unsynced, branches, newbranches
200 repo._updatebranchcache(newmap, missingctx)
201 for branch, newheads in newmap.iteritems():
202 headssum[branch][1][:] = newheads
203 return headssum
192
204
193 def _oldbranchmapsummary(repo, remoteheads, outgoing, inc=False):
205 def _oldheadssummary(repo, remoteheads, outgoing, inc=False):
194 """Compute branchmapsummary for repo without branchmap support"""
206 """Compute branchmapsummary for repo without branchmap support"""
195
207
196 cl = repo.changelog
208 cl = repo.changelog
@@ -204,11 +216,9 b' def _oldbranchmapsummary(repo, remotehea'
204 # - nullrev
216 # - nullrev
205 # This explains why the new head are very simple to compute.
217 # This explains why the new head are very simple to compute.
206 r = repo.set('heads(%ln + %ln)', oldheads, outgoing.missing)
218 r = repo.set('heads(%ln + %ln)', oldheads, outgoing.missing)
207 branches = set([None])
219 newheads = list(c.node() for c in r)
208 newmap = {None: list(c.node() for c in r)}
220 unsynced = inc and set([None]) or set()
209 oldmap = {None: oldheads}
221 return {None: (oldheads, newheads, unsynced)}
210 unsynced = inc and branches or set()
211 return oldmap, newmap, unsynced, branches, set()
212
222
213 def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False):
223 def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False):
214 """Check that a push won't add any outgoing head
224 """Check that a push won't add any outgoing head
@@ -226,10 +236,11 b' def checkheads(repo, remote, outgoing, r'
226 return
236 return
227
237
228 if remote.capable('branchmap'):
238 if remote.capable('branchmap'):
229 bms = _branchmapsummary(repo, remote, outgoing)
239 headssum = _headssummary(repo, remote, outgoing)
230 else:
240 else:
231 bms = _oldbranchmapsummary(repo, remoteheads, outgoing, inc)
241 headssum = _oldheadssummary(repo, remoteheads, outgoing, inc)
232 oldmap, newmap, unsynced, branches, newbranches = bms
242 newbranches = [branch for branch, heads in headssum.iteritems()
243 if heads[0] is None]
233 # 1. Check for new branches on the remote.
244 # 1. Check for new branches on the remote.
234 if newbranches and not newbranch: # new branch requires --new-branch
245 if newbranches and not newbranch: # new branch requires --new-branch
235 branchnames = ', '.join(sorted(newbranches))
246 branchnames = ', '.join(sorted(newbranches))
@@ -244,12 +255,18 b' def checkheads(repo, remote, outgoing, r'
244 error = None
255 error = None
245 localbookmarks = repo._bookmarks
256 localbookmarks = repo._bookmarks
246
257
247 for branch in branches:
258 unsynced = False
248 newhs = set(newmap[branch])
259 for branch, heads in headssum.iteritems():
249 oldhs = set(oldmap[branch])
260 if heads[0] is None:
261 # Maybe we should abort if we push more that one head
262 # for new branches ?
263 continue
264 if heads[2]:
265 unsynced = True
266 oldhs = set(heads[0])
267 newhs = set(heads[1])
250 dhs = None
268 dhs = None
251 if len(newhs) > len(oldhs):
269 if len(newhs) > len(oldhs):
252 # strip updates to existing remote heads from the new heads list
253 remotebookmarks = remote.listkeys('bookmarks')
270 remotebookmarks = remote.listkeys('bookmarks')
254 bookmarkedheads = set()
271 bookmarkedheads = set()
255 for bm in localbookmarks:
272 for bm in localbookmarks:
@@ -258,6 +275,7 b' def checkheads(repo, remote, outgoing, r'
258 lctx, rctx = repo[bm], repo[rnode]
275 lctx, rctx = repo[bm], repo[rnode]
259 if rctx == lctx.ancestor(rctx):
276 if rctx == lctx.ancestor(rctx):
260 bookmarkedheads.add(lctx.node())
277 bookmarkedheads.add(lctx.node())
278 # strip updates to existing remote heads from the new heads list
261 dhs = list(newhs - bookmarkedheads - oldhs)
279 dhs = list(newhs - bookmarkedheads - oldhs)
262 if dhs:
280 if dhs:
263 if error is None:
281 if error is None:
@@ -267,7 +285,7 b' def checkheads(repo, remote, outgoing, r'
267 else:
285 else:
268 error = _("push creates new remote head %s!"
286 error = _("push creates new remote head %s!"
269 ) % short(dhs[0])
287 ) % short(dhs[0])
270 if branch in unsynced:
288 if heads[2]: # unsynced
271 hint = _("you should pull and merge or "
289 hint = _("you should pull and merge or "
272 "use push -f to force")
290 "use push -f to force")
273 else:
291 else:
General Comments 0
You need to be logged in to leave comments. Login now