##// END OF EJS Templates
bookmarks: don't allow pushing new head for existing mark with -B (issue4400)
Matt Mackall -
r26819:ba7eeeac stable
parent child Browse files
Show More
@@ -1,397 +1,397
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 __future__ import absolute_import
9 9
10 10 from .i18n import _
11 11 from .node import (
12 12 nullid,
13 13 short,
14 14 )
15 15
16 16 from . import (
17 17 bookmarks,
18 18 branchmap,
19 19 error,
20 20 obsolete,
21 21 phases,
22 22 setdiscovery,
23 23 treediscovery,
24 24 util,
25 25 )
26 26
27 27 def findcommonincoming(repo, remote, heads=None, force=False):
28 28 """Return a tuple (common, anyincoming, heads) used to identify the common
29 29 subset of nodes between repo and remote.
30 30
31 31 "common" is a list of (at least) the heads of the common subset.
32 32 "anyincoming" is testable as a boolean indicating if any nodes are missing
33 33 locally. If remote does not support getbundle, this actually is a list of
34 34 roots of the nodes that would be incoming, to be supplied to
35 35 changegroupsubset. No code except for pull should be relying on this fact
36 36 any longer.
37 37 "heads" is either the supplied heads, or else the remote's heads.
38 38
39 39 If you pass heads and they are all known locally, the response lists just
40 40 these heads in "common" and in "heads".
41 41
42 42 Please use findcommonoutgoing to compute the set of outgoing nodes to give
43 43 extensions a good hook into outgoing.
44 44 """
45 45
46 46 if not remote.capable('getbundle'):
47 47 return treediscovery.findcommonincoming(repo, remote, heads, force)
48 48
49 49 if heads:
50 50 allknown = True
51 51 knownnode = repo.changelog.hasnode # no nodemap until it is filtered
52 52 for h in heads:
53 53 if not knownnode(h):
54 54 allknown = False
55 55 break
56 56 if allknown:
57 57 return (heads, False, heads)
58 58
59 59 res = setdiscovery.findcommonheads(repo.ui, repo, remote,
60 60 abortwhenunrelated=not force)
61 61 common, anyinc, srvheads = res
62 62 return (list(common), anyinc, heads or list(srvheads))
63 63
64 64 class outgoing(object):
65 65 '''Represents the set of nodes present in a local repo but not in a
66 66 (possibly) remote one.
67 67
68 68 Members:
69 69
70 70 missing is a list of all nodes present in local but not in remote.
71 71 common is a list of all nodes shared between the two repos.
72 72 excluded is the list of missing changeset that shouldn't be sent remotely.
73 73 missingheads is the list of heads of missing.
74 74 commonheads is the list of heads of common.
75 75
76 76 The sets are computed on demand from the heads, unless provided upfront
77 77 by discovery.'''
78 78
79 79 def __init__(self, revlog, commonheads, missingheads):
80 80 self.commonheads = commonheads
81 81 self.missingheads = missingheads
82 82 self._revlog = revlog
83 83 self._common = None
84 84 self._missing = None
85 85 self.excluded = []
86 86
87 87 def _computecommonmissing(self):
88 88 sets = self._revlog.findcommonmissing(self.commonheads,
89 89 self.missingheads)
90 90 self._common, self._missing = sets
91 91
92 92 @util.propertycache
93 93 def common(self):
94 94 if self._common is None:
95 95 self._computecommonmissing()
96 96 return self._common
97 97
98 98 @util.propertycache
99 99 def missing(self):
100 100 if self._missing is None:
101 101 self._computecommonmissing()
102 102 return self._missing
103 103
104 104 def findcommonoutgoing(repo, other, onlyheads=None, force=False,
105 105 commoninc=None, portable=False):
106 106 '''Return an outgoing instance to identify the nodes present in repo but
107 107 not in other.
108 108
109 109 If onlyheads is given, only nodes ancestral to nodes in onlyheads
110 110 (inclusive) are included. If you already know the local repo's heads,
111 111 passing them in onlyheads is faster than letting them be recomputed here.
112 112
113 113 If commoninc is given, it must be the result of a prior call to
114 114 findcommonincoming(repo, other, force) to avoid recomputing it here.
115 115
116 116 If portable is given, compute more conservative common and missingheads,
117 117 to make bundles created from the instance more portable.'''
118 118 # declare an empty outgoing object to be filled later
119 119 og = outgoing(repo.changelog, None, None)
120 120
121 121 # get common set if not provided
122 122 if commoninc is None:
123 123 commoninc = findcommonincoming(repo, other, force=force)
124 124 og.commonheads, _any, _hds = commoninc
125 125
126 126 # compute outgoing
127 127 mayexclude = (repo._phasecache.phaseroots[phases.secret] or repo.obsstore)
128 128 if not mayexclude:
129 129 og.missingheads = onlyheads or repo.heads()
130 130 elif onlyheads is None:
131 131 # use visible heads as it should be cached
132 132 og.missingheads = repo.filtered("served").heads()
133 133 og.excluded = [ctx.node() for ctx in repo.set('secret() or extinct()')]
134 134 else:
135 135 # compute common, missing and exclude secret stuff
136 136 sets = repo.changelog.findcommonmissing(og.commonheads, onlyheads)
137 137 og._common, allmissing = sets
138 138 og._missing = missing = []
139 139 og.excluded = excluded = []
140 140 for node in allmissing:
141 141 ctx = repo[node]
142 142 if ctx.phase() >= phases.secret or ctx.extinct():
143 143 excluded.append(node)
144 144 else:
145 145 missing.append(node)
146 146 if len(missing) == len(allmissing):
147 147 missingheads = onlyheads
148 148 else: # update missing heads
149 149 missingheads = phases.newheads(repo, onlyheads, excluded)
150 150 og.missingheads = missingheads
151 151 if portable:
152 152 # recompute common and missingheads as if -r<rev> had been given for
153 153 # each head of missing, and --base <rev> for each head of the proper
154 154 # ancestors of missing
155 155 og._computecommonmissing()
156 156 cl = repo.changelog
157 157 missingrevs = set(cl.rev(n) for n in og._missing)
158 158 og._common = set(cl.ancestors(missingrevs)) - missingrevs
159 159 commonheads = set(og.commonheads)
160 160 og.missingheads = [h for h in og.missingheads if h not in commonheads]
161 161
162 162 return og
163 163
164 164 def _headssummary(repo, remote, outgoing):
165 165 """compute a summary of branch and heads status before and after push
166 166
167 167 return {'branch': ([remoteheads], [newheads], [unsyncedheads])} mapping
168 168
169 169 - branch: the branch name
170 170 - remoteheads: the list of remote heads known locally
171 171 None if the branch is new
172 172 - newheads: the new remote heads (known locally) with outgoing pushed
173 173 - unsyncedheads: the list of remote heads unknown locally.
174 174 """
175 175 cl = repo.changelog
176 176 headssum = {}
177 177 # A. Create set of branches involved in the push.
178 178 branches = set(repo[n].branch() for n in outgoing.missing)
179 179 remotemap = remote.branchmap()
180 180 newbranches = branches - set(remotemap)
181 181 branches.difference_update(newbranches)
182 182
183 183 # A. register remote heads
184 184 remotebranches = set()
185 185 for branch, heads in remote.branchmap().iteritems():
186 186 remotebranches.add(branch)
187 187 known = []
188 188 unsynced = []
189 189 knownnode = cl.hasnode # do not use nodemap until it is filtered
190 190 for h in heads:
191 191 if knownnode(h):
192 192 known.append(h)
193 193 else:
194 194 unsynced.append(h)
195 195 headssum[branch] = (known, list(known), unsynced)
196 196 # B. add new branch data
197 197 missingctx = list(repo[n] for n in outgoing.missing)
198 198 touchedbranches = set()
199 199 for ctx in missingctx:
200 200 branch = ctx.branch()
201 201 touchedbranches.add(branch)
202 202 if branch not in headssum:
203 203 headssum[branch] = (None, [], [])
204 204
205 205 # C drop data about untouched branches:
206 206 for branch in remotebranches - touchedbranches:
207 207 del headssum[branch]
208 208
209 209 # D. Update newmap with outgoing changes.
210 210 # This will possibly add new heads and remove existing ones.
211 211 newmap = branchmap.branchcache((branch, heads[1])
212 212 for branch, heads in headssum.iteritems()
213 213 if heads[0] is not None)
214 214 newmap.update(repo, (ctx.rev() for ctx in missingctx))
215 215 for branch, newheads in newmap.iteritems():
216 216 headssum[branch][1][:] = newheads
217 217 return headssum
218 218
219 219 def _oldheadssummary(repo, remoteheads, outgoing, inc=False):
220 220 """Compute branchmapsummary for repo without branchmap support"""
221 221
222 222 # 1-4b. old servers: Check for new topological heads.
223 223 # Construct {old,new}map with branch = None (topological branch).
224 224 # (code based on update)
225 225 knownnode = repo.changelog.hasnode # no nodemap until it is filtered
226 226 oldheads = set(h for h in remoteheads if knownnode(h))
227 227 # all nodes in outgoing.missing are children of either:
228 228 # - an element of oldheads
229 229 # - another element of outgoing.missing
230 230 # - nullrev
231 231 # This explains why the new head are very simple to compute.
232 232 r = repo.set('heads(%ln + %ln)', oldheads, outgoing.missing)
233 233 newheads = list(c.node() for c in r)
234 234 # set some unsynced head to issue the "unsynced changes" warning
235 235 if inc:
236 236 unsynced = set([None])
237 237 else:
238 238 unsynced = set()
239 239 return {None: (oldheads, newheads, unsynced)}
240 240
241 241 def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False,
242 242 newbookmarks=[]):
243 243 """Check that a push won't add any outgoing head
244 244
245 245 raise Abort error and display ui message as needed.
246 246 """
247 247 # Check for each named branch if we're creating new remote heads.
248 248 # To be a remote head after push, node must be either:
249 249 # - unknown locally
250 250 # - a local outgoing head descended from update
251 251 # - a remote head that's known locally and not
252 252 # ancestral to an outgoing head
253 253 if remoteheads == [nullid]:
254 254 # remote is empty, nothing to check.
255 255 return
256 256
257 257 if remote.capable('branchmap'):
258 258 headssum = _headssummary(repo, remote, outgoing)
259 259 else:
260 260 headssum = _oldheadssummary(repo, remoteheads, outgoing, inc)
261 261 newbranches = [branch for branch, heads in headssum.iteritems()
262 262 if heads[0] is None]
263 263 # 1. Check for new branches on the remote.
264 264 if newbranches and not newbranch: # new branch requires --new-branch
265 265 branchnames = ', '.join(sorted(newbranches))
266 266 raise error.Abort(_("push creates new remote branches: %s!")
267 267 % branchnames,
268 268 hint=_("use 'hg push --new-branch' to create"
269 269 " new remote branches"))
270 270
271 271 # 2. Compute newly pushed bookmarks. We don't warn about bookmarked heads.
272 272 localbookmarks = repo._bookmarks
273 273 remotebookmarks = remote.listkeys('bookmarks')
274 274 bookmarkedheads = set()
275 275 for bm in localbookmarks:
276 276 rnode = remotebookmarks.get(bm)
277 277 if rnode and rnode in repo:
278 278 lctx, rctx = repo[bm], repo[rnode]
279 279 if bookmarks.validdest(repo, rctx, lctx):
280 280 bookmarkedheads.add(lctx.node())
281 281 else:
282 if bm in newbookmarks:
282 if bm in newbookmarks and bm not in remotebookmarks:
283 283 bookmarkedheads.add(repo[bm].node())
284 284
285 285 # 3. Check for new heads.
286 286 # If there are more heads after the push than before, a suitable
287 287 # error message, depending on unsynced status, is displayed.
288 288 errormsg = None
289 289 # If there is no obsstore, allfuturecommon won't be used, so no
290 290 # need to compute it.
291 291 if repo.obsstore:
292 292 allmissing = set(outgoing.missing)
293 293 cctx = repo.set('%ld', outgoing.common)
294 294 allfuturecommon = set(c.node() for c in cctx)
295 295 allfuturecommon.update(allmissing)
296 296 for branch, heads in sorted(headssum.iteritems()):
297 297 remoteheads, newheads, unsyncedheads = heads
298 298 candidate_newhs = set(newheads)
299 299 # add unsynced data
300 300 if remoteheads is None:
301 301 oldhs = set()
302 302 else:
303 303 oldhs = set(remoteheads)
304 304 oldhs.update(unsyncedheads)
305 305 candidate_newhs.update(unsyncedheads)
306 306 dhs = None # delta heads, the new heads on branch
307 307 discardedheads = set()
308 308 if not repo.obsstore:
309 309 newhs = candidate_newhs
310 310 else:
311 311 # remove future heads which are actually obsoleted by another
312 312 # pushed element:
313 313 #
314 314 # XXX as above, There are several cases this code does not handle
315 315 # XXX properly
316 316 #
317 317 # (1) if <nh> is public, it won't be affected by obsolete marker
318 318 # and a new is created
319 319 #
320 320 # (2) if the new heads have ancestors which are not obsolete and
321 321 # not ancestors of any other heads we will have a new head too.
322 322 #
323 323 # These two cases will be easy to handle for known changeset but
324 324 # much more tricky for unsynced changes.
325 325 #
326 326 # In addition, this code is confused by prune as it only looks for
327 327 # successors of the heads (none if pruned) leading to issue4354
328 328 newhs = set()
329 329 for nh in candidate_newhs:
330 330 if nh in repo and repo[nh].phase() <= phases.public:
331 331 newhs.add(nh)
332 332 else:
333 333 for suc in obsolete.allsuccessors(repo.obsstore, [nh]):
334 334 if suc != nh and suc in allfuturecommon:
335 335 discardedheads.add(nh)
336 336 break
337 337 else:
338 338 newhs.add(nh)
339 339 unsynced = sorted(h for h in unsyncedheads if h not in discardedheads)
340 340 if unsynced:
341 341 if None in unsynced:
342 342 # old remote, no heads data
343 343 heads = None
344 344 elif len(unsynced) <= 4 or repo.ui.verbose:
345 345 heads = ' '.join(short(h) for h in unsynced)
346 346 else:
347 347 heads = (' '.join(short(h) for h in unsynced[:4]) +
348 348 ' ' + _("and %s others") % (len(unsynced) - 4))
349 349 if heads is None:
350 350 repo.ui.status(_("remote has heads that are "
351 351 "not known locally\n"))
352 352 elif branch is None:
353 353 repo.ui.status(_("remote has heads that are "
354 354 "not known locally: %s\n") % heads)
355 355 else:
356 356 repo.ui.status(_("remote has heads on branch '%s' that are "
357 357 "not known locally: %s\n") % (branch, heads))
358 358 if remoteheads is None:
359 359 if len(newhs) > 1:
360 360 dhs = list(newhs)
361 361 if errormsg is None:
362 362 errormsg = (_("push creates new branch '%s' "
363 363 "with multiple heads") % (branch))
364 364 hint = _("merge or"
365 365 " see \"hg help push\" for details about"
366 366 " pushing new heads")
367 367 elif len(newhs) > len(oldhs):
368 368 # remove bookmarked or existing remote heads from the new heads list
369 369 dhs = sorted(newhs - bookmarkedheads - oldhs)
370 370 if dhs:
371 371 if errormsg is None:
372 372 if branch not in ('default', None):
373 373 errormsg = _("push creates new remote head %s "
374 374 "on branch '%s'!") % (short(dhs[0]), branch)
375 375 elif repo[dhs[0]].bookmarks():
376 376 errormsg = _("push creates new remote head %s "
377 377 "with bookmark '%s'!") % (
378 378 short(dhs[0]), repo[dhs[0]].bookmarks()[0])
379 379 else:
380 380 errormsg = _("push creates new remote head %s!"
381 381 ) % short(dhs[0])
382 382 if unsyncedheads:
383 383 hint = _("pull and merge or"
384 384 " see \"hg help push\" for details about"
385 385 " pushing new heads")
386 386 else:
387 387 hint = _("merge or"
388 388 " see \"hg help push\" for details about"
389 389 " pushing new heads")
390 390 if branch is None:
391 391 repo.ui.note(_("new remote heads:\n"))
392 392 else:
393 393 repo.ui.note(_("new remote heads on branch '%s':\n") % branch)
394 394 for h in dhs:
395 395 repo.ui.note((" %s\n") % short(h))
396 396 if errormsg:
397 397 raise error.Abort(errormsg, hint=hint)
@@ -1,807 +1,827
1 1 #require serve
2 2
3 3 $ cat << EOF >> $HGRCPATH
4 4 > [ui]
5 5 > logtemplate={rev}:{node|short} {desc|firstline}
6 6 > [phases]
7 7 > publish=False
8 8 > [experimental]
9 9 > evolution=createmarkers,exchange
10 10 > # drop me once bundle2 is the default,
11 11 > # added to get test change early.
12 12 > bundle2-exp = True
13 13 > EOF
14 14
15 15 initialize
16 16
17 17 $ hg init a
18 18 $ cd a
19 19 $ echo 'test' > test
20 20 $ hg commit -Am'test'
21 21 adding test
22 22
23 23 set bookmarks
24 24
25 25 $ hg bookmark X
26 26 $ hg bookmark Y
27 27 $ hg bookmark Z
28 28
29 29 import bookmark by name
30 30
31 31 $ hg init ../b
32 32 $ cd ../b
33 33 $ hg book Y
34 34 $ hg book
35 35 * Y -1:000000000000
36 36 $ hg pull ../a
37 37 pulling from ../a
38 38 requesting all changes
39 39 adding changesets
40 40 adding manifests
41 41 adding file changes
42 42 added 1 changesets with 1 changes to 1 files
43 43 adding remote bookmark X
44 44 updating bookmark Y
45 45 adding remote bookmark Z
46 46 (run 'hg update' to get a working copy)
47 47 $ hg bookmarks
48 48 X 0:4e3505fd9583
49 49 * Y 0:4e3505fd9583
50 50 Z 0:4e3505fd9583
51 51 $ hg debugpushkey ../a namespaces
52 52 bookmarks
53 53 namespaces
54 54 obsolete
55 55 phases
56 56 $ hg debugpushkey ../a bookmarks
57 57 X 4e3505fd95835d721066b76e75dbb8cc554d7f77
58 58 Y 4e3505fd95835d721066b76e75dbb8cc554d7f77
59 59 Z 4e3505fd95835d721066b76e75dbb8cc554d7f77
60 60
61 61 delete the bookmark to re-pull it
62 62
63 63 $ hg book -d X
64 64 $ hg pull -B X ../a
65 65 pulling from ../a
66 66 no changes found
67 67 adding remote bookmark X
68 68
69 69 finally no-op pull
70 70
71 71 $ hg pull -B X ../a
72 72 pulling from ../a
73 73 no changes found
74 74 $ hg bookmark
75 75 X 0:4e3505fd9583
76 76 * Y 0:4e3505fd9583
77 77 Z 0:4e3505fd9583
78 78
79 79 export bookmark by name
80 80
81 81 $ hg bookmark W
82 82 $ hg bookmark foo
83 83 $ hg bookmark foobar
84 84 $ hg push -B W ../a
85 85 pushing to ../a
86 86 searching for changes
87 87 no changes found
88 88 exporting bookmark W
89 89 [1]
90 90 $ hg -R ../a bookmarks
91 91 W -1:000000000000
92 92 X 0:4e3505fd9583
93 93 Y 0:4e3505fd9583
94 94 * Z 0:4e3505fd9583
95 95
96 96 delete a remote bookmark
97 97
98 98 $ hg book -d W
99 99 $ hg push -B W ../a
100 100 pushing to ../a
101 101 searching for changes
102 102 no changes found
103 103 deleting remote bookmark W
104 104 [1]
105 105
106 106 push/pull name that doesn't exist
107 107
108 108 $ hg push -B badname ../a
109 109 pushing to ../a
110 110 searching for changes
111 111 bookmark badname does not exist on the local or remote repository!
112 112 no changes found
113 113 [2]
114 114 $ hg pull -B anotherbadname ../a
115 115 pulling from ../a
116 116 abort: remote bookmark anotherbadname not found!
117 117 [255]
118 118
119 119 divergent bookmarks
120 120
121 121 $ cd ../a
122 122 $ echo c1 > f1
123 123 $ hg ci -Am1
124 124 adding f1
125 125 $ hg book -f @
126 126 $ hg book -f X
127 127 $ hg book
128 128 @ 1:0d2164f0ce0d
129 129 * X 1:0d2164f0ce0d
130 130 Y 0:4e3505fd9583
131 131 Z 1:0d2164f0ce0d
132 132
133 133 $ cd ../b
134 134 $ hg up
135 135 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
136 136 updating bookmark foobar
137 137 $ echo c2 > f2
138 138 $ hg ci -Am2
139 139 adding f2
140 140 $ hg book -if @
141 141 $ hg book -if X
142 142 $ hg book
143 143 @ 1:9b140be10808
144 144 X 1:9b140be10808
145 145 Y 0:4e3505fd9583
146 146 Z 0:4e3505fd9583
147 147 foo -1:000000000000
148 148 * foobar 1:9b140be10808
149 149
150 150 $ hg pull --config paths.foo=../a foo
151 151 pulling from $TESTTMP/a (glob)
152 152 searching for changes
153 153 adding changesets
154 154 adding manifests
155 155 adding file changes
156 156 added 1 changesets with 1 changes to 1 files (+1 heads)
157 157 divergent bookmark @ stored as @foo
158 158 divergent bookmark X stored as X@foo
159 159 updating bookmark Z
160 160 (run 'hg heads' to see heads, 'hg merge' to merge)
161 161 $ hg book
162 162 @ 1:9b140be10808
163 163 @foo 2:0d2164f0ce0d
164 164 X 1:9b140be10808
165 165 X@foo 2:0d2164f0ce0d
166 166 Y 0:4e3505fd9583
167 167 Z 2:0d2164f0ce0d
168 168 foo -1:000000000000
169 169 * foobar 1:9b140be10808
170 170
171 171 (test that too many divergence of bookmark)
172 172
173 173 $ python $TESTDIR/seq.py 1 100 | while read i; do hg bookmarks -r 000000000000 "X@${i}"; done
174 174 $ hg pull ../a
175 175 pulling from ../a
176 176 searching for changes
177 177 no changes found
178 178 warning: failed to assign numbered name to divergent bookmark X
179 179 divergent bookmark @ stored as @1
180 180 $ hg bookmarks | grep '^ X' | grep -v ':000000000000'
181 181 X 1:9b140be10808
182 182 X@foo 2:0d2164f0ce0d
183 183
184 184 (test that remotely diverged bookmarks are reused if they aren't changed)
185 185
186 186 $ hg bookmarks | grep '^ @'
187 187 @ 1:9b140be10808
188 188 @1 2:0d2164f0ce0d
189 189 @foo 2:0d2164f0ce0d
190 190 $ hg pull ../a
191 191 pulling from ../a
192 192 searching for changes
193 193 no changes found
194 194 warning: failed to assign numbered name to divergent bookmark X
195 195 divergent bookmark @ stored as @1
196 196 $ hg bookmarks | grep '^ @'
197 197 @ 1:9b140be10808
198 198 @1 2:0d2164f0ce0d
199 199 @foo 2:0d2164f0ce0d
200 200
201 201 $ python $TESTDIR/seq.py 1 100 | while read i; do hg bookmarks -d "X@${i}"; done
202 202 $ hg bookmarks -d "@1"
203 203
204 204 $ hg push -f ../a
205 205 pushing to ../a
206 206 searching for changes
207 207 adding changesets
208 208 adding manifests
209 209 adding file changes
210 210 added 1 changesets with 1 changes to 1 files (+1 heads)
211 211 $ hg -R ../a book
212 212 @ 1:0d2164f0ce0d
213 213 * X 1:0d2164f0ce0d
214 214 Y 0:4e3505fd9583
215 215 Z 1:0d2164f0ce0d
216 216
217 217 explicit pull should overwrite the local version (issue4439)
218 218
219 219 $ hg pull --config paths.foo=../a foo -B X
220 220 pulling from $TESTTMP/a (glob)
221 221 no changes found
222 222 divergent bookmark @ stored as @foo
223 223 importing bookmark X
224 224
225 225 reinstall state for further testing:
226 226
227 227 $ hg book -fr 9b140be10808 X
228 228
229 229 revsets should not ignore divergent bookmarks
230 230
231 231 $ hg bookmark -fr 1 Z
232 232 $ hg log -r 'bookmark()' --template '{rev}:{node|short} {bookmarks}\n'
233 233 0:4e3505fd9583 Y
234 234 1:9b140be10808 @ X Z foobar
235 235 2:0d2164f0ce0d @foo X@foo
236 236 $ hg log -r 'bookmark("X@foo")' --template '{rev}:{node|short} {bookmarks}\n'
237 237 2:0d2164f0ce0d @foo X@foo
238 238 $ hg log -r 'bookmark("re:X@foo")' --template '{rev}:{node|short} {bookmarks}\n'
239 239 2:0d2164f0ce0d @foo X@foo
240 240
241 241 update a remote bookmark from a non-head to a head
242 242
243 243 $ hg up -q Y
244 244 $ echo c3 > f2
245 245 $ hg ci -Am3
246 246 adding f2
247 247 created new head
248 248 $ hg push ../a
249 249 pushing to ../a
250 250 searching for changes
251 251 adding changesets
252 252 adding manifests
253 253 adding file changes
254 254 added 1 changesets with 1 changes to 1 files (+1 heads)
255 255 updating bookmark Y
256 256 $ hg -R ../a book
257 257 @ 1:0d2164f0ce0d
258 258 * X 1:0d2164f0ce0d
259 259 Y 3:f6fc62dde3c0
260 260 Z 1:0d2164f0ce0d
261 261
262 262 update a bookmark in the middle of a client pulling changes
263 263
264 264 $ cd ..
265 265 $ hg clone -q a pull-race
266 266
267 267 We want to use http because it is stateless and therefore more susceptible to
268 268 race conditions
269 269
270 270 $ hg -R pull-race serve -p $HGPORT -d --pid-file=pull-race.pid -E main-error.log
271 271 $ cat pull-race.pid >> $DAEMON_PIDS
272 272
273 273 $ hg clone -q http://localhost:$HGPORT/ pull-race2
274 274 $ cd pull-race
275 275 $ hg up -q Y
276 276 $ echo c4 > f2
277 277 $ hg ci -Am4
278 278 $ echo c5 > f3
279 279 $ cat <<EOF > .hg/hgrc
280 280 > [hooks]
281 281 > outgoing.makecommit = hg ci -Am5; echo committed in pull-race
282 282 > EOF
283 283
284 284 (new config needs a server restart)
285 285
286 286 $ cd ..
287 287 $ killdaemons.py
288 288 $ hg -R pull-race serve -p $HGPORT -d --pid-file=pull-race.pid -E main-error.log
289 289 $ cat pull-race.pid >> $DAEMON_PIDS
290 290 $ cd pull-race2
291 291 $ hg -R $TESTTMP/pull-race book
292 292 @ 1:0d2164f0ce0d
293 293 X 1:0d2164f0ce0d
294 294 * Y 4:b0a5eff05604
295 295 Z 1:0d2164f0ce0d
296 296 $ hg pull
297 297 pulling from http://localhost:$HGPORT/
298 298 searching for changes
299 299 adding changesets
300 300 adding manifests
301 301 adding file changes
302 302 added 1 changesets with 1 changes to 1 files
303 303 updating bookmark Y
304 304 (run 'hg update' to get a working copy)
305 305 $ hg book
306 306 * @ 1:0d2164f0ce0d
307 307 X 1:0d2164f0ce0d
308 308 Y 4:b0a5eff05604
309 309 Z 1:0d2164f0ce0d
310 310
311 311 Update a bookmark right after the initial lookup -B (issue4689)
312 312
313 313 $ echo c6 > ../pull-race/f3 # to be committed during the race
314 314 $ cat <<EOF > ../pull-race/.hg/hgrc
315 315 > [hooks]
316 316 > # If anything to commit, commit it right after the first key listing used
317 317 > # during lookup. This makes the commit appear before the actual getbundle
318 318 > # call.
319 319 > listkeys.makecommit= ((hg st | grep -q M) && (hg commit -m race; echo commited in pull-race)) || exit 0
320 320 > EOF
321 321
322 322 (new config need server restart)
323 323
324 324 $ killdaemons.py
325 325 $ hg -R ../pull-race serve -p $HGPORT -d --pid-file=../pull-race.pid -E main-error.log
326 326 $ cat ../pull-race.pid >> $DAEMON_PIDS
327 327
328 328 $ hg -R $TESTTMP/pull-race book
329 329 @ 1:0d2164f0ce0d
330 330 X 1:0d2164f0ce0d
331 331 * Y 5:35d1ef0a8d1b
332 332 Z 1:0d2164f0ce0d
333 333 $ hg pull -B Y
334 334 pulling from http://localhost:$HGPORT/
335 335 searching for changes
336 336 adding changesets
337 337 adding manifests
338 338 adding file changes
339 339 added 1 changesets with 1 changes to 1 files
340 340 updating bookmark Y
341 341 (run 'hg update' to get a working copy)
342 342 $ hg book
343 343 * @ 1:0d2164f0ce0d
344 344 X 1:0d2164f0ce0d
345 345 Y 5:35d1ef0a8d1b
346 346 Z 1:0d2164f0ce0d
347 347
348 348 (done with this section of the test)
349 349
350 350 $ killdaemons.py
351 351 $ cd ../b
352 352
353 353 diverging a remote bookmark fails
354 354
355 355 $ hg up -q 4e3505fd9583
356 356 $ echo c4 > f2
357 357 $ hg ci -Am4
358 358 adding f2
359 359 created new head
360 360 $ echo c5 > f2
361 361 $ hg ci -Am5
362 362 $ hg log -G
363 363 @ 5:c922c0139ca0 5
364 364 |
365 365 o 4:4efff6d98829 4
366 366 |
367 367 | o 3:f6fc62dde3c0 3
368 368 |/
369 369 | o 2:0d2164f0ce0d 1
370 370 |/
371 371 | o 1:9b140be10808 2
372 372 |/
373 373 o 0:4e3505fd9583 test
374 374
375 375
376 376 $ hg book -f Y
377 377
378 378 $ cat <<EOF > ../a/.hg/hgrc
379 379 > [web]
380 380 > push_ssl = false
381 381 > allow_push = *
382 382 > EOF
383 383
384 384 $ hg -R ../a serve -p $HGPORT2 -d --pid-file=../hg2.pid
385 385 $ cat ../hg2.pid >> $DAEMON_PIDS
386 386
387 387 $ hg push http://localhost:$HGPORT2/
388 388 pushing to http://localhost:$HGPORT2/
389 389 searching for changes
390 390 abort: push creates new remote head c922c0139ca0 with bookmark 'Y'!
391 391 (merge or see "hg help push" for details about pushing new heads)
392 392 [255]
393 393 $ hg -R ../a book
394 394 @ 1:0d2164f0ce0d
395 395 * X 1:0d2164f0ce0d
396 396 Y 3:f6fc62dde3c0
397 397 Z 1:0d2164f0ce0d
398 398
399 399
400 400 Unrelated marker does not alter the decision
401 401
402 402 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
403 403 $ hg push http://localhost:$HGPORT2/
404 404 pushing to http://localhost:$HGPORT2/
405 405 searching for changes
406 406 abort: push creates new remote head c922c0139ca0 with bookmark 'Y'!
407 407 (merge or see "hg help push" for details about pushing new heads)
408 408 [255]
409 409 $ hg -R ../a book
410 410 @ 1:0d2164f0ce0d
411 411 * X 1:0d2164f0ce0d
412 412 Y 3:f6fc62dde3c0
413 413 Z 1:0d2164f0ce0d
414 414
415 415 Update to a successor works
416 416
417 417 $ hg id --debug -r 3
418 418 f6fc62dde3c0771e29704af56ba4d8af77abcc2f
419 419 $ hg id --debug -r 4
420 420 4efff6d98829d9c824c621afd6e3f01865f5439f
421 421 $ hg id --debug -r 5
422 422 c922c0139ca03858f655e4a2af4dd02796a63969 tip Y
423 423 $ hg debugobsolete f6fc62dde3c0771e29704af56ba4d8af77abcc2f cccccccccccccccccccccccccccccccccccccccc
424 424 $ hg debugobsolete cccccccccccccccccccccccccccccccccccccccc 4efff6d98829d9c824c621afd6e3f01865f5439f
425 425 $ hg push http://localhost:$HGPORT2/
426 426 pushing to http://localhost:$HGPORT2/
427 427 searching for changes
428 428 remote: adding changesets
429 429 remote: adding manifests
430 430 remote: adding file changes
431 431 remote: added 2 changesets with 2 changes to 1 files (+1 heads)
432 432 remote: 2 new obsolescence markers
433 433 updating bookmark Y
434 434 $ hg -R ../a book
435 435 @ 1:0d2164f0ce0d
436 436 * X 1:0d2164f0ce0d
437 437 Y 5:c922c0139ca0
438 438 Z 1:0d2164f0ce0d
439 439
440 440 hgweb
441 441
442 442 $ cat <<EOF > .hg/hgrc
443 443 > [web]
444 444 > push_ssl = false
445 445 > allow_push = *
446 446 > EOF
447 447
448 448 $ hg serve -p $HGPORT -d --pid-file=../hg.pid -E errors.log
449 449 $ cat ../hg.pid >> $DAEMON_PIDS
450 450 $ cd ../a
451 451
452 452 $ hg debugpushkey http://localhost:$HGPORT/ namespaces
453 453 bookmarks
454 454 namespaces
455 455 obsolete
456 456 phases
457 457 $ hg debugpushkey http://localhost:$HGPORT/ bookmarks
458 458 @ 9b140be1080824d768c5a4691a564088eede71f9
459 459 X 9b140be1080824d768c5a4691a564088eede71f9
460 460 Y c922c0139ca03858f655e4a2af4dd02796a63969
461 461 Z 9b140be1080824d768c5a4691a564088eede71f9
462 462 foo 0000000000000000000000000000000000000000
463 463 foobar 9b140be1080824d768c5a4691a564088eede71f9
464 464 $ hg out -B http://localhost:$HGPORT/
465 465 comparing with http://localhost:$HGPORT/
466 466 searching for changed bookmarks
467 467 @ 0d2164f0ce0d
468 468 X 0d2164f0ce0d
469 469 Z 0d2164f0ce0d
470 470 foo
471 471 foobar
472 472 $ hg push -B Z http://localhost:$HGPORT/
473 473 pushing to http://localhost:$HGPORT/
474 474 searching for changes
475 475 no changes found
476 476 updating bookmark Z
477 477 [1]
478 478 $ hg book -d Z
479 479 $ hg in -B http://localhost:$HGPORT/
480 480 comparing with http://localhost:$HGPORT/
481 481 searching for changed bookmarks
482 482 @ 9b140be10808
483 483 X 9b140be10808
484 484 Z 0d2164f0ce0d
485 485 foo 000000000000
486 486 foobar 9b140be10808
487 487 $ hg pull -B Z http://localhost:$HGPORT/
488 488 pulling from http://localhost:$HGPORT/
489 489 no changes found
490 490 divergent bookmark @ stored as @1
491 491 divergent bookmark X stored as X@1
492 492 adding remote bookmark Z
493 493 adding remote bookmark foo
494 494 adding remote bookmark foobar
495 495 $ hg clone http://localhost:$HGPORT/ cloned-bookmarks
496 496 requesting all changes
497 497 adding changesets
498 498 adding manifests
499 499 adding file changes
500 500 added 5 changesets with 5 changes to 3 files (+2 heads)
501 501 2 new obsolescence markers
502 502 updating to bookmark @
503 503 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
504 504 $ hg -R cloned-bookmarks bookmarks
505 505 * @ 1:9b140be10808
506 506 X 1:9b140be10808
507 507 Y 4:c922c0139ca0
508 508 Z 2:0d2164f0ce0d
509 509 foo -1:000000000000
510 510 foobar 1:9b140be10808
511 511
512 512 $ cd ..
513 513
514 514 Test to show result of bookmarks comparision
515 515
516 516 $ mkdir bmcomparison
517 517 $ cd bmcomparison
518 518
519 519 $ hg init source
520 520 $ hg -R source debugbuilddag '+2*2*3*4'
521 521 $ hg -R source log -G --template '{rev}:{node|short}'
522 522 o 4:e7bd5218ca15
523 523 |
524 524 | o 3:6100d3090acf
525 525 |/
526 526 | o 2:fa942426a6fd
527 527 |/
528 528 | o 1:66f7d451a68b
529 529 |/
530 530 o 0:1ea73414a91b
531 531
532 532 $ hg -R source bookmarks -r 0 SAME
533 533 $ hg -R source bookmarks -r 0 ADV_ON_REPO1
534 534 $ hg -R source bookmarks -r 0 ADV_ON_REPO2
535 535 $ hg -R source bookmarks -r 0 DIFF_ADV_ON_REPO1
536 536 $ hg -R source bookmarks -r 0 DIFF_ADV_ON_REPO2
537 537 $ hg -R source bookmarks -r 1 DIVERGED
538 538
539 539 $ hg clone -U source repo1
540 540
541 541 (test that incoming/outgoing exit with 1, if there is no bookmark to
542 542 be exchanged)
543 543
544 544 $ hg -R repo1 incoming -B
545 545 comparing with $TESTTMP/bmcomparison/source
546 546 searching for changed bookmarks
547 547 no changed bookmarks found
548 548 [1]
549 549 $ hg -R repo1 outgoing -B
550 550 comparing with $TESTTMP/bmcomparison/source
551 551 searching for changed bookmarks
552 552 no changed bookmarks found
553 553 [1]
554 554
555 555 $ hg -R repo1 bookmarks -f -r 1 ADD_ON_REPO1
556 556 $ hg -R repo1 bookmarks -f -r 2 ADV_ON_REPO1
557 557 $ hg -R repo1 bookmarks -f -r 3 DIFF_ADV_ON_REPO1
558 558 $ hg -R repo1 bookmarks -f -r 3 DIFF_DIVERGED
559 559 $ hg -R repo1 -q --config extensions.mq= strip 4
560 560 $ hg -R repo1 log -G --template '{node|short} ({bookmarks})'
561 561 o 6100d3090acf (DIFF_ADV_ON_REPO1 DIFF_DIVERGED)
562 562 |
563 563 | o fa942426a6fd (ADV_ON_REPO1)
564 564 |/
565 565 | o 66f7d451a68b (ADD_ON_REPO1 DIVERGED)
566 566 |/
567 567 o 1ea73414a91b (ADV_ON_REPO2 DIFF_ADV_ON_REPO2 SAME)
568 568
569 569
570 570 $ hg clone -U source repo2
571 571 $ hg -R repo2 bookmarks -f -r 1 ADD_ON_REPO2
572 572 $ hg -R repo2 bookmarks -f -r 1 ADV_ON_REPO2
573 573 $ hg -R repo2 bookmarks -f -r 2 DIVERGED
574 574 $ hg -R repo2 bookmarks -f -r 4 DIFF_ADV_ON_REPO2
575 575 $ hg -R repo2 bookmarks -f -r 4 DIFF_DIVERGED
576 576 $ hg -R repo2 -q --config extensions.mq= strip 3
577 577 $ hg -R repo2 log -G --template '{node|short} ({bookmarks})'
578 578 o e7bd5218ca15 (DIFF_ADV_ON_REPO2 DIFF_DIVERGED)
579 579 |
580 580 | o fa942426a6fd (DIVERGED)
581 581 |/
582 582 | o 66f7d451a68b (ADD_ON_REPO2 ADV_ON_REPO2)
583 583 |/
584 584 o 1ea73414a91b (ADV_ON_REPO1 DIFF_ADV_ON_REPO1 SAME)
585 585
586 586
587 587 (test that difference of bookmarks between repositories are fully shown)
588 588
589 589 $ hg -R repo1 incoming -B repo2 -v
590 590 comparing with repo2
591 591 searching for changed bookmarks
592 592 ADD_ON_REPO2 66f7d451a68b added
593 593 ADV_ON_REPO2 66f7d451a68b advanced
594 594 DIFF_ADV_ON_REPO2 e7bd5218ca15 changed
595 595 DIFF_DIVERGED e7bd5218ca15 changed
596 596 DIVERGED fa942426a6fd diverged
597 597 $ hg -R repo1 outgoing -B repo2 -v
598 598 comparing with repo2
599 599 searching for changed bookmarks
600 600 ADD_ON_REPO1 66f7d451a68b added
601 601 ADD_ON_REPO2 deleted
602 602 ADV_ON_REPO1 fa942426a6fd advanced
603 603 DIFF_ADV_ON_REPO1 6100d3090acf advanced
604 604 DIFF_ADV_ON_REPO2 1ea73414a91b changed
605 605 DIFF_DIVERGED 6100d3090acf changed
606 606 DIVERGED 66f7d451a68b diverged
607 607
608 608 $ hg -R repo2 incoming -B repo1 -v
609 609 comparing with repo1
610 610 searching for changed bookmarks
611 611 ADD_ON_REPO1 66f7d451a68b added
612 612 ADV_ON_REPO1 fa942426a6fd advanced
613 613 DIFF_ADV_ON_REPO1 6100d3090acf changed
614 614 DIFF_DIVERGED 6100d3090acf changed
615 615 DIVERGED 66f7d451a68b diverged
616 616 $ hg -R repo2 outgoing -B repo1 -v
617 617 comparing with repo1
618 618 searching for changed bookmarks
619 619 ADD_ON_REPO1 deleted
620 620 ADD_ON_REPO2 66f7d451a68b added
621 621 ADV_ON_REPO2 66f7d451a68b advanced
622 622 DIFF_ADV_ON_REPO1 1ea73414a91b changed
623 623 DIFF_ADV_ON_REPO2 e7bd5218ca15 advanced
624 624 DIFF_DIVERGED e7bd5218ca15 changed
625 625 DIVERGED fa942426a6fd diverged
626 626
627 627 $ cd ..
628 628
629 629 Pushing a bookmark should only push the changes required by that
630 630 bookmark, not all outgoing changes:
631 631 $ hg clone http://localhost:$HGPORT/ addmarks
632 632 requesting all changes
633 633 adding changesets
634 634 adding manifests
635 635 adding file changes
636 636 added 5 changesets with 5 changes to 3 files (+2 heads)
637 637 2 new obsolescence markers
638 638 updating to bookmark @
639 639 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
640 640 $ cd addmarks
641 641 $ echo foo > foo
642 642 $ hg add foo
643 643 $ hg commit -m 'add foo'
644 644 $ echo bar > bar
645 645 $ hg add bar
646 646 $ hg commit -m 'add bar'
647 647 $ hg co "tip^"
648 648 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
649 649 (leaving bookmark @)
650 650 $ hg book add-foo
651 651 $ hg book -r tip add-bar
652 652 Note: this push *must* push only a single changeset, as that's the point
653 653 of this test.
654 654 $ hg push -B add-foo --traceback
655 655 pushing to http://localhost:$HGPORT/
656 656 searching for changes
657 657 remote: adding changesets
658 658 remote: adding manifests
659 659 remote: adding file changes
660 660 remote: added 1 changesets with 1 changes to 1 files
661 661 exporting bookmark add-foo
662 662
663 663 pushing a new bookmark on a new head does not require -f if -B is specified
664 664
665 665 $ hg up -q X
666 666 $ hg book W
667 667 $ echo c5 > f2
668 668 $ hg ci -Am5
669 669 created new head
670 670 $ hg push -B W
671 671 pushing to http://localhost:$HGPORT/
672 672 searching for changes
673 673 remote: adding changesets
674 674 remote: adding manifests
675 675 remote: adding file changes
676 676 remote: added 1 changesets with 1 changes to 1 files (+1 heads)
677 677 exporting bookmark W
678 678 $ hg -R ../b id -r W
679 679 cc978a373a53 tip W
680 680
681 pushing an existing but divergent bookmark with -B still requires -f
682
683 $ hg clone -q . r
684 $ hg up -q X
685 $ echo 1 > f2
686 $ hg ci -qAml
687
688 $ cd r
689 $ hg up -q X
690 $ echo 2 > f2
691 $ hg ci -qAmr
692 $ hg push -B X
693 pushing to $TESTTMP/addmarks (glob)
694 searching for changes
695 remote has heads on branch 'default' that are not known locally: a2a606d9ff1b
696 abort: push creates new remote head 54694f811df9 with bookmark 'X'!
697 (pull and merge or see "hg help push" for details about pushing new heads)
698 [255]
699 $ cd ..
700
681 701 Check summary output for incoming/outgoing bookmarks
682 702
683 703 $ hg bookmarks -d X
684 704 $ hg bookmarks -d Y
685 705 $ hg summary --remote | grep '^remote:'
686 706 remote: *, 2 incoming bookmarks, 1 outgoing bookmarks (glob)
687 707
688 708 $ cd ..
689 709
690 710 pushing an unchanged bookmark should result in no changes
691 711
692 712 $ hg init unchanged-a
693 713 $ hg init unchanged-b
694 714 $ cd unchanged-a
695 715 $ echo initial > foo
696 716 $ hg commit -A -m initial
697 717 adding foo
698 718 $ hg bookmark @
699 719 $ hg push -B @ ../unchanged-b
700 720 pushing to ../unchanged-b
701 721 searching for changes
702 722 adding changesets
703 723 adding manifests
704 724 adding file changes
705 725 added 1 changesets with 1 changes to 1 files
706 726 exporting bookmark @
707 727
708 728 $ hg push -B @ ../unchanged-b
709 729 pushing to ../unchanged-b
710 730 searching for changes
711 731 no changes found
712 732 [1]
713 733
714 734
715 735 Check hook preventing push (issue4455)
716 736 ======================================
717 737
718 738 $ hg bookmarks
719 739 * @ 0:55482a6fb4b1
720 740 $ hg log -G
721 741 @ 0:55482a6fb4b1 initial
722 742
723 743 $ hg init ../issue4455-dest
724 744 $ hg push ../issue4455-dest # changesets only
725 745 pushing to ../issue4455-dest
726 746 searching for changes
727 747 adding changesets
728 748 adding manifests
729 749 adding file changes
730 750 added 1 changesets with 1 changes to 1 files
731 751 $ cat >> .hg/hgrc << EOF
732 752 > [paths]
733 753 > local=../issue4455-dest/
734 754 > ssh=ssh://user@dummy/issue4455-dest
735 755 > http=http://localhost:$HGPORT/
736 756 > [ui]
737 757 > ssh=python "$TESTDIR/dummyssh"
738 758 > EOF
739 759 $ cat >> ../issue4455-dest/.hg/hgrc << EOF
740 760 > [hooks]
741 761 > prepushkey=false
742 762 > [web]
743 763 > push_ssl = false
744 764 > allow_push = *
745 765 > EOF
746 766 $ killdaemons.py
747 767 $ hg -R ../issue4455-dest serve -p $HGPORT -d --pid-file=../issue4455.pid -E ../issue4455-error.log
748 768 $ cat ../issue4455.pid >> $DAEMON_PIDS
749 769
750 770 Local push
751 771 ----------
752 772
753 773 $ hg push -B @ local
754 774 pushing to $TESTTMP/issue4455-dest (glob)
755 775 searching for changes
756 776 no changes found
757 777 pushkey-abort: prepushkey hook exited with status 1
758 778 abort: exporting bookmark @ failed!
759 779 [255]
760 780 $ hg -R ../issue4455-dest/ bookmarks
761 781 no bookmarks set
762 782
763 783 Using ssh
764 784 ---------
765 785
766 786 $ hg push -B @ ssh --config experimental.bundle2-exp=True
767 787 pushing to ssh://user@dummy/issue4455-dest
768 788 searching for changes
769 789 no changes found
770 790 remote: pushkey-abort: prepushkey hook exited with status 1
771 791 abort: exporting bookmark @ failed!
772 792 [255]
773 793 $ hg -R ../issue4455-dest/ bookmarks
774 794 no bookmarks set
775 795
776 796 $ hg push -B @ ssh --config experimental.bundle2-exp=False
777 797 pushing to ssh://user@dummy/issue4455-dest
778 798 searching for changes
779 799 no changes found
780 800 remote: pushkey-abort: prepushkey hook exited with status 1
781 801 exporting bookmark @ failed!
782 802 [1]
783 803 $ hg -R ../issue4455-dest/ bookmarks
784 804 no bookmarks set
785 805
786 806 Using http
787 807 ----------
788 808
789 809 $ hg push -B @ http --config experimental.bundle2-exp=True
790 810 pushing to http://localhost:$HGPORT/
791 811 searching for changes
792 812 no changes found
793 813 remote: pushkey-abort: prepushkey hook exited with status 1
794 814 abort: exporting bookmark @ failed!
795 815 [255]
796 816 $ hg -R ../issue4455-dest/ bookmarks
797 817 no bookmarks set
798 818
799 819 $ hg push -B @ http --config experimental.bundle2-exp=False
800 820 pushing to http://localhost:$HGPORT/
801 821 searching for changes
802 822 no changes found
803 823 remote: pushkey-abort: prepushkey hook exited with status 1
804 824 exporting bookmark @ failed!
805 825 [1]
806 826 $ hg -R ../issue4455-dest/ bookmarks
807 827 no bookmarks set
General Comments 0
You need to be logged in to leave comments. Login now