##// END OF EJS Templates
hg: add support for cloning bookmarks
David Soria Parra -
r13604:3f6a4579 default
parent child Browse files
Show More
@@ -1,554 +1,569 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 i18n import _
9 from i18n import _
10 from lock import release
10 from lock import release
11 from node import hex, nullid, nullrev, short
11 from node import hex, nullid, nullrev, short
12 import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo
12 import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo, bookmarks
13 import lock, util, extensions, error, encoding, node
13 import lock, util, extensions, error, encoding, node
14 import cmdutil, discovery, url
14 import cmdutil, discovery, url
15 import merge as mergemod
15 import merge as mergemod
16 import verify as verifymod
16 import verify as verifymod
17 import errno, os, shutil
17 import errno, os, shutil
18
18
19 def _local(path):
19 def _local(path):
20 path = util.expandpath(util.drop_scheme('file', path))
20 path = util.expandpath(util.drop_scheme('file', path))
21 return (os.path.isfile(path) and bundlerepo or localrepo)
21 return (os.path.isfile(path) and bundlerepo or localrepo)
22
22
23 def addbranchrevs(lrepo, repo, branches, revs):
23 def addbranchrevs(lrepo, repo, branches, revs):
24 hashbranch, branches = branches
24 hashbranch, branches = branches
25 if not hashbranch and not branches:
25 if not hashbranch and not branches:
26 return revs or None, revs and revs[0] or None
26 return revs or None, revs and revs[0] or None
27 revs = revs and list(revs) or []
27 revs = revs and list(revs) or []
28 if not repo.capable('branchmap'):
28 if not repo.capable('branchmap'):
29 if branches:
29 if branches:
30 raise util.Abort(_("remote branch lookup not supported"))
30 raise util.Abort(_("remote branch lookup not supported"))
31 revs.append(hashbranch)
31 revs.append(hashbranch)
32 return revs, revs[0]
32 return revs, revs[0]
33 branchmap = repo.branchmap()
33 branchmap = repo.branchmap()
34
34
35 def primary(branch):
35 def primary(branch):
36 if branch == '.':
36 if branch == '.':
37 if not lrepo or not lrepo.local():
37 if not lrepo or not lrepo.local():
38 raise util.Abort(_("dirstate branch not accessible"))
38 raise util.Abort(_("dirstate branch not accessible"))
39 branch = lrepo.dirstate.branch()
39 branch = lrepo.dirstate.branch()
40 if branch in branchmap:
40 if branch in branchmap:
41 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
41 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
42 return True
42 return True
43 else:
43 else:
44 return False
44 return False
45
45
46 for branch in branches:
46 for branch in branches:
47 if not primary(branch):
47 if not primary(branch):
48 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
48 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
49 if hashbranch:
49 if hashbranch:
50 if not primary(hashbranch):
50 if not primary(hashbranch):
51 revs.append(hashbranch)
51 revs.append(hashbranch)
52 return revs, revs[0]
52 return revs, revs[0]
53
53
54 def parseurl(url, branches=None):
54 def parseurl(url, branches=None):
55 '''parse url#branch, returning (url, (branch, branches))'''
55 '''parse url#branch, returning (url, (branch, branches))'''
56
56
57 if '#' not in url:
57 if '#' not in url:
58 return url, (None, branches or [])
58 return url, (None, branches or [])
59 url, branch = url.split('#', 1)
59 url, branch = url.split('#', 1)
60 return url, (branch, branches or [])
60 return url, (branch, branches or [])
61
61
62 schemes = {
62 schemes = {
63 'bundle': bundlerepo,
63 'bundle': bundlerepo,
64 'file': _local,
64 'file': _local,
65 'http': httprepo,
65 'http': httprepo,
66 'https': httprepo,
66 'https': httprepo,
67 'ssh': sshrepo,
67 'ssh': sshrepo,
68 'static-http': statichttprepo,
68 'static-http': statichttprepo,
69 }
69 }
70
70
71 def _lookup(path):
71 def _lookup(path):
72 scheme = 'file'
72 scheme = 'file'
73 if path:
73 if path:
74 c = path.find(':')
74 c = path.find(':')
75 if c > 0:
75 if c > 0:
76 scheme = path[:c]
76 scheme = path[:c]
77 thing = schemes.get(scheme) or schemes['file']
77 thing = schemes.get(scheme) or schemes['file']
78 try:
78 try:
79 return thing(path)
79 return thing(path)
80 except TypeError:
80 except TypeError:
81 return thing
81 return thing
82
82
83 def islocal(repo):
83 def islocal(repo):
84 '''return true if repo or path is local'''
84 '''return true if repo or path is local'''
85 if isinstance(repo, str):
85 if isinstance(repo, str):
86 try:
86 try:
87 return _lookup(repo).islocal(repo)
87 return _lookup(repo).islocal(repo)
88 except AttributeError:
88 except AttributeError:
89 return False
89 return False
90 return repo.local()
90 return repo.local()
91
91
92 def repository(ui, path='', create=False):
92 def repository(ui, path='', create=False):
93 """return a repository object for the specified path"""
93 """return a repository object for the specified path"""
94 repo = _lookup(path).instance(ui, path, create)
94 repo = _lookup(path).instance(ui, path, create)
95 ui = getattr(repo, "ui", ui)
95 ui = getattr(repo, "ui", ui)
96 for name, module in extensions.extensions():
96 for name, module in extensions.extensions():
97 hook = getattr(module, 'reposetup', None)
97 hook = getattr(module, 'reposetup', None)
98 if hook:
98 if hook:
99 hook(ui, repo)
99 hook(ui, repo)
100 return repo
100 return repo
101
101
102 def defaultdest(source):
102 def defaultdest(source):
103 '''return default destination of clone if none is given'''
103 '''return default destination of clone if none is given'''
104 return os.path.basename(os.path.normpath(source))
104 return os.path.basename(os.path.normpath(source))
105
105
106 def localpath(path):
106 def localpath(path):
107 if path.startswith('file://localhost/'):
107 if path.startswith('file://localhost/'):
108 return path[16:]
108 return path[16:]
109 if path.startswith('file://'):
109 if path.startswith('file://'):
110 return path[7:]
110 return path[7:]
111 if path.startswith('file:'):
111 if path.startswith('file:'):
112 return path[5:]
112 return path[5:]
113 return path
113 return path
114
114
115 def share(ui, source, dest=None, update=True):
115 def share(ui, source, dest=None, update=True):
116 '''create a shared repository'''
116 '''create a shared repository'''
117
117
118 if not islocal(source):
118 if not islocal(source):
119 raise util.Abort(_('can only share local repositories'))
119 raise util.Abort(_('can only share local repositories'))
120
120
121 if not dest:
121 if not dest:
122 dest = defaultdest(source)
122 dest = defaultdest(source)
123 else:
123 else:
124 dest = ui.expandpath(dest)
124 dest = ui.expandpath(dest)
125
125
126 if isinstance(source, str):
126 if isinstance(source, str):
127 origsource = ui.expandpath(source)
127 origsource = ui.expandpath(source)
128 source, branches = parseurl(origsource)
128 source, branches = parseurl(origsource)
129 srcrepo = repository(ui, source)
129 srcrepo = repository(ui, source)
130 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
130 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
131 else:
131 else:
132 srcrepo = source
132 srcrepo = source
133 origsource = source = srcrepo.url()
133 origsource = source = srcrepo.url()
134 checkout = None
134 checkout = None
135
135
136 sharedpath = srcrepo.sharedpath # if our source is already sharing
136 sharedpath = srcrepo.sharedpath # if our source is already sharing
137
137
138 root = os.path.realpath(dest)
138 root = os.path.realpath(dest)
139 roothg = os.path.join(root, '.hg')
139 roothg = os.path.join(root, '.hg')
140
140
141 if os.path.exists(roothg):
141 if os.path.exists(roothg):
142 raise util.Abort(_('destination already exists'))
142 raise util.Abort(_('destination already exists'))
143
143
144 if not os.path.isdir(root):
144 if not os.path.isdir(root):
145 os.mkdir(root)
145 os.mkdir(root)
146 os.mkdir(roothg)
146 os.mkdir(roothg)
147
147
148 requirements = ''
148 requirements = ''
149 try:
149 try:
150 requirements = srcrepo.opener('requires').read()
150 requirements = srcrepo.opener('requires').read()
151 except IOError, inst:
151 except IOError, inst:
152 if inst.errno != errno.ENOENT:
152 if inst.errno != errno.ENOENT:
153 raise
153 raise
154
154
155 requirements += 'shared\n'
155 requirements += 'shared\n'
156 file(os.path.join(roothg, 'requires'), 'w').write(requirements)
156 file(os.path.join(roothg, 'requires'), 'w').write(requirements)
157 file(os.path.join(roothg, 'sharedpath'), 'w').write(sharedpath)
157 file(os.path.join(roothg, 'sharedpath'), 'w').write(sharedpath)
158
158
159 default = srcrepo.ui.config('paths', 'default')
159 default = srcrepo.ui.config('paths', 'default')
160 if default:
160 if default:
161 f = file(os.path.join(roothg, 'hgrc'), 'w')
161 f = file(os.path.join(roothg, 'hgrc'), 'w')
162 f.write('[paths]\ndefault = %s\n' % default)
162 f.write('[paths]\ndefault = %s\n' % default)
163 f.close()
163 f.close()
164
164
165 r = repository(ui, root)
165 r = repository(ui, root)
166
166
167 if update:
167 if update:
168 r.ui.status(_("updating working directory\n"))
168 r.ui.status(_("updating working directory\n"))
169 if update is not True:
169 if update is not True:
170 checkout = update
170 checkout = update
171 for test in (checkout, 'default', 'tip'):
171 for test in (checkout, 'default', 'tip'):
172 if test is None:
172 if test is None:
173 continue
173 continue
174 try:
174 try:
175 uprev = r.lookup(test)
175 uprev = r.lookup(test)
176 break
176 break
177 except error.RepoLookupError:
177 except error.RepoLookupError:
178 continue
178 continue
179 _update(r, uprev)
179 _update(r, uprev)
180
180
181 def clone(ui, source, dest=None, pull=False, rev=None, update=True,
181 def clone(ui, source, dest=None, pull=False, rev=None, update=True,
182 stream=False, branch=None):
182 stream=False, branch=None):
183 """Make a copy of an existing repository.
183 """Make a copy of an existing repository.
184
184
185 Create a copy of an existing repository in a new directory. The
185 Create a copy of an existing repository in a new directory. The
186 source and destination are URLs, as passed to the repository
186 source and destination are URLs, as passed to the repository
187 function. Returns a pair of repository objects, the source and
187 function. Returns a pair of repository objects, the source and
188 newly created destination.
188 newly created destination.
189
189
190 The location of the source is added to the new repository's
190 The location of the source is added to the new repository's
191 .hg/hgrc file, as the default to be used for future pulls and
191 .hg/hgrc file, as the default to be used for future pulls and
192 pushes.
192 pushes.
193
193
194 If an exception is raised, the partly cloned/updated destination
194 If an exception is raised, the partly cloned/updated destination
195 repository will be deleted.
195 repository will be deleted.
196
196
197 Arguments:
197 Arguments:
198
198
199 source: repository object or URL
199 source: repository object or URL
200
200
201 dest: URL of destination repository to create (defaults to base
201 dest: URL of destination repository to create (defaults to base
202 name of source repository)
202 name of source repository)
203
203
204 pull: always pull from source repository, even in local case
204 pull: always pull from source repository, even in local case
205
205
206 stream: stream raw data uncompressed from repository (fast over
206 stream: stream raw data uncompressed from repository (fast over
207 LAN, slow over WAN)
207 LAN, slow over WAN)
208
208
209 rev: revision to clone up to (implies pull=True)
209 rev: revision to clone up to (implies pull=True)
210
210
211 update: update working directory after clone completes, if
211 update: update working directory after clone completes, if
212 destination is local repository (True means update to default rev,
212 destination is local repository (True means update to default rev,
213 anything else is treated as a revision)
213 anything else is treated as a revision)
214
214
215 branch: branches to clone
215 branch: branches to clone
216 """
216 """
217
217
218 if isinstance(source, str):
218 if isinstance(source, str):
219 origsource = ui.expandpath(source)
219 origsource = ui.expandpath(source)
220 source, branch = parseurl(origsource, branch)
220 source, branch = parseurl(origsource, branch)
221 src_repo = repository(ui, source)
221 src_repo = repository(ui, source)
222 else:
222 else:
223 src_repo = source
223 src_repo = source
224 branch = (None, branch or [])
224 branch = (None, branch or [])
225 origsource = source = src_repo.url()
225 origsource = source = src_repo.url()
226 rev, checkout = addbranchrevs(src_repo, src_repo, branch, rev)
226 rev, checkout = addbranchrevs(src_repo, src_repo, branch, rev)
227
227
228 if dest is None:
228 if dest is None:
229 dest = defaultdest(source)
229 dest = defaultdest(source)
230 ui.status(_("destination directory: %s\n") % dest)
230 ui.status(_("destination directory: %s\n") % dest)
231 else:
231 else:
232 dest = ui.expandpath(dest)
232 dest = ui.expandpath(dest)
233
233
234 dest = localpath(dest)
234 dest = localpath(dest)
235 source = localpath(source)
235 source = localpath(source)
236
236
237 if os.path.exists(dest):
237 if os.path.exists(dest):
238 if not os.path.isdir(dest):
238 if not os.path.isdir(dest):
239 raise util.Abort(_("destination '%s' already exists") % dest)
239 raise util.Abort(_("destination '%s' already exists") % dest)
240 elif os.listdir(dest):
240 elif os.listdir(dest):
241 raise util.Abort(_("destination '%s' is not empty") % dest)
241 raise util.Abort(_("destination '%s' is not empty") % dest)
242
242
243 class DirCleanup(object):
243 class DirCleanup(object):
244 def __init__(self, dir_):
244 def __init__(self, dir_):
245 self.rmtree = shutil.rmtree
245 self.rmtree = shutil.rmtree
246 self.dir_ = dir_
246 self.dir_ = dir_
247 def close(self):
247 def close(self):
248 self.dir_ = None
248 self.dir_ = None
249 def cleanup(self):
249 def cleanup(self):
250 if self.dir_:
250 if self.dir_:
251 self.rmtree(self.dir_, True)
251 self.rmtree(self.dir_, True)
252
252
253 src_lock = dest_lock = dir_cleanup = None
253 src_lock = dest_lock = dir_cleanup = None
254 try:
254 try:
255 if islocal(dest):
255 if islocal(dest):
256 dir_cleanup = DirCleanup(dest)
256 dir_cleanup = DirCleanup(dest)
257
257
258 abspath = origsource
258 abspath = origsource
259 copy = False
259 copy = False
260 if src_repo.cancopy() and islocal(dest):
260 if src_repo.cancopy() and islocal(dest):
261 abspath = os.path.abspath(util.drop_scheme('file', origsource))
261 abspath = os.path.abspath(util.drop_scheme('file', origsource))
262 copy = not pull and not rev
262 copy = not pull and not rev
263
263
264 if copy:
264 if copy:
265 try:
265 try:
266 # we use a lock here because if we race with commit, we
266 # we use a lock here because if we race with commit, we
267 # can end up with extra data in the cloned revlogs that's
267 # can end up with extra data in the cloned revlogs that's
268 # not pointed to by changesets, thus causing verify to
268 # not pointed to by changesets, thus causing verify to
269 # fail
269 # fail
270 src_lock = src_repo.lock(wait=False)
270 src_lock = src_repo.lock(wait=False)
271 except error.LockError:
271 except error.LockError:
272 copy = False
272 copy = False
273
273
274 if copy:
274 if copy:
275 src_repo.hook('preoutgoing', throw=True, source='clone')
275 src_repo.hook('preoutgoing', throw=True, source='clone')
276 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
276 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
277 if not os.path.exists(dest):
277 if not os.path.exists(dest):
278 os.mkdir(dest)
278 os.mkdir(dest)
279 else:
279 else:
280 # only clean up directories we create ourselves
280 # only clean up directories we create ourselves
281 dir_cleanup.dir_ = hgdir
281 dir_cleanup.dir_ = hgdir
282 try:
282 try:
283 dest_path = hgdir
283 dest_path = hgdir
284 os.mkdir(dest_path)
284 os.mkdir(dest_path)
285 except OSError, inst:
285 except OSError, inst:
286 if inst.errno == errno.EEXIST:
286 if inst.errno == errno.EEXIST:
287 dir_cleanup.close()
287 dir_cleanup.close()
288 raise util.Abort(_("destination '%s' already exists")
288 raise util.Abort(_("destination '%s' already exists")
289 % dest)
289 % dest)
290 raise
290 raise
291
291
292 hardlink = None
292 hardlink = None
293 num = 0
293 num = 0
294 for f in src_repo.store.copylist():
294 for f in src_repo.store.copylist():
295 src = os.path.join(src_repo.sharedpath, f)
295 src = os.path.join(src_repo.sharedpath, f)
296 dst = os.path.join(dest_path, f)
296 dst = os.path.join(dest_path, f)
297 dstbase = os.path.dirname(dst)
297 dstbase = os.path.dirname(dst)
298 if dstbase and not os.path.exists(dstbase):
298 if dstbase and not os.path.exists(dstbase):
299 os.mkdir(dstbase)
299 os.mkdir(dstbase)
300 if os.path.exists(src):
300 if os.path.exists(src):
301 if dst.endswith('data'):
301 if dst.endswith('data'):
302 # lock to avoid premature writing to the target
302 # lock to avoid premature writing to the target
303 dest_lock = lock.lock(os.path.join(dstbase, "lock"))
303 dest_lock = lock.lock(os.path.join(dstbase, "lock"))
304 hardlink, n = util.copyfiles(src, dst, hardlink)
304 hardlink, n = util.copyfiles(src, dst, hardlink)
305 num += n
305 num += n
306 if hardlink:
306 if hardlink:
307 ui.debug("linked %d files\n" % num)
307 ui.debug("linked %d files\n" % num)
308 else:
308 else:
309 ui.debug("copied %d files\n" % num)
309 ui.debug("copied %d files\n" % num)
310
310
311 # we need to re-init the repo after manually copying the data
311 # we need to re-init the repo after manually copying the data
312 # into it
312 # into it
313 dest_repo = repository(ui, dest)
313 dest_repo = repository(ui, dest)
314 src_repo.hook('outgoing', source='clone',
314 src_repo.hook('outgoing', source='clone',
315 node=node.hex(node.nullid))
315 node=node.hex(node.nullid))
316 else:
316 else:
317 try:
317 try:
318 dest_repo = repository(ui, dest, create=True)
318 dest_repo = repository(ui, dest, create=True)
319 except OSError, inst:
319 except OSError, inst:
320 if inst.errno == errno.EEXIST:
320 if inst.errno == errno.EEXIST:
321 dir_cleanup.close()
321 dir_cleanup.close()
322 raise util.Abort(_("destination '%s' already exists")
322 raise util.Abort(_("destination '%s' already exists")
323 % dest)
323 % dest)
324 raise
324 raise
325
325
326 revs = None
326 revs = None
327 if rev:
327 if rev:
328 if 'lookup' not in src_repo.capabilities:
328 if 'lookup' not in src_repo.capabilities:
329 raise util.Abort(_("src repository does not support "
329 raise util.Abort(_("src repository does not support "
330 "revision lookup and so doesn't "
330 "revision lookup and so doesn't "
331 "support clone by revision"))
331 "support clone by revision"))
332 revs = [src_repo.lookup(r) for r in rev]
332 revs = [src_repo.lookup(r) for r in rev]
333 checkout = revs[0]
333 checkout = revs[0]
334 if dest_repo.local():
334 if dest_repo.local():
335 dest_repo.clone(src_repo, heads=revs, stream=stream)
335 dest_repo.clone(src_repo, heads=revs, stream=stream)
336 elif src_repo.local():
336 elif src_repo.local():
337 src_repo.push(dest_repo, revs=revs)
337 src_repo.push(dest_repo, revs=revs)
338 else:
338 else:
339 raise util.Abort(_("clone from remote to remote not supported"))
339 raise util.Abort(_("clone from remote to remote not supported"))
340
340
341 if dir_cleanup:
341 if dir_cleanup:
342 dir_cleanup.close()
342 dir_cleanup.close()
343
343
344 if dest_repo.local():
344 if dest_repo.local():
345 fp = dest_repo.opener("hgrc", "w", text=True)
345 fp = dest_repo.opener("hgrc", "w", text=True)
346 fp.write("[paths]\n")
346 fp.write("[paths]\n")
347 fp.write("default = %s\n" % abspath)
347 fp.write("default = %s\n" % abspath)
348 fp.close()
348 fp.close()
349
349
350 dest_repo.ui.setconfig('paths', 'default', abspath)
350 dest_repo.ui.setconfig('paths', 'default', abspath)
351
351
352 if update:
352 if update:
353 if update is not True:
353 if update is not True:
354 checkout = update
354 checkout = update
355 if src_repo.local():
355 if src_repo.local():
356 checkout = src_repo.lookup(update)
356 checkout = src_repo.lookup(update)
357 for test in (checkout, 'default', 'tip'):
357 for test in (checkout, 'default', 'tip'):
358 if test is None:
358 if test is None:
359 continue
359 continue
360 try:
360 try:
361 uprev = dest_repo.lookup(test)
361 uprev = dest_repo.lookup(test)
362 break
362 break
363 except error.RepoLookupError:
363 except error.RepoLookupError:
364 continue
364 continue
365 bn = dest_repo[uprev].branch()
365 bn = dest_repo[uprev].branch()
366 dest_repo.ui.status(_("updating to branch %s\n") % bn)
366 dest_repo.ui.status(_("updating to branch %s\n") % bn)
367 _update(dest_repo, uprev)
367 _update(dest_repo, uprev)
368
368
369 # clone all bookmarks
370 if dest_repo.local() and src_repo.capable("pushkey"):
371 rb = src_repo.listkeys('bookmarks')
372 for k, n in rb.iteritems():
373 try:
374 m = dest_repo.lookup(n)
375 dest_repo._bookmarks[k] = m
376 except:
377 pass
378 if rb:
379 bookmarks.write(dest_repo)
380 elif src_repo.local() and dest_repo.capable("pushkey"):
381 for k, n in src_repo._bookmarks.iteritems():
382 dest_repo.pushkey('bookmarks', k, '', hex(n))
383
369 return src_repo, dest_repo
384 return src_repo, dest_repo
370 finally:
385 finally:
371 release(src_lock, dest_lock)
386 release(src_lock, dest_lock)
372 if dir_cleanup is not None:
387 if dir_cleanup is not None:
373 dir_cleanup.cleanup()
388 dir_cleanup.cleanup()
374
389
375 def _showstats(repo, stats):
390 def _showstats(repo, stats):
376 repo.ui.status(_("%d files updated, %d files merged, "
391 repo.ui.status(_("%d files updated, %d files merged, "
377 "%d files removed, %d files unresolved\n") % stats)
392 "%d files removed, %d files unresolved\n") % stats)
378
393
379 def update(repo, node):
394 def update(repo, node):
380 """update the working directory to node, merging linear changes"""
395 """update the working directory to node, merging linear changes"""
381 stats = mergemod.update(repo, node, False, False, None)
396 stats = mergemod.update(repo, node, False, False, None)
382 _showstats(repo, stats)
397 _showstats(repo, stats)
383 if stats[3]:
398 if stats[3]:
384 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
399 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
385 return stats[3] > 0
400 return stats[3] > 0
386
401
387 # naming conflict in clone()
402 # naming conflict in clone()
388 _update = update
403 _update = update
389
404
390 def clean(repo, node, show_stats=True):
405 def clean(repo, node, show_stats=True):
391 """forcibly switch the working directory to node, clobbering changes"""
406 """forcibly switch the working directory to node, clobbering changes"""
392 stats = mergemod.update(repo, node, False, True, None)
407 stats = mergemod.update(repo, node, False, True, None)
393 if show_stats:
408 if show_stats:
394 _showstats(repo, stats)
409 _showstats(repo, stats)
395 return stats[3] > 0
410 return stats[3] > 0
396
411
397 def merge(repo, node, force=None, remind=True):
412 def merge(repo, node, force=None, remind=True):
398 """Branch merge with node, resolving changes. Return true if any
413 """Branch merge with node, resolving changes. Return true if any
399 unresolved conflicts."""
414 unresolved conflicts."""
400 stats = mergemod.update(repo, node, True, force, False)
415 stats = mergemod.update(repo, node, True, force, False)
401 _showstats(repo, stats)
416 _showstats(repo, stats)
402 if stats[3]:
417 if stats[3]:
403 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
418 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
404 "or 'hg update -C .' to abandon\n"))
419 "or 'hg update -C .' to abandon\n"))
405 elif remind:
420 elif remind:
406 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
421 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
407 return stats[3] > 0
422 return stats[3] > 0
408
423
409 def _incoming(displaychlist, subreporecurse, ui, repo, source,
424 def _incoming(displaychlist, subreporecurse, ui, repo, source,
410 opts, buffered=False):
425 opts, buffered=False):
411 """
426 """
412 Helper for incoming / gincoming.
427 Helper for incoming / gincoming.
413 displaychlist gets called with
428 displaychlist gets called with
414 (remoterepo, incomingchangesetlist, displayer) parameters,
429 (remoterepo, incomingchangesetlist, displayer) parameters,
415 and is supposed to contain only code that can't be unified.
430 and is supposed to contain only code that can't be unified.
416 """
431 """
417 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
432 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
418 other = repository(remoteui(repo, opts), source)
433 other = repository(remoteui(repo, opts), source)
419 ui.status(_('comparing with %s\n') % url.hidepassword(source))
434 ui.status(_('comparing with %s\n') % url.hidepassword(source))
420 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
435 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
421
436
422 if revs:
437 if revs:
423 revs = [other.lookup(rev) for rev in revs]
438 revs = [other.lookup(rev) for rev in revs]
424 other, incoming, bundle = bundlerepo.getremotechanges(ui, repo, other, revs,
439 other, incoming, bundle = bundlerepo.getremotechanges(ui, repo, other, revs,
425 opts["bundle"], opts["force"])
440 opts["bundle"], opts["force"])
426 if incoming is None:
441 if incoming is None:
427 ui.status(_("no changes found\n"))
442 ui.status(_("no changes found\n"))
428 return subreporecurse()
443 return subreporecurse()
429
444
430 try:
445 try:
431 chlist = other.changelog.nodesbetween(incoming, revs)[0]
446 chlist = other.changelog.nodesbetween(incoming, revs)[0]
432 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
447 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
433
448
434 # XXX once graphlog extension makes it into core,
449 # XXX once graphlog extension makes it into core,
435 # should be replaced by a if graph/else
450 # should be replaced by a if graph/else
436 displaychlist(other, chlist, displayer)
451 displaychlist(other, chlist, displayer)
437
452
438 displayer.close()
453 displayer.close()
439 finally:
454 finally:
440 if hasattr(other, 'close'):
455 if hasattr(other, 'close'):
441 other.close()
456 other.close()
442 if bundle:
457 if bundle:
443 os.unlink(bundle)
458 os.unlink(bundle)
444 subreporecurse()
459 subreporecurse()
445 return 0 # exit code is zero since we found incoming changes
460 return 0 # exit code is zero since we found incoming changes
446
461
447 def incoming(ui, repo, source, opts):
462 def incoming(ui, repo, source, opts):
448 def subreporecurse():
463 def subreporecurse():
449 ret = 1
464 ret = 1
450 if opts.get('subrepos'):
465 if opts.get('subrepos'):
451 ctx = repo[None]
466 ctx = repo[None]
452 for subpath in sorted(ctx.substate):
467 for subpath in sorted(ctx.substate):
453 sub = ctx.sub(subpath)
468 sub = ctx.sub(subpath)
454 ret = min(ret, sub.incoming(ui, source, opts))
469 ret = min(ret, sub.incoming(ui, source, opts))
455 return ret
470 return ret
456
471
457 def display(other, chlist, displayer):
472 def display(other, chlist, displayer):
458 limit = cmdutil.loglimit(opts)
473 limit = cmdutil.loglimit(opts)
459 if opts.get('newest_first'):
474 if opts.get('newest_first'):
460 chlist.reverse()
475 chlist.reverse()
461 count = 0
476 count = 0
462 for n in chlist:
477 for n in chlist:
463 if limit is not None and count >= limit:
478 if limit is not None and count >= limit:
464 break
479 break
465 parents = [p for p in other.changelog.parents(n) if p != nullid]
480 parents = [p for p in other.changelog.parents(n) if p != nullid]
466 if opts.get('no_merges') and len(parents) == 2:
481 if opts.get('no_merges') and len(parents) == 2:
467 continue
482 continue
468 count += 1
483 count += 1
469 displayer.show(other[n])
484 displayer.show(other[n])
470 return _incoming(display, subreporecurse, ui, repo, source, opts)
485 return _incoming(display, subreporecurse, ui, repo, source, opts)
471
486
472 def _outgoing(ui, repo, dest, opts):
487 def _outgoing(ui, repo, dest, opts):
473 dest = ui.expandpath(dest or 'default-push', dest or 'default')
488 dest = ui.expandpath(dest or 'default-push', dest or 'default')
474 dest, branches = parseurl(dest, opts.get('branch'))
489 dest, branches = parseurl(dest, opts.get('branch'))
475 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
490 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
476 if revs:
491 if revs:
477 revs = [repo.lookup(rev) for rev in revs]
492 revs = [repo.lookup(rev) for rev in revs]
478
493
479 other = repository(remoteui(repo, opts), dest)
494 other = repository(remoteui(repo, opts), dest)
480 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
495 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
481 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
496 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
482 if not o:
497 if not o:
483 ui.status(_("no changes found\n"))
498 ui.status(_("no changes found\n"))
484 return None
499 return None
485
500
486 return repo.changelog.nodesbetween(o, revs)[0]
501 return repo.changelog.nodesbetween(o, revs)[0]
487
502
488 def outgoing(ui, repo, dest, opts):
503 def outgoing(ui, repo, dest, opts):
489 def recurse():
504 def recurse():
490 ret = 1
505 ret = 1
491 if opts.get('subrepos'):
506 if opts.get('subrepos'):
492 ctx = repo[None]
507 ctx = repo[None]
493 for subpath in sorted(ctx.substate):
508 for subpath in sorted(ctx.substate):
494 sub = ctx.sub(subpath)
509 sub = ctx.sub(subpath)
495 ret = min(ret, sub.outgoing(ui, dest, opts))
510 ret = min(ret, sub.outgoing(ui, dest, opts))
496 return ret
511 return ret
497
512
498 limit = cmdutil.loglimit(opts)
513 limit = cmdutil.loglimit(opts)
499 o = _outgoing(ui, repo, dest, opts)
514 o = _outgoing(ui, repo, dest, opts)
500 if o is None:
515 if o is None:
501 return recurse()
516 return recurse()
502
517
503 if opts.get('newest_first'):
518 if opts.get('newest_first'):
504 o.reverse()
519 o.reverse()
505 displayer = cmdutil.show_changeset(ui, repo, opts)
520 displayer = cmdutil.show_changeset(ui, repo, opts)
506 count = 0
521 count = 0
507 for n in o:
522 for n in o:
508 if limit is not None and count >= limit:
523 if limit is not None and count >= limit:
509 break
524 break
510 parents = [p for p in repo.changelog.parents(n) if p != nullid]
525 parents = [p for p in repo.changelog.parents(n) if p != nullid]
511 if opts.get('no_merges') and len(parents) == 2:
526 if opts.get('no_merges') and len(parents) == 2:
512 continue
527 continue
513 count += 1
528 count += 1
514 displayer.show(repo[n])
529 displayer.show(repo[n])
515 displayer.close()
530 displayer.close()
516 recurse()
531 recurse()
517 return 0 # exit code is zero since we found outgoing changes
532 return 0 # exit code is zero since we found outgoing changes
518
533
519 def revert(repo, node, choose):
534 def revert(repo, node, choose):
520 """revert changes to revision in node without updating dirstate"""
535 """revert changes to revision in node without updating dirstate"""
521 return mergemod.update(repo, node, False, True, choose)[3] > 0
536 return mergemod.update(repo, node, False, True, choose)[3] > 0
522
537
523 def verify(repo):
538 def verify(repo):
524 """verify the consistency of a repository"""
539 """verify the consistency of a repository"""
525 return verifymod.verify(repo)
540 return verifymod.verify(repo)
526
541
527 def remoteui(src, opts):
542 def remoteui(src, opts):
528 'build a remote ui from ui or repo and opts'
543 'build a remote ui from ui or repo and opts'
529 if hasattr(src, 'baseui'): # looks like a repository
544 if hasattr(src, 'baseui'): # looks like a repository
530 dst = src.baseui.copy() # drop repo-specific config
545 dst = src.baseui.copy() # drop repo-specific config
531 src = src.ui # copy target options from repo
546 src = src.ui # copy target options from repo
532 else: # assume it's a global ui object
547 else: # assume it's a global ui object
533 dst = src.copy() # keep all global options
548 dst = src.copy() # keep all global options
534
549
535 # copy ssh-specific options
550 # copy ssh-specific options
536 for o in 'ssh', 'remotecmd':
551 for o in 'ssh', 'remotecmd':
537 v = opts.get(o) or src.config('ui', o)
552 v = opts.get(o) or src.config('ui', o)
538 if v:
553 if v:
539 dst.setconfig("ui", o, v)
554 dst.setconfig("ui", o, v)
540
555
541 # copy bundle-specific options
556 # copy bundle-specific options
542 r = src.config('bundle', 'mainreporoot')
557 r = src.config('bundle', 'mainreporoot')
543 if r:
558 if r:
544 dst.setconfig('bundle', 'mainreporoot', r)
559 dst.setconfig('bundle', 'mainreporoot', r)
545
560
546 # copy selected local settings to the remote ui
561 # copy selected local settings to the remote ui
547 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
562 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
548 for key, val in src.configitems(sect):
563 for key, val in src.configitems(sect):
549 dst.setconfig(sect, key, val)
564 dst.setconfig(sect, key, val)
550 v = src.config('web', 'cacerts')
565 v = src.config('web', 'cacerts')
551 if v:
566 if v:
552 dst.setconfig('web', 'cacerts', util.expandpath(v))
567 dst.setconfig('web', 'cacerts', util.expandpath(v))
553
568
554 return dst
569 return dst
@@ -1,180 +1,194 b''
1 initialize
1 initialize
2
2
3 $ hg init a
3 $ hg init a
4 $ cd a
4 $ cd a
5 $ echo 'test' > test
5 $ echo 'test' > test
6 $ hg commit -Am'test'
6 $ hg commit -Am'test'
7 adding test
7 adding test
8
8
9 set bookmarks
9 set bookmarks
10
10
11 $ hg bookmark X
11 $ hg bookmark X
12 $ hg bookmark Y
12 $ hg bookmark Y
13 $ hg bookmark Z
13 $ hg bookmark Z
14
14
15 import bookmark by name
15 import bookmark by name
16
16
17 $ hg init ../b
17 $ hg init ../b
18 $ cd ../b
18 $ cd ../b
19 $ hg book Y
19 $ hg book Y
20 $ hg book
20 $ hg book
21 * Y -1:000000000000
21 * Y -1:000000000000
22 $ hg pull ../a
22 $ hg pull ../a
23 pulling from ../a
23 pulling from ../a
24 requesting all changes
24 requesting all changes
25 adding changesets
25 adding changesets
26 adding manifests
26 adding manifests
27 adding file changes
27 adding file changes
28 added 1 changesets with 1 changes to 1 files
28 added 1 changesets with 1 changes to 1 files
29 (run 'hg update' to get a working copy)
29 (run 'hg update' to get a working copy)
30 $ hg bookmarks
30 $ hg bookmarks
31 Y 0:4e3505fd9583
31 Y 0:4e3505fd9583
32 $ hg debugpushkey ../a namespaces
32 $ hg debugpushkey ../a namespaces
33 bookmarks
33 bookmarks
34 namespaces
34 namespaces
35 $ hg debugpushkey ../a bookmarks
35 $ hg debugpushkey ../a bookmarks
36 Y 4e3505fd95835d721066b76e75dbb8cc554d7f77
36 Y 4e3505fd95835d721066b76e75dbb8cc554d7f77
37 X 4e3505fd95835d721066b76e75dbb8cc554d7f77
37 X 4e3505fd95835d721066b76e75dbb8cc554d7f77
38 Z 4e3505fd95835d721066b76e75dbb8cc554d7f77
38 Z 4e3505fd95835d721066b76e75dbb8cc554d7f77
39 $ hg pull -B X ../a
39 $ hg pull -B X ../a
40 pulling from ../a
40 pulling from ../a
41 searching for changes
41 searching for changes
42 no changes found
42 no changes found
43 importing bookmark X
43 importing bookmark X
44 $ hg bookmark
44 $ hg bookmark
45 X 0:4e3505fd9583
45 X 0:4e3505fd9583
46 Y 0:4e3505fd9583
46 Y 0:4e3505fd9583
47
47
48 export bookmark by name
48 export bookmark by name
49
49
50 $ hg bookmark W
50 $ hg bookmark W
51 $ hg bookmark foo
51 $ hg bookmark foo
52 $ hg bookmark foobar
52 $ hg bookmark foobar
53 $ hg push -B W ../a
53 $ hg push -B W ../a
54 pushing to ../a
54 pushing to ../a
55 searching for changes
55 searching for changes
56 no changes found
56 no changes found
57 exporting bookmark W
57 exporting bookmark W
58 $ hg -R ../a bookmarks
58 $ hg -R ../a bookmarks
59 W -1:000000000000
59 W -1:000000000000
60 X 0:4e3505fd9583
60 X 0:4e3505fd9583
61 Y 0:4e3505fd9583
61 Y 0:4e3505fd9583
62 * Z 0:4e3505fd9583
62 * Z 0:4e3505fd9583
63
63
64 delete a remote bookmark
64 delete a remote bookmark
65
65
66 $ hg book -d W
66 $ hg book -d W
67 $ hg push -B W ../a
67 $ hg push -B W ../a
68 pushing to ../a
68 pushing to ../a
69 searching for changes
69 searching for changes
70 no changes found
70 no changes found
71 deleting remote bookmark W
71 deleting remote bookmark W
72
72
73 push/pull name that doesn't exist
73 push/pull name that doesn't exist
74
74
75 $ hg push -B badname ../a
75 $ hg push -B badname ../a
76 pushing to ../a
76 pushing to ../a
77 searching for changes
77 searching for changes
78 no changes found
78 no changes found
79 bookmark badname does not exist on the local or remote repository!
79 bookmark badname does not exist on the local or remote repository!
80 [2]
80 [2]
81 $ hg pull -B anotherbadname ../a
81 $ hg pull -B anotherbadname ../a
82 pulling from ../a
82 pulling from ../a
83 abort: remote bookmark anotherbadname not found!
83 abort: remote bookmark anotherbadname not found!
84 [255]
84 [255]
85
85
86 divergent bookmarks
86 divergent bookmarks
87
87
88 $ cd ../a
88 $ cd ../a
89 $ echo c1 > f1
89 $ echo c1 > f1
90 $ hg ci -Am1
90 $ hg ci -Am1
91 adding f1
91 adding f1
92 $ hg book -f X
92 $ hg book -f X
93 $ hg book
93 $ hg book
94 * X 1:0d2164f0ce0d
94 * X 1:0d2164f0ce0d
95 Y 0:4e3505fd9583
95 Y 0:4e3505fd9583
96 Z 1:0d2164f0ce0d
96 Z 1:0d2164f0ce0d
97
97
98 $ cd ../b
98 $ cd ../b
99 $ hg up
99 $ hg up
100 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
100 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
101 $ echo c2 > f2
101 $ echo c2 > f2
102 $ hg ci -Am2
102 $ hg ci -Am2
103 adding f2
103 adding f2
104 $ hg book -f X
104 $ hg book -f X
105 $ hg book
105 $ hg book
106 * X 1:9b140be10808
106 * X 1:9b140be10808
107 Y 0:4e3505fd9583
107 Y 0:4e3505fd9583
108 foo -1:000000000000
108 foo -1:000000000000
109 foobar -1:000000000000
109 foobar -1:000000000000
110
110
111 $ hg pull ../a
111 $ hg pull ../a
112 pulling from ../a
112 pulling from ../a
113 searching for changes
113 searching for changes
114 adding changesets
114 adding changesets
115 adding manifests
115 adding manifests
116 adding file changes
116 adding file changes
117 added 1 changesets with 1 changes to 1 files (+1 heads)
117 added 1 changesets with 1 changes to 1 files (+1 heads)
118 not updating divergent bookmark X
118 not updating divergent bookmark X
119 (run 'hg heads' to see heads, 'hg merge' to merge)
119 (run 'hg heads' to see heads, 'hg merge' to merge)
120 $ hg book
120 $ hg book
121 * X 1:9b140be10808
121 * X 1:9b140be10808
122 Y 0:4e3505fd9583
122 Y 0:4e3505fd9583
123 foo -1:000000000000
123 foo -1:000000000000
124 foobar -1:000000000000
124 foobar -1:000000000000
125 $ hg push -f ../a
125 $ hg push -f ../a
126 pushing to ../a
126 pushing to ../a
127 searching for changes
127 searching for changes
128 adding changesets
128 adding changesets
129 adding manifests
129 adding manifests
130 adding file changes
130 adding file changes
131 added 1 changesets with 1 changes to 1 files (+1 heads)
131 added 1 changesets with 1 changes to 1 files (+1 heads)
132 $ hg -R ../a book
132 $ hg -R ../a book
133 * X 1:0d2164f0ce0d
133 * X 1:0d2164f0ce0d
134 Y 0:4e3505fd9583
134 Y 0:4e3505fd9583
135 Z 1:0d2164f0ce0d
135 Z 1:0d2164f0ce0d
136
136
137 hgweb
137 hgweb
138
138
139 $ cat <<EOF > .hg/hgrc
139 $ cat <<EOF > .hg/hgrc
140 > [web]
140 > [web]
141 > push_ssl = false
141 > push_ssl = false
142 > allow_push = *
142 > allow_push = *
143 > EOF
143 > EOF
144
144
145 $ hg serve -p $HGPORT -d --pid-file=../hg.pid -E errors.log
145 $ hg serve -p $HGPORT -d --pid-file=../hg.pid -E errors.log
146 $ cat ../hg.pid >> $DAEMON_PIDS
146 $ cat ../hg.pid >> $DAEMON_PIDS
147 $ cd ../a
147 $ cd ../a
148
148
149 $ hg debugpushkey http://localhost:$HGPORT/ namespaces
149 $ hg debugpushkey http://localhost:$HGPORT/ namespaces
150 bookmarks
150 bookmarks
151 namespaces
151 namespaces
152 $ hg debugpushkey http://localhost:$HGPORT/ bookmarks
152 $ hg debugpushkey http://localhost:$HGPORT/ bookmarks
153 Y 4e3505fd95835d721066b76e75dbb8cc554d7f77
153 Y 4e3505fd95835d721066b76e75dbb8cc554d7f77
154 X 9b140be1080824d768c5a4691a564088eede71f9
154 X 9b140be1080824d768c5a4691a564088eede71f9
155 foo 0000000000000000000000000000000000000000
155 foo 0000000000000000000000000000000000000000
156 foobar 0000000000000000000000000000000000000000
156 foobar 0000000000000000000000000000000000000000
157 $ hg out -B http://localhost:$HGPORT/
157 $ hg out -B http://localhost:$HGPORT/
158 comparing with http://localhost:$HGPORT/
158 comparing with http://localhost:$HGPORT/
159 searching for changed bookmarks
159 searching for changed bookmarks
160 Z 0d2164f0ce0d
160 Z 0d2164f0ce0d
161 $ hg push -B Z http://localhost:$HGPORT/
161 $ hg push -B Z http://localhost:$HGPORT/
162 pushing to http://localhost:$HGPORT/
162 pushing to http://localhost:$HGPORT/
163 searching for changes
163 searching for changes
164 no changes found
164 no changes found
165 exporting bookmark Z
165 exporting bookmark Z
166 $ hg book -d Z
166 $ hg book -d Z
167 $ hg in -B http://localhost:$HGPORT/
167 $ hg in -B http://localhost:$HGPORT/
168 comparing with http://localhost:$HGPORT/
168 comparing with http://localhost:$HGPORT/
169 searching for changed bookmarks
169 searching for changed bookmarks
170 Z 0d2164f0ce0d
170 Z 0d2164f0ce0d
171 foo 000000000000
171 foo 000000000000
172 foobar 000000000000
172 foobar 000000000000
173 $ hg pull -B Z http://localhost:$HGPORT/
173 $ hg pull -B Z http://localhost:$HGPORT/
174 pulling from http://localhost:$HGPORT/
174 pulling from http://localhost:$HGPORT/
175 searching for changes
175 searching for changes
176 no changes found
176 no changes found
177 not updating divergent bookmark X
177 not updating divergent bookmark X
178 importing bookmark Z
178 importing bookmark Z
179 $ hg clone http://localhost:$HGPORT/ cloned-bookmarks
180 requesting all changes
181 adding changesets
182 adding manifests
183 adding file changes
184 added 3 changesets with 3 changes to 3 files (+1 heads)
185 updating to branch default
186 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
187 $ hg -R cloned-bookmarks bookmarks
188 X 1:9b140be10808
189 Y 0:4e3505fd9583
190 Z 2:0d2164f0ce0d
191 foo -1:000000000000
192 foobar -1:000000000000
179
193
180 $ kill `cat ../hg.pid`
194 $ kill `cat ../hg.pid`
@@ -1,246 +1,290 b''
1 $ hg init
1 $ hg init
2
2
3 no bookmarks
3 no bookmarks
4
4
5 $ hg bookmarks
5 $ hg bookmarks
6 no bookmarks set
6 no bookmarks set
7
7
8 bookmark rev -1
8 bookmark rev -1
9
9
10 $ hg bookmark X
10 $ hg bookmark X
11
11
12 list bookmarks
12 list bookmarks
13
13
14 $ hg bookmarks
14 $ hg bookmarks
15 * X -1:000000000000
15 * X -1:000000000000
16
16
17 list bookmarks with color
17 list bookmarks with color
18
18
19 $ hg --config extensions.color= --config color.mode=ansi \
19 $ hg --config extensions.color= --config color.mode=ansi \
20 > bookmarks --color=always
20 > bookmarks --color=always
21 \x1b[0;32m * X -1:000000000000\x1b[0m (esc)
21 \x1b[0;32m * X -1:000000000000\x1b[0m (esc)
22
22
23 $ echo a > a
23 $ echo a > a
24 $ hg add a
24 $ hg add a
25 $ hg commit -m 0
25 $ hg commit -m 0
26
26
27 bookmark X moved to rev 0
27 bookmark X moved to rev 0
28
28
29 $ hg bookmarks
29 $ hg bookmarks
30 * X 0:f7b1eb17ad24
30 * X 0:f7b1eb17ad24
31
31
32 look up bookmark
32 look up bookmark
33
33
34 $ hg log -r X
34 $ hg log -r X
35 changeset: 0:f7b1eb17ad24
35 changeset: 0:f7b1eb17ad24
36 bookmark: X
36 bookmark: X
37 tag: tip
37 tag: tip
38 user: test
38 user: test
39 date: Thu Jan 01 00:00:00 1970 +0000
39 date: Thu Jan 01 00:00:00 1970 +0000
40 summary: 0
40 summary: 0
41
41
42
42
43 second bookmark for rev 0
43 second bookmark for rev 0
44
44
45 $ hg bookmark X2
45 $ hg bookmark X2
46
46
47 bookmark rev -1 again
47 bookmark rev -1 again
48
48
49 $ hg bookmark -r null Y
49 $ hg bookmark -r null Y
50
50
51 list bookmarks
51 list bookmarks
52
52
53 $ hg bookmarks
53 $ hg bookmarks
54 X 0:f7b1eb17ad24
54 X 0:f7b1eb17ad24
55 * X2 0:f7b1eb17ad24
55 * X2 0:f7b1eb17ad24
56 Y -1:000000000000
56 Y -1:000000000000
57
57
58 $ echo b > b
58 $ echo b > b
59 $ hg add b
59 $ hg add b
60 $ hg commit -m 1
60 $ hg commit -m 1
61
61
62 bookmarks revset
62 bookmarks revset
63
63
64 $ hg log -r 'bookmark()'
64 $ hg log -r 'bookmark()'
65 changeset: 0:f7b1eb17ad24
65 changeset: 0:f7b1eb17ad24
66 bookmark: X
66 bookmark: X
67 user: test
67 user: test
68 date: Thu Jan 01 00:00:00 1970 +0000
68 date: Thu Jan 01 00:00:00 1970 +0000
69 summary: 0
69 summary: 0
70
70
71 changeset: 1:925d80f479bb
71 changeset: 1:925d80f479bb
72 bookmark: X2
72 bookmark: X2
73 tag: tip
73 tag: tip
74 user: test
74 user: test
75 date: Thu Jan 01 00:00:00 1970 +0000
75 date: Thu Jan 01 00:00:00 1970 +0000
76 summary: 1
76 summary: 1
77
77
78 $ hg log -r 'bookmark(Y)'
78 $ hg log -r 'bookmark(Y)'
79 $ hg log -r 'bookmark(X2)'
79 $ hg log -r 'bookmark(X2)'
80 changeset: 1:925d80f479bb
80 changeset: 1:925d80f479bb
81 bookmark: X2
81 bookmark: X2
82 tag: tip
82 tag: tip
83 user: test
83 user: test
84 date: Thu Jan 01 00:00:00 1970 +0000
84 date: Thu Jan 01 00:00:00 1970 +0000
85 summary: 1
85 summary: 1
86
86
87 $ hg help revsets | grep 'bookmark('
87 $ hg help revsets | grep 'bookmark('
88 "bookmark([name])"
88 "bookmark([name])"
89
89
90 bookmarks X and X2 moved to rev 1, Y at rev -1
90 bookmarks X and X2 moved to rev 1, Y at rev -1
91
91
92 $ hg bookmarks
92 $ hg bookmarks
93 X 0:f7b1eb17ad24
93 X 0:f7b1eb17ad24
94 * X2 1:925d80f479bb
94 * X2 1:925d80f479bb
95 Y -1:000000000000
95 Y -1:000000000000
96
96
97 bookmark rev 0 again
97 bookmark rev 0 again
98
98
99 $ hg bookmark -r 0 Z
99 $ hg bookmark -r 0 Z
100
100
101 $ hg update X
101 $ hg update X
102 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
102 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
103 $ echo c > c
103 $ echo c > c
104 $ hg add c
104 $ hg add c
105 $ hg commit -m 2
105 $ hg commit -m 2
106 created new head
106 created new head
107
107
108 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
108 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
109
109
110 $ hg bookmarks
110 $ hg bookmarks
111 * X 2:db815d6d32e6
111 * X 2:db815d6d32e6
112 X2 1:925d80f479bb
112 X2 1:925d80f479bb
113 Y -1:000000000000
113 Y -1:000000000000
114 Z 0:f7b1eb17ad24
114 Z 0:f7b1eb17ad24
115
115
116 rename nonexistent bookmark
116 rename nonexistent bookmark
117
117
118 $ hg bookmark -m A B
118 $ hg bookmark -m A B
119 abort: a bookmark of this name does not exist
119 abort: a bookmark of this name does not exist
120 [255]
120 [255]
121
121
122 rename to existent bookmark
122 rename to existent bookmark
123
123
124 $ hg bookmark -m X Y
124 $ hg bookmark -m X Y
125 abort: a bookmark of the same name already exists
125 abort: a bookmark of the same name already exists
126 [255]
126 [255]
127
127
128 force rename to existent bookmark
128 force rename to existent bookmark
129
129
130 $ hg bookmark -f -m X Y
130 $ hg bookmark -f -m X Y
131
131
132 list bookmarks
132 list bookmarks
133
133
134 $ hg bookmark
134 $ hg bookmark
135 X2 1:925d80f479bb
135 X2 1:925d80f479bb
136 * Y 2:db815d6d32e6
136 * Y 2:db815d6d32e6
137 Z 0:f7b1eb17ad24
137 Z 0:f7b1eb17ad24
138
138
139 rename without new name
139 rename without new name
140
140
141 $ hg bookmark -m Y
141 $ hg bookmark -m Y
142 abort: new bookmark name required
142 abort: new bookmark name required
143 [255]
143 [255]
144
144
145 delete without name
145 delete without name
146
146
147 $ hg bookmark -d
147 $ hg bookmark -d
148 abort: bookmark name required
148 abort: bookmark name required
149 [255]
149 [255]
150
150
151 delete nonexistent bookmark
151 delete nonexistent bookmark
152
152
153 $ hg bookmark -d A
153 $ hg bookmark -d A
154 abort: a bookmark of this name does not exist
154 abort: a bookmark of this name does not exist
155 [255]
155 [255]
156
156
157 bookmark name with spaces should be stripped
157 bookmark name with spaces should be stripped
158
158
159 $ hg bookmark ' x y '
159 $ hg bookmark ' x y '
160
160
161 list bookmarks
161 list bookmarks
162
162
163 $ hg bookmarks
163 $ hg bookmarks
164 X2 1:925d80f479bb
164 X2 1:925d80f479bb
165 Y 2:db815d6d32e6
165 Y 2:db815d6d32e6
166 Z 0:f7b1eb17ad24
166 Z 0:f7b1eb17ad24
167 * x y 2:db815d6d32e6
167 * x y 2:db815d6d32e6
168
168
169 look up stripped bookmark name
169 look up stripped bookmark name
170
170
171 $ hg log -r '"x y"'
171 $ hg log -r '"x y"'
172 changeset: 2:db815d6d32e6
172 changeset: 2:db815d6d32e6
173 bookmark: Y
173 bookmark: Y
174 bookmark: x y
174 bookmark: x y
175 tag: tip
175 tag: tip
176 parent: 0:f7b1eb17ad24
176 parent: 0:f7b1eb17ad24
177 user: test
177 user: test
178 date: Thu Jan 01 00:00:00 1970 +0000
178 date: Thu Jan 01 00:00:00 1970 +0000
179 summary: 2
179 summary: 2
180
180
181
181
182 reject bookmark name with newline
182 reject bookmark name with newline
183
183
184 $ hg bookmark '
184 $ hg bookmark '
185 > '
185 > '
186 abort: bookmark name cannot contain newlines
186 abort: bookmark name cannot contain newlines
187 [255]
187 [255]
188
188
189 bookmark with existing name
189 bookmark with existing name
190
190
191 $ hg bookmark Z
191 $ hg bookmark Z
192 abort: a bookmark of the same name already exists
192 abort: a bookmark of the same name already exists
193 [255]
193 [255]
194
194
195 force bookmark with existing name
195 force bookmark with existing name
196
196
197 $ hg bookmark -f Z
197 $ hg bookmark -f Z
198
198
199 list bookmarks
199 list bookmarks
200
200
201 $ hg bookmark
201 $ hg bookmark
202 X2 1:925d80f479bb
202 X2 1:925d80f479bb
203 Y 2:db815d6d32e6
203 Y 2:db815d6d32e6
204 * Z 2:db815d6d32e6
204 * Z 2:db815d6d32e6
205 x y 2:db815d6d32e6
205 x y 2:db815d6d32e6
206
206
207 revision but no bookmark name
207 revision but no bookmark name
208
208
209 $ hg bookmark -r .
209 $ hg bookmark -r .
210 abort: bookmark name required
210 abort: bookmark name required
211 [255]
211 [255]
212
212
213 bookmark name with whitespace only
213 bookmark name with whitespace only
214
214
215 $ hg bookmark ' '
215 $ hg bookmark ' '
216 abort: bookmark names cannot consist entirely of whitespace
216 abort: bookmark names cannot consist entirely of whitespace
217 [255]
217 [255]
218
218
219 invalid bookmark
219 invalid bookmark
220
220
221 $ hg bookmark 'foo:bar'
221 $ hg bookmark 'foo:bar'
222 abort: bookmark 'foo:bar' contains illegal character
222 abort: bookmark 'foo:bar' contains illegal character
223 [255]
223 [255]
224
224
225 the bookmark extension should be ignored now that it is part of core
225 the bookmark extension should be ignored now that it is part of core
226
226
227 $ echo "[extensions]" >> $HGRCPATH
227 $ echo "[extensions]" >> $HGRCPATH
228 $ echo "bookmarks=" >> $HGRCPATH
228 $ echo "bookmarks=" >> $HGRCPATH
229 $ hg bookmarks
229 $ hg bookmarks
230 X2 1:925d80f479bb
230 X2 1:925d80f479bb
231 Y 2:db815d6d32e6
231 Y 2:db815d6d32e6
232 * Z 2:db815d6d32e6
232 * Z 2:db815d6d32e6
233 x y 2:db815d6d32e6
233 x y 2:db815d6d32e6
234 test summary
234 test summary
235
235
236 $ hg summary
236 $ hg summary
237 parent: 2:db815d6d32e6 tip Y Z x y
237 parent: 2:db815d6d32e6 tip Y Z x y
238 2
238 2
239 branch: default
239 branch: default
240 commit: (clean)
240 commit: (clean)
241 update: 1 new changesets, 2 branch heads (merge)
241 update: 1 new changesets, 2 branch heads (merge)
242
242
243 test id
243 test id
244
244
245 $ hg id
245 $ hg id
246 db815d6d32e6 tip Y/Z/x y
246 db815d6d32e6 tip Y/Z/x y
247
248 test clone
249
250 $ hg bookmarks
251 X2 1:925d80f479bb
252 Y 2:db815d6d32e6
253 * Z 2:db815d6d32e6
254 x y 2:db815d6d32e6
255 $ hg clone . cloned-bookmarks
256 updating to branch default
257 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
258 $ hg -R cloned-bookmarks bookmarks
259 X2 1:925d80f479bb
260 Y 2:db815d6d32e6
261 Z 2:db815d6d32e6
262 x y 2:db815d6d32e6
263
264 test clone with pull protocol
265
266 $ hg clone --pull . cloned-bookmarks-pull
267 requesting all changes
268 adding changesets
269 adding manifests
270 adding file changes
271 added 3 changesets with 3 changes to 3 files (+1 heads)
272 updating to branch default
273 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
274 $ hg -R cloned-bookmarks-pull bookmarks
275 X2 1:925d80f479bb
276 Y 2:db815d6d32e6
277 Z 2:db815d6d32e6
278 x y 2:db815d6d32e6
279
280 test clone with a specific revision
281
282 $ hg clone -r 925d80 . cloned-bookmarks-rev
283 adding changesets
284 adding manifests
285 adding file changes
286 added 2 changesets with 2 changes to 2 files
287 updating to branch default
288 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
289 $ hg -R cloned-bookmarks-rev bookmarks
290 X2 1:925d80f479bb
@@ -1,201 +1,215 b''
1 This test tries to exercise the ssh functionality with a dummy script
1 This test tries to exercise the ssh functionality with a dummy script
2
2
3 $ cat <<EOF > dummyssh
3 $ cat <<EOF > dummyssh
4 > import sys
4 > import sys
5 > import os
5 > import os
6 >
6 >
7 > os.chdir(os.path.dirname(sys.argv[0]))
7 > os.chdir(os.path.dirname(sys.argv[0]))
8 > if sys.argv[1] != "user@dummy":
8 > if sys.argv[1] != "user@dummy":
9 > sys.exit(-1)
9 > sys.exit(-1)
10 >
10 >
11 > if not os.path.exists("dummyssh"):
11 > if not os.path.exists("dummyssh"):
12 > sys.exit(-1)
12 > sys.exit(-1)
13 >
13 >
14 > log = open("dummylog", "ab")
14 > log = open("dummylog", "ab")
15 > log.write("Got arguments")
15 > log.write("Got arguments")
16 > for i, arg in enumerate(sys.argv[1:]):
16 > for i, arg in enumerate(sys.argv[1:]):
17 > log.write(" %d:%s" % (i+1, arg))
17 > log.write(" %d:%s" % (i+1, arg))
18 > log.write("\n")
18 > log.write("\n")
19 > log.close()
19 > log.close()
20 > r = os.system(sys.argv[2])
20 > r = os.system(sys.argv[2])
21 > sys.exit(bool(r))
21 > sys.exit(bool(r))
22 > EOF
22 > EOF
23
23
24 $ checknewrepo()
24 $ checknewrepo()
25 > {
25 > {
26 > name=$1
26 > name=$1
27 > if [ -d "$name"/.hg/store ]; then
27 > if [ -d "$name"/.hg/store ]; then
28 > echo store created
28 > echo store created
29 > fi
29 > fi
30 > if [ -f "$name"/.hg/00changelog.i ]; then
30 > if [ -f "$name"/.hg/00changelog.i ]; then
31 > echo 00changelog.i created
31 > echo 00changelog.i created
32 > fi
32 > fi
33 > cat "$name"/.hg/requires
33 > cat "$name"/.hg/requires
34 > }
34 > }
35
35
36 creating 'local'
36 creating 'local'
37
37
38 $ hg init local
38 $ hg init local
39 $ checknewrepo local
39 $ checknewrepo local
40 store created
40 store created
41 00changelog.i created
41 00changelog.i created
42 revlogv1
42 revlogv1
43 store
43 store
44 fncache
44 fncache
45 dotencode
45 dotencode
46 $ echo this > local/foo
46 $ echo this > local/foo
47 $ hg ci --cwd local -A -m "init"
47 $ hg ci --cwd local -A -m "init"
48 adding foo
48 adding foo
49
49
50 creating repo with format.usestore=false
50 creating repo with format.usestore=false
51
51
52 $ hg --config format.usestore=false init old
52 $ hg --config format.usestore=false init old
53 $ checknewrepo old
53 $ checknewrepo old
54 revlogv1
54 revlogv1
55
55
56 creating repo with format.usefncache=false
56 creating repo with format.usefncache=false
57
57
58 $ hg --config format.usefncache=false init old2
58 $ hg --config format.usefncache=false init old2
59 $ checknewrepo old2
59 $ checknewrepo old2
60 store created
60 store created
61 00changelog.i created
61 00changelog.i created
62 revlogv1
62 revlogv1
63 store
63 store
64
64
65 creating repo with format.dotencode=false
65 creating repo with format.dotencode=false
66
66
67 $ hg --config format.dotencode=false init old3
67 $ hg --config format.dotencode=false init old3
68 $ checknewrepo old3
68 $ checknewrepo old3
69 store created
69 store created
70 00changelog.i created
70 00changelog.i created
71 revlogv1
71 revlogv1
72 store
72 store
73 fncache
73 fncache
74
74
75 test failure
75 test failure
76
76
77 $ hg init local
77 $ hg init local
78 abort: repository local already exists!
78 abort: repository local already exists!
79 [255]
79 [255]
80
80
81 init+push to remote2
81 init+push to remote2
82
82
83 $ hg init -e "python ./dummyssh" ssh://user@dummy/remote2
83 $ hg init -e "python ./dummyssh" ssh://user@dummy/remote2
84 $ hg incoming -R remote2 local
84 $ hg incoming -R remote2 local
85 comparing with local
85 comparing with local
86 changeset: 0:08b9e9f63b32
86 changeset: 0:08b9e9f63b32
87 tag: tip
87 tag: tip
88 user: test
88 user: test
89 date: Thu Jan 01 00:00:00 1970 +0000
89 date: Thu Jan 01 00:00:00 1970 +0000
90 summary: init
90 summary: init
91
91
92
92
93 $ hg push -R local -e "python ./dummyssh" ssh://user@dummy/remote2
93 $ hg push -R local -e "python ./dummyssh" ssh://user@dummy/remote2
94 pushing to ssh://user@dummy/remote2
94 pushing to ssh://user@dummy/remote2
95 searching for changes
95 searching for changes
96 remote: adding changesets
96 remote: adding changesets
97 remote: adding manifests
97 remote: adding manifests
98 remote: adding file changes
98 remote: adding file changes
99 remote: added 1 changesets with 1 changes to 1 files
99 remote: added 1 changesets with 1 changes to 1 files
100
100
101 clone to remote1
101 clone to remote1
102
102
103 $ hg clone -e "python ./dummyssh" local ssh://user@dummy/remote1
103 $ hg clone -e "python ./dummyssh" local ssh://user@dummy/remote1
104 searching for changes
104 searching for changes
105 remote: adding changesets
105 remote: adding changesets
106 remote: adding manifests
106 remote: adding manifests
107 remote: adding file changes
107 remote: adding file changes
108 remote: added 1 changesets with 1 changes to 1 files
108 remote: added 1 changesets with 1 changes to 1 files
109
109
110 init to existing repo
110 init to existing repo
111
111
112 $ hg init -e "python ./dummyssh" ssh://user@dummy/remote1
112 $ hg init -e "python ./dummyssh" ssh://user@dummy/remote1
113 abort: repository remote1 already exists!
113 abort: repository remote1 already exists!
114 abort: could not create remote repo!
114 abort: could not create remote repo!
115 [255]
115 [255]
116
116
117 clone to existing repo
117 clone to existing repo
118
118
119 $ hg clone -e "python ./dummyssh" local ssh://user@dummy/remote1
119 $ hg clone -e "python ./dummyssh" local ssh://user@dummy/remote1
120 abort: repository remote1 already exists!
120 abort: repository remote1 already exists!
121 abort: could not create remote repo!
121 abort: could not create remote repo!
122 [255]
122 [255]
123
123
124 output of dummyssh
124 output of dummyssh
125
125
126 $ cat dummylog
126 $ cat dummylog
127 Got arguments 1:user@dummy 2:hg init remote2
127 Got arguments 1:user@dummy 2:hg init remote2
128 Got arguments 1:user@dummy 2:hg -R remote2 serve --stdio
128 Got arguments 1:user@dummy 2:hg -R remote2 serve --stdio
129 Got arguments 1:user@dummy 2:hg -R remote2 serve --stdio
129 Got arguments 1:user@dummy 2:hg -R remote2 serve --stdio
130 Got arguments 1:user@dummy 2:hg init remote1
130 Got arguments 1:user@dummy 2:hg init remote1
131 Got arguments 1:user@dummy 2:hg -R remote1 serve --stdio
131 Got arguments 1:user@dummy 2:hg -R remote1 serve --stdio
132 Got arguments 1:user@dummy 2:hg init remote1
132 Got arguments 1:user@dummy 2:hg init remote1
133 Got arguments 1:user@dummy 2:hg init remote1
133 Got arguments 1:user@dummy 2:hg init remote1
134
134
135 comparing repositories
135 comparing repositories
136
136
137 $ hg tip -q -R local
137 $ hg tip -q -R local
138 0:08b9e9f63b32
138 0:08b9e9f63b32
139 $ hg tip -q -R remote1
139 $ hg tip -q -R remote1
140 0:08b9e9f63b32
140 0:08b9e9f63b32
141 $ hg tip -q -R remote2
141 $ hg tip -q -R remote2
142 0:08b9e9f63b32
142 0:08b9e9f63b32
143
143
144 check names for repositories (clashes with URL schemes, special chars)
144 check names for repositories (clashes with URL schemes, special chars)
145
145
146 $ for i in bundle file hg http https old-http ssh static-http " " "with space"; do
146 $ for i in bundle file hg http https old-http ssh static-http " " "with space"; do
147 > printf "hg init \"$i\"... "
147 > printf "hg init \"$i\"... "
148 > hg init "$i"
148 > hg init "$i"
149 > test -d "$i" -a -d "$i/.hg" && echo "ok" || echo "failed"
149 > test -d "$i" -a -d "$i/.hg" && echo "ok" || echo "failed"
150 > done
150 > done
151 hg init "bundle"... ok
151 hg init "bundle"... ok
152 hg init "file"... ok
152 hg init "file"... ok
153 hg init "hg"... ok
153 hg init "hg"... ok
154 hg init "http"... ok
154 hg init "http"... ok
155 hg init "https"... ok
155 hg init "https"... ok
156 hg init "old-http"... ok
156 hg init "old-http"... ok
157 hg init "ssh"... ok
157 hg init "ssh"... ok
158 hg init "static-http"... ok
158 hg init "static-http"... ok
159 hg init " "... ok
159 hg init " "... ok
160 hg init "with space"... ok
160 hg init "with space"... ok
161
161
162 creating 'local/sub/repo'
162 creating 'local/sub/repo'
163
163
164 $ hg init local/sub/repo
164 $ hg init local/sub/repo
165 $ checknewrepo local/sub/repo
165 $ checknewrepo local/sub/repo
166 store created
166 store created
167 00changelog.i created
167 00changelog.i created
168 revlogv1
168 revlogv1
169 store
169 store
170 fncache
170 fncache
171 dotencode
171 dotencode
172
172
173 prepare test of init of url configured from paths
173 prepare test of init of url configured from paths
174
174
175 $ echo '[paths]' >> $HGRCPATH
175 $ echo '[paths]' >> $HGRCPATH
176 $ echo "somewhere = `pwd`/url from paths" >> $HGRCPATH
176 $ echo "somewhere = `pwd`/url from paths" >> $HGRCPATH
177 $ echo "elsewhere = `pwd`/another paths url" >> $HGRCPATH
177 $ echo "elsewhere = `pwd`/another paths url" >> $HGRCPATH
178
178
179 init should (for consistency with clone) expand the url
179 init should (for consistency with clone) expand the url
180
180
181 $ hg init somewhere
181 $ hg init somewhere
182 $ checknewrepo "url from paths"
182 $ checknewrepo "url from paths"
183 store created
183 store created
184 00changelog.i created
184 00changelog.i created
185 revlogv1
185 revlogv1
186 store
186 store
187 fncache
187 fncache
188 dotencode
188 dotencode
189
189
190 verify that clone also expand urls
190 verify that clone also expand urls
191
191
192 $ hg clone somewhere elsewhere
192 $ hg clone somewhere elsewhere
193 updating to branch default
193 updating to branch default
194 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
194 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
195 $ checknewrepo "another paths url"
195 $ checknewrepo "another paths url"
196 store created
196 store created
197 00changelog.i created
197 00changelog.i created
198 revlogv1
198 revlogv1
199 store
199 store
200 fncache
200 fncache
201 dotencode
201 dotencode
202
203 clone bookmarks
204
205 $ hg -R local bookmark test
206 $ hg -R local bookmarks
207 * test 0:08b9e9f63b32
208 $ hg clone -e "python ./dummyssh" local ssh://user@dummy/remote-bookmarks
209 searching for changes
210 remote: adding changesets
211 remote: adding manifests
212 remote: adding file changes
213 remote: added 1 changesets with 1 changes to 1 files
214 $ hg -R remote-bookmarks bookmarks
215 test 0:08b9e9f63b32
@@ -1,291 +1,308 b''
1
1
2
2
3 This test tries to exercise the ssh functionality with a dummy script
3 This test tries to exercise the ssh functionality with a dummy script
4
4
5 $ cat <<EOF > dummyssh
5 $ cat <<EOF > dummyssh
6 > import sys
6 > import sys
7 > import os
7 > import os
8 >
8 >
9 > os.chdir(os.path.dirname(sys.argv[0]))
9 > os.chdir(os.path.dirname(sys.argv[0]))
10 > if sys.argv[1] != "user@dummy":
10 > if sys.argv[1] != "user@dummy":
11 > sys.exit(-1)
11 > sys.exit(-1)
12 >
12 >
13 > if not os.path.exists("dummyssh"):
13 > if not os.path.exists("dummyssh"):
14 > sys.exit(-1)
14 > sys.exit(-1)
15 >
15 >
16 > os.environ["SSH_CLIENT"] = "127.0.0.1 1 2"
16 > os.environ["SSH_CLIENT"] = "127.0.0.1 1 2"
17 >
17 >
18 > log = open("dummylog", "ab")
18 > log = open("dummylog", "ab")
19 > log.write("Got arguments")
19 > log.write("Got arguments")
20 > for i, arg in enumerate(sys.argv[1:]):
20 > for i, arg in enumerate(sys.argv[1:]):
21 > log.write(" %d:%s" % (i+1, arg))
21 > log.write(" %d:%s" % (i+1, arg))
22 > log.write("\n")
22 > log.write("\n")
23 > log.close()
23 > log.close()
24 > r = os.system(sys.argv[2])
24 > r = os.system(sys.argv[2])
25 > sys.exit(bool(r))
25 > sys.exit(bool(r))
26 > EOF
26 > EOF
27 $ cat <<EOF > badhook
27 $ cat <<EOF > badhook
28 > import sys
28 > import sys
29 > sys.stdout.write("KABOOM\n")
29 > sys.stdout.write("KABOOM\n")
30 > EOF
30 > EOF
31
31
32 creating 'remote
32 creating 'remote
33
33
34 $ hg init remote
34 $ hg init remote
35 $ cd remote
35 $ cd remote
36 $ echo this > foo
36 $ echo this > foo
37 $ echo this > fooO
37 $ echo this > fooO
38 $ hg ci -A -m "init" foo fooO
38 $ hg ci -A -m "init" foo fooO
39 $ echo <<EOF > .hg/hgrc
39 $ echo <<EOF > .hg/hgrc
40 > [server]
40 > [server]
41 > uncompressed = True
41 > uncompressed = True
42 >
42 >
43 > [hooks]
43 > [hooks]
44 > changegroup = python "$TESTDIR"/printenv.py changegroup-in-remote 0 ../dummylog
44 > changegroup = python "$TESTDIR"/printenv.py changegroup-in-remote 0 ../dummylog
45 > EOF
45 > EOF
46 $ cd ..
46 $ cd ..
47
47
48 repo not found error
48 repo not found error
49
49
50 $ hg clone -e "python ./dummyssh" ssh://user@dummy/nonexistent local
50 $ hg clone -e "python ./dummyssh" ssh://user@dummy/nonexistent local
51 remote: abort: There is no Mercurial repository here (.hg not found)!
51 remote: abort: There is no Mercurial repository here (.hg not found)!
52 abort: no suitable response from remote hg!
52 abort: no suitable response from remote hg!
53 [255]
53 [255]
54
54
55 non-existent absolute path
55 non-existent absolute path
56
56
57 $ hg clone -e "python ./dummyssh" ssh://user@dummy//`pwd`/nonexistent local
57 $ hg clone -e "python ./dummyssh" ssh://user@dummy//`pwd`/nonexistent local
58 remote: abort: There is no Mercurial repository here (.hg not found)!
58 remote: abort: There is no Mercurial repository here (.hg not found)!
59 abort: no suitable response from remote hg!
59 abort: no suitable response from remote hg!
60 [255]
60 [255]
61
61
62 clone remote via stream
62 clone remote via stream
63
63
64 $ hg clone -e "python ./dummyssh" --uncompressed ssh://user@dummy/remote local-stream
64 $ hg clone -e "python ./dummyssh" --uncompressed ssh://user@dummy/remote local-stream
65 streaming all changes
65 streaming all changes
66 4 files to transfer, 392 bytes of data
66 4 files to transfer, 392 bytes of data
67 transferred 392 bytes in * seconds (*/sec) (glob)
67 transferred 392 bytes in * seconds (*/sec) (glob)
68 updating to branch default
68 updating to branch default
69 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
69 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
70 $ cd local-stream
70 $ cd local-stream
71 $ hg verify
71 $ hg verify
72 checking changesets
72 checking changesets
73 checking manifests
73 checking manifests
74 crosschecking files in changesets and manifests
74 crosschecking files in changesets and manifests
75 checking files
75 checking files
76 2 files, 1 changesets, 2 total revisions
76 2 files, 1 changesets, 2 total revisions
77 $ cd ..
77 $ cd ..
78
78
79 clone remote via pull
79 clone remote via pull
80
80
81 $ hg clone -e "python ./dummyssh" ssh://user@dummy/remote local
81 $ hg clone -e "python ./dummyssh" ssh://user@dummy/remote local
82 requesting all changes
82 requesting all changes
83 adding changesets
83 adding changesets
84 adding manifests
84 adding manifests
85 adding file changes
85 adding file changes
86 added 1 changesets with 2 changes to 2 files
86 added 1 changesets with 2 changes to 2 files
87 updating to branch default
87 updating to branch default
88 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
88 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
89
89
90 verify
90 verify
91
91
92 $ cd local
92 $ cd local
93 $ hg verify
93 $ hg verify
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 2 files, 1 changesets, 2 total revisions
98 2 files, 1 changesets, 2 total revisions
99 $ echo '[hooks]' >> .hg/hgrc
99 $ echo '[hooks]' >> .hg/hgrc
100 $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup-in-local 0 ../dummylog' >> .hg/hgrc
100 $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup-in-local 0 ../dummylog' >> .hg/hgrc
101
101
102 empty default pull
102 empty default pull
103
103
104 $ hg paths
104 $ hg paths
105 default = ssh://user@dummy/remote
105 default = ssh://user@dummy/remote
106 $ hg pull -e "python ../dummyssh"
106 $ hg pull -e "python ../dummyssh"
107 pulling from ssh://user@dummy/remote
107 pulling from ssh://user@dummy/remote
108 searching for changes
108 searching for changes
109 no changes found
109 no changes found
110
110
111 local change
111 local change
112
112
113 $ echo bleah > foo
113 $ echo bleah > foo
114 $ hg ci -m "add"
114 $ hg ci -m "add"
115
115
116 updating rc
116 updating rc
117
117
118 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
118 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
119 $ echo "[ui]" >> .hg/hgrc
119 $ echo "[ui]" >> .hg/hgrc
120 $ echo "ssh = python ../dummyssh" >> .hg/hgrc
120 $ echo "ssh = python ../dummyssh" >> .hg/hgrc
121
121
122 find outgoing
122 find outgoing
123
123
124 $ hg out ssh://user@dummy/remote
124 $ hg out ssh://user@dummy/remote
125 comparing with ssh://user@dummy/remote
125 comparing with ssh://user@dummy/remote
126 searching for changes
126 searching for changes
127 changeset: 1:a28a9d1a809c
127 changeset: 1:a28a9d1a809c
128 tag: tip
128 tag: tip
129 user: test
129 user: test
130 date: Thu Jan 01 00:00:00 1970 +0000
130 date: Thu Jan 01 00:00:00 1970 +0000
131 summary: add
131 summary: add
132
132
133
133
134 find incoming on the remote side
134 find incoming on the remote side
135
135
136 $ hg incoming -R ../remote -e "python ../dummyssh" ssh://user@dummy/local
136 $ hg incoming -R ../remote -e "python ../dummyssh" ssh://user@dummy/local
137 comparing with ssh://user@dummy/local
137 comparing with ssh://user@dummy/local
138 searching for changes
138 searching for changes
139 changeset: 1:a28a9d1a809c
139 changeset: 1:a28a9d1a809c
140 tag: tip
140 tag: tip
141 user: test
141 user: test
142 date: Thu Jan 01 00:00:00 1970 +0000
142 date: Thu Jan 01 00:00:00 1970 +0000
143 summary: add
143 summary: add
144
144
145
145
146 find incoming on the remote side (using absolute path)
146 find incoming on the remote side (using absolute path)
147
147
148 $ hg incoming -R ../remote -e "python ../dummyssh" "ssh://user@dummy/`pwd`"
148 $ hg incoming -R ../remote -e "python ../dummyssh" "ssh://user@dummy/`pwd`"
149 comparing with ssh://user@dummy/$TESTTMP/local
149 comparing with ssh://user@dummy/$TESTTMP/local
150 searching for changes
150 searching for changes
151 changeset: 1:a28a9d1a809c
151 changeset: 1:a28a9d1a809c
152 tag: tip
152 tag: tip
153 user: test
153 user: test
154 date: Thu Jan 01 00:00:00 1970 +0000
154 date: Thu Jan 01 00:00:00 1970 +0000
155 summary: add
155 summary: add
156
156
157
157
158 push
158 push
159
159
160 $ hg push
160 $ hg push
161 pushing to ssh://user@dummy/remote
161 pushing to ssh://user@dummy/remote
162 searching for changes
162 searching for changes
163 remote: adding changesets
163 remote: adding changesets
164 remote: adding manifests
164 remote: adding manifests
165 remote: adding file changes
165 remote: adding file changes
166 remote: added 1 changesets with 1 changes to 1 files
166 remote: added 1 changesets with 1 changes to 1 files
167 $ cd ../remote
167 $ cd ../remote
168
168
169 check remote tip
169 check remote tip
170
170
171 $ hg tip
171 $ hg tip
172 changeset: 1:a28a9d1a809c
172 changeset: 1:a28a9d1a809c
173 tag: tip
173 tag: tip
174 user: test
174 user: test
175 date: Thu Jan 01 00:00:00 1970 +0000
175 date: Thu Jan 01 00:00:00 1970 +0000
176 summary: add
176 summary: add
177
177
178 $ hg verify
178 $ hg verify
179 checking changesets
179 checking changesets
180 checking manifests
180 checking manifests
181 crosschecking files in changesets and manifests
181 crosschecking files in changesets and manifests
182 checking files
182 checking files
183 2 files, 2 changesets, 3 total revisions
183 2 files, 2 changesets, 3 total revisions
184 $ hg cat -r tip foo
184 $ hg cat -r tip foo
185 bleah
185 bleah
186 $ echo z > z
186 $ echo z > z
187 $ hg ci -A -m z z
187 $ hg ci -A -m z z
188 created new head
188 created new head
189
189
190 test pushkeys and bookmarks
190 test pushkeys and bookmarks
191
191
192 $ cd ../local
192 $ cd ../local
193 $ hg debugpushkey --config ui.ssh="python ../dummyssh" ssh://user@dummy/remote namespaces
193 $ hg debugpushkey --config ui.ssh="python ../dummyssh" ssh://user@dummy/remote namespaces
194 bookmarks
194 bookmarks
195 namespaces
195 namespaces
196 $ hg book foo -r 0
196 $ hg book foo -r 0
197 $ hg out -B
197 $ hg out -B
198 comparing with ssh://user@dummy/remote
198 comparing with ssh://user@dummy/remote
199 searching for changed bookmarks
199 searching for changed bookmarks
200 foo 1160648e36ce
200 foo 1160648e36ce
201 $ hg push -B foo
201 $ hg push -B foo
202 pushing to ssh://user@dummy/remote
202 pushing to ssh://user@dummy/remote
203 searching for changes
203 searching for changes
204 no changes found
204 no changes found
205 exporting bookmark foo
205 exporting bookmark foo
206 $ hg debugpushkey --config ui.ssh="python ../dummyssh" ssh://user@dummy/remote bookmarks
206 $ hg debugpushkey --config ui.ssh="python ../dummyssh" ssh://user@dummy/remote bookmarks
207 foo 1160648e36cec0054048a7edc4110c6f84fde594
207 foo 1160648e36cec0054048a7edc4110c6f84fde594
208 $ hg book -f foo
208 $ hg book -f foo
209 $ hg push --traceback
209 $ hg push --traceback
210 pushing to ssh://user@dummy/remote
210 pushing to ssh://user@dummy/remote
211 searching for changes
211 searching for changes
212 no changes found
212 no changes found
213 updating bookmark foo
213 updating bookmark foo
214 $ hg book -d foo
214 $ hg book -d foo
215 $ hg in -B
215 $ hg in -B
216 comparing with ssh://user@dummy/remote
216 comparing with ssh://user@dummy/remote
217 searching for changed bookmarks
217 searching for changed bookmarks
218 foo a28a9d1a809c
218 foo a28a9d1a809c
219 $ hg book -f -r 0 foo
219 $ hg book -f -r 0 foo
220 $ hg pull -B foo
220 $ hg pull -B foo
221 pulling from ssh://user@dummy/remote
221 pulling from ssh://user@dummy/remote
222 searching for changes
222 searching for changes
223 no changes found
223 no changes found
224 updating bookmark foo
224 updating bookmark foo
225 importing bookmark foo
225 importing bookmark foo
226 $ hg book -d foo
226 $ hg book -d foo
227 $ hg push -B foo
227 $ hg push -B foo
228 pushing to ssh://user@dummy/remote
228 pushing to ssh://user@dummy/remote
229 searching for changes
229 searching for changes
230 no changes found
230 no changes found
231 deleting remote bookmark foo
231 deleting remote bookmark foo
232
232
233 a bad, evil hook that prints to stdout
233 a bad, evil hook that prints to stdout
234
234
235 $ echo '[hooks]' >> ../remote/.hg/hgrc
235 $ echo '[hooks]' >> ../remote/.hg/hgrc
236 $ echo 'changegroup.stdout = python ../badhook' >> ../remote/.hg/hgrc
236 $ echo 'changegroup.stdout = python ../badhook' >> ../remote/.hg/hgrc
237 $ echo r > r
237 $ echo r > r
238 $ hg ci -A -m z r
238 $ hg ci -A -m z r
239
239
240 push should succeed even though it has an unexpected response
240 push should succeed even though it has an unexpected response
241
241
242 $ hg push
242 $ hg push
243 pushing to ssh://user@dummy/remote
243 pushing to ssh://user@dummy/remote
244 searching for changes
244 searching for changes
245 note: unsynced remote changes!
245 note: unsynced remote changes!
246 remote: adding changesets
246 remote: adding changesets
247 remote: adding manifests
247 remote: adding manifests
248 remote: adding file changes
248 remote: adding file changes
249 remote: added 1 changesets with 1 changes to 1 files
249 remote: added 1 changesets with 1 changes to 1 files
250 remote: KABOOM
250 remote: KABOOM
251 $ hg -R ../remote heads
251 $ hg -R ../remote heads
252 changeset: 3:1383141674ec
252 changeset: 3:1383141674ec
253 tag: tip
253 tag: tip
254 parent: 1:a28a9d1a809c
254 parent: 1:a28a9d1a809c
255 user: test
255 user: test
256 date: Thu Jan 01 00:00:00 1970 +0000
256 date: Thu Jan 01 00:00:00 1970 +0000
257 summary: z
257 summary: z
258
258
259 changeset: 2:6c0482d977a3
259 changeset: 2:6c0482d977a3
260 parent: 0:1160648e36ce
260 parent: 0:1160648e36ce
261 user: test
261 user: test
262 date: Thu Jan 01 00:00:00 1970 +0000
262 date: Thu Jan 01 00:00:00 1970 +0000
263 summary: z
263 summary: z
264
264
265
265
266 clone bookmarks
267
268 $ hg -R ../remote bookmark test
269 $ hg -R ../remote bookmarks
270 * test 2:6c0482d977a3
271 $ hg clone -e "python ../dummyssh" ssh://user@dummy/remote local-bookmarks
272 requesting all changes
273 adding changesets
274 adding manifests
275 adding file changes
276 added 4 changesets with 5 changes to 4 files (+1 heads)
277 updating to branch default
278 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
279 $ hg -R local-bookmarks bookmarks
280 test 2:6c0482d977a3
281
266 passwords in ssh urls are not supported
282 passwords in ssh urls are not supported
267
283
268 $ hg push ssh://user:erroneouspwd@dummy/remote
284 $ hg push ssh://user:erroneouspwd@dummy/remote
269 abort: password in URL not supported!
285 abort: password in URL not supported!
270 [255]
286 [255]
271
287
272 $ cd ..
288 $ cd ..
273 $ cat dummylog
289 $ cat dummylog
274 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
290 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
275 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
291 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
276 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
292 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
277 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
293 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
278 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
294 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
279 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
295 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
280 Got arguments 1:user@dummy 2:hg -R local serve --stdio
296 Got arguments 1:user@dummy 2:hg -R local serve --stdio
281 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
297 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
282 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
298 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
283 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
299 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
284 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
300 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
285 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
301 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
286 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
302 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
287 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
303 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
288 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
304 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
289 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
305 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
290 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
306 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
291 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
307 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
308 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
General Comments 0
You need to be logged in to leave comments. Login now