##// END OF EJS Templates
discovery: don't report all "unsynced" remote heads (issue4230)...
Mads Kiilerich -
r21198:56a04085 stable
parent child Browse files
Show More
@@ -1,358 +1,362
1 1 # discovery.py - protocol changeset discovery functions
2 2 #
3 3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from node import nullid, short
9 9 from i18n import _
10 10 import util, setdiscovery, treediscovery, phases, obsolete, bookmarks
11 11 import branchmap
12 12
13 13 def findcommonincoming(repo, remote, heads=None, force=False):
14 14 """Return a tuple (common, anyincoming, heads) used to identify the common
15 15 subset of nodes between repo and remote.
16 16
17 17 "common" is a list of (at least) the heads of the common subset.
18 18 "anyincoming" is testable as a boolean indicating if any nodes are missing
19 19 locally. If remote does not support getbundle, this actually is a list of
20 20 roots of the nodes that would be incoming, to be supplied to
21 21 changegroupsubset. No code except for pull should be relying on this fact
22 22 any longer.
23 23 "heads" is either the supplied heads, or else the remote's heads.
24 24
25 25 If you pass heads and they are all known locally, the response lists just
26 26 these heads in "common" and in "heads".
27 27
28 28 Please use findcommonoutgoing to compute the set of outgoing nodes to give
29 29 extensions a good hook into outgoing.
30 30 """
31 31
32 32 if not remote.capable('getbundle'):
33 33 return treediscovery.findcommonincoming(repo, remote, heads, force)
34 34
35 35 if heads:
36 36 allknown = True
37 37 knownnode = repo.changelog.hasnode # no nodemap until it is filtered
38 38 for h in heads:
39 39 if not knownnode(h):
40 40 allknown = False
41 41 break
42 42 if allknown:
43 43 return (heads, False, heads)
44 44
45 45 res = setdiscovery.findcommonheads(repo.ui, repo, remote,
46 46 abortwhenunrelated=not force)
47 47 common, anyinc, srvheads = res
48 48 return (list(common), anyinc, heads or list(srvheads))
49 49
50 50 class outgoing(object):
51 51 '''Represents the set of nodes present in a local repo but not in a
52 52 (possibly) remote one.
53 53
54 54 Members:
55 55
56 56 missing is a list of all nodes present in local but not in remote.
57 57 common is a list of all nodes shared between the two repos.
58 58 excluded is the list of missing changeset that shouldn't be sent remotely.
59 59 missingheads is the list of heads of missing.
60 60 commonheads is the list of heads of common.
61 61
62 62 The sets are computed on demand from the heads, unless provided upfront
63 63 by discovery.'''
64 64
65 65 def __init__(self, revlog, commonheads, missingheads):
66 66 self.commonheads = commonheads
67 67 self.missingheads = missingheads
68 68 self._revlog = revlog
69 69 self._common = None
70 70 self._missing = None
71 71 self.excluded = []
72 72
73 73 def _computecommonmissing(self):
74 74 sets = self._revlog.findcommonmissing(self.commonheads,
75 75 self.missingheads)
76 76 self._common, self._missing = sets
77 77
78 78 @util.propertycache
79 79 def common(self):
80 80 if self._common is None:
81 81 self._computecommonmissing()
82 82 return self._common
83 83
84 84 @util.propertycache
85 85 def missing(self):
86 86 if self._missing is None:
87 87 self._computecommonmissing()
88 88 return self._missing
89 89
90 90 def findcommonoutgoing(repo, other, onlyheads=None, force=False,
91 91 commoninc=None, portable=False):
92 92 '''Return an outgoing instance to identify the nodes present in repo but
93 93 not in other.
94 94
95 95 If onlyheads is given, only nodes ancestral to nodes in onlyheads
96 96 (inclusive) are included. If you already know the local repo's heads,
97 97 passing them in onlyheads is faster than letting them be recomputed here.
98 98
99 99 If commoninc is given, it must be the result of a prior call to
100 100 findcommonincoming(repo, other, force) to avoid recomputing it here.
101 101
102 102 If portable is given, compute more conservative common and missingheads,
103 103 to make bundles created from the instance more portable.'''
104 104 # declare an empty outgoing object to be filled later
105 105 og = outgoing(repo.changelog, None, None)
106 106
107 107 # get common set if not provided
108 108 if commoninc is None:
109 109 commoninc = findcommonincoming(repo, other, force=force)
110 110 og.commonheads, _any, _hds = commoninc
111 111
112 112 # compute outgoing
113 113 mayexclude = (repo._phasecache.phaseroots[phases.secret] or repo.obsstore)
114 114 if not mayexclude:
115 115 og.missingheads = onlyheads or repo.heads()
116 116 elif onlyheads is None:
117 117 # use visible heads as it should be cached
118 118 og.missingheads = repo.filtered("served").heads()
119 119 og.excluded = [ctx.node() for ctx in repo.set('secret() or extinct()')]
120 120 else:
121 121 # compute common, missing and exclude secret stuff
122 122 sets = repo.changelog.findcommonmissing(og.commonheads, onlyheads)
123 123 og._common, allmissing = sets
124 124 og._missing = missing = []
125 125 og.excluded = excluded = []
126 126 for node in allmissing:
127 127 ctx = repo[node]
128 128 if ctx.phase() >= phases.secret or ctx.extinct():
129 129 excluded.append(node)
130 130 else:
131 131 missing.append(node)
132 132 if len(missing) == len(allmissing):
133 133 missingheads = onlyheads
134 134 else: # update missing heads
135 135 missingheads = phases.newheads(repo, onlyheads, excluded)
136 136 og.missingheads = missingheads
137 137 if portable:
138 138 # recompute common and missingheads as if -r<rev> had been given for
139 139 # each head of missing, and --base <rev> for each head of the proper
140 140 # ancestors of missing
141 141 og._computecommonmissing()
142 142 cl = repo.changelog
143 143 missingrevs = set(cl.rev(n) for n in og._missing)
144 144 og._common = set(cl.ancestors(missingrevs)) - missingrevs
145 145 commonheads = set(og.commonheads)
146 146 og.missingheads = [h for h in og.missingheads if h not in commonheads]
147 147
148 148 return og
149 149
150 150 def _headssummary(repo, remote, outgoing):
151 151 """compute a summary of branch and heads status before and after push
152 152
153 153 return {'branch': ([remoteheads], [newheads], [unsyncedheads])} mapping
154 154
155 155 - branch: the branch name
156 156 - remoteheads: the list of remote heads known locally
157 157 None if the branch is new
158 158 - newheads: the new remote heads (known locally) with outgoing pushed
159 159 - unsyncedheads: the list of remote heads unknown locally.
160 160 """
161 161 cl = repo.changelog
162 162 headssum = {}
163 163 # A. Create set of branches involved in the push.
164 164 branches = set(repo[n].branch() for n in outgoing.missing)
165 165 remotemap = remote.branchmap()
166 166 newbranches = branches - set(remotemap)
167 167 branches.difference_update(newbranches)
168 168
169 169 # A. register remote heads
170 170 remotebranches = set()
171 171 for branch, heads in remote.branchmap().iteritems():
172 172 remotebranches.add(branch)
173 173 known = []
174 174 unsynced = []
175 175 knownnode = cl.hasnode # do not use nodemap until it is filtered
176 176 for h in heads:
177 177 if knownnode(h):
178 178 known.append(h)
179 179 else:
180 180 unsynced.append(h)
181 181 headssum[branch] = (known, list(known), unsynced)
182 182 # B. add new branch data
183 183 missingctx = list(repo[n] for n in outgoing.missing)
184 184 touchedbranches = set()
185 185 for ctx in missingctx:
186 186 branch = ctx.branch()
187 187 touchedbranches.add(branch)
188 188 if branch not in headssum:
189 189 headssum[branch] = (None, [], [])
190 190
191 191 # C drop data about untouched branches:
192 192 for branch in remotebranches - touchedbranches:
193 193 del headssum[branch]
194 194
195 195 # D. Update newmap with outgoing changes.
196 196 # This will possibly add new heads and remove existing ones.
197 197 newmap = branchmap.branchcache((branch, heads[1])
198 198 for branch, heads in headssum.iteritems()
199 199 if heads[0] is not None)
200 200 newmap.update(repo, (ctx.rev() for ctx in missingctx))
201 201 for branch, newheads in newmap.iteritems():
202 202 headssum[branch][1][:] = newheads
203 203 return headssum
204 204
205 205 def _oldheadssummary(repo, remoteheads, outgoing, inc=False):
206 206 """Compute branchmapsummary for repo without branchmap support"""
207 207
208 208 # 1-4b. old servers: Check for new topological heads.
209 209 # Construct {old,new}map with branch = None (topological branch).
210 210 # (code based on update)
211 211 knownnode = repo.changelog.hasnode # no nodemap until it is filtered
212 212 oldheads = set(h for h in remoteheads if knownnode(h))
213 213 # all nodes in outgoing.missing are children of either:
214 214 # - an element of oldheads
215 215 # - another element of outgoing.missing
216 216 # - nullrev
217 217 # This explains why the new head are very simple to compute.
218 218 r = repo.set('heads(%ln + %ln)', oldheads, outgoing.missing)
219 219 newheads = list(c.node() for c in r)
220 220 unsynced = inc and set([None]) or set()
221 221 return {None: (oldheads, newheads, unsynced)}
222 222
223 223 def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False,
224 224 newbookmarks=[]):
225 225 """Check that a push won't add any outgoing head
226 226
227 227 raise Abort error and display ui message as needed.
228 228 """
229 229 # Check for each named branch if we're creating new remote heads.
230 230 # To be a remote head after push, node must be either:
231 231 # - unknown locally
232 232 # - a local outgoing head descended from update
233 233 # - a remote head that's known locally and not
234 234 # ancestral to an outgoing head
235 235 if remoteheads == [nullid]:
236 236 # remote is empty, nothing to check.
237 237 return
238 238
239 239 if remote.capable('branchmap'):
240 240 headssum = _headssummary(repo, remote, outgoing)
241 241 else:
242 242 headssum = _oldheadssummary(repo, remoteheads, outgoing, inc)
243 243 newbranches = [branch for branch, heads in headssum.iteritems()
244 244 if heads[0] is None]
245 245 # 1. Check for new branches on the remote.
246 246 if newbranches and not newbranch: # new branch requires --new-branch
247 247 branchnames = ', '.join(sorted(newbranches))
248 248 raise util.Abort(_("push creates new remote branches: %s!")
249 249 % branchnames,
250 250 hint=_("use 'hg push --new-branch' to create"
251 251 " new remote branches"))
252 252
253 253 # 2. Compute newly pushed bookmarks. We don't warn about bookmarked heads.
254 254 localbookmarks = repo._bookmarks
255 255 remotebookmarks = remote.listkeys('bookmarks')
256 256 bookmarkedheads = set()
257 257 for bm in localbookmarks:
258 258 rnode = remotebookmarks.get(bm)
259 259 if rnode and rnode in repo:
260 260 lctx, rctx = repo[bm], repo[rnode]
261 261 if bookmarks.validdest(repo, rctx, lctx):
262 262 bookmarkedheads.add(lctx.node())
263 263 else:
264 264 if bm in newbookmarks:
265 265 bookmarkedheads.add(repo[bm].node())
266 266
267 267 # 3. Check for new heads.
268 268 # If there are more heads after the push than before, a suitable
269 269 # error message, depending on unsynced status, is displayed.
270 270 error = None
271 271 allmissing = set(outgoing.missing)
272 272 allfuturecommon = set(c.node() for c in repo.set('%ld', outgoing.common))
273 273 allfuturecommon.update(allmissing)
274 274 for branch, heads in sorted(headssum.iteritems()):
275 275 remoteheads, newheads, unsyncedheads = heads
276 276 candidate_newhs = set(newheads)
277 277 # add unsynced data
278 278 if remoteheads is None:
279 279 oldhs = set()
280 280 else:
281 281 oldhs = set(remoteheads)
282 282 oldhs.update(unsyncedheads)
283 283 candidate_newhs.update(unsyncedheads)
284 284 dhs = None # delta heads, the new heads on branch
285 285 discardedheads = set()
286 286 if repo.obsstore:
287 287 # remove future heads which are actually obsoleted by another
288 288 # pushed element:
289 289 #
290 290 # XXX as above, There are several cases this case does not handle
291 291 # XXX properly
292 292 #
293 293 # (1) if <nh> is public, it won't be affected by obsolete marker
294 294 # and a new is created
295 295 #
296 296 # (2) if the new heads have ancestors which are not obsolete and
297 297 # not ancestors of any other heads we will have a new head too.
298 298 #
299 299 # These two cases will be easy to handle for known changeset but
300 300 # much more tricky for unsynced changes.
301 301 newhs = set()
302 302 for nh in candidate_newhs:
303 303 if nh in repo and repo[nh].phase() <= phases.public:
304 304 newhs.add(nh)
305 305 else:
306 306 for suc in obsolete.allsuccessors(repo.obsstore, [nh]):
307 307 if suc != nh and suc in allfuturecommon:
308 308 discardedheads.add(nh)
309 309 break
310 310 else:
311 311 newhs.add(nh)
312 312 else:
313 313 newhs = candidate_newhs
314 314 unsynced = sorted(h for h in unsyncedheads if h not in discardedheads)
315 315 if unsynced:
316 if len(unsynced) <= 4 or repo.ui.verbose:
316 317 heads = ' '.join(short(h) for h in unsynced)
318 else:
319 heads = (' '.join(short(h) for h in unsynced[:4]) +
320 ' ' + _("and %s others") % (len(unsynced) - 4))
317 321 if branch is None:
318 322 repo.ui.status(_("remote has heads that are "
319 323 "not known locally: %s\n") % heads)
320 324 else:
321 325 repo.ui.status(_("remote has heads on branch '%s' that are "
322 326 "not known locally: %s\n") % (branch, heads))
323 327 if remoteheads is None:
324 328 if len(newhs) > 1:
325 329 dhs = list(newhs)
326 330 if error is None:
327 331 error = (_("push creates new branch '%s' "
328 332 "with multiple heads") % (branch))
329 333 hint = _("merge or"
330 334 " see \"hg help push\" for details about"
331 335 " pushing new heads")
332 336 elif len(newhs) > len(oldhs):
333 337 # remove bookmarked or existing remote heads from the new heads list
334 338 dhs = sorted(newhs - bookmarkedheads - oldhs)
335 339 if dhs:
336 340 if error is None:
337 341 if branch not in ('default', None):
338 342 error = _("push creates new remote head %s "
339 343 "on branch '%s'!") % (short(dhs[0]), branch)
340 344 else:
341 345 error = _("push creates new remote head %s!"
342 346 ) % short(dhs[0])
343 347 if unsyncedheads:
344 348 hint = _("pull and merge or"
345 349 " see \"hg help push\" for details about"
346 350 " pushing new heads")
347 351 else:
348 352 hint = _("merge or"
349 353 " see \"hg help push\" for details about"
350 354 " pushing new heads")
351 355 if branch is None:
352 356 repo.ui.note(_("new remote heads:\n"))
353 357 else:
354 358 repo.ui.note(_("new remote heads on branch '%s':\n") % branch)
355 359 for h in dhs:
356 360 repo.ui.note((" %s\n") % short(h))
357 361 if error:
358 362 raise util.Abort(error, hint=hint)
@@ -1,755 +1,774
1 1 $ hg init a
2 2 $ cd a
3 3 $ echo foo > t1
4 4 $ hg add t1
5 5 $ hg commit -m "1"
6 6
7 7 $ cd ..
8 8 $ hg clone a b
9 9 updating to branch default
10 10 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
11 11
12 12 $ cd a
13 13 $ echo foo > t2
14 14 $ hg add t2
15 15 $ hg commit -m "2"
16 16
17 17 $ cd ../b
18 18 $ echo foo > t3
19 19 $ hg add t3
20 20 $ hg commit -m "3"
21 21
22 22 $ hg push ../a
23 23 pushing to ../a
24 24 searching for changes
25 25 remote has heads on branch 'default' that are not known locally: 1c9246a22a0a
26 26 abort: push creates new remote head 1e108cc5548c!
27 27 (pull and merge or see "hg help push" for details about pushing new heads)
28 28 [255]
29 29
30 30 $ hg push --debug ../a
31 31 pushing to ../a
32 32 query 1; heads
33 33 searching for changes
34 34 taking quick initial sample
35 35 searching: 2 queries
36 36 query 2; still undecided: 1, sample size is: 1
37 37 2 total queries
38 38 listing keys for "bookmarks"
39 39 remote has heads on branch 'default' that are not known locally: 1c9246a22a0a
40 40 new remote heads on branch 'default':
41 41 1e108cc5548c
42 42 abort: push creates new remote head 1e108cc5548c!
43 43 (pull and merge or see "hg help push" for details about pushing new heads)
44 44 [255]
45 45
46 46 $ hg pull ../a
47 47 pulling from ../a
48 48 searching for changes
49 49 adding changesets
50 50 adding manifests
51 51 adding file changes
52 52 added 1 changesets with 1 changes to 1 files (+1 heads)
53 53 (run 'hg heads' to see heads, 'hg merge' to merge)
54 54
55 55 $ hg push ../a
56 56 pushing to ../a
57 57 searching for changes
58 58 abort: push creates new remote head 1e108cc5548c!
59 59 (merge or see "hg help push" for details about pushing new heads)
60 60 [255]
61 61
62 62 $ hg merge
63 63 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
64 64 (branch merge, don't forget to commit)
65 65
66 66 $ hg commit -m "4"
67 67 $ hg push ../a
68 68 pushing to ../a
69 69 searching for changes
70 70 adding changesets
71 71 adding manifests
72 72 adding file changes
73 73 added 2 changesets with 1 changes to 1 files
74 74
75 75 $ cd ..
76 76
77 77 $ hg init c
78 78 $ cd c
79 79 $ for i in 0 1 2; do
80 80 > echo $i >> foo
81 81 > hg ci -Am $i
82 82 > done
83 83 adding foo
84 84 $ cd ..
85 85
86 86 $ hg clone c d
87 87 updating to branch default
88 88 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 89
90 90 $ cd d
91 91 $ for i in 0 1; do
92 92 > hg co -C $i
93 93 > echo d-$i >> foo
94 94 > hg ci -m d-$i
95 95 > done
96 96 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
97 97 created new head
98 98 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
99 99 created new head
100 100
101 101 $ HGMERGE=true hg merge 3
102 102 merging foo
103 103 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
104 104 (branch merge, don't forget to commit)
105 105
106 106 $ hg ci -m c-d
107 107
108 108 $ hg push ../c
109 109 pushing to ../c
110 110 searching for changes
111 111 abort: push creates new remote head 6346d66eb9f5!
112 112 (merge or see "hg help push" for details about pushing new heads)
113 113 [255]
114 114
115 115 $ hg push -r 2 ../c
116 116 pushing to ../c
117 117 searching for changes
118 118 no changes found
119 119 [1]
120 120
121 121 $ hg push -r 3 ../c
122 122 pushing to ../c
123 123 searching for changes
124 124 abort: push creates new remote head a5dda829a167!
125 125 (merge or see "hg help push" for details about pushing new heads)
126 126 [255]
127 127
128 128 $ hg push -v -r 3 -r 4 ../c
129 129 pushing to ../c
130 130 searching for changes
131 131 new remote heads on branch 'default':
132 132 a5dda829a167
133 133 ee8fbc7a0295
134 134 abort: push creates new remote head a5dda829a167!
135 135 (merge or see "hg help push" for details about pushing new heads)
136 136 [255]
137 137
138 138 $ hg push -v -f -r 3 -r 4 ../c
139 139 pushing to ../c
140 140 searching for changes
141 141 2 changesets found
142 142 adding changesets
143 143 adding manifests
144 144 adding file changes
145 145 added 2 changesets with 2 changes to 1 files (+2 heads)
146 146
147 147 $ hg push -r 5 ../c
148 148 pushing to ../c
149 149 searching for changes
150 150 adding changesets
151 151 adding manifests
152 152 adding file changes
153 153 added 1 changesets with 1 changes to 1 files (-1 heads)
154 154
155 155 $ hg in ../c
156 156 comparing with ../c
157 157 searching for changes
158 158 no changes found
159 159 [1]
160 160
161 161
162 162 Issue450: push -r warns about remote head creation even if no heads
163 163 will be created
164 164
165 165 $ hg init ../e
166 166 $ hg push -r 0 ../e
167 167 pushing to ../e
168 168 searching for changes
169 169 adding changesets
170 170 adding manifests
171 171 adding file changes
172 172 added 1 changesets with 1 changes to 1 files
173 173
174 174 $ hg push -r 1 ../e
175 175 pushing to ../e
176 176 searching for changes
177 177 adding changesets
178 178 adding manifests
179 179 adding file changes
180 180 added 1 changesets with 1 changes to 1 files
181 181
182 182 $ cd ..
183 183
184 184
185 185 Issue736: named branches are not considered for detection of
186 186 unmerged heads in "hg push"
187 187
188 188 $ hg init f
189 189 $ cd f
190 190 $ hg -q branch a
191 191 $ echo 0 > foo
192 192 $ hg -q ci -Am 0
193 193 $ echo 1 > foo
194 194 $ hg -q ci -m 1
195 195 $ hg -q up 0
196 196 $ echo 2 > foo
197 197 $ hg -q ci -m 2
198 198 $ hg -q up 0
199 199 $ hg -q branch b
200 200 $ echo 3 > foo
201 201 $ hg -q ci -m 3
202 202 $ cd ..
203 203
204 204 $ hg -q clone f g
205 205 $ cd g
206 206
207 207 Push on existing branch and new branch:
208 208
209 209 $ hg -q up 1
210 210 $ echo 4 > foo
211 211 $ hg -q ci -m 4
212 212 $ hg -q up 0
213 213 $ echo 5 > foo
214 214 $ hg -q branch c
215 215 $ hg -q ci -m 5
216 216
217 217 $ hg push ../f
218 218 pushing to ../f
219 219 searching for changes
220 220 abort: push creates new remote branches: c!
221 221 (use 'hg push --new-branch' to create new remote branches)
222 222 [255]
223 223
224 224 $ hg push -r 4 -r 5 ../f
225 225 pushing to ../f
226 226 searching for changes
227 227 abort: push creates new remote branches: c!
228 228 (use 'hg push --new-branch' to create new remote branches)
229 229 [255]
230 230
231 231
232 232 Multiple new branches:
233 233
234 234 $ hg -q branch d
235 235 $ echo 6 > foo
236 236 $ hg -q ci -m 6
237 237
238 238 $ hg push ../f
239 239 pushing to ../f
240 240 searching for changes
241 241 abort: push creates new remote branches: c, d!
242 242 (use 'hg push --new-branch' to create new remote branches)
243 243 [255]
244 244
245 245 $ hg push -r 4 -r 6 ../f
246 246 pushing to ../f
247 247 searching for changes
248 248 abort: push creates new remote branches: c, d!
249 249 (use 'hg push --new-branch' to create new remote branches)
250 250 [255]
251 251
252 252 $ cd ../g
253 253
254 254
255 255 Fail on multiple head push:
256 256
257 257 $ hg -q up 1
258 258 $ echo 7 > foo
259 259 $ hg -q ci -m 7
260 260
261 261 $ hg push -r 4 -r 7 ../f
262 262 pushing to ../f
263 263 searching for changes
264 264 abort: push creates new remote head 0b715ef6ff8f on branch 'a'!
265 265 (merge or see "hg help push" for details about pushing new heads)
266 266 [255]
267 267
268 268 Push replacement head on existing branches:
269 269
270 270 $ hg -q up 3
271 271 $ echo 8 > foo
272 272 $ hg -q ci -m 8
273 273
274 274 $ hg push -r 7 -r 8 ../f
275 275 pushing to ../f
276 276 searching for changes
277 277 adding changesets
278 278 adding manifests
279 279 adding file changes
280 280 added 2 changesets with 2 changes to 1 files
281 281
282 282
283 283 Merge of branch a to other branch b followed by unrelated push
284 284 on branch a:
285 285
286 286 $ hg -q up 7
287 287 $ HGMERGE=true hg -q merge 8
288 288 $ hg -q ci -m 9
289 289 $ hg -q up 8
290 290 $ echo 10 > foo
291 291 $ hg -q ci -m 10
292 292
293 293 $ hg push -r 9 ../f
294 294 pushing to ../f
295 295 searching for changes
296 296 adding changesets
297 297 adding manifests
298 298 adding file changes
299 299 added 1 changesets with 1 changes to 1 files (-1 heads)
300 300
301 301 $ hg push -r 10 ../f
302 302 pushing to ../f
303 303 searching for changes
304 304 adding changesets
305 305 adding manifests
306 306 adding file changes
307 307 added 1 changesets with 1 changes to 1 files (+1 heads)
308 308
309 309
310 310 Cheating the counting algorithm:
311 311
312 312 $ hg -q up 9
313 313 $ HGMERGE=true hg -q merge 2
314 314 $ hg -q ci -m 11
315 315 $ hg -q up 1
316 316 $ echo 12 > foo
317 317 $ hg -q ci -m 12
318 318
319 319 $ hg push -r 11 -r 12 ../f
320 320 pushing to ../f
321 321 searching for changes
322 322 adding changesets
323 323 adding manifests
324 324 adding file changes
325 325 added 2 changesets with 2 changes to 1 files
326 326
327 327
328 328 Failed push of new named branch:
329 329
330 330 $ echo 12 > foo
331 331 $ hg -q ci -m 12a
332 332 [1]
333 333 $ hg -q up 11
334 334 $ echo 13 > foo
335 335 $ hg -q branch e
336 336 $ hg -q ci -m 13d
337 337
338 338 $ hg push -r 12 -r 13 ../f
339 339 pushing to ../f
340 340 searching for changes
341 341 abort: push creates new remote branches: e!
342 342 (use 'hg push --new-branch' to create new remote branches)
343 343 [255]
344 344
345 345
346 346 Using --new-branch to push new named branch:
347 347
348 348 $ hg push --new-branch -r 12 -r 13 ../f
349 349 pushing to ../f
350 350 searching for changes
351 351 adding changesets
352 352 adding manifests
353 353 adding file changes
354 354 added 1 changesets with 1 changes to 1 files
355 355
356 356 Pushing multi headed new branch:
357 357
358 358 $ echo 14 > foo
359 359 $ hg -q branch f
360 360 $ hg -q ci -m 14
361 361 $ echo 15 > foo
362 362 $ hg -q ci -m 15
363 363 $ hg -q up 14
364 364 $ echo 16 > foo
365 365 $ hg -q ci -m 16
366 366 $ hg push --branch f --new-branch ../f
367 367 pushing to ../f
368 368 searching for changes
369 369 abort: push creates new branch 'f' with multiple heads
370 370 (merge or see "hg help push" for details about pushing new heads)
371 371 [255]
372 372 $ hg push --branch f --new-branch --force ../f
373 373 pushing to ../f
374 374 searching for changes
375 375 adding changesets
376 376 adding manifests
377 377 adding file changes
378 378 added 3 changesets with 3 changes to 1 files (+1 heads)
379 379
380 380 Checking prepush logic does not allow silently pushing
381 multiple new heads:
381 multiple new heads but also doesn't report too many heads:
382 382
383 383 $ cd ..
384 384 $ hg init h
385 385 $ echo init > h/init
386 386 $ hg -R h ci -Am init
387 387 adding init
388 388 $ echo a > h/a
389 389 $ hg -R h ci -Am a
390 390 adding a
391 391 $ hg clone h i
392 392 updating to branch default
393 393 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
394 394 $ hg -R h up 0
395 395 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
396 396 $ echo b > h/b
397 397 $ hg -R h ci -Am b
398 398 adding b
399 399 created new head
400 400 $ hg -R i up 0
401 401 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
402 402 $ echo c > i/c
403 403 $ hg -R i ci -Am c
404 404 adding c
405 405 created new head
406 406
407 $ for i in `seq 3`; do hg -R h up -q 0; echo $i > h/b; hg -R h ci -qAm$i; done
408
407 409 $ hg -R i push h
408 410 pushing to h
409 411 searching for changes
410 remote has heads on branch 'default' that are not known locally: ce4212fc8847
412 remote has heads on branch 'default' that are not known locally: 534543e22c29 764f8ec07b96 afe7cc7679f5 ce4212fc8847
413 abort: push creates new remote head 97bd0c84d346!
414 (pull and merge or see "hg help push" for details about pushing new heads)
415 [255]
416 $ hg -R h up -q 0; echo x > h/b; hg -R h ci -qAmx
417 $ hg -R i push h
418 pushing to h
419 searching for changes
420 remote has heads on branch 'default' that are not known locally: 18ddb72c4590 534543e22c29 764f8ec07b96 afe7cc7679f5 and 1 others
421 abort: push creates new remote head 97bd0c84d346!
422 (pull and merge or see "hg help push" for details about pushing new heads)
423 [255]
424 $ hg -R i push h -v
425 pushing to h
426 searching for changes
427 remote has heads on branch 'default' that are not known locally: 18ddb72c4590 534543e22c29 764f8ec07b96 afe7cc7679f5 ce4212fc8847
428 new remote heads on branch 'default':
429 97bd0c84d346
411 430 abort: push creates new remote head 97bd0c84d346!
412 431 (pull and merge or see "hg help push" for details about pushing new heads)
413 432 [255]
414 433
415 434
416 435 Check prepush logic with merged branches:
417 436
418 437 $ hg init j
419 438 $ hg -R j branch a
420 439 marked working directory as branch a
421 440 (branches are permanent and global, did you want a bookmark?)
422 441 $ echo init > j/foo
423 442 $ hg -R j ci -Am init
424 443 adding foo
425 444 $ hg clone j k
426 445 updating to branch a
427 446 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
428 447 $ echo a1 > j/foo
429 448 $ hg -R j ci -m a1
430 449 $ hg -R k branch b
431 450 marked working directory as branch b
432 451 (branches are permanent and global, did you want a bookmark?)
433 452 $ echo b > k/foo
434 453 $ hg -R k ci -m b
435 454 $ hg -R k up 0
436 455 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
437 456
438 457 $ hg -R k merge b
439 458 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
440 459 (branch merge, don't forget to commit)
441 460
442 461 $ hg -R k ci -m merge
443 462
444 463 $ hg -R k push -r a j
445 464 pushing to j
446 465 searching for changes
447 466 abort: push creates new remote branches: b!
448 467 (use 'hg push --new-branch' to create new remote branches)
449 468 [255]
450 469
451 470
452 471 Prepush -r should not allow you to sneak in new heads:
453 472
454 473 $ hg init l
455 474 $ cd l
456 475 $ echo a >> foo
457 476 $ hg -q add foo
458 477 $ hg -q branch a
459 478 $ hg -q ci -ma
460 479 $ hg -q up null
461 480 $ echo a >> foo
462 481 $ hg -q add foo
463 482 $ hg -q branch b
464 483 $ hg -q ci -mb
465 484 $ cd ..
466 485 $ hg -q clone l m -u a
467 486 $ cd m
468 487 $ hg -q merge b
469 488 $ hg -q ci -mmb
470 489 $ hg -q up 0
471 490 $ echo a >> foo
472 491 $ hg -q ci -ma2
473 492 $ hg -q up 2
474 493 $ echo a >> foo
475 494 $ hg -q branch -f b
476 495 $ hg -q ci -mb2
477 496 $ hg -q merge 3
478 497 $ hg -q ci -mma
479 498
480 499 $ hg push ../l -b b
481 500 pushing to ../l
482 501 searching for changes
483 502 abort: push creates new remote head 451211cc22b0 on branch 'a'!
484 503 (merge or see "hg help push" for details about pushing new heads)
485 504 [255]
486 505
487 506 $ cd ..
488 507
489 508
490 509 Check prepush with new branch head on former topo non-head:
491 510
492 511 $ hg init n
493 512 $ cd n
494 513 $ hg branch A
495 514 marked working directory as branch A
496 515 (branches are permanent and global, did you want a bookmark?)
497 516 $ echo a >a
498 517 $ hg ci -Ama
499 518 adding a
500 519 $ hg branch B
501 520 marked working directory as branch B
502 521 (branches are permanent and global, did you want a bookmark?)
503 522 $ echo b >b
504 523 $ hg ci -Amb
505 524 adding b
506 525
507 526 b is now branch head of B, and a topological head
508 527 a is now branch head of A, but not a topological head
509 528
510 529 $ hg clone . inner
511 530 updating to branch B
512 531 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
513 532 $ cd inner
514 533 $ hg up B
515 534 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
516 535 $ echo b1 >b1
517 536 $ hg ci -Amb1
518 537 adding b1
519 538
520 539 in the clone b1 is now the head of B
521 540
522 541 $ cd ..
523 542 $ hg up 0
524 543 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
525 544 $ echo a2 >a2
526 545 $ hg ci -Ama2
527 546 adding a2
528 547
529 548 a2 is now the new branch head of A, and a new topological head
530 549 it replaces a former inner branch head, so it should at most warn about
531 550 A, not B
532 551
533 552 glog of local:
534 553
535 554 $ hg log -G --template "{rev}: {branches} {desc}\n"
536 555 @ 2: A a2
537 556 |
538 557 | o 1: B b
539 558 |/
540 559 o 0: A a
541 560
542 561 glog of remote:
543 562
544 563 $ hg log -G -R inner --template "{rev}: {branches} {desc}\n"
545 564 @ 2: B b1
546 565 |
547 566 o 1: B b
548 567 |
549 568 o 0: A a
550 569
551 570 outgoing:
552 571
553 572 $ hg out inner --template "{rev}: {branches} {desc}\n"
554 573 comparing with inner
555 574 searching for changes
556 575 2: A a2
557 576
558 577 $ hg push inner
559 578 pushing to inner
560 579 searching for changes
561 580 adding changesets
562 581 adding manifests
563 582 adding file changes
564 583 added 1 changesets with 1 changes to 1 files (+1 heads)
565 584
566 585 $ cd ..
567 586
568 587
569 588 Check prepush with new branch head on former topo head:
570 589
571 590 $ hg init o
572 591 $ cd o
573 592 $ hg branch A
574 593 marked working directory as branch A
575 594 (branches are permanent and global, did you want a bookmark?)
576 595 $ echo a >a
577 596 $ hg ci -Ama
578 597 adding a
579 598 $ hg branch B
580 599 marked working directory as branch B
581 600 (branches are permanent and global, did you want a bookmark?)
582 601 $ echo b >b
583 602 $ hg ci -Amb
584 603 adding b
585 604
586 605 b is now branch head of B, and a topological head
587 606
588 607 $ hg up 0
589 608 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
590 609 $ echo a1 >a1
591 610 $ hg ci -Ama1
592 611 adding a1
593 612
594 613 a1 is now branch head of A, and a topological head
595 614
596 615 $ hg clone . inner
597 616 updating to branch A
598 617 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
599 618 $ cd inner
600 619 $ hg up B
601 620 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
602 621 $ echo b1 >b1
603 622 $ hg ci -Amb1
604 623 adding b1
605 624
606 625 in the clone b1 is now the head of B
607 626
608 627 $ cd ..
609 628 $ echo a2 >a2
610 629 $ hg ci -Ama2
611 630 adding a2
612 631
613 632 a2 is now the new branch head of A, and a topological head
614 633 it replaces a former topological and branch head, so this should not warn
615 634
616 635 glog of local:
617 636
618 637 $ hg log -G --template "{rev}: {branches} {desc}\n"
619 638 @ 3: A a2
620 639 |
621 640 o 2: A a1
622 641 |
623 642 | o 1: B b
624 643 |/
625 644 o 0: A a
626 645
627 646 glog of remote:
628 647
629 648 $ hg log -G -R inner --template "{rev}: {branches} {desc}\n"
630 649 @ 3: B b1
631 650 |
632 651 | o 2: A a1
633 652 | |
634 653 o | 1: B b
635 654 |/
636 655 o 0: A a
637 656
638 657 outgoing:
639 658
640 659 $ hg out inner --template "{rev}: {branches} {desc}\n"
641 660 comparing with inner
642 661 searching for changes
643 662 3: A a2
644 663
645 664 $ hg push inner
646 665 pushing to inner
647 666 searching for changes
648 667 adding changesets
649 668 adding manifests
650 669 adding file changes
651 670 added 1 changesets with 1 changes to 1 files
652 671
653 672 $ cd ..
654 673
655 674
656 675 Check prepush with new branch head and new child of former branch head
657 676 but child is on different branch:
658 677
659 678 $ hg init p
660 679 $ cd p
661 680 $ hg branch A
662 681 marked working directory as branch A
663 682 (branches are permanent and global, did you want a bookmark?)
664 683 $ echo a0 >a
665 684 $ hg ci -Ama0
666 685 adding a
667 686 $ echo a1 >a
668 687 $ hg ci -ma1
669 688 $ hg up null
670 689 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
671 690 $ hg branch B
672 691 marked working directory as branch B
673 692 (branches are permanent and global, did you want a bookmark?)
674 693 $ echo b0 >b
675 694 $ hg ci -Amb0
676 695 adding b
677 696 $ echo b1 >b
678 697 $ hg ci -mb1
679 698
680 699 $ hg clone . inner
681 700 updating to branch B
682 701 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
683 702
684 703 $ hg up A
685 704 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
686 705 $ hg branch -f B
687 706 marked working directory as branch B
688 707 (branches are permanent and global, did you want a bookmark?)
689 708 $ echo a3 >a
690 709 $ hg ci -ma3
691 710 created new head
692 711 $ hg up 3
693 712 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
694 713 $ hg branch -f A
695 714 marked working directory as branch A
696 715 (branches are permanent and global, did you want a bookmark?)
697 716 $ echo b3 >b
698 717 $ hg ci -mb3
699 718 created new head
700 719
701 720 glog of local:
702 721
703 722 $ hg log -G --template "{rev}: {branches} {desc}\n"
704 723 @ 5: A b3
705 724 |
706 725 | o 4: B a3
707 726 | |
708 727 o | 3: B b1
709 728 | |
710 729 o | 2: B b0
711 730 /
712 731 o 1: A a1
713 732 |
714 733 o 0: A a0
715 734
716 735 glog of remote:
717 736
718 737 $ hg log -G -R inner --template "{rev}: {branches} {desc}\n"
719 738 @ 3: B b1
720 739 |
721 740 o 2: B b0
722 741
723 742 o 1: A a1
724 743 |
725 744 o 0: A a0
726 745
727 746 outgoing:
728 747
729 748 $ hg out inner --template "{rev}: {branches} {desc}\n"
730 749 comparing with inner
731 750 searching for changes
732 751 4: B a3
733 752 5: A b3
734 753
735 754 $ hg push inner
736 755 pushing to inner
737 756 searching for changes
738 757 abort: push creates new remote head 7d0f4fb6cf04 on branch 'A'!
739 758 (merge or see "hg help push" for details about pushing new heads)
740 759 [255]
741 760
742 761 $ hg push inner -r4 -r5
743 762 pushing to inner
744 763 searching for changes
745 764 abort: push creates new remote head 7d0f4fb6cf04 on branch 'A'!
746 765 (merge or see "hg help push" for details about pushing new heads)
747 766 [255]
748 767
749 768 $ hg in inner
750 769 comparing with inner
751 770 searching for changes
752 771 no changes found
753 772 [1]
754 773
755 774 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now