##// END OF EJS Templates
bookmarks: check HG_PENDING strictly...
FUJIWARA Katsunori -
r31052:0332b8fa default
parent child Browse files
Show More
@@ -1,194 +1,216 b''
1 1 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
2 2 #
3 3 # This software may be used and distributed according to the terms of the
4 4 # GNU General Public License version 2 or any later version.
5 5
6 6 '''share a common history between several working directories
7 7
8 8 Automatic Pooled Storage for Clones
9 9 -----------------------------------
10 10
11 11 When this extension is active, :hg:`clone` can be configured to
12 12 automatically share/pool storage across multiple clones. This
13 13 mode effectively converts :hg:`clone` to :hg:`clone` + :hg:`share`.
14 14 The benefit of using this mode is the automatic management of
15 15 store paths and intelligent pooling of related repositories.
16 16
17 17 The following ``share.`` config options influence this feature:
18 18
19 19 ``share.pool``
20 20 Filesystem path where shared repository data will be stored. When
21 21 defined, :hg:`clone` will automatically use shared repository
22 22 storage instead of creating a store inside each clone.
23 23
24 24 ``share.poolnaming``
25 25 How directory names in ``share.pool`` are constructed.
26 26
27 27 "identity" means the name is derived from the first changeset in the
28 28 repository. In this mode, different remotes share storage if their
29 29 root/initial changeset is identical. In this mode, the local shared
30 30 repository is an aggregate of all encountered remote repositories.
31 31
32 32 "remote" means the name is derived from the source repository's
33 33 path or URL. In this mode, storage is only shared if the path or URL
34 34 requested in the :hg:`clone` command matches exactly to a repository
35 35 that was cloned before.
36 36
37 37 The default naming mode is "identity."
38 38 '''
39 39
40 40 from __future__ import absolute_import
41 41
42 42 import errno
43 43 from mercurial.i18n import _
44 44 from mercurial import (
45 45 bookmarks,
46 46 cmdutil,
47 47 commands,
48 48 error,
49 49 extensions,
50 50 hg,
51 txnutil,
51 52 util,
52 53 )
53 54
54 55 repository = hg.repository
55 56 parseurl = hg.parseurl
56 57
57 58 cmdtable = {}
58 59 command = cmdutil.command(cmdtable)
59 60 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
60 61 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
61 62 # be specifying the version(s) of Mercurial they are tested with, or
62 63 # leave the attribute unspecified.
63 64 testedwith = 'ships-with-hg-core'
64 65
65 66 @command('share',
66 67 [('U', 'noupdate', None, _('do not create a working directory')),
67 68 ('B', 'bookmarks', None, _('also share bookmarks'))],
68 69 _('[-U] [-B] SOURCE [DEST]'),
69 70 norepo=True)
70 71 def share(ui, source, dest=None, noupdate=False, bookmarks=False):
71 72 """create a new shared repository
72 73
73 74 Initialize a new repository and working directory that shares its
74 75 history (and optionally bookmarks) with another repository.
75 76
76 77 .. note::
77 78
78 79 using rollback or extensions that destroy/modify history (mq,
79 80 rebase, etc.) can cause considerable confusion with shared
80 81 clones. In particular, if two shared clones are both updated to
81 82 the same changeset, and one of them destroys that changeset
82 83 with rollback, the other clone will suddenly stop working: all
83 84 operations will fail with "abort: working directory has unknown
84 85 parent". The only known workaround is to use debugsetparents on
85 86 the broken clone to reset it to a changeset that still exists.
86 87 """
87 88
88 89 return hg.share(ui, source, dest=dest, update=not noupdate,
89 90 bookmarks=bookmarks)
90 91
91 92 @command('unshare', [], '')
92 93 def unshare(ui, repo):
93 94 """convert a shared repository to a normal one
94 95
95 96 Copy the store data to the repo and remove the sharedpath data.
96 97 """
97 98
98 99 if not repo.shared():
99 100 raise error.Abort(_("this is not a shared repo"))
100 101
101 102 destlock = lock = None
102 103 lock = repo.lock()
103 104 try:
104 105 # we use locks here because if we race with commit, we
105 106 # can end up with extra data in the cloned revlogs that's
106 107 # not pointed to by changesets, thus causing verify to
107 108 # fail
108 109
109 110 destlock = hg.copystore(ui, repo, repo.path)
110 111
111 112 sharefile = repo.join('sharedpath')
112 113 util.rename(sharefile, sharefile + '.old')
113 114
114 115 repo.requirements.discard('sharedpath')
115 116 repo._writerequirements()
116 117 finally:
117 118 destlock and destlock.release()
118 119 lock and lock.release()
119 120
120 121 # update store, spath, svfs and sjoin of repo
121 122 repo.unfiltered().__init__(repo.baseui, repo.root)
122 123
123 124 # Wrap clone command to pass auto share options.
124 125 def clone(orig, ui, source, *args, **opts):
125 126 pool = ui.config('share', 'pool', None)
126 127 if pool:
127 128 pool = util.expandpath(pool)
128 129
129 130 opts['shareopts'] = dict(
130 131 pool=pool,
131 132 mode=ui.config('share', 'poolnaming', 'identity'),
132 133 )
133 134
134 135 return orig(ui, source, *args, **opts)
135 136
136 137 def extsetup(ui):
137 138 extensions.wrapfunction(bookmarks, '_getbkfile', getbkfile)
138 139 extensions.wrapfunction(bookmarks.bmstore, 'recordchange', recordchange)
139 140 extensions.wrapfunction(bookmarks.bmstore, '_writerepo', writerepo)
140 141 extensions.wrapcommand(commands.table, 'clone', clone)
141 142
142 143 def _hassharedbookmarks(repo):
143 144 """Returns whether this repo has shared bookmarks"""
144 145 try:
145 146 shared = repo.vfs.read('shared').splitlines()
146 147 except IOError as inst:
147 148 if inst.errno != errno.ENOENT:
148 149 raise
149 150 return False
150 151 return hg.sharedbookmarks in shared
151 152
152 153 def _getsrcrepo(repo):
153 154 """
154 155 Returns the source repository object for a given shared repository.
155 156 If repo is not a shared repository, return None.
156 157 """
157 158 if repo.sharedpath == repo.path:
158 159 return None
159 160
160 161 if util.safehasattr(repo, 'srcrepo') and repo.srcrepo:
161 162 return repo.srcrepo
162 163
163 164 # the sharedpath always ends in the .hg; we want the path to the repo
164 165 source = repo.vfs.split(repo.sharedpath)[0]
165 166 srcurl, branches = parseurl(source)
166 167 srcrepo = repository(repo.ui, srcurl)
167 168 repo.srcrepo = srcrepo
168 169 return srcrepo
169 170
170 171 def getbkfile(orig, repo):
171 172 if _hassharedbookmarks(repo):
172 173 srcrepo = _getsrcrepo(repo)
173 174 if srcrepo is not None:
175 # just orig(srcrepo) doesn't work as expected, because
176 # HG_PENDING refers repo.root.
177 try:
178 fp, pending = txnutil.trypending(repo.root, repo.vfs,
179 'bookmarks')
180 if pending:
181 # only in this case, bookmark information in repo
182 # is up-to-date.
183 return fp
184 fp.close()
185 except IOError as inst:
186 if inst.errno != errno.ENOENT:
187 raise
188
189 # otherwise, we should read bookmarks from srcrepo,
190 # because .hg/bookmarks in srcrepo might be already
191 # changed via another sharing repo
174 192 repo = srcrepo
193
194 # TODO: Pending changes in repo are still invisible in
195 # srcrepo, because bookmarks.pending is written only into repo.
196 # See also https://www.mercurial-scm.org/wiki/SharedRepository
175 197 return orig(repo)
176 198
177 199 def recordchange(orig, self, tr):
178 200 # Continue with write to local bookmarks file as usual
179 201 orig(self, tr)
180 202
181 203 if _hassharedbookmarks(self._repo):
182 204 srcrepo = _getsrcrepo(self._repo)
183 205 if srcrepo is not None:
184 206 category = 'share-bookmarks'
185 207 tr.addpostclose(category, lambda tr: self._writerepo(srcrepo))
186 208
187 209 def writerepo(orig, self, repo):
188 210 # First write local bookmarks file in case we ever unshare
189 211 orig(self, repo)
190 212
191 213 if _hassharedbookmarks(self._repo):
192 214 srcrepo = _getsrcrepo(self._repo)
193 215 if srcrepo is not None:
194 216 orig(self, srcrepo)
@@ -1,607 +1,599 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
12 12 from .i18n import _
13 13 from .node import (
14 14 bin,
15 15 hex,
16 16 )
17 17 from . import (
18 18 encoding,
19 19 error,
20 20 lock as lockmod,
21 21 obsolete,
22 txnutil,
22 23 util,
23 24 )
24 25
25 26 def _getbkfile(repo):
26 27 """Hook so that extensions that mess with the store can hook bm storage.
27 28
28 29 For core, this just handles wether we should see pending
29 30 bookmarks or the committed ones. Other extensions (like share)
30 31 may need to tweak this behavior further.
31 32 """
32 bkfile = None
33 if 'HG_PENDING' in encoding.environ:
34 try:
35 bkfile = repo.vfs('bookmarks.pending')
36 except IOError as inst:
37 if inst.errno != errno.ENOENT:
38 raise
39 if bkfile is None:
40 bkfile = repo.vfs('bookmarks')
41 return bkfile
42
33 fp, pending = txnutil.trypending(repo.root, repo.vfs, 'bookmarks')
34 return fp
43 35
44 36 class bmstore(dict):
45 37 """Storage for bookmarks.
46 38
47 39 This object should do all bookmark-related reads and writes, so
48 40 that it's fairly simple to replace the storage underlying
49 41 bookmarks without having to clone the logic surrounding
50 42 bookmarks. This type also should manage the active bookmark, if
51 43 any.
52 44
53 45 This particular bmstore implementation stores bookmarks as
54 46 {hash}\s{name}\n (the same format as localtags) in
55 47 .hg/bookmarks. The mapping is stored as {name: nodeid}.
56 48 """
57 49
58 50 def __init__(self, repo):
59 51 dict.__init__(self)
60 52 self._repo = repo
61 53 try:
62 54 bkfile = _getbkfile(repo)
63 55 for line in bkfile:
64 56 line = line.strip()
65 57 if not line:
66 58 continue
67 59 if ' ' not in line:
68 60 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
69 61 % line)
70 62 continue
71 63 sha, refspec = line.split(' ', 1)
72 64 refspec = encoding.tolocal(refspec)
73 65 try:
74 66 self[refspec] = repo.changelog.lookup(sha)
75 67 except LookupError:
76 68 pass
77 69 except IOError as inst:
78 70 if inst.errno != errno.ENOENT:
79 71 raise
80 72 self._clean = True
81 73 self._active = _readactive(repo, self)
82 74 self._aclean = True
83 75
84 76 @property
85 77 def active(self):
86 78 return self._active
87 79
88 80 @active.setter
89 81 def active(self, mark):
90 82 if mark is not None and mark not in self:
91 83 raise AssertionError('bookmark %s does not exist!' % mark)
92 84
93 85 self._active = mark
94 86 self._aclean = False
95 87
96 88 def __setitem__(self, *args, **kwargs):
97 89 self._clean = False
98 90 return dict.__setitem__(self, *args, **kwargs)
99 91
100 92 def __delitem__(self, key):
101 93 self._clean = False
102 94 return dict.__delitem__(self, key)
103 95
104 96 def recordchange(self, tr):
105 97 """record that bookmarks have been changed in a transaction
106 98
107 99 The transaction is then responsible for updating the file content."""
108 100 tr.addfilegenerator('bookmarks', ('bookmarks',), self._write,
109 101 location='plain')
110 102 tr.hookargs['bookmark_moved'] = '1'
111 103
112 104 def _writerepo(self, repo):
113 105 """Factored out for extensibility"""
114 106 rbm = repo._bookmarks
115 107 if rbm.active not in self:
116 108 rbm.active = None
117 109 rbm._writeactive()
118 110
119 111 with repo.wlock():
120 112 file_ = repo.vfs('bookmarks', 'w', atomictemp=True,
121 113 checkambig=True)
122 114 try:
123 115 self._write(file_)
124 116 except: # re-raises
125 117 file_.discard()
126 118 raise
127 119 finally:
128 120 file_.close()
129 121
130 122 def _writeactive(self):
131 123 if self._aclean:
132 124 return
133 125 with self._repo.wlock():
134 126 if self._active is not None:
135 127 f = self._repo.vfs('bookmarks.current', 'w', atomictemp=True,
136 128 checkambig=True)
137 129 try:
138 130 f.write(encoding.fromlocal(self._active))
139 131 finally:
140 132 f.close()
141 133 else:
142 134 try:
143 135 self._repo.vfs.unlink('bookmarks.current')
144 136 except OSError as inst:
145 137 if inst.errno != errno.ENOENT:
146 138 raise
147 139 self._aclean = True
148 140
149 141 def _write(self, fp):
150 142 for name, node in self.iteritems():
151 143 fp.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
152 144 self._clean = True
153 145 self._repo.invalidatevolatilesets()
154 146
155 147 def expandname(self, bname):
156 148 if bname == '.':
157 149 if self.active:
158 150 return self.active
159 151 else:
160 152 raise error.Abort(_("no active bookmark"))
161 153 return bname
162 154
163 155 def _readactive(repo, marks):
164 156 """
165 157 Get the active bookmark. We can have an active bookmark that updates
166 158 itself as we commit. This function returns the name of that bookmark.
167 159 It is stored in .hg/bookmarks.current
168 160 """
169 161 mark = None
170 162 try:
171 163 file = repo.vfs('bookmarks.current')
172 164 except IOError as inst:
173 165 if inst.errno != errno.ENOENT:
174 166 raise
175 167 return None
176 168 try:
177 169 # No readline() in osutil.posixfile, reading everything is
178 170 # cheap.
179 171 # Note that it's possible for readlines() here to raise
180 172 # IOError, since we might be reading the active mark over
181 173 # static-http which only tries to load the file when we try
182 174 # to read from it.
183 175 mark = encoding.tolocal((file.readlines() or [''])[0])
184 176 if mark == '' or mark not in marks:
185 177 mark = None
186 178 except IOError as inst:
187 179 if inst.errno != errno.ENOENT:
188 180 raise
189 181 return None
190 182 finally:
191 183 file.close()
192 184 return mark
193 185
194 186 def activate(repo, mark):
195 187 """
196 188 Set the given bookmark to be 'active', meaning that this bookmark will
197 189 follow new commits that are made.
198 190 The name is recorded in .hg/bookmarks.current
199 191 """
200 192 repo._bookmarks.active = mark
201 193 repo._bookmarks._writeactive()
202 194
203 195 def deactivate(repo):
204 196 """
205 197 Unset the active bookmark in this repository.
206 198 """
207 199 repo._bookmarks.active = None
208 200 repo._bookmarks._writeactive()
209 201
210 202 def isactivewdirparent(repo):
211 203 """
212 204 Tell whether the 'active' bookmark (the one that follows new commits)
213 205 points to one of the parents of the current working directory (wdir).
214 206
215 207 While this is normally the case, it can on occasion be false; for example,
216 208 immediately after a pull, the active bookmark can be moved to point
217 209 to a place different than the wdir. This is solved by running `hg update`.
218 210 """
219 211 mark = repo._activebookmark
220 212 marks = repo._bookmarks
221 213 parents = [p.node() for p in repo[None].parents()]
222 214 return (mark in marks and marks[mark] in parents)
223 215
224 216 def deletedivergent(repo, deletefrom, bm):
225 217 '''Delete divergent versions of bm on nodes in deletefrom.
226 218
227 219 Return True if at least one bookmark was deleted, False otherwise.'''
228 220 deleted = False
229 221 marks = repo._bookmarks
230 222 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
231 223 for mark in divergent:
232 224 if mark == '@' or '@' not in mark:
233 225 # can't be divergent by definition
234 226 continue
235 227 if mark and marks[mark] in deletefrom:
236 228 if mark != bm:
237 229 del marks[mark]
238 230 deleted = True
239 231 return deleted
240 232
241 233 def calculateupdate(ui, repo, checkout):
242 234 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
243 235 check out and where to move the active bookmark from, if needed.'''
244 236 movemarkfrom = None
245 237 if checkout is None:
246 238 activemark = repo._activebookmark
247 239 if isactivewdirparent(repo):
248 240 movemarkfrom = repo['.'].node()
249 241 elif activemark:
250 242 ui.status(_("updating to active bookmark %s\n") % activemark)
251 243 checkout = activemark
252 244 return (checkout, movemarkfrom)
253 245
254 246 def update(repo, parents, node):
255 247 deletefrom = parents
256 248 marks = repo._bookmarks
257 249 update = False
258 250 active = marks.active
259 251 if not active:
260 252 return False
261 253
262 254 if marks[active] in parents:
263 255 new = repo[node]
264 256 divs = [repo[b] for b in marks
265 257 if b.split('@', 1)[0] == active.split('@', 1)[0]]
266 258 anc = repo.changelog.ancestors([new.rev()])
267 259 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
268 260 if validdest(repo, repo[marks[active]], new):
269 261 marks[active] = new.node()
270 262 update = True
271 263
272 264 if deletedivergent(repo, deletefrom, active):
273 265 update = True
274 266
275 267 if update:
276 268 lock = tr = None
277 269 try:
278 270 lock = repo.lock()
279 271 tr = repo.transaction('bookmark')
280 272 marks.recordchange(tr)
281 273 tr.close()
282 274 finally:
283 275 lockmod.release(tr, lock)
284 276 return update
285 277
286 278 def listbinbookmarks(repo):
287 279 # We may try to list bookmarks on a repo type that does not
288 280 # support it (e.g., statichttprepository).
289 281 marks = getattr(repo, '_bookmarks', {})
290 282
291 283 hasnode = repo.changelog.hasnode
292 284 for k, v in marks.iteritems():
293 285 # don't expose local divergent bookmarks
294 286 if hasnode(v) and ('@' not in k or k.endswith('@')):
295 287 yield k, v
296 288
297 289 def listbookmarks(repo):
298 290 d = {}
299 291 for book, node in listbinbookmarks(repo):
300 292 d[book] = hex(node)
301 293 return d
302 294
303 295 def pushbookmark(repo, key, old, new):
304 296 w = l = tr = None
305 297 try:
306 298 w = repo.wlock()
307 299 l = repo.lock()
308 300 tr = repo.transaction('bookmarks')
309 301 marks = repo._bookmarks
310 302 existing = hex(marks.get(key, ''))
311 303 if existing != old and existing != new:
312 304 return False
313 305 if new == '':
314 306 del marks[key]
315 307 else:
316 308 if new not in repo:
317 309 return False
318 310 marks[key] = repo[new].node()
319 311 marks.recordchange(tr)
320 312 tr.close()
321 313 return True
322 314 finally:
323 315 lockmod.release(tr, l, w)
324 316
325 317 def comparebookmarks(repo, srcmarks, dstmarks, targets=None):
326 318 '''Compare bookmarks between srcmarks and dstmarks
327 319
328 320 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
329 321 differ, invalid)", each are list of bookmarks below:
330 322
331 323 :addsrc: added on src side (removed on dst side, perhaps)
332 324 :adddst: added on dst side (removed on src side, perhaps)
333 325 :advsrc: advanced on src side
334 326 :advdst: advanced on dst side
335 327 :diverge: diverge
336 328 :differ: changed, but changeset referred on src is unknown on dst
337 329 :invalid: unknown on both side
338 330 :same: same on both side
339 331
340 332 Each elements of lists in result tuple is tuple "(bookmark name,
341 333 changeset ID on source side, changeset ID on destination
342 334 side)". Each changeset IDs are 40 hexadecimal digit string or
343 335 None.
344 336
345 337 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
346 338 "invalid" list may be unknown for repo.
347 339
348 340 If "targets" is specified, only bookmarks listed in it are
349 341 examined.
350 342 '''
351 343
352 344 if targets:
353 345 bset = set(targets)
354 346 else:
355 347 srcmarkset = set(srcmarks)
356 348 dstmarkset = set(dstmarks)
357 349 bset = srcmarkset | dstmarkset
358 350
359 351 results = ([], [], [], [], [], [], [], [])
360 352 addsrc = results[0].append
361 353 adddst = results[1].append
362 354 advsrc = results[2].append
363 355 advdst = results[3].append
364 356 diverge = results[4].append
365 357 differ = results[5].append
366 358 invalid = results[6].append
367 359 same = results[7].append
368 360
369 361 for b in sorted(bset):
370 362 if b not in srcmarks:
371 363 if b in dstmarks:
372 364 adddst((b, None, dstmarks[b]))
373 365 else:
374 366 invalid((b, None, None))
375 367 elif b not in dstmarks:
376 368 addsrc((b, srcmarks[b], None))
377 369 else:
378 370 scid = srcmarks[b]
379 371 dcid = dstmarks[b]
380 372 if scid == dcid:
381 373 same((b, scid, dcid))
382 374 elif scid in repo and dcid in repo:
383 375 sctx = repo[scid]
384 376 dctx = repo[dcid]
385 377 if sctx.rev() < dctx.rev():
386 378 if validdest(repo, sctx, dctx):
387 379 advdst((b, scid, dcid))
388 380 else:
389 381 diverge((b, scid, dcid))
390 382 else:
391 383 if validdest(repo, dctx, sctx):
392 384 advsrc((b, scid, dcid))
393 385 else:
394 386 diverge((b, scid, dcid))
395 387 else:
396 388 # it is too expensive to examine in detail, in this case
397 389 differ((b, scid, dcid))
398 390
399 391 return results
400 392
401 393 def _diverge(ui, b, path, localmarks, remotenode):
402 394 '''Return appropriate diverged bookmark for specified ``path``
403 395
404 396 This returns None, if it is failed to assign any divergent
405 397 bookmark name.
406 398
407 399 This reuses already existing one with "@number" suffix, if it
408 400 refers ``remotenode``.
409 401 '''
410 402 if b == '@':
411 403 b = ''
412 404 # try to use an @pathalias suffix
413 405 # if an @pathalias already exists, we overwrite (update) it
414 406 if path.startswith("file:"):
415 407 path = util.url(path).path
416 408 for p, u in ui.configitems("paths"):
417 409 if u.startswith("file:"):
418 410 u = util.url(u).path
419 411 if path == u:
420 412 return '%s@%s' % (b, p)
421 413
422 414 # assign a unique "@number" suffix newly
423 415 for x in range(1, 100):
424 416 n = '%s@%d' % (b, x)
425 417 if n not in localmarks or localmarks[n] == remotenode:
426 418 return n
427 419
428 420 return None
429 421
430 422 def unhexlifybookmarks(marks):
431 423 binremotemarks = {}
432 424 for name, node in marks.items():
433 425 binremotemarks[name] = bin(node)
434 426 return binremotemarks
435 427
436 428 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
437 429 ui.debug("checking for updated bookmarks\n")
438 430 localmarks = repo._bookmarks
439 431 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same
440 432 ) = comparebookmarks(repo, remotemarks, localmarks)
441 433
442 434 status = ui.status
443 435 warn = ui.warn
444 436 if ui.configbool('ui', 'quietbookmarkmove', False):
445 437 status = warn = ui.debug
446 438
447 439 explicit = set(explicit)
448 440 changed = []
449 441 for b, scid, dcid in addsrc:
450 442 if scid in repo: # add remote bookmarks for changes we already have
451 443 changed.append((b, scid, status,
452 444 _("adding remote bookmark %s\n") % (b)))
453 445 elif b in explicit:
454 446 explicit.remove(b)
455 447 ui.warn(_("remote bookmark %s points to locally missing %s\n")
456 448 % (b, hex(scid)[:12]))
457 449
458 450 for b, scid, dcid in advsrc:
459 451 changed.append((b, scid, status,
460 452 _("updating bookmark %s\n") % (b)))
461 453 # remove normal movement from explicit set
462 454 explicit.difference_update(d[0] for d in changed)
463 455
464 456 for b, scid, dcid in diverge:
465 457 if b in explicit:
466 458 explicit.discard(b)
467 459 changed.append((b, scid, status,
468 460 _("importing bookmark %s\n") % (b)))
469 461 else:
470 462 db = _diverge(ui, b, path, localmarks, scid)
471 463 if db:
472 464 changed.append((db, scid, warn,
473 465 _("divergent bookmark %s stored as %s\n") %
474 466 (b, db)))
475 467 else:
476 468 warn(_("warning: failed to assign numbered name "
477 469 "to divergent bookmark %s\n") % (b))
478 470 for b, scid, dcid in adddst + advdst:
479 471 if b in explicit:
480 472 explicit.discard(b)
481 473 changed.append((b, scid, status,
482 474 _("importing bookmark %s\n") % (b)))
483 475 for b, scid, dcid in differ:
484 476 if b in explicit:
485 477 explicit.remove(b)
486 478 ui.warn(_("remote bookmark %s points to locally missing %s\n")
487 479 % (b, hex(scid)[:12]))
488 480
489 481 if changed:
490 482 tr = trfunc()
491 483 for b, node, writer, msg in sorted(changed):
492 484 localmarks[b] = node
493 485 writer(msg)
494 486 localmarks.recordchange(tr)
495 487
496 488 def incoming(ui, repo, other):
497 489 '''Show bookmarks incoming from other to repo
498 490 '''
499 491 ui.status(_("searching for changed bookmarks\n"))
500 492
501 493 remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
502 494 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
503 495 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
504 496
505 497 incomings = []
506 498 if ui.debugflag:
507 499 getid = lambda id: id
508 500 else:
509 501 getid = lambda id: id[:12]
510 502 if ui.verbose:
511 503 def add(b, id, st):
512 504 incomings.append(" %-25s %s %s\n" % (b, getid(id), st))
513 505 else:
514 506 def add(b, id, st):
515 507 incomings.append(" %-25s %s\n" % (b, getid(id)))
516 508 for b, scid, dcid in addsrc:
517 509 # i18n: "added" refers to a bookmark
518 510 add(b, hex(scid), _('added'))
519 511 for b, scid, dcid in advsrc:
520 512 # i18n: "advanced" refers to a bookmark
521 513 add(b, hex(scid), _('advanced'))
522 514 for b, scid, dcid in diverge:
523 515 # i18n: "diverged" refers to a bookmark
524 516 add(b, hex(scid), _('diverged'))
525 517 for b, scid, dcid in differ:
526 518 # i18n: "changed" refers to a bookmark
527 519 add(b, hex(scid), _('changed'))
528 520
529 521 if not incomings:
530 522 ui.status(_("no changed bookmarks found\n"))
531 523 return 1
532 524
533 525 for s in sorted(incomings):
534 526 ui.write(s)
535 527
536 528 return 0
537 529
538 530 def outgoing(ui, repo, other):
539 531 '''Show bookmarks outgoing from repo to other
540 532 '''
541 533 ui.status(_("searching for changed bookmarks\n"))
542 534
543 535 remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
544 536 r = comparebookmarks(repo, repo._bookmarks, remotemarks)
545 537 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
546 538
547 539 outgoings = []
548 540 if ui.debugflag:
549 541 getid = lambda id: id
550 542 else:
551 543 getid = lambda id: id[:12]
552 544 if ui.verbose:
553 545 def add(b, id, st):
554 546 outgoings.append(" %-25s %s %s\n" % (b, getid(id), st))
555 547 else:
556 548 def add(b, id, st):
557 549 outgoings.append(" %-25s %s\n" % (b, getid(id)))
558 550 for b, scid, dcid in addsrc:
559 551 # i18n: "added refers to a bookmark
560 552 add(b, hex(scid), _('added'))
561 553 for b, scid, dcid in adddst:
562 554 # i18n: "deleted" refers to a bookmark
563 555 add(b, ' ' * 40, _('deleted'))
564 556 for b, scid, dcid in advsrc:
565 557 # i18n: "advanced" refers to a bookmark
566 558 add(b, hex(scid), _('advanced'))
567 559 for b, scid, dcid in diverge:
568 560 # i18n: "diverged" refers to a bookmark
569 561 add(b, hex(scid), _('diverged'))
570 562 for b, scid, dcid in differ:
571 563 # i18n: "changed" refers to a bookmark
572 564 add(b, hex(scid), _('changed'))
573 565
574 566 if not outgoings:
575 567 ui.status(_("no changed bookmarks found\n"))
576 568 return 1
577 569
578 570 for s in sorted(outgoings):
579 571 ui.write(s)
580 572
581 573 return 0
582 574
583 575 def summary(repo, other):
584 576 '''Compare bookmarks between repo and other for "hg summary" output
585 577
586 578 This returns "(# of incoming, # of outgoing)" tuple.
587 579 '''
588 580 remotemarks = unhexlifybookmarks(other.listkeys('bookmarks'))
589 581 r = comparebookmarks(repo, remotemarks, repo._bookmarks)
590 582 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
591 583 return (len(addsrc), len(adddst))
592 584
593 585 def validdest(repo, old, new):
594 586 """Is the new bookmark destination a valid update from the old one"""
595 587 repo = repo.unfiltered()
596 588 if old == new:
597 589 # Old == new -> nothing to update.
598 590 return False
599 591 elif not old:
600 592 # old is nullrev, anything is valid.
601 593 # (new != nullrev has been excluded by the previous check)
602 594 return True
603 595 elif repo.obsstore:
604 596 return new.node() in obsolete.foreground(repo, [old.node()])
605 597 else:
606 598 # still an independent clause as it is lazier (and therefore faster)
607 599 return old.descendant(new)
@@ -1,898 +1,953 b''
1 1 $ hg init repo
2 2 $ cd repo
3 3
4 4 no bookmarks
5 5
6 6 $ hg bookmarks
7 7 no bookmarks set
8 8
9 9 $ hg bookmarks -Tjson
10 10 [
11 11 ]
12 12
13 13 bookmark rev -1
14 14
15 15 $ hg bookmark X
16 16
17 17 list bookmarks
18 18
19 19 $ hg bookmarks
20 20 * X -1:000000000000
21 21
22 22 list bookmarks with color
23 23
24 24 $ hg --config extensions.color= --config color.mode=ansi \
25 25 > bookmarks --color=always
26 26 \x1b[0;32m * \x1b[0m\x1b[0;32mX\x1b[0m\x1b[0;32m -1:000000000000\x1b[0m (esc)
27 27
28 28 $ echo a > a
29 29 $ hg add a
30 30 $ hg commit -m 0
31 31
32 32 bookmark X moved to rev 0
33 33
34 34 $ hg bookmarks
35 35 * X 0:f7b1eb17ad24
36 36
37 37 look up bookmark
38 38
39 39 $ hg log -r X
40 40 changeset: 0:f7b1eb17ad24
41 41 bookmark: X
42 42 tag: tip
43 43 user: test
44 44 date: Thu Jan 01 00:00:00 1970 +0000
45 45 summary: 0
46 46
47 47
48 48 second bookmark for rev 0, command should work even with ui.strict on
49 49
50 50 $ hg --config ui.strict=1 bookmark X2
51 51
52 52 bookmark rev -1 again
53 53
54 54 $ hg bookmark -r null Y
55 55
56 56 list bookmarks
57 57
58 58 $ hg bookmarks
59 59 X 0:f7b1eb17ad24
60 60 * X2 0:f7b1eb17ad24
61 61 Y -1:000000000000
62 62
63 63 $ echo b > b
64 64 $ hg add b
65 65 $ hg commit -m 1
66 66
67 67 $ hg bookmarks -Tjson
68 68 [
69 69 {
70 70 "active": false,
71 71 "bookmark": "X",
72 72 "node": "f7b1eb17ad24730a1651fccd46c43826d1bbc2ac",
73 73 "rev": 0
74 74 },
75 75 {
76 76 "active": true,
77 77 "bookmark": "X2",
78 78 "node": "925d80f479bb026b0fb3deb27503780b13f74123",
79 79 "rev": 1
80 80 },
81 81 {
82 82 "active": false,
83 83 "bookmark": "Y",
84 84 "node": "0000000000000000000000000000000000000000",
85 85 "rev": -1
86 86 }
87 87 ]
88 88
89 89 bookmarks revset
90 90
91 91 $ hg log -r 'bookmark()'
92 92 changeset: 0:f7b1eb17ad24
93 93 bookmark: X
94 94 user: test
95 95 date: Thu Jan 01 00:00:00 1970 +0000
96 96 summary: 0
97 97
98 98 changeset: 1:925d80f479bb
99 99 bookmark: X2
100 100 tag: tip
101 101 user: test
102 102 date: Thu Jan 01 00:00:00 1970 +0000
103 103 summary: 1
104 104
105 105 $ hg log -r 'bookmark(Y)'
106 106 $ hg log -r 'bookmark(X2)'
107 107 changeset: 1:925d80f479bb
108 108 bookmark: X2
109 109 tag: tip
110 110 user: test
111 111 date: Thu Jan 01 00:00:00 1970 +0000
112 112 summary: 1
113 113
114 114 $ hg log -r 'bookmark("re:X")'
115 115 changeset: 0:f7b1eb17ad24
116 116 bookmark: X
117 117 user: test
118 118 date: Thu Jan 01 00:00:00 1970 +0000
119 119 summary: 0
120 120
121 121 changeset: 1:925d80f479bb
122 122 bookmark: X2
123 123 tag: tip
124 124 user: test
125 125 date: Thu Jan 01 00:00:00 1970 +0000
126 126 summary: 1
127 127
128 128 $ hg log -r 'bookmark("literal:X")'
129 129 changeset: 0:f7b1eb17ad24
130 130 bookmark: X
131 131 user: test
132 132 date: Thu Jan 01 00:00:00 1970 +0000
133 133 summary: 0
134 134
135 135
136 136 $ hg log -r 'bookmark(unknown)'
137 137 abort: bookmark 'unknown' does not exist!
138 138 [255]
139 139 $ hg log -r 'bookmark("literal:unknown")'
140 140 abort: bookmark 'unknown' does not exist!
141 141 [255]
142 142 $ hg log -r 'bookmark("re:unknown")'
143 143 abort: no bookmarks exist that match 'unknown'!
144 144 [255]
145 145 $ hg log -r 'present(bookmark("literal:unknown"))'
146 146 $ hg log -r 'present(bookmark("re:unknown"))'
147 147
148 148 $ hg help revsets | grep 'bookmark('
149 149 "bookmark([name])"
150 150
151 151 bookmarks X and X2 moved to rev 1, Y at rev -1
152 152
153 153 $ hg bookmarks
154 154 X 0:f7b1eb17ad24
155 155 * X2 1:925d80f479bb
156 156 Y -1:000000000000
157 157
158 158 bookmark rev 0 again
159 159
160 160 $ hg bookmark -r 0 Z
161 161
162 162 $ hg update X
163 163 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
164 164 (activating bookmark X)
165 165 $ echo c > c
166 166 $ hg add c
167 167 $ hg commit -m 2
168 168 created new head
169 169
170 170 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
171 171
172 172 $ hg bookmarks
173 173 * X 2:db815d6d32e6
174 174 X2 1:925d80f479bb
175 175 Y -1:000000000000
176 176 Z 0:f7b1eb17ad24
177 177
178 178 rename nonexistent bookmark
179 179
180 180 $ hg bookmark -m A B
181 181 abort: bookmark 'A' does not exist
182 182 [255]
183 183
184 184 rename to existent bookmark
185 185
186 186 $ hg bookmark -m X Y
187 187 abort: bookmark 'Y' already exists (use -f to force)
188 188 [255]
189 189
190 190 force rename to existent bookmark
191 191
192 192 $ hg bookmark -f -m X Y
193 193
194 194 list bookmarks
195 195
196 196 $ hg bookmark
197 197 X2 1:925d80f479bb
198 198 * Y 2:db815d6d32e6
199 199 Z 0:f7b1eb17ad24
200 200
201 201 bookmarks from a revset
202 202 $ hg bookmark -r '.^1' REVSET
203 203 $ hg bookmark -r ':tip' TIP
204 204 $ hg up -q TIP
205 205 $ hg bookmarks
206 206 REVSET 0:f7b1eb17ad24
207 207 * TIP 2:db815d6d32e6
208 208 X2 1:925d80f479bb
209 209 Y 2:db815d6d32e6
210 210 Z 0:f7b1eb17ad24
211 211
212 212 $ hg bookmark -d REVSET
213 213 $ hg bookmark -d TIP
214 214
215 215 rename without new name or multiple names
216 216
217 217 $ hg bookmark -m Y
218 218 abort: new bookmark name required
219 219 [255]
220 220 $ hg bookmark -m Y Y2 Y3
221 221 abort: only one new bookmark name allowed
222 222 [255]
223 223
224 224 delete without name
225 225
226 226 $ hg bookmark -d
227 227 abort: bookmark name required
228 228 [255]
229 229
230 230 delete nonexistent bookmark
231 231
232 232 $ hg bookmark -d A
233 233 abort: bookmark 'A' does not exist
234 234 [255]
235 235
236 236 bookmark name with spaces should be stripped
237 237
238 238 $ hg bookmark ' x y '
239 239
240 240 list bookmarks
241 241
242 242 $ hg bookmarks
243 243 X2 1:925d80f479bb
244 244 Y 2:db815d6d32e6
245 245 Z 0:f7b1eb17ad24
246 246 * x y 2:db815d6d32e6
247 247
248 248 look up stripped bookmark name
249 249
250 250 $ hg log -r '"x y"'
251 251 changeset: 2:db815d6d32e6
252 252 bookmark: Y
253 253 bookmark: x y
254 254 tag: tip
255 255 parent: 0:f7b1eb17ad24
256 256 user: test
257 257 date: Thu Jan 01 00:00:00 1970 +0000
258 258 summary: 2
259 259
260 260
261 261 reject bookmark name with newline
262 262
263 263 $ hg bookmark '
264 264 > '
265 265 abort: bookmark names cannot consist entirely of whitespace
266 266 [255]
267 267
268 268 $ hg bookmark -m Z '
269 269 > '
270 270 abort: bookmark names cannot consist entirely of whitespace
271 271 [255]
272 272
273 273 bookmark with reserved name
274 274
275 275 $ hg bookmark tip
276 276 abort: the name 'tip' is reserved
277 277 [255]
278 278
279 279 $ hg bookmark .
280 280 abort: the name '.' is reserved
281 281 [255]
282 282
283 283 $ hg bookmark null
284 284 abort: the name 'null' is reserved
285 285 [255]
286 286
287 287
288 288 bookmark with existing name
289 289
290 290 $ hg bookmark X2
291 291 abort: bookmark 'X2' already exists (use -f to force)
292 292 [255]
293 293
294 294 $ hg bookmark -m Y Z
295 295 abort: bookmark 'Z' already exists (use -f to force)
296 296 [255]
297 297
298 298 bookmark with name of branch
299 299
300 300 $ hg bookmark default
301 301 abort: a bookmark cannot have the name of an existing branch
302 302 [255]
303 303
304 304 $ hg bookmark -m Y default
305 305 abort: a bookmark cannot have the name of an existing branch
306 306 [255]
307 307
308 308 bookmark with integer name
309 309
310 310 $ hg bookmark 10
311 311 abort: cannot use an integer as a name
312 312 [255]
313 313
314 314 incompatible options
315 315
316 316 $ hg bookmark -m Y -d Z
317 317 abort: --delete and --rename are incompatible
318 318 [255]
319 319
320 320 $ hg bookmark -r 1 -d Z
321 321 abort: --rev is incompatible with --delete
322 322 [255]
323 323
324 324 $ hg bookmark -r 1 -m Z Y
325 325 abort: --rev is incompatible with --rename
326 326 [255]
327 327
328 328 force bookmark with existing name
329 329
330 330 $ hg bookmark -f X2
331 331
332 332 force bookmark back to where it was, should deactivate it
333 333
334 334 $ hg bookmark -fr1 X2
335 335 $ hg bookmarks
336 336 X2 1:925d80f479bb
337 337 Y 2:db815d6d32e6
338 338 Z 0:f7b1eb17ad24
339 339 x y 2:db815d6d32e6
340 340
341 341 forward bookmark to descendant without --force
342 342
343 343 $ hg bookmark Z
344 344 moving bookmark 'Z' forward from f7b1eb17ad24
345 345
346 346 list bookmarks
347 347
348 348 $ hg bookmark
349 349 X2 1:925d80f479bb
350 350 Y 2:db815d6d32e6
351 351 * Z 2:db815d6d32e6
352 352 x y 2:db815d6d32e6
353 353
354 354 revision but no bookmark name
355 355
356 356 $ hg bookmark -r .
357 357 abort: bookmark name required
358 358 [255]
359 359
360 360 bookmark name with whitespace only
361 361
362 362 $ hg bookmark ' '
363 363 abort: bookmark names cannot consist entirely of whitespace
364 364 [255]
365 365
366 366 $ hg bookmark -m Y ' '
367 367 abort: bookmark names cannot consist entirely of whitespace
368 368 [255]
369 369
370 370 invalid bookmark
371 371
372 372 $ hg bookmark 'foo:bar'
373 373 abort: ':' cannot be used in a name
374 374 [255]
375 375
376 376 $ hg bookmark 'foo
377 377 > bar'
378 378 abort: '\n' cannot be used in a name
379 379 [255]
380 380
381 381 the bookmark extension should be ignored now that it is part of core
382 382
383 383 $ echo "[extensions]" >> $HGRCPATH
384 384 $ echo "bookmarks=" >> $HGRCPATH
385 385 $ hg bookmarks
386 386 X2 1:925d80f479bb
387 387 Y 2:db815d6d32e6
388 388 * Z 2:db815d6d32e6
389 389 x y 2:db815d6d32e6
390 390
391 391 test summary
392 392
393 393 $ hg summary
394 394 parent: 2:db815d6d32e6 tip
395 395 2
396 396 branch: default
397 397 bookmarks: *Z Y x y
398 398 commit: (clean)
399 399 update: 1 new changesets, 2 branch heads (merge)
400 400 phases: 3 draft
401 401
402 402 test id
403 403
404 404 $ hg id
405 405 db815d6d32e6 tip Y/Z/x y
406 406
407 407 test rollback
408 408
409 409 $ echo foo > f1
410 410 $ hg bookmark tmp-rollback
411 411 $ hg ci -Amr
412 412 adding f1
413 413 $ hg bookmarks
414 414 X2 1:925d80f479bb
415 415 Y 2:db815d6d32e6
416 416 Z 2:db815d6d32e6
417 417 * tmp-rollback 3:2bf5cfec5864
418 418 x y 2:db815d6d32e6
419 419 $ hg rollback
420 420 repository tip rolled back to revision 2 (undo commit)
421 421 working directory now based on revision 2
422 422 $ hg bookmarks
423 423 X2 1:925d80f479bb
424 424 Y 2:db815d6d32e6
425 425 Z 2:db815d6d32e6
426 426 * tmp-rollback 2:db815d6d32e6
427 427 x y 2:db815d6d32e6
428 428 $ hg bookmark -f Z -r 1
429 429 $ hg rollback
430 430 repository tip rolled back to revision 2 (undo bookmark)
431 431 $ hg bookmarks
432 432 X2 1:925d80f479bb
433 433 Y 2:db815d6d32e6
434 434 Z 2:db815d6d32e6
435 435 * tmp-rollback 2:db815d6d32e6
436 436 x y 2:db815d6d32e6
437 437 $ hg bookmark -d tmp-rollback
438 438
439 439 activate bookmark on working dir parent without --force
440 440
441 441 $ hg bookmark --inactive Z
442 442 $ hg bookmark Z
443 443
444 444 test clone
445 445
446 446 $ hg bookmark -r 2 -i @
447 447 $ hg bookmark -r 2 -i a@
448 448 $ hg bookmarks
449 449 @ 2:db815d6d32e6
450 450 X2 1:925d80f479bb
451 451 Y 2:db815d6d32e6
452 452 * Z 2:db815d6d32e6
453 453 a@ 2:db815d6d32e6
454 454 x y 2:db815d6d32e6
455 455 $ hg clone . cloned-bookmarks
456 456 updating to bookmark @
457 457 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
458 458 $ hg -R cloned-bookmarks bookmarks
459 459 * @ 2:db815d6d32e6
460 460 X2 1:925d80f479bb
461 461 Y 2:db815d6d32e6
462 462 Z 2:db815d6d32e6
463 463 a@ 2:db815d6d32e6
464 464 x y 2:db815d6d32e6
465 465
466 466 test clone with pull protocol
467 467
468 468 $ hg clone --pull . cloned-bookmarks-pull
469 469 requesting all changes
470 470 adding changesets
471 471 adding manifests
472 472 adding file changes
473 473 added 3 changesets with 3 changes to 3 files (+1 heads)
474 474 updating to bookmark @
475 475 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
476 476 $ hg -R cloned-bookmarks-pull bookmarks
477 477 * @ 2:db815d6d32e6
478 478 X2 1:925d80f479bb
479 479 Y 2:db815d6d32e6
480 480 Z 2:db815d6d32e6
481 481 a@ 2:db815d6d32e6
482 482 x y 2:db815d6d32e6
483 483
484 484 delete multiple bookmarks at once
485 485
486 486 $ hg bookmark -d @ a@
487 487
488 488 test clone with a bookmark named "default" (issue3677)
489 489
490 490 $ hg bookmark -r 1 -f -i default
491 491 $ hg clone . cloned-bookmark-default
492 492 updating to branch default
493 493 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
494 494 $ hg -R cloned-bookmark-default bookmarks
495 495 X2 1:925d80f479bb
496 496 Y 2:db815d6d32e6
497 497 Z 2:db815d6d32e6
498 498 default 1:925d80f479bb
499 499 x y 2:db815d6d32e6
500 500 $ hg -R cloned-bookmark-default parents -q
501 501 2:db815d6d32e6
502 502 $ hg bookmark -d default
503 503
504 504 test clone with a specific revision
505 505
506 506 $ hg clone -r 925d80 . cloned-bookmarks-rev
507 507 adding changesets
508 508 adding manifests
509 509 adding file changes
510 510 added 2 changesets with 2 changes to 2 files
511 511 updating to branch default
512 512 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
513 513 $ hg -R cloned-bookmarks-rev bookmarks
514 514 X2 1:925d80f479bb
515 515
516 516 test clone with update to a bookmark
517 517
518 518 $ hg clone -u Z . ../cloned-bookmarks-update
519 519 updating to branch default
520 520 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
521 521 $ hg -R ../cloned-bookmarks-update bookmarks
522 522 X2 1:925d80f479bb
523 523 Y 2:db815d6d32e6
524 524 * Z 2:db815d6d32e6
525 525 x y 2:db815d6d32e6
526 526
527 527 create bundle with two heads
528 528
529 529 $ hg clone . tobundle
530 530 updating to branch default
531 531 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
532 532 $ echo x > tobundle/x
533 533 $ hg -R tobundle add tobundle/x
534 534 $ hg -R tobundle commit -m'x'
535 535 $ hg -R tobundle update -r -2
536 536 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
537 537 $ echo y > tobundle/y
538 538 $ hg -R tobundle branch test
539 539 marked working directory as branch test
540 540 (branches are permanent and global, did you want a bookmark?)
541 541 $ hg -R tobundle add tobundle/y
542 542 $ hg -R tobundle commit -m'y'
543 543 $ hg -R tobundle bundle tobundle.hg
544 544 searching for changes
545 545 2 changesets found
546 546 $ hg unbundle tobundle.hg
547 547 adding changesets
548 548 adding manifests
549 549 adding file changes
550 550 added 2 changesets with 2 changes to 2 files (+1 heads)
551 551 (run 'hg heads' to see heads, 'hg merge' to merge)
552 552
553 553 update to active bookmark if it's not the parent
554 554
555 555 $ hg summary
556 556 parent: 2:db815d6d32e6
557 557 2
558 558 branch: default
559 559 bookmarks: *Z Y x y
560 560 commit: 1 added, 1 unknown (new branch head)
561 561 update: 2 new changesets (update)
562 562 phases: 5 draft
563 563 $ hg update
564 564 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
565 565 updating bookmark Z
566 566 $ hg bookmarks
567 567 X2 1:925d80f479bb
568 568 Y 2:db815d6d32e6
569 569 * Z 3:125c9a1d6df6
570 570 x y 2:db815d6d32e6
571 571
572 572 pull --update works the same as pull && update
573 573
574 574 $ hg bookmark -r3 Y
575 575 moving bookmark 'Y' forward from db815d6d32e6
576 576 $ cp -R ../cloned-bookmarks-update ../cloned-bookmarks-manual-update
577 577 $ cp -R ../cloned-bookmarks-update ../cloned-bookmarks-manual-update-with-divergence
578 578
579 579 (manual version)
580 580
581 581 $ hg -R ../cloned-bookmarks-manual-update update Y
582 582 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
583 583 (activating bookmark Y)
584 584 $ hg -R ../cloned-bookmarks-manual-update pull .
585 585 pulling from .
586 586 searching for changes
587 587 adding changesets
588 588 adding manifests
589 589 adding file changes
590 590 added 2 changesets with 2 changes to 2 files (+1 heads)
591 591 updating bookmark Y
592 592 updating bookmark Z
593 593 (run 'hg heads' to see heads, 'hg merge' to merge)
594 594
595 595 (# tests strange but with --date crashing when bookmark have to move)
596 596
597 597 $ hg -R ../cloned-bookmarks-manual-update update -d 1986
598 598 abort: revision matching date not found
599 599 [255]
600 600 $ hg -R ../cloned-bookmarks-manual-update update
601 601 updating to active bookmark Y
602 602 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
603 603
604 604 (all in one version)
605 605
606 606 $ hg -R ../cloned-bookmarks-update update Y
607 607 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
608 608 (activating bookmark Y)
609 609 $ hg -R ../cloned-bookmarks-update pull --update .
610 610 pulling from .
611 611 searching for changes
612 612 adding changesets
613 613 adding manifests
614 614 adding file changes
615 615 added 2 changesets with 2 changes to 2 files (+1 heads)
616 616 updating bookmark Y
617 617 updating bookmark Z
618 618 updating to active bookmark Y
619 619 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
620 620
621 621 We warn about divergent during bare update to the active bookmark
622 622
623 623 $ hg -R ../cloned-bookmarks-manual-update-with-divergence update Y
624 624 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
625 625 (activating bookmark Y)
626 626 $ hg -R ../cloned-bookmarks-manual-update-with-divergence bookmarks -r X2 Y@1
627 627 $ hg -R ../cloned-bookmarks-manual-update-with-divergence bookmarks
628 628 X2 1:925d80f479bb
629 629 * Y 2:db815d6d32e6
630 630 Y@1 1:925d80f479bb
631 631 Z 2:db815d6d32e6
632 632 x y 2:db815d6d32e6
633 633 $ hg -R ../cloned-bookmarks-manual-update-with-divergence pull
634 634 pulling from $TESTTMP/repo (glob)
635 635 searching for changes
636 636 adding changesets
637 637 adding manifests
638 638 adding file changes
639 639 added 2 changesets with 2 changes to 2 files (+1 heads)
640 640 updating bookmark Y
641 641 updating bookmark Z
642 642 (run 'hg heads' to see heads, 'hg merge' to merge)
643 643 $ hg -R ../cloned-bookmarks-manual-update-with-divergence update
644 644 updating to active bookmark Y
645 645 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
646 646 1 other divergent bookmarks for "Y"
647 647
648 648 test wrongly formated bookmark
649 649
650 650 $ echo '' >> .hg/bookmarks
651 651 $ hg bookmarks
652 652 X2 1:925d80f479bb
653 653 Y 3:125c9a1d6df6
654 654 * Z 3:125c9a1d6df6
655 655 x y 2:db815d6d32e6
656 656 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
657 657 $ hg bookmarks
658 658 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
659 659 X2 1:925d80f479bb
660 660 Y 3:125c9a1d6df6
661 661 * Z 3:125c9a1d6df6
662 662 x y 2:db815d6d32e6
663 663
664 664 test missing revisions
665 665
666 666 $ echo "925d80f479bc z" > .hg/bookmarks
667 667 $ hg book
668 668 no bookmarks set
669 669
670 670 test stripping a non-checked-out but bookmarked revision
671 671
672 672 $ hg log --graph
673 673 o changeset: 4:9ba5f110a0b3
674 674 | branch: test
675 675 | tag: tip
676 676 | parent: 2:db815d6d32e6
677 677 | user: test
678 678 | date: Thu Jan 01 00:00:00 1970 +0000
679 679 | summary: y
680 680 |
681 681 | @ changeset: 3:125c9a1d6df6
682 682 |/ user: test
683 683 | date: Thu Jan 01 00:00:00 1970 +0000
684 684 | summary: x
685 685 |
686 686 o changeset: 2:db815d6d32e6
687 687 | parent: 0:f7b1eb17ad24
688 688 | user: test
689 689 | date: Thu Jan 01 00:00:00 1970 +0000
690 690 | summary: 2
691 691 |
692 692 | o changeset: 1:925d80f479bb
693 693 |/ user: test
694 694 | date: Thu Jan 01 00:00:00 1970 +0000
695 695 | summary: 1
696 696 |
697 697 o changeset: 0:f7b1eb17ad24
698 698 user: test
699 699 date: Thu Jan 01 00:00:00 1970 +0000
700 700 summary: 0
701 701
702 702 $ hg book should-end-on-two
703 703 $ hg co --clean 4
704 704 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
705 705 (leaving bookmark should-end-on-two)
706 706 $ hg book four
707 707 $ hg --config extensions.mq= strip 3
708 708 saved backup bundle to * (glob)
709 709 should-end-on-two should end up pointing to revision 2, as that's the
710 710 tipmost surviving ancestor of the stripped revision.
711 711 $ hg log --graph
712 712 @ changeset: 3:9ba5f110a0b3
713 713 | branch: test
714 714 | bookmark: four
715 715 | tag: tip
716 716 | user: test
717 717 | date: Thu Jan 01 00:00:00 1970 +0000
718 718 | summary: y
719 719 |
720 720 o changeset: 2:db815d6d32e6
721 721 | bookmark: should-end-on-two
722 722 | parent: 0:f7b1eb17ad24
723 723 | user: test
724 724 | date: Thu Jan 01 00:00:00 1970 +0000
725 725 | summary: 2
726 726 |
727 727 | o changeset: 1:925d80f479bb
728 728 |/ user: test
729 729 | date: Thu Jan 01 00:00:00 1970 +0000
730 730 | summary: 1
731 731 |
732 732 o changeset: 0:f7b1eb17ad24
733 733 user: test
734 734 date: Thu Jan 01 00:00:00 1970 +0000
735 735 summary: 0
736 736
737 737
738 738 no-op update doesn't deactivate bookmarks
739 739
740 740 $ hg bookmarks
741 741 * four 3:9ba5f110a0b3
742 742 should-end-on-two 2:db815d6d32e6
743 743 $ hg up four
744 744 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
745 745 $ hg up
746 746 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
747 747 $ hg sum
748 748 parent: 3:9ba5f110a0b3 tip
749 749 y
750 750 branch: test
751 751 bookmarks: *four
752 752 commit: 2 unknown (clean)
753 753 update: (current)
754 754 phases: 4 draft
755 755
756 756 test clearing divergent bookmarks of linear ancestors
757 757
758 758 $ hg bookmark Z -r 0
759 759 $ hg bookmark Z@1 -r 1
760 760 $ hg bookmark Z@2 -r 2
761 761 $ hg bookmark Z@3 -r 3
762 762 $ hg book
763 763 Z 0:f7b1eb17ad24
764 764 Z@1 1:925d80f479bb
765 765 Z@2 2:db815d6d32e6
766 766 Z@3 3:9ba5f110a0b3
767 767 * four 3:9ba5f110a0b3
768 768 should-end-on-two 2:db815d6d32e6
769 769 $ hg bookmark Z
770 770 moving bookmark 'Z' forward from f7b1eb17ad24
771 771 $ hg book
772 772 * Z 3:9ba5f110a0b3
773 773 Z@1 1:925d80f479bb
774 774 four 3:9ba5f110a0b3
775 775 should-end-on-two 2:db815d6d32e6
776 776
777 777 test clearing only a single divergent bookmark across branches
778 778
779 779 $ hg book foo -r 1
780 780 $ hg book foo@1 -r 0
781 781 $ hg book foo@2 -r 2
782 782 $ hg book foo@3 -r 3
783 783 $ hg book foo -r foo@3
784 784 $ hg book
785 785 * Z 3:9ba5f110a0b3
786 786 Z@1 1:925d80f479bb
787 787 foo 3:9ba5f110a0b3
788 788 foo@1 0:f7b1eb17ad24
789 789 foo@2 2:db815d6d32e6
790 790 four 3:9ba5f110a0b3
791 791 should-end-on-two 2:db815d6d32e6
792 792
793 793 pull --update works the same as pull && update (case #2)
794 794
795 795 It is assumed that "hg pull" itself doesn't update current active
796 796 bookmark ('Y' in tests below).
797 797
798 798 $ hg pull -q ../cloned-bookmarks-update
799 799 divergent bookmark Z stored as Z@2
800 800
801 801 (pulling revision on another named branch with --update updates
802 802 neither the working directory nor current active bookmark: "no-op"
803 803 case)
804 804
805 805 $ echo yy >> y
806 806 $ hg commit -m yy
807 807
808 808 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
809 809 * Y 3:125c9a1d6df6
810 810 $ hg -R ../cloned-bookmarks-update pull . --update
811 811 pulling from .
812 812 searching for changes
813 813 adding changesets
814 814 adding manifests
815 815 adding file changes
816 816 added 1 changesets with 1 changes to 1 files
817 817 divergent bookmark Z stored as Z@default
818 818 adding remote bookmark foo
819 819 adding remote bookmark four
820 820 adding remote bookmark should-end-on-two
821 821 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
822 822 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
823 823 3:125c9a1d6df6
824 824 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
825 825 * Y 3:125c9a1d6df6
826 826
827 827 (pulling revision on current named/topological branch with --update
828 828 updates the working directory and current active bookmark)
829 829
830 830 $ hg update -C -q 125c9a1d6df6
831 831 $ echo xx >> x
832 832 $ hg commit -m xx
833 833
834 834 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
835 835 * Y 3:125c9a1d6df6
836 836 $ hg -R ../cloned-bookmarks-update pull . --update
837 837 pulling from .
838 838 searching for changes
839 839 adding changesets
840 840 adding manifests
841 841 adding file changes
842 842 added 1 changesets with 1 changes to 1 files
843 843 divergent bookmark Z stored as Z@default
844 844 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
845 845 updating bookmark Y
846 846 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
847 847 6:81dcce76aa0b
848 848 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
849 849 * Y 6:81dcce76aa0b
850 850
851 851 $ cd ..
852 852
853 853 ensure changelog is written before bookmarks
854 854 $ hg init orderrepo
855 855 $ cd orderrepo
856 856 $ touch a
857 857 $ hg commit -Aqm one
858 858 $ hg book mybook
859 859 $ echo a > a
860 860
861 861 $ cat > $TESTTMP/pausefinalize.py <<EOF
862 862 > from mercurial import extensions, localrepo
863 863 > import os, time
864 864 > def transaction(orig, self, desc, report=None):
865 865 > tr = orig(self, desc, report)
866 866 > def sleep(*args, **kwargs):
867 867 > retry = 20
868 868 > while retry > 0 and not os.path.exists("$TESTTMP/unpause"):
869 869 > retry -= 1
870 870 > time.sleep(0.5)
871 871 > if os.path.exists("$TESTTMP/unpause"):
872 872 > os.remove("$TESTTMP/unpause")
873 873 > # It is important that this finalizer start with 'a', so it runs before
874 874 > # the changelog finalizer appends to the changelog.
875 875 > tr.addfinalize('a-sleep', sleep)
876 876 > return tr
877 877 >
878 878 > def extsetup(ui):
879 879 > # This extension inserts an artifical pause during the transaction
880 880 > # finalizer, so we can run commands mid-transaction-close.
881 881 > extensions.wrapfunction(localrepo.localrepository, 'transaction',
882 882 > transaction)
883 883 > EOF
884 884 $ hg commit -qm two --config extensions.pausefinalize=$TESTTMP/pausefinalize.py &
885 885 $ sleep 2
886 886 $ hg log -r .
887 887 changeset: 0:867bc5792c8c
888 888 bookmark: mybook
889 889 tag: tip
890 890 user: test
891 891 date: Thu Jan 01 00:00:00 1970 +0000
892 892 summary: one
893 893
894 894 $ hg bookmarks
895 895 * mybook 0:867bc5792c8c
896 896 $ touch $TESTTMP/unpause
897 897
898 898 $ cd ..
899
900 check whether HG_PENDING makes pending changes only in related
901 repositories visible to an external hook.
902
903 (emulate a transaction running concurrently by copied
904 .hg/bookmarks.pending in subsequent test)
905
906 $ cat > $TESTTMP/savepending.sh <<EOF
907 > cp .hg/bookmarks.pending .hg/bookmarks.pending.saved
908 > exit 1 # to avoid adding new bookmark for subsequent tests
909 > EOF
910
911 $ hg init unrelated
912 $ cd unrelated
913 $ echo a > a
914 $ hg add a
915 $ hg commit -m '#0'
916 $ hg --config hooks.pretxnclose="sh $TESTTMP/savepending.sh" bookmarks INVISIBLE
917 transaction abort!
918 rollback completed
919 abort: pretxnclose hook exited with status 1
920 [255]
921 $ cp .hg/bookmarks.pending.saved .hg/bookmarks.pending
922
923 (check visible bookmarks while transaction running in repo)
924
925 $ cat > $TESTTMP/checkpending.sh <<EOF
926 > echo "@repo"
927 > hg -R $TESTTMP/repo bookmarks
928 > echo "@unrelated"
929 > hg -R $TESTTMP/unrelated bookmarks
930 > exit 1 # to avoid adding new bookmark for subsequent tests
931 > EOF
932
933 $ cd ../repo
934 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkpending.sh" bookmarks NEW
935 @repo
936 * NEW 6:81dcce76aa0b
937 X2 1:925d80f479bb
938 Y 4:125c9a1d6df6
939 Z 5:5fb12f0f2d51
940 Z@1 1:925d80f479bb
941 Z@2 4:125c9a1d6df6
942 foo 3:9ba5f110a0b3
943 foo@1 0:f7b1eb17ad24
944 foo@2 2:db815d6d32e6
945 four 3:9ba5f110a0b3
946 should-end-on-two 2:db815d6d32e6
947 x y 2:db815d6d32e6
948 @unrelated
949 no bookmarks set
950 transaction abort!
951 rollback completed
952 abort: pretxnclose hook exited with status 1
953 [255]
@@ -1,303 +1,364 b''
1 1 #require killdaemons
2 2
3 3 $ echo "[extensions]" >> $HGRCPATH
4 4 $ echo "share = " >> $HGRCPATH
5 5
6 6 prepare repo1
7 7
8 8 $ hg init repo1
9 9 $ cd repo1
10 10 $ echo a > a
11 11 $ hg commit -A -m'init'
12 12 adding a
13 13
14 14 share it
15 15
16 16 $ cd ..
17 17 $ hg share repo1 repo2
18 18 updating working directory
19 19 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
20 20
21 21 share shouldn't have a store dir
22 22
23 23 $ cd repo2
24 24 $ test -d .hg/store
25 25 [1]
26 26
27 27 Some sed versions appends newline, some don't, and some just fails
28 28
29 29 $ cat .hg/sharedpath; echo
30 30 $TESTTMP/repo1/.hg (glob)
31 31
32 32 trailing newline on .hg/sharedpath is ok
33 33 $ hg tip -q
34 34 0:d3873e73d99e
35 35 $ echo '' >> .hg/sharedpath
36 36 $ cat .hg/sharedpath
37 37 $TESTTMP/repo1/.hg (glob)
38 38 $ hg tip -q
39 39 0:d3873e73d99e
40 40
41 41 commit in shared clone
42 42
43 43 $ echo a >> a
44 44 $ hg commit -m'change in shared clone'
45 45
46 46 check original
47 47
48 48 $ cd ../repo1
49 49 $ hg log
50 50 changeset: 1:8af4dc49db9e
51 51 tag: tip
52 52 user: test
53 53 date: Thu Jan 01 00:00:00 1970 +0000
54 54 summary: change in shared clone
55 55
56 56 changeset: 0:d3873e73d99e
57 57 user: test
58 58 date: Thu Jan 01 00:00:00 1970 +0000
59 59 summary: init
60 60
61 61 $ hg update
62 62 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
63 63 $ cat a # should be two lines of "a"
64 64 a
65 65 a
66 66
67 67 commit in original
68 68
69 69 $ echo b > b
70 70 $ hg commit -A -m'another file'
71 71 adding b
72 72
73 73 check in shared clone
74 74
75 75 $ cd ../repo2
76 76 $ hg log
77 77 changeset: 2:c2e0ac586386
78 78 tag: tip
79 79 user: test
80 80 date: Thu Jan 01 00:00:00 1970 +0000
81 81 summary: another file
82 82
83 83 changeset: 1:8af4dc49db9e
84 84 user: test
85 85 date: Thu Jan 01 00:00:00 1970 +0000
86 86 summary: change in shared clone
87 87
88 88 changeset: 0:d3873e73d99e
89 89 user: test
90 90 date: Thu Jan 01 00:00:00 1970 +0000
91 91 summary: init
92 92
93 93 $ hg update
94 94 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
95 95 $ cat b # should exist with one "b"
96 96 b
97 97
98 98 hg serve shared clone
99 99
100 100 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid
101 101 $ cat hg.pid >> $DAEMON_PIDS
102 102 $ get-with-headers.py localhost:$HGPORT 'raw-file/'
103 103 200 Script output follows
104 104
105 105
106 106 -rw-r--r-- 4 a
107 107 -rw-r--r-- 2 b
108 108
109 109
110 110
111 111 test unshare command
112 112
113 113 $ hg unshare
114 114 $ test -d .hg/store
115 115 $ test -f .hg/sharedpath
116 116 [1]
117 117 $ hg unshare
118 118 abort: this is not a shared repo
119 119 [255]
120 120
121 121 check that a change does not propagate
122 122
123 123 $ echo b >> b
124 124 $ hg commit -m'change in unshared'
125 125 $ cd ../repo1
126 126 $ hg id -r tip
127 127 c2e0ac586386 tip
128 128
129 129 $ cd ..
130 130
131 131
132 132 test sharing bookmarks
133 133
134 134 $ hg share -B repo1 repo3
135 135 updating working directory
136 136 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
137 137 $ cd repo1
138 138 $ hg bookmark bm1
139 139 $ hg bookmarks
140 140 * bm1 2:c2e0ac586386
141 141 $ cd ../repo2
142 142 $ hg book bm2
143 143 $ hg bookmarks
144 144 * bm2 3:0e6e70d1d5f1
145 145 $ cd ../repo3
146 146 $ hg bookmarks
147 147 bm1 2:c2e0ac586386
148 148 $ hg book bm3
149 149 $ hg bookmarks
150 150 bm1 2:c2e0ac586386
151 151 * bm3 2:c2e0ac586386
152 152 $ cd ../repo1
153 153 $ hg bookmarks
154 154 * bm1 2:c2e0ac586386
155 155 bm3 2:c2e0ac586386
156 156
157 check whether HG_PENDING makes pending changes only in relatd
158 repositories visible to an external hook.
159
160 In "hg share" case, another transaction can't run in other
161 repositories sharing same source repository, because starting
162 transaction requires locking store of source repository.
163
164 Therefore, this test scenario ignores checking visibility of
165 .hg/bookmakrs.pending in repo2, which shares repo1 without bookmarks.
166
167 $ cat > $TESTTMP/checkbookmarks.sh <<EOF
168 > echo "@repo1"
169 > hg -R $TESTTMP/repo1 bookmarks
170 > echo "@repo2"
171 > hg -R $TESTTMP/repo2 bookmarks
172 > echo "@repo3"
173 > hg -R $TESTTMP/repo3 bookmarks
174 > exit 1 # to avoid adding new bookmark for subsequent tests
175 > EOF
176
177 $ cd ../repo1
178 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkbookmarks.sh" -q book bmX
179 @repo1
180 bm1 2:c2e0ac586386
181 bm3 2:c2e0ac586386
182 * bmX 2:c2e0ac586386
183 @repo2
184 * bm2 3:0e6e70d1d5f1
185 @repo3
186 bm1 2:c2e0ac586386
187 * bm3 2:c2e0ac586386
188 bmX 2:c2e0ac586386
189 transaction abort!
190 rollback completed
191 abort: pretxnclose hook exited with status 1
192 [255]
193 $ hg book bm1
194
195 FYI, in contrast to above test, bmX is invisible in repo1 (= shared
196 src), because (1) HG_PENDING refers only repo3 and (2)
197 "bookmarks.pending" is written only into repo3.
198
199 $ cd ../repo3
200 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkbookmarks.sh" -q book bmX
201 @repo1
202 * bm1 2:c2e0ac586386
203 bm3 2:c2e0ac586386
204 @repo2
205 * bm2 3:0e6e70d1d5f1
206 @repo3
207 bm1 2:c2e0ac586386
208 bm3 2:c2e0ac586386
209 * bmX 2:c2e0ac586386
210 transaction abort!
211 rollback completed
212 abort: pretxnclose hook exited with status 1
213 [255]
214 $ hg book bm3
215
216 $ cd ../repo1
217
157 218 test that commits work
158 219
159 220 $ echo 'shared bookmarks' > a
160 221 $ hg commit -m 'testing shared bookmarks'
161 222 $ hg bookmarks
162 223 * bm1 3:b87954705719
163 224 bm3 2:c2e0ac586386
164 225 $ cd ../repo3
165 226 $ hg bookmarks
166 227 bm1 3:b87954705719
167 228 * bm3 2:c2e0ac586386
168 229 $ echo 'more shared bookmarks' > a
169 230 $ hg commit -m 'testing shared bookmarks'
170 231 created new head
171 232 $ hg bookmarks
172 233 bm1 3:b87954705719
173 234 * bm3 4:62f4ded848e4
174 235 $ cd ../repo1
175 236 $ hg bookmarks
176 237 * bm1 3:b87954705719
177 238 bm3 4:62f4ded848e4
178 239 $ cd ..
179 240
180 241 test pushing bookmarks works
181 242
182 243 $ hg clone repo3 repo4
183 244 updating to branch default
184 245 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
185 246 $ cd repo4
186 247 $ hg boo bm4
187 248 $ echo foo > b
188 249 $ hg commit -m 'foo in b'
189 250 $ hg boo
190 251 bm1 3:b87954705719
191 252 bm3 4:62f4ded848e4
192 253 * bm4 5:92793bfc8cad
193 254 $ hg push -B bm4
194 255 pushing to $TESTTMP/repo3 (glob)
195 256 searching for changes
196 257 adding changesets
197 258 adding manifests
198 259 adding file changes
199 260 added 1 changesets with 1 changes to 1 files
200 261 exporting bookmark bm4
201 262 $ cd ../repo1
202 263 $ hg bookmarks
203 264 * bm1 3:b87954705719
204 265 bm3 4:62f4ded848e4
205 266 bm4 5:92793bfc8cad
206 267 $ cd ../repo3
207 268 $ hg bookmarks
208 269 bm1 3:b87954705719
209 270 * bm3 4:62f4ded848e4
210 271 bm4 5:92793bfc8cad
211 272 $ cd ..
212 273
213 274 test behavior when sharing a shared repo
214 275
215 276 $ hg share -B repo3 repo5
216 277 updating working directory
217 278 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
218 279 $ cd repo5
219 280 $ hg book
220 281 bm1 3:b87954705719
221 282 bm3 4:62f4ded848e4
222 283 bm4 5:92793bfc8cad
223 284 $ cd ..
224 285
225 286 test what happens when an active bookmark is deleted
226 287
227 288 $ cd repo1
228 289 $ hg boo -d bm3
229 290 $ hg boo
230 291 * bm1 3:b87954705719
231 292 bm4 5:92793bfc8cad
232 293 $ cd ../repo3
233 294 $ hg boo
234 295 bm1 3:b87954705719
235 296 bm4 5:92793bfc8cad
236 297 $ cd ..
237 298
238 299 verify that bookmarks are not written on failed transaction
239 300
240 301 $ cat > failpullbookmarks.py << EOF
241 302 > """A small extension that makes bookmark pulls fail, for testing"""
242 303 > from mercurial import extensions, exchange, error
243 304 > def _pullbookmarks(orig, pullop):
244 305 > orig(pullop)
245 306 > raise error.HookAbort('forced failure by extension')
246 307 > def extsetup(ui):
247 308 > extensions.wrapfunction(exchange, '_pullbookmarks', _pullbookmarks)
248 309 > EOF
249 310 $ cd repo4
250 311 $ hg boo
251 312 bm1 3:b87954705719
252 313 bm3 4:62f4ded848e4
253 314 * bm4 5:92793bfc8cad
254 315 $ cd ../repo3
255 316 $ hg boo
256 317 bm1 3:b87954705719
257 318 bm4 5:92793bfc8cad
258 319 $ hg --config "extensions.failpullbookmarks=$TESTTMP/failpullbookmarks.py" pull $TESTTMP/repo4
259 320 pulling from $TESTTMP/repo4 (glob)
260 321 searching for changes
261 322 no changes found
262 323 adding remote bookmark bm3
263 324 abort: forced failure by extension
264 325 [255]
265 326 $ hg boo
266 327 bm1 3:b87954705719
267 328 bm4 5:92793bfc8cad
268 329 $ hg pull $TESTTMP/repo4
269 330 pulling from $TESTTMP/repo4 (glob)
270 331 searching for changes
271 332 no changes found
272 333 adding remote bookmark bm3
273 334 $ hg boo
274 335 bm1 3:b87954705719
275 336 * bm3 4:62f4ded848e4
276 337 bm4 5:92793bfc8cad
277 338 $ cd ..
278 339
279 340 verify bookmark behavior after unshare
280 341
281 342 $ cd repo3
282 343 $ hg unshare
283 344 $ hg boo
284 345 bm1 3:b87954705719
285 346 * bm3 4:62f4ded848e4
286 347 bm4 5:92793bfc8cad
287 348 $ hg boo -d bm4
288 349 $ hg boo bm5
289 350 $ hg boo
290 351 bm1 3:b87954705719
291 352 bm3 4:62f4ded848e4
292 353 * bm5 4:62f4ded848e4
293 354 $ cd ../repo1
294 355 $ hg boo
295 356 * bm1 3:b87954705719
296 357 bm3 4:62f4ded848e4
297 358 bm4 5:92793bfc8cad
298 359 $ cd ..
299 360
300 361 Explicitly kill daemons to let the test exit on Windows
301 362
302 363 $ killdaemons.py
303 364
General Comments 0
You need to be logged in to leave comments. Login now