##// END OF EJS Templates
hg: use "os.path.join()" to join path components which may be empty (issue4203)...
FUJIWARA Katsunori -
r20825:dda11e79 stable
parent child Browse files
Show More
@@ -1,631 +1,633 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 i18n import _
10 10 from lock import release
11 11 from node import hex, nullid
12 12 import localrepo, bundlerepo, unionrepo, httppeer, sshpeer, statichttprepo
13 13 import bookmarks, lock, util, extensions, error, node, scmutil, phases, url
14 14 import cmdutil, discovery
15 15 import merge as mergemod
16 16 import verify as verifymod
17 17 import errno, os, shutil
18 18
19 19 def _local(path):
20 20 path = util.expandpath(util.urllocalpath(path))
21 21 return (os.path.isfile(path) and bundlerepo or localrepo)
22 22
23 23 def addbranchrevs(lrepo, other, branches, revs):
24 24 peer = other.peer() # a courtesy to callers using a localrepo for other
25 25 hashbranch, branches = branches
26 26 if not hashbranch and not branches:
27 27 return revs or None, revs and revs[0] or None
28 28 revs = revs and list(revs) or []
29 29 if not peer.capable('branchmap'):
30 30 if branches:
31 31 raise util.Abort(_("remote branch lookup not supported"))
32 32 revs.append(hashbranch)
33 33 return revs, revs[0]
34 34 branchmap = peer.branchmap()
35 35
36 36 def primary(branch):
37 37 if branch == '.':
38 38 if not lrepo:
39 39 raise util.Abort(_("dirstate branch not accessible"))
40 40 branch = lrepo.dirstate.branch()
41 41 if branch in branchmap:
42 42 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
43 43 return True
44 44 else:
45 45 return False
46 46
47 47 for branch in branches:
48 48 if not primary(branch):
49 49 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
50 50 if hashbranch:
51 51 if not primary(hashbranch):
52 52 revs.append(hashbranch)
53 53 return revs, revs[0]
54 54
55 55 def parseurl(path, branches=None):
56 56 '''parse url#branch, returning (url, (branch, branches))'''
57 57
58 58 u = util.url(path)
59 59 branch = None
60 60 if u.fragment:
61 61 branch = u.fragment
62 62 u.fragment = None
63 63 return str(u), (branch, branches or [])
64 64
65 65 schemes = {
66 66 'bundle': bundlerepo,
67 67 'union': unionrepo,
68 68 'file': _local,
69 69 'http': httppeer,
70 70 'https': httppeer,
71 71 'ssh': sshpeer,
72 72 'static-http': statichttprepo,
73 73 }
74 74
75 75 def _peerlookup(path):
76 76 u = util.url(path)
77 77 scheme = u.scheme or 'file'
78 78 thing = schemes.get(scheme) or schemes['file']
79 79 try:
80 80 return thing(path)
81 81 except TypeError:
82 82 return thing
83 83
84 84 def islocal(repo):
85 85 '''return true if repo (or path pointing to repo) is local'''
86 86 if isinstance(repo, str):
87 87 try:
88 88 return _peerlookup(repo).islocal(repo)
89 89 except AttributeError:
90 90 return False
91 91 return repo.local()
92 92
93 93 def openpath(ui, path):
94 94 '''open path with open if local, url.open if remote'''
95 95 pathurl = util.url(path, parsequery=False, parsefragment=False)
96 96 if pathurl.islocal():
97 97 return util.posixfile(pathurl.localpath(), 'rb')
98 98 else:
99 99 return url.open(ui, path)
100 100
101 101 def _peerorrepo(ui, path, create=False):
102 102 """return a repository object for the specified path"""
103 103 obj = _peerlookup(path).instance(ui, path, create)
104 104 ui = getattr(obj, "ui", ui)
105 105 for name, module in extensions.extensions(ui):
106 106 hook = getattr(module, 'reposetup', None)
107 107 if hook:
108 108 hook(ui, obj)
109 109 return obj
110 110
111 111 def repository(ui, path='', create=False):
112 112 """return a repository object for the specified path"""
113 113 peer = _peerorrepo(ui, path, create)
114 114 repo = peer.local()
115 115 if not repo:
116 116 raise util.Abort(_("repository '%s' is not local") %
117 117 (path or peer.url()))
118 118 return repo.filtered('visible')
119 119
120 120 def peer(uiorrepo, opts, path, create=False):
121 121 '''return a repository peer for the specified path'''
122 122 rui = remoteui(uiorrepo, opts)
123 123 return _peerorrepo(rui, path, create).peer()
124 124
125 125 def defaultdest(source):
126 126 '''return default destination of clone if none is given'''
127 127 return os.path.basename(os.path.normpath(util.url(source).path or ''))
128 128
129 129 def share(ui, source, dest=None, update=True):
130 130 '''create a shared repository'''
131 131
132 132 if not islocal(source):
133 133 raise util.Abort(_('can only share local repositories'))
134 134
135 135 if not dest:
136 136 dest = defaultdest(source)
137 137 else:
138 138 dest = ui.expandpath(dest)
139 139
140 140 if isinstance(source, str):
141 141 origsource = ui.expandpath(source)
142 142 source, branches = parseurl(origsource)
143 143 srcrepo = repository(ui, source)
144 144 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
145 145 else:
146 146 srcrepo = source.local()
147 147 origsource = source = srcrepo.url()
148 148 checkout = None
149 149
150 150 sharedpath = srcrepo.sharedpath # if our source is already sharing
151 151
152 152 root = os.path.realpath(dest)
153 153 roothg = os.path.join(root, '.hg')
154 154
155 155 if os.path.exists(roothg):
156 156 raise util.Abort(_('destination already exists'))
157 157
158 158 if not os.path.isdir(root):
159 159 os.mkdir(root)
160 160 util.makedir(roothg, notindexed=True)
161 161
162 162 requirements = ''
163 163 try:
164 164 requirements = srcrepo.opener.read('requires')
165 165 except IOError, inst:
166 166 if inst.errno != errno.ENOENT:
167 167 raise
168 168
169 169 requirements += 'shared\n'
170 170 util.writefile(os.path.join(roothg, 'requires'), requirements)
171 171 util.writefile(os.path.join(roothg, 'sharedpath'), sharedpath)
172 172
173 173 r = repository(ui, root)
174 174
175 175 default = srcrepo.ui.config('paths', 'default')
176 176 if default:
177 177 fp = r.opener("hgrc", "w", text=True)
178 178 fp.write("[paths]\n")
179 179 fp.write("default = %s\n" % default)
180 180 fp.close()
181 181
182 182 if update:
183 183 r.ui.status(_("updating working directory\n"))
184 184 if update is not True:
185 185 checkout = update
186 186 for test in (checkout, 'default', 'tip'):
187 187 if test is None:
188 188 continue
189 189 try:
190 190 uprev = r.lookup(test)
191 191 break
192 192 except error.RepoLookupError:
193 193 continue
194 194 _update(r, uprev)
195 195
196 196 def copystore(ui, srcrepo, destpath):
197 197 '''copy files from store of srcrepo in destpath
198 198
199 199 returns destlock
200 200 '''
201 201 destlock = None
202 202 try:
203 203 hardlink = None
204 204 num = 0
205 205 srcpublishing = srcrepo.ui.configbool('phases', 'publish', True)
206 206 srcvfs = scmutil.vfs(srcrepo.sharedpath)
207 207 dstvfs = scmutil.vfs(destpath)
208 208 for f in srcrepo.store.copylist():
209 209 if srcpublishing and f.endswith('phaseroots'):
210 210 continue
211 211 dstbase = os.path.dirname(f)
212 212 if dstbase and not dstvfs.exists(dstbase):
213 213 dstvfs.mkdir(dstbase)
214 214 if srcvfs.exists(f):
215 215 if f.endswith('data'):
216 # 'dstbase' may be empty (e.g. revlog format 0)
217 lockfile = os.path.join(dstbase, "lock")
216 218 # lock to avoid premature writing to the target
217 destlock = lock.lock(dstvfs, dstbase + "/lock")
219 destlock = lock.lock(dstvfs, lockfile)
218 220 hardlink, n = util.copyfiles(srcvfs.join(f), dstvfs.join(f),
219 221 hardlink)
220 222 num += n
221 223 if hardlink:
222 224 ui.debug("linked %d files\n" % num)
223 225 else:
224 226 ui.debug("copied %d files\n" % num)
225 227 return destlock
226 228 except: # re-raises
227 229 release(destlock)
228 230 raise
229 231
230 232 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
231 233 update=True, stream=False, branch=None):
232 234 """Make a copy of an existing repository.
233 235
234 236 Create a copy of an existing repository in a new directory. The
235 237 source and destination are URLs, as passed to the repository
236 238 function. Returns a pair of repository peers, the source and
237 239 newly created destination.
238 240
239 241 The location of the source is added to the new repository's
240 242 .hg/hgrc file, as the default to be used for future pulls and
241 243 pushes.
242 244
243 245 If an exception is raised, the partly cloned/updated destination
244 246 repository will be deleted.
245 247
246 248 Arguments:
247 249
248 250 source: repository object or URL
249 251
250 252 dest: URL of destination repository to create (defaults to base
251 253 name of source repository)
252 254
253 255 pull: always pull from source repository, even in local case
254 256
255 257 stream: stream raw data uncompressed from repository (fast over
256 258 LAN, slow over WAN)
257 259
258 260 rev: revision to clone up to (implies pull=True)
259 261
260 262 update: update working directory after clone completes, if
261 263 destination is local repository (True means update to default rev,
262 264 anything else is treated as a revision)
263 265
264 266 branch: branches to clone
265 267 """
266 268
267 269 if isinstance(source, str):
268 270 origsource = ui.expandpath(source)
269 271 source, branch = parseurl(origsource, branch)
270 272 srcpeer = peer(ui, peeropts, source)
271 273 else:
272 274 srcpeer = source.peer() # in case we were called with a localrepo
273 275 branch = (None, branch or [])
274 276 origsource = source = srcpeer.url()
275 277 rev, checkout = addbranchrevs(srcpeer, srcpeer, branch, rev)
276 278
277 279 if dest is None:
278 280 dest = defaultdest(source)
279 281 ui.status(_("destination directory: %s\n") % dest)
280 282 else:
281 283 dest = ui.expandpath(dest)
282 284
283 285 dest = util.urllocalpath(dest)
284 286 source = util.urllocalpath(source)
285 287
286 288 if not dest:
287 289 raise util.Abort(_("empty destination path is not valid"))
288 290 if os.path.exists(dest):
289 291 if not os.path.isdir(dest):
290 292 raise util.Abort(_("destination '%s' already exists") % dest)
291 293 elif os.listdir(dest):
292 294 raise util.Abort(_("destination '%s' is not empty") % dest)
293 295
294 296 srclock = destlock = cleandir = None
295 297 srcrepo = srcpeer.local()
296 298 try:
297 299 abspath = origsource
298 300 if islocal(origsource):
299 301 abspath = os.path.abspath(util.urllocalpath(origsource))
300 302
301 303 if islocal(dest):
302 304 cleandir = dest
303 305
304 306 copy = False
305 307 if (srcrepo and srcrepo.cancopy() and islocal(dest)
306 308 and not phases.hassecret(srcrepo)):
307 309 copy = not pull and not rev
308 310
309 311 if copy:
310 312 try:
311 313 # we use a lock here because if we race with commit, we
312 314 # can end up with extra data in the cloned revlogs that's
313 315 # not pointed to by changesets, thus causing verify to
314 316 # fail
315 317 srclock = srcrepo.lock(wait=False)
316 318 except error.LockError:
317 319 copy = False
318 320
319 321 if copy:
320 322 srcrepo.hook('preoutgoing', throw=True, source='clone')
321 323 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
322 324 if not os.path.exists(dest):
323 325 os.mkdir(dest)
324 326 else:
325 327 # only clean up directories we create ourselves
326 328 cleandir = hgdir
327 329 try:
328 330 destpath = hgdir
329 331 util.makedir(destpath, notindexed=True)
330 332 except OSError, inst:
331 333 if inst.errno == errno.EEXIST:
332 334 cleandir = None
333 335 raise util.Abort(_("destination '%s' already exists")
334 336 % dest)
335 337 raise
336 338
337 339 destlock = copystore(ui, srcrepo, destpath)
338 340
339 341 # Recomputing branch cache might be slow on big repos,
340 342 # so just copy it
341 343 dstcachedir = os.path.join(destpath, 'cache')
342 344 srcbranchcache = srcrepo.sjoin('cache/branch2')
343 345 dstbranchcache = os.path.join(dstcachedir, 'branch2')
344 346 if os.path.exists(srcbranchcache):
345 347 if not os.path.exists(dstcachedir):
346 348 os.mkdir(dstcachedir)
347 349 util.copyfile(srcbranchcache, dstbranchcache)
348 350
349 351 # we need to re-init the repo after manually copying the data
350 352 # into it
351 353 destpeer = peer(srcrepo, peeropts, dest)
352 354 srcrepo.hook('outgoing', source='clone',
353 355 node=node.hex(node.nullid))
354 356 else:
355 357 try:
356 358 destpeer = peer(srcrepo or ui, peeropts, dest, create=True)
357 359 # only pass ui when no srcrepo
358 360 except OSError, inst:
359 361 if inst.errno == errno.EEXIST:
360 362 cleandir = None
361 363 raise util.Abort(_("destination '%s' already exists")
362 364 % dest)
363 365 raise
364 366
365 367 revs = None
366 368 if rev:
367 369 if not srcpeer.capable('lookup'):
368 370 raise util.Abort(_("src repository does not support "
369 371 "revision lookup and so doesn't "
370 372 "support clone by revision"))
371 373 revs = [srcpeer.lookup(r) for r in rev]
372 374 checkout = revs[0]
373 375 if destpeer.local():
374 376 destpeer.local().clone(srcpeer, heads=revs, stream=stream)
375 377 elif srcrepo:
376 378 srcrepo.push(destpeer, revs=revs)
377 379 else:
378 380 raise util.Abort(_("clone from remote to remote not supported"))
379 381
380 382 cleandir = None
381 383
382 384 # clone all bookmarks except divergent ones
383 385 destrepo = destpeer.local()
384 386 if destrepo and srcpeer.capable("pushkey"):
385 387 rb = srcpeer.listkeys('bookmarks')
386 388 marks = destrepo._bookmarks
387 389 for k, n in rb.iteritems():
388 390 try:
389 391 m = destrepo.lookup(n)
390 392 marks[k] = m
391 393 except error.RepoLookupError:
392 394 pass
393 395 if rb:
394 396 marks.write()
395 397 elif srcrepo and destpeer.capable("pushkey"):
396 398 for k, n in srcrepo._bookmarks.iteritems():
397 399 destpeer.pushkey('bookmarks', k, '', hex(n))
398 400
399 401 if destrepo:
400 402 fp = destrepo.opener("hgrc", "w", text=True)
401 403 fp.write("[paths]\n")
402 404 u = util.url(abspath)
403 405 u.passwd = None
404 406 defaulturl = str(u)
405 407 fp.write("default = %s\n" % defaulturl)
406 408 fp.close()
407 409
408 410 destrepo.ui.setconfig('paths', 'default', defaulturl)
409 411
410 412 if update:
411 413 if update is not True:
412 414 checkout = srcpeer.lookup(update)
413 415 uprev = None
414 416 status = None
415 417 if checkout is not None:
416 418 try:
417 419 uprev = destrepo.lookup(checkout)
418 420 except error.RepoLookupError:
419 421 pass
420 422 if uprev is None:
421 423 try:
422 424 uprev = destrepo._bookmarks['@']
423 425 update = '@'
424 426 bn = destrepo[uprev].branch()
425 427 if bn == 'default':
426 428 status = _("updating to bookmark @\n")
427 429 else:
428 430 status = _("updating to bookmark @ on branch %s\n"
429 431 % bn)
430 432 except KeyError:
431 433 try:
432 434 uprev = destrepo.branchtip('default')
433 435 except error.RepoLookupError:
434 436 uprev = destrepo.lookup('tip')
435 437 if not status:
436 438 bn = destrepo[uprev].branch()
437 439 status = _("updating to branch %s\n") % bn
438 440 destrepo.ui.status(status)
439 441 _update(destrepo, uprev)
440 442 if update in destrepo._bookmarks:
441 443 bookmarks.setcurrent(destrepo, update)
442 444 finally:
443 445 release(srclock, destlock)
444 446 if cleandir is not None:
445 447 shutil.rmtree(cleandir, True)
446 448 if srcpeer is not None:
447 449 srcpeer.close()
448 450 return srcpeer, destpeer
449 451
450 452 def _showstats(repo, stats):
451 453 repo.ui.status(_("%d files updated, %d files merged, "
452 454 "%d files removed, %d files unresolved\n") % stats)
453 455
454 456 def updaterepo(repo, node, overwrite):
455 457 """Update the working directory to node.
456 458
457 459 When overwrite is set, changes are clobbered, merged else
458 460
459 461 returns stats (see pydoc mercurial.merge.applyupdates)"""
460 462 return mergemod.update(repo, node, False, overwrite, None)
461 463
462 464 def update(repo, node):
463 465 """update the working directory to node, merging linear changes"""
464 466 stats = updaterepo(repo, node, False)
465 467 _showstats(repo, stats)
466 468 if stats[3]:
467 469 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
468 470 return stats[3] > 0
469 471
470 472 # naming conflict in clone()
471 473 _update = update
472 474
473 475 def clean(repo, node, show_stats=True):
474 476 """forcibly switch the working directory to node, clobbering changes"""
475 477 stats = updaterepo(repo, node, True)
476 478 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
477 479 if show_stats:
478 480 _showstats(repo, stats)
479 481 return stats[3] > 0
480 482
481 483 def merge(repo, node, force=None, remind=True):
482 484 """Branch merge with node, resolving changes. Return true if any
483 485 unresolved conflicts."""
484 486 stats = mergemod.update(repo, node, True, force, False)
485 487 _showstats(repo, stats)
486 488 if stats[3]:
487 489 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
488 490 "or 'hg update -C .' to abandon\n"))
489 491 elif remind:
490 492 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
491 493 return stats[3] > 0
492 494
493 495 def _incoming(displaychlist, subreporecurse, ui, repo, source,
494 496 opts, buffered=False):
495 497 """
496 498 Helper for incoming / gincoming.
497 499 displaychlist gets called with
498 500 (remoterepo, incomingchangesetlist, displayer) parameters,
499 501 and is supposed to contain only code that can't be unified.
500 502 """
501 503 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
502 504 other = peer(repo, opts, source)
503 505 ui.status(_('comparing with %s\n') % util.hidepassword(source))
504 506 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
505 507
506 508 if revs:
507 509 revs = [other.lookup(rev) for rev in revs]
508 510 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
509 511 revs, opts["bundle"], opts["force"])
510 512 try:
511 513 if not chlist:
512 514 ui.status(_("no changes found\n"))
513 515 return subreporecurse()
514 516
515 517 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
516 518 displaychlist(other, chlist, displayer)
517 519 displayer.close()
518 520 finally:
519 521 cleanupfn()
520 522 subreporecurse()
521 523 return 0 # exit code is zero since we found incoming changes
522 524
523 525 def incoming(ui, repo, source, opts):
524 526 def subreporecurse():
525 527 ret = 1
526 528 if opts.get('subrepos'):
527 529 ctx = repo[None]
528 530 for subpath in sorted(ctx.substate):
529 531 sub = ctx.sub(subpath)
530 532 ret = min(ret, sub.incoming(ui, source, opts))
531 533 return ret
532 534
533 535 def display(other, chlist, displayer):
534 536 limit = cmdutil.loglimit(opts)
535 537 if opts.get('newest_first'):
536 538 chlist.reverse()
537 539 count = 0
538 540 for n in chlist:
539 541 if limit is not None and count >= limit:
540 542 break
541 543 parents = [p for p in other.changelog.parents(n) if p != nullid]
542 544 if opts.get('no_merges') and len(parents) == 2:
543 545 continue
544 546 count += 1
545 547 displayer.show(other[n])
546 548 return _incoming(display, subreporecurse, ui, repo, source, opts)
547 549
548 550 def _outgoing(ui, repo, dest, opts):
549 551 dest = ui.expandpath(dest or 'default-push', dest or 'default')
550 552 dest, branches = parseurl(dest, opts.get('branch'))
551 553 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
552 554 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
553 555 if revs:
554 556 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
555 557
556 558 other = peer(repo, opts, dest)
557 559 outgoing = discovery.findcommonoutgoing(repo.unfiltered(), other, revs,
558 560 force=opts.get('force'))
559 561 o = outgoing.missing
560 562 if not o:
561 563 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
562 564 return None
563 565 return o
564 566
565 567 def outgoing(ui, repo, dest, opts):
566 568 def recurse():
567 569 ret = 1
568 570 if opts.get('subrepos'):
569 571 ctx = repo[None]
570 572 for subpath in sorted(ctx.substate):
571 573 sub = ctx.sub(subpath)
572 574 ret = min(ret, sub.outgoing(ui, dest, opts))
573 575 return ret
574 576
575 577 limit = cmdutil.loglimit(opts)
576 578 o = _outgoing(ui, repo, dest, opts)
577 579 if o is None:
578 580 return recurse()
579 581
580 582 if opts.get('newest_first'):
581 583 o.reverse()
582 584 displayer = cmdutil.show_changeset(ui, repo, opts)
583 585 count = 0
584 586 for n in o:
585 587 if limit is not None and count >= limit:
586 588 break
587 589 parents = [p for p in repo.changelog.parents(n) if p != nullid]
588 590 if opts.get('no_merges') and len(parents) == 2:
589 591 continue
590 592 count += 1
591 593 displayer.show(repo[n])
592 594 displayer.close()
593 595 recurse()
594 596 return 0 # exit code is zero since we found outgoing changes
595 597
596 598 def revert(repo, node, choose):
597 599 """revert changes to revision in node without updating dirstate"""
598 600 return mergemod.update(repo, node, False, True, choose)[3] > 0
599 601
600 602 def verify(repo):
601 603 """verify the consistency of a repository"""
602 604 return verifymod.verify(repo)
603 605
604 606 def remoteui(src, opts):
605 607 'build a remote ui from ui or repo and opts'
606 608 if util.safehasattr(src, 'baseui'): # looks like a repository
607 609 dst = src.baseui.copy() # drop repo-specific config
608 610 src = src.ui # copy target options from repo
609 611 else: # assume it's a global ui object
610 612 dst = src.copy() # keep all global options
611 613
612 614 # copy ssh-specific options
613 615 for o in 'ssh', 'remotecmd':
614 616 v = opts.get(o) or src.config('ui', o)
615 617 if v:
616 618 dst.setconfig("ui", o, v)
617 619
618 620 # copy bundle-specific options
619 621 r = src.config('bundle', 'mainreporoot')
620 622 if r:
621 623 dst.setconfig('bundle', 'mainreporoot', r)
622 624
623 625 # copy selected local settings to the remote ui
624 626 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
625 627 for key, val in src.configitems(sect):
626 628 dst.setconfig(sect, key, val)
627 629 v = src.config('web', 'cacerts')
628 630 if v:
629 631 dst.setconfig('web', 'cacerts', util.expandpath(v))
630 632
631 633 return dst
@@ -1,623 +1,637 b''
1 1 Prepare repo a:
2 2
3 3 $ hg init a
4 4 $ cd a
5 5 $ echo a > a
6 6 $ hg add a
7 7 $ hg commit -m test
8 8 $ echo first line > b
9 9 $ hg add b
10 10
11 11 Create a non-inlined filelog:
12 12
13 13 $ python -c 'file("data1", "wb").write("".join("%s\n" % x for x in range(10000)))'
14 14 $ for j in 0 1 2 3 4 5 6 7 8 9; do
15 15 > cat data1 >> b
16 16 > hg commit -m test
17 17 > done
18 18
19 19 List files in store/data (should show a 'b.d'):
20 20
21 21 $ for i in .hg/store/data/*; do
22 22 > echo $i
23 23 > done
24 24 .hg/store/data/a.i
25 25 .hg/store/data/b.d
26 26 .hg/store/data/b.i
27 27
28 28 Default operation:
29 29
30 30 $ hg clone . ../b
31 31 updating to branch default
32 32 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
33 33 $ cd ../b
34 34 $ cat a
35 35 a
36 36 $ hg verify
37 37 checking changesets
38 38 checking manifests
39 39 crosschecking files in changesets and manifests
40 40 checking files
41 41 2 files, 11 changesets, 11 total revisions
42 42
43 43 Invalid dest '' must abort:
44 44
45 45 $ hg clone . ''
46 46 abort: empty destination path is not valid
47 47 [255]
48 48
49 49 No update, with debug option:
50 50
51 51 #if hardlink
52 52 $ hg --debug clone -U . ../c
53 53 linked 8 files
54 54 listing keys for "bookmarks"
55 55 #else
56 56 $ hg --debug clone -U . ../c
57 57 copied 8 files
58 58 listing keys for "bookmarks"
59 59 #endif
60 60 $ cd ../c
61 61 $ cat a 2>/dev/null || echo "a not present"
62 62 a not present
63 63 $ hg verify
64 64 checking changesets
65 65 checking manifests
66 66 crosschecking files in changesets and manifests
67 67 checking files
68 68 2 files, 11 changesets, 11 total revisions
69 69
70 70 Default destination:
71 71
72 72 $ mkdir ../d
73 73 $ cd ../d
74 74 $ hg clone ../a
75 75 destination directory: a
76 76 updating to branch default
77 77 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 78 $ cd a
79 79 $ hg cat a
80 80 a
81 81 $ cd ../..
82 82
83 83 Check that we drop the 'file:' from the path before writing the .hgrc:
84 84
85 85 $ hg clone file:a e
86 86 updating to branch default
87 87 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
88 88 $ grep 'file:' e/.hg/hgrc
89 89 [1]
90 90
91 91 Check that path aliases are expanded:
92 92
93 93 $ hg clone -q -U --config 'paths.foobar=a#0' foobar f
94 94 $ hg -R f showconfig paths.default
95 95 $TESTTMP/a#0 (glob)
96 96
97 97 Use --pull:
98 98
99 99 $ hg clone --pull a g
100 100 requesting all changes
101 101 adding changesets
102 102 adding manifests
103 103 adding file changes
104 104 added 11 changesets with 11 changes to 2 files
105 105 updating to branch default
106 106 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
107 107 $ hg -R g verify
108 108 checking changesets
109 109 checking manifests
110 110 crosschecking files in changesets and manifests
111 111 checking files
112 112 2 files, 11 changesets, 11 total revisions
113 113
114 114 Invalid dest '' with --pull must abort (issue2528):
115 115
116 116 $ hg clone --pull a ''
117 117 abort: empty destination path is not valid
118 118 [255]
119 119
120 120 Clone to '.':
121 121
122 122 $ mkdir h
123 123 $ cd h
124 124 $ hg clone ../a .
125 125 updating to branch default
126 126 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
127 127 $ cd ..
128 128
129 129
130 130 *** Tests for option -u ***
131 131
132 132 Adding some more history to repo a:
133 133
134 134 $ cd a
135 135 $ hg tag ref1
136 136 $ echo the quick brown fox >a
137 137 $ hg ci -m "hacked default"
138 138 $ hg up ref1
139 139 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
140 140 $ hg branch stable
141 141 marked working directory as branch stable
142 142 (branches are permanent and global, did you want a bookmark?)
143 143 $ echo some text >a
144 144 $ hg ci -m "starting branch stable"
145 145 $ hg tag ref2
146 146 $ echo some more text >a
147 147 $ hg ci -m "another change for branch stable"
148 148 $ hg up ref2
149 149 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
150 150 $ hg parents
151 151 changeset: 13:e8ece76546a6
152 152 branch: stable
153 153 tag: ref2
154 154 parent: 10:a7949464abda
155 155 user: test
156 156 date: Thu Jan 01 00:00:00 1970 +0000
157 157 summary: starting branch stable
158 158
159 159
160 160 Repo a has two heads:
161 161
162 162 $ hg heads
163 163 changeset: 15:0aae7cf88f0d
164 164 branch: stable
165 165 tag: tip
166 166 user: test
167 167 date: Thu Jan 01 00:00:00 1970 +0000
168 168 summary: another change for branch stable
169 169
170 170 changeset: 12:f21241060d6a
171 171 user: test
172 172 date: Thu Jan 01 00:00:00 1970 +0000
173 173 summary: hacked default
174 174
175 175
176 176 $ cd ..
177 177
178 178
179 179 Testing --noupdate with --updaterev (must abort):
180 180
181 181 $ hg clone --noupdate --updaterev 1 a ua
182 182 abort: cannot specify both --noupdate and --updaterev
183 183 [255]
184 184
185 185
186 186 Testing clone -u:
187 187
188 188 $ hg clone -u . a ua
189 189 updating to branch stable
190 190 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
191 191
192 192 Repo ua has both heads:
193 193
194 194 $ hg -R ua heads
195 195 changeset: 15:0aae7cf88f0d
196 196 branch: stable
197 197 tag: tip
198 198 user: test
199 199 date: Thu Jan 01 00:00:00 1970 +0000
200 200 summary: another change for branch stable
201 201
202 202 changeset: 12:f21241060d6a
203 203 user: test
204 204 date: Thu Jan 01 00:00:00 1970 +0000
205 205 summary: hacked default
206 206
207 207
208 208 Same revision checked out in repo a and ua:
209 209
210 210 $ hg -R a parents --template "{node|short}\n"
211 211 e8ece76546a6
212 212 $ hg -R ua parents --template "{node|short}\n"
213 213 e8ece76546a6
214 214
215 215 $ rm -r ua
216 216
217 217
218 218 Testing clone --pull -u:
219 219
220 220 $ hg clone --pull -u . a ua
221 221 requesting all changes
222 222 adding changesets
223 223 adding manifests
224 224 adding file changes
225 225 added 16 changesets with 16 changes to 3 files (+1 heads)
226 226 updating to branch stable
227 227 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
228 228
229 229 Repo ua has both heads:
230 230
231 231 $ hg -R ua heads
232 232 changeset: 15:0aae7cf88f0d
233 233 branch: stable
234 234 tag: tip
235 235 user: test
236 236 date: Thu Jan 01 00:00:00 1970 +0000
237 237 summary: another change for branch stable
238 238
239 239 changeset: 12:f21241060d6a
240 240 user: test
241 241 date: Thu Jan 01 00:00:00 1970 +0000
242 242 summary: hacked default
243 243
244 244
245 245 Same revision checked out in repo a and ua:
246 246
247 247 $ hg -R a parents --template "{node|short}\n"
248 248 e8ece76546a6
249 249 $ hg -R ua parents --template "{node|short}\n"
250 250 e8ece76546a6
251 251
252 252 $ rm -r ua
253 253
254 254
255 255 Testing clone -u <branch>:
256 256
257 257 $ hg clone -u stable a ua
258 258 updating to branch stable
259 259 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
260 260
261 261 Repo ua has both heads:
262 262
263 263 $ hg -R ua heads
264 264 changeset: 15:0aae7cf88f0d
265 265 branch: stable
266 266 tag: tip
267 267 user: test
268 268 date: Thu Jan 01 00:00:00 1970 +0000
269 269 summary: another change for branch stable
270 270
271 271 changeset: 12:f21241060d6a
272 272 user: test
273 273 date: Thu Jan 01 00:00:00 1970 +0000
274 274 summary: hacked default
275 275
276 276
277 277 Branch 'stable' is checked out:
278 278
279 279 $ hg -R ua parents
280 280 changeset: 15:0aae7cf88f0d
281 281 branch: stable
282 282 tag: tip
283 283 user: test
284 284 date: Thu Jan 01 00:00:00 1970 +0000
285 285 summary: another change for branch stable
286 286
287 287
288 288 $ rm -r ua
289 289
290 290
291 291 Testing default checkout:
292 292
293 293 $ hg clone a ua
294 294 updating to branch default
295 295 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
296 296
297 297 Repo ua has both heads:
298 298
299 299 $ hg -R ua heads
300 300 changeset: 15:0aae7cf88f0d
301 301 branch: stable
302 302 tag: tip
303 303 user: test
304 304 date: Thu Jan 01 00:00:00 1970 +0000
305 305 summary: another change for branch stable
306 306
307 307 changeset: 12:f21241060d6a
308 308 user: test
309 309 date: Thu Jan 01 00:00:00 1970 +0000
310 310 summary: hacked default
311 311
312 312
313 313 Branch 'default' is checked out:
314 314
315 315 $ hg -R ua parents
316 316 changeset: 12:f21241060d6a
317 317 user: test
318 318 date: Thu Jan 01 00:00:00 1970 +0000
319 319 summary: hacked default
320 320
321 321 Test clone with a branch named "@" (issue3677)
322 322
323 323 $ hg -R ua branch @
324 324 marked working directory as branch @
325 325 (branches are permanent and global, did you want a bookmark?)
326 326 $ hg -R ua commit -m 'created branch @'
327 327 $ hg clone ua atbranch
328 328 updating to branch default
329 329 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
330 330 $ hg -R atbranch heads
331 331 changeset: 16:798b6d97153e
332 332 branch: @
333 333 tag: tip
334 334 parent: 12:f21241060d6a
335 335 user: test
336 336 date: Thu Jan 01 00:00:00 1970 +0000
337 337 summary: created branch @
338 338
339 339 changeset: 15:0aae7cf88f0d
340 340 branch: stable
341 341 user: test
342 342 date: Thu Jan 01 00:00:00 1970 +0000
343 343 summary: another change for branch stable
344 344
345 345 changeset: 12:f21241060d6a
346 346 user: test
347 347 date: Thu Jan 01 00:00:00 1970 +0000
348 348 summary: hacked default
349 349
350 350 $ hg -R atbranch parents
351 351 changeset: 12:f21241060d6a
352 352 user: test
353 353 date: Thu Jan 01 00:00:00 1970 +0000
354 354 summary: hacked default
355 355
356 356
357 357 $ rm -r ua atbranch
358 358
359 359
360 360 Testing #<branch>:
361 361
362 362 $ hg clone -u . a#stable ua
363 363 adding changesets
364 364 adding manifests
365 365 adding file changes
366 366 added 14 changesets with 14 changes to 3 files
367 367 updating to branch stable
368 368 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
369 369
370 370 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
371 371
372 372 $ hg -R ua heads
373 373 changeset: 13:0aae7cf88f0d
374 374 branch: stable
375 375 tag: tip
376 376 user: test
377 377 date: Thu Jan 01 00:00:00 1970 +0000
378 378 summary: another change for branch stable
379 379
380 380 changeset: 10:a7949464abda
381 381 user: test
382 382 date: Thu Jan 01 00:00:00 1970 +0000
383 383 summary: test
384 384
385 385
386 386 Same revision checked out in repo a and ua:
387 387
388 388 $ hg -R a parents --template "{node|short}\n"
389 389 e8ece76546a6
390 390 $ hg -R ua parents --template "{node|short}\n"
391 391 e8ece76546a6
392 392
393 393 $ rm -r ua
394 394
395 395
396 396 Testing -u -r <branch>:
397 397
398 398 $ hg clone -u . -r stable a ua
399 399 adding changesets
400 400 adding manifests
401 401 adding file changes
402 402 added 14 changesets with 14 changes to 3 files
403 403 updating to branch stable
404 404 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
405 405
406 406 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
407 407
408 408 $ hg -R ua heads
409 409 changeset: 13:0aae7cf88f0d
410 410 branch: stable
411 411 tag: tip
412 412 user: test
413 413 date: Thu Jan 01 00:00:00 1970 +0000
414 414 summary: another change for branch stable
415 415
416 416 changeset: 10:a7949464abda
417 417 user: test
418 418 date: Thu Jan 01 00:00:00 1970 +0000
419 419 summary: test
420 420
421 421
422 422 Same revision checked out in repo a and ua:
423 423
424 424 $ hg -R a parents --template "{node|short}\n"
425 425 e8ece76546a6
426 426 $ hg -R ua parents --template "{node|short}\n"
427 427 e8ece76546a6
428 428
429 429 $ rm -r ua
430 430
431 431
432 432 Testing -r <branch>:
433 433
434 434 $ hg clone -r stable a ua
435 435 adding changesets
436 436 adding manifests
437 437 adding file changes
438 438 added 14 changesets with 14 changes to 3 files
439 439 updating to branch stable
440 440 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
441 441
442 442 Repo ua has branch 'stable' and 'default' (was changed in fd511e9eeea6):
443 443
444 444 $ hg -R ua heads
445 445 changeset: 13:0aae7cf88f0d
446 446 branch: stable
447 447 tag: tip
448 448 user: test
449 449 date: Thu Jan 01 00:00:00 1970 +0000
450 450 summary: another change for branch stable
451 451
452 452 changeset: 10:a7949464abda
453 453 user: test
454 454 date: Thu Jan 01 00:00:00 1970 +0000
455 455 summary: test
456 456
457 457
458 458 Branch 'stable' is checked out:
459 459
460 460 $ hg -R ua parents
461 461 changeset: 13:0aae7cf88f0d
462 462 branch: stable
463 463 tag: tip
464 464 user: test
465 465 date: Thu Jan 01 00:00:00 1970 +0000
466 466 summary: another change for branch stable
467 467
468 468
469 469 $ rm -r ua
470 470
471 471
472 472 Issue2267: Error in 1.6 hg.py: TypeError: 'NoneType' object is not
473 473 iterable in addbranchrevs()
474 474
475 475 $ cat <<EOF > simpleclone.py
476 476 > from mercurial import ui, hg
477 477 > myui = ui.ui()
478 478 > repo = hg.repository(myui, 'a')
479 479 > hg.clone(myui, {}, repo, dest="ua")
480 480 > EOF
481 481
482 482 $ python simpleclone.py
483 483 updating to branch default
484 484 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
485 485
486 486 $ rm -r ua
487 487
488 488 $ cat <<EOF > branchclone.py
489 489 > from mercurial import ui, hg, extensions
490 490 > myui = ui.ui()
491 491 > extensions.loadall(myui)
492 492 > repo = hg.repository(myui, 'a')
493 493 > hg.clone(myui, {}, repo, dest="ua", branch=["stable",])
494 494 > EOF
495 495
496 496 $ python branchclone.py
497 497 adding changesets
498 498 adding manifests
499 499 adding file changes
500 500 added 14 changesets with 14 changes to 3 files
501 501 updating to branch stable
502 502 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
503 503 $ rm -r ua
504 504
505 505
506 506 Test clone with special '@' bookmark:
507 507 $ cd a
508 508 $ hg bookmark -r a7949464abda @ # branch point of stable from default
509 509 $ hg clone . ../i
510 510 updating to bookmark @
511 511 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
512 512 $ hg id -i ../i
513 513 a7949464abda
514 514 $ rm -r ../i
515 515
516 516 $ hg bookmark -f -r stable @
517 517 $ hg bookmarks
518 518 @ 15:0aae7cf88f0d
519 519 $ hg clone . ../i
520 520 updating to bookmark @ on branch stable
521 521 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
522 522 $ hg id -i ../i
523 523 0aae7cf88f0d
524 524 $ cd "$TESTTMP"
525 525
526 526
527 527 Testing failures:
528 528
529 529 $ mkdir fail
530 530 $ cd fail
531 531
532 532 No local source
533 533
534 534 $ hg clone a b
535 535 abort: repository a not found!
536 536 [255]
537 537
538 538 No remote source
539 539
540 540 $ hg clone http://127.0.0.1:3121/a b
541 541 abort: error: *refused* (glob)
542 542 [255]
543 543 $ rm -rf b # work around bug with http clone
544 544
545 545
546 546 #if unix-permissions no-root
547 547
548 548 Inaccessible source
549 549
550 550 $ mkdir a
551 551 $ chmod 000 a
552 552 $ hg clone a b
553 553 abort: repository a not found!
554 554 [255]
555 555
556 556 Inaccessible destination
557 557
558 558 $ hg init b
559 559 $ cd b
560 560 $ hg clone . ../a
561 561 abort: Permission denied: '../a'
562 562 [255]
563 563 $ cd ..
564 564 $ chmod 700 a
565 565 $ rm -r a b
566 566
567 567 #endif
568 568
569 569
570 570 #if fifo
571 571
572 572 Source of wrong type
573 573
574 574 $ mkfifo a
575 575 $ hg clone a b
576 576 abort: repository a not found!
577 577 [255]
578 578 $ rm a
579 579
580 580 #endif
581 581
582 582 Default destination, same directory
583 583
584 584 $ hg init q
585 585 $ hg clone q
586 586 destination directory: q
587 587 abort: destination 'q' is not empty
588 588 [255]
589 589
590 590 destination directory not empty
591 591
592 592 $ mkdir a
593 593 $ echo stuff > a/a
594 594 $ hg clone q a
595 595 abort: destination 'a' is not empty
596 596 [255]
597 597
598 598
599 599 #if unix-permissions no-root
600 600
601 601 leave existing directory in place after clone failure
602 602
603 603 $ hg init c
604 604 $ cd c
605 605 $ echo c > c
606 606 $ hg commit -A -m test
607 607 adding c
608 608 $ chmod -rx .hg/store/data
609 609 $ cd ..
610 610 $ mkdir d
611 611 $ hg clone c d 2> err
612 612 [255]
613 613 $ test -d d
614 614 $ test -d d/.hg
615 615 [1]
616 616
617 617 re-enable perm to allow deletion
618 618
619 619 $ chmod +rx c/.hg/store/data
620 620
621 621 #endif
622 622
623 623 $ cd ..
624
625 Test clone from the repository in (emulated) revlog format 0 (issue4203):
626
627 $ mkdir issue4203
628 $ mkdir -p src/.hg
629 $ echo foo > src/foo
630 $ hg -R src add src/foo
631 $ hg -R src commit -m '#0'
632 $ hg -R src log -q
633 0:e1bab28bca43
634 $ hg clone -U -q src dst
635 $ hg -R dst log -q
636 0:e1bab28bca43
637 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now