##// END OF EJS Templates
clone: fix updaterev to update to latest branch changeset (issue4528)...
liscju -
r26103:30be3aeb default
parent child Browse files
Show More
@@ -1,822 +1,825 b''
1 # hg.py - repository classes for mercurial
1 # hg.py - repository classes for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from __future__ import absolute_import
9 from __future__ import absolute_import
10
10
11 import errno
11 import errno
12 import os
12 import os
13 import shutil
13 import shutil
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import nullid
16 from .node import nullid
17
17
18 from . import (
18 from . import (
19 bookmarks,
19 bookmarks,
20 bundlerepo,
20 bundlerepo,
21 cmdutil,
21 cmdutil,
22 discovery,
22 discovery,
23 error,
23 error,
24 exchange,
24 exchange,
25 extensions,
25 extensions,
26 httppeer,
26 httppeer,
27 localrepo,
27 localrepo,
28 lock,
28 lock,
29 merge as mergemod,
29 merge as mergemod,
30 node,
30 node,
31 phases,
31 phases,
32 repoview,
32 repoview,
33 scmutil,
33 scmutil,
34 sshpeer,
34 sshpeer,
35 statichttprepo,
35 statichttprepo,
36 ui as uimod,
36 ui as uimod,
37 unionrepo,
37 unionrepo,
38 url,
38 url,
39 util,
39 util,
40 verify as verifymod,
40 verify as verifymod,
41 )
41 )
42
42
43 release = lock.release
43 release = lock.release
44
44
45 def _local(path):
45 def _local(path):
46 path = util.expandpath(util.urllocalpath(path))
46 path = util.expandpath(util.urllocalpath(path))
47 return (os.path.isfile(path) and bundlerepo or localrepo)
47 return (os.path.isfile(path) and bundlerepo or localrepo)
48
48
49 def addbranchrevs(lrepo, other, branches, revs):
49 def addbranchrevs(lrepo, other, branches, revs):
50 peer = other.peer() # a courtesy to callers using a localrepo for other
50 peer = other.peer() # a courtesy to callers using a localrepo for other
51 hashbranch, branches = branches
51 hashbranch, branches = branches
52 if not hashbranch and not branches:
52 if not hashbranch and not branches:
53 x = revs or None
53 x = revs or None
54 if util.safehasattr(revs, 'first'):
54 if util.safehasattr(revs, 'first'):
55 y = revs.first()
55 y = revs.first()
56 elif revs:
56 elif revs:
57 y = revs[0]
57 y = revs[0]
58 else:
58 else:
59 y = None
59 y = None
60 return x, y
60 return x, y
61 if revs:
61 if revs:
62 revs = list(revs)
62 revs = list(revs)
63 else:
63 else:
64 revs = []
64 revs = []
65
65
66 if not peer.capable('branchmap'):
66 if not peer.capable('branchmap'):
67 if branches:
67 if branches:
68 raise util.Abort(_("remote branch lookup not supported"))
68 raise util.Abort(_("remote branch lookup not supported"))
69 revs.append(hashbranch)
69 revs.append(hashbranch)
70 return revs, revs[0]
70 return revs, revs[0]
71 branchmap = peer.branchmap()
71 branchmap = peer.branchmap()
72
72
73 def primary(branch):
73 def primary(branch):
74 if branch == '.':
74 if branch == '.':
75 if not lrepo:
75 if not lrepo:
76 raise util.Abort(_("dirstate branch not accessible"))
76 raise util.Abort(_("dirstate branch not accessible"))
77 branch = lrepo.dirstate.branch()
77 branch = lrepo.dirstate.branch()
78 if branch in branchmap:
78 if branch in branchmap:
79 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
79 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
80 return True
80 return True
81 else:
81 else:
82 return False
82 return False
83
83
84 for branch in branches:
84 for branch in branches:
85 if not primary(branch):
85 if not primary(branch):
86 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
86 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
87 if hashbranch:
87 if hashbranch:
88 if not primary(hashbranch):
88 if not primary(hashbranch):
89 revs.append(hashbranch)
89 revs.append(hashbranch)
90 return revs, revs[0]
90 return revs, revs[0]
91
91
92 def parseurl(path, branches=None):
92 def parseurl(path, branches=None):
93 '''parse url#branch, returning (url, (branch, branches))'''
93 '''parse url#branch, returning (url, (branch, branches))'''
94
94
95 u = util.url(path)
95 u = util.url(path)
96 branch = None
96 branch = None
97 if u.fragment:
97 if u.fragment:
98 branch = u.fragment
98 branch = u.fragment
99 u.fragment = None
99 u.fragment = None
100 return str(u), (branch, branches or [])
100 return str(u), (branch, branches or [])
101
101
102 schemes = {
102 schemes = {
103 'bundle': bundlerepo,
103 'bundle': bundlerepo,
104 'union': unionrepo,
104 'union': unionrepo,
105 'file': _local,
105 'file': _local,
106 'http': httppeer,
106 'http': httppeer,
107 'https': httppeer,
107 'https': httppeer,
108 'ssh': sshpeer,
108 'ssh': sshpeer,
109 'static-http': statichttprepo,
109 'static-http': statichttprepo,
110 }
110 }
111
111
112 def _peerlookup(path):
112 def _peerlookup(path):
113 u = util.url(path)
113 u = util.url(path)
114 scheme = u.scheme or 'file'
114 scheme = u.scheme or 'file'
115 thing = schemes.get(scheme) or schemes['file']
115 thing = schemes.get(scheme) or schemes['file']
116 try:
116 try:
117 return thing(path)
117 return thing(path)
118 except TypeError:
118 except TypeError:
119 # we can't test callable(thing) because 'thing' can be an unloaded
119 # we can't test callable(thing) because 'thing' can be an unloaded
120 # module that implements __call__
120 # module that implements __call__
121 if not util.safehasattr(thing, 'instance'):
121 if not util.safehasattr(thing, 'instance'):
122 raise
122 raise
123 return thing
123 return thing
124
124
125 def islocal(repo):
125 def islocal(repo):
126 '''return true if repo (or path pointing to repo) is local'''
126 '''return true if repo (or path pointing to repo) is local'''
127 if isinstance(repo, str):
127 if isinstance(repo, str):
128 try:
128 try:
129 return _peerlookup(repo).islocal(repo)
129 return _peerlookup(repo).islocal(repo)
130 except AttributeError:
130 except AttributeError:
131 return False
131 return False
132 return repo.local()
132 return repo.local()
133
133
134 def openpath(ui, path):
134 def openpath(ui, path):
135 '''open path with open if local, url.open if remote'''
135 '''open path with open if local, url.open if remote'''
136 pathurl = util.url(path, parsequery=False, parsefragment=False)
136 pathurl = util.url(path, parsequery=False, parsefragment=False)
137 if pathurl.islocal():
137 if pathurl.islocal():
138 return util.posixfile(pathurl.localpath(), 'rb')
138 return util.posixfile(pathurl.localpath(), 'rb')
139 else:
139 else:
140 return url.open(ui, path)
140 return url.open(ui, path)
141
141
142 # a list of (ui, repo) functions called for wire peer initialization
142 # a list of (ui, repo) functions called for wire peer initialization
143 wirepeersetupfuncs = []
143 wirepeersetupfuncs = []
144
144
145 def _peerorrepo(ui, path, create=False):
145 def _peerorrepo(ui, path, create=False):
146 """return a repository object for the specified path"""
146 """return a repository object for the specified path"""
147 obj = _peerlookup(path).instance(ui, path, create)
147 obj = _peerlookup(path).instance(ui, path, create)
148 ui = getattr(obj, "ui", ui)
148 ui = getattr(obj, "ui", ui)
149 for name, module in extensions.extensions(ui):
149 for name, module in extensions.extensions(ui):
150 hook = getattr(module, 'reposetup', None)
150 hook = getattr(module, 'reposetup', None)
151 if hook:
151 if hook:
152 hook(ui, obj)
152 hook(ui, obj)
153 if not obj.local():
153 if not obj.local():
154 for f in wirepeersetupfuncs:
154 for f in wirepeersetupfuncs:
155 f(ui, obj)
155 f(ui, obj)
156 return obj
156 return obj
157
157
158 def repository(ui, path='', create=False):
158 def repository(ui, path='', create=False):
159 """return a repository object for the specified path"""
159 """return a repository object for the specified path"""
160 peer = _peerorrepo(ui, path, create)
160 peer = _peerorrepo(ui, path, create)
161 repo = peer.local()
161 repo = peer.local()
162 if not repo:
162 if not repo:
163 raise util.Abort(_("repository '%s' is not local") %
163 raise util.Abort(_("repository '%s' is not local") %
164 (path or peer.url()))
164 (path or peer.url()))
165 return repo.filtered('visible')
165 return repo.filtered('visible')
166
166
167 def peer(uiorrepo, opts, path, create=False):
167 def peer(uiorrepo, opts, path, create=False):
168 '''return a repository peer for the specified path'''
168 '''return a repository peer for the specified path'''
169 rui = remoteui(uiorrepo, opts)
169 rui = remoteui(uiorrepo, opts)
170 return _peerorrepo(rui, path, create).peer()
170 return _peerorrepo(rui, path, create).peer()
171
171
172 def defaultdest(source):
172 def defaultdest(source):
173 '''return default destination of clone if none is given
173 '''return default destination of clone if none is given
174
174
175 >>> defaultdest('foo')
175 >>> defaultdest('foo')
176 'foo'
176 'foo'
177 >>> defaultdest('/foo/bar')
177 >>> defaultdest('/foo/bar')
178 'bar'
178 'bar'
179 >>> defaultdest('/')
179 >>> defaultdest('/')
180 ''
180 ''
181 >>> defaultdest('')
181 >>> defaultdest('')
182 ''
182 ''
183 >>> defaultdest('http://example.org/')
183 >>> defaultdest('http://example.org/')
184 ''
184 ''
185 >>> defaultdest('http://example.org/foo/')
185 >>> defaultdest('http://example.org/foo/')
186 'foo'
186 'foo'
187 '''
187 '''
188 path = util.url(source).path
188 path = util.url(source).path
189 if not path:
189 if not path:
190 return ''
190 return ''
191 return os.path.basename(os.path.normpath(path))
191 return os.path.basename(os.path.normpath(path))
192
192
193 def share(ui, source, dest=None, update=True, bookmarks=True):
193 def share(ui, source, dest=None, update=True, bookmarks=True):
194 '''create a shared repository'''
194 '''create a shared repository'''
195
195
196 if not islocal(source):
196 if not islocal(source):
197 raise util.Abort(_('can only share local repositories'))
197 raise util.Abort(_('can only share local repositories'))
198
198
199 if not dest:
199 if not dest:
200 dest = defaultdest(source)
200 dest = defaultdest(source)
201 else:
201 else:
202 dest = ui.expandpath(dest)
202 dest = ui.expandpath(dest)
203
203
204 if isinstance(source, str):
204 if isinstance(source, str):
205 origsource = ui.expandpath(source)
205 origsource = ui.expandpath(source)
206 source, branches = parseurl(origsource)
206 source, branches = parseurl(origsource)
207 srcrepo = repository(ui, source)
207 srcrepo = repository(ui, source)
208 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
208 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
209 else:
209 else:
210 srcrepo = source.local()
210 srcrepo = source.local()
211 origsource = source = srcrepo.url()
211 origsource = source = srcrepo.url()
212 checkout = None
212 checkout = None
213
213
214 sharedpath = srcrepo.sharedpath # if our source is already sharing
214 sharedpath = srcrepo.sharedpath # if our source is already sharing
215
215
216 destwvfs = scmutil.vfs(dest, realpath=True)
216 destwvfs = scmutil.vfs(dest, realpath=True)
217 destvfs = scmutil.vfs(os.path.join(destwvfs.base, '.hg'), realpath=True)
217 destvfs = scmutil.vfs(os.path.join(destwvfs.base, '.hg'), realpath=True)
218
218
219 if destvfs.lexists():
219 if destvfs.lexists():
220 raise util.Abort(_('destination already exists'))
220 raise util.Abort(_('destination already exists'))
221
221
222 if not destwvfs.isdir():
222 if not destwvfs.isdir():
223 destwvfs.mkdir()
223 destwvfs.mkdir()
224 destvfs.makedir()
224 destvfs.makedir()
225
225
226 requirements = ''
226 requirements = ''
227 try:
227 try:
228 requirements = srcrepo.vfs.read('requires')
228 requirements = srcrepo.vfs.read('requires')
229 except IOError as inst:
229 except IOError as inst:
230 if inst.errno != errno.ENOENT:
230 if inst.errno != errno.ENOENT:
231 raise
231 raise
232
232
233 requirements += 'shared\n'
233 requirements += 'shared\n'
234 destvfs.write('requires', requirements)
234 destvfs.write('requires', requirements)
235 destvfs.write('sharedpath', sharedpath)
235 destvfs.write('sharedpath', sharedpath)
236
236
237 r = repository(ui, destwvfs.base)
237 r = repository(ui, destwvfs.base)
238
238
239 default = srcrepo.ui.config('paths', 'default')
239 default = srcrepo.ui.config('paths', 'default')
240 if default:
240 if default:
241 fp = r.vfs("hgrc", "w", text=True)
241 fp = r.vfs("hgrc", "w", text=True)
242 fp.write("[paths]\n")
242 fp.write("[paths]\n")
243 fp.write("default = %s\n" % default)
243 fp.write("default = %s\n" % default)
244 fp.close()
244 fp.close()
245
245
246 if update:
246 if update:
247 r.ui.status(_("updating working directory\n"))
247 r.ui.status(_("updating working directory\n"))
248 if update is not True:
248 if update is not True:
249 checkout = update
249 checkout = update
250 for test in (checkout, 'default', 'tip'):
250 for test in (checkout, 'default', 'tip'):
251 if test is None:
251 if test is None:
252 continue
252 continue
253 try:
253 try:
254 uprev = r.lookup(test)
254 uprev = r.lookup(test)
255 break
255 break
256 except error.RepoLookupError:
256 except error.RepoLookupError:
257 continue
257 continue
258 _update(r, uprev)
258 _update(r, uprev)
259
259
260 if bookmarks:
260 if bookmarks:
261 fp = r.vfs('shared', 'w')
261 fp = r.vfs('shared', 'w')
262 fp.write('bookmarks\n')
262 fp.write('bookmarks\n')
263 fp.close()
263 fp.close()
264
264
265 def copystore(ui, srcrepo, destpath):
265 def copystore(ui, srcrepo, destpath):
266 '''copy files from store of srcrepo in destpath
266 '''copy files from store of srcrepo in destpath
267
267
268 returns destlock
268 returns destlock
269 '''
269 '''
270 destlock = None
270 destlock = None
271 try:
271 try:
272 hardlink = None
272 hardlink = None
273 num = 0
273 num = 0
274 closetopic = [None]
274 closetopic = [None]
275 def prog(topic, pos):
275 def prog(topic, pos):
276 if pos is None:
276 if pos is None:
277 closetopic[0] = topic
277 closetopic[0] = topic
278 else:
278 else:
279 ui.progress(topic, pos + num)
279 ui.progress(topic, pos + num)
280 srcpublishing = srcrepo.publishing()
280 srcpublishing = srcrepo.publishing()
281 srcvfs = scmutil.vfs(srcrepo.sharedpath)
281 srcvfs = scmutil.vfs(srcrepo.sharedpath)
282 dstvfs = scmutil.vfs(destpath)
282 dstvfs = scmutil.vfs(destpath)
283 for f in srcrepo.store.copylist():
283 for f in srcrepo.store.copylist():
284 if srcpublishing and f.endswith('phaseroots'):
284 if srcpublishing and f.endswith('phaseroots'):
285 continue
285 continue
286 dstbase = os.path.dirname(f)
286 dstbase = os.path.dirname(f)
287 if dstbase and not dstvfs.exists(dstbase):
287 if dstbase and not dstvfs.exists(dstbase):
288 dstvfs.mkdir(dstbase)
288 dstvfs.mkdir(dstbase)
289 if srcvfs.exists(f):
289 if srcvfs.exists(f):
290 if f.endswith('data'):
290 if f.endswith('data'):
291 # 'dstbase' may be empty (e.g. revlog format 0)
291 # 'dstbase' may be empty (e.g. revlog format 0)
292 lockfile = os.path.join(dstbase, "lock")
292 lockfile = os.path.join(dstbase, "lock")
293 # lock to avoid premature writing to the target
293 # lock to avoid premature writing to the target
294 destlock = lock.lock(dstvfs, lockfile)
294 destlock = lock.lock(dstvfs, lockfile)
295 hardlink, n = util.copyfiles(srcvfs.join(f), dstvfs.join(f),
295 hardlink, n = util.copyfiles(srcvfs.join(f), dstvfs.join(f),
296 hardlink, progress=prog)
296 hardlink, progress=prog)
297 num += n
297 num += n
298 if hardlink:
298 if hardlink:
299 ui.debug("linked %d files\n" % num)
299 ui.debug("linked %d files\n" % num)
300 if closetopic[0]:
300 if closetopic[0]:
301 ui.progress(closetopic[0], None)
301 ui.progress(closetopic[0], None)
302 else:
302 else:
303 ui.debug("copied %d files\n" % num)
303 ui.debug("copied %d files\n" % num)
304 if closetopic[0]:
304 if closetopic[0]:
305 ui.progress(closetopic[0], None)
305 ui.progress(closetopic[0], None)
306 return destlock
306 return destlock
307 except: # re-raises
307 except: # re-raises
308 release(destlock)
308 release(destlock)
309 raise
309 raise
310
310
311 def clonewithshare(ui, peeropts, sharepath, source, srcpeer, dest, pull=False,
311 def clonewithshare(ui, peeropts, sharepath, source, srcpeer, dest, pull=False,
312 rev=None, update=True, stream=False):
312 rev=None, update=True, stream=False):
313 """Perform a clone using a shared repo.
313 """Perform a clone using a shared repo.
314
314
315 The store for the repository will be located at <sharepath>/.hg. The
315 The store for the repository will be located at <sharepath>/.hg. The
316 specified revisions will be cloned or pulled from "source". A shared repo
316 specified revisions will be cloned or pulled from "source". A shared repo
317 will be created at "dest" and a working copy will be created if "update" is
317 will be created at "dest" and a working copy will be created if "update" is
318 True.
318 True.
319 """
319 """
320 revs = None
320 revs = None
321 if rev:
321 if rev:
322 if not srcpeer.capable('lookup'):
322 if not srcpeer.capable('lookup'):
323 raise util.Abort(_("src repository does not support "
323 raise util.Abort(_("src repository does not support "
324 "revision lookup and so doesn't "
324 "revision lookup and so doesn't "
325 "support clone by revision"))
325 "support clone by revision"))
326 revs = [srcpeer.lookup(r) for r in rev]
326 revs = [srcpeer.lookup(r) for r in rev]
327
327
328 basename = os.path.basename(sharepath)
328 basename = os.path.basename(sharepath)
329
329
330 if os.path.exists(sharepath):
330 if os.path.exists(sharepath):
331 ui.status(_('(sharing from existing pooled repository %s)\n') %
331 ui.status(_('(sharing from existing pooled repository %s)\n') %
332 basename)
332 basename)
333 else:
333 else:
334 ui.status(_('(sharing from new pooled repository %s)\n') % basename)
334 ui.status(_('(sharing from new pooled repository %s)\n') % basename)
335 # Always use pull mode because hardlinks in share mode don't work well.
335 # Always use pull mode because hardlinks in share mode don't work well.
336 # Never update because working copies aren't necessary in share mode.
336 # Never update because working copies aren't necessary in share mode.
337 clone(ui, peeropts, source, dest=sharepath, pull=True,
337 clone(ui, peeropts, source, dest=sharepath, pull=True,
338 rev=rev, update=False, stream=stream)
338 rev=rev, update=False, stream=stream)
339
339
340 sharerepo = repository(ui, path=sharepath)
340 sharerepo = repository(ui, path=sharepath)
341 share(ui, sharerepo, dest=dest, update=update, bookmarks=False)
341 share(ui, sharerepo, dest=dest, update=update, bookmarks=False)
342
342
343 # We need to perform a pull against the dest repo to fetch bookmarks
343 # We need to perform a pull against the dest repo to fetch bookmarks
344 # and other non-store data that isn't shared by default. In the case of
344 # and other non-store data that isn't shared by default. In the case of
345 # non-existing shared repo, this means we pull from the remote twice. This
345 # non-existing shared repo, this means we pull from the remote twice. This
346 # is a bit weird. But at the time it was implemented, there wasn't an easy
346 # is a bit weird. But at the time it was implemented, there wasn't an easy
347 # way to pull just non-changegroup data.
347 # way to pull just non-changegroup data.
348 destrepo = repository(ui, path=dest)
348 destrepo = repository(ui, path=dest)
349 exchange.pull(destrepo, srcpeer, heads=revs)
349 exchange.pull(destrepo, srcpeer, heads=revs)
350
350
351 return srcpeer, peer(ui, peeropts, dest)
351 return srcpeer, peer(ui, peeropts, dest)
352
352
353 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
353 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
354 update=True, stream=False, branch=None, shareopts=None):
354 update=True, stream=False, branch=None, shareopts=None):
355 """Make a copy of an existing repository.
355 """Make a copy of an existing repository.
356
356
357 Create a copy of an existing repository in a new directory. The
357 Create a copy of an existing repository in a new directory. The
358 source and destination are URLs, as passed to the repository
358 source and destination are URLs, as passed to the repository
359 function. Returns a pair of repository peers, the source and
359 function. Returns a pair of repository peers, the source and
360 newly created destination.
360 newly created destination.
361
361
362 The location of the source is added to the new repository's
362 The location of the source is added to the new repository's
363 .hg/hgrc file, as the default to be used for future pulls and
363 .hg/hgrc file, as the default to be used for future pulls and
364 pushes.
364 pushes.
365
365
366 If an exception is raised, the partly cloned/updated destination
366 If an exception is raised, the partly cloned/updated destination
367 repository will be deleted.
367 repository will be deleted.
368
368
369 Arguments:
369 Arguments:
370
370
371 source: repository object or URL
371 source: repository object or URL
372
372
373 dest: URL of destination repository to create (defaults to base
373 dest: URL of destination repository to create (defaults to base
374 name of source repository)
374 name of source repository)
375
375
376 pull: always pull from source repository, even in local case or if the
376 pull: always pull from source repository, even in local case or if the
377 server prefers streaming
377 server prefers streaming
378
378
379 stream: stream raw data uncompressed from repository (fast over
379 stream: stream raw data uncompressed from repository (fast over
380 LAN, slow over WAN)
380 LAN, slow over WAN)
381
381
382 rev: revision to clone up to (implies pull=True)
382 rev: revision to clone up to (implies pull=True)
383
383
384 update: update working directory after clone completes, if
384 update: update working directory after clone completes, if
385 destination is local repository (True means update to default rev,
385 destination is local repository (True means update to default rev,
386 anything else is treated as a revision)
386 anything else is treated as a revision)
387
387
388 branch: branches to clone
388 branch: branches to clone
389
389
390 shareopts: dict of options to control auto sharing behavior. The "pool" key
390 shareopts: dict of options to control auto sharing behavior. The "pool" key
391 activates auto sharing mode and defines the directory for stores. The
391 activates auto sharing mode and defines the directory for stores. The
392 "mode" key determines how to construct the directory name of the shared
392 "mode" key determines how to construct the directory name of the shared
393 repository. "identity" means the name is derived from the node of the first
393 repository. "identity" means the name is derived from the node of the first
394 changeset in the repository. "remote" means the name is derived from the
394 changeset in the repository. "remote" means the name is derived from the
395 remote's path/URL. Defaults to "identity."
395 remote's path/URL. Defaults to "identity."
396 """
396 """
397
397
398 if isinstance(source, str):
398 if isinstance(source, str):
399 origsource = ui.expandpath(source)
399 origsource = ui.expandpath(source)
400 source, branch = parseurl(origsource, branch)
400 source, branch = parseurl(origsource, branch)
401 srcpeer = peer(ui, peeropts, source)
401 srcpeer = peer(ui, peeropts, source)
402 else:
402 else:
403 srcpeer = source.peer() # in case we were called with a localrepo
403 srcpeer = source.peer() # in case we were called with a localrepo
404 branch = (None, branch or [])
404 branch = (None, branch or [])
405 origsource = source = srcpeer.url()
405 origsource = source = srcpeer.url()
406 rev, checkout = addbranchrevs(srcpeer, srcpeer, branch, rev)
406 rev, checkout = addbranchrevs(srcpeer, srcpeer, branch, rev)
407
407
408 if dest is None:
408 if dest is None:
409 dest = defaultdest(source)
409 dest = defaultdest(source)
410 if dest:
410 if dest:
411 ui.status(_("destination directory: %s\n") % dest)
411 ui.status(_("destination directory: %s\n") % dest)
412 else:
412 else:
413 dest = ui.expandpath(dest)
413 dest = ui.expandpath(dest)
414
414
415 dest = util.urllocalpath(dest)
415 dest = util.urllocalpath(dest)
416 source = util.urllocalpath(source)
416 source = util.urllocalpath(source)
417
417
418 if not dest:
418 if not dest:
419 raise util.Abort(_("empty destination path is not valid"))
419 raise util.Abort(_("empty destination path is not valid"))
420
420
421 destvfs = scmutil.vfs(dest, expandpath=True)
421 destvfs = scmutil.vfs(dest, expandpath=True)
422 if destvfs.lexists():
422 if destvfs.lexists():
423 if not destvfs.isdir():
423 if not destvfs.isdir():
424 raise util.Abort(_("destination '%s' already exists") % dest)
424 raise util.Abort(_("destination '%s' already exists") % dest)
425 elif destvfs.listdir():
425 elif destvfs.listdir():
426 raise util.Abort(_("destination '%s' is not empty") % dest)
426 raise util.Abort(_("destination '%s' is not empty") % dest)
427
427
428 shareopts = shareopts or {}
428 shareopts = shareopts or {}
429 sharepool = shareopts.get('pool')
429 sharepool = shareopts.get('pool')
430 sharenamemode = shareopts.get('mode')
430 sharenamemode = shareopts.get('mode')
431 if sharepool and islocal(dest):
431 if sharepool and islocal(dest):
432 sharepath = None
432 sharepath = None
433 if sharenamemode == 'identity':
433 if sharenamemode == 'identity':
434 # Resolve the name from the initial changeset in the remote
434 # Resolve the name from the initial changeset in the remote
435 # repository. This returns nullid when the remote is empty. It
435 # repository. This returns nullid when the remote is empty. It
436 # raises RepoLookupError if revision 0 is filtered or otherwise
436 # raises RepoLookupError if revision 0 is filtered or otherwise
437 # not available. If we fail to resolve, sharing is not enabled.
437 # not available. If we fail to resolve, sharing is not enabled.
438 try:
438 try:
439 rootnode = srcpeer.lookup('0')
439 rootnode = srcpeer.lookup('0')
440 if rootnode != node.nullid:
440 if rootnode != node.nullid:
441 sharepath = os.path.join(sharepool, node.hex(rootnode))
441 sharepath = os.path.join(sharepool, node.hex(rootnode))
442 else:
442 else:
443 ui.status(_('(not using pooled storage: '
443 ui.status(_('(not using pooled storage: '
444 'remote appears to be empty)\n'))
444 'remote appears to be empty)\n'))
445 except error.RepoLookupError:
445 except error.RepoLookupError:
446 ui.status(_('(not using pooled storage: '
446 ui.status(_('(not using pooled storage: '
447 'unable to resolve identity of remote)\n'))
447 'unable to resolve identity of remote)\n'))
448 elif sharenamemode == 'remote':
448 elif sharenamemode == 'remote':
449 sharepath = os.path.join(sharepool, util.sha1(source).hexdigest())
449 sharepath = os.path.join(sharepool, util.sha1(source).hexdigest())
450 else:
450 else:
451 raise util.Abort('unknown share naming mode: %s' % sharenamemode)
451 raise util.Abort('unknown share naming mode: %s' % sharenamemode)
452
452
453 if sharepath:
453 if sharepath:
454 return clonewithshare(ui, peeropts, sharepath, source, srcpeer,
454 return clonewithshare(ui, peeropts, sharepath, source, srcpeer,
455 dest, pull=pull, rev=rev, update=update,
455 dest, pull=pull, rev=rev, update=update,
456 stream=stream)
456 stream=stream)
457
457
458 srclock = destlock = cleandir = None
458 srclock = destlock = cleandir = None
459 srcrepo = srcpeer.local()
459 srcrepo = srcpeer.local()
460 try:
460 try:
461 abspath = origsource
461 abspath = origsource
462 if islocal(origsource):
462 if islocal(origsource):
463 abspath = os.path.abspath(util.urllocalpath(origsource))
463 abspath = os.path.abspath(util.urllocalpath(origsource))
464
464
465 if islocal(dest):
465 if islocal(dest):
466 cleandir = dest
466 cleandir = dest
467
467
468 copy = False
468 copy = False
469 if (srcrepo and srcrepo.cancopy() and islocal(dest)
469 if (srcrepo and srcrepo.cancopy() and islocal(dest)
470 and not phases.hassecret(srcrepo)):
470 and not phases.hassecret(srcrepo)):
471 copy = not pull and not rev
471 copy = not pull and not rev
472
472
473 if copy:
473 if copy:
474 try:
474 try:
475 # we use a lock here because if we race with commit, we
475 # we use a lock here because if we race with commit, we
476 # can end up with extra data in the cloned revlogs that's
476 # can end up with extra data in the cloned revlogs that's
477 # not pointed to by changesets, thus causing verify to
477 # not pointed to by changesets, thus causing verify to
478 # fail
478 # fail
479 srclock = srcrepo.lock(wait=False)
479 srclock = srcrepo.lock(wait=False)
480 except error.LockError:
480 except error.LockError:
481 copy = False
481 copy = False
482
482
483 if copy:
483 if copy:
484 srcrepo.hook('preoutgoing', throw=True, source='clone')
484 srcrepo.hook('preoutgoing', throw=True, source='clone')
485 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
485 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
486 if not os.path.exists(dest):
486 if not os.path.exists(dest):
487 os.mkdir(dest)
487 os.mkdir(dest)
488 else:
488 else:
489 # only clean up directories we create ourselves
489 # only clean up directories we create ourselves
490 cleandir = hgdir
490 cleandir = hgdir
491 try:
491 try:
492 destpath = hgdir
492 destpath = hgdir
493 util.makedir(destpath, notindexed=True)
493 util.makedir(destpath, notindexed=True)
494 except OSError as inst:
494 except OSError as inst:
495 if inst.errno == errno.EEXIST:
495 if inst.errno == errno.EEXIST:
496 cleandir = None
496 cleandir = None
497 raise util.Abort(_("destination '%s' already exists")
497 raise util.Abort(_("destination '%s' already exists")
498 % dest)
498 % dest)
499 raise
499 raise
500
500
501 destlock = copystore(ui, srcrepo, destpath)
501 destlock = copystore(ui, srcrepo, destpath)
502 # copy bookmarks over
502 # copy bookmarks over
503 srcbookmarks = srcrepo.join('bookmarks')
503 srcbookmarks = srcrepo.join('bookmarks')
504 dstbookmarks = os.path.join(destpath, 'bookmarks')
504 dstbookmarks = os.path.join(destpath, 'bookmarks')
505 if os.path.exists(srcbookmarks):
505 if os.path.exists(srcbookmarks):
506 util.copyfile(srcbookmarks, dstbookmarks)
506 util.copyfile(srcbookmarks, dstbookmarks)
507
507
508 # Recomputing branch cache might be slow on big repos,
508 # Recomputing branch cache might be slow on big repos,
509 # so just copy it
509 # so just copy it
510 def copybranchcache(fname):
510 def copybranchcache(fname):
511 srcbranchcache = srcrepo.join('cache/%s' % fname)
511 srcbranchcache = srcrepo.join('cache/%s' % fname)
512 dstbranchcache = os.path.join(dstcachedir, fname)
512 dstbranchcache = os.path.join(dstcachedir, fname)
513 if os.path.exists(srcbranchcache):
513 if os.path.exists(srcbranchcache):
514 if not os.path.exists(dstcachedir):
514 if not os.path.exists(dstcachedir):
515 os.mkdir(dstcachedir)
515 os.mkdir(dstcachedir)
516 util.copyfile(srcbranchcache, dstbranchcache)
516 util.copyfile(srcbranchcache, dstbranchcache)
517
517
518 dstcachedir = os.path.join(destpath, 'cache')
518 dstcachedir = os.path.join(destpath, 'cache')
519 # In local clones we're copying all nodes, not just served
519 # In local clones we're copying all nodes, not just served
520 # ones. Therefore copy all branch caches over.
520 # ones. Therefore copy all branch caches over.
521 copybranchcache('branch2')
521 copybranchcache('branch2')
522 for cachename in repoview.filtertable:
522 for cachename in repoview.filtertable:
523 copybranchcache('branch2-%s' % cachename)
523 copybranchcache('branch2-%s' % cachename)
524
524
525 # we need to re-init the repo after manually copying the data
525 # we need to re-init the repo after manually copying the data
526 # into it
526 # into it
527 destpeer = peer(srcrepo, peeropts, dest)
527 destpeer = peer(srcrepo, peeropts, dest)
528 srcrepo.hook('outgoing', source='clone',
528 srcrepo.hook('outgoing', source='clone',
529 node=node.hex(node.nullid))
529 node=node.hex(node.nullid))
530 else:
530 else:
531 try:
531 try:
532 destpeer = peer(srcrepo or ui, peeropts, dest, create=True)
532 destpeer = peer(srcrepo or ui, peeropts, dest, create=True)
533 # only pass ui when no srcrepo
533 # only pass ui when no srcrepo
534 except OSError as inst:
534 except OSError as inst:
535 if inst.errno == errno.EEXIST:
535 if inst.errno == errno.EEXIST:
536 cleandir = None
536 cleandir = None
537 raise util.Abort(_("destination '%s' already exists")
537 raise util.Abort(_("destination '%s' already exists")
538 % dest)
538 % dest)
539 raise
539 raise
540
540
541 revs = None
541 revs = None
542 if rev:
542 if rev:
543 if not srcpeer.capable('lookup'):
543 if not srcpeer.capable('lookup'):
544 raise util.Abort(_("src repository does not support "
544 raise util.Abort(_("src repository does not support "
545 "revision lookup and so doesn't "
545 "revision lookup and so doesn't "
546 "support clone by revision"))
546 "support clone by revision"))
547 revs = [srcpeer.lookup(r) for r in rev]
547 revs = [srcpeer.lookup(r) for r in rev]
548 checkout = revs[0]
548 checkout = revs[0]
549 if destpeer.local():
549 if destpeer.local():
550 if not stream:
550 if not stream:
551 if pull:
551 if pull:
552 stream = False
552 stream = False
553 else:
553 else:
554 stream = None
554 stream = None
555 destpeer.local().clone(srcpeer, heads=revs, stream=stream)
555 destpeer.local().clone(srcpeer, heads=revs, stream=stream)
556 elif srcrepo:
556 elif srcrepo:
557 exchange.push(srcrepo, destpeer, revs=revs,
557 exchange.push(srcrepo, destpeer, revs=revs,
558 bookmarks=srcrepo._bookmarks.keys())
558 bookmarks=srcrepo._bookmarks.keys())
559 else:
559 else:
560 raise util.Abort(_("clone from remote to remote not supported"))
560 raise util.Abort(_("clone from remote to remote not supported"))
561
561
562 cleandir = None
562 cleandir = None
563
563
564 destrepo = destpeer.local()
564 destrepo = destpeer.local()
565 if destrepo:
565 if destrepo:
566 template = uimod.samplehgrcs['cloned']
566 template = uimod.samplehgrcs['cloned']
567 fp = destrepo.vfs("hgrc", "w", text=True)
567 fp = destrepo.vfs("hgrc", "w", text=True)
568 u = util.url(abspath)
568 u = util.url(abspath)
569 u.passwd = None
569 u.passwd = None
570 defaulturl = str(u)
570 defaulturl = str(u)
571 fp.write(template % defaulturl)
571 fp.write(template % defaulturl)
572 fp.close()
572 fp.close()
573
573
574 destrepo.ui.setconfig('paths', 'default', defaulturl, 'clone')
574 destrepo.ui.setconfig('paths', 'default', defaulturl, 'clone')
575
575
576 if update:
576 if update:
577 if update is not True:
577 if update is not True:
578 checkout = srcpeer.lookup(update)
578 checkout = srcpeer.lookup(update)
579 uprev = None
579 uprev = None
580 status = None
580 status = None
581 if checkout is not None:
581 if checkout is not None:
582 try:
582 try:
583 uprev = destrepo.lookup(checkout)
583 uprev = destrepo.lookup(checkout)
584 except error.RepoLookupError:
584 except error.RepoLookupError:
585 pass
585 try:
586 uprev = destrepo.lookup(update)
587 except error.RepoLookupError:
588 pass
586 if uprev is None:
589 if uprev is None:
587 try:
590 try:
588 uprev = destrepo._bookmarks['@']
591 uprev = destrepo._bookmarks['@']
589 update = '@'
592 update = '@'
590 bn = destrepo[uprev].branch()
593 bn = destrepo[uprev].branch()
591 if bn == 'default':
594 if bn == 'default':
592 status = _("updating to bookmark @\n")
595 status = _("updating to bookmark @\n")
593 else:
596 else:
594 status = (_("updating to bookmark @ on branch %s\n")
597 status = (_("updating to bookmark @ on branch %s\n")
595 % bn)
598 % bn)
596 except KeyError:
599 except KeyError:
597 try:
600 try:
598 uprev = destrepo.branchtip('default')
601 uprev = destrepo.branchtip('default')
599 except error.RepoLookupError:
602 except error.RepoLookupError:
600 uprev = destrepo.lookup('tip')
603 uprev = destrepo.lookup('tip')
601 if not status:
604 if not status:
602 bn = destrepo[uprev].branch()
605 bn = destrepo[uprev].branch()
603 status = _("updating to branch %s\n") % bn
606 status = _("updating to branch %s\n") % bn
604 destrepo.ui.status(status)
607 destrepo.ui.status(status)
605 _update(destrepo, uprev)
608 _update(destrepo, uprev)
606 if update in destrepo._bookmarks:
609 if update in destrepo._bookmarks:
607 bookmarks.activate(destrepo, update)
610 bookmarks.activate(destrepo, update)
608 finally:
611 finally:
609 release(srclock, destlock)
612 release(srclock, destlock)
610 if cleandir is not None:
613 if cleandir is not None:
611 shutil.rmtree(cleandir, True)
614 shutil.rmtree(cleandir, True)
612 if srcpeer is not None:
615 if srcpeer is not None:
613 srcpeer.close()
616 srcpeer.close()
614 return srcpeer, destpeer
617 return srcpeer, destpeer
615
618
616 def _showstats(repo, stats):
619 def _showstats(repo, stats):
617 repo.ui.status(_("%d files updated, %d files merged, "
620 repo.ui.status(_("%d files updated, %d files merged, "
618 "%d files removed, %d files unresolved\n") % stats)
621 "%d files removed, %d files unresolved\n") % stats)
619
622
620 def updaterepo(repo, node, overwrite):
623 def updaterepo(repo, node, overwrite):
621 """Update the working directory to node.
624 """Update the working directory to node.
622
625
623 When overwrite is set, changes are clobbered, merged else
626 When overwrite is set, changes are clobbered, merged else
624
627
625 returns stats (see pydoc mercurial.merge.applyupdates)"""
628 returns stats (see pydoc mercurial.merge.applyupdates)"""
626 return mergemod.update(repo, node, False, overwrite, None,
629 return mergemod.update(repo, node, False, overwrite, None,
627 labels=['working copy', 'destination'])
630 labels=['working copy', 'destination'])
628
631
629 def update(repo, node):
632 def update(repo, node):
630 """update the working directory to node, merging linear changes"""
633 """update the working directory to node, merging linear changes"""
631 stats = updaterepo(repo, node, False)
634 stats = updaterepo(repo, node, False)
632 _showstats(repo, stats)
635 _showstats(repo, stats)
633 if stats[3]:
636 if stats[3]:
634 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
637 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
635 return stats[3] > 0
638 return stats[3] > 0
636
639
637 # naming conflict in clone()
640 # naming conflict in clone()
638 _update = update
641 _update = update
639
642
640 def clean(repo, node, show_stats=True):
643 def clean(repo, node, show_stats=True):
641 """forcibly switch the working directory to node, clobbering changes"""
644 """forcibly switch the working directory to node, clobbering changes"""
642 stats = updaterepo(repo, node, True)
645 stats = updaterepo(repo, node, True)
643 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
646 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
644 if show_stats:
647 if show_stats:
645 _showstats(repo, stats)
648 _showstats(repo, stats)
646 return stats[3] > 0
649 return stats[3] > 0
647
650
648 def merge(repo, node, force=None, remind=True):
651 def merge(repo, node, force=None, remind=True):
649 """Branch merge with node, resolving changes. Return true if any
652 """Branch merge with node, resolving changes. Return true if any
650 unresolved conflicts."""
653 unresolved conflicts."""
651 stats = mergemod.update(repo, node, True, force, False)
654 stats = mergemod.update(repo, node, True, force, False)
652 _showstats(repo, stats)
655 _showstats(repo, stats)
653 if stats[3]:
656 if stats[3]:
654 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
657 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
655 "or 'hg update -C .' to abandon\n"))
658 "or 'hg update -C .' to abandon\n"))
656 elif remind:
659 elif remind:
657 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
660 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
658 return stats[3] > 0
661 return stats[3] > 0
659
662
660 def _incoming(displaychlist, subreporecurse, ui, repo, source,
663 def _incoming(displaychlist, subreporecurse, ui, repo, source,
661 opts, buffered=False):
664 opts, buffered=False):
662 """
665 """
663 Helper for incoming / gincoming.
666 Helper for incoming / gincoming.
664 displaychlist gets called with
667 displaychlist gets called with
665 (remoterepo, incomingchangesetlist, displayer) parameters,
668 (remoterepo, incomingchangesetlist, displayer) parameters,
666 and is supposed to contain only code that can't be unified.
669 and is supposed to contain only code that can't be unified.
667 """
670 """
668 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
671 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
669 other = peer(repo, opts, source)
672 other = peer(repo, opts, source)
670 ui.status(_('comparing with %s\n') % util.hidepassword(source))
673 ui.status(_('comparing with %s\n') % util.hidepassword(source))
671 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
674 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
672
675
673 if revs:
676 if revs:
674 revs = [other.lookup(rev) for rev in revs]
677 revs = [other.lookup(rev) for rev in revs]
675 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
678 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
676 revs, opts["bundle"], opts["force"])
679 revs, opts["bundle"], opts["force"])
677 try:
680 try:
678 if not chlist:
681 if not chlist:
679 ui.status(_("no changes found\n"))
682 ui.status(_("no changes found\n"))
680 return subreporecurse()
683 return subreporecurse()
681
684
682 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
685 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
683 displaychlist(other, chlist, displayer)
686 displaychlist(other, chlist, displayer)
684 displayer.close()
687 displayer.close()
685 finally:
688 finally:
686 cleanupfn()
689 cleanupfn()
687 subreporecurse()
690 subreporecurse()
688 return 0 # exit code is zero since we found incoming changes
691 return 0 # exit code is zero since we found incoming changes
689
692
690 def incoming(ui, repo, source, opts):
693 def incoming(ui, repo, source, opts):
691 def subreporecurse():
694 def subreporecurse():
692 ret = 1
695 ret = 1
693 if opts.get('subrepos'):
696 if opts.get('subrepos'):
694 ctx = repo[None]
697 ctx = repo[None]
695 for subpath in sorted(ctx.substate):
698 for subpath in sorted(ctx.substate):
696 sub = ctx.sub(subpath)
699 sub = ctx.sub(subpath)
697 ret = min(ret, sub.incoming(ui, source, opts))
700 ret = min(ret, sub.incoming(ui, source, opts))
698 return ret
701 return ret
699
702
700 def display(other, chlist, displayer):
703 def display(other, chlist, displayer):
701 limit = cmdutil.loglimit(opts)
704 limit = cmdutil.loglimit(opts)
702 if opts.get('newest_first'):
705 if opts.get('newest_first'):
703 chlist.reverse()
706 chlist.reverse()
704 count = 0
707 count = 0
705 for n in chlist:
708 for n in chlist:
706 if limit is not None and count >= limit:
709 if limit is not None and count >= limit:
707 break
710 break
708 parents = [p for p in other.changelog.parents(n) if p != nullid]
711 parents = [p for p in other.changelog.parents(n) if p != nullid]
709 if opts.get('no_merges') and len(parents) == 2:
712 if opts.get('no_merges') and len(parents) == 2:
710 continue
713 continue
711 count += 1
714 count += 1
712 displayer.show(other[n])
715 displayer.show(other[n])
713 return _incoming(display, subreporecurse, ui, repo, source, opts)
716 return _incoming(display, subreporecurse, ui, repo, source, opts)
714
717
715 def _outgoing(ui, repo, dest, opts):
718 def _outgoing(ui, repo, dest, opts):
716 dest = ui.expandpath(dest or 'default-push', dest or 'default')
719 dest = ui.expandpath(dest or 'default-push', dest or 'default')
717 dest, branches = parseurl(dest, opts.get('branch'))
720 dest, branches = parseurl(dest, opts.get('branch'))
718 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
721 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
719 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
722 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
720 if revs:
723 if revs:
721 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
724 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
722
725
723 other = peer(repo, opts, dest)
726 other = peer(repo, opts, dest)
724 outgoing = discovery.findcommonoutgoing(repo.unfiltered(), other, revs,
727 outgoing = discovery.findcommonoutgoing(repo.unfiltered(), other, revs,
725 force=opts.get('force'))
728 force=opts.get('force'))
726 o = outgoing.missing
729 o = outgoing.missing
727 if not o:
730 if not o:
728 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
731 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
729 return o, other
732 return o, other
730
733
731 def outgoing(ui, repo, dest, opts):
734 def outgoing(ui, repo, dest, opts):
732 def recurse():
735 def recurse():
733 ret = 1
736 ret = 1
734 if opts.get('subrepos'):
737 if opts.get('subrepos'):
735 ctx = repo[None]
738 ctx = repo[None]
736 for subpath in sorted(ctx.substate):
739 for subpath in sorted(ctx.substate):
737 sub = ctx.sub(subpath)
740 sub = ctx.sub(subpath)
738 ret = min(ret, sub.outgoing(ui, dest, opts))
741 ret = min(ret, sub.outgoing(ui, dest, opts))
739 return ret
742 return ret
740
743
741 limit = cmdutil.loglimit(opts)
744 limit = cmdutil.loglimit(opts)
742 o, other = _outgoing(ui, repo, dest, opts)
745 o, other = _outgoing(ui, repo, dest, opts)
743 if not o:
746 if not o:
744 cmdutil.outgoinghooks(ui, repo, other, opts, o)
747 cmdutil.outgoinghooks(ui, repo, other, opts, o)
745 return recurse()
748 return recurse()
746
749
747 if opts.get('newest_first'):
750 if opts.get('newest_first'):
748 o.reverse()
751 o.reverse()
749 displayer = cmdutil.show_changeset(ui, repo, opts)
752 displayer = cmdutil.show_changeset(ui, repo, opts)
750 count = 0
753 count = 0
751 for n in o:
754 for n in o:
752 if limit is not None and count >= limit:
755 if limit is not None and count >= limit:
753 break
756 break
754 parents = [p for p in repo.changelog.parents(n) if p != nullid]
757 parents = [p for p in repo.changelog.parents(n) if p != nullid]
755 if opts.get('no_merges') and len(parents) == 2:
758 if opts.get('no_merges') and len(parents) == 2:
756 continue
759 continue
757 count += 1
760 count += 1
758 displayer.show(repo[n])
761 displayer.show(repo[n])
759 displayer.close()
762 displayer.close()
760 cmdutil.outgoinghooks(ui, repo, other, opts, o)
763 cmdutil.outgoinghooks(ui, repo, other, opts, o)
761 recurse()
764 recurse()
762 return 0 # exit code is zero since we found outgoing changes
765 return 0 # exit code is zero since we found outgoing changes
763
766
764 def revert(repo, node, choose):
767 def revert(repo, node, choose):
765 """revert changes to revision in node without updating dirstate"""
768 """revert changes to revision in node without updating dirstate"""
766 return mergemod.update(repo, node, False, True, choose)[3] > 0
769 return mergemod.update(repo, node, False, True, choose)[3] > 0
767
770
768 def verify(repo):
771 def verify(repo):
769 """verify the consistency of a repository"""
772 """verify the consistency of a repository"""
770 ret = verifymod.verify(repo)
773 ret = verifymod.verify(repo)
771
774
772 # Broken subrepo references in hidden csets don't seem worth worrying about,
775 # Broken subrepo references in hidden csets don't seem worth worrying about,
773 # since they can't be pushed/pulled, and --hidden can be used if they are a
776 # since they can't be pushed/pulled, and --hidden can be used if they are a
774 # concern.
777 # concern.
775
778
776 # pathto() is needed for -R case
779 # pathto() is needed for -R case
777 revs = repo.revs("filelog(%s)",
780 revs = repo.revs("filelog(%s)",
778 util.pathto(repo.root, repo.getcwd(), '.hgsubstate'))
781 util.pathto(repo.root, repo.getcwd(), '.hgsubstate'))
779
782
780 if revs:
783 if revs:
781 repo.ui.status(_('checking subrepo links\n'))
784 repo.ui.status(_('checking subrepo links\n'))
782 for rev in revs:
785 for rev in revs:
783 ctx = repo[rev]
786 ctx = repo[rev]
784 try:
787 try:
785 for subpath in ctx.substate:
788 for subpath in ctx.substate:
786 ret = ctx.sub(subpath).verify() or ret
789 ret = ctx.sub(subpath).verify() or ret
787 except Exception:
790 except Exception:
788 repo.ui.warn(_('.hgsubstate is corrupt in revision %s\n') %
791 repo.ui.warn(_('.hgsubstate is corrupt in revision %s\n') %
789 node.short(ctx.node()))
792 node.short(ctx.node()))
790
793
791 return ret
794 return ret
792
795
793 def remoteui(src, opts):
796 def remoteui(src, opts):
794 'build a remote ui from ui or repo and opts'
797 'build a remote ui from ui or repo and opts'
795 if util.safehasattr(src, 'baseui'): # looks like a repository
798 if util.safehasattr(src, 'baseui'): # looks like a repository
796 dst = src.baseui.copy() # drop repo-specific config
799 dst = src.baseui.copy() # drop repo-specific config
797 src = src.ui # copy target options from repo
800 src = src.ui # copy target options from repo
798 else: # assume it's a global ui object
801 else: # assume it's a global ui object
799 dst = src.copy() # keep all global options
802 dst = src.copy() # keep all global options
800
803
801 # copy ssh-specific options
804 # copy ssh-specific options
802 for o in 'ssh', 'remotecmd':
805 for o in 'ssh', 'remotecmd':
803 v = opts.get(o) or src.config('ui', o)
806 v = opts.get(o) or src.config('ui', o)
804 if v:
807 if v:
805 dst.setconfig("ui", o, v, 'copied')
808 dst.setconfig("ui", o, v, 'copied')
806
809
807 # copy bundle-specific options
810 # copy bundle-specific options
808 r = src.config('bundle', 'mainreporoot')
811 r = src.config('bundle', 'mainreporoot')
809 if r:
812 if r:
810 dst.setconfig('bundle', 'mainreporoot', r, 'copied')
813 dst.setconfig('bundle', 'mainreporoot', r, 'copied')
811
814
812 # copy selected local settings to the remote ui
815 # copy selected local settings to the remote ui
813 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
816 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
814 for key, val in src.configitems(sect):
817 for key, val in src.configitems(sect):
815 dst.setconfig(sect, key, val, 'copied')
818 dst.setconfig(sect, key, val, 'copied')
816 v = src.config('web', 'cacerts')
819 v = src.config('web', 'cacerts')
817 if v == '!':
820 if v == '!':
818 dst.setconfig('web', 'cacerts', v, 'copied')
821 dst.setconfig('web', 'cacerts', v, 'copied')
819 elif v:
822 elif v:
820 dst.setconfig('web', 'cacerts', util.expandpath(v), 'copied')
823 dst.setconfig('web', 'cacerts', util.expandpath(v), 'copied')
821
824
822 return dst
825 return dst
@@ -1,220 +1,243 b''
1 $ hg init test
1 $ hg init test
2 $ cd test
2 $ cd test
3
3
4 $ echo 0 >> afile
4 $ echo 0 >> afile
5 $ hg add afile
5 $ hg add afile
6 $ hg commit -m "0.0"
6 $ hg commit -m "0.0"
7
7
8 $ echo 1 >> afile
8 $ echo 1 >> afile
9 $ hg commit -m "0.1"
9 $ hg commit -m "0.1"
10
10
11 $ echo 2 >> afile
11 $ echo 2 >> afile
12 $ hg commit -m "0.2"
12 $ hg commit -m "0.2"
13
13
14 $ echo 3 >> afile
14 $ echo 3 >> afile
15 $ hg commit -m "0.3"
15 $ hg commit -m "0.3"
16
16
17 $ hg update -C 0
17 $ hg update -C 0
18 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
18 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
19
19
20 $ echo 1 >> afile
20 $ echo 1 >> afile
21 $ hg commit -m "1.1"
21 $ hg commit -m "1.1"
22 created new head
22 created new head
23
23
24 $ echo 2 >> afile
24 $ echo 2 >> afile
25 $ hg commit -m "1.2"
25 $ hg commit -m "1.2"
26
26
27 $ echo a line > fred
27 $ echo a line > fred
28 $ echo 3 >> afile
28 $ echo 3 >> afile
29 $ hg add fred
29 $ hg add fred
30 $ hg commit -m "1.3"
30 $ hg commit -m "1.3"
31 $ hg mv afile adifferentfile
31 $ hg mv afile adifferentfile
32 $ hg commit -m "1.3m"
32 $ hg commit -m "1.3m"
33
33
34 $ hg update -C 3
34 $ hg update -C 3
35 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
35 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
36
36
37 $ hg mv afile anotherfile
37 $ hg mv afile anotherfile
38 $ hg commit -m "0.3m"
38 $ hg commit -m "0.3m"
39
39
40 $ hg debugindex -f 1 afile
40 $ hg debugindex -f 1 afile
41 rev flag offset length size ..... link p1 p2 nodeid (re)
41 rev flag offset length size ..... link p1 p2 nodeid (re)
42 0 0000 0 3 2 ..... 0 -1 -1 362fef284ce2 (re)
42 0 0000 0 3 2 ..... 0 -1 -1 362fef284ce2 (re)
43 1 0000 3 5 4 ..... 1 0 -1 125144f7e028 (re)
43 1 0000 3 5 4 ..... 1 0 -1 125144f7e028 (re)
44 2 0000 8 7 6 ..... 2 1 -1 4c982badb186 (re)
44 2 0000 8 7 6 ..... 2 1 -1 4c982badb186 (re)
45 3 0000 15 9 8 ..... 3 2 -1 19b1fc555737 (re)
45 3 0000 15 9 8 ..... 3 2 -1 19b1fc555737 (re)
46
46
47 $ hg debugindex adifferentfile
47 $ hg debugindex adifferentfile
48 rev offset length ..... linkrev nodeid p1 p2 (re)
48 rev offset length ..... linkrev nodeid p1 p2 (re)
49 0 0 75 ..... 7 2565f3199a74 000000000000 000000000000 (re)
49 0 0 75 ..... 7 2565f3199a74 000000000000 000000000000 (re)
50
50
51 $ hg debugindex anotherfile
51 $ hg debugindex anotherfile
52 rev offset length ..... linkrev nodeid p1 p2 (re)
52 rev offset length ..... linkrev nodeid p1 p2 (re)
53 0 0 75 ..... 8 2565f3199a74 000000000000 000000000000 (re)
53 0 0 75 ..... 8 2565f3199a74 000000000000 000000000000 (re)
54
54
55 $ hg debugindex fred
55 $ hg debugindex fred
56 rev offset length ..... linkrev nodeid p1 p2 (re)
56 rev offset length ..... linkrev nodeid p1 p2 (re)
57 0 0 8 ..... 6 12ab3bcc5ea4 000000000000 000000000000 (re)
57 0 0 8 ..... 6 12ab3bcc5ea4 000000000000 000000000000 (re)
58
58
59 $ hg debugindex --manifest
59 $ hg debugindex --manifest
60 rev offset length ..... linkrev nodeid p1 p2 (re)
60 rev offset length ..... linkrev nodeid p1 p2 (re)
61 0 0 48 ..... 0 43eadb1d2d06 000000000000 000000000000 (re)
61 0 0 48 ..... 0 43eadb1d2d06 000000000000 000000000000 (re)
62 1 48 48 ..... 1 8b89697eba2c 43eadb1d2d06 000000000000 (re)
62 1 48 48 ..... 1 8b89697eba2c 43eadb1d2d06 000000000000 (re)
63 2 96 48 ..... 2 626a32663c2f 8b89697eba2c 000000000000 (re)
63 2 96 48 ..... 2 626a32663c2f 8b89697eba2c 000000000000 (re)
64 3 144 48 ..... 3 f54c32f13478 626a32663c2f 000000000000 (re)
64 3 144 48 ..... 3 f54c32f13478 626a32663c2f 000000000000 (re)
65 4 192 .. ..... 6 de68e904d169 626a32663c2f 000000000000 (re)
65 4 192 .. ..... 6 de68e904d169 626a32663c2f 000000000000 (re)
66 5 2.. 68 ..... 7 09bb521d218d de68e904d169 000000000000 (re)
66 5 2.. 68 ..... 7 09bb521d218d de68e904d169 000000000000 (re)
67 6 3.. 54 ..... 8 1fde233dfb0f f54c32f13478 000000000000 (re)
67 6 3.. 54 ..... 8 1fde233dfb0f f54c32f13478 000000000000 (re)
68
68
69 $ hg verify
69 $ hg verify
70 checking changesets
70 checking changesets
71 checking manifests
71 checking manifests
72 crosschecking files in changesets and manifests
72 crosschecking files in changesets and manifests
73 checking files
73 checking files
74 4 files, 9 changesets, 7 total revisions
74 4 files, 9 changesets, 7 total revisions
75
75
76 $ cd ..
76 $ cd ..
77
77
78 $ for i in 0 1 2 3 4 5 6 7 8; do
78 $ for i in 0 1 2 3 4 5 6 7 8; do
79 > echo
79 > echo
80 > echo ---- hg clone -r "$i" test test-"$i"
80 > echo ---- hg clone -r "$i" test test-"$i"
81 > hg clone -r "$i" test test-"$i"
81 > hg clone -r "$i" test test-"$i"
82 > cd test-"$i"
82 > cd test-"$i"
83 > hg verify
83 > hg verify
84 > cd ..
84 > cd ..
85 > done
85 > done
86
86
87 ---- hg clone -r 0 test test-0
87 ---- hg clone -r 0 test test-0
88 adding changesets
88 adding changesets
89 adding manifests
89 adding manifests
90 adding file changes
90 adding file changes
91 added 1 changesets with 1 changes to 1 files
91 added 1 changesets with 1 changes to 1 files
92 updating to branch default
92 updating to branch default
93 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
93 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
94 checking changesets
94 checking changesets
95 checking manifests
95 checking manifests
96 crosschecking files in changesets and manifests
96 crosschecking files in changesets and manifests
97 checking files
97 checking files
98 1 files, 1 changesets, 1 total revisions
98 1 files, 1 changesets, 1 total revisions
99
99
100 ---- hg clone -r 1 test test-1
100 ---- hg clone -r 1 test test-1
101 adding changesets
101 adding changesets
102 adding manifests
102 adding manifests
103 adding file changes
103 adding file changes
104 added 2 changesets with 2 changes to 1 files
104 added 2 changesets with 2 changes to 1 files
105 updating to branch default
105 updating to branch default
106 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
106 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
107 checking changesets
107 checking changesets
108 checking manifests
108 checking manifests
109 crosschecking files in changesets and manifests
109 crosschecking files in changesets and manifests
110 checking files
110 checking files
111 1 files, 2 changesets, 2 total revisions
111 1 files, 2 changesets, 2 total revisions
112
112
113 ---- hg clone -r 2 test test-2
113 ---- hg clone -r 2 test test-2
114 adding changesets
114 adding changesets
115 adding manifests
115 adding manifests
116 adding file changes
116 adding file changes
117 added 3 changesets with 3 changes to 1 files
117 added 3 changesets with 3 changes to 1 files
118 updating to branch default
118 updating to branch default
119 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
119 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 checking changesets
120 checking changesets
121 checking manifests
121 checking manifests
122 crosschecking files in changesets and manifests
122 crosschecking files in changesets and manifests
123 checking files
123 checking files
124 1 files, 3 changesets, 3 total revisions
124 1 files, 3 changesets, 3 total revisions
125
125
126 ---- hg clone -r 3 test test-3
126 ---- hg clone -r 3 test test-3
127 adding changesets
127 adding changesets
128 adding manifests
128 adding manifests
129 adding file changes
129 adding file changes
130 added 4 changesets with 4 changes to 1 files
130 added 4 changesets with 4 changes to 1 files
131 updating to branch default
131 updating to branch default
132 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
132 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
133 checking changesets
133 checking changesets
134 checking manifests
134 checking manifests
135 crosschecking files in changesets and manifests
135 crosschecking files in changesets and manifests
136 checking files
136 checking files
137 1 files, 4 changesets, 4 total revisions
137 1 files, 4 changesets, 4 total revisions
138
138
139 ---- hg clone -r 4 test test-4
139 ---- hg clone -r 4 test test-4
140 adding changesets
140 adding changesets
141 adding manifests
141 adding manifests
142 adding file changes
142 adding file changes
143 added 2 changesets with 2 changes to 1 files
143 added 2 changesets with 2 changes to 1 files
144 updating to branch default
144 updating to branch default
145 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
145 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
146 checking changesets
146 checking changesets
147 checking manifests
147 checking manifests
148 crosschecking files in changesets and manifests
148 crosschecking files in changesets and manifests
149 checking files
149 checking files
150 1 files, 2 changesets, 2 total revisions
150 1 files, 2 changesets, 2 total revisions
151
151
152 ---- hg clone -r 5 test test-5
152 ---- hg clone -r 5 test test-5
153 adding changesets
153 adding changesets
154 adding manifests
154 adding manifests
155 adding file changes
155 adding file changes
156 added 3 changesets with 3 changes to 1 files
156 added 3 changesets with 3 changes to 1 files
157 updating to branch default
157 updating to branch default
158 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
158 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
159 checking changesets
159 checking changesets
160 checking manifests
160 checking manifests
161 crosschecking files in changesets and manifests
161 crosschecking files in changesets and manifests
162 checking files
162 checking files
163 1 files, 3 changesets, 3 total revisions
163 1 files, 3 changesets, 3 total revisions
164
164
165 ---- hg clone -r 6 test test-6
165 ---- hg clone -r 6 test test-6
166 adding changesets
166 adding changesets
167 adding manifests
167 adding manifests
168 adding file changes
168 adding file changes
169 added 4 changesets with 5 changes to 2 files
169 added 4 changesets with 5 changes to 2 files
170 updating to branch default
170 updating to branch default
171 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
171 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
172 checking changesets
172 checking changesets
173 checking manifests
173 checking manifests
174 crosschecking files in changesets and manifests
174 crosschecking files in changesets and manifests
175 checking files
175 checking files
176 2 files, 4 changesets, 5 total revisions
176 2 files, 4 changesets, 5 total revisions
177
177
178 ---- hg clone -r 7 test test-7
178 ---- hg clone -r 7 test test-7
179 adding changesets
179 adding changesets
180 adding manifests
180 adding manifests
181 adding file changes
181 adding file changes
182 added 5 changesets with 6 changes to 3 files
182 added 5 changesets with 6 changes to 3 files
183 updating to branch default
183 updating to branch default
184 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
184 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
185 checking changesets
185 checking changesets
186 checking manifests
186 checking manifests
187 crosschecking files in changesets and manifests
187 crosschecking files in changesets and manifests
188 checking files
188 checking files
189 3 files, 5 changesets, 6 total revisions
189 3 files, 5 changesets, 6 total revisions
190
190
191 ---- hg clone -r 8 test test-8
191 ---- hg clone -r 8 test test-8
192 adding changesets
192 adding changesets
193 adding manifests
193 adding manifests
194 adding file changes
194 adding file changes
195 added 5 changesets with 5 changes to 2 files
195 added 5 changesets with 5 changes to 2 files
196 updating to branch default
196 updating to branch default
197 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
197 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
198 checking changesets
198 checking changesets
199 checking manifests
199 checking manifests
200 crosschecking files in changesets and manifests
200 crosschecking files in changesets and manifests
201 checking files
201 checking files
202 2 files, 5 changesets, 5 total revisions
202 2 files, 5 changesets, 5 total revisions
203
203
204 $ cd test-8
204 $ cd test-8
205 $ hg pull ../test-7
205 $ hg pull ../test-7
206 pulling from ../test-7
206 pulling from ../test-7
207 searching for changes
207 searching for changes
208 adding changesets
208 adding changesets
209 adding manifests
209 adding manifests
210 adding file changes
210 adding file changes
211 added 4 changesets with 2 changes to 3 files (+1 heads)
211 added 4 changesets with 2 changes to 3 files (+1 heads)
212 (run 'hg heads' to see heads, 'hg merge' to merge)
212 (run 'hg heads' to see heads, 'hg merge' to merge)
213 $ hg verify
213 $ hg verify
214 checking changesets
214 checking changesets
215 checking manifests
215 checking manifests
216 crosschecking files in changesets and manifests
216 crosschecking files in changesets and manifests
217 checking files
217 checking files
218 4 files, 9 changesets, 7 total revisions
218 4 files, 9 changesets, 7 total revisions
219 $ cd ..
219 $ cd ..
220
220
221 $ hg clone test test-9
222 updating to branch default
223 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
224 $ cd test-9
225 $ hg branch foobar
226 marked working directory as branch foobar
227 (branches are permanent and global, did you want a bookmark?)
228 $ echo file2 >> file2
229 $ hg add file2
230 $ hg commit -m "changeset9"
231 $ echo file3 >> file3
232 $ hg add file3
233 $ hg commit -m "changeset10"
234 $ cd ..
235 $ hg clone -r 9 -u foobar test-9 test-10
236 adding changesets
237 adding manifests
238 adding file changes
239 added 6 changesets with 6 changes to 3 files
240 updating to branch foobar
241 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
242
243
General Comments 0
You need to be logged in to leave comments. Login now