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