##// END OF EJS Templates
copystore: provide unit to ui.makeprogress()
av6 -
r40671:e5f54c4e stable
parent child Browse files
Show More
@@ -1,1229 +1,1229 b''
1 1 # hg.py - repository classes for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 from __future__ import absolute_import
10 10
11 11 import errno
12 12 import hashlib
13 13 import os
14 14 import shutil
15 15 import stat
16 16
17 17 from .i18n import _
18 18 from .node import (
19 19 nullid,
20 20 )
21 21
22 22 from . import (
23 23 bookmarks,
24 24 bundlerepo,
25 25 cacheutil,
26 26 cmdutil,
27 27 destutil,
28 28 discovery,
29 29 error,
30 30 exchange,
31 31 extensions,
32 32 httppeer,
33 33 localrepo,
34 34 lock,
35 35 logcmdutil,
36 36 logexchange,
37 37 merge as mergemod,
38 38 narrowspec,
39 39 node,
40 40 phases,
41 41 scmutil,
42 42 sshpeer,
43 43 statichttprepo,
44 44 ui as uimod,
45 45 unionrepo,
46 46 url,
47 47 util,
48 48 verify as verifymod,
49 49 vfs as vfsmod,
50 50 )
51 51
52 52 release = lock.release
53 53
54 54 # shared features
55 55 sharedbookmarks = 'bookmarks'
56 56
57 57 def _local(path):
58 58 path = util.expandpath(util.urllocalpath(path))
59 59 return (os.path.isfile(path) and bundlerepo or localrepo)
60 60
61 61 def addbranchrevs(lrepo, other, branches, revs):
62 62 peer = other.peer() # a courtesy to callers using a localrepo for other
63 63 hashbranch, branches = branches
64 64 if not hashbranch and not branches:
65 65 x = revs or None
66 66 if revs:
67 67 y = revs[0]
68 68 else:
69 69 y = None
70 70 return x, y
71 71 if revs:
72 72 revs = list(revs)
73 73 else:
74 74 revs = []
75 75
76 76 if not peer.capable('branchmap'):
77 77 if branches:
78 78 raise error.Abort(_("remote branch lookup not supported"))
79 79 revs.append(hashbranch)
80 80 return revs, revs[0]
81 81
82 82 with peer.commandexecutor() as e:
83 83 branchmap = e.callcommand('branchmap', {}).result()
84 84
85 85 def primary(branch):
86 86 if branch == '.':
87 87 if not lrepo:
88 88 raise error.Abort(_("dirstate branch not accessible"))
89 89 branch = lrepo.dirstate.branch()
90 90 if branch in branchmap:
91 91 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
92 92 return True
93 93 else:
94 94 return False
95 95
96 96 for branch in branches:
97 97 if not primary(branch):
98 98 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
99 99 if hashbranch:
100 100 if not primary(hashbranch):
101 101 revs.append(hashbranch)
102 102 return revs, revs[0]
103 103
104 104 def parseurl(path, branches=None):
105 105 '''parse url#branch, returning (url, (branch, branches))'''
106 106
107 107 u = util.url(path)
108 108 branch = None
109 109 if u.fragment:
110 110 branch = u.fragment
111 111 u.fragment = None
112 112 return bytes(u), (branch, branches or [])
113 113
114 114 schemes = {
115 115 'bundle': bundlerepo,
116 116 'union': unionrepo,
117 117 'file': _local,
118 118 'http': httppeer,
119 119 'https': httppeer,
120 120 'ssh': sshpeer,
121 121 'static-http': statichttprepo,
122 122 }
123 123
124 124 def _peerlookup(path):
125 125 u = util.url(path)
126 126 scheme = u.scheme or 'file'
127 127 thing = schemes.get(scheme) or schemes['file']
128 128 try:
129 129 return thing(path)
130 130 except TypeError:
131 131 # we can't test callable(thing) because 'thing' can be an unloaded
132 132 # module that implements __call__
133 133 if not util.safehasattr(thing, 'instance'):
134 134 raise
135 135 return thing
136 136
137 137 def islocal(repo):
138 138 '''return true if repo (or path pointing to repo) is local'''
139 139 if isinstance(repo, bytes):
140 140 try:
141 141 return _peerlookup(repo).islocal(repo)
142 142 except AttributeError:
143 143 return False
144 144 return repo.local()
145 145
146 146 def openpath(ui, path):
147 147 '''open path with open if local, url.open if remote'''
148 148 pathurl = util.url(path, parsequery=False, parsefragment=False)
149 149 if pathurl.islocal():
150 150 return util.posixfile(pathurl.localpath(), 'rb')
151 151 else:
152 152 return url.open(ui, path)
153 153
154 154 # a list of (ui, repo) functions called for wire peer initialization
155 155 wirepeersetupfuncs = []
156 156
157 157 def _peerorrepo(ui, path, create=False, presetupfuncs=None,
158 158 intents=None, createopts=None):
159 159 """return a repository object for the specified path"""
160 160 obj = _peerlookup(path).instance(ui, path, create, intents=intents,
161 161 createopts=createopts)
162 162 ui = getattr(obj, "ui", ui)
163 163 if ui.configbool('devel', 'debug.extensions'):
164 164 log = lambda msg, *values: ui.debug('debug.extensions: ',
165 165 msg % values, label='debug.extensions')
166 166 else:
167 167 log = lambda *a, **kw: None
168 168 for f in presetupfuncs or []:
169 169 f(ui, obj)
170 170 log('- executing reposetup hooks\n')
171 171 with util.timedcm('all reposetup') as allreposetupstats:
172 172 for name, module in extensions.extensions(ui):
173 173 log(' - running reposetup for %s\n' % (name,))
174 174 hook = getattr(module, 'reposetup', None)
175 175 if hook:
176 176 with util.timedcm('reposetup %r', name) as stats:
177 177 hook(ui, obj)
178 178 log(' > reposetup for %r took %s\n', name, stats)
179 179 log('> all reposetup took %s\n', allreposetupstats)
180 180 if not obj.local():
181 181 for f in wirepeersetupfuncs:
182 182 f(ui, obj)
183 183 return obj
184 184
185 185 def repository(ui, path='', create=False, presetupfuncs=None, intents=None,
186 186 createopts=None):
187 187 """return a repository object for the specified path"""
188 188 peer = _peerorrepo(ui, path, create, presetupfuncs=presetupfuncs,
189 189 intents=intents, createopts=createopts)
190 190 repo = peer.local()
191 191 if not repo:
192 192 raise error.Abort(_("repository '%s' is not local") %
193 193 (path or peer.url()))
194 194 return repo.filtered('visible')
195 195
196 196 def peer(uiorrepo, opts, path, create=False, intents=None, createopts=None):
197 197 '''return a repository peer for the specified path'''
198 198 rui = remoteui(uiorrepo, opts)
199 199 return _peerorrepo(rui, path, create, intents=intents,
200 200 createopts=createopts).peer()
201 201
202 202 def defaultdest(source):
203 203 '''return default destination of clone if none is given
204 204
205 205 >>> defaultdest(b'foo')
206 206 'foo'
207 207 >>> defaultdest(b'/foo/bar')
208 208 'bar'
209 209 >>> defaultdest(b'/')
210 210 ''
211 211 >>> defaultdest(b'')
212 212 ''
213 213 >>> defaultdest(b'http://example.org/')
214 214 ''
215 215 >>> defaultdest(b'http://example.org/foo/')
216 216 'foo'
217 217 '''
218 218 path = util.url(source).path
219 219 if not path:
220 220 return ''
221 221 return os.path.basename(os.path.normpath(path))
222 222
223 223 def sharedreposource(repo):
224 224 """Returns repository object for source repository of a shared repo.
225 225
226 226 If repo is not a shared repository, returns None.
227 227 """
228 228 if repo.sharedpath == repo.path:
229 229 return None
230 230
231 231 if util.safehasattr(repo, 'srcrepo') and repo.srcrepo:
232 232 return repo.srcrepo
233 233
234 234 # the sharedpath always ends in the .hg; we want the path to the repo
235 235 source = repo.vfs.split(repo.sharedpath)[0]
236 236 srcurl, branches = parseurl(source)
237 237 srcrepo = repository(repo.ui, srcurl)
238 238 repo.srcrepo = srcrepo
239 239 return srcrepo
240 240
241 241 def share(ui, source, dest=None, update=True, bookmarks=True, defaultpath=None,
242 242 relative=False):
243 243 '''create a shared repository'''
244 244
245 245 if not islocal(source):
246 246 raise error.Abort(_('can only share local repositories'))
247 247
248 248 if not dest:
249 249 dest = defaultdest(source)
250 250 else:
251 251 dest = ui.expandpath(dest)
252 252
253 253 if isinstance(source, bytes):
254 254 origsource = ui.expandpath(source)
255 255 source, branches = parseurl(origsource)
256 256 srcrepo = repository(ui, source)
257 257 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
258 258 else:
259 259 srcrepo = source.local()
260 260 checkout = None
261 261
262 262 shareditems = set()
263 263 if bookmarks:
264 264 shareditems.add(sharedbookmarks)
265 265
266 266 r = repository(ui, dest, create=True, createopts={
267 267 'sharedrepo': srcrepo,
268 268 'sharedrelative': relative,
269 269 'shareditems': shareditems,
270 270 })
271 271
272 272 postshare(srcrepo, r, defaultpath=defaultpath)
273 273 _postshareupdate(r, update, checkout=checkout)
274 274 return r
275 275
276 276 def unshare(ui, repo):
277 277 """convert a shared repository to a normal one
278 278
279 279 Copy the store data to the repo and remove the sharedpath data.
280 280
281 281 Returns a new repository object representing the unshared repository.
282 282
283 283 The passed repository object is not usable after this function is
284 284 called.
285 285 """
286 286
287 287 destlock = lock = None
288 288 lock = repo.lock()
289 289 try:
290 290 # we use locks here because if we race with commit, we
291 291 # can end up with extra data in the cloned revlogs that's
292 292 # not pointed to by changesets, thus causing verify to
293 293 # fail
294 294
295 295 destlock = copystore(ui, repo, repo.path)
296 296
297 297 sharefile = repo.vfs.join('sharedpath')
298 298 util.rename(sharefile, sharefile + '.old')
299 299
300 300 repo.requirements.discard('shared')
301 301 repo.requirements.discard('relshared')
302 302 repo._writerequirements()
303 303 finally:
304 304 destlock and destlock.release()
305 305 lock and lock.release()
306 306
307 307 # Removing share changes some fundamental properties of the repo instance.
308 308 # So we instantiate a new repo object and operate on it rather than
309 309 # try to keep the existing repo usable.
310 310 newrepo = repository(repo.baseui, repo.root, create=False)
311 311
312 312 # TODO: figure out how to access subrepos that exist, but were previously
313 313 # removed from .hgsub
314 314 c = newrepo['.']
315 315 subs = c.substate
316 316 for s in sorted(subs):
317 317 c.sub(s).unshare()
318 318
319 319 localrepo.poisonrepository(repo)
320 320
321 321 return newrepo
322 322
323 323 def postshare(sourcerepo, destrepo, defaultpath=None):
324 324 """Called after a new shared repo is created.
325 325
326 326 The new repo only has a requirements file and pointer to the source.
327 327 This function configures additional shared data.
328 328
329 329 Extensions can wrap this function and write additional entries to
330 330 destrepo/.hg/shared to indicate additional pieces of data to be shared.
331 331 """
332 332 default = defaultpath or sourcerepo.ui.config('paths', 'default')
333 333 if default:
334 334 template = ('[paths]\n'
335 335 'default = %s\n')
336 336 destrepo.vfs.write('hgrc', util.tonativeeol(template % default))
337 337
338 338 def _postshareupdate(repo, update, checkout=None):
339 339 """Maybe perform a working directory update after a shared repo is created.
340 340
341 341 ``update`` can be a boolean or a revision to update to.
342 342 """
343 343 if not update:
344 344 return
345 345
346 346 repo.ui.status(_("updating working directory\n"))
347 347 if update is not True:
348 348 checkout = update
349 349 for test in (checkout, 'default', 'tip'):
350 350 if test is None:
351 351 continue
352 352 try:
353 353 uprev = repo.lookup(test)
354 354 break
355 355 except error.RepoLookupError:
356 356 continue
357 357 _update(repo, uprev)
358 358
359 359 def copystore(ui, srcrepo, destpath):
360 360 '''copy files from store of srcrepo in destpath
361 361
362 362 returns destlock
363 363 '''
364 364 destlock = None
365 365 try:
366 366 hardlink = None
367 367 topic = _('linking') if hardlink else _('copying')
368 with ui.makeprogress(topic) as progress:
368 with ui.makeprogress(topic, unit=_('files')) as progress:
369 369 num = 0
370 370 srcpublishing = srcrepo.publishing()
371 371 srcvfs = vfsmod.vfs(srcrepo.sharedpath)
372 372 dstvfs = vfsmod.vfs(destpath)
373 373 for f in srcrepo.store.copylist():
374 374 if srcpublishing and f.endswith('phaseroots'):
375 375 continue
376 376 dstbase = os.path.dirname(f)
377 377 if dstbase and not dstvfs.exists(dstbase):
378 378 dstvfs.mkdir(dstbase)
379 379 if srcvfs.exists(f):
380 380 if f.endswith('data'):
381 381 # 'dstbase' may be empty (e.g. revlog format 0)
382 382 lockfile = os.path.join(dstbase, "lock")
383 383 # lock to avoid premature writing to the target
384 384 destlock = lock.lock(dstvfs, lockfile)
385 385 hardlink, n = util.copyfiles(srcvfs.join(f), dstvfs.join(f),
386 386 hardlink, progress)
387 387 num += n
388 388 if hardlink:
389 389 ui.debug("linked %d files\n" % num)
390 390 else:
391 391 ui.debug("copied %d files\n" % num)
392 392 return destlock
393 393 except: # re-raises
394 394 release(destlock)
395 395 raise
396 396
397 397 def clonewithshare(ui, peeropts, sharepath, source, srcpeer, dest, pull=False,
398 398 rev=None, update=True, stream=False):
399 399 """Perform a clone using a shared repo.
400 400
401 401 The store for the repository will be located at <sharepath>/.hg. The
402 402 specified revisions will be cloned or pulled from "source". A shared repo
403 403 will be created at "dest" and a working copy will be created if "update" is
404 404 True.
405 405 """
406 406 revs = None
407 407 if rev:
408 408 if not srcpeer.capable('lookup'):
409 409 raise error.Abort(_("src repository does not support "
410 410 "revision lookup and so doesn't "
411 411 "support clone by revision"))
412 412
413 413 # TODO this is batchable.
414 414 remoterevs = []
415 415 for r in rev:
416 416 with srcpeer.commandexecutor() as e:
417 417 remoterevs.append(e.callcommand('lookup', {
418 418 'key': r,
419 419 }).result())
420 420 revs = remoterevs
421 421
422 422 # Obtain a lock before checking for or cloning the pooled repo otherwise
423 423 # 2 clients may race creating or populating it.
424 424 pooldir = os.path.dirname(sharepath)
425 425 # lock class requires the directory to exist.
426 426 try:
427 427 util.makedir(pooldir, False)
428 428 except OSError as e:
429 429 if e.errno != errno.EEXIST:
430 430 raise
431 431
432 432 poolvfs = vfsmod.vfs(pooldir)
433 433 basename = os.path.basename(sharepath)
434 434
435 435 with lock.lock(poolvfs, '%s.lock' % basename):
436 436 if os.path.exists(sharepath):
437 437 ui.status(_('(sharing from existing pooled repository %s)\n') %
438 438 basename)
439 439 else:
440 440 ui.status(_('(sharing from new pooled repository %s)\n') % basename)
441 441 # Always use pull mode because hardlinks in share mode don't work
442 442 # well. Never update because working copies aren't necessary in
443 443 # share mode.
444 444 clone(ui, peeropts, source, dest=sharepath, pull=True,
445 445 revs=rev, update=False, stream=stream)
446 446
447 447 # Resolve the value to put in [paths] section for the source.
448 448 if islocal(source):
449 449 defaultpath = os.path.abspath(util.urllocalpath(source))
450 450 else:
451 451 defaultpath = source
452 452
453 453 sharerepo = repository(ui, path=sharepath)
454 454 share(ui, sharerepo, dest=dest, update=False, bookmarks=False,
455 455 defaultpath=defaultpath)
456 456
457 457 # We need to perform a pull against the dest repo to fetch bookmarks
458 458 # and other non-store data that isn't shared by default. In the case of
459 459 # non-existing shared repo, this means we pull from the remote twice. This
460 460 # is a bit weird. But at the time it was implemented, there wasn't an easy
461 461 # way to pull just non-changegroup data.
462 462 destrepo = repository(ui, path=dest)
463 463 exchange.pull(destrepo, srcpeer, heads=revs)
464 464
465 465 _postshareupdate(destrepo, update)
466 466
467 467 return srcpeer, peer(ui, peeropts, dest)
468 468
469 469 # Recomputing branch cache might be slow on big repos,
470 470 # so just copy it
471 471 def _copycache(srcrepo, dstcachedir, fname):
472 472 """copy a cache from srcrepo to destcachedir (if it exists)"""
473 473 srcbranchcache = srcrepo.vfs.join('cache/%s' % fname)
474 474 dstbranchcache = os.path.join(dstcachedir, fname)
475 475 if os.path.exists(srcbranchcache):
476 476 if not os.path.exists(dstcachedir):
477 477 os.mkdir(dstcachedir)
478 478 util.copyfile(srcbranchcache, dstbranchcache)
479 479
480 480 def clone(ui, peeropts, source, dest=None, pull=False, revs=None,
481 481 update=True, stream=False, branch=None, shareopts=None,
482 482 storeincludepats=None, storeexcludepats=None, depth=None):
483 483 """Make a copy of an existing repository.
484 484
485 485 Create a copy of an existing repository in a new directory. The
486 486 source and destination are URLs, as passed to the repository
487 487 function. Returns a pair of repository peers, the source and
488 488 newly created destination.
489 489
490 490 The location of the source is added to the new repository's
491 491 .hg/hgrc file, as the default to be used for future pulls and
492 492 pushes.
493 493
494 494 If an exception is raised, the partly cloned/updated destination
495 495 repository will be deleted.
496 496
497 497 Arguments:
498 498
499 499 source: repository object or URL
500 500
501 501 dest: URL of destination repository to create (defaults to base
502 502 name of source repository)
503 503
504 504 pull: always pull from source repository, even in local case or if the
505 505 server prefers streaming
506 506
507 507 stream: stream raw data uncompressed from repository (fast over
508 508 LAN, slow over WAN)
509 509
510 510 revs: revision to clone up to (implies pull=True)
511 511
512 512 update: update working directory after clone completes, if
513 513 destination is local repository (True means update to default rev,
514 514 anything else is treated as a revision)
515 515
516 516 branch: branches to clone
517 517
518 518 shareopts: dict of options to control auto sharing behavior. The "pool" key
519 519 activates auto sharing mode and defines the directory for stores. The
520 520 "mode" key determines how to construct the directory name of the shared
521 521 repository. "identity" means the name is derived from the node of the first
522 522 changeset in the repository. "remote" means the name is derived from the
523 523 remote's path/URL. Defaults to "identity."
524 524
525 525 storeincludepats and storeexcludepats: sets of file patterns to include and
526 526 exclude in the repository copy, respectively. If not defined, all files
527 527 will be included (a "full" clone). Otherwise a "narrow" clone containing
528 528 only the requested files will be performed. If ``storeincludepats`` is not
529 529 defined but ``storeexcludepats`` is, ``storeincludepats`` is assumed to be
530 530 ``path:.``. If both are empty sets, no files will be cloned.
531 531 """
532 532
533 533 if isinstance(source, bytes):
534 534 origsource = ui.expandpath(source)
535 535 source, branches = parseurl(origsource, branch)
536 536 srcpeer = peer(ui, peeropts, source)
537 537 else:
538 538 srcpeer = source.peer() # in case we were called with a localrepo
539 539 branches = (None, branch or [])
540 540 origsource = source = srcpeer.url()
541 541 revs, checkout = addbranchrevs(srcpeer, srcpeer, branches, revs)
542 542
543 543 if dest is None:
544 544 dest = defaultdest(source)
545 545 if dest:
546 546 ui.status(_("destination directory: %s\n") % dest)
547 547 else:
548 548 dest = ui.expandpath(dest)
549 549
550 550 dest = util.urllocalpath(dest)
551 551 source = util.urllocalpath(source)
552 552
553 553 if not dest:
554 554 raise error.Abort(_("empty destination path is not valid"))
555 555
556 556 destvfs = vfsmod.vfs(dest, expandpath=True)
557 557 if destvfs.lexists():
558 558 if not destvfs.isdir():
559 559 raise error.Abort(_("destination '%s' already exists") % dest)
560 560 elif destvfs.listdir():
561 561 raise error.Abort(_("destination '%s' is not empty") % dest)
562 562
563 563 createopts = {}
564 564 narrow = False
565 565
566 566 if storeincludepats is not None:
567 567 narrowspec.validatepatterns(storeincludepats)
568 568 narrow = True
569 569
570 570 if storeexcludepats is not None:
571 571 narrowspec.validatepatterns(storeexcludepats)
572 572 narrow = True
573 573
574 574 if narrow:
575 575 # Include everything by default if only exclusion patterns defined.
576 576 if storeexcludepats and not storeincludepats:
577 577 storeincludepats = {'path:.'}
578 578
579 579 createopts['narrowfiles'] = True
580 580
581 581 if depth:
582 582 createopts['shallowfilestore'] = True
583 583
584 584 if srcpeer.capable(b'lfs-serve'):
585 585 # Repository creation honors the config if it disabled the extension, so
586 586 # we can't just announce that lfs will be enabled. This check avoids
587 587 # saying that lfs will be enabled, and then saying it's an unknown
588 588 # feature. The lfs creation option is set in either case so that a
589 589 # requirement is added. If the extension is explicitly disabled but the
590 590 # requirement is set, the clone aborts early, before transferring any
591 591 # data.
592 592 createopts['lfs'] = True
593 593
594 594 if extensions.disabledext('lfs'):
595 595 ui.status(_('(remote is using large file support (lfs), but it is '
596 596 'explicitly disabled in the local configuration)\n'))
597 597 else:
598 598 ui.status(_('(remote is using large file support (lfs); lfs will '
599 599 'be enabled for this repository)\n'))
600 600
601 601 shareopts = shareopts or {}
602 602 sharepool = shareopts.get('pool')
603 603 sharenamemode = shareopts.get('mode')
604 604 if sharepool and islocal(dest):
605 605 sharepath = None
606 606 if sharenamemode == 'identity':
607 607 # Resolve the name from the initial changeset in the remote
608 608 # repository. This returns nullid when the remote is empty. It
609 609 # raises RepoLookupError if revision 0 is filtered or otherwise
610 610 # not available. If we fail to resolve, sharing is not enabled.
611 611 try:
612 612 with srcpeer.commandexecutor() as e:
613 613 rootnode = e.callcommand('lookup', {
614 614 'key': '0',
615 615 }).result()
616 616
617 617 if rootnode != node.nullid:
618 618 sharepath = os.path.join(sharepool, node.hex(rootnode))
619 619 else:
620 620 ui.status(_('(not using pooled storage: '
621 621 'remote appears to be empty)\n'))
622 622 except error.RepoLookupError:
623 623 ui.status(_('(not using pooled storage: '
624 624 'unable to resolve identity of remote)\n'))
625 625 elif sharenamemode == 'remote':
626 626 sharepath = os.path.join(
627 627 sharepool, node.hex(hashlib.sha1(source).digest()))
628 628 else:
629 629 raise error.Abort(_('unknown share naming mode: %s') %
630 630 sharenamemode)
631 631
632 632 # TODO this is a somewhat arbitrary restriction.
633 633 if narrow:
634 634 ui.status(_('(pooled storage not supported for narrow clones)\n'))
635 635 sharepath = None
636 636
637 637 if sharepath:
638 638 return clonewithshare(ui, peeropts, sharepath, source, srcpeer,
639 639 dest, pull=pull, rev=revs, update=update,
640 640 stream=stream)
641 641
642 642 srclock = destlock = cleandir = None
643 643 srcrepo = srcpeer.local()
644 644 try:
645 645 abspath = origsource
646 646 if islocal(origsource):
647 647 abspath = os.path.abspath(util.urllocalpath(origsource))
648 648
649 649 if islocal(dest):
650 650 cleandir = dest
651 651
652 652 copy = False
653 653 if (srcrepo and srcrepo.cancopy() and islocal(dest)
654 654 and not phases.hassecret(srcrepo)):
655 655 copy = not pull and not revs
656 656
657 657 # TODO this is a somewhat arbitrary restriction.
658 658 if narrow:
659 659 copy = False
660 660
661 661 if copy:
662 662 try:
663 663 # we use a lock here because if we race with commit, we
664 664 # can end up with extra data in the cloned revlogs that's
665 665 # not pointed to by changesets, thus causing verify to
666 666 # fail
667 667 srclock = srcrepo.lock(wait=False)
668 668 except error.LockError:
669 669 copy = False
670 670
671 671 if copy:
672 672 srcrepo.hook('preoutgoing', throw=True, source='clone')
673 673 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
674 674 if not os.path.exists(dest):
675 675 util.makedirs(dest)
676 676 else:
677 677 # only clean up directories we create ourselves
678 678 cleandir = hgdir
679 679 try:
680 680 destpath = hgdir
681 681 util.makedir(destpath, notindexed=True)
682 682 except OSError as inst:
683 683 if inst.errno == errno.EEXIST:
684 684 cleandir = None
685 685 raise error.Abort(_("destination '%s' already exists")
686 686 % dest)
687 687 raise
688 688
689 689 destlock = copystore(ui, srcrepo, destpath)
690 690 # copy bookmarks over
691 691 srcbookmarks = srcrepo.vfs.join('bookmarks')
692 692 dstbookmarks = os.path.join(destpath, 'bookmarks')
693 693 if os.path.exists(srcbookmarks):
694 694 util.copyfile(srcbookmarks, dstbookmarks)
695 695
696 696 dstcachedir = os.path.join(destpath, 'cache')
697 697 for cache in cacheutil.cachetocopy(srcrepo):
698 698 _copycache(srcrepo, dstcachedir, cache)
699 699
700 700 # we need to re-init the repo after manually copying the data
701 701 # into it
702 702 destpeer = peer(srcrepo, peeropts, dest)
703 703 srcrepo.hook('outgoing', source='clone',
704 704 node=node.hex(node.nullid))
705 705 else:
706 706 try:
707 707 # only pass ui when no srcrepo
708 708 destpeer = peer(srcrepo or ui, peeropts, dest, create=True,
709 709 createopts=createopts)
710 710 except OSError as inst:
711 711 if inst.errno == errno.EEXIST:
712 712 cleandir = None
713 713 raise error.Abort(_("destination '%s' already exists")
714 714 % dest)
715 715 raise
716 716
717 717 if revs:
718 718 if not srcpeer.capable('lookup'):
719 719 raise error.Abort(_("src repository does not support "
720 720 "revision lookup and so doesn't "
721 721 "support clone by revision"))
722 722
723 723 # TODO this is batchable.
724 724 remoterevs = []
725 725 for rev in revs:
726 726 with srcpeer.commandexecutor() as e:
727 727 remoterevs.append(e.callcommand('lookup', {
728 728 'key': rev,
729 729 }).result())
730 730 revs = remoterevs
731 731
732 732 checkout = revs[0]
733 733 else:
734 734 revs = None
735 735 local = destpeer.local()
736 736 if local:
737 737 if narrow:
738 738 with local.lock():
739 739 local.setnarrowpats(storeincludepats, storeexcludepats)
740 740
741 741 u = util.url(abspath)
742 742 defaulturl = bytes(u)
743 743 local.ui.setconfig('paths', 'default', defaulturl, 'clone')
744 744 if not stream:
745 745 if pull:
746 746 stream = False
747 747 else:
748 748 stream = None
749 749 # internal config: ui.quietbookmarkmove
750 750 overrides = {('ui', 'quietbookmarkmove'): True}
751 751 with local.ui.configoverride(overrides, 'clone'):
752 752 exchange.pull(local, srcpeer, revs,
753 753 streamclonerequested=stream,
754 754 includepats=storeincludepats,
755 755 excludepats=storeexcludepats,
756 756 depth=depth)
757 757 elif srcrepo:
758 758 # TODO lift restriction once exchange.push() accepts narrow
759 759 # push.
760 760 if narrow:
761 761 raise error.Abort(_('narrow clone not available for '
762 762 'remote destinations'))
763 763
764 764 exchange.push(srcrepo, destpeer, revs=revs,
765 765 bookmarks=srcrepo._bookmarks.keys())
766 766 else:
767 767 raise error.Abort(_("clone from remote to remote not supported")
768 768 )
769 769
770 770 cleandir = None
771 771
772 772 destrepo = destpeer.local()
773 773 if destrepo:
774 774 template = uimod.samplehgrcs['cloned']
775 775 u = util.url(abspath)
776 776 u.passwd = None
777 777 defaulturl = bytes(u)
778 778 destrepo.vfs.write('hgrc', util.tonativeeol(template % defaulturl))
779 779 destrepo.ui.setconfig('paths', 'default', defaulturl, 'clone')
780 780
781 781 if ui.configbool('experimental', 'remotenames'):
782 782 logexchange.pullremotenames(destrepo, srcpeer)
783 783
784 784 if update:
785 785 if update is not True:
786 786 with srcpeer.commandexecutor() as e:
787 787 checkout = e.callcommand('lookup', {
788 788 'key': update,
789 789 }).result()
790 790
791 791 uprev = None
792 792 status = None
793 793 if checkout is not None:
794 794 # Some extensions (at least hg-git and hg-subversion) have
795 795 # a peer.lookup() implementation that returns a name instead
796 796 # of a nodeid. We work around it here until we've figured
797 797 # out a better solution.
798 798 if len(checkout) == 20 and checkout in destrepo:
799 799 uprev = checkout
800 800 elif scmutil.isrevsymbol(destrepo, checkout):
801 801 uprev = scmutil.revsymbol(destrepo, checkout).node()
802 802 else:
803 803 if update is not True:
804 804 try:
805 805 uprev = destrepo.lookup(update)
806 806 except error.RepoLookupError:
807 807 pass
808 808 if uprev is None:
809 809 try:
810 810 uprev = destrepo._bookmarks['@']
811 811 update = '@'
812 812 bn = destrepo[uprev].branch()
813 813 if bn == 'default':
814 814 status = _("updating to bookmark @\n")
815 815 else:
816 816 status = (_("updating to bookmark @ on branch %s\n")
817 817 % bn)
818 818 except KeyError:
819 819 try:
820 820 uprev = destrepo.branchtip('default')
821 821 except error.RepoLookupError:
822 822 uprev = destrepo.lookup('tip')
823 823 if not status:
824 824 bn = destrepo[uprev].branch()
825 825 status = _("updating to branch %s\n") % bn
826 826 destrepo.ui.status(status)
827 827 _update(destrepo, uprev)
828 828 if update in destrepo._bookmarks:
829 829 bookmarks.activate(destrepo, update)
830 830 finally:
831 831 release(srclock, destlock)
832 832 if cleandir is not None:
833 833 shutil.rmtree(cleandir, True)
834 834 if srcpeer is not None:
835 835 srcpeer.close()
836 836 return srcpeer, destpeer
837 837
838 838 def _showstats(repo, stats, quietempty=False):
839 839 if quietempty and stats.isempty():
840 840 return
841 841 repo.ui.status(_("%d files updated, %d files merged, "
842 842 "%d files removed, %d files unresolved\n") % (
843 843 stats.updatedcount, stats.mergedcount,
844 844 stats.removedcount, stats.unresolvedcount))
845 845
846 846 def updaterepo(repo, node, overwrite, updatecheck=None):
847 847 """Update the working directory to node.
848 848
849 849 When overwrite is set, changes are clobbered, merged else
850 850
851 851 returns stats (see pydoc mercurial.merge.applyupdates)"""
852 852 return mergemod.update(repo, node, branchmerge=False, force=overwrite,
853 853 labels=['working copy', 'destination'],
854 854 updatecheck=updatecheck)
855 855
856 856 def update(repo, node, quietempty=False, updatecheck=None):
857 857 """update the working directory to node"""
858 858 stats = updaterepo(repo, node, False, updatecheck=updatecheck)
859 859 _showstats(repo, stats, quietempty)
860 860 if stats.unresolvedcount:
861 861 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
862 862 return stats.unresolvedcount > 0
863 863
864 864 # naming conflict in clone()
865 865 _update = update
866 866
867 867 def clean(repo, node, show_stats=True, quietempty=False):
868 868 """forcibly switch the working directory to node, clobbering changes"""
869 869 stats = updaterepo(repo, node, True)
870 870 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
871 871 if show_stats:
872 872 _showstats(repo, stats, quietempty)
873 873 return stats.unresolvedcount > 0
874 874
875 875 # naming conflict in updatetotally()
876 876 _clean = clean
877 877
878 878 def updatetotally(ui, repo, checkout, brev, clean=False, updatecheck=None):
879 879 """Update the working directory with extra care for non-file components
880 880
881 881 This takes care of non-file components below:
882 882
883 883 :bookmark: might be advanced or (in)activated
884 884
885 885 This takes arguments below:
886 886
887 887 :checkout: to which revision the working directory is updated
888 888 :brev: a name, which might be a bookmark to be activated after updating
889 889 :clean: whether changes in the working directory can be discarded
890 890 :updatecheck: how to deal with a dirty working directory
891 891
892 892 Valid values for updatecheck are (None => linear):
893 893
894 894 * abort: abort if the working directory is dirty
895 895 * none: don't check (merge working directory changes into destination)
896 896 * linear: check that update is linear before merging working directory
897 897 changes into destination
898 898 * noconflict: check that the update does not result in file merges
899 899
900 900 This returns whether conflict is detected at updating or not.
901 901 """
902 902 if updatecheck is None:
903 903 updatecheck = ui.config('commands', 'update.check')
904 904 if updatecheck not in ('abort', 'none', 'linear', 'noconflict'):
905 905 # If not configured, or invalid value configured
906 906 updatecheck = 'linear'
907 907 with repo.wlock():
908 908 movemarkfrom = None
909 909 warndest = False
910 910 if checkout is None:
911 911 updata = destutil.destupdate(repo, clean=clean)
912 912 checkout, movemarkfrom, brev = updata
913 913 warndest = True
914 914
915 915 if clean:
916 916 ret = _clean(repo, checkout)
917 917 else:
918 918 if updatecheck == 'abort':
919 919 cmdutil.bailifchanged(repo, merge=False)
920 920 updatecheck = 'none'
921 921 ret = _update(repo, checkout, updatecheck=updatecheck)
922 922
923 923 if not ret and movemarkfrom:
924 924 if movemarkfrom == repo['.'].node():
925 925 pass # no-op update
926 926 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
927 927 b = ui.label(repo._activebookmark, 'bookmarks.active')
928 928 ui.status(_("updating bookmark %s\n") % b)
929 929 else:
930 930 # this can happen with a non-linear update
931 931 b = ui.label(repo._activebookmark, 'bookmarks')
932 932 ui.status(_("(leaving bookmark %s)\n") % b)
933 933 bookmarks.deactivate(repo)
934 934 elif brev in repo._bookmarks:
935 935 if brev != repo._activebookmark:
936 936 b = ui.label(brev, 'bookmarks.active')
937 937 ui.status(_("(activating bookmark %s)\n") % b)
938 938 bookmarks.activate(repo, brev)
939 939 elif brev:
940 940 if repo._activebookmark:
941 941 b = ui.label(repo._activebookmark, 'bookmarks')
942 942 ui.status(_("(leaving bookmark %s)\n") % b)
943 943 bookmarks.deactivate(repo)
944 944
945 945 if warndest:
946 946 destutil.statusotherdests(ui, repo)
947 947
948 948 return ret
949 949
950 950 def merge(repo, node, force=None, remind=True, mergeforce=False, labels=None,
951 951 abort=False):
952 952 """Branch merge with node, resolving changes. Return true if any
953 953 unresolved conflicts."""
954 954 if not abort:
955 955 stats = mergemod.update(repo, node, branchmerge=True, force=force,
956 956 mergeforce=mergeforce, labels=labels)
957 957 else:
958 958 ms = mergemod.mergestate.read(repo)
959 959 if ms.active():
960 960 # there were conflicts
961 961 node = ms.localctx.hex()
962 962 else:
963 963 # there were no conficts, mergestate was not stored
964 964 node = repo['.'].hex()
965 965
966 966 repo.ui.status(_("aborting the merge, updating back to"
967 967 " %s\n") % node[:12])
968 968 stats = mergemod.update(repo, node, branchmerge=False, force=True,
969 969 labels=labels)
970 970
971 971 _showstats(repo, stats)
972 972 if stats.unresolvedcount:
973 973 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
974 974 "or 'hg merge --abort' to abandon\n"))
975 975 elif remind and not abort:
976 976 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
977 977 return stats.unresolvedcount > 0
978 978
979 979 def _incoming(displaychlist, subreporecurse, ui, repo, source,
980 980 opts, buffered=False):
981 981 """
982 982 Helper for incoming / gincoming.
983 983 displaychlist gets called with
984 984 (remoterepo, incomingchangesetlist, displayer) parameters,
985 985 and is supposed to contain only code that can't be unified.
986 986 """
987 987 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
988 988 other = peer(repo, opts, source)
989 989 ui.status(_('comparing with %s\n') % util.hidepassword(source))
990 990 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
991 991
992 992 if revs:
993 993 revs = [other.lookup(rev) for rev in revs]
994 994 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
995 995 revs, opts["bundle"], opts["force"])
996 996 try:
997 997 if not chlist:
998 998 ui.status(_("no changes found\n"))
999 999 return subreporecurse()
1000 1000 ui.pager('incoming')
1001 1001 displayer = logcmdutil.changesetdisplayer(ui, other, opts,
1002 1002 buffered=buffered)
1003 1003 displaychlist(other, chlist, displayer)
1004 1004 displayer.close()
1005 1005 finally:
1006 1006 cleanupfn()
1007 1007 subreporecurse()
1008 1008 return 0 # exit code is zero since we found incoming changes
1009 1009
1010 1010 def incoming(ui, repo, source, opts):
1011 1011 def subreporecurse():
1012 1012 ret = 1
1013 1013 if opts.get('subrepos'):
1014 1014 ctx = repo[None]
1015 1015 for subpath in sorted(ctx.substate):
1016 1016 sub = ctx.sub(subpath)
1017 1017 ret = min(ret, sub.incoming(ui, source, opts))
1018 1018 return ret
1019 1019
1020 1020 def display(other, chlist, displayer):
1021 1021 limit = logcmdutil.getlimit(opts)
1022 1022 if opts.get('newest_first'):
1023 1023 chlist.reverse()
1024 1024 count = 0
1025 1025 for n in chlist:
1026 1026 if limit is not None and count >= limit:
1027 1027 break
1028 1028 parents = [p for p in other.changelog.parents(n) if p != nullid]
1029 1029 if opts.get('no_merges') and len(parents) == 2:
1030 1030 continue
1031 1031 count += 1
1032 1032 displayer.show(other[n])
1033 1033 return _incoming(display, subreporecurse, ui, repo, source, opts)
1034 1034
1035 1035 def _outgoing(ui, repo, dest, opts):
1036 1036 path = ui.paths.getpath(dest, default=('default-push', 'default'))
1037 1037 if not path:
1038 1038 raise error.Abort(_('default repository not configured!'),
1039 1039 hint=_("see 'hg help config.paths'"))
1040 1040 dest = path.pushloc or path.loc
1041 1041 branches = path.branch, opts.get('branch') or []
1042 1042
1043 1043 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
1044 1044 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
1045 1045 if revs:
1046 1046 revs = [repo[rev].node() for rev in scmutil.revrange(repo, revs)]
1047 1047
1048 1048 other = peer(repo, opts, dest)
1049 1049 outgoing = discovery.findcommonoutgoing(repo, other, revs,
1050 1050 force=opts.get('force'))
1051 1051 o = outgoing.missing
1052 1052 if not o:
1053 1053 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
1054 1054 return o, other
1055 1055
1056 1056 def outgoing(ui, repo, dest, opts):
1057 1057 def recurse():
1058 1058 ret = 1
1059 1059 if opts.get('subrepos'):
1060 1060 ctx = repo[None]
1061 1061 for subpath in sorted(ctx.substate):
1062 1062 sub = ctx.sub(subpath)
1063 1063 ret = min(ret, sub.outgoing(ui, dest, opts))
1064 1064 return ret
1065 1065
1066 1066 limit = logcmdutil.getlimit(opts)
1067 1067 o, other = _outgoing(ui, repo, dest, opts)
1068 1068 if not o:
1069 1069 cmdutil.outgoinghooks(ui, repo, other, opts, o)
1070 1070 return recurse()
1071 1071
1072 1072 if opts.get('newest_first'):
1073 1073 o.reverse()
1074 1074 ui.pager('outgoing')
1075 1075 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
1076 1076 count = 0
1077 1077 for n in o:
1078 1078 if limit is not None and count >= limit:
1079 1079 break
1080 1080 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1081 1081 if opts.get('no_merges') and len(parents) == 2:
1082 1082 continue
1083 1083 count += 1
1084 1084 displayer.show(repo[n])
1085 1085 displayer.close()
1086 1086 cmdutil.outgoinghooks(ui, repo, other, opts, o)
1087 1087 recurse()
1088 1088 return 0 # exit code is zero since we found outgoing changes
1089 1089
1090 1090 def verify(repo):
1091 1091 """verify the consistency of a repository"""
1092 1092 ret = verifymod.verify(repo)
1093 1093
1094 1094 # Broken subrepo references in hidden csets don't seem worth worrying about,
1095 1095 # since they can't be pushed/pulled, and --hidden can be used if they are a
1096 1096 # concern.
1097 1097
1098 1098 # pathto() is needed for -R case
1099 1099 revs = repo.revs("filelog(%s)",
1100 1100 util.pathto(repo.root, repo.getcwd(), '.hgsubstate'))
1101 1101
1102 1102 if revs:
1103 1103 repo.ui.status(_('checking subrepo links\n'))
1104 1104 for rev in revs:
1105 1105 ctx = repo[rev]
1106 1106 try:
1107 1107 for subpath in ctx.substate:
1108 1108 try:
1109 1109 ret = (ctx.sub(subpath, allowcreate=False).verify()
1110 1110 or ret)
1111 1111 except error.RepoError as e:
1112 1112 repo.ui.warn(('%d: %s\n') % (rev, e))
1113 1113 except Exception:
1114 1114 repo.ui.warn(_('.hgsubstate is corrupt in revision %s\n') %
1115 1115 node.short(ctx.node()))
1116 1116
1117 1117 return ret
1118 1118
1119 1119 def remoteui(src, opts):
1120 1120 'build a remote ui from ui or repo and opts'
1121 1121 if util.safehasattr(src, 'baseui'): # looks like a repository
1122 1122 dst = src.baseui.copy() # drop repo-specific config
1123 1123 src = src.ui # copy target options from repo
1124 1124 else: # assume it's a global ui object
1125 1125 dst = src.copy() # keep all global options
1126 1126
1127 1127 # copy ssh-specific options
1128 1128 for o in 'ssh', 'remotecmd':
1129 1129 v = opts.get(o) or src.config('ui', o)
1130 1130 if v:
1131 1131 dst.setconfig("ui", o, v, 'copied')
1132 1132
1133 1133 # copy bundle-specific options
1134 1134 r = src.config('bundle', 'mainreporoot')
1135 1135 if r:
1136 1136 dst.setconfig('bundle', 'mainreporoot', r, 'copied')
1137 1137
1138 1138 # copy selected local settings to the remote ui
1139 1139 for sect in ('auth', 'hostfingerprints', 'hostsecurity', 'http_proxy'):
1140 1140 for key, val in src.configitems(sect):
1141 1141 dst.setconfig(sect, key, val, 'copied')
1142 1142 v = src.config('web', 'cacerts')
1143 1143 if v:
1144 1144 dst.setconfig('web', 'cacerts', util.expandpath(v), 'copied')
1145 1145
1146 1146 return dst
1147 1147
1148 1148 # Files of interest
1149 1149 # Used to check if the repository has changed looking at mtime and size of
1150 1150 # these files.
1151 1151 foi = [('spath', '00changelog.i'),
1152 1152 ('spath', 'phaseroots'), # ! phase can change content at the same size
1153 1153 ('spath', 'obsstore'),
1154 1154 ('path', 'bookmarks'), # ! bookmark can change content at the same size
1155 1155 ]
1156 1156
1157 1157 class cachedlocalrepo(object):
1158 1158 """Holds a localrepository that can be cached and reused."""
1159 1159
1160 1160 def __init__(self, repo):
1161 1161 """Create a new cached repo from an existing repo.
1162 1162
1163 1163 We assume the passed in repo was recently created. If the
1164 1164 repo has changed between when it was created and when it was
1165 1165 turned into a cache, it may not refresh properly.
1166 1166 """
1167 1167 assert isinstance(repo, localrepo.localrepository)
1168 1168 self._repo = repo
1169 1169 self._state, self.mtime = self._repostate()
1170 1170 self._filtername = repo.filtername
1171 1171
1172 1172 def fetch(self):
1173 1173 """Refresh (if necessary) and return a repository.
1174 1174
1175 1175 If the cached instance is out of date, it will be recreated
1176 1176 automatically and returned.
1177 1177
1178 1178 Returns a tuple of the repo and a boolean indicating whether a new
1179 1179 repo instance was created.
1180 1180 """
1181 1181 # We compare the mtimes and sizes of some well-known files to
1182 1182 # determine if the repo changed. This is not precise, as mtimes
1183 1183 # are susceptible to clock skew and imprecise filesystems and
1184 1184 # file content can change while maintaining the same size.
1185 1185
1186 1186 state, mtime = self._repostate()
1187 1187 if state == self._state:
1188 1188 return self._repo, False
1189 1189
1190 1190 repo = repository(self._repo.baseui, self._repo.url())
1191 1191 if self._filtername:
1192 1192 self._repo = repo.filtered(self._filtername)
1193 1193 else:
1194 1194 self._repo = repo.unfiltered()
1195 1195 self._state = state
1196 1196 self.mtime = mtime
1197 1197
1198 1198 return self._repo, True
1199 1199
1200 1200 def _repostate(self):
1201 1201 state = []
1202 1202 maxmtime = -1
1203 1203 for attr, fname in foi:
1204 1204 prefix = getattr(self._repo, attr)
1205 1205 p = os.path.join(prefix, fname)
1206 1206 try:
1207 1207 st = os.stat(p)
1208 1208 except OSError:
1209 1209 st = os.stat(prefix)
1210 1210 state.append((st[stat.ST_MTIME], st.st_size))
1211 1211 maxmtime = max(maxmtime, st[stat.ST_MTIME])
1212 1212
1213 1213 return tuple(state), maxmtime
1214 1214
1215 1215 def copy(self):
1216 1216 """Obtain a copy of this class instance.
1217 1217
1218 1218 A new localrepository instance is obtained. The new instance should be
1219 1219 completely independent of the original.
1220 1220 """
1221 1221 repo = repository(self._repo.baseui, self._repo.origroot)
1222 1222 if self._filtername:
1223 1223 repo = repo.filtered(self._filtername)
1224 1224 else:
1225 1225 repo = repo.unfiltered()
1226 1226 c = cachedlocalrepo(repo)
1227 1227 c._state = self._state
1228 1228 c.mtime = self.mtime
1229 1229 return c
@@ -1,1296 +1,1296 b''
1 1 #testcases sshv1 sshv2
2 2
3 3 #if sshv2
4 4 $ cat >> $HGRCPATH << EOF
5 5 > [experimental]
6 6 > sshpeer.advertise-v2 = true
7 7 > sshserver.support-v2 = true
8 8 > EOF
9 9 #endif
10 10
11 11 Prepare repo a:
12 12
13 13 $ hg init a
14 14 $ cd a
15 15 $ echo a > a
16 16 $ hg add a
17 17 $ hg commit -m test
18 18 $ echo first line > b
19 19 $ hg add b
20 20
21 21 Create a non-inlined filelog:
22 22
23 23 $ "$PYTHON" -c 'open("data1", "wb").write(b"".join(b"%d\n" % x for x in range(10000)))'
24 24 $ for j in 0 1 2 3 4 5 6 7 8 9; do
25 25 > cat data1 >> b
26 26 > hg commit -m test
27 27 > done
28 28
29 29 List files in store/data (should show a 'b.d'):
30 30
31 31 #if reporevlogstore
32 32 $ for i in .hg/store/data/*; do
33 33 > echo $i
34 34 > done
35 35 .hg/store/data/a.i
36 36 .hg/store/data/b.d
37 37 .hg/store/data/b.i
38 38 #endif
39 39
40 40 Trigger branchcache creation:
41 41
42 42 $ hg branches
43 43 default 10:a7949464abda
44 44 $ ls .hg/cache
45 45 branch2-served
46 46 checkisexec (execbit !)
47 47 checklink (symlink !)
48 48 checklink-target (symlink !)
49 49 checknoexec (execbit !)
50 50 manifestfulltextcache (reporevlogstore !)
51 51 rbc-names-v1
52 52 rbc-revs-v1
53 53
54 54 Default operation:
55 55
56 56 $ hg clone . ../b
57 57 updating to branch default
58 58 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
59 59 $ cd ../b
60 60
61 61 Ensure branchcache got copied over:
62 62
63 63 $ ls .hg/cache
64 64 branch2-served
65 65 checkisexec (execbit !)
66 66 checklink (symlink !)
67 67 checklink-target (symlink !)
68 68 rbc-names-v1
69 69 rbc-revs-v1
70 70
71 71 $ cat a
72 72 a
73 73 $ hg verify
74 74 checking changesets
75 75 checking manifests
76 76 crosschecking files in changesets and manifests
77 77 checking files
78 78 checked 11 changesets with 11 changes to 2 files
79 79
80 80 Invalid dest '' must abort:
81 81
82 82 $ hg clone . ''
83 83 abort: empty destination path is not valid
84 84 [255]
85 85
86 86 No update, with debug option:
87 87
88 88 #if hardlink
89 89 $ hg --debug clone -U . ../c --config progress.debug=true
90 linking: 1
91 linking: 2
92 linking: 3
93 linking: 4
94 linking: 5
95 linking: 6
96 linking: 7
97 linking: 8
90 linking: 1 files
91 linking: 2 files
92 linking: 3 files
93 linking: 4 files
94 linking: 5 files
95 linking: 6 files
96 linking: 7 files
97 linking: 8 files
98 98 linked 8 files (reporevlogstore !)
99 linking: 9 (reposimplestore !)
100 linking: 10 (reposimplestore !)
101 linking: 11 (reposimplestore !)
102 linking: 12 (reposimplestore !)
103 linking: 13 (reposimplestore !)
104 linking: 14 (reposimplestore !)
105 linking: 15 (reposimplestore !)
106 linking: 16 (reposimplestore !)
107 linking: 17 (reposimplestore !)
108 linking: 18 (reposimplestore !)
99 linking: 9 files (reposimplestore !)
100 linking: 10 files (reposimplestore !)
101 linking: 11 files (reposimplestore !)
102 linking: 12 files (reposimplestore !)
103 linking: 13 files (reposimplestore !)
104 linking: 14 files (reposimplestore !)
105 linking: 15 files (reposimplestore !)
106 linking: 16 files (reposimplestore !)
107 linking: 17 files (reposimplestore !)
108 linking: 18 files (reposimplestore !)
109 109 linked 18 files (reposimplestore !)
110 110 #else
111 111 $ hg --debug clone -U . ../c --config progress.debug=true
112 linking: 1
113 copying: 2
114 copying: 3
115 copying: 4
116 copying: 5
117 copying: 6
118 copying: 7
119 copying: 8
112 linking: 1 files
113 copying: 2 files
114 copying: 3 files
115 copying: 4 files
116 copying: 5 files
117 copying: 6 files
118 copying: 7 files
119 copying: 8 files
120 120 copied 8 files (reporevlogstore !)
121 copying: 9 (reposimplestore !)
122 copying: 10 (reposimplestore !)
123 copying: 11 (reposimplestore !)
124 copying: 12 (reposimplestore !)
125 copying: 13 (reposimplestore !)
126 copying: 14 (reposimplestore !)
127 copying: 15 (reposimplestore !)
128 copying: 16 (reposimplestore !)
129 copying: 17 (reposimplestore !)
130 copying: 18 (reposimplestore !)
121 copying: 9 files (reposimplestore !)
122 copying: 10 files (reposimplestore !)
123 copying: 11 files (reposimplestore !)
124 copying: 12 files (reposimplestore !)
125 copying: 13 files (reposimplestore !)
126 copying: 14 files (reposimplestore !)
127 copying: 15 files (reposimplestore !)
128 copying: 16 files (reposimplestore !)
129 copying: 17 files (reposimplestore !)
130 copying: 18 files (reposimplestore !)
131 131 copied 18 files (reposimplestore !)
132 132 #endif
133 133 $ cd ../c
134 134
135 135 Ensure branchcache got copied over:
136 136
137 137 $ ls .hg/cache
138 138 branch2-served
139 139 rbc-names-v1
140 140 rbc-revs-v1
141 141
142 142 $ cat a 2>/dev/null || echo "a not present"
143 143 a not present
144 144 $ hg verify
145 145 checking changesets
146 146 checking manifests
147 147 crosschecking files in changesets and manifests
148 148 checking files
149 149 checked 11 changesets with 11 changes to 2 files
150 150
151 151 Default destination:
152 152
153 153 $ mkdir ../d
154 154 $ cd ../d
155 155 $ hg clone ../a
156 156 destination directory: a
157 157 updating to branch default
158 158 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
159 159 $ cd a
160 160 $ hg cat a
161 161 a
162 162 $ cd ../..
163 163
164 164 Check that we drop the 'file:' from the path before writing the .hgrc:
165 165
166 166 $ hg clone file:a e
167 167 updating to branch default
168 168 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
169 169 $ grep 'file:' e/.hg/hgrc
170 170 [1]
171 171
172 172 Check that path aliases are expanded:
173 173
174 174 $ hg clone -q -U --config 'paths.foobar=a#0' foobar f
175 175 $ hg -R f showconfig paths.default
176 176 $TESTTMP/a#0
177 177
178 178 Use --pull:
179 179
180 180 $ hg clone --pull a g
181 181 requesting all changes
182 182 adding changesets
183 183 adding manifests
184 184 adding file changes
185 185 added 11 changesets with 11 changes to 2 files
186 186 new changesets acb14030fe0a:a7949464abda
187 187 updating to branch default
188 188 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
189 189 $ hg -R g verify
190 190 checking changesets
191 191 checking manifests
192 192 crosschecking files in changesets and manifests
193 193 checking files
194 194 checked 11 changesets with 11 changes to 2 files
195 195
196 196 Invalid dest '' with --pull must abort (issue2528):
197 197
198 198 $ hg clone --pull a ''
199 199 abort: empty destination path is not valid
200 200 [255]
201 201
202 202 Clone to '.':
203 203
204 204 $ mkdir h
205 205 $ cd h
206 206 $ hg clone ../a .
207 207 updating to branch default
208 208 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
209 209 $ cd ..
210 210
211 211
212 212 *** Tests for option -u ***
213 213
214 214 Adding some more history to repo a:
215 215
216 216 $ cd a
217 217 $ hg tag ref1
218 218 $ echo the quick brown fox >a
219 219 $ hg ci -m "hacked default"
220 220 $ hg up ref1
221 221 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
222 222 $ hg branch stable
223 223 marked working directory as branch stable
224 224 (branches are permanent and global, did you want a bookmark?)
225 225 $ echo some text >a
226 226 $ hg ci -m "starting branch stable"
227 227 $ hg tag ref2
228 228 $ echo some more text >a
229 229 $ hg ci -m "another change for branch stable"
230 230 $ hg up ref2
231 231 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
232 232 $ hg parents
233 233 changeset: 13:e8ece76546a6
234 234 branch: stable
235 235 tag: ref2
236 236 parent: 10:a7949464abda
237 237 user: test
238 238 date: Thu Jan 01 00:00:00 1970 +0000
239 239 summary: starting branch stable
240 240
241 241
242 242 Repo a has two heads:
243 243
244 244 $ hg heads
245 245 changeset: 15:0aae7cf88f0d
246 246 branch: stable
247 247 tag: tip
248 248 user: test
249 249 date: Thu Jan 01 00:00:00 1970 +0000
250 250 summary: another change for branch stable
251 251
252 252 changeset: 12:f21241060d6a
253 253 user: test
254 254 date: Thu Jan 01 00:00:00 1970 +0000
255 255 summary: hacked default
256 256
257 257
258 258 $ cd ..
259 259
260 260
261 261 Testing --noupdate with --updaterev (must abort):
262 262
263 263 $ hg clone --noupdate --updaterev 1 a ua
264 264 abort: cannot specify both --noupdate and --updaterev
265 265 [255]
266 266
267 267
268 268 Testing clone -u:
269 269
270 270 $ hg clone -u . a ua
271 271 updating to branch stable
272 272 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
273 273
274 274 Repo ua has both heads:
275 275
276 276 $ hg -R ua heads
277 277 changeset: 15:0aae7cf88f0d
278 278 branch: stable
279 279 tag: tip
280 280 user: test
281 281 date: Thu Jan 01 00:00:00 1970 +0000
282 282 summary: another change for branch stable
283 283
284 284 changeset: 12:f21241060d6a
285 285 user: test
286 286 date: Thu Jan 01 00:00:00 1970 +0000
287 287 summary: hacked default
288 288
289 289
290 290 Same revision checked out in repo a and ua:
291 291
292 292 $ hg -R a parents --template "{node|short}\n"
293 293 e8ece76546a6
294 294 $ hg -R ua parents --template "{node|short}\n"
295 295 e8ece76546a6
296 296
297 297 $ rm -r ua
298 298
299 299
300 300 Testing clone --pull -u:
301 301
302 302 $ hg clone --pull -u . a ua
303 303 requesting all changes
304 304 adding changesets
305 305 adding manifests
306 306 adding file changes
307 307 added 16 changesets with 16 changes to 3 files (+1 heads)
308 308 new changesets acb14030fe0a:0aae7cf88f0d
309 309 updating to branch stable
310 310 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
311 311
312 312 Repo ua has both heads:
313 313
314 314 $ hg -R ua heads
315 315 changeset: 15:0aae7cf88f0d
316 316 branch: stable
317 317 tag: tip
318 318 user: test
319 319 date: Thu Jan 01 00:00:00 1970 +0000
320 320 summary: another change for branch stable
321 321
322 322 changeset: 12:f21241060d6a
323 323 user: test
324 324 date: Thu Jan 01 00:00:00 1970 +0000
325 325 summary: hacked default
326 326
327 327
328 328 Same revision checked out in repo a and ua:
329 329
330 330 $ hg -R a parents --template "{node|short}\n"
331 331 e8ece76546a6
332 332 $ hg -R ua parents --template "{node|short}\n"
333 333 e8ece76546a6
334 334
335 335 $ rm -r ua
336 336
337 337
338 338 Testing clone -u <branch>:
339 339
340 340 $ hg clone -u stable a ua
341 341 updating to branch stable
342 342 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
343 343
344 344 Repo ua has both heads:
345 345
346 346 $ hg -R ua heads
347 347 changeset: 15:0aae7cf88f0d
348 348 branch: stable
349 349 tag: tip
350 350 user: test
351 351 date: Thu Jan 01 00:00:00 1970 +0000
352 352 summary: another change for branch stable
353 353
354 354 changeset: 12:f21241060d6a
355 355 user: test
356 356 date: Thu Jan 01 00:00:00 1970 +0000
357 357 summary: hacked default
358 358
359 359
360 360 Branch 'stable' is checked out:
361 361
362 362 $ hg -R ua parents
363 363 changeset: 15:0aae7cf88f0d
364 364 branch: stable
365 365 tag: tip
366 366 user: test
367 367 date: Thu Jan 01 00:00:00 1970 +0000
368 368 summary: another change for branch stable
369 369
370 370
371 371 $ rm -r ua
372 372
373 373
374 374 Testing default checkout:
375 375
376 376 $ hg clone a ua
377 377 updating to branch default
378 378 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
379 379
380 380 Repo ua has both heads:
381 381
382 382 $ hg -R ua heads
383 383 changeset: 15:0aae7cf88f0d
384 384 branch: stable
385 385 tag: tip
386 386 user: test
387 387 date: Thu Jan 01 00:00:00 1970 +0000
388 388 summary: another change for branch stable
389 389
390 390 changeset: 12:f21241060d6a
391 391 user: test
392 392 date: Thu Jan 01 00:00:00 1970 +0000
393 393 summary: hacked default
394 394
395 395
396 396 Branch 'default' is checked out:
397 397
398 398 $ hg -R ua parents
399 399 changeset: 12:f21241060d6a
400 400 user: test
401 401 date: Thu Jan 01 00:00:00 1970 +0000
402 402 summary: hacked default
403 403
404 404 Test clone with a branch named "@" (issue3677)
405 405
406 406 $ hg -R ua branch @
407 407 marked working directory as branch @
408 408 $ hg -R ua commit -m 'created branch @'
409 409 $ hg clone ua atbranch
410 410 updating to branch default
411 411 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
412 412 $ hg -R atbranch heads
413 413 changeset: 16:798b6d97153e
414 414 branch: @
415 415 tag: tip
416 416 parent: 12:f21241060d6a
417 417 user: test
418 418 date: Thu Jan 01 00:00:00 1970 +0000
419 419 summary: created branch @
420 420
421 421 changeset: 15:0aae7cf88f0d
422 422 branch: stable
423 423 user: test
424 424 date: Thu Jan 01 00:00:00 1970 +0000
425 425 summary: another change for branch stable
426 426
427 427 changeset: 12:f21241060d6a
428 428 user: test
429 429 date: Thu Jan 01 00:00:00 1970 +0000
430 430 summary: hacked default
431 431
432 432 $ hg -R atbranch parents
433 433 changeset: 12:f21241060d6a
434 434 user: test
435 435 date: Thu Jan 01 00:00:00 1970 +0000
436 436 summary: hacked default
437 437
438 438
439 439 $ rm -r ua atbranch
440 440
441 441
442 442 Testing #<branch>:
443 443
444 444 $ hg clone -u . a#stable ua
445 445 adding changesets
446 446 adding manifests
447 447 adding file changes
448 448 added 14 changesets with 14 changes to 3 files
449 449 new changesets acb14030fe0a:0aae7cf88f0d
450 450 updating to branch stable
451 451 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
452 452
453 453 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
454 454
455 455 $ hg -R ua heads
456 456 changeset: 13:0aae7cf88f0d
457 457 branch: stable
458 458 tag: tip
459 459 user: test
460 460 date: Thu Jan 01 00:00:00 1970 +0000
461 461 summary: another change for branch stable
462 462
463 463 changeset: 10:a7949464abda
464 464 user: test
465 465 date: Thu Jan 01 00:00:00 1970 +0000
466 466 summary: test
467 467
468 468
469 469 Same revision checked out in repo a and ua:
470 470
471 471 $ hg -R a parents --template "{node|short}\n"
472 472 e8ece76546a6
473 473 $ hg -R ua parents --template "{node|short}\n"
474 474 e8ece76546a6
475 475
476 476 $ rm -r ua
477 477
478 478
479 479 Testing -u -r <branch>:
480 480
481 481 $ hg clone -u . -r stable a ua
482 482 adding changesets
483 483 adding manifests
484 484 adding file changes
485 485 added 14 changesets with 14 changes to 3 files
486 486 new changesets acb14030fe0a:0aae7cf88f0d
487 487 updating to branch stable
488 488 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
489 489
490 490 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
491 491
492 492 $ hg -R ua heads
493 493 changeset: 13:0aae7cf88f0d
494 494 branch: stable
495 495 tag: tip
496 496 user: test
497 497 date: Thu Jan 01 00:00:00 1970 +0000
498 498 summary: another change for branch stable
499 499
500 500 changeset: 10:a7949464abda
501 501 user: test
502 502 date: Thu Jan 01 00:00:00 1970 +0000
503 503 summary: test
504 504
505 505
506 506 Same revision checked out in repo a and ua:
507 507
508 508 $ hg -R a parents --template "{node|short}\n"
509 509 e8ece76546a6
510 510 $ hg -R ua parents --template "{node|short}\n"
511 511 e8ece76546a6
512 512
513 513 $ rm -r ua
514 514
515 515
516 516 Testing -r <branch>:
517 517
518 518 $ hg clone -r stable a ua
519 519 adding changesets
520 520 adding manifests
521 521 adding file changes
522 522 added 14 changesets with 14 changes to 3 files
523 523 new changesets acb14030fe0a:0aae7cf88f0d
524 524 updating to branch stable
525 525 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
526 526
527 527 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
528 528
529 529 $ hg -R ua heads
530 530 changeset: 13:0aae7cf88f0d
531 531 branch: stable
532 532 tag: tip
533 533 user: test
534 534 date: Thu Jan 01 00:00:00 1970 +0000
535 535 summary: another change for branch stable
536 536
537 537 changeset: 10:a7949464abda
538 538 user: test
539 539 date: Thu Jan 01 00:00:00 1970 +0000
540 540 summary: test
541 541
542 542
543 543 Branch 'stable' is checked out:
544 544
545 545 $ hg -R ua parents
546 546 changeset: 13:0aae7cf88f0d
547 547 branch: stable
548 548 tag: tip
549 549 user: test
550 550 date: Thu Jan 01 00:00:00 1970 +0000
551 551 summary: another change for branch stable
552 552
553 553
554 554 $ rm -r ua
555 555
556 556
557 557 Issue2267: Error in 1.6 hg.py: TypeError: 'NoneType' object is not
558 558 iterable in addbranchrevs()
559 559
560 560 $ cat <<EOF > simpleclone.py
561 561 > from mercurial import hg, ui as uimod
562 562 > myui = uimod.ui.load()
563 563 > repo = hg.repository(myui, b'a')
564 564 > hg.clone(myui, {}, repo, dest=b"ua")
565 565 > EOF
566 566
567 567 $ "$PYTHON" simpleclone.py
568 568 updating to branch default
569 569 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
570 570
571 571 $ rm -r ua
572 572
573 573 $ cat <<EOF > branchclone.py
574 574 > from mercurial import extensions, hg, ui as uimod
575 575 > myui = uimod.ui.load()
576 576 > extensions.loadall(myui)
577 577 > repo = hg.repository(myui, b'a')
578 578 > hg.clone(myui, {}, repo, dest=b"ua", branch=[b"stable",])
579 579 > EOF
580 580
581 581 $ "$PYTHON" branchclone.py
582 582 adding changesets
583 583 adding manifests
584 584 adding file changes
585 585 added 14 changesets with 14 changes to 3 files
586 586 new changesets acb14030fe0a:0aae7cf88f0d
587 587 updating to branch stable
588 588 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
589 589 $ rm -r ua
590 590
591 591
592 592 Test clone with special '@' bookmark:
593 593 $ cd a
594 594 $ hg bookmark -r a7949464abda @ # branch point of stable from default
595 595 $ hg clone . ../i
596 596 updating to bookmark @
597 597 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
598 598 $ hg id -i ../i
599 599 a7949464abda
600 600 $ rm -r ../i
601 601
602 602 $ hg bookmark -f -r stable @
603 603 $ hg bookmarks
604 604 @ 15:0aae7cf88f0d
605 605 $ hg clone . ../i
606 606 updating to bookmark @ on branch stable
607 607 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
608 608 $ hg id -i ../i
609 609 0aae7cf88f0d
610 610 $ cd "$TESTTMP"
611 611
612 612
613 613 Testing failures:
614 614
615 615 $ mkdir fail
616 616 $ cd fail
617 617
618 618 No local source
619 619
620 620 $ hg clone a b
621 621 abort: repository a not found!
622 622 [255]
623 623
624 624 No remote source
625 625
626 626 #if windows
627 627 $ hg clone http://$LOCALIP:3121/a b
628 628 abort: error: * (glob)
629 629 [255]
630 630 #else
631 631 $ hg clone http://$LOCALIP:3121/a b
632 632 abort: error: *refused* (glob)
633 633 [255]
634 634 #endif
635 635 $ rm -rf b # work around bug with http clone
636 636
637 637
638 638 #if unix-permissions no-root
639 639
640 640 Inaccessible source
641 641
642 642 $ mkdir a
643 643 $ chmod 000 a
644 644 $ hg clone a b
645 645 abort: Permission denied: *$TESTTMP/fail/a/.hg* (glob)
646 646 [255]
647 647
648 648 Inaccessible destination
649 649
650 650 $ hg init b
651 651 $ cd b
652 652 $ hg clone . ../a
653 653 abort: Permission denied: *../a* (glob)
654 654 [255]
655 655 $ cd ..
656 656 $ chmod 700 a
657 657 $ rm -r a b
658 658
659 659 #endif
660 660
661 661
662 662 #if fifo
663 663
664 664 Source of wrong type
665 665
666 666 $ mkfifo a
667 667 $ hg clone a b
668 668 abort: $ENOTDIR$: *$TESTTMP/fail/a/.hg* (glob)
669 669 [255]
670 670 $ rm a
671 671
672 672 #endif
673 673
674 674 Default destination, same directory
675 675
676 676 $ hg init q
677 677 $ hg clone q
678 678 destination directory: q
679 679 abort: destination 'q' is not empty
680 680 [255]
681 681
682 682 destination directory not empty
683 683
684 684 $ mkdir a
685 685 $ echo stuff > a/a
686 686 $ hg clone q a
687 687 abort: destination 'a' is not empty
688 688 [255]
689 689
690 690
691 691 #if unix-permissions no-root
692 692
693 693 leave existing directory in place after clone failure
694 694
695 695 $ hg init c
696 696 $ cd c
697 697 $ echo c > c
698 698 $ hg commit -A -m test
699 699 adding c
700 700 $ chmod -rx .hg/store/data
701 701 $ cd ..
702 702 $ mkdir d
703 703 $ hg clone c d 2> err
704 704 [255]
705 705 $ test -d d
706 706 $ test -d d/.hg
707 707 [1]
708 708
709 709 re-enable perm to allow deletion
710 710
711 711 $ chmod +rx c/.hg/store/data
712 712
713 713 #endif
714 714
715 715 $ cd ..
716 716
717 717 Test clone from the repository in (emulated) revlog format 0 (issue4203):
718 718
719 719 $ mkdir issue4203
720 720 $ mkdir -p src/.hg
721 721 $ echo foo > src/foo
722 722 $ hg -R src add src/foo
723 723 $ hg -R src commit -m '#0'
724 724 $ hg -R src log -q
725 725 0:e1bab28bca43
726 726 $ hg clone -U -q src dst
727 727 $ hg -R dst log -q
728 728 0:e1bab28bca43
729 729
730 730 Create repositories to test auto sharing functionality
731 731
732 732 $ cat >> $HGRCPATH << EOF
733 733 > [extensions]
734 734 > share=
735 735 > EOF
736 736
737 737 $ hg init empty
738 738 $ hg init source1a
739 739 $ cd source1a
740 740 $ echo initial1 > foo
741 741 $ hg -q commit -A -m initial
742 742 $ echo second > foo
743 743 $ hg commit -m second
744 744 $ cd ..
745 745
746 746 $ hg init filteredrev0
747 747 $ cd filteredrev0
748 748 $ cat >> .hg/hgrc << EOF
749 749 > [experimental]
750 750 > evolution.createmarkers=True
751 751 > EOF
752 752 $ echo initial1 > foo
753 753 $ hg -q commit -A -m initial0
754 754 $ hg -q up -r null
755 755 $ echo initial2 > foo
756 756 $ hg -q commit -A -m initial1
757 757 $ hg debugobsolete c05d5c47a5cf81401869999f3d05f7d699d2b29a e082c1832e09a7d1e78b7fd49a592d372de854c8
758 758 obsoleted 1 changesets
759 759 $ cd ..
760 760
761 761 $ hg -q clone --pull source1a source1b
762 762 $ cd source1a
763 763 $ hg bookmark bookA
764 764 $ echo 1a > foo
765 765 $ hg commit -m 1a
766 766 $ cd ../source1b
767 767 $ hg -q up -r 0
768 768 $ echo head1 > foo
769 769 $ hg commit -m head1
770 770 created new head
771 771 $ hg bookmark head1
772 772 $ hg -q up -r 0
773 773 $ echo head2 > foo
774 774 $ hg commit -m head2
775 775 created new head
776 776 $ hg bookmark head2
777 777 $ hg -q up -r 0
778 778 $ hg branch branch1
779 779 marked working directory as branch branch1
780 780 (branches are permanent and global, did you want a bookmark?)
781 781 $ echo branch1 > foo
782 782 $ hg commit -m branch1
783 783 $ hg -q up -r 0
784 784 $ hg branch branch2
785 785 marked working directory as branch branch2
786 786 $ echo branch2 > foo
787 787 $ hg commit -m branch2
788 788 $ cd ..
789 789 $ hg init source2
790 790 $ cd source2
791 791 $ echo initial2 > foo
792 792 $ hg -q commit -A -m initial2
793 793 $ echo second > foo
794 794 $ hg commit -m second
795 795 $ cd ..
796 796
797 797 Clone with auto share from an empty repo should not result in share
798 798
799 799 $ mkdir share
800 800 $ hg --config share.pool=share clone empty share-empty
801 801 (not using pooled storage: remote appears to be empty)
802 802 updating to branch default
803 803 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
804 804 $ ls share
805 805 $ test -d share-empty/.hg/store
806 806 $ test -f share-empty/.hg/sharedpath
807 807 [1]
808 808
809 809 Clone with auto share from a repo with filtered revision 0 should not result in share
810 810
811 811 $ hg --config share.pool=share clone filteredrev0 share-filtered
812 812 (not using pooled storage: unable to resolve identity of remote)
813 813 requesting all changes
814 814 adding changesets
815 815 adding manifests
816 816 adding file changes
817 817 added 1 changesets with 1 changes to 1 files
818 818 new changesets e082c1832e09
819 819 updating to branch default
820 820 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
821 821
822 822 Clone from repo with content should result in shared store being created
823 823
824 824 $ hg --config share.pool=share clone source1a share-dest1a
825 825 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
826 826 requesting all changes
827 827 adding changesets
828 828 adding manifests
829 829 adding file changes
830 830 added 3 changesets with 3 changes to 1 files
831 831 new changesets b5f04eac9d8f:e5bfe23c0b47
832 832 searching for changes
833 833 no changes found
834 834 adding remote bookmark bookA
835 835 updating working directory
836 836 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
837 837
838 838 The shared repo should have been created
839 839
840 840 $ ls share
841 841 b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1
842 842
843 843 The destination should point to it
844 844
845 845 $ cat share-dest1a/.hg/sharedpath; echo
846 846 $TESTTMP/share/b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1/.hg
847 847
848 848 The destination should have bookmarks
849 849
850 850 $ hg -R share-dest1a bookmarks
851 851 bookA 2:e5bfe23c0b47
852 852
853 853 The default path should be the remote, not the share
854 854
855 855 $ hg -R share-dest1a config paths.default
856 856 $TESTTMP/source1a
857 857
858 858 Clone with existing share dir should result in pull + share
859 859
860 860 $ hg --config share.pool=share clone source1b share-dest1b
861 861 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
862 862 searching for changes
863 863 adding changesets
864 864 adding manifests
865 865 adding file changes
866 866 added 4 changesets with 4 changes to 1 files (+4 heads)
867 867 adding remote bookmark head1
868 868 adding remote bookmark head2
869 869 new changesets 4a8dc1ab4c13:6bacf4683960
870 870 updating working directory
871 871 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
872 872
873 873 $ ls share
874 874 b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1
875 875
876 876 $ cat share-dest1b/.hg/sharedpath; echo
877 877 $TESTTMP/share/b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1/.hg
878 878
879 879 We only get bookmarks from the remote, not everything in the share
880 880
881 881 $ hg -R share-dest1b bookmarks
882 882 head1 3:4a8dc1ab4c13
883 883 head2 4:99f71071f117
884 884
885 885 Default path should be source, not share.
886 886
887 887 $ hg -R share-dest1b config paths.default
888 888 $TESTTMP/source1b
889 889
890 890 Checked out revision should be head of default branch
891 891
892 892 $ hg -R share-dest1b log -r .
893 893 changeset: 4:99f71071f117
894 894 bookmark: head2
895 895 parent: 0:b5f04eac9d8f
896 896 user: test
897 897 date: Thu Jan 01 00:00:00 1970 +0000
898 898 summary: head2
899 899
900 900
901 901 Clone from unrelated repo should result in new share
902 902
903 903 $ hg --config share.pool=share clone source2 share-dest2
904 904 (sharing from new pooled repository 22aeff664783fd44c6d9b435618173c118c3448e)
905 905 requesting all changes
906 906 adding changesets
907 907 adding manifests
908 908 adding file changes
909 909 added 2 changesets with 2 changes to 1 files
910 910 new changesets 22aeff664783:63cf6c3dba4a
911 911 searching for changes
912 912 no changes found
913 913 updating working directory
914 914 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
915 915
916 916 $ ls share
917 917 22aeff664783fd44c6d9b435618173c118c3448e
918 918 b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1
919 919
920 920 remote naming mode works as advertised
921 921
922 922 $ hg --config share.pool=shareremote --config share.poolnaming=remote clone source1a share-remote1a
923 923 (sharing from new pooled repository 195bb1fcdb595c14a6c13e0269129ed78f6debde)
924 924 requesting all changes
925 925 adding changesets
926 926 adding manifests
927 927 adding file changes
928 928 added 3 changesets with 3 changes to 1 files
929 929 new changesets b5f04eac9d8f:e5bfe23c0b47
930 930 searching for changes
931 931 no changes found
932 932 adding remote bookmark bookA
933 933 updating working directory
934 934 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
935 935
936 936 $ ls shareremote
937 937 195bb1fcdb595c14a6c13e0269129ed78f6debde
938 938
939 939 $ hg --config share.pool=shareremote --config share.poolnaming=remote clone source1b share-remote1b
940 940 (sharing from new pooled repository c0d4f83847ca2a873741feb7048a45085fd47c46)
941 941 requesting all changes
942 942 adding changesets
943 943 adding manifests
944 944 adding file changes
945 945 added 6 changesets with 6 changes to 1 files (+4 heads)
946 946 new changesets b5f04eac9d8f:6bacf4683960
947 947 searching for changes
948 948 no changes found
949 949 adding remote bookmark head1
950 950 adding remote bookmark head2
951 951 updating working directory
952 952 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
953 953
954 954 $ ls shareremote
955 955 195bb1fcdb595c14a6c13e0269129ed78f6debde
956 956 c0d4f83847ca2a873741feb7048a45085fd47c46
957 957
958 958 request to clone a single revision is respected in sharing mode
959 959
960 960 $ hg --config share.pool=sharerevs clone -r 4a8dc1ab4c13 source1b share-1arev
961 961 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
962 962 adding changesets
963 963 adding manifests
964 964 adding file changes
965 965 added 2 changesets with 2 changes to 1 files
966 966 new changesets b5f04eac9d8f:4a8dc1ab4c13
967 967 no changes found
968 968 adding remote bookmark head1
969 969 updating working directory
970 970 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
971 971
972 972 $ hg -R share-1arev log -G
973 973 @ changeset: 1:4a8dc1ab4c13
974 974 | bookmark: head1
975 975 | tag: tip
976 976 | user: test
977 977 | date: Thu Jan 01 00:00:00 1970 +0000
978 978 | summary: head1
979 979 |
980 980 o changeset: 0:b5f04eac9d8f
981 981 user: test
982 982 date: Thu Jan 01 00:00:00 1970 +0000
983 983 summary: initial
984 984
985 985
986 986 making another clone should only pull down requested rev
987 987
988 988 $ hg --config share.pool=sharerevs clone -r 99f71071f117 source1b share-1brev
989 989 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
990 990 searching for changes
991 991 adding changesets
992 992 adding manifests
993 993 adding file changes
994 994 added 1 changesets with 1 changes to 1 files (+1 heads)
995 995 adding remote bookmark head1
996 996 adding remote bookmark head2
997 997 new changesets 99f71071f117
998 998 updating working directory
999 999 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1000 1000
1001 1001 $ hg -R share-1brev log -G
1002 1002 @ changeset: 2:99f71071f117
1003 1003 | bookmark: head2
1004 1004 | tag: tip
1005 1005 | parent: 0:b5f04eac9d8f
1006 1006 | user: test
1007 1007 | date: Thu Jan 01 00:00:00 1970 +0000
1008 1008 | summary: head2
1009 1009 |
1010 1010 | o changeset: 1:4a8dc1ab4c13
1011 1011 |/ bookmark: head1
1012 1012 | user: test
1013 1013 | date: Thu Jan 01 00:00:00 1970 +0000
1014 1014 | summary: head1
1015 1015 |
1016 1016 o changeset: 0:b5f04eac9d8f
1017 1017 user: test
1018 1018 date: Thu Jan 01 00:00:00 1970 +0000
1019 1019 summary: initial
1020 1020
1021 1021
1022 1022 Request to clone a single branch is respected in sharing mode
1023 1023
1024 1024 $ hg --config share.pool=sharebranch clone -b branch1 source1b share-1bbranch1
1025 1025 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1026 1026 adding changesets
1027 1027 adding manifests
1028 1028 adding file changes
1029 1029 added 2 changesets with 2 changes to 1 files
1030 1030 new changesets b5f04eac9d8f:5f92a6c1a1b1
1031 1031 no changes found
1032 1032 updating working directory
1033 1033 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1034 1034
1035 1035 $ hg -R share-1bbranch1 log -G
1036 1036 o changeset: 1:5f92a6c1a1b1
1037 1037 | branch: branch1
1038 1038 | tag: tip
1039 1039 | user: test
1040 1040 | date: Thu Jan 01 00:00:00 1970 +0000
1041 1041 | summary: branch1
1042 1042 |
1043 1043 @ changeset: 0:b5f04eac9d8f
1044 1044 user: test
1045 1045 date: Thu Jan 01 00:00:00 1970 +0000
1046 1046 summary: initial
1047 1047
1048 1048
1049 1049 $ hg --config share.pool=sharebranch clone -b branch2 source1b share-1bbranch2
1050 1050 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1051 1051 searching for changes
1052 1052 adding changesets
1053 1053 adding manifests
1054 1054 adding file changes
1055 1055 added 1 changesets with 1 changes to 1 files (+1 heads)
1056 1056 new changesets 6bacf4683960
1057 1057 updating working directory
1058 1058 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1059 1059
1060 1060 $ hg -R share-1bbranch2 log -G
1061 1061 o changeset: 2:6bacf4683960
1062 1062 | branch: branch2
1063 1063 | tag: tip
1064 1064 | parent: 0:b5f04eac9d8f
1065 1065 | user: test
1066 1066 | date: Thu Jan 01 00:00:00 1970 +0000
1067 1067 | summary: branch2
1068 1068 |
1069 1069 | o changeset: 1:5f92a6c1a1b1
1070 1070 |/ branch: branch1
1071 1071 | user: test
1072 1072 | date: Thu Jan 01 00:00:00 1970 +0000
1073 1073 | summary: branch1
1074 1074 |
1075 1075 @ changeset: 0:b5f04eac9d8f
1076 1076 user: test
1077 1077 date: Thu Jan 01 00:00:00 1970 +0000
1078 1078 summary: initial
1079 1079
1080 1080
1081 1081 -U is respected in share clone mode
1082 1082
1083 1083 $ hg --config share.pool=share clone -U source1a share-1anowc
1084 1084 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1085 1085 searching for changes
1086 1086 no changes found
1087 1087 adding remote bookmark bookA
1088 1088
1089 1089 $ ls share-1anowc
1090 1090
1091 1091 Test that auto sharing doesn't cause failure of "hg clone local remote"
1092 1092
1093 1093 $ cd $TESTTMP
1094 1094 $ hg -R a id -r 0
1095 1095 acb14030fe0a
1096 1096 $ hg id -R remote -r 0
1097 1097 abort: repository remote not found!
1098 1098 [255]
1099 1099 $ hg --config share.pool=share -q clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" a ssh://user@dummy/remote
1100 1100 $ hg -R remote id -r 0
1101 1101 acb14030fe0a
1102 1102
1103 1103 Cloning into pooled storage doesn't race (issue5104)
1104 1104
1105 1105 $ HGPOSTLOCKDELAY=2.0 hg --config share.pool=racepool --config extensions.lockdelay=$TESTDIR/lockdelay.py clone source1a share-destrace1 > race1.log 2>&1 &
1106 1106 $ HGPRELOCKDELAY=1.0 hg --config share.pool=racepool --config extensions.lockdelay=$TESTDIR/lockdelay.py clone source1a share-destrace2 > race2.log 2>&1
1107 1107 $ wait
1108 1108
1109 1109 $ hg -R share-destrace1 log -r tip
1110 1110 changeset: 2:e5bfe23c0b47
1111 1111 bookmark: bookA
1112 1112 tag: tip
1113 1113 user: test
1114 1114 date: Thu Jan 01 00:00:00 1970 +0000
1115 1115 summary: 1a
1116 1116
1117 1117
1118 1118 $ hg -R share-destrace2 log -r tip
1119 1119 changeset: 2:e5bfe23c0b47
1120 1120 bookmark: bookA
1121 1121 tag: tip
1122 1122 user: test
1123 1123 date: Thu Jan 01 00:00:00 1970 +0000
1124 1124 summary: 1a
1125 1125
1126 1126 One repo should be new, the other should be shared from the pool. We
1127 1127 don't care which is which, so we just make sure we always print the
1128 1128 one containing "new pooled" first, then one one containing "existing
1129 1129 pooled".
1130 1130
1131 1131 $ (grep 'new pooled' race1.log > /dev/null && cat race1.log || cat race2.log) | grep -v lock
1132 1132 (sharing from new pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1133 1133 requesting all changes
1134 1134 adding changesets
1135 1135 adding manifests
1136 1136 adding file changes
1137 1137 added 3 changesets with 3 changes to 1 files
1138 1138 new changesets b5f04eac9d8f:e5bfe23c0b47
1139 1139 searching for changes
1140 1140 no changes found
1141 1141 adding remote bookmark bookA
1142 1142 updating working directory
1143 1143 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1144 1144
1145 1145 $ (grep 'existing pooled' race1.log > /dev/null && cat race1.log || cat race2.log) | grep -v lock
1146 1146 (sharing from existing pooled repository b5f04eac9d8f7a6a9fcb070243cccea7dc5ea0c1)
1147 1147 searching for changes
1148 1148 no changes found
1149 1149 adding remote bookmark bookA
1150 1150 updating working directory
1151 1151 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1152 1152
1153 1153 SEC: check for unsafe ssh url
1154 1154
1155 1155 $ cat >> $HGRCPATH << EOF
1156 1156 > [ui]
1157 1157 > ssh = sh -c "read l; read l; read l"
1158 1158 > EOF
1159 1159
1160 1160 $ hg clone 'ssh://-oProxyCommand=touch${IFS}owned/path'
1161 1161 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path'
1162 1162 [255]
1163 1163 $ hg clone 'ssh://%2DoProxyCommand=touch${IFS}owned/path'
1164 1164 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path'
1165 1165 [255]
1166 1166 $ hg clone 'ssh://fakehost|touch%20owned/path'
1167 1167 abort: no suitable response from remote hg!
1168 1168 [255]
1169 1169 $ hg clone 'ssh://fakehost%7Ctouch%20owned/path'
1170 1170 abort: no suitable response from remote hg!
1171 1171 [255]
1172 1172
1173 1173 $ hg clone 'ssh://-oProxyCommand=touch owned%20foo@example.com/nonexistent/path'
1174 1174 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch owned foo@example.com/nonexistent/path'
1175 1175 [255]
1176 1176
1177 1177 #if windows
1178 1178 $ hg clone "ssh://%26touch%20owned%20/" --debug
1179 1179 running sh -c "read l; read l; read l" "&touch owned " "hg -R . serve --stdio"
1180 1180 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1181 1181 sending hello command
1182 1182 sending between command
1183 1183 abort: no suitable response from remote hg!
1184 1184 [255]
1185 1185 $ hg clone "ssh://example.com:%26touch%20owned%20/" --debug
1186 1186 running sh -c "read l; read l; read l" -p "&touch owned " example.com "hg -R . serve --stdio"
1187 1187 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1188 1188 sending hello command
1189 1189 sending between command
1190 1190 abort: no suitable response from remote hg!
1191 1191 [255]
1192 1192 #else
1193 1193 $ hg clone "ssh://%3btouch%20owned%20/" --debug
1194 1194 running sh -c "read l; read l; read l" ';touch owned ' 'hg -R . serve --stdio'
1195 1195 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1196 1196 sending hello command
1197 1197 sending between command
1198 1198 abort: no suitable response from remote hg!
1199 1199 [255]
1200 1200 $ hg clone "ssh://example.com:%3btouch%20owned%20/" --debug
1201 1201 running sh -c "read l; read l; read l" -p ';touch owned ' example.com 'hg -R . serve --stdio'
1202 1202 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1203 1203 sending hello command
1204 1204 sending between command
1205 1205 abort: no suitable response from remote hg!
1206 1206 [255]
1207 1207 #endif
1208 1208
1209 1209 $ hg clone "ssh://v-alid.example.com/" --debug
1210 1210 running sh -c "read l; read l; read l" v-alid\.example\.com ['"]hg -R \. serve --stdio['"] (re)
1211 1211 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
1212 1212 sending hello command
1213 1213 sending between command
1214 1214 abort: no suitable response from remote hg!
1215 1215 [255]
1216 1216
1217 1217 We should not have created a file named owned - if it exists, the
1218 1218 attack succeeded.
1219 1219 $ if test -f owned; then echo 'you got owned'; fi
1220 1220
1221 1221 Cloning without fsmonitor enabled does not print a warning for small repos
1222 1222
1223 1223 $ hg clone a fsmonitor-default
1224 1224 updating to bookmark @ on branch stable
1225 1225 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1226 1226
1227 1227 Lower the warning threshold to simulate a large repo
1228 1228
1229 1229 $ cat >> $HGRCPATH << EOF
1230 1230 > [fsmonitor]
1231 1231 > warn_update_file_count = 2
1232 1232 > EOF
1233 1233
1234 1234 We should see a warning about no fsmonitor on supported platforms
1235 1235
1236 1236 #if linuxormacos no-fsmonitor
1237 1237 $ hg clone a nofsmonitor
1238 1238 updating to bookmark @ on branch stable
1239 1239 (warning: large working directory being used without fsmonitor enabled; enable fsmonitor to improve performance; see "hg help -e fsmonitor")
1240 1240 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1241 1241 #else
1242 1242 $ hg clone a nofsmonitor
1243 1243 updating to bookmark @ on branch stable
1244 1244 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1245 1245 #endif
1246 1246
1247 1247 We should not see warning about fsmonitor when it is enabled
1248 1248
1249 1249 #if fsmonitor
1250 1250 $ hg clone a fsmonitor-enabled
1251 1251 updating to bookmark @ on branch stable
1252 1252 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1253 1253 #endif
1254 1254
1255 1255 We can disable the fsmonitor warning
1256 1256
1257 1257 $ hg --config fsmonitor.warn_when_unused=false clone a fsmonitor-disable-warning
1258 1258 updating to bookmark @ on branch stable
1259 1259 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1260 1260
1261 1261 Loaded fsmonitor but disabled in config should still print warning
1262 1262
1263 1263 #if linuxormacos fsmonitor
1264 1264 $ hg --config fsmonitor.mode=off clone a fsmonitor-mode-off
1265 1265 updating to bookmark @ on branch stable
1266 1266 (warning: large working directory being used without fsmonitor enabled; enable fsmonitor to improve performance; see "hg help -e fsmonitor") (fsmonitor !)
1267 1267 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1268 1268 #endif
1269 1269
1270 1270 Warning not printed if working directory isn't empty
1271 1271
1272 1272 $ hg -q clone a fsmonitor-update
1273 1273 (warning: large working directory being used without fsmonitor enabled; enable fsmonitor to improve performance; see "hg help -e fsmonitor") (?)
1274 1274 $ cd fsmonitor-update
1275 1275 $ hg up acb14030fe0a
1276 1276 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
1277 1277 (leaving bookmark @)
1278 1278 $ hg up cf0fe1914066
1279 1279 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1280 1280
1281 1281 `hg update` from null revision also prints
1282 1282
1283 1283 $ hg up null
1284 1284 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1285 1285
1286 1286 #if linuxormacos no-fsmonitor
1287 1287 $ hg up cf0fe1914066
1288 1288 (warning: large working directory being used without fsmonitor enabled; enable fsmonitor to improve performance; see "hg help -e fsmonitor")
1289 1289 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1290 1290 #else
1291 1291 $ hg up cf0fe1914066
1292 1292 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1293 1293 #endif
1294 1294
1295 1295 $ cd ..
1296 1296
@@ -1,432 +1,432 b''
1 1 #require hardlink reporevlogstore
2 2
3 3 $ cat > nlinks.py <<EOF
4 4 > from __future__ import print_function
5 5 > import sys
6 6 > from mercurial import util
7 7 > for f in sorted(sys.stdin.readlines()):
8 8 > f = f[:-1]
9 9 > print(util.nlinks(f), f)
10 10 > EOF
11 11
12 12 $ nlinksdir()
13 13 > {
14 14 > find "$@" -type f | "$PYTHON" $TESTTMP/nlinks.py
15 15 > }
16 16
17 17 Some implementations of cp can't create hardlinks (replaces 'cp -al' on Linux):
18 18
19 19 $ cat > linkcp.py <<EOF
20 20 > from __future__ import absolute_import
21 21 > import sys
22 22 > from mercurial import pycompat, util
23 23 > util.copyfiles(pycompat.fsencode(sys.argv[1]),
24 24 > pycompat.fsencode(sys.argv[2]), hardlink=True)
25 25 > EOF
26 26
27 27 $ linkcp()
28 28 > {
29 29 > "$PYTHON" $TESTTMP/linkcp.py $1 $2
30 30 > }
31 31
32 32 Prepare repo r1:
33 33
34 34 $ hg init r1
35 35 $ cd r1
36 36
37 37 $ echo c1 > f1
38 38 $ hg add f1
39 39 $ hg ci -m0
40 40
41 41 $ mkdir d1
42 42 $ cd d1
43 43 $ echo c2 > f2
44 44 $ hg add f2
45 45 $ hg ci -m1
46 46 $ cd ../..
47 47
48 48 $ nlinksdir r1/.hg/store
49 49 1 r1/.hg/store/00changelog.i
50 50 1 r1/.hg/store/00manifest.i
51 51 1 r1/.hg/store/data/d1/f2.i
52 52 1 r1/.hg/store/data/f1.i
53 53 1 r1/.hg/store/fncache (repofncache !)
54 54 1 r1/.hg/store/phaseroots
55 55 1 r1/.hg/store/undo
56 56 1 r1/.hg/store/undo.backup.fncache (repofncache !)
57 57 1 r1/.hg/store/undo.backupfiles
58 58 1 r1/.hg/store/undo.phaseroots
59 59
60 60
61 61 Create hardlinked clone r2:
62 62
63 63 $ hg clone -U --debug r1 r2 --config progress.debug=true
64 linking: 1
65 linking: 2
66 linking: 3
67 linking: 4
68 linking: 5
69 linking: 6
70 linking: 7
64 linking: 1 files
65 linking: 2 files
66 linking: 3 files
67 linking: 4 files
68 linking: 5 files
69 linking: 6 files
70 linking: 7 files
71 71 linked 7 files
72 72
73 73 Create non-hardlinked clone r3:
74 74
75 75 $ hg clone --pull r1 r3
76 76 requesting all changes
77 77 adding changesets
78 78 adding manifests
79 79 adding file changes
80 80 added 2 changesets with 2 changes to 2 files
81 81 new changesets 40d85e9847f2:7069c422939c
82 82 updating to branch default
83 83 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
84 84
85 85
86 86 Repos r1 and r2 should now contain hardlinked files:
87 87
88 88 $ nlinksdir r1/.hg/store
89 89 2 r1/.hg/store/00changelog.i
90 90 2 r1/.hg/store/00manifest.i
91 91 2 r1/.hg/store/data/d1/f2.i
92 92 2 r1/.hg/store/data/f1.i
93 93 2 r1/.hg/store/fncache (repofncache !)
94 94 1 r1/.hg/store/phaseroots
95 95 1 r1/.hg/store/undo
96 96 1 r1/.hg/store/undo.backup.fncache (repofncache !)
97 97 1 r1/.hg/store/undo.backupfiles
98 98 1 r1/.hg/store/undo.phaseroots
99 99
100 100 $ nlinksdir r2/.hg/store
101 101 2 r2/.hg/store/00changelog.i
102 102 2 r2/.hg/store/00manifest.i
103 103 2 r2/.hg/store/data/d1/f2.i
104 104 2 r2/.hg/store/data/f1.i
105 105 2 r2/.hg/store/fncache (repofncache !)
106 106
107 107 Repo r3 should not be hardlinked:
108 108
109 109 $ nlinksdir r3/.hg/store
110 110 1 r3/.hg/store/00changelog.i
111 111 1 r3/.hg/store/00manifest.i
112 112 1 r3/.hg/store/data/d1/f2.i
113 113 1 r3/.hg/store/data/f1.i
114 114 1 r3/.hg/store/fncache (repofncache !)
115 115 1 r3/.hg/store/phaseroots
116 116 1 r3/.hg/store/undo
117 117 1 r3/.hg/store/undo.backupfiles
118 118 1 r3/.hg/store/undo.phaseroots
119 119
120 120
121 121 Create a non-inlined filelog in r3:
122 122
123 123 $ cd r3/d1
124 124 >>> f = open('data1', 'wb')
125 125 >>> for x in range(10000):
126 126 ... f.write(b"%d\n" % x) and None
127 127 >>> f.close()
128 128 $ for j in 0 1 2 3 4 5 6 7 8 9; do
129 129 > cat data1 >> f2
130 130 > hg commit -m$j
131 131 > done
132 132 $ cd ../..
133 133
134 134 $ nlinksdir r3/.hg/store
135 135 1 r3/.hg/store/00changelog.i
136 136 1 r3/.hg/store/00manifest.i
137 137 1 r3/.hg/store/data/d1/f2.d
138 138 1 r3/.hg/store/data/d1/f2.i
139 139 1 r3/.hg/store/data/f1.i
140 140 1 r3/.hg/store/fncache (repofncache !)
141 141 1 r3/.hg/store/phaseroots
142 142 1 r3/.hg/store/undo
143 143 1 r3/.hg/store/undo.backup.fncache (repofncache !)
144 144 1 r3/.hg/store/undo.backup.phaseroots
145 145 1 r3/.hg/store/undo.backupfiles
146 146 1 r3/.hg/store/undo.phaseroots
147 147
148 148 Push to repo r1 should break up most hardlinks in r2:
149 149
150 150 $ hg -R r2 verify
151 151 checking changesets
152 152 checking manifests
153 153 crosschecking files in changesets and manifests
154 154 checking files
155 155 checked 2 changesets with 2 changes to 2 files
156 156
157 157 $ cd r3
158 158 $ hg push
159 159 pushing to $TESTTMP/r1
160 160 searching for changes
161 161 adding changesets
162 162 adding manifests
163 163 adding file changes
164 164 added 10 changesets with 10 changes to 1 files
165 165
166 166 $ cd ..
167 167
168 168 $ nlinksdir r2/.hg/store
169 169 1 r2/.hg/store/00changelog.i
170 170 1 r2/.hg/store/00manifest.i
171 171 1 r2/.hg/store/data/d1/f2.i
172 172 2 r2/.hg/store/data/f1.i
173 173 [12] r2/\.hg/store/fncache (re) (repofncache !)
174 174
175 175 #if hardlink-whitelisted repofncache
176 176 $ nlinksdir r2/.hg/store/fncache
177 177 2 r2/.hg/store/fncache
178 178 #endif
179 179
180 180 $ hg -R r2 verify
181 181 checking changesets
182 182 checking manifests
183 183 crosschecking files in changesets and manifests
184 184 checking files
185 185 checked 2 changesets with 2 changes to 2 files
186 186
187 187
188 188 $ cd r1
189 189 $ hg up
190 190 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
191 191
192 192 Committing a change to f1 in r1 must break up hardlink f1.i in r2:
193 193
194 194 $ echo c1c1 >> f1
195 195 $ hg ci -m00
196 196 $ cd ..
197 197
198 198 $ nlinksdir r2/.hg/store
199 199 1 r2/.hg/store/00changelog.i
200 200 1 r2/.hg/store/00manifest.i
201 201 1 r2/.hg/store/data/d1/f2.i
202 202 1 r2/.hg/store/data/f1.i
203 203 [12] r2/\.hg/store/fncache (re) (repofncache !)
204 204
205 205 #if hardlink-whitelisted repofncache
206 206 $ nlinksdir r2/.hg/store/fncache
207 207 2 r2/.hg/store/fncache
208 208 #endif
209 209
210 210 Create a file which exec permissions we will change
211 211 $ cd r3
212 212 $ echo "echo hello world" > f3
213 213 $ hg add f3
214 214 $ hg ci -mf3
215 215 $ cd ..
216 216
217 217 $ cd r3
218 218 $ hg tip --template '{rev}:{node|short}\n'
219 219 12:d3b77733a28a
220 220 $ echo bla > f1
221 221 $ chmod +x f3
222 222 $ hg ci -m1
223 223 $ cd ..
224 224
225 225 Create hardlinked copy r4 of r3 (on Linux, we would call 'cp -al'):
226 226
227 227 $ linkcp r3 r4
228 228
229 229 'checklink' is produced by hardlinking a symlink, which is undefined whether
230 230 the symlink should be followed or not. It does behave differently on Linux and
231 231 BSD. Just remove it so the test pass on both platforms.
232 232
233 233 $ rm -f r4/.hg/cache/checklink
234 234
235 235 r4 has hardlinks in the working dir (not just inside .hg):
236 236
237 237 $ nlinksdir r4
238 238 2 r4/.hg/00changelog.i
239 239 2 r4/.hg/branch
240 240 2 r4/.hg/cache/branch2-base
241 241 2 r4/.hg/cache/branch2-served
242 242 2 r4/.hg/cache/checkisexec (execbit !)
243 243 ? r4/.hg/cache/checklink-target (glob) (symlink !)
244 244 2 r4/.hg/cache/checknoexec (execbit !)
245 245 2 r4/.hg/cache/manifestfulltextcache (reporevlogstore !)
246 246 2 r4/.hg/cache/rbc-names-v1
247 247 2 r4/.hg/cache/rbc-revs-v1
248 248 2 r4/.hg/dirstate
249 249 2 r4/.hg/fsmonitor.state (fsmonitor !)
250 250 2 r4/.hg/hgrc
251 251 2 r4/.hg/last-message.txt
252 252 2 r4/.hg/requires
253 253 2 r4/.hg/store/00changelog.i
254 254 2 r4/.hg/store/00manifest.i
255 255 2 r4/.hg/store/data/d1/f2.d
256 256 2 r4/.hg/store/data/d1/f2.i
257 257 2 r4/.hg/store/data/f1.i
258 258 2 r4/.hg/store/data/f3.i
259 259 2 r4/.hg/store/fncache (repofncache !)
260 260 2 r4/.hg/store/phaseroots
261 261 2 r4/.hg/store/undo
262 262 2 r4/.hg/store/undo.backup.fncache (repofncache !)
263 263 2 r4/.hg/store/undo.backup.phaseroots
264 264 2 r4/.hg/store/undo.backupfiles
265 265 2 r4/.hg/store/undo.phaseroots
266 266 [24] r4/\.hg/undo\.backup\.dirstate (re)
267 267 2 r4/.hg/undo.bookmarks
268 268 2 r4/.hg/undo.branch
269 269 2 r4/.hg/undo.desc
270 270 [24] r4/\.hg/undo\.dirstate (re)
271 271 2 r4/d1/data1
272 272 2 r4/d1/f2
273 273 2 r4/f1
274 274 2 r4/f3
275 275
276 276 Update back to revision 12 in r4 should break hardlink of file f1 and f3:
277 277 #if hardlink-whitelisted
278 278 $ nlinksdir r4/.hg/undo.backup.dirstate r4/.hg/undo.dirstate
279 279 4 r4/.hg/undo.backup.dirstate
280 280 4 r4/.hg/undo.dirstate
281 281 #endif
282 282
283 283
284 284 $ hg -R r4 up 12
285 285 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (execbit !)
286 286 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-execbit !)
287 287
288 288 $ nlinksdir r4
289 289 2 r4/.hg/00changelog.i
290 290 1 r4/.hg/branch
291 291 2 r4/.hg/cache/branch2-base
292 292 2 r4/.hg/cache/branch2-served
293 293 2 r4/.hg/cache/checkisexec (execbit !)
294 294 2 r4/.hg/cache/checklink-target (symlink !)
295 295 2 r4/.hg/cache/checknoexec (execbit !)
296 296 2 r4/.hg/cache/manifestfulltextcache (reporevlogstore !)
297 297 2 r4/.hg/cache/rbc-names-v1
298 298 2 r4/.hg/cache/rbc-revs-v1
299 299 1 r4/.hg/dirstate
300 300 1 r4/.hg/fsmonitor.state (fsmonitor !)
301 301 2 r4/.hg/hgrc
302 302 2 r4/.hg/last-message.txt
303 303 2 r4/.hg/requires
304 304 2 r4/.hg/store/00changelog.i
305 305 2 r4/.hg/store/00manifest.i
306 306 2 r4/.hg/store/data/d1/f2.d
307 307 2 r4/.hg/store/data/d1/f2.i
308 308 2 r4/.hg/store/data/f1.i
309 309 2 r4/.hg/store/data/f3.i
310 310 2 r4/.hg/store/fncache
311 311 2 r4/.hg/store/phaseroots
312 312 2 r4/.hg/store/undo
313 313 2 r4/.hg/store/undo.backup.fncache (repofncache !)
314 314 2 r4/.hg/store/undo.backup.phaseroots
315 315 2 r4/.hg/store/undo.backupfiles
316 316 2 r4/.hg/store/undo.phaseroots
317 317 [24] r4/\.hg/undo\.backup\.dirstate (re)
318 318 2 r4/.hg/undo.bookmarks
319 319 2 r4/.hg/undo.branch
320 320 2 r4/.hg/undo.desc
321 321 [24] r4/\.hg/undo\.dirstate (re)
322 322 2 r4/d1/data1
323 323 2 r4/d1/f2
324 324 1 r4/f1
325 325 1 r4/f3 (execbit !)
326 326 2 r4/f3 (no-execbit !)
327 327
328 328 #if hardlink-whitelisted
329 329 $ nlinksdir r4/.hg/undo.backup.dirstate r4/.hg/undo.dirstate
330 330 4 r4/.hg/undo.backup.dirstate
331 331 4 r4/.hg/undo.dirstate
332 332 #endif
333 333
334 334 Test hardlinking outside hg:
335 335
336 336 $ mkdir x
337 337 $ echo foo > x/a
338 338
339 339 $ linkcp x y
340 340 $ echo bar >> y/a
341 341
342 342 No diff if hardlink:
343 343
344 344 $ diff x/a y/a
345 345
346 346 Test mq hardlinking:
347 347
348 348 $ echo "[extensions]" >> $HGRCPATH
349 349 $ echo "mq=" >> $HGRCPATH
350 350
351 351 $ hg init a
352 352 $ cd a
353 353
354 354 $ hg qimport -n foo - << EOF
355 355 > # HG changeset patch
356 356 > # Date 1 0
357 357 > diff -r 2588a8b53d66 a
358 358 > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
359 359 > +++ b/a Wed Jul 23 15:54:29 2008 +0200
360 360 > @@ -0,0 +1,1 @@
361 361 > +a
362 362 > EOF
363 363 adding foo to series file
364 364
365 365 $ hg qpush
366 366 applying foo
367 367 now at: foo
368 368
369 369 $ cd ..
370 370 $ linkcp a b
371 371 $ cd b
372 372
373 373 $ hg qimport -n bar - << EOF
374 374 > # HG changeset patch
375 375 > # Date 2 0
376 376 > diff -r 2588a8b53d66 a
377 377 > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
378 378 > +++ b/b Wed Jul 23 15:54:29 2008 +0200
379 379 > @@ -0,0 +1,1 @@
380 380 > +b
381 381 > EOF
382 382 adding bar to series file
383 383
384 384 $ hg qpush
385 385 applying bar
386 386 now at: bar
387 387
388 388 $ cat .hg/patches/status
389 389 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
390 390 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c:bar
391 391
392 392 $ cat .hg/patches/series
393 393 foo
394 394 bar
395 395
396 396 $ cat ../a/.hg/patches/status
397 397 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
398 398
399 399 $ cat ../a/.hg/patches/series
400 400 foo
401 401
402 402 Test tags hardlinking:
403 403
404 404 $ hg qdel -r qbase:qtip
405 405 patch foo finalized without changeset message
406 406 patch bar finalized without changeset message
407 407
408 408 $ hg tag -l lfoo
409 409 $ hg tag foo
410 410
411 411 $ cd ..
412 412 $ linkcp b c
413 413 $ cd c
414 414
415 415 $ hg tag -l -r 0 lbar
416 416 $ hg tag -r 0 bar
417 417
418 418 $ cat .hgtags
419 419 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
420 420 430ed4828a74fa4047bc816a25500f7472ab4bfe bar
421 421
422 422 $ cat .hg/localtags
423 423 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
424 424 430ed4828a74fa4047bc816a25500f7472ab4bfe lbar
425 425
426 426 $ cat ../b/.hgtags
427 427 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
428 428
429 429 $ cat ../b/.hg/localtags
430 430 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
431 431
432 432 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now