##// END OF EJS Templates
httprepo: make __del__ more stable in error situations...
Mads Kiilerich -
r15246:7b15dd91 default
parent child Browse files
Show More
@@ -1,245 +1,247 b''
1 # httprepo.py - HTTP repository proxy classes for mercurial
1 # httprepo.py - HTTP repository proxy classes for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 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 node import nullid
9 from node import nullid
10 from i18n import _
10 from i18n import _
11 import changegroup, statichttprepo, error, httpconnection, url, util, wireproto
11 import changegroup, statichttprepo, error, httpconnection, url, util, wireproto
12 import os, urllib, urllib2, zlib, httplib
12 import os, urllib, urllib2, zlib, httplib
13 import errno, socket
13 import errno, socket
14
14
15 def zgenerator(f):
15 def zgenerator(f):
16 zd = zlib.decompressobj()
16 zd = zlib.decompressobj()
17 try:
17 try:
18 for chunk in util.filechunkiter(f):
18 for chunk in util.filechunkiter(f):
19 while chunk:
19 while chunk:
20 yield zd.decompress(chunk, 2**18)
20 yield zd.decompress(chunk, 2**18)
21 chunk = zd.unconsumed_tail
21 chunk = zd.unconsumed_tail
22 except httplib.HTTPException:
22 except httplib.HTTPException:
23 raise IOError(None, _('connection ended unexpectedly'))
23 raise IOError(None, _('connection ended unexpectedly'))
24 yield zd.flush()
24 yield zd.flush()
25
25
26 class httprepository(wireproto.wirerepository):
26 class httprepository(wireproto.wirerepository):
27 def __init__(self, ui, path):
27 def __init__(self, ui, path):
28 self.path = path
28 self.path = path
29 self.caps = None
29 self.caps = None
30 self.handler = None
30 self.handler = None
31 self.urlopener = None
31 u = util.url(path)
32 u = util.url(path)
32 if u.query or u.fragment:
33 if u.query or u.fragment:
33 raise util.Abort(_('unsupported URL component: "%s"') %
34 raise util.Abort(_('unsupported URL component: "%s"') %
34 (u.query or u.fragment))
35 (u.query or u.fragment))
35
36
36 # urllib cannot handle URLs with embedded user or passwd
37 # urllib cannot handle URLs with embedded user or passwd
37 self._url, authinfo = u.authinfo()
38 self._url, authinfo = u.authinfo()
38
39
39 self.ui = ui
40 self.ui = ui
40 self.ui.debug('using %s\n' % self._url)
41 self.ui.debug('using %s\n' % self._url)
41
42
42 self.urlopener = url.opener(ui, authinfo)
43 self.urlopener = url.opener(ui, authinfo)
43
44
44 def __del__(self):
45 def __del__(self):
45 for h in self.urlopener.handlers:
46 if self.urlopener:
46 h.close()
47 for h in self.urlopener.handlers:
47 getattr(h, "close_all", lambda : None)()
48 h.close()
49 getattr(h, "close_all", lambda : None)()
48
50
49 def url(self):
51 def url(self):
50 return self.path
52 return self.path
51
53
52 # look up capabilities only when needed
54 # look up capabilities only when needed
53
55
54 def _fetchcaps(self):
56 def _fetchcaps(self):
55 self.caps = set(self._call('capabilities').split())
57 self.caps = set(self._call('capabilities').split())
56
58
57 def get_caps(self):
59 def get_caps(self):
58 if self.caps is None:
60 if self.caps is None:
59 try:
61 try:
60 self._fetchcaps()
62 self._fetchcaps()
61 except error.RepoError:
63 except error.RepoError:
62 self.caps = set()
64 self.caps = set()
63 self.ui.debug('capabilities: %s\n' %
65 self.ui.debug('capabilities: %s\n' %
64 (' '.join(self.caps or ['none'])))
66 (' '.join(self.caps or ['none'])))
65 return self.caps
67 return self.caps
66
68
67 capabilities = property(get_caps)
69 capabilities = property(get_caps)
68
70
69 def lock(self):
71 def lock(self):
70 raise util.Abort(_('operation not supported over http'))
72 raise util.Abort(_('operation not supported over http'))
71
73
72 def _callstream(self, cmd, **args):
74 def _callstream(self, cmd, **args):
73 if cmd == 'pushkey':
75 if cmd == 'pushkey':
74 args['data'] = ''
76 args['data'] = ''
75 data = args.pop('data', None)
77 data = args.pop('data', None)
76 size = 0
78 size = 0
77 if util.safehasattr(data, 'length'):
79 if util.safehasattr(data, 'length'):
78 size = data.length
80 size = data.length
79 elif data is not None:
81 elif data is not None:
80 size = len(data)
82 size = len(data)
81 headers = args.pop('headers', {})
83 headers = args.pop('headers', {})
82
84
83 if size and self.ui.configbool('ui', 'usehttp2', False):
85 if size and self.ui.configbool('ui', 'usehttp2', False):
84 headers['Expect'] = '100-Continue'
86 headers['Expect'] = '100-Continue'
85 headers['X-HgHttp2'] = '1'
87 headers['X-HgHttp2'] = '1'
86
88
87 self.ui.debug("sending %s command\n" % cmd)
89 self.ui.debug("sending %s command\n" % cmd)
88 q = [('cmd', cmd)]
90 q = [('cmd', cmd)]
89 headersize = 0
91 headersize = 0
90 if len(args) > 0:
92 if len(args) > 0:
91 httpheader = self.capable('httpheader')
93 httpheader = self.capable('httpheader')
92 if httpheader:
94 if httpheader:
93 headersize = int(httpheader.split(',')[0])
95 headersize = int(httpheader.split(',')[0])
94 if headersize > 0:
96 if headersize > 0:
95 # The headers can typically carry more data than the URL.
97 # The headers can typically carry more data than the URL.
96 encargs = urllib.urlencode(sorted(args.items()))
98 encargs = urllib.urlencode(sorted(args.items()))
97 headerfmt = 'X-HgArg-%s'
99 headerfmt = 'X-HgArg-%s'
98 contentlen = headersize - len(headerfmt % '000' + ': \r\n')
100 contentlen = headersize - len(headerfmt % '000' + ': \r\n')
99 headernum = 0
101 headernum = 0
100 for i in xrange(0, len(encargs), contentlen):
102 for i in xrange(0, len(encargs), contentlen):
101 headernum += 1
103 headernum += 1
102 header = headerfmt % str(headernum)
104 header = headerfmt % str(headernum)
103 headers[header] = encargs[i:i + contentlen]
105 headers[header] = encargs[i:i + contentlen]
104 varyheaders = [headerfmt % str(h) for h in range(1, headernum + 1)]
106 varyheaders = [headerfmt % str(h) for h in range(1, headernum + 1)]
105 headers['Vary'] = ','.join(varyheaders)
107 headers['Vary'] = ','.join(varyheaders)
106 else:
108 else:
107 q += sorted(args.items())
109 q += sorted(args.items())
108 qs = '?%s' % urllib.urlencode(q)
110 qs = '?%s' % urllib.urlencode(q)
109 cu = "%s%s" % (self._url, qs)
111 cu = "%s%s" % (self._url, qs)
110 req = urllib2.Request(cu, data, headers)
112 req = urllib2.Request(cu, data, headers)
111 if data is not None:
113 if data is not None:
112 self.ui.debug("sending %s bytes\n" % size)
114 self.ui.debug("sending %s bytes\n" % size)
113 req.add_unredirected_header('Content-Length', '%d' % size)
115 req.add_unredirected_header('Content-Length', '%d' % size)
114 try:
116 try:
115 resp = self.urlopener.open(req)
117 resp = self.urlopener.open(req)
116 except urllib2.HTTPError, inst:
118 except urllib2.HTTPError, inst:
117 if inst.code == 401:
119 if inst.code == 401:
118 raise util.Abort(_('authorization failed'))
120 raise util.Abort(_('authorization failed'))
119 raise
121 raise
120 except httplib.HTTPException, inst:
122 except httplib.HTTPException, inst:
121 self.ui.debug('http error while sending %s command\n' % cmd)
123 self.ui.debug('http error while sending %s command\n' % cmd)
122 self.ui.traceback()
124 self.ui.traceback()
123 raise IOError(None, inst)
125 raise IOError(None, inst)
124 except IndexError:
126 except IndexError:
125 # this only happens with Python 2.3, later versions raise URLError
127 # this only happens with Python 2.3, later versions raise URLError
126 raise util.Abort(_('http error, possibly caused by proxy setting'))
128 raise util.Abort(_('http error, possibly caused by proxy setting'))
127 # record the url we got redirected to
129 # record the url we got redirected to
128 resp_url = resp.geturl()
130 resp_url = resp.geturl()
129 if resp_url.endswith(qs):
131 if resp_url.endswith(qs):
130 resp_url = resp_url[:-len(qs)]
132 resp_url = resp_url[:-len(qs)]
131 if self._url.rstrip('/') != resp_url.rstrip('/'):
133 if self._url.rstrip('/') != resp_url.rstrip('/'):
132 if not self.ui.quiet:
134 if not self.ui.quiet:
133 self.ui.warn(_('real URL is %s\n') % resp_url)
135 self.ui.warn(_('real URL is %s\n') % resp_url)
134 self._url = resp_url
136 self._url = resp_url
135 try:
137 try:
136 proto = resp.getheader('content-type')
138 proto = resp.getheader('content-type')
137 except AttributeError:
139 except AttributeError:
138 proto = resp.headers.get('content-type', '')
140 proto = resp.headers.get('content-type', '')
139
141
140 safeurl = util.hidepassword(self._url)
142 safeurl = util.hidepassword(self._url)
141 if proto.startswith('application/hg-error'):
143 if proto.startswith('application/hg-error'):
142 raise error.OutOfBandError(resp.read())
144 raise error.OutOfBandError(resp.read())
143 # accept old "text/plain" and "application/hg-changegroup" for now
145 # accept old "text/plain" and "application/hg-changegroup" for now
144 if not (proto.startswith('application/mercurial-') or
146 if not (proto.startswith('application/mercurial-') or
145 proto.startswith('text/plain') or
147 proto.startswith('text/plain') or
146 proto.startswith('application/hg-changegroup')):
148 proto.startswith('application/hg-changegroup')):
147 self.ui.debug("requested URL: '%s'\n" % util.hidepassword(cu))
149 self.ui.debug("requested URL: '%s'\n" % util.hidepassword(cu))
148 raise error.RepoError(
150 raise error.RepoError(
149 _("'%s' does not appear to be an hg repository:\n"
151 _("'%s' does not appear to be an hg repository:\n"
150 "---%%<--- (%s)\n%s\n---%%<---\n")
152 "---%%<--- (%s)\n%s\n---%%<---\n")
151 % (safeurl, proto or 'no content-type', resp.read()))
153 % (safeurl, proto or 'no content-type', resp.read()))
152
154
153 if proto.startswith('application/mercurial-'):
155 if proto.startswith('application/mercurial-'):
154 try:
156 try:
155 version = proto.split('-', 1)[1]
157 version = proto.split('-', 1)[1]
156 version_info = tuple([int(n) for n in version.split('.')])
158 version_info = tuple([int(n) for n in version.split('.')])
157 except ValueError:
159 except ValueError:
158 raise error.RepoError(_("'%s' sent a broken Content-Type "
160 raise error.RepoError(_("'%s' sent a broken Content-Type "
159 "header (%s)") % (safeurl, proto))
161 "header (%s)") % (safeurl, proto))
160 if version_info > (0, 1):
162 if version_info > (0, 1):
161 raise error.RepoError(_("'%s' uses newer protocol %s") %
163 raise error.RepoError(_("'%s' uses newer protocol %s") %
162 (safeurl, version))
164 (safeurl, version))
163
165
164 return resp
166 return resp
165
167
166 def _call(self, cmd, **args):
168 def _call(self, cmd, **args):
167 fp = self._callstream(cmd, **args)
169 fp = self._callstream(cmd, **args)
168 try:
170 try:
169 return fp.read()
171 return fp.read()
170 finally:
172 finally:
171 # if using keepalive, allow connection to be reused
173 # if using keepalive, allow connection to be reused
172 fp.close()
174 fp.close()
173
175
174 def _callpush(self, cmd, cg, **args):
176 def _callpush(self, cmd, cg, **args):
175 # have to stream bundle to a temp file because we do not have
177 # have to stream bundle to a temp file because we do not have
176 # http 1.1 chunked transfer.
178 # http 1.1 chunked transfer.
177
179
178 types = self.capable('unbundle')
180 types = self.capable('unbundle')
179 try:
181 try:
180 types = types.split(',')
182 types = types.split(',')
181 except AttributeError:
183 except AttributeError:
182 # servers older than d1b16a746db6 will send 'unbundle' as a
184 # servers older than d1b16a746db6 will send 'unbundle' as a
183 # boolean capability. They only support headerless/uncompressed
185 # boolean capability. They only support headerless/uncompressed
184 # bundles.
186 # bundles.
185 types = [""]
187 types = [""]
186 for x in types:
188 for x in types:
187 if x in changegroup.bundletypes:
189 if x in changegroup.bundletypes:
188 type = x
190 type = x
189 break
191 break
190
192
191 tempname = changegroup.writebundle(cg, None, type)
193 tempname = changegroup.writebundle(cg, None, type)
192 fp = httpconnection.httpsendfile(self.ui, tempname, "rb")
194 fp = httpconnection.httpsendfile(self.ui, tempname, "rb")
193 headers = {'Content-Type': 'application/mercurial-0.1'}
195 headers = {'Content-Type': 'application/mercurial-0.1'}
194
196
195 try:
197 try:
196 try:
198 try:
197 r = self._call(cmd, data=fp, headers=headers, **args)
199 r = self._call(cmd, data=fp, headers=headers, **args)
198 vals = r.split('\n', 1)
200 vals = r.split('\n', 1)
199 if len(vals) < 2:
201 if len(vals) < 2:
200 raise error.ResponseError(_("unexpected response:"), r)
202 raise error.ResponseError(_("unexpected response:"), r)
201 return vals
203 return vals
202 except socket.error, err:
204 except socket.error, err:
203 if err.args[0] in (errno.ECONNRESET, errno.EPIPE):
205 if err.args[0] in (errno.ECONNRESET, errno.EPIPE):
204 raise util.Abort(_('push failed: %s') % err.args[1])
206 raise util.Abort(_('push failed: %s') % err.args[1])
205 raise util.Abort(err.args[1])
207 raise util.Abort(err.args[1])
206 finally:
208 finally:
207 fp.close()
209 fp.close()
208 os.unlink(tempname)
210 os.unlink(tempname)
209
211
210 def _abort(self, exception):
212 def _abort(self, exception):
211 raise exception
213 raise exception
212
214
213 def _decompress(self, stream):
215 def _decompress(self, stream):
214 return util.chunkbuffer(zgenerator(stream))
216 return util.chunkbuffer(zgenerator(stream))
215
217
216 class httpsrepository(httprepository):
218 class httpsrepository(httprepository):
217 def __init__(self, ui, path):
219 def __init__(self, ui, path):
218 if not url.has_https:
220 if not url.has_https:
219 raise util.Abort(_('Python support for SSL and HTTPS '
221 raise util.Abort(_('Python support for SSL and HTTPS '
220 'is not installed'))
222 'is not installed'))
221 httprepository.__init__(self, ui, path)
223 httprepository.__init__(self, ui, path)
222
224
223 def instance(ui, path, create):
225 def instance(ui, path, create):
224 if create:
226 if create:
225 raise util.Abort(_('cannot create new http repository'))
227 raise util.Abort(_('cannot create new http repository'))
226 try:
228 try:
227 if path.startswith('https:'):
229 if path.startswith('https:'):
228 inst = httpsrepository(ui, path)
230 inst = httpsrepository(ui, path)
229 else:
231 else:
230 inst = httprepository(ui, path)
232 inst = httprepository(ui, path)
231 try:
233 try:
232 # Try to do useful work when checking compatibility.
234 # Try to do useful work when checking compatibility.
233 # Usually saves a roundtrip since we want the caps anyway.
235 # Usually saves a roundtrip since we want the caps anyway.
234 inst._fetchcaps()
236 inst._fetchcaps()
235 except error.RepoError:
237 except error.RepoError:
236 # No luck, try older compatibility check.
238 # No luck, try older compatibility check.
237 inst.between([(nullid, nullid)])
239 inst.between([(nullid, nullid)])
238 return inst
240 return inst
239 except error.RepoError, httpexception:
241 except error.RepoError, httpexception:
240 try:
242 try:
241 r = statichttprepo.instance(ui, "static-" + path, create)
243 r = statichttprepo.instance(ui, "static-" + path, create)
242 ui.note('(falling back to static-http)\n')
244 ui.note('(falling back to static-http)\n')
243 return r
245 return r
244 except error.RepoError:
246 except error.RepoError:
245 raise httpexception # use the original http RepoError instead
247 raise httpexception # use the original http RepoError instead
@@ -1,203 +1,207 b''
1 Test basic functionality of url#rev syntax
1 Test basic functionality of url#rev syntax
2
2
3 $ hg init repo
3 $ hg init repo
4 $ cd repo
4 $ cd repo
5 $ echo a > a
5 $ echo a > a
6 $ hg ci -qAm 'add a'
6 $ hg ci -qAm 'add a'
7 $ hg branch foo
7 $ hg branch foo
8 marked working directory as branch foo
8 marked working directory as branch foo
9 $ echo >> a
9 $ echo >> a
10 $ hg ci -m 'change a'
10 $ hg ci -m 'change a'
11 $ cd ..
11 $ cd ..
12
12
13 $ hg clone 'repo#foo' clone
13 $ hg clone 'repo#foo' clone
14 adding changesets
14 adding changesets
15 adding manifests
15 adding manifests
16 adding file changes
16 adding file changes
17 added 2 changesets with 2 changes to 1 files
17 added 2 changesets with 2 changes to 1 files
18 updating to branch foo
18 updating to branch foo
19 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
19 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
20
20
21 $ hg --cwd clone heads
21 $ hg --cwd clone heads
22 changeset: 1:cd2a86ecc814
22 changeset: 1:cd2a86ecc814
23 branch: foo
23 branch: foo
24 tag: tip
24 tag: tip
25 user: test
25 user: test
26 date: Thu Jan 01 00:00:00 1970 +0000
26 date: Thu Jan 01 00:00:00 1970 +0000
27 summary: change a
27 summary: change a
28
28
29 changeset: 0:1f0dee641bb7
29 changeset: 0:1f0dee641bb7
30 user: test
30 user: test
31 date: Thu Jan 01 00:00:00 1970 +0000
31 date: Thu Jan 01 00:00:00 1970 +0000
32 summary: add a
32 summary: add a
33
33
34 $ hg --cwd clone parents
34 $ hg --cwd clone parents
35 changeset: 1:cd2a86ecc814
35 changeset: 1:cd2a86ecc814
36 branch: foo
36 branch: foo
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: change a
40 summary: change a
41
41
42 $ cat clone/.hg/hgrc
42 $ cat clone/.hg/hgrc
43 [paths]
43 [paths]
44 default = $TESTTMP/repo#foo
44 default = $TESTTMP/repo#foo
45
45
46 Changing original repo:
46 Changing original repo:
47
47
48 $ cd repo
48 $ cd repo
49
49
50 $ echo >> a
50 $ echo >> a
51 $ hg ci -m 'new head of branch foo'
51 $ hg ci -m 'new head of branch foo'
52
52
53 $ hg up -qC default
53 $ hg up -qC default
54 $ echo bar > bar
54 $ echo bar > bar
55 $ hg ci -qAm 'add bar'
55 $ hg ci -qAm 'add bar'
56
56
57 $ hg log
57 $ hg log
58 changeset: 3:4cd725637392
58 changeset: 3:4cd725637392
59 tag: tip
59 tag: tip
60 parent: 0:1f0dee641bb7
60 parent: 0:1f0dee641bb7
61 user: test
61 user: test
62 date: Thu Jan 01 00:00:00 1970 +0000
62 date: Thu Jan 01 00:00:00 1970 +0000
63 summary: add bar
63 summary: add bar
64
64
65 changeset: 2:faba9097cad4
65 changeset: 2:faba9097cad4
66 branch: foo
66 branch: foo
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: new head of branch foo
69 summary: new head of branch foo
70
70
71 changeset: 1:cd2a86ecc814
71 changeset: 1:cd2a86ecc814
72 branch: foo
72 branch: foo
73 user: test
73 user: test
74 date: Thu Jan 01 00:00:00 1970 +0000
74 date: Thu Jan 01 00:00:00 1970 +0000
75 summary: change a
75 summary: change a
76
76
77 changeset: 0:1f0dee641bb7
77 changeset: 0:1f0dee641bb7
78 user: test
78 user: test
79 date: Thu Jan 01 00:00:00 1970 +0000
79 date: Thu Jan 01 00:00:00 1970 +0000
80 summary: add a
80 summary: add a
81
81
82 $ hg -q outgoing '../clone#foo'
82 $ hg -q outgoing '../clone#foo'
83 2:faba9097cad4
83 2:faba9097cad4
84
84
85 $ hg -q push '../clone#foo'
85 $ hg -q push '../clone#foo'
86
86
87 $ hg --cwd ../clone heads
87 $ hg --cwd ../clone heads
88 changeset: 2:faba9097cad4
88 changeset: 2:faba9097cad4
89 branch: foo
89 branch: foo
90 tag: tip
90 tag: tip
91 user: test
91 user: test
92 date: Thu Jan 01 00:00:00 1970 +0000
92 date: Thu Jan 01 00:00:00 1970 +0000
93 summary: new head of branch foo
93 summary: new head of branch foo
94
94
95 changeset: 0:1f0dee641bb7
95 changeset: 0:1f0dee641bb7
96 user: test
96 user: test
97 date: Thu Jan 01 00:00:00 1970 +0000
97 date: Thu Jan 01 00:00:00 1970 +0000
98 summary: add a
98 summary: add a
99
99
100 $ cd ..
100 $ cd ..
101
101
102 $ cd clone
102 $ cd clone
103 $ hg rollback
103 $ hg rollback
104 repository tip rolled back to revision 1 (undo push)
104 repository tip rolled back to revision 1 (undo push)
105
105
106 $ hg -q incoming
106 $ hg -q incoming
107 2:faba9097cad4
107 2:faba9097cad4
108
108
109 $ hg -q pull
109 $ hg -q pull
110
110
111 $ hg heads
111 $ hg heads
112 changeset: 2:faba9097cad4
112 changeset: 2:faba9097cad4
113 branch: foo
113 branch: foo
114 tag: tip
114 tag: tip
115 user: test
115 user: test
116 date: Thu Jan 01 00:00:00 1970 +0000
116 date: Thu Jan 01 00:00:00 1970 +0000
117 summary: new head of branch foo
117 summary: new head of branch foo
118
118
119 changeset: 0:1f0dee641bb7
119 changeset: 0:1f0dee641bb7
120 user: test
120 user: test
121 date: Thu Jan 01 00:00:00 1970 +0000
121 date: Thu Jan 01 00:00:00 1970 +0000
122 summary: add a
122 summary: add a
123
123
124 Pull should not have updated:
124 Pull should not have updated:
125
125
126 $ hg parents -q
126 $ hg parents -q
127 1:cd2a86ecc814
127 1:cd2a86ecc814
128
128
129 Going back to the default branch:
129 Going back to the default branch:
130
130
131 $ hg up -C 0
131 $ hg up -C 0
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
133
134 $ hg parents
134 $ hg parents
135 changeset: 0:1f0dee641bb7
135 changeset: 0:1f0dee641bb7
136 user: test
136 user: test
137 date: Thu Jan 01 00:00:00 1970 +0000
137 date: Thu Jan 01 00:00:00 1970 +0000
138 summary: add a
138 summary: add a
139
139
140 No new revs, no update:
140 No new revs, no update:
141
141
142 $ hg pull -qu
142 $ hg pull -qu
143
143
144 $ hg parents -q
144 $ hg parents -q
145 0:1f0dee641bb7
145 0:1f0dee641bb7
146
146
147 $ hg rollback
147 $ hg rollback
148 repository tip rolled back to revision 1 (undo pull)
148 repository tip rolled back to revision 1 (undo pull)
149
149
150 $ hg parents -q
150 $ hg parents -q
151 0:1f0dee641bb7
151 0:1f0dee641bb7
152
152
153 Pull -u takes us back to branch foo:
153 Pull -u takes us back to branch foo:
154
154
155 $ hg pull -qu
155 $ hg pull -qu
156
156
157 $ hg parents
157 $ hg parents
158 changeset: 2:faba9097cad4
158 changeset: 2:faba9097cad4
159 branch: foo
159 branch: foo
160 tag: tip
160 tag: tip
161 user: test
161 user: test
162 date: Thu Jan 01 00:00:00 1970 +0000
162 date: Thu Jan 01 00:00:00 1970 +0000
163 summary: new head of branch foo
163 summary: new head of branch foo
164
164
165 $ hg rollback
165 $ hg rollback
166 repository tip rolled back to revision 1 (undo pull)
166 repository tip rolled back to revision 1 (undo pull)
167 working directory now based on revision 0
167 working directory now based on revision 0
168
168
169 $ hg up -C 0
169 $ hg up -C 0
170 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
170 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
171
171
172 $ hg parents -q
172 $ hg parents -q
173 0:1f0dee641bb7
173 0:1f0dee641bb7
174
174
175 $ hg heads -q
175 $ hg heads -q
176 1:cd2a86ecc814
176 1:cd2a86ecc814
177 0:1f0dee641bb7
177 0:1f0dee641bb7
178
178
179 $ hg pull -qur default default
179 $ hg pull -qur default default
180
180
181 $ hg parents
181 $ hg parents
182 changeset: 3:4cd725637392
182 changeset: 3:4cd725637392
183 tag: tip
183 tag: tip
184 parent: 0:1f0dee641bb7
184 parent: 0:1f0dee641bb7
185 user: test
185 user: test
186 date: Thu Jan 01 00:00:00 1970 +0000
186 date: Thu Jan 01 00:00:00 1970 +0000
187 summary: add bar
187 summary: add bar
188
188
189 $ hg heads
189 $ hg heads
190 changeset: 3:4cd725637392
190 changeset: 3:4cd725637392
191 tag: tip
191 tag: tip
192 parent: 0:1f0dee641bb7
192 parent: 0:1f0dee641bb7
193 user: test
193 user: test
194 date: Thu Jan 01 00:00:00 1970 +0000
194 date: Thu Jan 01 00:00:00 1970 +0000
195 summary: add bar
195 summary: add bar
196
196
197 changeset: 2:faba9097cad4
197 changeset: 2:faba9097cad4
198 branch: foo
198 branch: foo
199 user: test
199 user: test
200 date: Thu Jan 01 00:00:00 1970 +0000
200 date: Thu Jan 01 00:00:00 1970 +0000
201 summary: new head of branch foo
201 summary: new head of branch foo
202
202
203 Test handling of invalid urls
203
204
205 $ hg id http://foo/?bar
206 abort: unsupported URL component: "bar"
207 [255]
General Comments 0
You need to be logged in to leave comments. Login now