##// END OF EJS Templates
bookmarks: adjust exception type so present(bookmark(.)) works as expected
Yuya Nishihara -
r39340:fc54a290 default
parent child Browse files
Show More
@@ -1,968 +1,968 b''
1 1 # Mercurial bookmark support code
2 2 #
3 3 # Copyright 2008 David Soria Parra <dsp@php.net>
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 import errno
11 11 import struct
12 12
13 13 from .i18n import _
14 14 from .node import (
15 15 bin,
16 16 hex,
17 17 short,
18 18 wdirid,
19 19 )
20 20 from . import (
21 21 encoding,
22 22 error,
23 23 obsutil,
24 24 pycompat,
25 25 scmutil,
26 26 txnutil,
27 27 util,
28 28 )
29 29
30 30 # label constants
31 31 # until 3.5, bookmarks.current was the advertised name, not
32 32 # bookmarks.active, so we must use both to avoid breaking old
33 33 # custom styles
34 34 activebookmarklabel = 'bookmarks.active bookmarks.current'
35 35
36 36 def _getbkfile(repo):
37 37 """Hook so that extensions that mess with the store can hook bm storage.
38 38
39 39 For core, this just handles wether we should see pending
40 40 bookmarks or the committed ones. Other extensions (like share)
41 41 may need to tweak this behavior further.
42 42 """
43 43 fp, pending = txnutil.trypending(repo.root, repo.vfs, 'bookmarks')
44 44 return fp
45 45
46 46 class bmstore(object):
47 47 """Storage for bookmarks.
48 48
49 49 This object should do all bookmark-related reads and writes, so
50 50 that it's fairly simple to replace the storage underlying
51 51 bookmarks without having to clone the logic surrounding
52 52 bookmarks. This type also should manage the active bookmark, if
53 53 any.
54 54
55 55 This particular bmstore implementation stores bookmarks as
56 56 {hash}\s{name}\n (the same format as localtags) in
57 57 .hg/bookmarks. The mapping is stored as {name: nodeid}.
58 58 """
59 59
60 60 def __init__(self, repo):
61 61 self._repo = repo
62 62 self._refmap = refmap = {} # refspec: node
63 63 self._nodemap = nodemap = {} # node: sorted([refspec, ...])
64 64 self._clean = True
65 65 self._aclean = True
66 66 nm = repo.changelog.nodemap
67 67 tonode = bin # force local lookup
68 68 try:
69 69 with _getbkfile(repo) as bkfile:
70 70 for line in bkfile:
71 71 line = line.strip()
72 72 if not line:
73 73 continue
74 74 try:
75 75 sha, refspec = line.split(' ', 1)
76 76 node = tonode(sha)
77 77 if node in nm:
78 78 refspec = encoding.tolocal(refspec)
79 79 refmap[refspec] = node
80 80 nrefs = nodemap.get(node)
81 81 if nrefs is None:
82 82 nodemap[node] = [refspec]
83 83 else:
84 84 nrefs.append(refspec)
85 85 if nrefs[-2] > refspec:
86 86 # bookmarks weren't sorted before 4.5
87 87 nrefs.sort()
88 88 except (TypeError, ValueError):
89 89 # TypeError:
90 90 # - bin(...)
91 91 # ValueError:
92 92 # - node in nm, for non-20-bytes entry
93 93 # - split(...), for string without ' '
94 94 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
95 95 % pycompat.bytestr(line))
96 96 except IOError as inst:
97 97 if inst.errno != errno.ENOENT:
98 98 raise
99 99 self._active = _readactive(repo, self)
100 100
101 101 @property
102 102 def active(self):
103 103 return self._active
104 104
105 105 @active.setter
106 106 def active(self, mark):
107 107 if mark is not None and mark not in self._refmap:
108 108 raise AssertionError('bookmark %s does not exist!' % mark)
109 109
110 110 self._active = mark
111 111 self._aclean = False
112 112
113 113 def __len__(self):
114 114 return len(self._refmap)
115 115
116 116 def __iter__(self):
117 117 return iter(self._refmap)
118 118
119 119 def iteritems(self):
120 120 return self._refmap.iteritems()
121 121
122 122 def items(self):
123 123 return self._refmap.items()
124 124
125 125 # TODO: maybe rename to allnames()?
126 126 def keys(self):
127 127 return self._refmap.keys()
128 128
129 129 # TODO: maybe rename to allnodes()? but nodes would have to be deduplicated
130 130 # could be self._nodemap.keys()
131 131 def values(self):
132 132 return self._refmap.values()
133 133
134 134 def __contains__(self, mark):
135 135 return mark in self._refmap
136 136
137 137 def __getitem__(self, mark):
138 138 return self._refmap[mark]
139 139
140 140 def get(self, mark, default=None):
141 141 return self._refmap.get(mark, default)
142 142
143 143 def _set(self, mark, node):
144 144 self._clean = False
145 145 if mark in self._refmap:
146 146 self._del(mark)
147 147 self._refmap[mark] = node
148 148 nrefs = self._nodemap.get(node)
149 149 if nrefs is None:
150 150 self._nodemap[node] = [mark]
151 151 else:
152 152 nrefs.append(mark)
153 153 nrefs.sort()
154 154
155 155 def _del(self, mark):
156 156 self._clean = False
157 157 node = self._refmap.pop(mark)
158 158 nrefs = self._nodemap[node]
159 159 if len(nrefs) == 1:
160 160 assert nrefs[0] == mark
161 161 del self._nodemap[node]
162 162 else:
163 163 nrefs.remove(mark)
164 164
165 165 def names(self, node):
166 166 """Return a sorted list of bookmarks pointing to the specified node"""
167 167 return self._nodemap.get(node, [])
168 168
169 169 def changectx(self, mark):
170 170 node = self._refmap[mark]
171 171 return self._repo[node]
172 172
173 173 def applychanges(self, repo, tr, changes):
174 174 """Apply a list of changes to bookmarks
175 175 """
176 176 bmchanges = tr.changes.get('bookmarks')
177 177 for name, node in changes:
178 178 old = self._refmap.get(name)
179 179 if node is None:
180 180 self._del(name)
181 181 else:
182 182 self._set(name, node)
183 183 if bmchanges is not None:
184 184 # if a previous value exist preserve the "initial" value
185 185 previous = bmchanges.get(name)
186 186 if previous is not None:
187 187 old = previous[0]
188 188 bmchanges[name] = (old, node)
189 189 self._recordchange(tr)
190 190
191 191 def _recordchange(self, tr):
192 192 """record that bookmarks have been changed in a transaction
193 193
194 194 The transaction is then responsible for updating the file content."""
195 195 tr.addfilegenerator('bookmarks', ('bookmarks',), self._write,
196 196 location='plain')
197 197 tr.hookargs['bookmark_moved'] = '1'
198 198
199 199 def _writerepo(self, repo):
200 200 """Factored out for extensibility"""
201 201 rbm = repo._bookmarks
202 202 if rbm.active not in self._refmap:
203 203 rbm.active = None
204 204 rbm._writeactive()
205 205
206 206 with repo.wlock():
207 207 file_ = repo.vfs('bookmarks', 'w', atomictemp=True,
208 208 checkambig=True)
209 209 try:
210 210 self._write(file_)
211 211 except: # re-raises
212 212 file_.discard()
213 213 raise
214 214 finally:
215 215 file_.close()
216 216
217 217 def _writeactive(self):
218 218 if self._aclean:
219 219 return
220 220 with self._repo.wlock():
221 221 if self._active is not None:
222 222 f = self._repo.vfs('bookmarks.current', 'w', atomictemp=True,
223 223 checkambig=True)
224 224 try:
225 225 f.write(encoding.fromlocal(self._active))
226 226 finally:
227 227 f.close()
228 228 else:
229 229 self._repo.vfs.tryunlink('bookmarks.current')
230 230 self._aclean = True
231 231
232 232 def _write(self, fp):
233 233 for name, node in sorted(self._refmap.iteritems()):
234 234 fp.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
235 235 self._clean = True
236 236 self._repo.invalidatevolatilesets()
237 237
238 238 def expandname(self, bname):
239 239 if bname == '.':
240 240 if self.active:
241 241 return self.active
242 242 else:
243 raise error.Abort(_("no active bookmark"))
243 raise error.RepoLookupError(_("no active bookmark"))
244 244 return bname
245 245
246 246 def checkconflict(self, mark, force=False, target=None):
247 247 """check repo for a potential clash of mark with an existing bookmark,
248 248 branch, or hash
249 249
250 250 If target is supplied, then check that we are moving the bookmark
251 251 forward.
252 252
253 253 If force is supplied, then forcibly move the bookmark to a new commit
254 254 regardless if it is a move forward.
255 255
256 256 If divergent bookmark are to be deleted, they will be returned as list.
257 257 """
258 258 cur = self._repo['.'].node()
259 259 if mark in self._refmap and not force:
260 260 if target:
261 261 if self._refmap[mark] == target and target == cur:
262 262 # re-activating a bookmark
263 263 return []
264 264 rev = self._repo[target].rev()
265 265 anc = self._repo.changelog.ancestors([rev])
266 266 bmctx = self.changectx(mark)
267 267 divs = [self._refmap[b] for b in self._refmap
268 268 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
269 269
270 270 # allow resolving a single divergent bookmark even if moving
271 271 # the bookmark across branches when a revision is specified
272 272 # that contains a divergent bookmark
273 273 if bmctx.rev() not in anc and target in divs:
274 274 return divergent2delete(self._repo, [target], mark)
275 275
276 276 deletefrom = [b for b in divs
277 277 if self._repo[b].rev() in anc or b == target]
278 278 delbms = divergent2delete(self._repo, deletefrom, mark)
279 279 if validdest(self._repo, bmctx, self._repo[target]):
280 280 self._repo.ui.status(
281 281 _("moving bookmark '%s' forward from %s\n") %
282 282 (mark, short(bmctx.node())))
283 283 return delbms
284 284 raise error.Abort(_("bookmark '%s' already exists "
285 285 "(use -f to force)") % mark)
286 286 if ((mark in self._repo.branchmap() or
287 287 mark == self._repo.dirstate.branch()) and not force):
288 288 raise error.Abort(
289 289 _("a bookmark cannot have the name of an existing branch"))
290 290 if len(mark) > 3 and not force:
291 291 try:
292 292 shadowhash = scmutil.isrevsymbol(self._repo, mark)
293 293 except error.LookupError: # ambiguous identifier
294 294 shadowhash = False
295 295 if shadowhash:
296 296 self._repo.ui.warn(
297 297 _("bookmark %s matches a changeset hash\n"
298 298 "(did you leave a -r out of an 'hg bookmark' "
299 299 "command?)\n")
300 300 % mark)
301 301 return []
302 302
303 303 def _readactive(repo, marks):
304 304 """
305 305 Get the active bookmark. We can have an active bookmark that updates
306 306 itself as we commit. This function returns the name of that bookmark.
307 307 It is stored in .hg/bookmarks.current
308 308 """
309 309 mark = None
310 310 try:
311 311 file = repo.vfs('bookmarks.current')
312 312 except IOError as inst:
313 313 if inst.errno != errno.ENOENT:
314 314 raise
315 315 return None
316 316 try:
317 317 # No readline() in osutil.posixfile, reading everything is
318 318 # cheap.
319 319 # Note that it's possible for readlines() here to raise
320 320 # IOError, since we might be reading the active mark over
321 321 # static-http which only tries to load the file when we try
322 322 # to read from it.
323 323 mark = encoding.tolocal((file.readlines() or [''])[0])
324 324 if mark == '' or mark not in marks:
325 325 mark = None
326 326 except IOError as inst:
327 327 if inst.errno != errno.ENOENT:
328 328 raise
329 329 return None
330 330 finally:
331 331 file.close()
332 332 return mark
333 333
334 334 def activate(repo, mark):
335 335 """
336 336 Set the given bookmark to be 'active', meaning that this bookmark will
337 337 follow new commits that are made.
338 338 The name is recorded in .hg/bookmarks.current
339 339 """
340 340 repo._bookmarks.active = mark
341 341 repo._bookmarks._writeactive()
342 342
343 343 def deactivate(repo):
344 344 """
345 345 Unset the active bookmark in this repository.
346 346 """
347 347 repo._bookmarks.active = None
348 348 repo._bookmarks._writeactive()
349 349
350 350 def isactivewdirparent(repo):
351 351 """
352 352 Tell whether the 'active' bookmark (the one that follows new commits)
353 353 points to one of the parents of the current working directory (wdir).
354 354
355 355 While this is normally the case, it can on occasion be false; for example,
356 356 immediately after a pull, the active bookmark can be moved to point
357 357 to a place different than the wdir. This is solved by running `hg update`.
358 358 """
359 359 mark = repo._activebookmark
360 360 marks = repo._bookmarks
361 361 parents = [p.node() for p in repo[None].parents()]
362 362 return (mark in marks and marks[mark] in parents)
363 363
364 364 def divergent2delete(repo, deletefrom, bm):
365 365 """find divergent versions of bm on nodes in deletefrom.
366 366
367 367 the list of bookmark to delete."""
368 368 todelete = []
369 369 marks = repo._bookmarks
370 370 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
371 371 for mark in divergent:
372 372 if mark == '@' or '@' not in mark:
373 373 # can't be divergent by definition
374 374 continue
375 375 if mark and marks[mark] in deletefrom:
376 376 if mark != bm:
377 377 todelete.append(mark)
378 378 return todelete
379 379
380 380 def headsforactive(repo):
381 381 """Given a repo with an active bookmark, return divergent bookmark nodes.
382 382
383 383 Args:
384 384 repo: A repository with an active bookmark.
385 385
386 386 Returns:
387 387 A list of binary node ids that is the full list of other
388 388 revisions with bookmarks divergent from the active bookmark. If
389 389 there were no divergent bookmarks, then this list will contain
390 390 only one entry.
391 391 """
392 392 if not repo._activebookmark:
393 393 raise ValueError(
394 394 'headsforactive() only makes sense with an active bookmark')
395 395 name = repo._activebookmark.split('@', 1)[0]
396 396 heads = []
397 397 for mark, n in repo._bookmarks.iteritems():
398 398 if mark.split('@', 1)[0] == name:
399 399 heads.append(n)
400 400 return heads
401 401
402 402 def calculateupdate(ui, repo):
403 403 '''Return a tuple (activemark, movemarkfrom) indicating the active bookmark
404 404 and where to move the active bookmark from, if needed.'''
405 405 checkout, movemarkfrom = None, None
406 406 activemark = repo._activebookmark
407 407 if isactivewdirparent(repo):
408 408 movemarkfrom = repo['.'].node()
409 409 elif activemark:
410 410 ui.status(_("updating to active bookmark %s\n") % activemark)
411 411 checkout = activemark
412 412 return (checkout, movemarkfrom)
413 413
414 414 def update(repo, parents, node):
415 415 deletefrom = parents
416 416 marks = repo._bookmarks
417 417 active = marks.active
418 418 if not active:
419 419 return False
420 420
421 421 bmchanges = []
422 422 if marks[active] in parents:
423 423 new = repo[node]
424 424 divs = [marks.changectx(b) for b in marks
425 425 if b.split('@', 1)[0] == active.split('@', 1)[0]]
426 426 anc = repo.changelog.ancestors([new.rev()])
427 427 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
428 428 if validdest(repo, marks.changectx(active), new):
429 429 bmchanges.append((active, new.node()))
430 430
431 431 for bm in divergent2delete(repo, deletefrom, active):
432 432 bmchanges.append((bm, None))
433 433
434 434 if bmchanges:
435 435 with repo.lock(), repo.transaction('bookmark') as tr:
436 436 marks.applychanges(repo, tr, bmchanges)
437 437 return bool(bmchanges)
438 438
439 439 def listbinbookmarks(repo):
440 440 # We may try to list bookmarks on a repo type that does not
441 441 # support it (e.g., statichttprepository).
442 442 marks = getattr(repo, '_bookmarks', {})
443 443
444 444 hasnode = repo.changelog.hasnode
445 445 for k, v in marks.iteritems():
446 446 # don't expose local divergent bookmarks
447 447 if hasnode(v) and ('@' not in k or k.endswith('@')):
448 448 yield k, v
449 449
450 450 def listbookmarks(repo):
451 451 d = {}
452 452 for book, node in listbinbookmarks(repo):
453 453 d[book] = hex(node)
454 454 return d
455 455
456 456 def pushbookmark(repo, key, old, new):
457 457 with repo.wlock(), repo.lock(), repo.transaction('bookmarks') as tr:
458 458 marks = repo._bookmarks
459 459 existing = hex(marks.get(key, ''))
460 460 if existing != old and existing != new:
461 461 return False
462 462 if new == '':
463 463 changes = [(key, None)]
464 464 else:
465 465 if new not in repo:
466 466 return False
467 467 changes = [(key, repo[new].node())]
468 468 marks.applychanges(repo, tr, changes)
469 469 return True
470 470
471 471 def comparebookmarks(repo, srcmarks, dstmarks, targets=None):
472 472 '''Compare bookmarks between srcmarks and dstmarks
473 473
474 474 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
475 475 differ, invalid)", each are list of bookmarks below:
476 476
477 477 :addsrc: added on src side (removed on dst side, perhaps)
478 478 :adddst: added on dst side (removed on src side, perhaps)
479 479 :advsrc: advanced on src side
480 480 :advdst: advanced on dst side
481 481 :diverge: diverge
482 482 :differ: changed, but changeset referred on src is unknown on dst
483 483 :invalid: unknown on both side
484 484 :same: same on both side
485 485
486 486 Each elements of lists in result tuple is tuple "(bookmark name,
487 487 changeset ID on source side, changeset ID on destination
488 488 side)". Each changeset IDs are 40 hexadecimal digit string or
489 489 None.
490 490
491 491 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
492 492 "invalid" list may be unknown for repo.
493 493
494 494 If "targets" is specified, only bookmarks listed in it are
495 495 examined.
496 496 '''
497 497
498 498 if targets:
499 499 bset = set(targets)
500 500 else:
501 501 srcmarkset = set(srcmarks)
502 502 dstmarkset = set(dstmarks)
503 503 bset = srcmarkset | dstmarkset
504 504
505 505 results = ([], [], [], [], [], [], [], [])
506 506 addsrc = results[0].append
507 507 adddst = results[1].append
508 508 advsrc = results[2].append
509 509 advdst = results[3].append
510 510 diverge = results[4].append
511 511 differ = results[5].append
512 512 invalid = results[6].append
513 513 same = results[7].append
514 514
515 515 for b in sorted(bset):
516 516 if b not in srcmarks:
517 517 if b in dstmarks:
518 518 adddst((b, None, dstmarks[b]))
519 519 else:
520 520 invalid((b, None, None))
521 521 elif b not in dstmarks:
522 522 addsrc((b, srcmarks[b], None))
523 523 else:
524 524 scid = srcmarks[b]
525 525 dcid = dstmarks[b]
526 526 if scid == dcid:
527 527 same((b, scid, dcid))
528 528 elif scid in repo and dcid in repo:
529 529 sctx = repo[scid]
530 530 dctx = repo[dcid]
531 531 if sctx.rev() < dctx.rev():
532 532 if validdest(repo, sctx, dctx):
533 533 advdst((b, scid, dcid))
534 534 else:
535 535 diverge((b, scid, dcid))
536 536 else:
537 537 if validdest(repo, dctx, sctx):
538 538 advsrc((b, scid, dcid))
539 539 else:
540 540 diverge((b, scid, dcid))
541 541 else:
542 542 # it is too expensive to examine in detail, in this case
543 543 differ((b, scid, dcid))
544 544
545 545 return results
546 546
547 547 def _diverge(ui, b, path, localmarks, remotenode):
548 548 '''Return appropriate diverged bookmark for specified ``path``
549 549
550 550 This returns None, if it is failed to assign any divergent
551 551 bookmark name.
552 552
553 553 This reuses already existing one with "@number" suffix, if it
554 554 refers ``remotenode``.
555 555 '''
556 556 if b == '@':
557 557 b = ''
558 558 # try to use an @pathalias suffix
559 559 # if an @pathalias already exists, we overwrite (update) it
560 560 if path.startswith("file:"):
561 561 path = util.url(path).path
562 562 for p, u in ui.configitems("paths"):
563 563 if u.startswith("file:"):
564 564 u = util.url(u).path
565 565 if path == u:
566 566 return '%s@%s' % (b, p)
567 567
568 568 # assign a unique "@number" suffix newly
569 569 for x in range(1, 100):
570 570 n = '%s@%d' % (b, x)
571 571 if n not in localmarks or localmarks[n] == remotenode:
572 572 return n
573 573
574 574 return None
575 575
576 576 def unhexlifybookmarks(marks):
577 577 binremotemarks = {}
578 578 for name, node in marks.items():
579 579 binremotemarks[name] = bin(node)
580 580 return binremotemarks
581 581
582 582 _binaryentry = struct.Struct('>20sH')
583 583
584 584 def binaryencode(bookmarks):
585 585 """encode a '(bookmark, node)' iterable into a binary stream
586 586
587 587 the binary format is:
588 588
589 589 <node><bookmark-length><bookmark-name>
590 590
591 591 :node: is a 20 bytes binary node,
592 592 :bookmark-length: an unsigned short,
593 593 :bookmark-name: the name of the bookmark (of length <bookmark-length>)
594 594
595 595 wdirid (all bits set) will be used as a special value for "missing"
596 596 """
597 597 binarydata = []
598 598 for book, node in bookmarks:
599 599 if not node: # None or ''
600 600 node = wdirid
601 601 binarydata.append(_binaryentry.pack(node, len(book)))
602 602 binarydata.append(book)
603 603 return ''.join(binarydata)
604 604
605 605 def binarydecode(stream):
606 606 """decode a binary stream into an '(bookmark, node)' iterable
607 607
608 608 the binary format is:
609 609
610 610 <node><bookmark-length><bookmark-name>
611 611
612 612 :node: is a 20 bytes binary node,
613 613 :bookmark-length: an unsigned short,
614 614 :bookmark-name: the name of the bookmark (of length <bookmark-length>))
615 615
616 616 wdirid (all bits set) will be used as a special value for "missing"
617 617 """
618 618 entrysize = _binaryentry.size
619 619 books = []
620 620 while True:
621 621 entry = stream.read(entrysize)
622 622 if len(entry) < entrysize:
623 623 if entry:
624 624 raise error.Abort(_('bad bookmark stream'))
625 625 break
626 626 node, length = _binaryentry.unpack(entry)
627 627 bookmark = stream.read(length)
628 628 if len(bookmark) < length:
629 629 if entry:
630 630 raise error.Abort(_('bad bookmark stream'))
631 631 if node == wdirid:
632 632 node = None
633 633 books.append((bookmark, node))
634 634 return books
635 635
636 636 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
637 637 ui.debug("checking for updated bookmarks\n")
638 638 localmarks = repo._bookmarks
639 639 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same
640 640 ) = comparebookmarks(repo, remotemarks, localmarks)
641 641
642 642 status = ui.status
643 643 warn = ui.warn
644 644 if ui.configbool('ui', 'quietbookmarkmove'):
645 645 status = warn = ui.debug
646 646
647 647 explicit = set(explicit)
648 648 changed = []
649 649 for b, scid, dcid in addsrc:
650 650 if scid in repo: # add remote bookmarks for changes we already have
651 651 changed.append((b, scid, status,
652 652 _("adding remote bookmark %s\n") % (b)))
653 653 elif b in explicit:
654 654 explicit.remove(b)
655 655 ui.warn(_("remote bookmark %s points to locally missing %s\n")
656 656 % (b, hex(scid)[:12]))
657 657
658 658 for b, scid, dcid in advsrc:
659 659 changed.append((b, scid, status,
660 660 _("updating bookmark %s\n") % (b)))
661 661 # remove normal movement from explicit set
662 662 explicit.difference_update(d[0] for d in changed)
663 663
664 664 for b, scid, dcid in diverge:
665 665 if b in explicit:
666 666 explicit.discard(b)
667 667 changed.append((b, scid, status,
668 668 _("importing bookmark %s\n") % (b)))
669 669 else:
670 670 db = _diverge(ui, b, path, localmarks, scid)
671 671 if db:
672 672 changed.append((db, scid, warn,
673 673 _("divergent bookmark %s stored as %s\n") %
674 674 (b, db)))
675 675 else:
676 676 warn(_("warning: failed to assign numbered name "
677 677 "to divergent bookmark %s\n") % (b))
678 678 for b, scid, dcid in adddst + advdst:
679 679 if b in explicit:
680 680 explicit.discard(b)
681 681 changed.append((b, scid, status,
682 682 _("importing bookmark %s\n") % (b)))
683 683 for b, scid, dcid in differ:
684 684 if b in explicit:
685 685 explicit.remove(b)
686 686 ui.warn(_("remote bookmark %s points to locally missing %s\n")
687 687 % (b, hex(scid)[:12]))
688 688
689 689 if changed:
690 690 tr = trfunc()
691 691 changes = []
692 692 for b, node, writer, msg in sorted(changed):
693 693 changes.append((b, node))
694 694 writer(msg)
695 695 localmarks.applychanges(repo, tr, changes)
696 696
697 697 def incoming(ui, repo, peer):
698 698 '''Show bookmarks incoming from other to repo
699 699 '''
700 700 ui.status(_("searching for changed bookmarks\n"))
701 701
702 702 with peer.commandexecutor() as e:
703 703 remotemarks = unhexlifybookmarks(e.callcommand('listkeys', {
704 704 'namespace': 'bookmarks',
705 705 }).result())
706 706
707 707 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
708 708 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
709 709
710 710 incomings = []
711 711 if ui.debugflag:
712 712 getid = lambda id: id
713 713 else:
714 714 getid = lambda id: id[:12]
715 715 if ui.verbose:
716 716 def add(b, id, st):
717 717 incomings.append(" %-25s %s %s\n" % (b, getid(id), st))
718 718 else:
719 719 def add(b, id, st):
720 720 incomings.append(" %-25s %s\n" % (b, getid(id)))
721 721 for b, scid, dcid in addsrc:
722 722 # i18n: "added" refers to a bookmark
723 723 add(b, hex(scid), _('added'))
724 724 for b, scid, dcid in advsrc:
725 725 # i18n: "advanced" refers to a bookmark
726 726 add(b, hex(scid), _('advanced'))
727 727 for b, scid, dcid in diverge:
728 728 # i18n: "diverged" refers to a bookmark
729 729 add(b, hex(scid), _('diverged'))
730 730 for b, scid, dcid in differ:
731 731 # i18n: "changed" refers to a bookmark
732 732 add(b, hex(scid), _('changed'))
733 733
734 734 if not incomings:
735 735 ui.status(_("no changed bookmarks found\n"))
736 736 return 1
737 737
738 738 for s in sorted(incomings):
739 739 ui.write(s)
740 740
741 741 return 0
742 742
743 743 def outgoing(ui, repo, other):
744 744 '''Show bookmarks outgoing from repo to other
745 745 '''
746 746 ui.status(_("searching for changed bookmarks\n"))
747 747
748 748 remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
749 749 r = comparebookmarks(repo, repo._bookmarks, remotemarks)
750 750 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
751 751
752 752 outgoings = []
753 753 if ui.debugflag:
754 754 getid = lambda id: id
755 755 else:
756 756 getid = lambda id: id[:12]
757 757 if ui.verbose:
758 758 def add(b, id, st):
759 759 outgoings.append(" %-25s %s %s\n" % (b, getid(id), st))
760 760 else:
761 761 def add(b, id, st):
762 762 outgoings.append(" %-25s %s\n" % (b, getid(id)))
763 763 for b, scid, dcid in addsrc:
764 764 # i18n: "added refers to a bookmark
765 765 add(b, hex(scid), _('added'))
766 766 for b, scid, dcid in adddst:
767 767 # i18n: "deleted" refers to a bookmark
768 768 add(b, ' ' * 40, _('deleted'))
769 769 for b, scid, dcid in advsrc:
770 770 # i18n: "advanced" refers to a bookmark
771 771 add(b, hex(scid), _('advanced'))
772 772 for b, scid, dcid in diverge:
773 773 # i18n: "diverged" refers to a bookmark
774 774 add(b, hex(scid), _('diverged'))
775 775 for b, scid, dcid in differ:
776 776 # i18n: "changed" refers to a bookmark
777 777 add(b, hex(scid), _('changed'))
778 778
779 779 if not outgoings:
780 780 ui.status(_("no changed bookmarks found\n"))
781 781 return 1
782 782
783 783 for s in sorted(outgoings):
784 784 ui.write(s)
785 785
786 786 return 0
787 787
788 788 def summary(repo, peer):
789 789 '''Compare bookmarks between repo and other for "hg summary" output
790 790
791 791 This returns "(# of incoming, # of outgoing)" tuple.
792 792 '''
793 793 with peer.commandexecutor() as e:
794 794 remotemarks = unhexlifybookmarks(e.callcommand('listkeys', {
795 795 'namespace': 'bookmarks',
796 796 }).result())
797 797
798 798 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
799 799 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
800 800 return (len(addsrc), len(adddst))
801 801
802 802 def validdest(repo, old, new):
803 803 """Is the new bookmark destination a valid update from the old one"""
804 804 repo = repo.unfiltered()
805 805 if old == new:
806 806 # Old == new -> nothing to update.
807 807 return False
808 808 elif not old:
809 809 # old is nullrev, anything is valid.
810 810 # (new != nullrev has been excluded by the previous check)
811 811 return True
812 812 elif repo.obsstore:
813 813 return new.node() in obsutil.foreground(repo, [old.node()])
814 814 else:
815 815 # still an independent clause as it is lazier (and therefore faster)
816 816 return old.isancestorof(new)
817 817
818 818 def checkformat(repo, mark):
819 819 """return a valid version of a potential bookmark name
820 820
821 821 Raises an abort error if the bookmark name is not valid.
822 822 """
823 823 mark = mark.strip()
824 824 if not mark:
825 825 raise error.Abort(_("bookmark names cannot consist entirely of "
826 826 "whitespace"))
827 827 scmutil.checknewlabel(repo, mark, 'bookmark')
828 828 return mark
829 829
830 830 def delete(repo, tr, names):
831 831 """remove a mark from the bookmark store
832 832
833 833 Raises an abort error if mark does not exist.
834 834 """
835 835 marks = repo._bookmarks
836 836 changes = []
837 837 for mark in names:
838 838 if mark not in marks:
839 839 raise error.Abort(_("bookmark '%s' does not exist") % mark)
840 840 if mark == repo._activebookmark:
841 841 deactivate(repo)
842 842 changes.append((mark, None))
843 843 marks.applychanges(repo, tr, changes)
844 844
845 845 def rename(repo, tr, old, new, force=False, inactive=False):
846 846 """rename a bookmark from old to new
847 847
848 848 If force is specified, then the new name can overwrite an existing
849 849 bookmark.
850 850
851 851 If inactive is specified, then do not activate the new bookmark.
852 852
853 853 Raises an abort error if old is not in the bookmark store.
854 854 """
855 855 marks = repo._bookmarks
856 856 mark = checkformat(repo, new)
857 857 if old not in marks:
858 858 raise error.Abort(_("bookmark '%s' does not exist") % old)
859 859 changes = []
860 860 for bm in marks.checkconflict(mark, force):
861 861 changes.append((bm, None))
862 862 changes.extend([(mark, marks[old]), (old, None)])
863 863 marks.applychanges(repo, tr, changes)
864 864 if repo._activebookmark == old and not inactive:
865 865 activate(repo, mark)
866 866
867 867 def addbookmarks(repo, tr, names, rev=None, force=False, inactive=False):
868 868 """add a list of bookmarks
869 869
870 870 If force is specified, then the new name can overwrite an existing
871 871 bookmark.
872 872
873 873 If inactive is specified, then do not activate any bookmark. Otherwise, the
874 874 first bookmark is activated.
875 875
876 876 Raises an abort error if old is not in the bookmark store.
877 877 """
878 878 marks = repo._bookmarks
879 879 cur = repo['.'].node()
880 880 newact = None
881 881 changes = []
882 882 hiddenrev = None
883 883
884 884 # unhide revs if any
885 885 if rev:
886 886 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
887 887
888 888 for mark in names:
889 889 mark = checkformat(repo, mark)
890 890 if newact is None:
891 891 newact = mark
892 892 if inactive and mark == repo._activebookmark:
893 893 deactivate(repo)
894 894 return
895 895 tgt = cur
896 896 if rev:
897 897 ctx = scmutil.revsingle(repo, rev)
898 898 if ctx.hidden():
899 899 hiddenrev = ctx.hex()[:12]
900 900 tgt = ctx.node()
901 901 for bm in marks.checkconflict(mark, force, tgt):
902 902 changes.append((bm, None))
903 903 changes.append((mark, tgt))
904 904
905 905 if hiddenrev:
906 906 repo.ui.warn(_("bookmarking hidden changeset %s\n") % hiddenrev)
907 907
908 908 if ctx.obsolete():
909 909 msg = obsutil._getfilteredreason(repo, "%s" % hiddenrev, ctx)
910 910 repo.ui.warn("(%s)\n" % msg)
911 911
912 912 marks.applychanges(repo, tr, changes)
913 913 if not inactive and cur == marks[newact] and not rev:
914 914 activate(repo, newact)
915 915 elif cur != tgt and newact == repo._activebookmark:
916 916 deactivate(repo)
917 917
918 918 def _printbookmarks(ui, repo, bmarks, **opts):
919 919 """private method to print bookmarks
920 920
921 921 Provides a way for extensions to control how bookmarks are printed (e.g.
922 922 prepend or postpend names)
923 923 """
924 924 opts = pycompat.byteskwargs(opts)
925 925 fm = ui.formatter('bookmarks', opts)
926 926 contexthint = fm.contexthint('bookmark rev node active')
927 927 hexfn = fm.hexfunc
928 928 if len(bmarks) == 0 and fm.isplain():
929 929 ui.status(_("no bookmarks set\n"))
930 930 for bmark, (n, prefix, label) in sorted(bmarks.iteritems()):
931 931 fm.startitem()
932 932 if 'ctx' in contexthint:
933 933 fm.context(ctx=repo[n])
934 934 if not ui.quiet:
935 935 fm.plain(' %s ' % prefix, label=label)
936 936 fm.write('bookmark', '%s', bmark, label=label)
937 937 pad = " " * (25 - encoding.colwidth(bmark))
938 938 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
939 939 repo.changelog.rev(n), hexfn(n), label=label)
940 940 fm.data(active=(activebookmarklabel in label))
941 941 fm.plain('\n')
942 942 fm.end()
943 943
944 944 def printbookmarks(ui, repo, **opts):
945 945 """print bookmarks to a formatter
946 946
947 947 Provides a way for extensions to control how bookmarks are printed.
948 948 """
949 949 marks = repo._bookmarks
950 950 bmarks = {}
951 951 for bmark, n in sorted(marks.iteritems()):
952 952 active = repo._activebookmark
953 953 if bmark == active:
954 954 prefix, label = '*', activebookmarklabel
955 955 else:
956 956 prefix, label = ' ', ''
957 957
958 958 bmarks[bmark] = (n, prefix, label)
959 959 _printbookmarks(ui, repo, bmarks, **opts)
960 960
961 961 def preparehookargs(name, old, new):
962 962 if new is None:
963 963 new = ''
964 964 if old is None:
965 965 old = ''
966 966 return {'bookmark': name,
967 967 'node': hex(new),
968 968 'oldnode': hex(old)}
@@ -1,1277 +1,1277 b''
1 1 #testcases b2-pushkey b2-binary
2 2
3 3 #if b2-pushkey
4 4 $ cat << EOF >> $HGRCPATH
5 5 > [devel]
6 6 > legacy.exchange=bookmarks
7 7 > EOF
8 8 #endif
9 9
10 10 #require serve
11 11
12 12 $ cat << EOF >> $HGRCPATH
13 13 > [ui]
14 14 > logtemplate={rev}:{node|short} {desc|firstline}
15 15 > [phases]
16 16 > publish=False
17 17 > [experimental]
18 18 > evolution.createmarkers=True
19 19 > evolution.exchange=True
20 20 > EOF
21 21
22 22 $ cat > $TESTTMP/hook.sh <<'EOF'
23 23 > echo "test-hook-bookmark: $HG_BOOKMARK: $HG_OLDNODE -> $HG_NODE"
24 24 > EOF
25 25 $ TESTHOOK="hooks.txnclose-bookmark.test=sh $TESTTMP/hook.sh"
26 26
27 27 initialize
28 28
29 29 $ hg init a
30 30 $ cd a
31 31 $ echo 'test' > test
32 32 $ hg commit -Am'test'
33 33 adding test
34 34
35 35 set bookmarks
36 36
37 37 $ hg bookmark X
38 38 $ hg bookmark Y
39 39 $ hg bookmark Z
40 40
41 41 import bookmark by name
42 42
43 43 $ hg init ../b
44 44 $ cd ../b
45 45 $ hg book Y
46 46 $ hg book
47 47 * Y -1:000000000000
48 48 $ hg pull ../a --config "$TESTHOOK"
49 49 pulling from ../a
50 50 requesting all changes
51 51 adding changesets
52 52 adding manifests
53 53 adding file changes
54 54 added 1 changesets with 1 changes to 1 files
55 55 adding remote bookmark X
56 56 updating bookmark Y
57 57 adding remote bookmark Z
58 58 new changesets 4e3505fd9583
59 59 test-hook-bookmark: X: -> 4e3505fd95835d721066b76e75dbb8cc554d7f77
60 60 test-hook-bookmark: Y: 0000000000000000000000000000000000000000 -> 4e3505fd95835d721066b76e75dbb8cc554d7f77
61 61 test-hook-bookmark: Z: -> 4e3505fd95835d721066b76e75dbb8cc554d7f77
62 62 (run 'hg update' to get a working copy)
63 63 $ hg bookmarks
64 64 X 0:4e3505fd9583
65 65 * Y 0:4e3505fd9583
66 66 Z 0:4e3505fd9583
67 67 $ hg debugpushkey ../a namespaces
68 68 bookmarks
69 69 namespaces
70 70 obsolete
71 71 phases
72 72 $ hg debugpushkey ../a bookmarks
73 73 X 4e3505fd95835d721066b76e75dbb8cc554d7f77
74 74 Y 4e3505fd95835d721066b76e75dbb8cc554d7f77
75 75 Z 4e3505fd95835d721066b76e75dbb8cc554d7f77
76 76
77 77 delete the bookmark to re-pull it
78 78
79 79 $ hg book -d X
80 80 $ hg pull -B X ../a
81 81 pulling from ../a
82 82 no changes found
83 83 adding remote bookmark X
84 84
85 85 finally no-op pull
86 86
87 87 $ hg pull -B X ../a
88 88 pulling from ../a
89 89 no changes found
90 90 $ hg bookmark
91 91 X 0:4e3505fd9583
92 92 * Y 0:4e3505fd9583
93 93 Z 0:4e3505fd9583
94 94
95 95 export bookmark by name
96 96
97 97 $ hg bookmark W
98 98 $ hg bookmark foo
99 99 $ hg bookmark foobar
100 100 $ hg push -B W ../a
101 101 pushing to ../a
102 102 searching for changes
103 103 no changes found
104 104 exporting bookmark W
105 105 [1]
106 106 $ hg -R ../a bookmarks
107 107 W -1:000000000000
108 108 X 0:4e3505fd9583
109 109 Y 0:4e3505fd9583
110 110 * Z 0:4e3505fd9583
111 111
112 112 delete a remote bookmark
113 113
114 114 $ hg book -d W
115 115
116 116 #if b2-pushkey
117 117
118 118 $ hg push -B W ../a --config "$TESTHOOK" --debug --config devel.bundle2.debug=yes
119 119 pushing to ../a
120 120 query 1; heads
121 121 searching for changes
122 122 all remote heads known locally
123 123 listing keys for "phases"
124 124 checking for updated bookmarks
125 125 listing keys for "bookmarks"
126 126 no changes found
127 127 bundle2-output-bundle: "HG20", 4 parts total
128 128 bundle2-output: start emission of HG20 stream
129 129 bundle2-output: bundle parameter:
130 130 bundle2-output: start of parts
131 131 bundle2-output: bundle part: "replycaps"
132 132 bundle2-output-part: "replycaps" 222 bytes payload
133 133 bundle2-output: part 0: "REPLYCAPS"
134 134 bundle2-output: header chunk size: 16
135 135 bundle2-output: payload chunk size: 222
136 136 bundle2-output: closing payload chunk
137 137 bundle2-output: bundle part: "check:bookmarks"
138 138 bundle2-output-part: "check:bookmarks" 23 bytes payload
139 139 bundle2-output: part 1: "CHECK:BOOKMARKS"
140 140 bundle2-output: header chunk size: 22
141 141 bundle2-output: payload chunk size: 23
142 142 bundle2-output: closing payload chunk
143 143 bundle2-output: bundle part: "check:phases"
144 144 bundle2-output-part: "check:phases" 24 bytes payload
145 145 bundle2-output: part 2: "CHECK:PHASES"
146 146 bundle2-output: header chunk size: 19
147 147 bundle2-output: payload chunk size: 24
148 148 bundle2-output: closing payload chunk
149 149 bundle2-output: bundle part: "pushkey"
150 150 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
151 151 bundle2-output: part 3: "PUSHKEY"
152 152 bundle2-output: header chunk size: 90
153 153 bundle2-output: closing payload chunk
154 154 bundle2-output: end of bundle
155 155 bundle2-input: start processing of HG20 stream
156 156 bundle2-input: reading bundle2 stream parameters
157 157 bundle2-input-bundle: with-transaction
158 158 bundle2-input: start extraction of bundle2 parts
159 159 bundle2-input: part header size: 16
160 160 bundle2-input: part type: "REPLYCAPS"
161 161 bundle2-input: part id: "0"
162 162 bundle2-input: part parameters: 0
163 163 bundle2-input: found a handler for part replycaps
164 164 bundle2-input-part: "replycaps" supported
165 165 bundle2-input: payload chunk size: 222
166 166 bundle2-input: payload chunk size: 0
167 167 bundle2-input-part: total payload size 222
168 168 bundle2-input: part header size: 22
169 169 bundle2-input: part type: "CHECK:BOOKMARKS"
170 170 bundle2-input: part id: "1"
171 171 bundle2-input: part parameters: 0
172 172 bundle2-input: found a handler for part check:bookmarks
173 173 bundle2-input-part: "check:bookmarks" supported
174 174 bundle2-input: payload chunk size: 23
175 175 bundle2-input: payload chunk size: 0
176 176 bundle2-input-part: total payload size 23
177 177 bundle2-input: part header size: 19
178 178 bundle2-input: part type: "CHECK:PHASES"
179 179 bundle2-input: part id: "2"
180 180 bundle2-input: part parameters: 0
181 181 bundle2-input: found a handler for part check:phases
182 182 bundle2-input-part: "check:phases" supported
183 183 bundle2-input: payload chunk size: 24
184 184 bundle2-input: payload chunk size: 0
185 185 bundle2-input-part: total payload size 24
186 186 bundle2-input: part header size: 90
187 187 bundle2-input: part type: "PUSHKEY"
188 188 bundle2-input: part id: "3"
189 189 bundle2-input: part parameters: 4
190 190 bundle2-input: found a handler for part pushkey
191 191 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
192 192 pushing key for "bookmarks:W"
193 193 bundle2-input: payload chunk size: 0
194 194 bundle2-input: part header size: 0
195 195 bundle2-input: end of bundle2 stream
196 196 bundle2-input-bundle: 3 parts total
197 197 running hook txnclose-bookmark.test: sh $TESTTMP/hook.sh
198 198 test-hook-bookmark: W: 0000000000000000000000000000000000000000 ->
199 199 bundle2-output-bundle: "HG20", 1 parts total
200 200 bundle2-output: start emission of HG20 stream
201 201 bundle2-output: bundle parameter:
202 202 bundle2-output: start of parts
203 203 bundle2-output: bundle part: "reply:pushkey"
204 204 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
205 205 bundle2-output: part 0: "REPLY:PUSHKEY"
206 206 bundle2-output: header chunk size: 43
207 207 bundle2-output: closing payload chunk
208 208 bundle2-output: end of bundle
209 209 bundle2-input: start processing of HG20 stream
210 210 bundle2-input: reading bundle2 stream parameters
211 211 bundle2-input-bundle: no-transaction
212 212 bundle2-input: start extraction of bundle2 parts
213 213 bundle2-input: part header size: 43
214 214 bundle2-input: part type: "REPLY:PUSHKEY"
215 215 bundle2-input: part id: "0"
216 216 bundle2-input: part parameters: 2
217 217 bundle2-input: found a handler for part reply:pushkey
218 218 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
219 219 bundle2-input: payload chunk size: 0
220 220 bundle2-input: part header size: 0
221 221 bundle2-input: end of bundle2 stream
222 222 bundle2-input-bundle: 0 parts total
223 223 deleting remote bookmark W
224 224 listing keys for "phases"
225 225 [1]
226 226
227 227 #endif
228 228 #if b2-binary
229 229
230 230 $ hg push -B W ../a --config "$TESTHOOK" --debug --config devel.bundle2.debug=yes
231 231 pushing to ../a
232 232 query 1; heads
233 233 searching for changes
234 234 all remote heads known locally
235 235 listing keys for "phases"
236 236 checking for updated bookmarks
237 237 listing keys for "bookmarks"
238 238 no changes found
239 239 bundle2-output-bundle: "HG20", 4 parts total
240 240 bundle2-output: start emission of HG20 stream
241 241 bundle2-output: bundle parameter:
242 242 bundle2-output: start of parts
243 243 bundle2-output: bundle part: "replycaps"
244 244 bundle2-output-part: "replycaps" 222 bytes payload
245 245 bundle2-output: part 0: "REPLYCAPS"
246 246 bundle2-output: header chunk size: 16
247 247 bundle2-output: payload chunk size: 222
248 248 bundle2-output: closing payload chunk
249 249 bundle2-output: bundle part: "check:bookmarks"
250 250 bundle2-output-part: "check:bookmarks" 23 bytes payload
251 251 bundle2-output: part 1: "CHECK:BOOKMARKS"
252 252 bundle2-output: header chunk size: 22
253 253 bundle2-output: payload chunk size: 23
254 254 bundle2-output: closing payload chunk
255 255 bundle2-output: bundle part: "check:phases"
256 256 bundle2-output-part: "check:phases" 24 bytes payload
257 257 bundle2-output: part 2: "CHECK:PHASES"
258 258 bundle2-output: header chunk size: 19
259 259 bundle2-output: payload chunk size: 24
260 260 bundle2-output: closing payload chunk
261 261 bundle2-output: bundle part: "bookmarks"
262 262 bundle2-output-part: "bookmarks" 23 bytes payload
263 263 bundle2-output: part 3: "BOOKMARKS"
264 264 bundle2-output: header chunk size: 16
265 265 bundle2-output: payload chunk size: 23
266 266 bundle2-output: closing payload chunk
267 267 bundle2-output: end of bundle
268 268 bundle2-input: start processing of HG20 stream
269 269 bundle2-input: reading bundle2 stream parameters
270 270 bundle2-input-bundle: with-transaction
271 271 bundle2-input: start extraction of bundle2 parts
272 272 bundle2-input: part header size: 16
273 273 bundle2-input: part type: "REPLYCAPS"
274 274 bundle2-input: part id: "0"
275 275 bundle2-input: part parameters: 0
276 276 bundle2-input: found a handler for part replycaps
277 277 bundle2-input-part: "replycaps" supported
278 278 bundle2-input: payload chunk size: 222
279 279 bundle2-input: payload chunk size: 0
280 280 bundle2-input-part: total payload size 222
281 281 bundle2-input: part header size: 22
282 282 bundle2-input: part type: "CHECK:BOOKMARKS"
283 283 bundle2-input: part id: "1"
284 284 bundle2-input: part parameters: 0
285 285 bundle2-input: found a handler for part check:bookmarks
286 286 bundle2-input-part: "check:bookmarks" supported
287 287 bundle2-input: payload chunk size: 23
288 288 bundle2-input: payload chunk size: 0
289 289 bundle2-input-part: total payload size 23
290 290 bundle2-input: part header size: 19
291 291 bundle2-input: part type: "CHECK:PHASES"
292 292 bundle2-input: part id: "2"
293 293 bundle2-input: part parameters: 0
294 294 bundle2-input: found a handler for part check:phases
295 295 bundle2-input-part: "check:phases" supported
296 296 bundle2-input: payload chunk size: 24
297 297 bundle2-input: payload chunk size: 0
298 298 bundle2-input-part: total payload size 24
299 299 bundle2-input: part header size: 16
300 300 bundle2-input: part type: "BOOKMARKS"
301 301 bundle2-input: part id: "3"
302 302 bundle2-input: part parameters: 0
303 303 bundle2-input: found a handler for part bookmarks
304 304 bundle2-input-part: "bookmarks" supported
305 305 bundle2-input: payload chunk size: 23
306 306 bundle2-input: payload chunk size: 0
307 307 bundle2-input-part: total payload size 23
308 308 bundle2-input: part header size: 0
309 309 bundle2-input: end of bundle2 stream
310 310 bundle2-input-bundle: 3 parts total
311 311 running hook txnclose-bookmark.test: sh $TESTTMP/hook.sh
312 312 test-hook-bookmark: W: 0000000000000000000000000000000000000000 ->
313 313 bundle2-output-bundle: "HG20", 0 parts total
314 314 bundle2-output: start emission of HG20 stream
315 315 bundle2-output: bundle parameter:
316 316 bundle2-output: start of parts
317 317 bundle2-output: end of bundle
318 318 bundle2-input: start processing of HG20 stream
319 319 bundle2-input: reading bundle2 stream parameters
320 320 bundle2-input-bundle: no-transaction
321 321 bundle2-input: start extraction of bundle2 parts
322 322 bundle2-input: part header size: 0
323 323 bundle2-input: end of bundle2 stream
324 324 bundle2-input-bundle: 0 parts total
325 325 deleting remote bookmark W
326 326 listing keys for "phases"
327 327 [1]
328 328
329 329 #endif
330 330
331 331 export the active bookmark
332 332
333 333 $ hg bookmark V
334 334 $ hg push -B . ../a
335 335 pushing to ../a
336 336 searching for changes
337 337 no changes found
338 338 exporting bookmark V
339 339 [1]
340 340
341 341 exporting the active bookmark with 'push -B .'
342 342 demand that one of the bookmarks is activated
343 343
344 344 $ hg update -r default
345 345 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
346 346 (leaving bookmark V)
347 347 $ hg push -B . ../a
348 abort: no active bookmark
348 abort: no active bookmark!
349 349 [255]
350 350 $ hg update -r V
351 351 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
352 352 (activating bookmark V)
353 353
354 354 delete the bookmark
355 355
356 356 $ hg book -d V
357 357 $ hg push -B V ../a
358 358 pushing to ../a
359 359 searching for changes
360 360 no changes found
361 361 deleting remote bookmark V
362 362 [1]
363 363 $ hg up foobar
364 364 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
365 365 (activating bookmark foobar)
366 366
367 367 push/pull name that doesn't exist
368 368
369 369 $ hg push -B badname ../a
370 370 pushing to ../a
371 371 searching for changes
372 372 bookmark badname does not exist on the local or remote repository!
373 373 no changes found
374 374 [2]
375 375 $ hg pull -B anotherbadname ../a
376 376 pulling from ../a
377 377 abort: remote bookmark anotherbadname not found!
378 378 [255]
379 379
380 380 divergent bookmarks
381 381
382 382 $ cd ../a
383 383 $ echo c1 > f1
384 384 $ hg ci -Am1
385 385 adding f1
386 386 $ hg book -f @
387 387 $ hg book -f X
388 388 $ hg book
389 389 @ 1:0d2164f0ce0d
390 390 * X 1:0d2164f0ce0d
391 391 Y 0:4e3505fd9583
392 392 Z 1:0d2164f0ce0d
393 393
394 394 $ cd ../b
395 395 $ hg up
396 396 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
397 397 updating bookmark foobar
398 398 $ echo c2 > f2
399 399 $ hg ci -Am2
400 400 adding f2
401 401 $ hg book -if @
402 402 $ hg book -if X
403 403 $ hg book
404 404 @ 1:9b140be10808
405 405 X 1:9b140be10808
406 406 Y 0:4e3505fd9583
407 407 Z 0:4e3505fd9583
408 408 foo -1:000000000000
409 409 * foobar 1:9b140be10808
410 410
411 411 $ hg pull --config paths.foo=../a foo --config "$TESTHOOK"
412 412 pulling from $TESTTMP/a
413 413 searching for changes
414 414 adding changesets
415 415 adding manifests
416 416 adding file changes
417 417 added 1 changesets with 1 changes to 1 files (+1 heads)
418 418 divergent bookmark @ stored as @foo
419 419 divergent bookmark X stored as X@foo
420 420 updating bookmark Z
421 421 new changesets 0d2164f0ce0d
422 422 test-hook-bookmark: @foo: -> 0d2164f0ce0d8f1d6f94351eba04b794909be66c
423 423 test-hook-bookmark: X@foo: -> 0d2164f0ce0d8f1d6f94351eba04b794909be66c
424 424 test-hook-bookmark: Z: 4e3505fd95835d721066b76e75dbb8cc554d7f77 -> 0d2164f0ce0d8f1d6f94351eba04b794909be66c
425 425 (run 'hg heads' to see heads, 'hg merge' to merge)
426 426 $ hg book
427 427 @ 1:9b140be10808
428 428 @foo 2:0d2164f0ce0d
429 429 X 1:9b140be10808
430 430 X@foo 2:0d2164f0ce0d
431 431 Y 0:4e3505fd9583
432 432 Z 2:0d2164f0ce0d
433 433 foo -1:000000000000
434 434 * foobar 1:9b140be10808
435 435
436 436 (test that too many divergence of bookmark)
437 437
438 438 $ $PYTHON $TESTDIR/seq.py 1 100 | while read i; do hg bookmarks -r 000000000000 "X@${i}"; done
439 439 $ hg pull ../a
440 440 pulling from ../a
441 441 searching for changes
442 442 no changes found
443 443 warning: failed to assign numbered name to divergent bookmark X
444 444 divergent bookmark @ stored as @1
445 445 $ hg bookmarks | grep '^ X' | grep -v ':000000000000'
446 446 X 1:9b140be10808
447 447 X@foo 2:0d2164f0ce0d
448 448
449 449 (test that remotely diverged bookmarks are reused if they aren't changed)
450 450
451 451 $ hg bookmarks | grep '^ @'
452 452 @ 1:9b140be10808
453 453 @1 2:0d2164f0ce0d
454 454 @foo 2:0d2164f0ce0d
455 455 $ hg pull ../a
456 456 pulling from ../a
457 457 searching for changes
458 458 no changes found
459 459 warning: failed to assign numbered name to divergent bookmark X
460 460 divergent bookmark @ stored as @1
461 461 $ hg bookmarks | grep '^ @'
462 462 @ 1:9b140be10808
463 463 @1 2:0d2164f0ce0d
464 464 @foo 2:0d2164f0ce0d
465 465
466 466 $ $PYTHON $TESTDIR/seq.py 1 100 | while read i; do hg bookmarks -d "X@${i}"; done
467 467 $ hg bookmarks -d "@1"
468 468
469 469 $ hg push -f ../a
470 470 pushing to ../a
471 471 searching for changes
472 472 adding changesets
473 473 adding manifests
474 474 adding file changes
475 475 added 1 changesets with 1 changes to 1 files (+1 heads)
476 476 $ hg -R ../a book
477 477 @ 1:0d2164f0ce0d
478 478 * X 1:0d2164f0ce0d
479 479 Y 0:4e3505fd9583
480 480 Z 1:0d2164f0ce0d
481 481
482 482 explicit pull should overwrite the local version (issue4439)
483 483
484 484 $ hg update -r X
485 485 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
486 486 (activating bookmark X)
487 487 $ hg pull --config paths.foo=../a foo -B . --config "$TESTHOOK"
488 488 pulling from $TESTTMP/a
489 489 no changes found
490 490 divergent bookmark @ stored as @foo
491 491 importing bookmark X
492 492 test-hook-bookmark: @foo: 0d2164f0ce0d8f1d6f94351eba04b794909be66c -> 0d2164f0ce0d8f1d6f94351eba04b794909be66c
493 493 test-hook-bookmark: X: 9b140be1080824d768c5a4691a564088eede71f9 -> 0d2164f0ce0d8f1d6f94351eba04b794909be66c
494 494
495 495 reinstall state for further testing:
496 496
497 497 $ hg book -fr 9b140be10808 X
498 498
499 499 revsets should not ignore divergent bookmarks
500 500
501 501 $ hg bookmark -fr 1 Z
502 502 $ hg log -r 'bookmark()' --template '{rev}:{node|short} {bookmarks}\n'
503 503 0:4e3505fd9583 Y
504 504 1:9b140be10808 @ X Z foobar
505 505 2:0d2164f0ce0d @foo X@foo
506 506 $ hg log -r 'bookmark("X@foo")' --template '{rev}:{node|short} {bookmarks}\n'
507 507 2:0d2164f0ce0d @foo X@foo
508 508 $ hg log -r 'bookmark("re:X@foo")' --template '{rev}:{node|short} {bookmarks}\n'
509 509 2:0d2164f0ce0d @foo X@foo
510 510
511 511 update a remote bookmark from a non-head to a head
512 512
513 513 $ hg up -q Y
514 514 $ echo c3 > f2
515 515 $ hg ci -Am3
516 516 adding f2
517 517 created new head
518 518 $ hg push ../a --config "$TESTHOOK"
519 519 pushing to ../a
520 520 searching for changes
521 521 adding changesets
522 522 adding manifests
523 523 adding file changes
524 524 added 1 changesets with 1 changes to 1 files (+1 heads)
525 525 test-hook-bookmark: Y: 4e3505fd95835d721066b76e75dbb8cc554d7f77 -> f6fc62dde3c0771e29704af56ba4d8af77abcc2f
526 526 updating bookmark Y
527 527 $ hg -R ../a book
528 528 @ 1:0d2164f0ce0d
529 529 * X 1:0d2164f0ce0d
530 530 Y 3:f6fc62dde3c0
531 531 Z 1:0d2164f0ce0d
532 532
533 533 update a bookmark in the middle of a client pulling changes
534 534
535 535 $ cd ..
536 536 $ hg clone -q a pull-race
537 537
538 538 We want to use http because it is stateless and therefore more susceptible to
539 539 race conditions
540 540
541 541 $ hg serve -R pull-race -p $HGPORT -d --pid-file=pull-race.pid -E main-error.log
542 542 $ cat pull-race.pid >> $DAEMON_PIDS
543 543
544 544 $ cat <<EOF > $TESTTMP/out_makecommit.sh
545 545 > #!/bin/sh
546 546 > hg ci -Am5
547 547 > echo committed in pull-race
548 548 > EOF
549 549
550 550 $ hg clone -q http://localhost:$HGPORT/ pull-race2 --config "$TESTHOOK"
551 551 test-hook-bookmark: @: -> 0d2164f0ce0d8f1d6f94351eba04b794909be66c
552 552 test-hook-bookmark: X: -> 0d2164f0ce0d8f1d6f94351eba04b794909be66c
553 553 test-hook-bookmark: Y: -> f6fc62dde3c0771e29704af56ba4d8af77abcc2f
554 554 test-hook-bookmark: Z: -> 0d2164f0ce0d8f1d6f94351eba04b794909be66c
555 555 $ cd pull-race
556 556 $ hg up -q Y
557 557 $ echo c4 > f2
558 558 $ hg ci -Am4
559 559 $ echo c5 > f3
560 560 $ cat <<EOF > .hg/hgrc
561 561 > [hooks]
562 562 > outgoing.makecommit = sh $TESTTMP/out_makecommit.sh
563 563 > EOF
564 564
565 565 (new config needs a server restart)
566 566
567 567 $ cd ..
568 568 $ killdaemons.py
569 569 $ hg serve -R pull-race -p $HGPORT -d --pid-file=pull-race.pid -E main-error.log
570 570 $ cat pull-race.pid >> $DAEMON_PIDS
571 571 $ cd pull-race2
572 572 $ hg -R $TESTTMP/pull-race book
573 573 @ 1:0d2164f0ce0d
574 574 X 1:0d2164f0ce0d
575 575 * Y 4:b0a5eff05604
576 576 Z 1:0d2164f0ce0d
577 577 $ hg pull
578 578 pulling from http://localhost:$HGPORT/
579 579 searching for changes
580 580 adding changesets
581 581 adding manifests
582 582 adding file changes
583 583 added 1 changesets with 1 changes to 1 files
584 584 updating bookmark Y
585 585 new changesets b0a5eff05604
586 586 (run 'hg update' to get a working copy)
587 587 $ hg book
588 588 * @ 1:0d2164f0ce0d
589 589 X 1:0d2164f0ce0d
590 590 Y 4:b0a5eff05604
591 591 Z 1:0d2164f0ce0d
592 592
593 593 Update a bookmark right after the initial lookup -B (issue4689)
594 594
595 595 $ echo c6 > ../pull-race/f3 # to be committed during the race
596 596 $ cat <<EOF > $TESTTMP/listkeys_makecommit.sh
597 597 > #!/bin/sh
598 598 > if hg st | grep -q M; then
599 599 > hg commit -m race
600 600 > echo committed in pull-race
601 601 > else
602 602 > exit 0
603 603 > fi
604 604 > EOF
605 605 $ cat <<EOF > ../pull-race/.hg/hgrc
606 606 > [hooks]
607 607 > # If anything to commit, commit it right after the first key listing used
608 608 > # during lookup. This makes the commit appear before the actual getbundle
609 609 > # call.
610 610 > listkeys.makecommit= sh $TESTTMP/listkeys_makecommit.sh
611 611 > EOF
612 612
613 613 (new config need server restart)
614 614
615 615 $ killdaemons.py
616 616 $ hg serve -R ../pull-race -p $HGPORT -d --pid-file=../pull-race.pid -E main-error.log
617 617 $ cat ../pull-race.pid >> $DAEMON_PIDS
618 618
619 619 $ hg -R $TESTTMP/pull-race book
620 620 @ 1:0d2164f0ce0d
621 621 X 1:0d2164f0ce0d
622 622 * Y 5:35d1ef0a8d1b
623 623 Z 1:0d2164f0ce0d
624 624 $ hg update -r Y
625 625 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
626 626 (activating bookmark Y)
627 627 $ hg pull -B .
628 628 pulling from http://localhost:$HGPORT/
629 629 searching for changes
630 630 adding changesets
631 631 adding manifests
632 632 adding file changes
633 633 added 1 changesets with 1 changes to 1 files
634 634 updating bookmark Y
635 635 new changesets 35d1ef0a8d1b
636 636 (run 'hg update' to get a working copy)
637 637 $ hg book
638 638 @ 1:0d2164f0ce0d
639 639 X 1:0d2164f0ce0d
640 640 * Y 5:35d1ef0a8d1b
641 641 Z 1:0d2164f0ce0d
642 642
643 643 (done with this section of the test)
644 644
645 645 $ killdaemons.py
646 646 $ cd ../b
647 647
648 648 diverging a remote bookmark fails
649 649
650 650 $ hg up -q 4e3505fd9583
651 651 $ echo c4 > f2
652 652 $ hg ci -Am4
653 653 adding f2
654 654 created new head
655 655 $ echo c5 > f2
656 656 $ hg ci -Am5
657 657 $ hg log -G
658 658 @ 5:c922c0139ca0 5
659 659 |
660 660 o 4:4efff6d98829 4
661 661 |
662 662 | o 3:f6fc62dde3c0 3
663 663 |/
664 664 | o 2:0d2164f0ce0d 1
665 665 |/
666 666 | o 1:9b140be10808 2
667 667 |/
668 668 o 0:4e3505fd9583 test
669 669
670 670
671 671 $ hg book -f Y
672 672
673 673 $ cat <<EOF > ../a/.hg/hgrc
674 674 > [web]
675 675 > push_ssl = false
676 676 > allow_push = *
677 677 > EOF
678 678
679 679 $ hg serve -R ../a -p $HGPORT2 -d --pid-file=../hg2.pid
680 680 $ cat ../hg2.pid >> $DAEMON_PIDS
681 681
682 682 $ hg push http://localhost:$HGPORT2/
683 683 pushing to http://localhost:$HGPORT2/
684 684 searching for changes
685 685 abort: push creates new remote head c922c0139ca0 with bookmark 'Y'!
686 686 (merge or see 'hg help push' for details about pushing new heads)
687 687 [255]
688 688 $ hg -R ../a book
689 689 @ 1:0d2164f0ce0d
690 690 * X 1:0d2164f0ce0d
691 691 Y 3:f6fc62dde3c0
692 692 Z 1:0d2164f0ce0d
693 693
694 694
695 695 Unrelated marker does not alter the decision
696 696
697 697 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
698 698 $ hg push http://localhost:$HGPORT2/
699 699 pushing to http://localhost:$HGPORT2/
700 700 searching for changes
701 701 abort: push creates new remote head c922c0139ca0 with bookmark 'Y'!
702 702 (merge or see 'hg help push' for details about pushing new heads)
703 703 [255]
704 704 $ hg -R ../a book
705 705 @ 1:0d2164f0ce0d
706 706 * X 1:0d2164f0ce0d
707 707 Y 3:f6fc62dde3c0
708 708 Z 1:0d2164f0ce0d
709 709
710 710 Update to a successor works
711 711
712 712 $ hg id --debug -r 3
713 713 f6fc62dde3c0771e29704af56ba4d8af77abcc2f
714 714 $ hg id --debug -r 4
715 715 4efff6d98829d9c824c621afd6e3f01865f5439f
716 716 $ hg id --debug -r 5
717 717 c922c0139ca03858f655e4a2af4dd02796a63969 tip Y
718 718 $ hg debugobsolete f6fc62dde3c0771e29704af56ba4d8af77abcc2f cccccccccccccccccccccccccccccccccccccccc
719 719 obsoleted 1 changesets
720 720 $ hg debugobsolete cccccccccccccccccccccccccccccccccccccccc 4efff6d98829d9c824c621afd6e3f01865f5439f
721 721 $ hg push http://localhost:$HGPORT2/
722 722 pushing to http://localhost:$HGPORT2/
723 723 searching for changes
724 724 remote: adding changesets
725 725 remote: adding manifests
726 726 remote: adding file changes
727 727 remote: added 2 changesets with 2 changes to 1 files (+1 heads)
728 728 remote: 2 new obsolescence markers
729 729 remote: obsoleted 1 changesets
730 730 updating bookmark Y
731 731 $ hg -R ../a book
732 732 @ 1:0d2164f0ce0d
733 733 * X 1:0d2164f0ce0d
734 734 Y 5:c922c0139ca0
735 735 Z 1:0d2164f0ce0d
736 736
737 737 hgweb
738 738
739 739 $ cat <<EOF > .hg/hgrc
740 740 > [web]
741 741 > push_ssl = false
742 742 > allow_push = *
743 743 > EOF
744 744
745 745 $ hg serve -p $HGPORT -d --pid-file=../hg.pid -E errors.log
746 746 $ cat ../hg.pid >> $DAEMON_PIDS
747 747 $ cd ../a
748 748
749 749 $ hg debugpushkey http://localhost:$HGPORT/ namespaces
750 750 bookmarks
751 751 namespaces
752 752 obsolete
753 753 phases
754 754 $ hg debugpushkey http://localhost:$HGPORT/ bookmarks
755 755 @ 9b140be1080824d768c5a4691a564088eede71f9
756 756 X 9b140be1080824d768c5a4691a564088eede71f9
757 757 Y c922c0139ca03858f655e4a2af4dd02796a63969
758 758 Z 9b140be1080824d768c5a4691a564088eede71f9
759 759 foo 0000000000000000000000000000000000000000
760 760 foobar 9b140be1080824d768c5a4691a564088eede71f9
761 761 $ hg out -B http://localhost:$HGPORT/
762 762 comparing with http://localhost:$HGPORT/
763 763 searching for changed bookmarks
764 764 @ 0d2164f0ce0d
765 765 X 0d2164f0ce0d
766 766 Z 0d2164f0ce0d
767 767 foo
768 768 foobar
769 769 $ hg push -B Z http://localhost:$HGPORT/
770 770 pushing to http://localhost:$HGPORT/
771 771 searching for changes
772 772 no changes found
773 773 updating bookmark Z
774 774 [1]
775 775 $ hg book -d Z
776 776 $ hg in -B http://localhost:$HGPORT/
777 777 comparing with http://localhost:$HGPORT/
778 778 searching for changed bookmarks
779 779 @ 9b140be10808
780 780 X 9b140be10808
781 781 Z 0d2164f0ce0d
782 782 foo 000000000000
783 783 foobar 9b140be10808
784 784 $ hg pull -B Z http://localhost:$HGPORT/
785 785 pulling from http://localhost:$HGPORT/
786 786 no changes found
787 787 divergent bookmark @ stored as @1
788 788 divergent bookmark X stored as X@1
789 789 adding remote bookmark Z
790 790 adding remote bookmark foo
791 791 adding remote bookmark foobar
792 792 $ hg clone http://localhost:$HGPORT/ cloned-bookmarks
793 793 requesting all changes
794 794 adding changesets
795 795 adding manifests
796 796 adding file changes
797 797 added 5 changesets with 5 changes to 3 files (+2 heads)
798 798 2 new obsolescence markers
799 799 new changesets 4e3505fd9583:c922c0139ca0
800 800 updating to bookmark @
801 801 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
802 802 $ hg -R cloned-bookmarks bookmarks
803 803 * @ 1:9b140be10808
804 804 X 1:9b140be10808
805 805 Y 4:c922c0139ca0
806 806 Z 2:0d2164f0ce0d
807 807 foo -1:000000000000
808 808 foobar 1:9b140be10808
809 809
810 810 $ cd ..
811 811
812 812 Test to show result of bookmarks comparison
813 813
814 814 $ mkdir bmcomparison
815 815 $ cd bmcomparison
816 816
817 817 $ hg init source
818 818 $ hg -R source debugbuilddag '+2*2*3*4'
819 819 $ hg -R source log -G --template '{rev}:{node|short}'
820 820 o 4:e7bd5218ca15
821 821 |
822 822 | o 3:6100d3090acf
823 823 |/
824 824 | o 2:fa942426a6fd
825 825 |/
826 826 | o 1:66f7d451a68b
827 827 |/
828 828 o 0:1ea73414a91b
829 829
830 830 $ hg -R source bookmarks -r 0 SAME
831 831 $ hg -R source bookmarks -r 0 ADV_ON_REPO1
832 832 $ hg -R source bookmarks -r 0 ADV_ON_REPO2
833 833 $ hg -R source bookmarks -r 0 DIFF_ADV_ON_REPO1
834 834 $ hg -R source bookmarks -r 0 DIFF_ADV_ON_REPO2
835 835 $ hg -R source bookmarks -r 1 DIVERGED
836 836
837 837 $ hg clone -U source repo1
838 838
839 839 (test that incoming/outgoing exit with 1, if there is no bookmark to
840 840 be exchanged)
841 841
842 842 $ hg -R repo1 incoming -B
843 843 comparing with $TESTTMP/bmcomparison/source
844 844 searching for changed bookmarks
845 845 no changed bookmarks found
846 846 [1]
847 847 $ hg -R repo1 outgoing -B
848 848 comparing with $TESTTMP/bmcomparison/source
849 849 searching for changed bookmarks
850 850 no changed bookmarks found
851 851 [1]
852 852
853 853 $ hg -R repo1 bookmarks -f -r 1 ADD_ON_REPO1
854 854 $ hg -R repo1 bookmarks -f -r 2 ADV_ON_REPO1
855 855 $ hg -R repo1 bookmarks -f -r 3 DIFF_ADV_ON_REPO1
856 856 $ hg -R repo1 bookmarks -f -r 3 DIFF_DIVERGED
857 857 $ hg -R repo1 -q --config extensions.mq= strip 4
858 858 $ hg -R repo1 log -G --template '{node|short} ({bookmarks})'
859 859 o 6100d3090acf (DIFF_ADV_ON_REPO1 DIFF_DIVERGED)
860 860 |
861 861 | o fa942426a6fd (ADV_ON_REPO1)
862 862 |/
863 863 | o 66f7d451a68b (ADD_ON_REPO1 DIVERGED)
864 864 |/
865 865 o 1ea73414a91b (ADV_ON_REPO2 DIFF_ADV_ON_REPO2 SAME)
866 866
867 867
868 868 $ hg clone -U source repo2
869 869 $ hg -R repo2 bookmarks -f -r 1 ADD_ON_REPO2
870 870 $ hg -R repo2 bookmarks -f -r 1 ADV_ON_REPO2
871 871 $ hg -R repo2 bookmarks -f -r 2 DIVERGED
872 872 $ hg -R repo2 bookmarks -f -r 4 DIFF_ADV_ON_REPO2
873 873 $ hg -R repo2 bookmarks -f -r 4 DIFF_DIVERGED
874 874 $ hg -R repo2 -q --config extensions.mq= strip 3
875 875 $ hg -R repo2 log -G --template '{node|short} ({bookmarks})'
876 876 o e7bd5218ca15 (DIFF_ADV_ON_REPO2 DIFF_DIVERGED)
877 877 |
878 878 | o fa942426a6fd (DIVERGED)
879 879 |/
880 880 | o 66f7d451a68b (ADD_ON_REPO2 ADV_ON_REPO2)
881 881 |/
882 882 o 1ea73414a91b (ADV_ON_REPO1 DIFF_ADV_ON_REPO1 SAME)
883 883
884 884
885 885 (test that difference of bookmarks between repositories are fully shown)
886 886
887 887 $ hg -R repo1 incoming -B repo2 -v
888 888 comparing with repo2
889 889 searching for changed bookmarks
890 890 ADD_ON_REPO2 66f7d451a68b added
891 891 ADV_ON_REPO2 66f7d451a68b advanced
892 892 DIFF_ADV_ON_REPO2 e7bd5218ca15 changed
893 893 DIFF_DIVERGED e7bd5218ca15 changed
894 894 DIVERGED fa942426a6fd diverged
895 895 $ hg -R repo1 outgoing -B repo2 -v
896 896 comparing with repo2
897 897 searching for changed bookmarks
898 898 ADD_ON_REPO1 66f7d451a68b added
899 899 ADD_ON_REPO2 deleted
900 900 ADV_ON_REPO1 fa942426a6fd advanced
901 901 DIFF_ADV_ON_REPO1 6100d3090acf advanced
902 902 DIFF_ADV_ON_REPO2 1ea73414a91b changed
903 903 DIFF_DIVERGED 6100d3090acf changed
904 904 DIVERGED 66f7d451a68b diverged
905 905
906 906 $ hg -R repo2 incoming -B repo1 -v
907 907 comparing with repo1
908 908 searching for changed bookmarks
909 909 ADD_ON_REPO1 66f7d451a68b added
910 910 ADV_ON_REPO1 fa942426a6fd advanced
911 911 DIFF_ADV_ON_REPO1 6100d3090acf changed
912 912 DIFF_DIVERGED 6100d3090acf changed
913 913 DIVERGED 66f7d451a68b diverged
914 914 $ hg -R repo2 outgoing -B repo1 -v
915 915 comparing with repo1
916 916 searching for changed bookmarks
917 917 ADD_ON_REPO1 deleted
918 918 ADD_ON_REPO2 66f7d451a68b added
919 919 ADV_ON_REPO2 66f7d451a68b advanced
920 920 DIFF_ADV_ON_REPO1 1ea73414a91b changed
921 921 DIFF_ADV_ON_REPO2 e7bd5218ca15 advanced
922 922 DIFF_DIVERGED e7bd5218ca15 changed
923 923 DIVERGED fa942426a6fd diverged
924 924
925 925 $ cd ..
926 926
927 927 Pushing a bookmark should only push the changes required by that
928 928 bookmark, not all outgoing changes:
929 929 $ hg clone http://localhost:$HGPORT/ addmarks
930 930 requesting all changes
931 931 adding changesets
932 932 adding manifests
933 933 adding file changes
934 934 added 5 changesets with 5 changes to 3 files (+2 heads)
935 935 2 new obsolescence markers
936 936 new changesets 4e3505fd9583:c922c0139ca0
937 937 updating to bookmark @
938 938 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
939 939 $ cd addmarks
940 940 $ echo foo > foo
941 941 $ hg add foo
942 942 $ hg commit -m 'add foo'
943 943 $ echo bar > bar
944 944 $ hg add bar
945 945 $ hg commit -m 'add bar'
946 946 $ hg co "tip^"
947 947 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
948 948 (leaving bookmark @)
949 949 $ hg book add-foo
950 950 $ hg book -r tip add-bar
951 951 Note: this push *must* push only a single changeset, as that's the point
952 952 of this test.
953 953 $ hg push -B add-foo --traceback
954 954 pushing to http://localhost:$HGPORT/
955 955 searching for changes
956 956 remote: adding changesets
957 957 remote: adding manifests
958 958 remote: adding file changes
959 959 remote: added 1 changesets with 1 changes to 1 files
960 960 exporting bookmark add-foo
961 961
962 962 pushing a new bookmark on a new head does not require -f if -B is specified
963 963
964 964 $ hg up -q X
965 965 $ hg book W
966 966 $ echo c5 > f2
967 967 $ hg ci -Am5
968 968 created new head
969 969 $ hg push -B .
970 970 pushing to http://localhost:$HGPORT/
971 971 searching for changes
972 972 remote: adding changesets
973 973 remote: adding manifests
974 974 remote: adding file changes
975 975 remote: added 1 changesets with 1 changes to 1 files (+1 heads)
976 976 exporting bookmark W
977 977 $ hg -R ../b id -r W
978 978 cc978a373a53 tip W
979 979
980 980 pushing an existing but divergent bookmark with -B still requires -f
981 981
982 982 $ hg clone -q . ../r
983 983 $ hg up -q X
984 984 $ echo 1 > f2
985 985 $ hg ci -qAml
986 986
987 987 $ cd ../r
988 988 $ hg up -q X
989 989 $ echo 2 > f2
990 990 $ hg ci -qAmr
991 991 $ hg push -B X
992 992 pushing to $TESTTMP/addmarks
993 993 searching for changes
994 994 remote has heads on branch 'default' that are not known locally: a2a606d9ff1b
995 995 abort: push creates new remote head 54694f811df9 with bookmark 'X'!
996 996 (pull and merge or see 'hg help push' for details about pushing new heads)
997 997 [255]
998 998 $ cd ../addmarks
999 999
1000 1000 Check summary output for incoming/outgoing bookmarks
1001 1001
1002 1002 $ hg bookmarks -d X
1003 1003 $ hg bookmarks -d Y
1004 1004 $ hg summary --remote | grep '^remote:'
1005 1005 remote: *, 2 incoming bookmarks, 1 outgoing bookmarks (glob)
1006 1006
1007 1007 $ cd ..
1008 1008
1009 1009 pushing an unchanged bookmark should result in no changes
1010 1010
1011 1011 $ hg init unchanged-a
1012 1012 $ hg init unchanged-b
1013 1013 $ cd unchanged-a
1014 1014 $ echo initial > foo
1015 1015 $ hg commit -A -m initial
1016 1016 adding foo
1017 1017 $ hg bookmark @
1018 1018 $ hg push -B @ ../unchanged-b
1019 1019 pushing to ../unchanged-b
1020 1020 searching for changes
1021 1021 adding changesets
1022 1022 adding manifests
1023 1023 adding file changes
1024 1024 added 1 changesets with 1 changes to 1 files
1025 1025 exporting bookmark @
1026 1026
1027 1027 $ hg push -B @ ../unchanged-b
1028 1028 pushing to ../unchanged-b
1029 1029 searching for changes
1030 1030 no changes found
1031 1031 [1]
1032 1032
1033 1033 Pushing a really long bookmark should work fine (issue5165)
1034 1034 ===============================================
1035 1035
1036 1036 #if b2-binary
1037 1037 >>> with open('longname', 'w') as f:
1038 1038 ... f.write('wat' * 100) and None
1039 1039 $ hg book `cat longname`
1040 1040 $ hg push -B `cat longname` ../unchanged-b
1041 1041 pushing to ../unchanged-b
1042 1042 searching for changes
1043 1043 no changes found
1044 1044 exporting bookmark (wat){100} (re)
1045 1045 [1]
1046 1046 $ hg -R ../unchanged-b book --delete `cat longname`
1047 1047
1048 1048 Test again but forcing bundle2 exchange to make sure that doesn't regress.
1049 1049
1050 1050 $ hg push -B `cat longname` ../unchanged-b --config devel.legacy.exchange=bundle1
1051 1051 pushing to ../unchanged-b
1052 1052 searching for changes
1053 1053 no changes found
1054 1054 exporting bookmark (wat){100} (re)
1055 1055 [1]
1056 1056 $ hg -R ../unchanged-b book --delete `cat longname`
1057 1057 $ hg book --delete `cat longname`
1058 1058 $ hg co @
1059 1059 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1060 1060 (activating bookmark @)
1061 1061 #endif
1062 1062
1063 1063 Check hook preventing push (issue4455)
1064 1064 ======================================
1065 1065
1066 1066 $ hg bookmarks
1067 1067 * @ 0:55482a6fb4b1
1068 1068 $ hg log -G
1069 1069 @ 0:55482a6fb4b1 initial
1070 1070
1071 1071 $ hg init ../issue4455-dest
1072 1072 $ hg push ../issue4455-dest # changesets only
1073 1073 pushing to ../issue4455-dest
1074 1074 searching for changes
1075 1075 adding changesets
1076 1076 adding manifests
1077 1077 adding file changes
1078 1078 added 1 changesets with 1 changes to 1 files
1079 1079 $ cat >> .hg/hgrc << EOF
1080 1080 > [paths]
1081 1081 > local=../issue4455-dest/
1082 1082 > ssh=ssh://user@dummy/issue4455-dest
1083 1083 > http=http://localhost:$HGPORT/
1084 1084 > [ui]
1085 1085 > ssh=$PYTHON "$TESTDIR/dummyssh"
1086 1086 > EOF
1087 1087 $ cat >> ../issue4455-dest/.hg/hgrc << EOF
1088 1088 > [hooks]
1089 1089 > prepushkey=false
1090 1090 > [web]
1091 1091 > push_ssl = false
1092 1092 > allow_push = *
1093 1093 > EOF
1094 1094 $ killdaemons.py
1095 1095 $ hg serve -R ../issue4455-dest -p $HGPORT -d --pid-file=../issue4455.pid -E ../issue4455-error.log
1096 1096 $ cat ../issue4455.pid >> $DAEMON_PIDS
1097 1097
1098 1098 Local push
1099 1099 ----------
1100 1100
1101 1101 #if b2-pushkey
1102 1102
1103 1103 $ hg push -B @ local
1104 1104 pushing to $TESTTMP/issue4455-dest
1105 1105 searching for changes
1106 1106 no changes found
1107 1107 pushkey-abort: prepushkey hook exited with status 1
1108 1108 abort: exporting bookmark @ failed!
1109 1109 [255]
1110 1110
1111 1111 #endif
1112 1112 #if b2-binary
1113 1113
1114 1114 $ hg push -B @ local
1115 1115 pushing to $TESTTMP/issue4455-dest
1116 1116 searching for changes
1117 1117 no changes found
1118 1118 abort: prepushkey hook exited with status 1
1119 1119 [255]
1120 1120
1121 1121 #endif
1122 1122
1123 1123 $ hg -R ../issue4455-dest/ bookmarks
1124 1124 no bookmarks set
1125 1125
1126 1126 Using ssh
1127 1127 ---------
1128 1128
1129 1129 #if b2-pushkey
1130 1130
1131 1131 $ hg push -B @ ssh # bundle2+
1132 1132 pushing to ssh://user@dummy/issue4455-dest
1133 1133 searching for changes
1134 1134 no changes found
1135 1135 remote: pushkey-abort: prepushkey hook exited with status 1
1136 1136 abort: exporting bookmark @ failed!
1137 1137 [255]
1138 1138
1139 1139 $ hg -R ../issue4455-dest/ bookmarks
1140 1140 no bookmarks set
1141 1141
1142 1142 $ hg push -B @ ssh --config devel.legacy.exchange=bundle1
1143 1143 pushing to ssh://user@dummy/issue4455-dest
1144 1144 searching for changes
1145 1145 no changes found
1146 1146 remote: pushkey-abort: prepushkey hook exited with status 1
1147 1147 exporting bookmark @ failed!
1148 1148 [1]
1149 1149
1150 1150 #endif
1151 1151 #if b2-binary
1152 1152
1153 1153 $ hg push -B @ ssh # bundle2+
1154 1154 pushing to ssh://user@dummy/issue4455-dest
1155 1155 searching for changes
1156 1156 no changes found
1157 1157 remote: prepushkey hook exited with status 1
1158 1158 abort: push failed on remote
1159 1159 [255]
1160 1160
1161 1161 #endif
1162 1162
1163 1163 $ hg -R ../issue4455-dest/ bookmarks
1164 1164 no bookmarks set
1165 1165
1166 1166 Using http
1167 1167 ----------
1168 1168
1169 1169 #if b2-pushkey
1170 1170 $ hg push -B @ http # bundle2+
1171 1171 pushing to http://localhost:$HGPORT/
1172 1172 searching for changes
1173 1173 no changes found
1174 1174 remote: pushkey-abort: prepushkey hook exited with status 1
1175 1175 abort: exporting bookmark @ failed!
1176 1176 [255]
1177 1177
1178 1178 $ hg -R ../issue4455-dest/ bookmarks
1179 1179 no bookmarks set
1180 1180
1181 1181 $ hg push -B @ http --config devel.legacy.exchange=bundle1
1182 1182 pushing to http://localhost:$HGPORT/
1183 1183 searching for changes
1184 1184 no changes found
1185 1185 remote: pushkey-abort: prepushkey hook exited with status 1
1186 1186 exporting bookmark @ failed!
1187 1187 [1]
1188 1188
1189 1189 #endif
1190 1190
1191 1191 #if b2-binary
1192 1192
1193 1193 $ hg push -B @ ssh # bundle2+
1194 1194 pushing to ssh://user@dummy/issue4455-dest
1195 1195 searching for changes
1196 1196 no changes found
1197 1197 remote: prepushkey hook exited with status 1
1198 1198 abort: push failed on remote
1199 1199 [255]
1200 1200
1201 1201 #endif
1202 1202
1203 1203 $ hg -R ../issue4455-dest/ bookmarks
1204 1204 no bookmarks set
1205 1205
1206 1206 $ cd ..
1207 1207
1208 1208 Test that pre-pushkey compat for bookmark works as expected (issue5777)
1209 1209
1210 1210 $ cat << EOF >> $HGRCPATH
1211 1211 > [ui]
1212 1212 > ssh="$PYTHON" "$TESTDIR/dummyssh"
1213 1213 > [server]
1214 1214 > bookmarks-pushkey-compat = yes
1215 1215 > EOF
1216 1216
1217 1217 $ hg init server
1218 1218 $ echo foo > server/a
1219 1219 $ hg -R server book foo
1220 1220 $ hg -R server commit -Am a
1221 1221 adding a
1222 1222 $ hg clone ssh://user@dummy/server client
1223 1223 requesting all changes
1224 1224 adding changesets
1225 1225 adding manifests
1226 1226 adding file changes
1227 1227 added 1 changesets with 1 changes to 1 files
1228 1228 new changesets 79513d0d7716
1229 1229 updating to branch default
1230 1230 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1231 1231
1232 1232 Forbid bookmark move on the server
1233 1233
1234 1234 $ cat << EOF >> $TESTDIR/no-bm-move.sh
1235 1235 > #!/bin/sh
1236 1236 > echo \$HG_NAMESPACE | grep -v bookmarks
1237 1237 > EOF
1238 1238 $ cat << EOF >> server/.hg/hgrc
1239 1239 > [hooks]
1240 1240 > prepushkey.no-bm-move= sh $TESTDIR/no-bm-move.sh
1241 1241 > EOF
1242 1242
1243 1243 pushing changeset is okay
1244 1244
1245 1245 $ echo bar >> client/a
1246 1246 $ hg -R client commit -m b
1247 1247 $ hg -R client push
1248 1248 pushing to ssh://user@dummy/server
1249 1249 searching for changes
1250 1250 remote: adding changesets
1251 1251 remote: adding manifests
1252 1252 remote: adding file changes
1253 1253 remote: added 1 changesets with 1 changes to 1 files
1254 1254
1255 1255 attempt to move the bookmark is rejected
1256 1256
1257 1257 $ hg -R client book foo -r .
1258 1258 moving bookmark 'foo' forward from 79513d0d7716
1259 1259
1260 1260 #if b2-pushkey
1261 1261 $ hg -R client push
1262 1262 pushing to ssh://user@dummy/server
1263 1263 searching for changes
1264 1264 no changes found
1265 1265 remote: pushkey-abort: prepushkey.no-bm-move hook exited with status 1
1266 1266 abort: updating bookmark foo failed!
1267 1267 [255]
1268 1268 #endif
1269 1269 #if b2-binary
1270 1270 $ hg -R client push
1271 1271 pushing to ssh://user@dummy/server
1272 1272 searching for changes
1273 1273 no changes found
1274 1274 remote: prepushkey.no-bm-move hook exited with status 1
1275 1275 abort: push failed on remote
1276 1276 [255]
1277 1277 #endif
@@ -1,1216 +1,1213 b''
1 1
2 2 $ hg init repo
3 3 $ cd repo
4 4
5 5 $ cat > $TESTTMP/hook.sh <<'EOF'
6 6 > echo "test-hook-bookmark: $HG_BOOKMARK: $HG_OLDNODE -> $HG_NODE"
7 7 > EOF
8 8 $ TESTHOOK="hooks.txnclose-bookmark.test=sh $TESTTMP/hook.sh"
9 9
10 10 no bookmarks
11 11
12 12 $ hg bookmarks
13 13 no bookmarks set
14 14
15 15 $ hg bookmarks -Tjson
16 16 [
17 17 ]
18 18
19 19 bookmark rev -1
20 20
21 21 $ hg bookmark X --config "$TESTHOOK"
22 22 test-hook-bookmark: X: -> 0000000000000000000000000000000000000000
23 23
24 24 list bookmarks
25 25
26 26 $ hg bookmarks
27 27 * X -1:000000000000
28 28
29 29 list bookmarks with color
30 30
31 31 $ hg --config extensions.color= --config color.mode=ansi \
32 32 > bookmarks --color=always
33 33 \x1b[0;32m * \x1b[0m\x1b[0;32mX\x1b[0m\x1b[0;32m -1:000000000000\x1b[0m (esc)
34 34
35 35 $ echo a > a
36 36 $ hg add a
37 37 $ hg commit -m 0 --config "$TESTHOOK"
38 38 test-hook-bookmark: X: 0000000000000000000000000000000000000000 -> f7b1eb17ad24730a1651fccd46c43826d1bbc2ac
39 39
40 40 bookmark X moved to rev 0
41 41
42 42 $ hg bookmarks
43 43 * X 0:f7b1eb17ad24
44 44
45 45 look up bookmark
46 46
47 47 $ hg log -r X
48 48 changeset: 0:f7b1eb17ad24
49 49 bookmark: X
50 50 tag: tip
51 51 user: test
52 52 date: Thu Jan 01 00:00:00 1970 +0000
53 53 summary: 0
54 54
55 55
56 56 second bookmark for rev 0, command should work even with ui.strict on
57 57
58 58 $ hg --config ui.strict=1 bookmark X2 --config "$TESTHOOK"
59 59 test-hook-bookmark: X2: -> f7b1eb17ad24730a1651fccd46c43826d1bbc2ac
60 60
61 61 bookmark rev -1 again
62 62
63 63 $ hg bookmark -r null Y
64 64
65 65 list bookmarks
66 66
67 67 $ hg bookmarks
68 68 X 0:f7b1eb17ad24
69 69 * X2 0:f7b1eb17ad24
70 70 Y -1:000000000000
71 71 $ hg log -T '{bookmarks % "{rev} {bookmark}\n"}'
72 72 0 X
73 73 0 X2
74 74
75 75 $ echo b > b
76 76 $ hg add b
77 77 $ hg commit -m 1 --config "$TESTHOOK"
78 78 test-hook-bookmark: X2: f7b1eb17ad24730a1651fccd46c43826d1bbc2ac -> 925d80f479bb026b0fb3deb27503780b13f74123
79 79
80 80 $ hg bookmarks -T '{rev}:{node|shortest} {bookmark} {desc|firstline}\n'
81 81 0:f7b1 X 0
82 82 1:925d X2 1
83 83 -1:0000 Y
84 84
85 85 $ hg bookmarks -Tjson
86 86 [
87 87 {
88 88 "active": false,
89 89 "bookmark": "X",
90 90 "node": "f7b1eb17ad24730a1651fccd46c43826d1bbc2ac",
91 91 "rev": 0
92 92 },
93 93 {
94 94 "active": true,
95 95 "bookmark": "X2",
96 96 "node": "925d80f479bb026b0fb3deb27503780b13f74123",
97 97 "rev": 1
98 98 },
99 99 {
100 100 "active": false,
101 101 "bookmark": "Y",
102 102 "node": "0000000000000000000000000000000000000000",
103 103 "rev": -1
104 104 }
105 105 ]
106 106
107 107 bookmarks revset
108 108
109 109 $ hg log -r 'bookmark()'
110 110 changeset: 0:f7b1eb17ad24
111 111 bookmark: X
112 112 user: test
113 113 date: Thu Jan 01 00:00:00 1970 +0000
114 114 summary: 0
115 115
116 116 changeset: 1:925d80f479bb
117 117 bookmark: X2
118 118 tag: tip
119 119 user: test
120 120 date: Thu Jan 01 00:00:00 1970 +0000
121 121 summary: 1
122 122
123 123 $ hg log -r 'bookmark(Y)'
124 124 $ hg log -r 'bookmark(X2)'
125 125 changeset: 1:925d80f479bb
126 126 bookmark: X2
127 127 tag: tip
128 128 user: test
129 129 date: Thu Jan 01 00:00:00 1970 +0000
130 130 summary: 1
131 131
132 132 $ hg log -r 'bookmark("re:X")'
133 133 changeset: 0:f7b1eb17ad24
134 134 bookmark: X
135 135 user: test
136 136 date: Thu Jan 01 00:00:00 1970 +0000
137 137 summary: 0
138 138
139 139 changeset: 1:925d80f479bb
140 140 bookmark: X2
141 141 tag: tip
142 142 user: test
143 143 date: Thu Jan 01 00:00:00 1970 +0000
144 144 summary: 1
145 145
146 146 $ hg log -r 'bookmark("literal:X")'
147 147 changeset: 0:f7b1eb17ad24
148 148 bookmark: X
149 149 user: test
150 150 date: Thu Jan 01 00:00:00 1970 +0000
151 151 summary: 0
152 152
153 153
154 154 "." is expanded to the active bookmark:
155 155
156 156 $ hg log -r 'bookmark(.)'
157 157 changeset: 1:925d80f479bb
158 158 bookmark: X2
159 159 tag: tip
160 160 user: test
161 161 date: Thu Jan 01 00:00:00 1970 +0000
162 162 summary: 1
163 163
164 164
165 165 but "literal:." is not since "." seems not a literal bookmark:
166 166
167 167 $ hg log -r 'bookmark("literal:.")'
168 168 abort: bookmark '.' does not exist!
169 169 [255]
170 170
171 171 "." should fail if there's no active bookmark:
172 172
173 173 $ hg bookmark --inactive
174 174 $ hg log -r 'bookmark(.)'
175 abort: no active bookmark
175 abort: no active bookmark!
176 176 [255]
177 BUG: this should be resolved to an empty set:
178 177 $ hg log -r 'present(bookmark(.))'
179 abort: no active bookmark
180 [255]
181 178
182 179 $ hg log -r 'bookmark(unknown)'
183 180 abort: bookmark 'unknown' does not exist!
184 181 [255]
185 182 $ hg log -r 'bookmark("literal:unknown")'
186 183 abort: bookmark 'unknown' does not exist!
187 184 [255]
188 185 $ hg log -r 'bookmark("re:unknown")'
189 186 abort: no bookmarks exist that match 'unknown'!
190 187 [255]
191 188 $ hg log -r 'present(bookmark("literal:unknown"))'
192 189 $ hg log -r 'present(bookmark("re:unknown"))'
193 190
194 191 $ hg help revsets | grep 'bookmark('
195 192 "bookmark([name])"
196 193
197 194 reactivate "X2"
198 195
199 196 $ hg update X2
200 197 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
201 198 (activating bookmark X2)
202 199
203 200 bookmarks X and X2 moved to rev 1, Y at rev -1
204 201
205 202 $ hg bookmarks
206 203 X 0:f7b1eb17ad24
207 204 * X2 1:925d80f479bb
208 205 Y -1:000000000000
209 206
210 207 bookmark rev 0 again
211 208
212 209 $ hg bookmark -r 0 Z
213 210
214 211 $ hg update X
215 212 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
216 213 (activating bookmark X)
217 214 $ echo c > c
218 215 $ hg add c
219 216 $ hg commit -m 2
220 217 created new head
221 218
222 219 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
223 220
224 221 $ hg bookmarks
225 222 * X 2:db815d6d32e6
226 223 X2 1:925d80f479bb
227 224 Y -1:000000000000
228 225 Z 0:f7b1eb17ad24
229 226
230 227 rename nonexistent bookmark
231 228
232 229 $ hg bookmark -m A B
233 230 abort: bookmark 'A' does not exist
234 231 [255]
235 232
236 233 rename to existent bookmark
237 234
238 235 $ hg bookmark -m X Y
239 236 abort: bookmark 'Y' already exists (use -f to force)
240 237 [255]
241 238
242 239 force rename to existent bookmark
243 240
244 241 $ hg bookmark -f -m X Y
245 242
246 243 rename bookmark using .
247 244
248 245 $ hg book rename-me
249 246 $ hg book -m . renamed --config "$TESTHOOK"
250 247 test-hook-bookmark: rename-me: db815d6d32e69058eadefc8cffbad37675707975 ->
251 248 test-hook-bookmark: renamed: -> db815d6d32e69058eadefc8cffbad37675707975
252 249 $ hg bookmark
253 250 X2 1:925d80f479bb
254 251 Y 2:db815d6d32e6
255 252 Z 0:f7b1eb17ad24
256 253 * renamed 2:db815d6d32e6
257 254 $ hg up -q Y
258 255 $ hg book -d renamed --config "$TESTHOOK"
259 256 test-hook-bookmark: renamed: db815d6d32e69058eadefc8cffbad37675707975 ->
260 257
261 258 rename bookmark using . with no active bookmark
262 259
263 260 $ hg book rename-me
264 261 $ hg book -i rename-me
265 262 $ hg book -m . renamed
266 abort: no active bookmark
263 abort: no active bookmark!
267 264 [255]
268 265 $ hg up -q Y
269 266 $ hg book -d rename-me
270 267
271 268 delete bookmark using .
272 269
273 270 $ hg book delete-me
274 271 $ hg book -d .
275 272 $ hg bookmark
276 273 X2 1:925d80f479bb
277 274 Y 2:db815d6d32e6
278 275 Z 0:f7b1eb17ad24
279 276 $ hg up -q Y
280 277
281 278 delete bookmark using . with no active bookmark
282 279
283 280 $ hg book delete-me
284 281 $ hg book -i delete-me
285 282 $ hg book -d .
286 abort: no active bookmark
283 abort: no active bookmark!
287 284 [255]
288 285 $ hg up -q Y
289 286 $ hg book -d delete-me
290 287
291 288 list bookmarks
292 289
293 290 $ hg bookmark
294 291 X2 1:925d80f479bb
295 292 * Y 2:db815d6d32e6
296 293 Z 0:f7b1eb17ad24
297 294
298 295 bookmarks from a revset
299 296 $ hg bookmark -r '.^1' REVSET
300 297 $ hg bookmark -r ':tip' TIP
301 298 $ hg up -q TIP
302 299 $ hg bookmarks
303 300 REVSET 0:f7b1eb17ad24
304 301 * TIP 2:db815d6d32e6
305 302 X2 1:925d80f479bb
306 303 Y 2:db815d6d32e6
307 304 Z 0:f7b1eb17ad24
308 305
309 306 $ hg bookmark -d REVSET
310 307 $ hg bookmark -d TIP
311 308
312 309 rename without new name or multiple names
313 310
314 311 $ hg bookmark -m Y
315 312 abort: new bookmark name required
316 313 [255]
317 314 $ hg bookmark -m Y Y2 Y3
318 315 abort: only one new bookmark name allowed
319 316 [255]
320 317
321 318 delete without name
322 319
323 320 $ hg bookmark -d
324 321 abort: bookmark name required
325 322 [255]
326 323
327 324 delete nonexistent bookmark
328 325
329 326 $ hg bookmark -d A
330 327 abort: bookmark 'A' does not exist
331 328 [255]
332 329
333 330 bookmark name with spaces should be stripped
334 331
335 332 $ hg bookmark ' x y '
336 333
337 334 list bookmarks
338 335
339 336 $ hg bookmarks
340 337 X2 1:925d80f479bb
341 338 Y 2:db815d6d32e6
342 339 Z 0:f7b1eb17ad24
343 340 * x y 2:db815d6d32e6
344 341 $ hg log -T '{bookmarks % "{rev} {bookmark}\n"}'
345 342 2 Y
346 343 2 x y
347 344 1 X2
348 345 0 Z
349 346
350 347 look up stripped bookmark name
351 348
352 349 $ hg log -r '"x y"'
353 350 changeset: 2:db815d6d32e6
354 351 bookmark: Y
355 352 bookmark: x y
356 353 tag: tip
357 354 parent: 0:f7b1eb17ad24
358 355 user: test
359 356 date: Thu Jan 01 00:00:00 1970 +0000
360 357 summary: 2
361 358
362 359
363 360 reject bookmark name with newline
364 361
365 362 $ hg bookmark '
366 363 > '
367 364 abort: bookmark names cannot consist entirely of whitespace
368 365 [255]
369 366
370 367 $ hg bookmark -m Z '
371 368 > '
372 369 abort: bookmark names cannot consist entirely of whitespace
373 370 [255]
374 371
375 372 bookmark with reserved name
376 373
377 374 $ hg bookmark tip
378 375 abort: the name 'tip' is reserved
379 376 [255]
380 377
381 378 $ hg bookmark .
382 379 abort: the name '.' is reserved
383 380 [255]
384 381
385 382 $ hg bookmark null
386 383 abort: the name 'null' is reserved
387 384 [255]
388 385
389 386
390 387 bookmark with existing name
391 388
392 389 $ hg bookmark X2
393 390 abort: bookmark 'X2' already exists (use -f to force)
394 391 [255]
395 392
396 393 $ hg bookmark -m Y Z
397 394 abort: bookmark 'Z' already exists (use -f to force)
398 395 [255]
399 396
400 397 bookmark with name of branch
401 398
402 399 $ hg bookmark default
403 400 abort: a bookmark cannot have the name of an existing branch
404 401 [255]
405 402
406 403 $ hg bookmark -m Y default
407 404 abort: a bookmark cannot have the name of an existing branch
408 405 [255]
409 406
410 407 bookmark with integer name
411 408
412 409 $ hg bookmark 10
413 410 abort: cannot use an integer as a name
414 411 [255]
415 412
416 413 bookmark with a name that matches a node id
417 414 $ hg bookmark 925d80f479bb db815d6d32e6 --config "$TESTHOOK"
418 415 bookmark 925d80f479bb matches a changeset hash
419 416 (did you leave a -r out of an 'hg bookmark' command?)
420 417 bookmark db815d6d32e6 matches a changeset hash
421 418 (did you leave a -r out of an 'hg bookmark' command?)
422 419 test-hook-bookmark: 925d80f479bb: -> db815d6d32e69058eadefc8cffbad37675707975
423 420 test-hook-bookmark: db815d6d32e6: -> db815d6d32e69058eadefc8cffbad37675707975
424 421 $ hg bookmark -d 925d80f479bb
425 422 $ hg bookmark -d db815d6d32e6
426 423
427 424 $ cd ..
428 425
429 426 bookmark with a name that matches an ambiguous node id
430 427
431 428 $ hg init ambiguous
432 429 $ cd ambiguous
433 430 $ echo 0 > a
434 431 $ hg ci -qAm 0
435 432 $ for i in 1057 2857 4025; do
436 433 > hg up -q 0
437 434 > echo $i > a
438 435 > hg ci -qm $i
439 436 > done
440 437 $ hg up -q null
441 438 $ hg log -r0: -T '{rev}:{node}\n'
442 439 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
443 440 1:c56256a09cd28e5764f32e8e2810d0f01e2e357a
444 441 2:c5623987d205cd6d9d8389bfc40fff9dbb670b48
445 442 3:c562ddd9c94164376c20b86b0b4991636a3bf84f
446 443
447 444 $ hg bookmark -r0 c562
448 445 $ hg bookmarks
449 446 c562 0:b4e73ffab476
450 447
451 448 $ cd ..
452 449
453 450 incompatible options
454 451
455 452 $ cd repo
456 453
457 454 $ hg bookmark -m Y -d Z
458 455 abort: --delete and --rename are incompatible
459 456 [255]
460 457
461 458 $ hg bookmark -r 1 -d Z
462 459 abort: --rev is incompatible with --delete
463 460 [255]
464 461
465 462 $ hg bookmark -r 1 -m Z Y
466 463 abort: --rev is incompatible with --rename
467 464 [255]
468 465
469 466 force bookmark with existing name
470 467
471 468 $ hg bookmark -f X2 --config "$TESTHOOK"
472 469 test-hook-bookmark: X2: 925d80f479bb026b0fb3deb27503780b13f74123 -> db815d6d32e69058eadefc8cffbad37675707975
473 470
474 471 force bookmark back to where it was, should deactivate it
475 472
476 473 $ hg bookmark -fr1 X2
477 474 $ hg bookmarks
478 475 X2 1:925d80f479bb
479 476 Y 2:db815d6d32e6
480 477 Z 0:f7b1eb17ad24
481 478 x y 2:db815d6d32e6
482 479
483 480 forward bookmark to descendant without --force
484 481
485 482 $ hg bookmark Z
486 483 moving bookmark 'Z' forward from f7b1eb17ad24
487 484
488 485 list bookmarks
489 486
490 487 $ hg bookmark
491 488 X2 1:925d80f479bb
492 489 Y 2:db815d6d32e6
493 490 * Z 2:db815d6d32e6
494 491 x y 2:db815d6d32e6
495 492 $ hg log -T '{bookmarks % "{rev} {bookmark}\n"}'
496 493 2 Y
497 494 2 Z
498 495 2 x y
499 496 1 X2
500 497
501 498 revision but no bookmark name
502 499
503 500 $ hg bookmark -r .
504 501 abort: bookmark name required
505 502 [255]
506 503
507 504 bookmark name with whitespace only
508 505
509 506 $ hg bookmark ' '
510 507 abort: bookmark names cannot consist entirely of whitespace
511 508 [255]
512 509
513 510 $ hg bookmark -m Y ' '
514 511 abort: bookmark names cannot consist entirely of whitespace
515 512 [255]
516 513
517 514 invalid bookmark
518 515
519 516 $ hg bookmark 'foo:bar'
520 517 abort: ':' cannot be used in a name
521 518 [255]
522 519
523 520 $ hg bookmark 'foo
524 521 > bar'
525 522 abort: '\n' cannot be used in a name
526 523 [255]
527 524
528 525 the bookmark extension should be ignored now that it is part of core
529 526
530 527 $ echo "[extensions]" >> $HGRCPATH
531 528 $ echo "bookmarks=" >> $HGRCPATH
532 529 $ hg bookmarks
533 530 X2 1:925d80f479bb
534 531 Y 2:db815d6d32e6
535 532 * Z 2:db815d6d32e6
536 533 x y 2:db815d6d32e6
537 534
538 535 test summary
539 536
540 537 $ hg summary
541 538 parent: 2:db815d6d32e6 tip
542 539 2
543 540 branch: default
544 541 bookmarks: *Z Y x y
545 542 commit: (clean)
546 543 update: 1 new changesets, 2 branch heads (merge)
547 544 phases: 3 draft
548 545
549 546 test id
550 547
551 548 $ hg id
552 549 db815d6d32e6 tip Y/Z/x y
553 550
554 551 test rollback
555 552
556 553 $ echo foo > f1
557 554 $ hg bookmark tmp-rollback
558 555 $ hg ci -Amr
559 556 adding f1
560 557 $ hg bookmarks
561 558 X2 1:925d80f479bb
562 559 Y 2:db815d6d32e6
563 560 Z 2:db815d6d32e6
564 561 * tmp-rollback 3:2bf5cfec5864
565 562 x y 2:db815d6d32e6
566 563 $ hg rollback
567 564 repository tip rolled back to revision 2 (undo commit)
568 565 working directory now based on revision 2
569 566 $ hg bookmarks
570 567 X2 1:925d80f479bb
571 568 Y 2:db815d6d32e6
572 569 Z 2:db815d6d32e6
573 570 * tmp-rollback 2:db815d6d32e6
574 571 x y 2:db815d6d32e6
575 572 $ hg bookmark -f Z -r 1
576 573 $ hg rollback
577 574 repository tip rolled back to revision 2 (undo bookmark)
578 575 $ hg bookmarks
579 576 X2 1:925d80f479bb
580 577 Y 2:db815d6d32e6
581 578 Z 2:db815d6d32e6
582 579 * tmp-rollback 2:db815d6d32e6
583 580 x y 2:db815d6d32e6
584 581 $ hg bookmark -d tmp-rollback
585 582
586 583 activate bookmark on working dir parent without --force
587 584
588 585 $ hg bookmark --inactive Z
589 586 $ hg bookmark Z
590 587
591 588 test clone
592 589
593 590 $ hg bookmark -r 2 -i @
594 591 $ hg bookmark -r 2 -i a@
595 592 $ hg bookmarks
596 593 @ 2:db815d6d32e6
597 594 X2 1:925d80f479bb
598 595 Y 2:db815d6d32e6
599 596 * Z 2:db815d6d32e6
600 597 a@ 2:db815d6d32e6
601 598 x y 2:db815d6d32e6
602 599 $ hg clone . cloned-bookmarks
603 600 updating to bookmark @
604 601 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
605 602 $ hg -R cloned-bookmarks bookmarks
606 603 * @ 2:db815d6d32e6
607 604 X2 1:925d80f479bb
608 605 Y 2:db815d6d32e6
609 606 Z 2:db815d6d32e6
610 607 a@ 2:db815d6d32e6
611 608 x y 2:db815d6d32e6
612 609
613 610 test clone with pull protocol
614 611
615 612 $ hg clone --pull . cloned-bookmarks-pull
616 613 requesting all changes
617 614 adding changesets
618 615 adding manifests
619 616 adding file changes
620 617 added 3 changesets with 3 changes to 3 files (+1 heads)
621 618 new changesets f7b1eb17ad24:db815d6d32e6
622 619 updating to bookmark @
623 620 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
624 621 $ hg -R cloned-bookmarks-pull bookmarks
625 622 * @ 2:db815d6d32e6
626 623 X2 1:925d80f479bb
627 624 Y 2:db815d6d32e6
628 625 Z 2:db815d6d32e6
629 626 a@ 2:db815d6d32e6
630 627 x y 2:db815d6d32e6
631 628
632 629 delete multiple bookmarks at once
633 630
634 631 $ hg bookmark -d @ a@
635 632
636 633 test clone with a bookmark named "default" (issue3677)
637 634
638 635 $ hg bookmark -r 1 -f -i default
639 636 $ hg clone . cloned-bookmark-default
640 637 updating to branch default
641 638 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
642 639 $ hg -R cloned-bookmark-default bookmarks
643 640 X2 1:925d80f479bb
644 641 Y 2:db815d6d32e6
645 642 Z 2:db815d6d32e6
646 643 default 1:925d80f479bb
647 644 x y 2:db815d6d32e6
648 645 $ hg -R cloned-bookmark-default parents -q
649 646 2:db815d6d32e6
650 647 $ hg bookmark -d default
651 648
652 649 test clone with a specific revision
653 650
654 651 $ hg clone -r 925d80 . cloned-bookmarks-rev
655 652 adding changesets
656 653 adding manifests
657 654 adding file changes
658 655 added 2 changesets with 2 changes to 2 files
659 656 new changesets f7b1eb17ad24:925d80f479bb
660 657 updating to branch default
661 658 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
662 659 $ hg -R cloned-bookmarks-rev bookmarks
663 660 X2 1:925d80f479bb
664 661
665 662 test clone with update to a bookmark
666 663
667 664 $ hg clone -u Z . ../cloned-bookmarks-update
668 665 updating to branch default
669 666 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
670 667 $ hg -R ../cloned-bookmarks-update bookmarks
671 668 X2 1:925d80f479bb
672 669 Y 2:db815d6d32e6
673 670 * Z 2:db815d6d32e6
674 671 x y 2:db815d6d32e6
675 672
676 673 create bundle with two heads
677 674
678 675 $ hg clone . tobundle
679 676 updating to branch default
680 677 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
681 678 $ echo x > tobundle/x
682 679 $ hg -R tobundle add tobundle/x
683 680 $ hg -R tobundle commit -m'x'
684 681 $ hg -R tobundle update -r -2
685 682 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
686 683 $ echo y > tobundle/y
687 684 $ hg -R tobundle branch test
688 685 marked working directory as branch test
689 686 (branches are permanent and global, did you want a bookmark?)
690 687 $ hg -R tobundle add tobundle/y
691 688 $ hg -R tobundle commit -m'y'
692 689 $ hg -R tobundle bundle tobundle.hg
693 690 searching for changes
694 691 2 changesets found
695 692 $ hg unbundle tobundle.hg
696 693 adding changesets
697 694 adding manifests
698 695 adding file changes
699 696 added 2 changesets with 2 changes to 2 files (+1 heads)
700 697 new changesets 125c9a1d6df6:9ba5f110a0b3
701 698 (run 'hg heads' to see heads, 'hg merge' to merge)
702 699
703 700 update to active bookmark if it's not the parent
704 701
705 702 (it is known issue that fsmonitor can't handle nested repositories. In
706 703 this test scenario, cloned-bookmark-default and tobundle exist in the
707 704 working directory of current repository)
708 705
709 706 $ hg summary
710 707 parent: 2:db815d6d32e6
711 708 2
712 709 branch: default
713 710 bookmarks: *Z Y x y
714 711 commit: 1 added, 1 unknown (new branch head) (no-fsmonitor !)
715 712 commit: 1 added, * unknown (new branch head) (glob) (fsmonitor !)
716 713 update: 2 new changesets (update)
717 714 phases: 5 draft
718 715 $ hg update
719 716 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
720 717 updating bookmark Z
721 718 $ hg bookmarks
722 719 X2 1:925d80f479bb
723 720 Y 2:db815d6d32e6
724 721 * Z 3:125c9a1d6df6
725 722 x y 2:db815d6d32e6
726 723
727 724 pull --update works the same as pull && update
728 725
729 726 $ hg bookmark -r3 Y
730 727 moving bookmark 'Y' forward from db815d6d32e6
731 728 $ cp -R ../cloned-bookmarks-update ../cloned-bookmarks-manual-update
732 729 $ cp -R ../cloned-bookmarks-update ../cloned-bookmarks-manual-update-with-divergence
733 730
734 731 (manual version)
735 732
736 733 $ hg -R ../cloned-bookmarks-manual-update update Y
737 734 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
738 735 (activating bookmark Y)
739 736 $ hg -R ../cloned-bookmarks-manual-update pull .
740 737 pulling from .
741 738 searching for changes
742 739 adding changesets
743 740 adding manifests
744 741 adding file changes
745 742 added 2 changesets with 2 changes to 2 files (+1 heads)
746 743 updating bookmark Y
747 744 updating bookmark Z
748 745 new changesets 125c9a1d6df6:9ba5f110a0b3
749 746 (run 'hg heads' to see heads, 'hg merge' to merge)
750 747
751 748 (# tests strange but with --date crashing when bookmark have to move)
752 749
753 750 $ hg -R ../cloned-bookmarks-manual-update update -d 1986
754 751 abort: revision matching date not found
755 752 [255]
756 753 $ hg -R ../cloned-bookmarks-manual-update update
757 754 updating to active bookmark Y
758 755 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
759 756
760 757 (all in one version)
761 758
762 759 $ hg -R ../cloned-bookmarks-update update Y
763 760 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
764 761 (activating bookmark Y)
765 762 $ hg -R ../cloned-bookmarks-update pull --update .
766 763 pulling from .
767 764 searching for changes
768 765 adding changesets
769 766 adding manifests
770 767 adding file changes
771 768 added 2 changesets with 2 changes to 2 files (+1 heads)
772 769 updating bookmark Y
773 770 updating bookmark Z
774 771 new changesets 125c9a1d6df6:9ba5f110a0b3
775 772 updating to active bookmark Y
776 773 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
777 774
778 775 We warn about divergent during bare update to the active bookmark
779 776
780 777 $ hg -R ../cloned-bookmarks-manual-update-with-divergence update Y
781 778 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
782 779 (activating bookmark Y)
783 780 $ hg -R ../cloned-bookmarks-manual-update-with-divergence bookmarks -r X2 Y@1
784 781 $ hg -R ../cloned-bookmarks-manual-update-with-divergence bookmarks
785 782 X2 1:925d80f479bb
786 783 * Y 2:db815d6d32e6
787 784 Y@1 1:925d80f479bb
788 785 Z 2:db815d6d32e6
789 786 x y 2:db815d6d32e6
790 787 $ hg -R ../cloned-bookmarks-manual-update-with-divergence pull
791 788 pulling from $TESTTMP/repo
792 789 searching for changes
793 790 adding changesets
794 791 adding manifests
795 792 adding file changes
796 793 added 2 changesets with 2 changes to 2 files (+1 heads)
797 794 updating bookmark Y
798 795 updating bookmark Z
799 796 new changesets 125c9a1d6df6:9ba5f110a0b3
800 797 (run 'hg heads' to see heads, 'hg merge' to merge)
801 798 $ hg -R ../cloned-bookmarks-manual-update-with-divergence update
802 799 updating to active bookmark Y
803 800 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
804 801 1 other divergent bookmarks for "Y"
805 802
806 803 test wrongly formated bookmark
807 804
808 805 $ echo '' >> .hg/bookmarks
809 806 $ hg bookmarks
810 807 X2 1:925d80f479bb
811 808 Y 3:125c9a1d6df6
812 809 * Z 3:125c9a1d6df6
813 810 x y 2:db815d6d32e6
814 811 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
815 812 $ hg bookmarks
816 813 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
817 814 X2 1:925d80f479bb
818 815 Y 3:125c9a1d6df6
819 816 * Z 3:125c9a1d6df6
820 817 x y 2:db815d6d32e6
821 818
822 819 test missing revisions
823 820
824 821 $ echo "925d80f479b925d80f479bc925d80f479bccabab z" > .hg/bookmarks
825 822 $ hg book
826 823 no bookmarks set
827 824
828 825 test stripping a non-checked-out but bookmarked revision
829 826
830 827 $ hg log --graph
831 828 o changeset: 4:9ba5f110a0b3
832 829 | branch: test
833 830 | tag: tip
834 831 | parent: 2:db815d6d32e6
835 832 | user: test
836 833 | date: Thu Jan 01 00:00:00 1970 +0000
837 834 | summary: y
838 835 |
839 836 | @ changeset: 3:125c9a1d6df6
840 837 |/ user: test
841 838 | date: Thu Jan 01 00:00:00 1970 +0000
842 839 | summary: x
843 840 |
844 841 o changeset: 2:db815d6d32e6
845 842 | parent: 0:f7b1eb17ad24
846 843 | user: test
847 844 | date: Thu Jan 01 00:00:00 1970 +0000
848 845 | summary: 2
849 846 |
850 847 | o changeset: 1:925d80f479bb
851 848 |/ user: test
852 849 | date: Thu Jan 01 00:00:00 1970 +0000
853 850 | summary: 1
854 851 |
855 852 o changeset: 0:f7b1eb17ad24
856 853 user: test
857 854 date: Thu Jan 01 00:00:00 1970 +0000
858 855 summary: 0
859 856
860 857 $ hg book should-end-on-two
861 858 $ hg co --clean 4
862 859 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
863 860 (leaving bookmark should-end-on-two)
864 861 $ hg book four
865 862 $ hg --config extensions.mq= strip 3
866 863 saved backup bundle to * (glob)
867 864 should-end-on-two should end up pointing to revision 2, as that's the
868 865 tipmost surviving ancestor of the stripped revision.
869 866 $ hg log --graph
870 867 @ changeset: 3:9ba5f110a0b3
871 868 | branch: test
872 869 | bookmark: four
873 870 | tag: tip
874 871 | user: test
875 872 | date: Thu Jan 01 00:00:00 1970 +0000
876 873 | summary: y
877 874 |
878 875 o changeset: 2:db815d6d32e6
879 876 | bookmark: should-end-on-two
880 877 | parent: 0:f7b1eb17ad24
881 878 | user: test
882 879 | date: Thu Jan 01 00:00:00 1970 +0000
883 880 | summary: 2
884 881 |
885 882 | o changeset: 1:925d80f479bb
886 883 |/ user: test
887 884 | date: Thu Jan 01 00:00:00 1970 +0000
888 885 | summary: 1
889 886 |
890 887 o changeset: 0:f7b1eb17ad24
891 888 user: test
892 889 date: Thu Jan 01 00:00:00 1970 +0000
893 890 summary: 0
894 891
895 892
896 893 no-op update doesn't deactivate bookmarks
897 894
898 895 (it is known issue that fsmonitor can't handle nested repositories. In
899 896 this test scenario, cloned-bookmark-default and tobundle exist in the
900 897 working directory of current repository)
901 898
902 899 $ hg bookmarks
903 900 * four 3:9ba5f110a0b3
904 901 should-end-on-two 2:db815d6d32e6
905 902 $ hg up four
906 903 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
907 904 $ hg up
908 905 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
909 906 $ hg sum
910 907 parent: 3:9ba5f110a0b3 tip
911 908 y
912 909 branch: test
913 910 bookmarks: *four
914 911 commit: 2 unknown (clean) (no-fsmonitor !)
915 912 commit: * unknown (clean) (glob) (fsmonitor !)
916 913 update: (current)
917 914 phases: 4 draft
918 915
919 916 test clearing divergent bookmarks of linear ancestors
920 917
921 918 $ hg bookmark Z -r 0
922 919 $ hg bookmark Z@1 -r 1
923 920 $ hg bookmark Z@2 -r 2
924 921 $ hg bookmark Z@3 -r 3
925 922 $ hg book
926 923 Z 0:f7b1eb17ad24
927 924 Z@1 1:925d80f479bb
928 925 Z@2 2:db815d6d32e6
929 926 Z@3 3:9ba5f110a0b3
930 927 * four 3:9ba5f110a0b3
931 928 should-end-on-two 2:db815d6d32e6
932 929 $ hg bookmark Z
933 930 moving bookmark 'Z' forward from f7b1eb17ad24
934 931 $ hg book
935 932 * Z 3:9ba5f110a0b3
936 933 Z@1 1:925d80f479bb
937 934 four 3:9ba5f110a0b3
938 935 should-end-on-two 2:db815d6d32e6
939 936
940 937 test clearing only a single divergent bookmark across branches
941 938
942 939 $ hg book foo -r 1
943 940 $ hg book foo@1 -r 0
944 941 $ hg book foo@2 -r 2
945 942 $ hg book foo@3 -r 3
946 943 $ hg book foo -r foo@3
947 944 $ hg book
948 945 * Z 3:9ba5f110a0b3
949 946 Z@1 1:925d80f479bb
950 947 foo 3:9ba5f110a0b3
951 948 foo@1 0:f7b1eb17ad24
952 949 foo@2 2:db815d6d32e6
953 950 four 3:9ba5f110a0b3
954 951 should-end-on-two 2:db815d6d32e6
955 952
956 953 pull --update works the same as pull && update (case #2)
957 954
958 955 It is assumed that "hg pull" itself doesn't update current active
959 956 bookmark ('Y' in tests below).
960 957
961 958 $ hg pull -q ../cloned-bookmarks-update
962 959 divergent bookmark Z stored as Z@2
963 960
964 961 (pulling revision on another named branch with --update updates
965 962 neither the working directory nor current active bookmark: "no-op"
966 963 case)
967 964
968 965 $ echo yy >> y
969 966 $ hg commit -m yy
970 967
971 968 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
972 969 * Y 3:125c9a1d6df6
973 970 $ hg -R ../cloned-bookmarks-update pull . --update
974 971 pulling from .
975 972 searching for changes
976 973 adding changesets
977 974 adding manifests
978 975 adding file changes
979 976 added 1 changesets with 1 changes to 1 files
980 977 divergent bookmark Z stored as Z@default
981 978 adding remote bookmark foo
982 979 adding remote bookmark four
983 980 adding remote bookmark should-end-on-two
984 981 new changesets 5fb12f0f2d51
985 982 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
986 983 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
987 984 3:125c9a1d6df6
988 985 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
989 986 * Y 3:125c9a1d6df6
990 987
991 988 (pulling revision on current named/topological branch with --update
992 989 updates the working directory and current active bookmark)
993 990
994 991 $ hg update -C -q 125c9a1d6df6
995 992 $ echo xx >> x
996 993 $ hg commit -m xx
997 994
998 995 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
999 996 * Y 3:125c9a1d6df6
1000 997 $ hg -R ../cloned-bookmarks-update pull . --update
1001 998 pulling from .
1002 999 searching for changes
1003 1000 adding changesets
1004 1001 adding manifests
1005 1002 adding file changes
1006 1003 added 1 changesets with 1 changes to 1 files
1007 1004 divergent bookmark Z stored as Z@default
1008 1005 new changesets 81dcce76aa0b
1009 1006 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1010 1007 updating bookmark Y
1011 1008 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
1012 1009 6:81dcce76aa0b
1013 1010 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
1014 1011 * Y 6:81dcce76aa0b
1015 1012
1016 1013 $ cd ..
1017 1014
1018 1015 ensure changelog is written before bookmarks
1019 1016 $ hg init orderrepo
1020 1017 $ cd orderrepo
1021 1018 $ touch a
1022 1019 $ hg commit -Aqm one
1023 1020 $ hg book mybook
1024 1021 $ echo a > a
1025 1022
1026 1023 $ cat > $TESTTMP/pausefinalize.py <<EOF
1027 1024 > from __future__ import absolute_import
1028 1025 > import os
1029 1026 > import time
1030 1027 > from mercurial import extensions, localrepo
1031 1028 > def transaction(orig, self, desc, report=None):
1032 1029 > tr = orig(self, desc, report)
1033 1030 > def sleep(*args, **kwargs):
1034 1031 > retry = 20
1035 1032 > while retry > 0 and not os.path.exists(b"$TESTTMP/unpause"):
1036 1033 > retry -= 1
1037 1034 > time.sleep(0.5)
1038 1035 > if os.path.exists(b"$TESTTMP/unpause"):
1039 1036 > os.remove(b"$TESTTMP/unpause")
1040 1037 > # It is important that this finalizer start with 'a', so it runs before
1041 1038 > # the changelog finalizer appends to the changelog.
1042 1039 > tr.addfinalize(b'a-sleep', sleep)
1043 1040 > return tr
1044 1041 >
1045 1042 > def extsetup(ui):
1046 1043 > # This extension inserts an artifical pause during the transaction
1047 1044 > # finalizer, so we can run commands mid-transaction-close.
1048 1045 > extensions.wrapfunction(localrepo.localrepository, 'transaction',
1049 1046 > transaction)
1050 1047 > EOF
1051 1048 $ hg commit -qm two --config extensions.pausefinalize=$TESTTMP/pausefinalize.py &
1052 1049 $ sleep 2
1053 1050 $ hg log -r .
1054 1051 changeset: 0:867bc5792c8c
1055 1052 bookmark: mybook
1056 1053 tag: tip
1057 1054 user: test
1058 1055 date: Thu Jan 01 00:00:00 1970 +0000
1059 1056 summary: one
1060 1057
1061 1058 $ hg bookmarks
1062 1059 * mybook 0:867bc5792c8c
1063 1060 $ touch $TESTTMP/unpause
1064 1061
1065 1062 $ cd ..
1066 1063
1067 1064 check whether HG_PENDING makes pending changes only in related
1068 1065 repositories visible to an external hook.
1069 1066
1070 1067 (emulate a transaction running concurrently by copied
1071 1068 .hg/bookmarks.pending in subsequent test)
1072 1069
1073 1070 $ cat > $TESTTMP/savepending.sh <<EOF
1074 1071 > cp .hg/bookmarks.pending .hg/bookmarks.pending.saved
1075 1072 > exit 1 # to avoid adding new bookmark for subsequent tests
1076 1073 > EOF
1077 1074
1078 1075 $ hg init unrelated
1079 1076 $ cd unrelated
1080 1077 $ echo a > a
1081 1078 $ hg add a
1082 1079 $ hg commit -m '#0'
1083 1080 $ hg --config hooks.pretxnclose="sh $TESTTMP/savepending.sh" bookmarks INVISIBLE
1084 1081 transaction abort!
1085 1082 rollback completed
1086 1083 abort: pretxnclose hook exited with status 1
1087 1084 [255]
1088 1085 $ cp .hg/bookmarks.pending.saved .hg/bookmarks.pending
1089 1086
1090 1087 (check visible bookmarks while transaction running in repo)
1091 1088
1092 1089 $ cat > $TESTTMP/checkpending.sh <<EOF
1093 1090 > echo "@repo"
1094 1091 > hg -R "$TESTTMP/repo" bookmarks
1095 1092 > echo "@unrelated"
1096 1093 > hg -R "$TESTTMP/unrelated" bookmarks
1097 1094 > exit 1 # to avoid adding new bookmark for subsequent tests
1098 1095 > EOF
1099 1096
1100 1097 $ cd ../repo
1101 1098 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkpending.sh" bookmarks NEW
1102 1099 @repo
1103 1100 * NEW 6:81dcce76aa0b
1104 1101 X2 1:925d80f479bb
1105 1102 Y 4:125c9a1d6df6
1106 1103 Z 5:5fb12f0f2d51
1107 1104 Z@1 1:925d80f479bb
1108 1105 Z@2 4:125c9a1d6df6
1109 1106 foo 3:9ba5f110a0b3
1110 1107 foo@1 0:f7b1eb17ad24
1111 1108 foo@2 2:db815d6d32e6
1112 1109 four 3:9ba5f110a0b3
1113 1110 should-end-on-two 2:db815d6d32e6
1114 1111 x y 2:db815d6d32e6
1115 1112 @unrelated
1116 1113 no bookmarks set
1117 1114 transaction abort!
1118 1115 rollback completed
1119 1116 abort: pretxnclose hook exited with status 1
1120 1117 [255]
1121 1118
1122 1119 Check pretxnclose-bookmark can abort a transaction
1123 1120 --------------------------------------------------
1124 1121
1125 1122 add hooks:
1126 1123
1127 1124 * to prevent NEW bookmark on a non-public changeset
1128 1125 * to prevent non-forward move of NEW bookmark
1129 1126
1130 1127 $ cat << EOF >> .hg/hgrc
1131 1128 > [hooks]
1132 1129 > pretxnclose-bookmark.force-public = sh -c "(echo \$HG_BOOKMARK| grep -v NEW > /dev/null) || [ -z \"\$HG_NODE\" ] || (hg log -r \"\$HG_NODE\" -T '{phase}' | grep public > /dev/null)"
1133 1130 > pretxnclose-bookmark.force-forward = sh -c "(echo \$HG_BOOKMARK| grep -v NEW > /dev/null) || [ -z \"\$HG_NODE\" ] || (hg log -r \"max(\$HG_OLDNODE::\$HG_NODE)\" -T 'MATCH' | grep MATCH > /dev/null)"
1134 1131 > EOF
1135 1132
1136 1133 $ hg log -G -T phases
1137 1134 @ changeset: 6:81dcce76aa0b
1138 1135 | tag: tip
1139 1136 | phase: draft
1140 1137 | parent: 4:125c9a1d6df6
1141 1138 | user: test
1142 1139 | date: Thu Jan 01 00:00:00 1970 +0000
1143 1140 | summary: xx
1144 1141 |
1145 1142 | o changeset: 5:5fb12f0f2d51
1146 1143 | | branch: test
1147 1144 | | bookmark: Z
1148 1145 | | phase: draft
1149 1146 | | parent: 3:9ba5f110a0b3
1150 1147 | | user: test
1151 1148 | | date: Thu Jan 01 00:00:00 1970 +0000
1152 1149 | | summary: yy
1153 1150 | |
1154 1151 o | changeset: 4:125c9a1d6df6
1155 1152 | | bookmark: Y
1156 1153 | | bookmark: Z@2
1157 1154 | | phase: public
1158 1155 | | parent: 2:db815d6d32e6
1159 1156 | | user: test
1160 1157 | | date: Thu Jan 01 00:00:00 1970 +0000
1161 1158 | | summary: x
1162 1159 | |
1163 1160 | o changeset: 3:9ba5f110a0b3
1164 1161 |/ branch: test
1165 1162 | bookmark: foo
1166 1163 | bookmark: four
1167 1164 | phase: public
1168 1165 | user: test
1169 1166 | date: Thu Jan 01 00:00:00 1970 +0000
1170 1167 | summary: y
1171 1168 |
1172 1169 o changeset: 2:db815d6d32e6
1173 1170 | bookmark: foo@2
1174 1171 | bookmark: should-end-on-two
1175 1172 | bookmark: x y
1176 1173 | phase: public
1177 1174 | parent: 0:f7b1eb17ad24
1178 1175 | user: test
1179 1176 | date: Thu Jan 01 00:00:00 1970 +0000
1180 1177 | summary: 2
1181 1178 |
1182 1179 | o changeset: 1:925d80f479bb
1183 1180 |/ bookmark: X2
1184 1181 | bookmark: Z@1
1185 1182 | phase: public
1186 1183 | user: test
1187 1184 | date: Thu Jan 01 00:00:00 1970 +0000
1188 1185 | summary: 1
1189 1186 |
1190 1187 o changeset: 0:f7b1eb17ad24
1191 1188 bookmark: foo@1
1192 1189 phase: public
1193 1190 user: test
1194 1191 date: Thu Jan 01 00:00:00 1970 +0000
1195 1192 summary: 0
1196 1193
1197 1194
1198 1195 attempt to create on a default changeset
1199 1196
1200 1197 $ hg bookmark -r 81dcce76aa0b NEW
1201 1198 transaction abort!
1202 1199 rollback completed
1203 1200 abort: pretxnclose-bookmark.force-public hook exited with status 1
1204 1201 [255]
1205 1202
1206 1203 create on a public changeset
1207 1204
1208 1205 $ hg bookmark -r 9ba5f110a0b3 NEW
1209 1206
1210 1207 move to the other branch
1211 1208
1212 1209 $ hg bookmark -f -r 125c9a1d6df6 NEW
1213 1210 transaction abort!
1214 1211 rollback completed
1215 1212 abort: pretxnclose-bookmark.force-forward hook exited with status 1
1216 1213 [255]
General Comments 0
You need to be logged in to leave comments. Login now