##// END OF EJS Templates
cmdutil: make_filename -> makefilename
Matt Mackall -
r14290:86e70956 default
parent child Browse files
Show More
@@ -1,562 +1,562 b''
1 # patchbomb.py - sending Mercurial changesets as patch emails
1 # patchbomb.py - sending Mercurial changesets as patch emails
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 '''command to send changesets as (a series of) patch emails
8 '''command to send changesets as (a series of) patch emails
9
9
10 The series is started off with a "[PATCH 0 of N]" introduction, which
10 The series is started off with a "[PATCH 0 of N]" introduction, which
11 describes the series as a whole.
11 describes the series as a whole.
12
12
13 Each patch email has a Subject line of "[PATCH M of N] ...", using the
13 Each patch email has a Subject line of "[PATCH M of N] ...", using the
14 first line of the changeset description as the subject text. The
14 first line of the changeset description as the subject text. The
15 message contains two or three body parts:
15 message contains two or three body parts:
16
16
17 - The changeset description.
17 - The changeset description.
18 - [Optional] The result of running diffstat on the patch.
18 - [Optional] The result of running diffstat on the patch.
19 - The patch itself, as generated by :hg:`export`.
19 - The patch itself, as generated by :hg:`export`.
20
20
21 Each message refers to the first in the series using the In-Reply-To
21 Each message refers to the first in the series using the In-Reply-To
22 and References headers, so they will show up as a sequence in threaded
22 and References headers, so they will show up as a sequence in threaded
23 mail and news readers, and in mail archives.
23 mail and news readers, and in mail archives.
24
24
25 To configure other defaults, add a section like this to your
25 To configure other defaults, add a section like this to your
26 configuration file::
26 configuration file::
27
27
28 [email]
28 [email]
29 from = My Name <my@email>
29 from = My Name <my@email>
30 to = recipient1, recipient2, ...
30 to = recipient1, recipient2, ...
31 cc = cc1, cc2, ...
31 cc = cc1, cc2, ...
32 bcc = bcc1, bcc2, ...
32 bcc = bcc1, bcc2, ...
33 reply-to = address1, address2, ...
33 reply-to = address1, address2, ...
34
34
35 Use ``[patchbomb]`` as configuration section name if you need to
35 Use ``[patchbomb]`` as configuration section name if you need to
36 override global ``[email]`` address settings.
36 override global ``[email]`` address settings.
37
37
38 Then you can use the :hg:`email` command to mail a series of
38 Then you can use the :hg:`email` command to mail a series of
39 changesets as a patchbomb.
39 changesets as a patchbomb.
40
40
41 You can also either configure the method option in the email section
41 You can also either configure the method option in the email section
42 to be a sendmail compatible mailer or fill out the [smtp] section so
42 to be a sendmail compatible mailer or fill out the [smtp] section so
43 that the patchbomb extension can automatically send patchbombs
43 that the patchbomb extension can automatically send patchbombs
44 directly from the commandline. See the [email] and [smtp] sections in
44 directly from the commandline. See the [email] and [smtp] sections in
45 hgrc(5) for details.
45 hgrc(5) for details.
46 '''
46 '''
47
47
48 import os, errno, socket, tempfile, cStringIO, time
48 import os, errno, socket, tempfile, cStringIO, time
49 import email.MIMEMultipart, email.MIMEBase
49 import email.MIMEMultipart, email.MIMEBase
50 import email.Utils, email.Encoders, email.Generator
50 import email.Utils, email.Encoders, email.Generator
51 from mercurial import cmdutil, commands, hg, mail, patch, util, discovery
51 from mercurial import cmdutil, commands, hg, mail, patch, util, discovery
52 from mercurial.i18n import _
52 from mercurial.i18n import _
53 from mercurial.node import bin
53 from mercurial.node import bin
54
54
55 def prompt(ui, prompt, default=None, rest=':'):
55 def prompt(ui, prompt, default=None, rest=':'):
56 if not ui.interactive() and default is None:
56 if not ui.interactive() and default is None:
57 raise util.Abort(_("%s Please enter a valid value" % (prompt + rest)))
57 raise util.Abort(_("%s Please enter a valid value" % (prompt + rest)))
58 if default:
58 if default:
59 prompt += ' [%s]' % default
59 prompt += ' [%s]' % default
60 prompt += rest
60 prompt += rest
61 while True:
61 while True:
62 r = ui.prompt(prompt, default=default)
62 r = ui.prompt(prompt, default=default)
63 if r:
63 if r:
64 return r
64 return r
65 if default is not None:
65 if default is not None:
66 return default
66 return default
67 ui.warn(_('Please enter a valid value.\n'))
67 ui.warn(_('Please enter a valid value.\n'))
68
68
69 def introneeded(opts, number):
69 def introneeded(opts, number):
70 '''is an introductory message required?'''
70 '''is an introductory message required?'''
71 return number > 1 or opts.get('intro') or opts.get('desc')
71 return number > 1 or opts.get('intro') or opts.get('desc')
72
72
73 def makepatch(ui, repo, patchlines, opts, _charsets, idx, total,
73 def makepatch(ui, repo, patchlines, opts, _charsets, idx, total,
74 patchname=None):
74 patchname=None):
75
75
76 desc = []
76 desc = []
77 node = None
77 node = None
78 body = ''
78 body = ''
79
79
80 for line in patchlines:
80 for line in patchlines:
81 if line.startswith('#'):
81 if line.startswith('#'):
82 if line.startswith('# Node ID'):
82 if line.startswith('# Node ID'):
83 node = line.split()[-1]
83 node = line.split()[-1]
84 continue
84 continue
85 if line.startswith('diff -r') or line.startswith('diff --git'):
85 if line.startswith('diff -r') or line.startswith('diff --git'):
86 break
86 break
87 desc.append(line)
87 desc.append(line)
88
88
89 if not patchname and not node:
89 if not patchname and not node:
90 raise ValueError
90 raise ValueError
91
91
92 if opts.get('attach'):
92 if opts.get('attach'):
93 body = ('\n'.join(desc[1:]).strip() or
93 body = ('\n'.join(desc[1:]).strip() or
94 'Patch subject is complete summary.')
94 'Patch subject is complete summary.')
95 body += '\n\n\n'
95 body += '\n\n\n'
96
96
97 if opts.get('plain'):
97 if opts.get('plain'):
98 while patchlines and patchlines[0].startswith('# '):
98 while patchlines and patchlines[0].startswith('# '):
99 patchlines.pop(0)
99 patchlines.pop(0)
100 if patchlines:
100 if patchlines:
101 patchlines.pop(0)
101 patchlines.pop(0)
102 while patchlines and not patchlines[0].strip():
102 while patchlines and not patchlines[0].strip():
103 patchlines.pop(0)
103 patchlines.pop(0)
104
104
105 ds = patch.diffstat(patchlines)
105 ds = patch.diffstat(patchlines)
106 if opts.get('diffstat'):
106 if opts.get('diffstat'):
107 body += ds + '\n\n'
107 body += ds + '\n\n'
108
108
109 if opts.get('attach') or opts.get('inline'):
109 if opts.get('attach') or opts.get('inline'):
110 msg = email.MIMEMultipart.MIMEMultipart()
110 msg = email.MIMEMultipart.MIMEMultipart()
111 if body:
111 if body:
112 msg.attach(mail.mimeencode(ui, body, _charsets, opts.get('test')))
112 msg.attach(mail.mimeencode(ui, body, _charsets, opts.get('test')))
113 p = mail.mimetextpatch('\n'.join(patchlines), 'x-patch', opts.get('test'))
113 p = mail.mimetextpatch('\n'.join(patchlines), 'x-patch', opts.get('test'))
114 binnode = bin(node)
114 binnode = bin(node)
115 # if node is mq patch, it will have the patch file's name as a tag
115 # if node is mq patch, it will have the patch file's name as a tag
116 if not patchname:
116 if not patchname:
117 patchtags = [t for t in repo.nodetags(binnode)
117 patchtags = [t for t in repo.nodetags(binnode)
118 if t.endswith('.patch') or t.endswith('.diff')]
118 if t.endswith('.patch') or t.endswith('.diff')]
119 if patchtags:
119 if patchtags:
120 patchname = patchtags[0]
120 patchname = patchtags[0]
121 elif total > 1:
121 elif total > 1:
122 patchname = cmdutil.make_filename(repo, '%b-%n.patch',
122 patchname = cmdutil.makefilename(repo, '%b-%n.patch',
123 binnode, seqno=idx, total=total)
123 binnode, seqno=idx, total=total)
124 else:
124 else:
125 patchname = cmdutil.make_filename(repo, '%b.patch', binnode)
125 patchname = cmdutil.makefilename(repo, '%b.patch', binnode)
126 disposition = 'inline'
126 disposition = 'inline'
127 if opts.get('attach'):
127 if opts.get('attach'):
128 disposition = 'attachment'
128 disposition = 'attachment'
129 p['Content-Disposition'] = disposition + '; filename=' + patchname
129 p['Content-Disposition'] = disposition + '; filename=' + patchname
130 msg.attach(p)
130 msg.attach(p)
131 else:
131 else:
132 body += '\n'.join(patchlines)
132 body += '\n'.join(patchlines)
133 msg = mail.mimetextpatch(body, display=opts.get('test'))
133 msg = mail.mimetextpatch(body, display=opts.get('test'))
134
134
135 flag = ' '.join(opts.get('flag'))
135 flag = ' '.join(opts.get('flag'))
136 if flag:
136 if flag:
137 flag = ' ' + flag
137 flag = ' ' + flag
138
138
139 subj = desc[0].strip().rstrip('. ')
139 subj = desc[0].strip().rstrip('. ')
140 if not introneeded(opts, total):
140 if not introneeded(opts, total):
141 subj = '[PATCH%s] %s' % (flag, opts.get('subject') or subj)
141 subj = '[PATCH%s] %s' % (flag, opts.get('subject') or subj)
142 else:
142 else:
143 tlen = len(str(total))
143 tlen = len(str(total))
144 subj = '[PATCH %0*d of %d%s] %s' % (tlen, idx, total, flag, subj)
144 subj = '[PATCH %0*d of %d%s] %s' % (tlen, idx, total, flag, subj)
145 msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test'))
145 msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test'))
146 msg['X-Mercurial-Node'] = node
146 msg['X-Mercurial-Node'] = node
147 return msg, subj, ds
147 return msg, subj, ds
148
148
149 def patchbomb(ui, repo, *revs, **opts):
149 def patchbomb(ui, repo, *revs, **opts):
150 '''send changesets by email
150 '''send changesets by email
151
151
152 By default, diffs are sent in the format generated by
152 By default, diffs are sent in the format generated by
153 :hg:`export`, one per message. The series starts with a "[PATCH 0
153 :hg:`export`, one per message. The series starts with a "[PATCH 0
154 of N]" introduction, which describes the series as a whole.
154 of N]" introduction, which describes the series as a whole.
155
155
156 Each patch email has a Subject line of "[PATCH M of N] ...", using
156 Each patch email has a Subject line of "[PATCH M of N] ...", using
157 the first line of the changeset description as the subject text.
157 the first line of the changeset description as the subject text.
158 The message contains two or three parts. First, the changeset
158 The message contains two or three parts. First, the changeset
159 description.
159 description.
160
160
161 With the -d/--diffstat option, if the diffstat program is
161 With the -d/--diffstat option, if the diffstat program is
162 installed, the result of running diffstat on the patch is inserted.
162 installed, the result of running diffstat on the patch is inserted.
163
163
164 Finally, the patch itself, as generated by :hg:`export`.
164 Finally, the patch itself, as generated by :hg:`export`.
165
165
166 With the -d/--diffstat or -c/--confirm options, you will be presented
166 With the -d/--diffstat or -c/--confirm options, you will be presented
167 with a final summary of all messages and asked for confirmation before
167 with a final summary of all messages and asked for confirmation before
168 the messages are sent.
168 the messages are sent.
169
169
170 By default the patch is included as text in the email body for
170 By default the patch is included as text in the email body for
171 easy reviewing. Using the -a/--attach option will instead create
171 easy reviewing. Using the -a/--attach option will instead create
172 an attachment for the patch. With -i/--inline an inline attachment
172 an attachment for the patch. With -i/--inline an inline attachment
173 will be created.
173 will be created.
174
174
175 With -o/--outgoing, emails will be generated for patches not found
175 With -o/--outgoing, emails will be generated for patches not found
176 in the destination repository (or only those which are ancestors
176 in the destination repository (or only those which are ancestors
177 of the specified revisions if any are provided)
177 of the specified revisions if any are provided)
178
178
179 With -b/--bundle, changesets are selected as for --outgoing, but a
179 With -b/--bundle, changesets are selected as for --outgoing, but a
180 single email containing a binary Mercurial bundle as an attachment
180 single email containing a binary Mercurial bundle as an attachment
181 will be sent.
181 will be sent.
182
182
183 With -m/--mbox, instead of previewing each patchbomb message in a
183 With -m/--mbox, instead of previewing each patchbomb message in a
184 pager or sending the messages directly, it will create a UNIX
184 pager or sending the messages directly, it will create a UNIX
185 mailbox file with the patch emails. This mailbox file can be
185 mailbox file with the patch emails. This mailbox file can be
186 previewed with any mail user agent which supports UNIX mbox
186 previewed with any mail user agent which supports UNIX mbox
187 files.
187 files.
188
188
189 With -n/--test, all steps will run, but mail will not be sent.
189 With -n/--test, all steps will run, but mail will not be sent.
190 You will be prompted for an email recipient address, a subject and
190 You will be prompted for an email recipient address, a subject and
191 an introductory message describing the patches of your patchbomb.
191 an introductory message describing the patches of your patchbomb.
192 Then when all is done, patchbomb messages are displayed. If the
192 Then when all is done, patchbomb messages are displayed. If the
193 PAGER environment variable is set, your pager will be fired up once
193 PAGER environment variable is set, your pager will be fired up once
194 for each patchbomb message, so you can verify everything is alright.
194 for each patchbomb message, so you can verify everything is alright.
195
195
196 In case email sending fails, you will find a backup of your series
196 In case email sending fails, you will find a backup of your series
197 introductory message in ``.hg/last-email.txt``.
197 introductory message in ``.hg/last-email.txt``.
198
198
199 Examples::
199 Examples::
200
200
201 hg email -r 3000 # send patch 3000 only
201 hg email -r 3000 # send patch 3000 only
202 hg email -r 3000 -r 3001 # send patches 3000 and 3001
202 hg email -r 3000 -r 3001 # send patches 3000 and 3001
203 hg email -r 3000:3005 # send patches 3000 through 3005
203 hg email -r 3000:3005 # send patches 3000 through 3005
204 hg email 3000 # send patch 3000 (deprecated)
204 hg email 3000 # send patch 3000 (deprecated)
205
205
206 hg email -o # send all patches not in default
206 hg email -o # send all patches not in default
207 hg email -o DEST # send all patches not in DEST
207 hg email -o DEST # send all patches not in DEST
208 hg email -o -r 3000 # send all ancestors of 3000 not in default
208 hg email -o -r 3000 # send all ancestors of 3000 not in default
209 hg email -o -r 3000 DEST # send all ancestors of 3000 not in DEST
209 hg email -o -r 3000 DEST # send all ancestors of 3000 not in DEST
210
210
211 hg email -b # send bundle of all patches not in default
211 hg email -b # send bundle of all patches not in default
212 hg email -b DEST # send bundle of all patches not in DEST
212 hg email -b DEST # send bundle of all patches not in DEST
213 hg email -b -r 3000 # bundle of all ancestors of 3000 not in default
213 hg email -b -r 3000 # bundle of all ancestors of 3000 not in default
214 hg email -b -r 3000 DEST # bundle of all ancestors of 3000 not in DEST
214 hg email -b -r 3000 DEST # bundle of all ancestors of 3000 not in DEST
215
215
216 hg email -o -m mbox && # generate an mbox file...
216 hg email -o -m mbox && # generate an mbox file...
217 mutt -R -f mbox # ... and view it with mutt
217 mutt -R -f mbox # ... and view it with mutt
218 hg email -o -m mbox && # generate an mbox file ...
218 hg email -o -m mbox && # generate an mbox file ...
219 formail -s sendmail \\ # ... and use formail to send from the mbox
219 formail -s sendmail \\ # ... and use formail to send from the mbox
220 -bm -t < mbox # ... using sendmail
220 -bm -t < mbox # ... using sendmail
221
221
222 Before using this command, you will need to enable email in your
222 Before using this command, you will need to enable email in your
223 hgrc. See the [email] section in hgrc(5) for details.
223 hgrc. See the [email] section in hgrc(5) for details.
224 '''
224 '''
225
225
226 _charsets = mail._charsets(ui)
226 _charsets = mail._charsets(ui)
227
227
228 bundle = opts.get('bundle')
228 bundle = opts.get('bundle')
229 date = opts.get('date')
229 date = opts.get('date')
230 mbox = opts.get('mbox')
230 mbox = opts.get('mbox')
231 outgoing = opts.get('outgoing')
231 outgoing = opts.get('outgoing')
232 rev = opts.get('rev')
232 rev = opts.get('rev')
233 # internal option used by pbranches
233 # internal option used by pbranches
234 patches = opts.get('patches')
234 patches = opts.get('patches')
235
235
236 def getoutgoing(dest, revs):
236 def getoutgoing(dest, revs):
237 '''Return the revisions present locally but not in dest'''
237 '''Return the revisions present locally but not in dest'''
238 dest = ui.expandpath(dest or 'default-push', dest or 'default')
238 dest = ui.expandpath(dest or 'default-push', dest or 'default')
239 dest, branches = hg.parseurl(dest)
239 dest, branches = hg.parseurl(dest)
240 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
240 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
241 other = hg.repository(hg.remoteui(repo, opts), dest)
241 other = hg.repository(hg.remoteui(repo, opts), dest)
242 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
242 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
243 common, _anyinc, _heads = discovery.findcommonincoming(repo, other)
243 common, _anyinc, _heads = discovery.findcommonincoming(repo, other)
244 nodes = revs and map(repo.lookup, revs) or revs
244 nodes = revs and map(repo.lookup, revs) or revs
245 o = repo.changelog.findmissing(common, heads=nodes)
245 o = repo.changelog.findmissing(common, heads=nodes)
246 if not o:
246 if not o:
247 ui.status(_("no changes found\n"))
247 ui.status(_("no changes found\n"))
248 return []
248 return []
249 return [str(repo.changelog.rev(r)) for r in o]
249 return [str(repo.changelog.rev(r)) for r in o]
250
250
251 def getpatches(revs):
251 def getpatches(revs):
252 for r in cmdutil.revrange(repo, revs):
252 for r in cmdutil.revrange(repo, revs):
253 output = cStringIO.StringIO()
253 output = cStringIO.StringIO()
254 cmdutil.export(repo, [r], fp=output,
254 cmdutil.export(repo, [r], fp=output,
255 opts=patch.diffopts(ui, opts))
255 opts=patch.diffopts(ui, opts))
256 yield output.getvalue().split('\n')
256 yield output.getvalue().split('\n')
257
257
258 def getbundle(dest):
258 def getbundle(dest):
259 tmpdir = tempfile.mkdtemp(prefix='hg-email-bundle-')
259 tmpdir = tempfile.mkdtemp(prefix='hg-email-bundle-')
260 tmpfn = os.path.join(tmpdir, 'bundle')
260 tmpfn = os.path.join(tmpdir, 'bundle')
261 try:
261 try:
262 commands.bundle(ui, repo, tmpfn, dest, **opts)
262 commands.bundle(ui, repo, tmpfn, dest, **opts)
263 fp = open(tmpfn, 'rb')
263 fp = open(tmpfn, 'rb')
264 data = fp.read()
264 data = fp.read()
265 fp.close()
265 fp.close()
266 return data
266 return data
267 finally:
267 finally:
268 try:
268 try:
269 os.unlink(tmpfn)
269 os.unlink(tmpfn)
270 except:
270 except:
271 pass
271 pass
272 os.rmdir(tmpdir)
272 os.rmdir(tmpdir)
273
273
274 if not (opts.get('test') or mbox):
274 if not (opts.get('test') or mbox):
275 # really sending
275 # really sending
276 mail.validateconfig(ui)
276 mail.validateconfig(ui)
277
277
278 if not (revs or rev or outgoing or bundle or patches):
278 if not (revs or rev or outgoing or bundle or patches):
279 raise util.Abort(_('specify at least one changeset with -r or -o'))
279 raise util.Abort(_('specify at least one changeset with -r or -o'))
280
280
281 if outgoing and bundle:
281 if outgoing and bundle:
282 raise util.Abort(_("--outgoing mode always on with --bundle;"
282 raise util.Abort(_("--outgoing mode always on with --bundle;"
283 " do not re-specify --outgoing"))
283 " do not re-specify --outgoing"))
284
284
285 if outgoing or bundle:
285 if outgoing or bundle:
286 if len(revs) > 1:
286 if len(revs) > 1:
287 raise util.Abort(_("too many destinations"))
287 raise util.Abort(_("too many destinations"))
288 dest = revs and revs[0] or None
288 dest = revs and revs[0] or None
289 revs = []
289 revs = []
290
290
291 if rev:
291 if rev:
292 if revs:
292 if revs:
293 raise util.Abort(_('use only one form to specify the revision'))
293 raise util.Abort(_('use only one form to specify the revision'))
294 revs = rev
294 revs = rev
295
295
296 if outgoing:
296 if outgoing:
297 revs = getoutgoing(dest, rev)
297 revs = getoutgoing(dest, rev)
298 if bundle:
298 if bundle:
299 opts['revs'] = revs
299 opts['revs'] = revs
300
300
301 # start
301 # start
302 if date:
302 if date:
303 start_time = util.parsedate(date)
303 start_time = util.parsedate(date)
304 else:
304 else:
305 start_time = util.makedate()
305 start_time = util.makedate()
306
306
307 def genmsgid(id):
307 def genmsgid(id):
308 return '<%s.%s@%s>' % (id[:20], int(start_time[0]), socket.getfqdn())
308 return '<%s.%s@%s>' % (id[:20], int(start_time[0]), socket.getfqdn())
309
309
310 def getdescription(body, sender):
310 def getdescription(body, sender):
311 if opts.get('desc'):
311 if opts.get('desc'):
312 body = open(opts.get('desc')).read()
312 body = open(opts.get('desc')).read()
313 else:
313 else:
314 ui.write(_('\nWrite the introductory message for the '
314 ui.write(_('\nWrite the introductory message for the '
315 'patch series.\n\n'))
315 'patch series.\n\n'))
316 body = ui.edit(body, sender)
316 body = ui.edit(body, sender)
317 # Save serie description in case sendmail fails
317 # Save serie description in case sendmail fails
318 msgfile = repo.opener('last-email.txt', 'wb')
318 msgfile = repo.opener('last-email.txt', 'wb')
319 msgfile.write(body)
319 msgfile.write(body)
320 msgfile.close()
320 msgfile.close()
321 return body
321 return body
322
322
323 def getpatchmsgs(patches, patchnames=None):
323 def getpatchmsgs(patches, patchnames=None):
324 jumbo = []
324 jumbo = []
325 msgs = []
325 msgs = []
326
326
327 ui.write(_('This patch series consists of %d patches.\n\n')
327 ui.write(_('This patch series consists of %d patches.\n\n')
328 % len(patches))
328 % len(patches))
329
329
330 name = None
330 name = None
331 for i, p in enumerate(patches):
331 for i, p in enumerate(patches):
332 jumbo.extend(p)
332 jumbo.extend(p)
333 if patchnames:
333 if patchnames:
334 name = patchnames[i]
334 name = patchnames[i]
335 msg = makepatch(ui, repo, p, opts, _charsets, i + 1,
335 msg = makepatch(ui, repo, p, opts, _charsets, i + 1,
336 len(patches), name)
336 len(patches), name)
337 msgs.append(msg)
337 msgs.append(msg)
338
338
339 if introneeded(opts, len(patches)):
339 if introneeded(opts, len(patches)):
340 tlen = len(str(len(patches)))
340 tlen = len(str(len(patches)))
341
341
342 flag = ' '.join(opts.get('flag'))
342 flag = ' '.join(opts.get('flag'))
343 if flag:
343 if flag:
344 subj = '[PATCH %0*d of %d %s]' % (tlen, 0, len(patches), flag)
344 subj = '[PATCH %0*d of %d %s]' % (tlen, 0, len(patches), flag)
345 else:
345 else:
346 subj = '[PATCH %0*d of %d]' % (tlen, 0, len(patches))
346 subj = '[PATCH %0*d of %d]' % (tlen, 0, len(patches))
347 subj += ' ' + (opts.get('subject') or
347 subj += ' ' + (opts.get('subject') or
348 prompt(ui, 'Subject: ', rest=subj))
348 prompt(ui, 'Subject: ', rest=subj))
349
349
350 body = ''
350 body = ''
351 ds = patch.diffstat(jumbo)
351 ds = patch.diffstat(jumbo)
352 if ds and opts.get('diffstat'):
352 if ds and opts.get('diffstat'):
353 body = '\n' + ds
353 body = '\n' + ds
354
354
355 body = getdescription(body, sender)
355 body = getdescription(body, sender)
356 msg = mail.mimeencode(ui, body, _charsets, opts.get('test'))
356 msg = mail.mimeencode(ui, body, _charsets, opts.get('test'))
357 msg['Subject'] = mail.headencode(ui, subj, _charsets,
357 msg['Subject'] = mail.headencode(ui, subj, _charsets,
358 opts.get('test'))
358 opts.get('test'))
359
359
360 msgs.insert(0, (msg, subj, ds))
360 msgs.insert(0, (msg, subj, ds))
361 return msgs
361 return msgs
362
362
363 def getbundlemsgs(bundle):
363 def getbundlemsgs(bundle):
364 subj = (opts.get('subject')
364 subj = (opts.get('subject')
365 or prompt(ui, 'Subject:', 'A bundle for your repository'))
365 or prompt(ui, 'Subject:', 'A bundle for your repository'))
366
366
367 body = getdescription('', sender)
367 body = getdescription('', sender)
368 msg = email.MIMEMultipart.MIMEMultipart()
368 msg = email.MIMEMultipart.MIMEMultipart()
369 if body:
369 if body:
370 msg.attach(mail.mimeencode(ui, body, _charsets, opts.get('test')))
370 msg.attach(mail.mimeencode(ui, body, _charsets, opts.get('test')))
371 datapart = email.MIMEBase.MIMEBase('application', 'x-mercurial-bundle')
371 datapart = email.MIMEBase.MIMEBase('application', 'x-mercurial-bundle')
372 datapart.set_payload(bundle)
372 datapart.set_payload(bundle)
373 bundlename = '%s.hg' % opts.get('bundlename', 'bundle')
373 bundlename = '%s.hg' % opts.get('bundlename', 'bundle')
374 datapart.add_header('Content-Disposition', 'attachment',
374 datapart.add_header('Content-Disposition', 'attachment',
375 filename=bundlename)
375 filename=bundlename)
376 email.Encoders.encode_base64(datapart)
376 email.Encoders.encode_base64(datapart)
377 msg.attach(datapart)
377 msg.attach(datapart)
378 msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test'))
378 msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test'))
379 return [(msg, subj, None)]
379 return [(msg, subj, None)]
380
380
381 sender = (opts.get('from') or ui.config('email', 'from') or
381 sender = (opts.get('from') or ui.config('email', 'from') or
382 ui.config('patchbomb', 'from') or
382 ui.config('patchbomb', 'from') or
383 prompt(ui, 'From', ui.username()))
383 prompt(ui, 'From', ui.username()))
384
384
385 if patches:
385 if patches:
386 msgs = getpatchmsgs(patches, opts.get('patchnames'))
386 msgs = getpatchmsgs(patches, opts.get('patchnames'))
387 elif bundle:
387 elif bundle:
388 msgs = getbundlemsgs(getbundle(dest))
388 msgs = getbundlemsgs(getbundle(dest))
389 else:
389 else:
390 msgs = getpatchmsgs(list(getpatches(revs)))
390 msgs = getpatchmsgs(list(getpatches(revs)))
391
391
392 showaddrs = []
392 showaddrs = []
393
393
394 def getaddrs(opt, prpt=None, default=None):
394 def getaddrs(opt, prpt=None, default=None):
395 addrs = opts.get(opt.replace('-', '_'))
395 addrs = opts.get(opt.replace('-', '_'))
396 if opt != 'reply-to':
396 if opt != 'reply-to':
397 showaddr = '%s:' % opt.capitalize()
397 showaddr = '%s:' % opt.capitalize()
398 else:
398 else:
399 showaddr = 'Reply-To:'
399 showaddr = 'Reply-To:'
400
400
401 if addrs:
401 if addrs:
402 showaddrs.append('%s %s' % (showaddr, ', '.join(addrs)))
402 showaddrs.append('%s %s' % (showaddr, ', '.join(addrs)))
403 return mail.addrlistencode(ui, addrs, _charsets, opts.get('test'))
403 return mail.addrlistencode(ui, addrs, _charsets, opts.get('test'))
404
404
405 addrs = ui.config('email', opt) or ui.config('patchbomb', opt) or ''
405 addrs = ui.config('email', opt) or ui.config('patchbomb', opt) or ''
406 if not addrs and prpt:
406 if not addrs and prpt:
407 addrs = prompt(ui, prpt, default)
407 addrs = prompt(ui, prpt, default)
408
408
409 if addrs:
409 if addrs:
410 showaddrs.append('%s %s' % (showaddr, addrs))
410 showaddrs.append('%s %s' % (showaddr, addrs))
411 return mail.addrlistencode(ui, [addrs], _charsets, opts.get('test'))
411 return mail.addrlistencode(ui, [addrs], _charsets, opts.get('test'))
412
412
413 to = getaddrs('to', 'To')
413 to = getaddrs('to', 'To')
414 cc = getaddrs('cc', 'Cc', '')
414 cc = getaddrs('cc', 'Cc', '')
415 bcc = getaddrs('bcc')
415 bcc = getaddrs('bcc')
416 replyto = getaddrs('reply-to')
416 replyto = getaddrs('reply-to')
417
417
418 if opts.get('diffstat') or opts.get('confirm'):
418 if opts.get('diffstat') or opts.get('confirm'):
419 ui.write(_('\nFinal summary:\n\n'))
419 ui.write(_('\nFinal summary:\n\n'))
420 ui.write('From: %s\n' % sender)
420 ui.write('From: %s\n' % sender)
421 for addr in showaddrs:
421 for addr in showaddrs:
422 ui.write('%s\n' % addr)
422 ui.write('%s\n' % addr)
423 for m, subj, ds in msgs:
423 for m, subj, ds in msgs:
424 ui.write('Subject: %s\n' % subj)
424 ui.write('Subject: %s\n' % subj)
425 if ds:
425 if ds:
426 ui.write(ds)
426 ui.write(ds)
427 ui.write('\n')
427 ui.write('\n')
428 if ui.promptchoice(_('are you sure you want to send (yn)?'),
428 if ui.promptchoice(_('are you sure you want to send (yn)?'),
429 (_('&Yes'), _('&No'))):
429 (_('&Yes'), _('&No'))):
430 raise util.Abort(_('patchbomb canceled'))
430 raise util.Abort(_('patchbomb canceled'))
431
431
432 ui.write('\n')
432 ui.write('\n')
433
433
434 parent = opts.get('in_reply_to') or None
434 parent = opts.get('in_reply_to') or None
435 # angle brackets may be omitted, they're not semantically part of the msg-id
435 # angle brackets may be omitted, they're not semantically part of the msg-id
436 if parent is not None:
436 if parent is not None:
437 if not parent.startswith('<'):
437 if not parent.startswith('<'):
438 parent = '<' + parent
438 parent = '<' + parent
439 if not parent.endswith('>'):
439 if not parent.endswith('>'):
440 parent += '>'
440 parent += '>'
441
441
442 first = True
442 first = True
443
443
444 sender_addr = email.Utils.parseaddr(sender)[1]
444 sender_addr = email.Utils.parseaddr(sender)[1]
445 sender = mail.addressencode(ui, sender, _charsets, opts.get('test'))
445 sender = mail.addressencode(ui, sender, _charsets, opts.get('test'))
446 sendmail = None
446 sendmail = None
447 for i, (m, subj, ds) in enumerate(msgs):
447 for i, (m, subj, ds) in enumerate(msgs):
448 try:
448 try:
449 m['Message-Id'] = genmsgid(m['X-Mercurial-Node'])
449 m['Message-Id'] = genmsgid(m['X-Mercurial-Node'])
450 except TypeError:
450 except TypeError:
451 m['Message-Id'] = genmsgid('patchbomb')
451 m['Message-Id'] = genmsgid('patchbomb')
452 if parent:
452 if parent:
453 m['In-Reply-To'] = parent
453 m['In-Reply-To'] = parent
454 m['References'] = parent
454 m['References'] = parent
455 if first:
455 if first:
456 parent = m['Message-Id']
456 parent = m['Message-Id']
457 first = False
457 first = False
458
458
459 m['User-Agent'] = 'Mercurial-patchbomb/%s' % util.version()
459 m['User-Agent'] = 'Mercurial-patchbomb/%s' % util.version()
460 m['Date'] = email.Utils.formatdate(start_time[0], localtime=True)
460 m['Date'] = email.Utils.formatdate(start_time[0], localtime=True)
461
461
462 start_time = (start_time[0] + 1, start_time[1])
462 start_time = (start_time[0] + 1, start_time[1])
463 m['From'] = sender
463 m['From'] = sender
464 m['To'] = ', '.join(to)
464 m['To'] = ', '.join(to)
465 if cc:
465 if cc:
466 m['Cc'] = ', '.join(cc)
466 m['Cc'] = ', '.join(cc)
467 if bcc:
467 if bcc:
468 m['Bcc'] = ', '.join(bcc)
468 m['Bcc'] = ', '.join(bcc)
469 if replyto:
469 if replyto:
470 m['Reply-To'] = ', '.join(replyto)
470 m['Reply-To'] = ', '.join(replyto)
471 if opts.get('test'):
471 if opts.get('test'):
472 ui.status(_('Displaying '), subj, ' ...\n')
472 ui.status(_('Displaying '), subj, ' ...\n')
473 ui.flush()
473 ui.flush()
474 if 'PAGER' in os.environ and not ui.plain():
474 if 'PAGER' in os.environ and not ui.plain():
475 fp = util.popen(os.environ['PAGER'], 'w')
475 fp = util.popen(os.environ['PAGER'], 'w')
476 else:
476 else:
477 fp = ui
477 fp = ui
478 generator = email.Generator.Generator(fp, mangle_from_=False)
478 generator = email.Generator.Generator(fp, mangle_from_=False)
479 try:
479 try:
480 generator.flatten(m, 0)
480 generator.flatten(m, 0)
481 fp.write('\n')
481 fp.write('\n')
482 except IOError, inst:
482 except IOError, inst:
483 if inst.errno != errno.EPIPE:
483 if inst.errno != errno.EPIPE:
484 raise
484 raise
485 if fp is not ui:
485 if fp is not ui:
486 fp.close()
486 fp.close()
487 elif mbox:
487 elif mbox:
488 ui.status(_('Writing '), subj, ' ...\n')
488 ui.status(_('Writing '), subj, ' ...\n')
489 ui.progress(_('writing'), i, item=subj, total=len(msgs))
489 ui.progress(_('writing'), i, item=subj, total=len(msgs))
490 fp = open(mbox, 'In-Reply-To' in m and 'ab+' or 'wb+')
490 fp = open(mbox, 'In-Reply-To' in m and 'ab+' or 'wb+')
491 generator = email.Generator.Generator(fp, mangle_from_=True)
491 generator = email.Generator.Generator(fp, mangle_from_=True)
492 # Should be time.asctime(), but Windows prints 2-characters day
492 # Should be time.asctime(), but Windows prints 2-characters day
493 # of month instead of one. Make them print the same thing.
493 # of month instead of one. Make them print the same thing.
494 date = time.strftime('%a %b %d %H:%M:%S %Y',
494 date = time.strftime('%a %b %d %H:%M:%S %Y',
495 time.localtime(start_time[0]))
495 time.localtime(start_time[0]))
496 fp.write('From %s %s\n' % (sender_addr, date))
496 fp.write('From %s %s\n' % (sender_addr, date))
497 generator.flatten(m, 0)
497 generator.flatten(m, 0)
498 fp.write('\n\n')
498 fp.write('\n\n')
499 fp.close()
499 fp.close()
500 else:
500 else:
501 if not sendmail:
501 if not sendmail:
502 sendmail = mail.connect(ui)
502 sendmail = mail.connect(ui)
503 ui.status(_('Sending '), subj, ' ...\n')
503 ui.status(_('Sending '), subj, ' ...\n')
504 ui.progress(_('sending'), i, item=subj, total=len(msgs))
504 ui.progress(_('sending'), i, item=subj, total=len(msgs))
505 # Exim does not remove the Bcc field
505 # Exim does not remove the Bcc field
506 del m['Bcc']
506 del m['Bcc']
507 fp = cStringIO.StringIO()
507 fp = cStringIO.StringIO()
508 generator = email.Generator.Generator(fp, mangle_from_=False)
508 generator = email.Generator.Generator(fp, mangle_from_=False)
509 generator.flatten(m, 0)
509 generator.flatten(m, 0)
510 sendmail(sender, to + bcc + cc, fp.getvalue())
510 sendmail(sender, to + bcc + cc, fp.getvalue())
511
511
512 ui.progress(_('writing'), None)
512 ui.progress(_('writing'), None)
513 ui.progress(_('sending'), None)
513 ui.progress(_('sending'), None)
514
514
515 emailopts = [
515 emailopts = [
516 ('a', 'attach', None, _('send patches as attachments')),
516 ('a', 'attach', None, _('send patches as attachments')),
517 ('i', 'inline', None, _('send patches as inline attachments')),
517 ('i', 'inline', None, _('send patches as inline attachments')),
518 ('', 'bcc', [], _('email addresses of blind carbon copy recipients')),
518 ('', 'bcc', [], _('email addresses of blind carbon copy recipients')),
519 ('c', 'cc', [], _('email addresses of copy recipients')),
519 ('c', 'cc', [], _('email addresses of copy recipients')),
520 ('', 'confirm', None, _('ask for confirmation before sending')),
520 ('', 'confirm', None, _('ask for confirmation before sending')),
521 ('d', 'diffstat', None, _('add diffstat output to messages')),
521 ('d', 'diffstat', None, _('add diffstat output to messages')),
522 ('', 'date', '', _('use the given date as the sending date')),
522 ('', 'date', '', _('use the given date as the sending date')),
523 ('', 'desc', '', _('use the given file as the series description')),
523 ('', 'desc', '', _('use the given file as the series description')),
524 ('f', 'from', '', _('email address of sender')),
524 ('f', 'from', '', _('email address of sender')),
525 ('n', 'test', None, _('print messages that would be sent')),
525 ('n', 'test', None, _('print messages that would be sent')),
526 ('m', 'mbox', '',
526 ('m', 'mbox', '',
527 _('write messages to mbox file instead of sending them')),
527 _('write messages to mbox file instead of sending them')),
528 ('', 'reply-to', [], _('email addresses replies should be sent to')),
528 ('', 'reply-to', [], _('email addresses replies should be sent to')),
529 ('s', 'subject', '',
529 ('s', 'subject', '',
530 _('subject of first message (intro or single patch)')),
530 _('subject of first message (intro or single patch)')),
531 ('', 'in-reply-to', '',
531 ('', 'in-reply-to', '',
532 _('message identifier to reply to')),
532 _('message identifier to reply to')),
533 ('', 'flag', [], _('flags to add in subject prefixes')),
533 ('', 'flag', [], _('flags to add in subject prefixes')),
534 ('t', 'to', [], _('email addresses of recipients')),
534 ('t', 'to', [], _('email addresses of recipients')),
535 ]
535 ]
536
536
537
537
538 cmdtable = {
538 cmdtable = {
539 "email":
539 "email":
540 (patchbomb,
540 (patchbomb,
541 [('g', 'git', None, _('use git extended diff format')),
541 [('g', 'git', None, _('use git extended diff format')),
542 ('', 'plain', None, _('omit hg patch header')),
542 ('', 'plain', None, _('omit hg patch header')),
543 ('o', 'outgoing', None,
543 ('o', 'outgoing', None,
544 _('send changes not found in the target repository')),
544 _('send changes not found in the target repository')),
545 ('b', 'bundle', None,
545 ('b', 'bundle', None,
546 _('send changes not in target as a binary bundle')),
546 _('send changes not in target as a binary bundle')),
547 ('', 'bundlename', 'bundle',
547 ('', 'bundlename', 'bundle',
548 _('name of the bundle attachment file'), _('NAME')),
548 _('name of the bundle attachment file'), _('NAME')),
549 ('r', 'rev', [],
549 ('r', 'rev', [],
550 _('a revision to send'), _('REV')),
550 _('a revision to send'), _('REV')),
551 ('', 'force', None,
551 ('', 'force', None,
552 _('run even when remote repository is unrelated '
552 _('run even when remote repository is unrelated '
553 '(with -b/--bundle)')),
553 '(with -b/--bundle)')),
554 ('', 'base', [],
554 ('', 'base', [],
555 _('a base changeset to specify instead of a destination '
555 _('a base changeset to specify instead of a destination '
556 '(with -b/--bundle)'),
556 '(with -b/--bundle)'),
557 _('REV')),
557 _('REV')),
558 ('', 'intro', None,
558 ('', 'intro', None,
559 _('send an introduction email for a single patch')),
559 _('send an introduction email for a single patch')),
560 ] + emailopts + commands.remoteopts,
560 ] + emailopts + commands.remoteopts,
561 _('hg email [OPTION]... [DEST]...'))
561 _('hg email [OPTION]... [DEST]...'))
562 }
562 }
@@ -1,1253 +1,1253 b''
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, nullid, nullrev, short
8 from node import hex, nullid, nullrev, short
9 from i18n import _
9 from i18n import _
10 import os, sys, errno, re, tempfile
10 import os, sys, errno, re, tempfile
11 import util, scmutil, templater, patch, error, templatekw, wdutil
11 import util, scmutil, templater, patch, error, templatekw, wdutil
12 import match as matchmod
12 import match as matchmod
13 import revset, subrepo
13 import revset, subrepo
14
14
15 expandpats = wdutil.expandpats
15 expandpats = wdutil.expandpats
16 match = wdutil.match
16 match = wdutil.match
17 matchall = wdutil.matchall
17 matchall = wdutil.matchall
18 matchfiles = wdutil.matchfiles
18 matchfiles = wdutil.matchfiles
19 addremove = wdutil.addremove
19 addremove = wdutil.addremove
20 dirstatecopy = wdutil.dirstatecopy
20 dirstatecopy = wdutil.dirstatecopy
21
21
22 revrangesep = ':'
22 revrangesep = ':'
23
23
24 def parsealiases(cmd):
24 def parsealiases(cmd):
25 return cmd.lstrip("^").split("|")
25 return cmd.lstrip("^").split("|")
26
26
27 def findpossible(cmd, table, strict=False):
27 def findpossible(cmd, table, strict=False):
28 """
28 """
29 Return cmd -> (aliases, command table entry)
29 Return cmd -> (aliases, command table entry)
30 for each matching command.
30 for each matching command.
31 Return debug commands (or their aliases) only if no normal command matches.
31 Return debug commands (or their aliases) only if no normal command matches.
32 """
32 """
33 choice = {}
33 choice = {}
34 debugchoice = {}
34 debugchoice = {}
35 for e in table.keys():
35 for e in table.keys():
36 aliases = parsealiases(e)
36 aliases = parsealiases(e)
37 found = None
37 found = None
38 if cmd in aliases:
38 if cmd in aliases:
39 found = cmd
39 found = cmd
40 elif not strict:
40 elif not strict:
41 for a in aliases:
41 for a in aliases:
42 if a.startswith(cmd):
42 if a.startswith(cmd):
43 found = a
43 found = a
44 break
44 break
45 if found is not None:
45 if found is not None:
46 if aliases[0].startswith("debug") or found.startswith("debug"):
46 if aliases[0].startswith("debug") or found.startswith("debug"):
47 debugchoice[found] = (aliases, table[e])
47 debugchoice[found] = (aliases, table[e])
48 else:
48 else:
49 choice[found] = (aliases, table[e])
49 choice[found] = (aliases, table[e])
50
50
51 if not choice and debugchoice:
51 if not choice and debugchoice:
52 choice = debugchoice
52 choice = debugchoice
53
53
54 return choice
54 return choice
55
55
56 def findcmd(cmd, table, strict=True):
56 def findcmd(cmd, table, strict=True):
57 """Return (aliases, command table entry) for command string."""
57 """Return (aliases, command table entry) for command string."""
58 choice = findpossible(cmd, table, strict)
58 choice = findpossible(cmd, table, strict)
59
59
60 if cmd in choice:
60 if cmd in choice:
61 return choice[cmd]
61 return choice[cmd]
62
62
63 if len(choice) > 1:
63 if len(choice) > 1:
64 clist = choice.keys()
64 clist = choice.keys()
65 clist.sort()
65 clist.sort()
66 raise error.AmbiguousCommand(cmd, clist)
66 raise error.AmbiguousCommand(cmd, clist)
67
67
68 if choice:
68 if choice:
69 return choice.values()[0]
69 return choice.values()[0]
70
70
71 raise error.UnknownCommand(cmd)
71 raise error.UnknownCommand(cmd)
72
72
73 def findrepo(p):
73 def findrepo(p):
74 while not os.path.isdir(os.path.join(p, ".hg")):
74 while not os.path.isdir(os.path.join(p, ".hg")):
75 oldp, p = p, os.path.dirname(p)
75 oldp, p = p, os.path.dirname(p)
76 if p == oldp:
76 if p == oldp:
77 return None
77 return None
78
78
79 return p
79 return p
80
80
81 def bailifchanged(repo):
81 def bailifchanged(repo):
82 if repo.dirstate.p2() != nullid:
82 if repo.dirstate.p2() != nullid:
83 raise util.Abort(_('outstanding uncommitted merge'))
83 raise util.Abort(_('outstanding uncommitted merge'))
84 modified, added, removed, deleted = repo.status()[:4]
84 modified, added, removed, deleted = repo.status()[:4]
85 if modified or added or removed or deleted:
85 if modified or added or removed or deleted:
86 raise util.Abort(_("outstanding uncommitted changes"))
86 raise util.Abort(_("outstanding uncommitted changes"))
87
87
88 def logmessage(opts):
88 def logmessage(opts):
89 """ get the log message according to -m and -l option """
89 """ get the log message according to -m and -l option """
90 message = opts.get('message')
90 message = opts.get('message')
91 logfile = opts.get('logfile')
91 logfile = opts.get('logfile')
92
92
93 if message and logfile:
93 if message and logfile:
94 raise util.Abort(_('options --message and --logfile are mutually '
94 raise util.Abort(_('options --message and --logfile are mutually '
95 'exclusive'))
95 'exclusive'))
96 if not message and logfile:
96 if not message and logfile:
97 try:
97 try:
98 if logfile == '-':
98 if logfile == '-':
99 message = sys.stdin.read()
99 message = sys.stdin.read()
100 else:
100 else:
101 message = '\n'.join(util.readfile(logfile).splitlines())
101 message = '\n'.join(util.readfile(logfile).splitlines())
102 except IOError, inst:
102 except IOError, inst:
103 raise util.Abort(_("can't read commit message '%s': %s") %
103 raise util.Abort(_("can't read commit message '%s': %s") %
104 (logfile, inst.strerror))
104 (logfile, inst.strerror))
105 return message
105 return message
106
106
107 def loglimit(opts):
107 def loglimit(opts):
108 """get the log limit according to option -l/--limit"""
108 """get the log limit according to option -l/--limit"""
109 limit = opts.get('limit')
109 limit = opts.get('limit')
110 if limit:
110 if limit:
111 try:
111 try:
112 limit = int(limit)
112 limit = int(limit)
113 except ValueError:
113 except ValueError:
114 raise util.Abort(_('limit must be a positive integer'))
114 raise util.Abort(_('limit must be a positive integer'))
115 if limit <= 0:
115 if limit <= 0:
116 raise util.Abort(_('limit must be positive'))
116 raise util.Abort(_('limit must be positive'))
117 else:
117 else:
118 limit = None
118 limit = None
119 return limit
119 return limit
120
120
121 def revsingle(repo, revspec, default='.'):
121 def revsingle(repo, revspec, default='.'):
122 if not revspec:
122 if not revspec:
123 return repo[default]
123 return repo[default]
124
124
125 l = revrange(repo, [revspec])
125 l = revrange(repo, [revspec])
126 if len(l) < 1:
126 if len(l) < 1:
127 raise util.Abort(_('empty revision set'))
127 raise util.Abort(_('empty revision set'))
128 return repo[l[-1]]
128 return repo[l[-1]]
129
129
130 def revpair(repo, revs):
130 def revpair(repo, revs):
131 if not revs:
131 if not revs:
132 return repo.dirstate.p1(), None
132 return repo.dirstate.p1(), None
133
133
134 l = revrange(repo, revs)
134 l = revrange(repo, revs)
135
135
136 if len(l) == 0:
136 if len(l) == 0:
137 return repo.dirstate.p1(), None
137 return repo.dirstate.p1(), None
138
138
139 if len(l) == 1:
139 if len(l) == 1:
140 return repo.lookup(l[0]), None
140 return repo.lookup(l[0]), None
141
141
142 return repo.lookup(l[0]), repo.lookup(l[-1])
142 return repo.lookup(l[0]), repo.lookup(l[-1])
143
143
144 def revrange(repo, revs):
144 def revrange(repo, revs):
145 """Yield revision as strings from a list of revision specifications."""
145 """Yield revision as strings from a list of revision specifications."""
146
146
147 def revfix(repo, val, defval):
147 def revfix(repo, val, defval):
148 if not val and val != 0 and defval is not None:
148 if not val and val != 0 and defval is not None:
149 return defval
149 return defval
150 return repo.changelog.rev(repo.lookup(val))
150 return repo.changelog.rev(repo.lookup(val))
151
151
152 seen, l = set(), []
152 seen, l = set(), []
153 for spec in revs:
153 for spec in revs:
154 # attempt to parse old-style ranges first to deal with
154 # attempt to parse old-style ranges first to deal with
155 # things like old-tag which contain query metacharacters
155 # things like old-tag which contain query metacharacters
156 try:
156 try:
157 if isinstance(spec, int):
157 if isinstance(spec, int):
158 seen.add(spec)
158 seen.add(spec)
159 l.append(spec)
159 l.append(spec)
160 continue
160 continue
161
161
162 if revrangesep in spec:
162 if revrangesep in spec:
163 start, end = spec.split(revrangesep, 1)
163 start, end = spec.split(revrangesep, 1)
164 start = revfix(repo, start, 0)
164 start = revfix(repo, start, 0)
165 end = revfix(repo, end, len(repo) - 1)
165 end = revfix(repo, end, len(repo) - 1)
166 step = start > end and -1 or 1
166 step = start > end and -1 or 1
167 for rev in xrange(start, end + step, step):
167 for rev in xrange(start, end + step, step):
168 if rev in seen:
168 if rev in seen:
169 continue
169 continue
170 seen.add(rev)
170 seen.add(rev)
171 l.append(rev)
171 l.append(rev)
172 continue
172 continue
173 elif spec and spec in repo: # single unquoted rev
173 elif spec and spec in repo: # single unquoted rev
174 rev = revfix(repo, spec, None)
174 rev = revfix(repo, spec, None)
175 if rev in seen:
175 if rev in seen:
176 continue
176 continue
177 seen.add(rev)
177 seen.add(rev)
178 l.append(rev)
178 l.append(rev)
179 continue
179 continue
180 except error.RepoLookupError:
180 except error.RepoLookupError:
181 pass
181 pass
182
182
183 # fall through to new-style queries if old-style fails
183 # fall through to new-style queries if old-style fails
184 m = revset.match(repo.ui, spec)
184 m = revset.match(repo.ui, spec)
185 for r in m(repo, range(len(repo))):
185 for r in m(repo, range(len(repo))):
186 if r not in seen:
186 if r not in seen:
187 l.append(r)
187 l.append(r)
188 seen.update(l)
188 seen.update(l)
189
189
190 return l
190 return l
191
191
192 def make_filename(repo, pat, node,
192 def makefilename(repo, pat, node,
193 total=None, seqno=None, revwidth=None, pathname=None):
193 total=None, seqno=None, revwidth=None, pathname=None):
194 node_expander = {
194 node_expander = {
195 'H': lambda: hex(node),
195 'H': lambda: hex(node),
196 'R': lambda: str(repo.changelog.rev(node)),
196 'R': lambda: str(repo.changelog.rev(node)),
197 'h': lambda: short(node),
197 'h': lambda: short(node),
198 }
198 }
199 expander = {
199 expander = {
200 '%': lambda: '%',
200 '%': lambda: '%',
201 'b': lambda: os.path.basename(repo.root),
201 'b': lambda: os.path.basename(repo.root),
202 }
202 }
203
203
204 try:
204 try:
205 if node:
205 if node:
206 expander.update(node_expander)
206 expander.update(node_expander)
207 if node:
207 if node:
208 expander['r'] = (lambda:
208 expander['r'] = (lambda:
209 str(repo.changelog.rev(node)).zfill(revwidth or 0))
209 str(repo.changelog.rev(node)).zfill(revwidth or 0))
210 if total is not None:
210 if total is not None:
211 expander['N'] = lambda: str(total)
211 expander['N'] = lambda: str(total)
212 if seqno is not None:
212 if seqno is not None:
213 expander['n'] = lambda: str(seqno)
213 expander['n'] = lambda: str(seqno)
214 if total is not None and seqno is not None:
214 if total is not None and seqno is not None:
215 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
215 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
216 if pathname is not None:
216 if pathname is not None:
217 expander['s'] = lambda: os.path.basename(pathname)
217 expander['s'] = lambda: os.path.basename(pathname)
218 expander['d'] = lambda: os.path.dirname(pathname) or '.'
218 expander['d'] = lambda: os.path.dirname(pathname) or '.'
219 expander['p'] = lambda: pathname
219 expander['p'] = lambda: pathname
220
220
221 newname = []
221 newname = []
222 patlen = len(pat)
222 patlen = len(pat)
223 i = 0
223 i = 0
224 while i < patlen:
224 while i < patlen:
225 c = pat[i]
225 c = pat[i]
226 if c == '%':
226 if c == '%':
227 i += 1
227 i += 1
228 c = pat[i]
228 c = pat[i]
229 c = expander[c]()
229 c = expander[c]()
230 newname.append(c)
230 newname.append(c)
231 i += 1
231 i += 1
232 return ''.join(newname)
232 return ''.join(newname)
233 except KeyError, inst:
233 except KeyError, inst:
234 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
234 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
235 inst.args[0])
235 inst.args[0])
236
236
237 def make_file(repo, pat, node=None,
237 def make_file(repo, pat, node=None,
238 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
238 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
239
239
240 writable = mode not in ('r', 'rb')
240 writable = mode not in ('r', 'rb')
241
241
242 if not pat or pat == '-':
242 if not pat or pat == '-':
243 fp = writable and sys.stdout or sys.stdin
243 fp = writable and sys.stdout or sys.stdin
244 return os.fdopen(os.dup(fp.fileno()), mode)
244 return os.fdopen(os.dup(fp.fileno()), mode)
245 if hasattr(pat, 'write') and writable:
245 if hasattr(pat, 'write') and writable:
246 return pat
246 return pat
247 if hasattr(pat, 'read') and 'r' in mode:
247 if hasattr(pat, 'read') and 'r' in mode:
248 return pat
248 return pat
249 return open(make_filename(repo, pat, node, total, seqno, revwidth,
249 return open(makefilename(repo, pat, node, total, seqno, revwidth,
250 pathname),
250 pathname),
251 mode)
251 mode)
252
252
253 def copy(ui, repo, pats, opts, rename=False):
253 def copy(ui, repo, pats, opts, rename=False):
254 # called with the repo lock held
254 # called with the repo lock held
255 #
255 #
256 # hgsep => pathname that uses "/" to separate directories
256 # hgsep => pathname that uses "/" to separate directories
257 # ossep => pathname that uses os.sep to separate directories
257 # ossep => pathname that uses os.sep to separate directories
258 cwd = repo.getcwd()
258 cwd = repo.getcwd()
259 targets = {}
259 targets = {}
260 after = opts.get("after")
260 after = opts.get("after")
261 dryrun = opts.get("dry_run")
261 dryrun = opts.get("dry_run")
262 wctx = repo[None]
262 wctx = repo[None]
263
263
264 def walkpat(pat):
264 def walkpat(pat):
265 srcs = []
265 srcs = []
266 badstates = after and '?' or '?r'
266 badstates = after and '?' or '?r'
267 m = match(repo, [pat], opts, globbed=True)
267 m = match(repo, [pat], opts, globbed=True)
268 for abs in repo.walk(m):
268 for abs in repo.walk(m):
269 state = repo.dirstate[abs]
269 state = repo.dirstate[abs]
270 rel = m.rel(abs)
270 rel = m.rel(abs)
271 exact = m.exact(abs)
271 exact = m.exact(abs)
272 if state in badstates:
272 if state in badstates:
273 if exact and state == '?':
273 if exact and state == '?':
274 ui.warn(_('%s: not copying - file is not managed\n') % rel)
274 ui.warn(_('%s: not copying - file is not managed\n') % rel)
275 if exact and state == 'r':
275 if exact and state == 'r':
276 ui.warn(_('%s: not copying - file has been marked for'
276 ui.warn(_('%s: not copying - file has been marked for'
277 ' remove\n') % rel)
277 ' remove\n') % rel)
278 continue
278 continue
279 # abs: hgsep
279 # abs: hgsep
280 # rel: ossep
280 # rel: ossep
281 srcs.append((abs, rel, exact))
281 srcs.append((abs, rel, exact))
282 return srcs
282 return srcs
283
283
284 # abssrc: hgsep
284 # abssrc: hgsep
285 # relsrc: ossep
285 # relsrc: ossep
286 # otarget: ossep
286 # otarget: ossep
287 def copyfile(abssrc, relsrc, otarget, exact):
287 def copyfile(abssrc, relsrc, otarget, exact):
288 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
288 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
289 reltarget = repo.pathto(abstarget, cwd)
289 reltarget = repo.pathto(abstarget, cwd)
290 target = repo.wjoin(abstarget)
290 target = repo.wjoin(abstarget)
291 src = repo.wjoin(abssrc)
291 src = repo.wjoin(abssrc)
292 state = repo.dirstate[abstarget]
292 state = repo.dirstate[abstarget]
293
293
294 scmutil.checkportable(ui, abstarget)
294 scmutil.checkportable(ui, abstarget)
295
295
296 # check for collisions
296 # check for collisions
297 prevsrc = targets.get(abstarget)
297 prevsrc = targets.get(abstarget)
298 if prevsrc is not None:
298 if prevsrc is not None:
299 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
299 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
300 (reltarget, repo.pathto(abssrc, cwd),
300 (reltarget, repo.pathto(abssrc, cwd),
301 repo.pathto(prevsrc, cwd)))
301 repo.pathto(prevsrc, cwd)))
302 return
302 return
303
303
304 # check for overwrites
304 # check for overwrites
305 exists = os.path.lexists(target)
305 exists = os.path.lexists(target)
306 if not after and exists or after and state in 'mn':
306 if not after and exists or after and state in 'mn':
307 if not opts['force']:
307 if not opts['force']:
308 ui.warn(_('%s: not overwriting - file exists\n') %
308 ui.warn(_('%s: not overwriting - file exists\n') %
309 reltarget)
309 reltarget)
310 return
310 return
311
311
312 if after:
312 if after:
313 if not exists:
313 if not exists:
314 if rename:
314 if rename:
315 ui.warn(_('%s: not recording move - %s does not exist\n') %
315 ui.warn(_('%s: not recording move - %s does not exist\n') %
316 (relsrc, reltarget))
316 (relsrc, reltarget))
317 else:
317 else:
318 ui.warn(_('%s: not recording copy - %s does not exist\n') %
318 ui.warn(_('%s: not recording copy - %s does not exist\n') %
319 (relsrc, reltarget))
319 (relsrc, reltarget))
320 return
320 return
321 elif not dryrun:
321 elif not dryrun:
322 try:
322 try:
323 if exists:
323 if exists:
324 os.unlink(target)
324 os.unlink(target)
325 targetdir = os.path.dirname(target) or '.'
325 targetdir = os.path.dirname(target) or '.'
326 if not os.path.isdir(targetdir):
326 if not os.path.isdir(targetdir):
327 os.makedirs(targetdir)
327 os.makedirs(targetdir)
328 util.copyfile(src, target)
328 util.copyfile(src, target)
329 except IOError, inst:
329 except IOError, inst:
330 if inst.errno == errno.ENOENT:
330 if inst.errno == errno.ENOENT:
331 ui.warn(_('%s: deleted in working copy\n') % relsrc)
331 ui.warn(_('%s: deleted in working copy\n') % relsrc)
332 else:
332 else:
333 ui.warn(_('%s: cannot copy - %s\n') %
333 ui.warn(_('%s: cannot copy - %s\n') %
334 (relsrc, inst.strerror))
334 (relsrc, inst.strerror))
335 return True # report a failure
335 return True # report a failure
336
336
337 if ui.verbose or not exact:
337 if ui.verbose or not exact:
338 if rename:
338 if rename:
339 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
339 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
340 else:
340 else:
341 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
341 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
342
342
343 targets[abstarget] = abssrc
343 targets[abstarget] = abssrc
344
344
345 # fix up dirstate
345 # fix up dirstate
346 dirstatecopy(ui, repo, wctx, abssrc, abstarget, dryrun=dryrun, cwd=cwd)
346 dirstatecopy(ui, repo, wctx, abssrc, abstarget, dryrun=dryrun, cwd=cwd)
347 if rename and not dryrun:
347 if rename and not dryrun:
348 wctx.remove([abssrc], not after)
348 wctx.remove([abssrc], not after)
349
349
350 # pat: ossep
350 # pat: ossep
351 # dest ossep
351 # dest ossep
352 # srcs: list of (hgsep, hgsep, ossep, bool)
352 # srcs: list of (hgsep, hgsep, ossep, bool)
353 # return: function that takes hgsep and returns ossep
353 # return: function that takes hgsep and returns ossep
354 def targetpathfn(pat, dest, srcs):
354 def targetpathfn(pat, dest, srcs):
355 if os.path.isdir(pat):
355 if os.path.isdir(pat):
356 abspfx = scmutil.canonpath(repo.root, cwd, pat)
356 abspfx = scmutil.canonpath(repo.root, cwd, pat)
357 abspfx = util.localpath(abspfx)
357 abspfx = util.localpath(abspfx)
358 if destdirexists:
358 if destdirexists:
359 striplen = len(os.path.split(abspfx)[0])
359 striplen = len(os.path.split(abspfx)[0])
360 else:
360 else:
361 striplen = len(abspfx)
361 striplen = len(abspfx)
362 if striplen:
362 if striplen:
363 striplen += len(os.sep)
363 striplen += len(os.sep)
364 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
364 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
365 elif destdirexists:
365 elif destdirexists:
366 res = lambda p: os.path.join(dest,
366 res = lambda p: os.path.join(dest,
367 os.path.basename(util.localpath(p)))
367 os.path.basename(util.localpath(p)))
368 else:
368 else:
369 res = lambda p: dest
369 res = lambda p: dest
370 return res
370 return res
371
371
372 # pat: ossep
372 # pat: ossep
373 # dest ossep
373 # dest ossep
374 # srcs: list of (hgsep, hgsep, ossep, bool)
374 # srcs: list of (hgsep, hgsep, ossep, bool)
375 # return: function that takes hgsep and returns ossep
375 # return: function that takes hgsep and returns ossep
376 def targetpathafterfn(pat, dest, srcs):
376 def targetpathafterfn(pat, dest, srcs):
377 if matchmod.patkind(pat):
377 if matchmod.patkind(pat):
378 # a mercurial pattern
378 # a mercurial pattern
379 res = lambda p: os.path.join(dest,
379 res = lambda p: os.path.join(dest,
380 os.path.basename(util.localpath(p)))
380 os.path.basename(util.localpath(p)))
381 else:
381 else:
382 abspfx = scmutil.canonpath(repo.root, cwd, pat)
382 abspfx = scmutil.canonpath(repo.root, cwd, pat)
383 if len(abspfx) < len(srcs[0][0]):
383 if len(abspfx) < len(srcs[0][0]):
384 # A directory. Either the target path contains the last
384 # A directory. Either the target path contains the last
385 # component of the source path or it does not.
385 # component of the source path or it does not.
386 def evalpath(striplen):
386 def evalpath(striplen):
387 score = 0
387 score = 0
388 for s in srcs:
388 for s in srcs:
389 t = os.path.join(dest, util.localpath(s[0])[striplen:])
389 t = os.path.join(dest, util.localpath(s[0])[striplen:])
390 if os.path.lexists(t):
390 if os.path.lexists(t):
391 score += 1
391 score += 1
392 return score
392 return score
393
393
394 abspfx = util.localpath(abspfx)
394 abspfx = util.localpath(abspfx)
395 striplen = len(abspfx)
395 striplen = len(abspfx)
396 if striplen:
396 if striplen:
397 striplen += len(os.sep)
397 striplen += len(os.sep)
398 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
398 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
399 score = evalpath(striplen)
399 score = evalpath(striplen)
400 striplen1 = len(os.path.split(abspfx)[0])
400 striplen1 = len(os.path.split(abspfx)[0])
401 if striplen1:
401 if striplen1:
402 striplen1 += len(os.sep)
402 striplen1 += len(os.sep)
403 if evalpath(striplen1) > score:
403 if evalpath(striplen1) > score:
404 striplen = striplen1
404 striplen = striplen1
405 res = lambda p: os.path.join(dest,
405 res = lambda p: os.path.join(dest,
406 util.localpath(p)[striplen:])
406 util.localpath(p)[striplen:])
407 else:
407 else:
408 # a file
408 # a file
409 if destdirexists:
409 if destdirexists:
410 res = lambda p: os.path.join(dest,
410 res = lambda p: os.path.join(dest,
411 os.path.basename(util.localpath(p)))
411 os.path.basename(util.localpath(p)))
412 else:
412 else:
413 res = lambda p: dest
413 res = lambda p: dest
414 return res
414 return res
415
415
416
416
417 pats = expandpats(pats)
417 pats = expandpats(pats)
418 if not pats:
418 if not pats:
419 raise util.Abort(_('no source or destination specified'))
419 raise util.Abort(_('no source or destination specified'))
420 if len(pats) == 1:
420 if len(pats) == 1:
421 raise util.Abort(_('no destination specified'))
421 raise util.Abort(_('no destination specified'))
422 dest = pats.pop()
422 dest = pats.pop()
423 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
423 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
424 if not destdirexists:
424 if not destdirexists:
425 if len(pats) > 1 or matchmod.patkind(pats[0]):
425 if len(pats) > 1 or matchmod.patkind(pats[0]):
426 raise util.Abort(_('with multiple sources, destination must be an '
426 raise util.Abort(_('with multiple sources, destination must be an '
427 'existing directory'))
427 'existing directory'))
428 if util.endswithsep(dest):
428 if util.endswithsep(dest):
429 raise util.Abort(_('destination %s is not a directory') % dest)
429 raise util.Abort(_('destination %s is not a directory') % dest)
430
430
431 tfn = targetpathfn
431 tfn = targetpathfn
432 if after:
432 if after:
433 tfn = targetpathafterfn
433 tfn = targetpathafterfn
434 copylist = []
434 copylist = []
435 for pat in pats:
435 for pat in pats:
436 srcs = walkpat(pat)
436 srcs = walkpat(pat)
437 if not srcs:
437 if not srcs:
438 continue
438 continue
439 copylist.append((tfn(pat, dest, srcs), srcs))
439 copylist.append((tfn(pat, dest, srcs), srcs))
440 if not copylist:
440 if not copylist:
441 raise util.Abort(_('no files to copy'))
441 raise util.Abort(_('no files to copy'))
442
442
443 errors = 0
443 errors = 0
444 for targetpath, srcs in copylist:
444 for targetpath, srcs in copylist:
445 for abssrc, relsrc, exact in srcs:
445 for abssrc, relsrc, exact in srcs:
446 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
446 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
447 errors += 1
447 errors += 1
448
448
449 if errors:
449 if errors:
450 ui.warn(_('(consider using --after)\n'))
450 ui.warn(_('(consider using --after)\n'))
451
451
452 return errors != 0
452 return errors != 0
453
453
454 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
454 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
455 runargs=None, appendpid=False):
455 runargs=None, appendpid=False):
456 '''Run a command as a service.'''
456 '''Run a command as a service.'''
457
457
458 if opts['daemon'] and not opts['daemon_pipefds']:
458 if opts['daemon'] and not opts['daemon_pipefds']:
459 # Signal child process startup with file removal
459 # Signal child process startup with file removal
460 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
460 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
461 os.close(lockfd)
461 os.close(lockfd)
462 try:
462 try:
463 if not runargs:
463 if not runargs:
464 runargs = util.hgcmd() + sys.argv[1:]
464 runargs = util.hgcmd() + sys.argv[1:]
465 runargs.append('--daemon-pipefds=%s' % lockpath)
465 runargs.append('--daemon-pipefds=%s' % lockpath)
466 # Don't pass --cwd to the child process, because we've already
466 # Don't pass --cwd to the child process, because we've already
467 # changed directory.
467 # changed directory.
468 for i in xrange(1, len(runargs)):
468 for i in xrange(1, len(runargs)):
469 if runargs[i].startswith('--cwd='):
469 if runargs[i].startswith('--cwd='):
470 del runargs[i]
470 del runargs[i]
471 break
471 break
472 elif runargs[i].startswith('--cwd'):
472 elif runargs[i].startswith('--cwd'):
473 del runargs[i:i + 2]
473 del runargs[i:i + 2]
474 break
474 break
475 def condfn():
475 def condfn():
476 return not os.path.exists(lockpath)
476 return not os.path.exists(lockpath)
477 pid = util.rundetached(runargs, condfn)
477 pid = util.rundetached(runargs, condfn)
478 if pid < 0:
478 if pid < 0:
479 raise util.Abort(_('child process failed to start'))
479 raise util.Abort(_('child process failed to start'))
480 finally:
480 finally:
481 try:
481 try:
482 os.unlink(lockpath)
482 os.unlink(lockpath)
483 except OSError, e:
483 except OSError, e:
484 if e.errno != errno.ENOENT:
484 if e.errno != errno.ENOENT:
485 raise
485 raise
486 if parentfn:
486 if parentfn:
487 return parentfn(pid)
487 return parentfn(pid)
488 else:
488 else:
489 return
489 return
490
490
491 if initfn:
491 if initfn:
492 initfn()
492 initfn()
493
493
494 if opts['pid_file']:
494 if opts['pid_file']:
495 mode = appendpid and 'a' or 'w'
495 mode = appendpid and 'a' or 'w'
496 fp = open(opts['pid_file'], mode)
496 fp = open(opts['pid_file'], mode)
497 fp.write(str(os.getpid()) + '\n')
497 fp.write(str(os.getpid()) + '\n')
498 fp.close()
498 fp.close()
499
499
500 if opts['daemon_pipefds']:
500 if opts['daemon_pipefds']:
501 lockpath = opts['daemon_pipefds']
501 lockpath = opts['daemon_pipefds']
502 try:
502 try:
503 os.setsid()
503 os.setsid()
504 except AttributeError:
504 except AttributeError:
505 pass
505 pass
506 os.unlink(lockpath)
506 os.unlink(lockpath)
507 util.hidewindow()
507 util.hidewindow()
508 sys.stdout.flush()
508 sys.stdout.flush()
509 sys.stderr.flush()
509 sys.stderr.flush()
510
510
511 nullfd = os.open(util.nulldev, os.O_RDWR)
511 nullfd = os.open(util.nulldev, os.O_RDWR)
512 logfilefd = nullfd
512 logfilefd = nullfd
513 if logfile:
513 if logfile:
514 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
514 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
515 os.dup2(nullfd, 0)
515 os.dup2(nullfd, 0)
516 os.dup2(logfilefd, 1)
516 os.dup2(logfilefd, 1)
517 os.dup2(logfilefd, 2)
517 os.dup2(logfilefd, 2)
518 if nullfd not in (0, 1, 2):
518 if nullfd not in (0, 1, 2):
519 os.close(nullfd)
519 os.close(nullfd)
520 if logfile and logfilefd not in (0, 1, 2):
520 if logfile and logfilefd not in (0, 1, 2):
521 os.close(logfilefd)
521 os.close(logfilefd)
522
522
523 if runfn:
523 if runfn:
524 return runfn()
524 return runfn()
525
525
526 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
526 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
527 opts=None):
527 opts=None):
528 '''export changesets as hg patches.'''
528 '''export changesets as hg patches.'''
529
529
530 total = len(revs)
530 total = len(revs)
531 revwidth = max([len(str(rev)) for rev in revs])
531 revwidth = max([len(str(rev)) for rev in revs])
532
532
533 def single(rev, seqno, fp):
533 def single(rev, seqno, fp):
534 ctx = repo[rev]
534 ctx = repo[rev]
535 node = ctx.node()
535 node = ctx.node()
536 parents = [p.node() for p in ctx.parents() if p]
536 parents = [p.node() for p in ctx.parents() if p]
537 branch = ctx.branch()
537 branch = ctx.branch()
538 if switch_parent:
538 if switch_parent:
539 parents.reverse()
539 parents.reverse()
540 prev = (parents and parents[0]) or nullid
540 prev = (parents and parents[0]) or nullid
541
541
542 shouldclose = False
542 shouldclose = False
543 if not fp:
543 if not fp:
544 fp = make_file(repo, template, node, total=total, seqno=seqno,
544 fp = make_file(repo, template, node, total=total, seqno=seqno,
545 revwidth=revwidth, mode='ab')
545 revwidth=revwidth, mode='ab')
546 if fp != template:
546 if fp != template:
547 shouldclose = True
547 shouldclose = True
548 if fp != sys.stdout and hasattr(fp, 'name'):
548 if fp != sys.stdout and hasattr(fp, 'name'):
549 repo.ui.note("%s\n" % fp.name)
549 repo.ui.note("%s\n" % fp.name)
550
550
551 fp.write("# HG changeset patch\n")
551 fp.write("# HG changeset patch\n")
552 fp.write("# User %s\n" % ctx.user())
552 fp.write("# User %s\n" % ctx.user())
553 fp.write("# Date %d %d\n" % ctx.date())
553 fp.write("# Date %d %d\n" % ctx.date())
554 if branch and branch != 'default':
554 if branch and branch != 'default':
555 fp.write("# Branch %s\n" % branch)
555 fp.write("# Branch %s\n" % branch)
556 fp.write("# Node ID %s\n" % hex(node))
556 fp.write("# Node ID %s\n" % hex(node))
557 fp.write("# Parent %s\n" % hex(prev))
557 fp.write("# Parent %s\n" % hex(prev))
558 if len(parents) > 1:
558 if len(parents) > 1:
559 fp.write("# Parent %s\n" % hex(parents[1]))
559 fp.write("# Parent %s\n" % hex(parents[1]))
560 fp.write(ctx.description().rstrip())
560 fp.write(ctx.description().rstrip())
561 fp.write("\n\n")
561 fp.write("\n\n")
562
562
563 for chunk in patch.diff(repo, prev, node, opts=opts):
563 for chunk in patch.diff(repo, prev, node, opts=opts):
564 fp.write(chunk)
564 fp.write(chunk)
565
565
566 if shouldclose:
566 if shouldclose:
567 fp.close()
567 fp.close()
568
568
569 for seqno, rev in enumerate(revs):
569 for seqno, rev in enumerate(revs):
570 single(rev, seqno + 1, fp)
570 single(rev, seqno + 1, fp)
571
571
572 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
572 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
573 changes=None, stat=False, fp=None, prefix='',
573 changes=None, stat=False, fp=None, prefix='',
574 listsubrepos=False):
574 listsubrepos=False):
575 '''show diff or diffstat.'''
575 '''show diff or diffstat.'''
576 if fp is None:
576 if fp is None:
577 write = ui.write
577 write = ui.write
578 else:
578 else:
579 def write(s, **kw):
579 def write(s, **kw):
580 fp.write(s)
580 fp.write(s)
581
581
582 if stat:
582 if stat:
583 diffopts = diffopts.copy(context=0)
583 diffopts = diffopts.copy(context=0)
584 width = 80
584 width = 80
585 if not ui.plain():
585 if not ui.plain():
586 width = ui.termwidth()
586 width = ui.termwidth()
587 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
587 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
588 prefix=prefix)
588 prefix=prefix)
589 for chunk, label in patch.diffstatui(util.iterlines(chunks),
589 for chunk, label in patch.diffstatui(util.iterlines(chunks),
590 width=width,
590 width=width,
591 git=diffopts.git):
591 git=diffopts.git):
592 write(chunk, label=label)
592 write(chunk, label=label)
593 else:
593 else:
594 for chunk, label in patch.diffui(repo, node1, node2, match,
594 for chunk, label in patch.diffui(repo, node1, node2, match,
595 changes, diffopts, prefix=prefix):
595 changes, diffopts, prefix=prefix):
596 write(chunk, label=label)
596 write(chunk, label=label)
597
597
598 if listsubrepos:
598 if listsubrepos:
599 ctx1 = repo[node1]
599 ctx1 = repo[node1]
600 ctx2 = repo[node2]
600 ctx2 = repo[node2]
601 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
601 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
602 if node2 is not None:
602 if node2 is not None:
603 node2 = ctx2.substate[subpath][1]
603 node2 = ctx2.substate[subpath][1]
604 submatch = matchmod.narrowmatcher(subpath, match)
604 submatch = matchmod.narrowmatcher(subpath, match)
605 sub.diff(diffopts, node2, submatch, changes=changes,
605 sub.diff(diffopts, node2, submatch, changes=changes,
606 stat=stat, fp=fp, prefix=prefix)
606 stat=stat, fp=fp, prefix=prefix)
607
607
608 class changeset_printer(object):
608 class changeset_printer(object):
609 '''show changeset information when templating not requested.'''
609 '''show changeset information when templating not requested.'''
610
610
611 def __init__(self, ui, repo, patch, diffopts, buffered):
611 def __init__(self, ui, repo, patch, diffopts, buffered):
612 self.ui = ui
612 self.ui = ui
613 self.repo = repo
613 self.repo = repo
614 self.buffered = buffered
614 self.buffered = buffered
615 self.patch = patch
615 self.patch = patch
616 self.diffopts = diffopts
616 self.diffopts = diffopts
617 self.header = {}
617 self.header = {}
618 self.hunk = {}
618 self.hunk = {}
619 self.lastheader = None
619 self.lastheader = None
620 self.footer = None
620 self.footer = None
621
621
622 def flush(self, rev):
622 def flush(self, rev):
623 if rev in self.header:
623 if rev in self.header:
624 h = self.header[rev]
624 h = self.header[rev]
625 if h != self.lastheader:
625 if h != self.lastheader:
626 self.lastheader = h
626 self.lastheader = h
627 self.ui.write(h)
627 self.ui.write(h)
628 del self.header[rev]
628 del self.header[rev]
629 if rev in self.hunk:
629 if rev in self.hunk:
630 self.ui.write(self.hunk[rev])
630 self.ui.write(self.hunk[rev])
631 del self.hunk[rev]
631 del self.hunk[rev]
632 return 1
632 return 1
633 return 0
633 return 0
634
634
635 def close(self):
635 def close(self):
636 if self.footer:
636 if self.footer:
637 self.ui.write(self.footer)
637 self.ui.write(self.footer)
638
638
639 def show(self, ctx, copies=None, matchfn=None, **props):
639 def show(self, ctx, copies=None, matchfn=None, **props):
640 if self.buffered:
640 if self.buffered:
641 self.ui.pushbuffer()
641 self.ui.pushbuffer()
642 self._show(ctx, copies, matchfn, props)
642 self._show(ctx, copies, matchfn, props)
643 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
643 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
644 else:
644 else:
645 self._show(ctx, copies, matchfn, props)
645 self._show(ctx, copies, matchfn, props)
646
646
647 def _show(self, ctx, copies, matchfn, props):
647 def _show(self, ctx, copies, matchfn, props):
648 '''show a single changeset or file revision'''
648 '''show a single changeset or file revision'''
649 changenode = ctx.node()
649 changenode = ctx.node()
650 rev = ctx.rev()
650 rev = ctx.rev()
651
651
652 if self.ui.quiet:
652 if self.ui.quiet:
653 self.ui.write("%d:%s\n" % (rev, short(changenode)),
653 self.ui.write("%d:%s\n" % (rev, short(changenode)),
654 label='log.node')
654 label='log.node')
655 return
655 return
656
656
657 log = self.repo.changelog
657 log = self.repo.changelog
658 date = util.datestr(ctx.date())
658 date = util.datestr(ctx.date())
659
659
660 hexfunc = self.ui.debugflag and hex or short
660 hexfunc = self.ui.debugflag and hex or short
661
661
662 parents = [(p, hexfunc(log.node(p)))
662 parents = [(p, hexfunc(log.node(p)))
663 for p in self._meaningful_parentrevs(log, rev)]
663 for p in self._meaningful_parentrevs(log, rev)]
664
664
665 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
665 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
666 label='log.changeset')
666 label='log.changeset')
667
667
668 branch = ctx.branch()
668 branch = ctx.branch()
669 # don't show the default branch name
669 # don't show the default branch name
670 if branch != 'default':
670 if branch != 'default':
671 self.ui.write(_("branch: %s\n") % branch,
671 self.ui.write(_("branch: %s\n") % branch,
672 label='log.branch')
672 label='log.branch')
673 for bookmark in self.repo.nodebookmarks(changenode):
673 for bookmark in self.repo.nodebookmarks(changenode):
674 self.ui.write(_("bookmark: %s\n") % bookmark,
674 self.ui.write(_("bookmark: %s\n") % bookmark,
675 label='log.bookmark')
675 label='log.bookmark')
676 for tag in self.repo.nodetags(changenode):
676 for tag in self.repo.nodetags(changenode):
677 self.ui.write(_("tag: %s\n") % tag,
677 self.ui.write(_("tag: %s\n") % tag,
678 label='log.tag')
678 label='log.tag')
679 for parent in parents:
679 for parent in parents:
680 self.ui.write(_("parent: %d:%s\n") % parent,
680 self.ui.write(_("parent: %d:%s\n") % parent,
681 label='log.parent')
681 label='log.parent')
682
682
683 if self.ui.debugflag:
683 if self.ui.debugflag:
684 mnode = ctx.manifestnode()
684 mnode = ctx.manifestnode()
685 self.ui.write(_("manifest: %d:%s\n") %
685 self.ui.write(_("manifest: %d:%s\n") %
686 (self.repo.manifest.rev(mnode), hex(mnode)),
686 (self.repo.manifest.rev(mnode), hex(mnode)),
687 label='ui.debug log.manifest')
687 label='ui.debug log.manifest')
688 self.ui.write(_("user: %s\n") % ctx.user(),
688 self.ui.write(_("user: %s\n") % ctx.user(),
689 label='log.user')
689 label='log.user')
690 self.ui.write(_("date: %s\n") % date,
690 self.ui.write(_("date: %s\n") % date,
691 label='log.date')
691 label='log.date')
692
692
693 if self.ui.debugflag:
693 if self.ui.debugflag:
694 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
694 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
695 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
695 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
696 files):
696 files):
697 if value:
697 if value:
698 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
698 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
699 label='ui.debug log.files')
699 label='ui.debug log.files')
700 elif ctx.files() and self.ui.verbose:
700 elif ctx.files() and self.ui.verbose:
701 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
701 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
702 label='ui.note log.files')
702 label='ui.note log.files')
703 if copies and self.ui.verbose:
703 if copies and self.ui.verbose:
704 copies = ['%s (%s)' % c for c in copies]
704 copies = ['%s (%s)' % c for c in copies]
705 self.ui.write(_("copies: %s\n") % ' '.join(copies),
705 self.ui.write(_("copies: %s\n") % ' '.join(copies),
706 label='ui.note log.copies')
706 label='ui.note log.copies')
707
707
708 extra = ctx.extra()
708 extra = ctx.extra()
709 if extra and self.ui.debugflag:
709 if extra and self.ui.debugflag:
710 for key, value in sorted(extra.items()):
710 for key, value in sorted(extra.items()):
711 self.ui.write(_("extra: %s=%s\n")
711 self.ui.write(_("extra: %s=%s\n")
712 % (key, value.encode('string_escape')),
712 % (key, value.encode('string_escape')),
713 label='ui.debug log.extra')
713 label='ui.debug log.extra')
714
714
715 description = ctx.description().strip()
715 description = ctx.description().strip()
716 if description:
716 if description:
717 if self.ui.verbose:
717 if self.ui.verbose:
718 self.ui.write(_("description:\n"),
718 self.ui.write(_("description:\n"),
719 label='ui.note log.description')
719 label='ui.note log.description')
720 self.ui.write(description,
720 self.ui.write(description,
721 label='ui.note log.description')
721 label='ui.note log.description')
722 self.ui.write("\n\n")
722 self.ui.write("\n\n")
723 else:
723 else:
724 self.ui.write(_("summary: %s\n") %
724 self.ui.write(_("summary: %s\n") %
725 description.splitlines()[0],
725 description.splitlines()[0],
726 label='log.summary')
726 label='log.summary')
727 self.ui.write("\n")
727 self.ui.write("\n")
728
728
729 self.showpatch(changenode, matchfn)
729 self.showpatch(changenode, matchfn)
730
730
731 def showpatch(self, node, matchfn):
731 def showpatch(self, node, matchfn):
732 if not matchfn:
732 if not matchfn:
733 matchfn = self.patch
733 matchfn = self.patch
734 if matchfn:
734 if matchfn:
735 stat = self.diffopts.get('stat')
735 stat = self.diffopts.get('stat')
736 diff = self.diffopts.get('patch')
736 diff = self.diffopts.get('patch')
737 diffopts = patch.diffopts(self.ui, self.diffopts)
737 diffopts = patch.diffopts(self.ui, self.diffopts)
738 prev = self.repo.changelog.parents(node)[0]
738 prev = self.repo.changelog.parents(node)[0]
739 if stat:
739 if stat:
740 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
740 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
741 match=matchfn, stat=True)
741 match=matchfn, stat=True)
742 if diff:
742 if diff:
743 if stat:
743 if stat:
744 self.ui.write("\n")
744 self.ui.write("\n")
745 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
745 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
746 match=matchfn, stat=False)
746 match=matchfn, stat=False)
747 self.ui.write("\n")
747 self.ui.write("\n")
748
748
749 def _meaningful_parentrevs(self, log, rev):
749 def _meaningful_parentrevs(self, log, rev):
750 """Return list of meaningful (or all if debug) parentrevs for rev.
750 """Return list of meaningful (or all if debug) parentrevs for rev.
751
751
752 For merges (two non-nullrev revisions) both parents are meaningful.
752 For merges (two non-nullrev revisions) both parents are meaningful.
753 Otherwise the first parent revision is considered meaningful if it
753 Otherwise the first parent revision is considered meaningful if it
754 is not the preceding revision.
754 is not the preceding revision.
755 """
755 """
756 parents = log.parentrevs(rev)
756 parents = log.parentrevs(rev)
757 if not self.ui.debugflag and parents[1] == nullrev:
757 if not self.ui.debugflag and parents[1] == nullrev:
758 if parents[0] >= rev - 1:
758 if parents[0] >= rev - 1:
759 parents = []
759 parents = []
760 else:
760 else:
761 parents = [parents[0]]
761 parents = [parents[0]]
762 return parents
762 return parents
763
763
764
764
765 class changeset_templater(changeset_printer):
765 class changeset_templater(changeset_printer):
766 '''format changeset information.'''
766 '''format changeset information.'''
767
767
768 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
768 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
769 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
769 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
770 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
770 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
771 defaulttempl = {
771 defaulttempl = {
772 'parent': '{rev}:{node|formatnode} ',
772 'parent': '{rev}:{node|formatnode} ',
773 'manifest': '{rev}:{node|formatnode}',
773 'manifest': '{rev}:{node|formatnode}',
774 'file_copy': '{name} ({source})',
774 'file_copy': '{name} ({source})',
775 'extra': '{key}={value|stringescape}'
775 'extra': '{key}={value|stringescape}'
776 }
776 }
777 # filecopy is preserved for compatibility reasons
777 # filecopy is preserved for compatibility reasons
778 defaulttempl['filecopy'] = defaulttempl['file_copy']
778 defaulttempl['filecopy'] = defaulttempl['file_copy']
779 self.t = templater.templater(mapfile, {'formatnode': formatnode},
779 self.t = templater.templater(mapfile, {'formatnode': formatnode},
780 cache=defaulttempl)
780 cache=defaulttempl)
781 self.cache = {}
781 self.cache = {}
782
782
783 def use_template(self, t):
783 def use_template(self, t):
784 '''set template string to use'''
784 '''set template string to use'''
785 self.t.cache['changeset'] = t
785 self.t.cache['changeset'] = t
786
786
787 def _meaningful_parentrevs(self, ctx):
787 def _meaningful_parentrevs(self, ctx):
788 """Return list of meaningful (or all if debug) parentrevs for rev.
788 """Return list of meaningful (or all if debug) parentrevs for rev.
789 """
789 """
790 parents = ctx.parents()
790 parents = ctx.parents()
791 if len(parents) > 1:
791 if len(parents) > 1:
792 return parents
792 return parents
793 if self.ui.debugflag:
793 if self.ui.debugflag:
794 return [parents[0], self.repo['null']]
794 return [parents[0], self.repo['null']]
795 if parents[0].rev() >= ctx.rev() - 1:
795 if parents[0].rev() >= ctx.rev() - 1:
796 return []
796 return []
797 return parents
797 return parents
798
798
799 def _show(self, ctx, copies, matchfn, props):
799 def _show(self, ctx, copies, matchfn, props):
800 '''show a single changeset or file revision'''
800 '''show a single changeset or file revision'''
801
801
802 showlist = templatekw.showlist
802 showlist = templatekw.showlist
803
803
804 # showparents() behaviour depends on ui trace level which
804 # showparents() behaviour depends on ui trace level which
805 # causes unexpected behaviours at templating level and makes
805 # causes unexpected behaviours at templating level and makes
806 # it harder to extract it in a standalone function. Its
806 # it harder to extract it in a standalone function. Its
807 # behaviour cannot be changed so leave it here for now.
807 # behaviour cannot be changed so leave it here for now.
808 def showparents(**args):
808 def showparents(**args):
809 ctx = args['ctx']
809 ctx = args['ctx']
810 parents = [[('rev', p.rev()), ('node', p.hex())]
810 parents = [[('rev', p.rev()), ('node', p.hex())]
811 for p in self._meaningful_parentrevs(ctx)]
811 for p in self._meaningful_parentrevs(ctx)]
812 return showlist('parent', parents, **args)
812 return showlist('parent', parents, **args)
813
813
814 props = props.copy()
814 props = props.copy()
815 props.update(templatekw.keywords)
815 props.update(templatekw.keywords)
816 props['parents'] = showparents
816 props['parents'] = showparents
817 props['templ'] = self.t
817 props['templ'] = self.t
818 props['ctx'] = ctx
818 props['ctx'] = ctx
819 props['repo'] = self.repo
819 props['repo'] = self.repo
820 props['revcache'] = {'copies': copies}
820 props['revcache'] = {'copies': copies}
821 props['cache'] = self.cache
821 props['cache'] = self.cache
822
822
823 # find correct templates for current mode
823 # find correct templates for current mode
824
824
825 tmplmodes = [
825 tmplmodes = [
826 (True, None),
826 (True, None),
827 (self.ui.verbose, 'verbose'),
827 (self.ui.verbose, 'verbose'),
828 (self.ui.quiet, 'quiet'),
828 (self.ui.quiet, 'quiet'),
829 (self.ui.debugflag, 'debug'),
829 (self.ui.debugflag, 'debug'),
830 ]
830 ]
831
831
832 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
832 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
833 for mode, postfix in tmplmodes:
833 for mode, postfix in tmplmodes:
834 for type in types:
834 for type in types:
835 cur = postfix and ('%s_%s' % (type, postfix)) or type
835 cur = postfix and ('%s_%s' % (type, postfix)) or type
836 if mode and cur in self.t:
836 if mode and cur in self.t:
837 types[type] = cur
837 types[type] = cur
838
838
839 try:
839 try:
840
840
841 # write header
841 # write header
842 if types['header']:
842 if types['header']:
843 h = templater.stringify(self.t(types['header'], **props))
843 h = templater.stringify(self.t(types['header'], **props))
844 if self.buffered:
844 if self.buffered:
845 self.header[ctx.rev()] = h
845 self.header[ctx.rev()] = h
846 else:
846 else:
847 if self.lastheader != h:
847 if self.lastheader != h:
848 self.lastheader = h
848 self.lastheader = h
849 self.ui.write(h)
849 self.ui.write(h)
850
850
851 # write changeset metadata, then patch if requested
851 # write changeset metadata, then patch if requested
852 key = types['changeset']
852 key = types['changeset']
853 self.ui.write(templater.stringify(self.t(key, **props)))
853 self.ui.write(templater.stringify(self.t(key, **props)))
854 self.showpatch(ctx.node(), matchfn)
854 self.showpatch(ctx.node(), matchfn)
855
855
856 if types['footer']:
856 if types['footer']:
857 if not self.footer:
857 if not self.footer:
858 self.footer = templater.stringify(self.t(types['footer'],
858 self.footer = templater.stringify(self.t(types['footer'],
859 **props))
859 **props))
860
860
861 except KeyError, inst:
861 except KeyError, inst:
862 msg = _("%s: no key named '%s'")
862 msg = _("%s: no key named '%s'")
863 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
863 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
864 except SyntaxError, inst:
864 except SyntaxError, inst:
865 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
865 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
866
866
867 def show_changeset(ui, repo, opts, buffered=False):
867 def show_changeset(ui, repo, opts, buffered=False):
868 """show one changeset using template or regular display.
868 """show one changeset using template or regular display.
869
869
870 Display format will be the first non-empty hit of:
870 Display format will be the first non-empty hit of:
871 1. option 'template'
871 1. option 'template'
872 2. option 'style'
872 2. option 'style'
873 3. [ui] setting 'logtemplate'
873 3. [ui] setting 'logtemplate'
874 4. [ui] setting 'style'
874 4. [ui] setting 'style'
875 If all of these values are either the unset or the empty string,
875 If all of these values are either the unset or the empty string,
876 regular display via changeset_printer() is done.
876 regular display via changeset_printer() is done.
877 """
877 """
878 # options
878 # options
879 patch = False
879 patch = False
880 if opts.get('patch') or opts.get('stat'):
880 if opts.get('patch') or opts.get('stat'):
881 patch = matchall(repo)
881 patch = matchall(repo)
882
882
883 tmpl = opts.get('template')
883 tmpl = opts.get('template')
884 style = None
884 style = None
885 if tmpl:
885 if tmpl:
886 tmpl = templater.parsestring(tmpl, quoted=False)
886 tmpl = templater.parsestring(tmpl, quoted=False)
887 else:
887 else:
888 style = opts.get('style')
888 style = opts.get('style')
889
889
890 # ui settings
890 # ui settings
891 if not (tmpl or style):
891 if not (tmpl or style):
892 tmpl = ui.config('ui', 'logtemplate')
892 tmpl = ui.config('ui', 'logtemplate')
893 if tmpl:
893 if tmpl:
894 tmpl = templater.parsestring(tmpl)
894 tmpl = templater.parsestring(tmpl)
895 else:
895 else:
896 style = util.expandpath(ui.config('ui', 'style', ''))
896 style = util.expandpath(ui.config('ui', 'style', ''))
897
897
898 if not (tmpl or style):
898 if not (tmpl or style):
899 return changeset_printer(ui, repo, patch, opts, buffered)
899 return changeset_printer(ui, repo, patch, opts, buffered)
900
900
901 mapfile = None
901 mapfile = None
902 if style and not tmpl:
902 if style and not tmpl:
903 mapfile = style
903 mapfile = style
904 if not os.path.split(mapfile)[0]:
904 if not os.path.split(mapfile)[0]:
905 mapname = (templater.templatepath('map-cmdline.' + mapfile)
905 mapname = (templater.templatepath('map-cmdline.' + mapfile)
906 or templater.templatepath(mapfile))
906 or templater.templatepath(mapfile))
907 if mapname:
907 if mapname:
908 mapfile = mapname
908 mapfile = mapname
909
909
910 try:
910 try:
911 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
911 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
912 except SyntaxError, inst:
912 except SyntaxError, inst:
913 raise util.Abort(inst.args[0])
913 raise util.Abort(inst.args[0])
914 if tmpl:
914 if tmpl:
915 t.use_template(tmpl)
915 t.use_template(tmpl)
916 return t
916 return t
917
917
918 def finddate(ui, repo, date):
918 def finddate(ui, repo, date):
919 """Find the tipmost changeset that matches the given date spec"""
919 """Find the tipmost changeset that matches the given date spec"""
920
920
921 df = util.matchdate(date)
921 df = util.matchdate(date)
922 m = matchall(repo)
922 m = matchall(repo)
923 results = {}
923 results = {}
924
924
925 def prep(ctx, fns):
925 def prep(ctx, fns):
926 d = ctx.date()
926 d = ctx.date()
927 if df(d[0]):
927 if df(d[0]):
928 results[ctx.rev()] = d
928 results[ctx.rev()] = d
929
929
930 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
930 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
931 rev = ctx.rev()
931 rev = ctx.rev()
932 if rev in results:
932 if rev in results:
933 ui.status(_("Found revision %s from %s\n") %
933 ui.status(_("Found revision %s from %s\n") %
934 (rev, util.datestr(results[rev])))
934 (rev, util.datestr(results[rev])))
935 return str(rev)
935 return str(rev)
936
936
937 raise util.Abort(_("revision matching date not found"))
937 raise util.Abort(_("revision matching date not found"))
938
938
939 def walkchangerevs(repo, match, opts, prepare):
939 def walkchangerevs(repo, match, opts, prepare):
940 '''Iterate over files and the revs in which they changed.
940 '''Iterate over files and the revs in which they changed.
941
941
942 Callers most commonly need to iterate backwards over the history
942 Callers most commonly need to iterate backwards over the history
943 in which they are interested. Doing so has awful (quadratic-looking)
943 in which they are interested. Doing so has awful (quadratic-looking)
944 performance, so we use iterators in a "windowed" way.
944 performance, so we use iterators in a "windowed" way.
945
945
946 We walk a window of revisions in the desired order. Within the
946 We walk a window of revisions in the desired order. Within the
947 window, we first walk forwards to gather data, then in the desired
947 window, we first walk forwards to gather data, then in the desired
948 order (usually backwards) to display it.
948 order (usually backwards) to display it.
949
949
950 This function returns an iterator yielding contexts. Before
950 This function returns an iterator yielding contexts. Before
951 yielding each context, the iterator will first call the prepare
951 yielding each context, the iterator will first call the prepare
952 function on each context in the window in forward order.'''
952 function on each context in the window in forward order.'''
953
953
954 def increasing_windows(start, end, windowsize=8, sizelimit=512):
954 def increasing_windows(start, end, windowsize=8, sizelimit=512):
955 if start < end:
955 if start < end:
956 while start < end:
956 while start < end:
957 yield start, min(windowsize, end - start)
957 yield start, min(windowsize, end - start)
958 start += windowsize
958 start += windowsize
959 if windowsize < sizelimit:
959 if windowsize < sizelimit:
960 windowsize *= 2
960 windowsize *= 2
961 else:
961 else:
962 while start > end:
962 while start > end:
963 yield start, min(windowsize, start - end - 1)
963 yield start, min(windowsize, start - end - 1)
964 start -= windowsize
964 start -= windowsize
965 if windowsize < sizelimit:
965 if windowsize < sizelimit:
966 windowsize *= 2
966 windowsize *= 2
967
967
968 follow = opts.get('follow') or opts.get('follow_first')
968 follow = opts.get('follow') or opts.get('follow_first')
969
969
970 if not len(repo):
970 if not len(repo):
971 return []
971 return []
972
972
973 if follow:
973 if follow:
974 defrange = '%s:0' % repo['.'].rev()
974 defrange = '%s:0' % repo['.'].rev()
975 else:
975 else:
976 defrange = '-1:0'
976 defrange = '-1:0'
977 revs = revrange(repo, opts['rev'] or [defrange])
977 revs = revrange(repo, opts['rev'] or [defrange])
978 if not revs:
978 if not revs:
979 return []
979 return []
980 wanted = set()
980 wanted = set()
981 slowpath = match.anypats() or (match.files() and opts.get('removed'))
981 slowpath = match.anypats() or (match.files() and opts.get('removed'))
982 fncache = {}
982 fncache = {}
983 change = util.cachefunc(repo.changectx)
983 change = util.cachefunc(repo.changectx)
984
984
985 # First step is to fill wanted, the set of revisions that we want to yield.
985 # First step is to fill wanted, the set of revisions that we want to yield.
986 # When it does not induce extra cost, we also fill fncache for revisions in
986 # When it does not induce extra cost, we also fill fncache for revisions in
987 # wanted: a cache of filenames that were changed (ctx.files()) and that
987 # wanted: a cache of filenames that were changed (ctx.files()) and that
988 # match the file filtering conditions.
988 # match the file filtering conditions.
989
989
990 if not slowpath and not match.files():
990 if not slowpath and not match.files():
991 # No files, no patterns. Display all revs.
991 # No files, no patterns. Display all revs.
992 wanted = set(revs)
992 wanted = set(revs)
993 copies = []
993 copies = []
994
994
995 if not slowpath:
995 if not slowpath:
996 # We only have to read through the filelog to find wanted revisions
996 # We only have to read through the filelog to find wanted revisions
997
997
998 minrev, maxrev = min(revs), max(revs)
998 minrev, maxrev = min(revs), max(revs)
999 def filerevgen(filelog, last):
999 def filerevgen(filelog, last):
1000 """
1000 """
1001 Only files, no patterns. Check the history of each file.
1001 Only files, no patterns. Check the history of each file.
1002
1002
1003 Examines filelog entries within minrev, maxrev linkrev range
1003 Examines filelog entries within minrev, maxrev linkrev range
1004 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1004 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1005 tuples in backwards order
1005 tuples in backwards order
1006 """
1006 """
1007 cl_count = len(repo)
1007 cl_count = len(repo)
1008 revs = []
1008 revs = []
1009 for j in xrange(0, last + 1):
1009 for j in xrange(0, last + 1):
1010 linkrev = filelog.linkrev(j)
1010 linkrev = filelog.linkrev(j)
1011 if linkrev < minrev:
1011 if linkrev < minrev:
1012 continue
1012 continue
1013 # only yield rev for which we have the changelog, it can
1013 # only yield rev for which we have the changelog, it can
1014 # happen while doing "hg log" during a pull or commit
1014 # happen while doing "hg log" during a pull or commit
1015 if linkrev >= cl_count:
1015 if linkrev >= cl_count:
1016 break
1016 break
1017
1017
1018 parentlinkrevs = []
1018 parentlinkrevs = []
1019 for p in filelog.parentrevs(j):
1019 for p in filelog.parentrevs(j):
1020 if p != nullrev:
1020 if p != nullrev:
1021 parentlinkrevs.append(filelog.linkrev(p))
1021 parentlinkrevs.append(filelog.linkrev(p))
1022 n = filelog.node(j)
1022 n = filelog.node(j)
1023 revs.append((linkrev, parentlinkrevs,
1023 revs.append((linkrev, parentlinkrevs,
1024 follow and filelog.renamed(n)))
1024 follow and filelog.renamed(n)))
1025
1025
1026 return reversed(revs)
1026 return reversed(revs)
1027 def iterfiles():
1027 def iterfiles():
1028 for filename in match.files():
1028 for filename in match.files():
1029 yield filename, None
1029 yield filename, None
1030 for filename_node in copies:
1030 for filename_node in copies:
1031 yield filename_node
1031 yield filename_node
1032 for file_, node in iterfiles():
1032 for file_, node in iterfiles():
1033 filelog = repo.file(file_)
1033 filelog = repo.file(file_)
1034 if not len(filelog):
1034 if not len(filelog):
1035 if node is None:
1035 if node is None:
1036 # A zero count may be a directory or deleted file, so
1036 # A zero count may be a directory or deleted file, so
1037 # try to find matching entries on the slow path.
1037 # try to find matching entries on the slow path.
1038 if follow:
1038 if follow:
1039 raise util.Abort(
1039 raise util.Abort(
1040 _('cannot follow nonexistent file: "%s"') % file_)
1040 _('cannot follow nonexistent file: "%s"') % file_)
1041 slowpath = True
1041 slowpath = True
1042 break
1042 break
1043 else:
1043 else:
1044 continue
1044 continue
1045
1045
1046 if node is None:
1046 if node is None:
1047 last = len(filelog) - 1
1047 last = len(filelog) - 1
1048 else:
1048 else:
1049 last = filelog.rev(node)
1049 last = filelog.rev(node)
1050
1050
1051
1051
1052 # keep track of all ancestors of the file
1052 # keep track of all ancestors of the file
1053 ancestors = set([filelog.linkrev(last)])
1053 ancestors = set([filelog.linkrev(last)])
1054
1054
1055 # iterate from latest to oldest revision
1055 # iterate from latest to oldest revision
1056 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1056 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1057 if not follow:
1057 if not follow:
1058 if rev > maxrev:
1058 if rev > maxrev:
1059 continue
1059 continue
1060 else:
1060 else:
1061 # Note that last might not be the first interesting
1061 # Note that last might not be the first interesting
1062 # rev to us:
1062 # rev to us:
1063 # if the file has been changed after maxrev, we'll
1063 # if the file has been changed after maxrev, we'll
1064 # have linkrev(last) > maxrev, and we still need
1064 # have linkrev(last) > maxrev, and we still need
1065 # to explore the file graph
1065 # to explore the file graph
1066 if rev not in ancestors:
1066 if rev not in ancestors:
1067 continue
1067 continue
1068 # XXX insert 1327 fix here
1068 # XXX insert 1327 fix here
1069 if flparentlinkrevs:
1069 if flparentlinkrevs:
1070 ancestors.update(flparentlinkrevs)
1070 ancestors.update(flparentlinkrevs)
1071
1071
1072 fncache.setdefault(rev, []).append(file_)
1072 fncache.setdefault(rev, []).append(file_)
1073 wanted.add(rev)
1073 wanted.add(rev)
1074 if copied:
1074 if copied:
1075 copies.append(copied)
1075 copies.append(copied)
1076 if slowpath:
1076 if slowpath:
1077 # We have to read the changelog to match filenames against
1077 # We have to read the changelog to match filenames against
1078 # changed files
1078 # changed files
1079
1079
1080 if follow:
1080 if follow:
1081 raise util.Abort(_('can only follow copies/renames for explicit '
1081 raise util.Abort(_('can only follow copies/renames for explicit '
1082 'filenames'))
1082 'filenames'))
1083
1083
1084 # The slow path checks files modified in every changeset.
1084 # The slow path checks files modified in every changeset.
1085 for i in sorted(revs):
1085 for i in sorted(revs):
1086 ctx = change(i)
1086 ctx = change(i)
1087 matches = filter(match, ctx.files())
1087 matches = filter(match, ctx.files())
1088 if matches:
1088 if matches:
1089 fncache[i] = matches
1089 fncache[i] = matches
1090 wanted.add(i)
1090 wanted.add(i)
1091
1091
1092 class followfilter(object):
1092 class followfilter(object):
1093 def __init__(self, onlyfirst=False):
1093 def __init__(self, onlyfirst=False):
1094 self.startrev = nullrev
1094 self.startrev = nullrev
1095 self.roots = set()
1095 self.roots = set()
1096 self.onlyfirst = onlyfirst
1096 self.onlyfirst = onlyfirst
1097
1097
1098 def match(self, rev):
1098 def match(self, rev):
1099 def realparents(rev):
1099 def realparents(rev):
1100 if self.onlyfirst:
1100 if self.onlyfirst:
1101 return repo.changelog.parentrevs(rev)[0:1]
1101 return repo.changelog.parentrevs(rev)[0:1]
1102 else:
1102 else:
1103 return filter(lambda x: x != nullrev,
1103 return filter(lambda x: x != nullrev,
1104 repo.changelog.parentrevs(rev))
1104 repo.changelog.parentrevs(rev))
1105
1105
1106 if self.startrev == nullrev:
1106 if self.startrev == nullrev:
1107 self.startrev = rev
1107 self.startrev = rev
1108 return True
1108 return True
1109
1109
1110 if rev > self.startrev:
1110 if rev > self.startrev:
1111 # forward: all descendants
1111 # forward: all descendants
1112 if not self.roots:
1112 if not self.roots:
1113 self.roots.add(self.startrev)
1113 self.roots.add(self.startrev)
1114 for parent in realparents(rev):
1114 for parent in realparents(rev):
1115 if parent in self.roots:
1115 if parent in self.roots:
1116 self.roots.add(rev)
1116 self.roots.add(rev)
1117 return True
1117 return True
1118 else:
1118 else:
1119 # backwards: all parents
1119 # backwards: all parents
1120 if not self.roots:
1120 if not self.roots:
1121 self.roots.update(realparents(self.startrev))
1121 self.roots.update(realparents(self.startrev))
1122 if rev in self.roots:
1122 if rev in self.roots:
1123 self.roots.remove(rev)
1123 self.roots.remove(rev)
1124 self.roots.update(realparents(rev))
1124 self.roots.update(realparents(rev))
1125 return True
1125 return True
1126
1126
1127 return False
1127 return False
1128
1128
1129 # it might be worthwhile to do this in the iterator if the rev range
1129 # it might be worthwhile to do this in the iterator if the rev range
1130 # is descending and the prune args are all within that range
1130 # is descending and the prune args are all within that range
1131 for rev in opts.get('prune', ()):
1131 for rev in opts.get('prune', ()):
1132 rev = repo.changelog.rev(repo.lookup(rev))
1132 rev = repo.changelog.rev(repo.lookup(rev))
1133 ff = followfilter()
1133 ff = followfilter()
1134 stop = min(revs[0], revs[-1])
1134 stop = min(revs[0], revs[-1])
1135 for x in xrange(rev, stop - 1, -1):
1135 for x in xrange(rev, stop - 1, -1):
1136 if ff.match(x):
1136 if ff.match(x):
1137 wanted.discard(x)
1137 wanted.discard(x)
1138
1138
1139 # Now that wanted is correctly initialized, we can iterate over the
1139 # Now that wanted is correctly initialized, we can iterate over the
1140 # revision range, yielding only revisions in wanted.
1140 # revision range, yielding only revisions in wanted.
1141 def iterate():
1141 def iterate():
1142 if follow and not match.files():
1142 if follow and not match.files():
1143 ff = followfilter(onlyfirst=opts.get('follow_first'))
1143 ff = followfilter(onlyfirst=opts.get('follow_first'))
1144 def want(rev):
1144 def want(rev):
1145 return ff.match(rev) and rev in wanted
1145 return ff.match(rev) and rev in wanted
1146 else:
1146 else:
1147 def want(rev):
1147 def want(rev):
1148 return rev in wanted
1148 return rev in wanted
1149
1149
1150 for i, window in increasing_windows(0, len(revs)):
1150 for i, window in increasing_windows(0, len(revs)):
1151 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1151 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1152 for rev in sorted(nrevs):
1152 for rev in sorted(nrevs):
1153 fns = fncache.get(rev)
1153 fns = fncache.get(rev)
1154 ctx = change(rev)
1154 ctx = change(rev)
1155 if not fns:
1155 if not fns:
1156 def fns_generator():
1156 def fns_generator():
1157 for f in ctx.files():
1157 for f in ctx.files():
1158 if match(f):
1158 if match(f):
1159 yield f
1159 yield f
1160 fns = fns_generator()
1160 fns = fns_generator()
1161 prepare(ctx, fns)
1161 prepare(ctx, fns)
1162 for rev in nrevs:
1162 for rev in nrevs:
1163 yield change(rev)
1163 yield change(rev)
1164 return iterate()
1164 return iterate()
1165
1165
1166 def add(ui, repo, match, dryrun, listsubrepos, prefix):
1166 def add(ui, repo, match, dryrun, listsubrepos, prefix):
1167 join = lambda f: os.path.join(prefix, f)
1167 join = lambda f: os.path.join(prefix, f)
1168 bad = []
1168 bad = []
1169 oldbad = match.bad
1169 oldbad = match.bad
1170 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1170 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1171 names = []
1171 names = []
1172 wctx = repo[None]
1172 wctx = repo[None]
1173 cca = None
1173 cca = None
1174 abort, warn = scmutil.checkportabilityalert(ui)
1174 abort, warn = scmutil.checkportabilityalert(ui)
1175 if abort or warn:
1175 if abort or warn:
1176 cca = scmutil.casecollisionauditor(ui, abort, wctx)
1176 cca = scmutil.casecollisionauditor(ui, abort, wctx)
1177 for f in repo.walk(match):
1177 for f in repo.walk(match):
1178 exact = match.exact(f)
1178 exact = match.exact(f)
1179 if exact or f not in repo.dirstate:
1179 if exact or f not in repo.dirstate:
1180 if cca:
1180 if cca:
1181 cca(f)
1181 cca(f)
1182 names.append(f)
1182 names.append(f)
1183 if ui.verbose or not exact:
1183 if ui.verbose or not exact:
1184 ui.status(_('adding %s\n') % match.rel(join(f)))
1184 ui.status(_('adding %s\n') % match.rel(join(f)))
1185
1185
1186 if listsubrepos:
1186 if listsubrepos:
1187 for subpath in wctx.substate:
1187 for subpath in wctx.substate:
1188 sub = wctx.sub(subpath)
1188 sub = wctx.sub(subpath)
1189 try:
1189 try:
1190 submatch = matchmod.narrowmatcher(subpath, match)
1190 submatch = matchmod.narrowmatcher(subpath, match)
1191 bad.extend(sub.add(ui, submatch, dryrun, prefix))
1191 bad.extend(sub.add(ui, submatch, dryrun, prefix))
1192 except error.LookupError:
1192 except error.LookupError:
1193 ui.status(_("skipping missing subrepository: %s\n")
1193 ui.status(_("skipping missing subrepository: %s\n")
1194 % join(subpath))
1194 % join(subpath))
1195
1195
1196 if not dryrun:
1196 if not dryrun:
1197 rejected = wctx.add(names, prefix)
1197 rejected = wctx.add(names, prefix)
1198 bad.extend(f for f in rejected if f in match.files())
1198 bad.extend(f for f in rejected if f in match.files())
1199 return bad
1199 return bad
1200
1200
1201 def commit(ui, repo, commitfunc, pats, opts):
1201 def commit(ui, repo, commitfunc, pats, opts):
1202 '''commit the specified files or all outstanding changes'''
1202 '''commit the specified files or all outstanding changes'''
1203 date = opts.get('date')
1203 date = opts.get('date')
1204 if date:
1204 if date:
1205 opts['date'] = util.parsedate(date)
1205 opts['date'] = util.parsedate(date)
1206 message = logmessage(opts)
1206 message = logmessage(opts)
1207
1207
1208 # extract addremove carefully -- this function can be called from a command
1208 # extract addremove carefully -- this function can be called from a command
1209 # that doesn't support addremove
1209 # that doesn't support addremove
1210 if opts.get('addremove'):
1210 if opts.get('addremove'):
1211 addremove(repo, pats, opts)
1211 addremove(repo, pats, opts)
1212
1212
1213 return commitfunc(ui, repo, message, match(repo, pats, opts), opts)
1213 return commitfunc(ui, repo, message, match(repo, pats, opts), opts)
1214
1214
1215 def commiteditor(repo, ctx, subs):
1215 def commiteditor(repo, ctx, subs):
1216 if ctx.description():
1216 if ctx.description():
1217 return ctx.description()
1217 return ctx.description()
1218 return commitforceeditor(repo, ctx, subs)
1218 return commitforceeditor(repo, ctx, subs)
1219
1219
1220 def commitforceeditor(repo, ctx, subs):
1220 def commitforceeditor(repo, ctx, subs):
1221 edittext = []
1221 edittext = []
1222 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1222 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1223 if ctx.description():
1223 if ctx.description():
1224 edittext.append(ctx.description())
1224 edittext.append(ctx.description())
1225 edittext.append("")
1225 edittext.append("")
1226 edittext.append("") # Empty line between message and comments.
1226 edittext.append("") # Empty line between message and comments.
1227 edittext.append(_("HG: Enter commit message."
1227 edittext.append(_("HG: Enter commit message."
1228 " Lines beginning with 'HG:' are removed."))
1228 " Lines beginning with 'HG:' are removed."))
1229 edittext.append(_("HG: Leave message empty to abort commit."))
1229 edittext.append(_("HG: Leave message empty to abort commit."))
1230 edittext.append("HG: --")
1230 edittext.append("HG: --")
1231 edittext.append(_("HG: user: %s") % ctx.user())
1231 edittext.append(_("HG: user: %s") % ctx.user())
1232 if ctx.p2():
1232 if ctx.p2():
1233 edittext.append(_("HG: branch merge"))
1233 edittext.append(_("HG: branch merge"))
1234 if ctx.branch():
1234 if ctx.branch():
1235 edittext.append(_("HG: branch '%s'") % ctx.branch())
1235 edittext.append(_("HG: branch '%s'") % ctx.branch())
1236 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1236 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1237 edittext.extend([_("HG: added %s") % f for f in added])
1237 edittext.extend([_("HG: added %s") % f for f in added])
1238 edittext.extend([_("HG: changed %s") % f for f in modified])
1238 edittext.extend([_("HG: changed %s") % f for f in modified])
1239 edittext.extend([_("HG: removed %s") % f for f in removed])
1239 edittext.extend([_("HG: removed %s") % f for f in removed])
1240 if not added and not modified and not removed:
1240 if not added and not modified and not removed:
1241 edittext.append(_("HG: no files changed"))
1241 edittext.append(_("HG: no files changed"))
1242 edittext.append("")
1242 edittext.append("")
1243 # run editor in the repository root
1243 # run editor in the repository root
1244 olddir = os.getcwd()
1244 olddir = os.getcwd()
1245 os.chdir(repo.root)
1245 os.chdir(repo.root)
1246 text = repo.ui.edit("\n".join(edittext), ctx.user())
1246 text = repo.ui.edit("\n".join(edittext), ctx.user())
1247 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1247 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1248 os.chdir(olddir)
1248 os.chdir(olddir)
1249
1249
1250 if not text.strip():
1250 if not text.strip():
1251 raise util.Abort(_("empty commit message"))
1251 raise util.Abort(_("empty commit message"))
1252
1252
1253 return text
1253 return text
@@ -1,5019 +1,5019 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, sys, difflib, time, tempfile
11 import os, re, sys, difflib, time, tempfile
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
15 import merge as mergemod
15 import merge as mergemod
16 import minirst, revset, templatefilters
16 import minirst, revset, templatefilters
17 import dagparser, context, simplemerge
17 import dagparser, context, simplemerge
18 import random, setdiscovery, treediscovery, dagutil
18 import random, setdiscovery, treediscovery, dagutil
19
19
20 # Commands start here, listed alphabetically
20 # Commands start here, listed alphabetically
21
21
22 def add(ui, repo, *pats, **opts):
22 def add(ui, repo, *pats, **opts):
23 """add the specified files on the next commit
23 """add the specified files on the next commit
24
24
25 Schedule files to be version controlled and added to the
25 Schedule files to be version controlled and added to the
26 repository.
26 repository.
27
27
28 The files will be added to the repository at the next commit. To
28 The files will be added to the repository at the next commit. To
29 undo an add before that, see :hg:`forget`.
29 undo an add before that, see :hg:`forget`.
30
30
31 If no names are given, add all files to the repository.
31 If no names are given, add all files to the repository.
32
32
33 .. container:: verbose
33 .. container:: verbose
34
34
35 An example showing how new (unknown) files are added
35 An example showing how new (unknown) files are added
36 automatically by :hg:`add`::
36 automatically by :hg:`add`::
37
37
38 $ ls
38 $ ls
39 foo.c
39 foo.c
40 $ hg status
40 $ hg status
41 ? foo.c
41 ? foo.c
42 $ hg add
42 $ hg add
43 adding foo.c
43 adding foo.c
44 $ hg status
44 $ hg status
45 A foo.c
45 A foo.c
46
46
47 Returns 0 if all files are successfully added.
47 Returns 0 if all files are successfully added.
48 """
48 """
49
49
50 m = cmdutil.match(repo, pats, opts)
50 m = cmdutil.match(repo, pats, opts)
51 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
51 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
52 opts.get('subrepos'), prefix="")
52 opts.get('subrepos'), prefix="")
53 return rejected and 1 or 0
53 return rejected and 1 or 0
54
54
55 def addremove(ui, repo, *pats, **opts):
55 def addremove(ui, repo, *pats, **opts):
56 """add all new files, delete all missing files
56 """add all new files, delete all missing files
57
57
58 Add all new files and remove all missing files from the
58 Add all new files and remove all missing files from the
59 repository.
59 repository.
60
60
61 New files are ignored if they match any of the patterns in
61 New files are ignored if they match any of the patterns in
62 ``.hgignore``. As with add, these changes take effect at the next
62 ``.hgignore``. As with add, these changes take effect at the next
63 commit.
63 commit.
64
64
65 Use the -s/--similarity option to detect renamed files. With a
65 Use the -s/--similarity option to detect renamed files. With a
66 parameter greater than 0, this compares every removed file with
66 parameter greater than 0, this compares every removed file with
67 every added file and records those similar enough as renames. This
67 every added file and records those similar enough as renames. This
68 option takes a percentage between 0 (disabled) and 100 (files must
68 option takes a percentage between 0 (disabled) and 100 (files must
69 be identical) as its parameter. Detecting renamed files this way
69 be identical) as its parameter. Detecting renamed files this way
70 can be expensive. After using this option, :hg:`status -C` can be
70 can be expensive. After using this option, :hg:`status -C` can be
71 used to check which files were identified as moved or renamed.
71 used to check which files were identified as moved or renamed.
72
72
73 Returns 0 if all files are successfully added.
73 Returns 0 if all files are successfully added.
74 """
74 """
75 try:
75 try:
76 sim = float(opts.get('similarity') or 100)
76 sim = float(opts.get('similarity') or 100)
77 except ValueError:
77 except ValueError:
78 raise util.Abort(_('similarity must be a number'))
78 raise util.Abort(_('similarity must be a number'))
79 if sim < 0 or sim > 100:
79 if sim < 0 or sim > 100:
80 raise util.Abort(_('similarity must be between 0 and 100'))
80 raise util.Abort(_('similarity must be between 0 and 100'))
81 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
81 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
82
82
83 def annotate(ui, repo, *pats, **opts):
83 def annotate(ui, repo, *pats, **opts):
84 """show changeset information by line for each file
84 """show changeset information by line for each file
85
85
86 List changes in files, showing the revision id responsible for
86 List changes in files, showing the revision id responsible for
87 each line
87 each line
88
88
89 This command is useful for discovering when a change was made and
89 This command is useful for discovering when a change was made and
90 by whom.
90 by whom.
91
91
92 Without the -a/--text option, annotate will avoid processing files
92 Without the -a/--text option, annotate will avoid processing files
93 it detects as binary. With -a, annotate will annotate the file
93 it detects as binary. With -a, annotate will annotate the file
94 anyway, although the results will probably be neither useful
94 anyway, although the results will probably be neither useful
95 nor desirable.
95 nor desirable.
96
96
97 Returns 0 on success.
97 Returns 0 on success.
98 """
98 """
99 if opts.get('follow'):
99 if opts.get('follow'):
100 # --follow is deprecated and now just an alias for -f/--file
100 # --follow is deprecated and now just an alias for -f/--file
101 # to mimic the behavior of Mercurial before version 1.5
101 # to mimic the behavior of Mercurial before version 1.5
102 opts['file'] = True
102 opts['file'] = True
103
103
104 datefunc = ui.quiet and util.shortdate or util.datestr
104 datefunc = ui.quiet and util.shortdate or util.datestr
105 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
105 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
106
106
107 if not pats:
107 if not pats:
108 raise util.Abort(_('at least one filename or pattern is required'))
108 raise util.Abort(_('at least one filename or pattern is required'))
109
109
110 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
110 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
111 ('number', lambda x: str(x[0].rev())),
111 ('number', lambda x: str(x[0].rev())),
112 ('changeset', lambda x: short(x[0].node())),
112 ('changeset', lambda x: short(x[0].node())),
113 ('date', getdate),
113 ('date', getdate),
114 ('file', lambda x: x[0].path()),
114 ('file', lambda x: x[0].path()),
115 ]
115 ]
116
116
117 if (not opts.get('user') and not opts.get('changeset')
117 if (not opts.get('user') and not opts.get('changeset')
118 and not opts.get('date') and not opts.get('file')):
118 and not opts.get('date') and not opts.get('file')):
119 opts['number'] = True
119 opts['number'] = True
120
120
121 linenumber = opts.get('line_number') is not None
121 linenumber = opts.get('line_number') is not None
122 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
122 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
123 raise util.Abort(_('at least one of -n/-c is required for -l'))
123 raise util.Abort(_('at least one of -n/-c is required for -l'))
124
124
125 funcmap = [func for op, func in opmap if opts.get(op)]
125 funcmap = [func for op, func in opmap if opts.get(op)]
126 if linenumber:
126 if linenumber:
127 lastfunc = funcmap[-1]
127 lastfunc = funcmap[-1]
128 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
128 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
129
129
130 def bad(x, y):
130 def bad(x, y):
131 raise util.Abort("%s: %s" % (x, y))
131 raise util.Abort("%s: %s" % (x, y))
132
132
133 ctx = cmdutil.revsingle(repo, opts.get('rev'))
133 ctx = cmdutil.revsingle(repo, opts.get('rev'))
134 m = cmdutil.match(repo, pats, opts)
134 m = cmdutil.match(repo, pats, opts)
135 m.bad = bad
135 m.bad = bad
136 follow = not opts.get('no_follow')
136 follow = not opts.get('no_follow')
137 for abs in ctx.walk(m):
137 for abs in ctx.walk(m):
138 fctx = ctx[abs]
138 fctx = ctx[abs]
139 if not opts.get('text') and util.binary(fctx.data()):
139 if not opts.get('text') and util.binary(fctx.data()):
140 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
140 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
141 continue
141 continue
142
142
143 lines = fctx.annotate(follow=follow, linenumber=linenumber)
143 lines = fctx.annotate(follow=follow, linenumber=linenumber)
144 pieces = []
144 pieces = []
145
145
146 for f in funcmap:
146 for f in funcmap:
147 l = [f(n) for n, dummy in lines]
147 l = [f(n) for n, dummy in lines]
148 if l:
148 if l:
149 sized = [(x, encoding.colwidth(x)) for x in l]
149 sized = [(x, encoding.colwidth(x)) for x in l]
150 ml = max([w for x, w in sized])
150 ml = max([w for x, w in sized])
151 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
151 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
152
152
153 if pieces:
153 if pieces:
154 for p, l in zip(zip(*pieces), lines):
154 for p, l in zip(zip(*pieces), lines):
155 ui.write("%s: %s" % (" ".join(p), l[1]))
155 ui.write("%s: %s" % (" ".join(p), l[1]))
156
156
157 def archive(ui, repo, dest, **opts):
157 def archive(ui, repo, dest, **opts):
158 '''create an unversioned archive of a repository revision
158 '''create an unversioned archive of a repository revision
159
159
160 By default, the revision used is the parent of the working
160 By default, the revision used is the parent of the working
161 directory; use -r/--rev to specify a different revision.
161 directory; use -r/--rev to specify a different revision.
162
162
163 The archive type is automatically detected based on file
163 The archive type is automatically detected based on file
164 extension (or override using -t/--type).
164 extension (or override using -t/--type).
165
165
166 Valid types are:
166 Valid types are:
167
167
168 :``files``: a directory full of files (default)
168 :``files``: a directory full of files (default)
169 :``tar``: tar archive, uncompressed
169 :``tar``: tar archive, uncompressed
170 :``tbz2``: tar archive, compressed using bzip2
170 :``tbz2``: tar archive, compressed using bzip2
171 :``tgz``: tar archive, compressed using gzip
171 :``tgz``: tar archive, compressed using gzip
172 :``uzip``: zip archive, uncompressed
172 :``uzip``: zip archive, uncompressed
173 :``zip``: zip archive, compressed using deflate
173 :``zip``: zip archive, compressed using deflate
174
174
175 The exact name of the destination archive or directory is given
175 The exact name of the destination archive or directory is given
176 using a format string; see :hg:`help export` for details.
176 using a format string; see :hg:`help export` for details.
177
177
178 Each member added to an archive file has a directory prefix
178 Each member added to an archive file has a directory prefix
179 prepended. Use -p/--prefix to specify a format string for the
179 prepended. Use -p/--prefix to specify a format string for the
180 prefix. The default is the basename of the archive, with suffixes
180 prefix. The default is the basename of the archive, with suffixes
181 removed.
181 removed.
182
182
183 Returns 0 on success.
183 Returns 0 on success.
184 '''
184 '''
185
185
186 ctx = cmdutil.revsingle(repo, opts.get('rev'))
186 ctx = cmdutil.revsingle(repo, opts.get('rev'))
187 if not ctx:
187 if not ctx:
188 raise util.Abort(_('no working directory: please specify a revision'))
188 raise util.Abort(_('no working directory: please specify a revision'))
189 node = ctx.node()
189 node = ctx.node()
190 dest = cmdutil.make_filename(repo, dest, node)
190 dest = cmdutil.makefilename(repo, dest, node)
191 if os.path.realpath(dest) == repo.root:
191 if os.path.realpath(dest) == repo.root:
192 raise util.Abort(_('repository root cannot be destination'))
192 raise util.Abort(_('repository root cannot be destination'))
193
193
194 kind = opts.get('type') or archival.guesskind(dest) or 'files'
194 kind = opts.get('type') or archival.guesskind(dest) or 'files'
195 prefix = opts.get('prefix')
195 prefix = opts.get('prefix')
196
196
197 if dest == '-':
197 if dest == '-':
198 if kind == 'files':
198 if kind == 'files':
199 raise util.Abort(_('cannot archive plain files to stdout'))
199 raise util.Abort(_('cannot archive plain files to stdout'))
200 dest = sys.stdout
200 dest = sys.stdout
201 if not prefix:
201 if not prefix:
202 prefix = os.path.basename(repo.root) + '-%h'
202 prefix = os.path.basename(repo.root) + '-%h'
203
203
204 prefix = cmdutil.make_filename(repo, prefix, node)
204 prefix = cmdutil.makefilename(repo, prefix, node)
205 matchfn = cmdutil.match(repo, [], opts)
205 matchfn = cmdutil.match(repo, [], opts)
206 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
206 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
207 matchfn, prefix, subrepos=opts.get('subrepos'))
207 matchfn, prefix, subrepos=opts.get('subrepos'))
208
208
209 def backout(ui, repo, node=None, rev=None, **opts):
209 def backout(ui, repo, node=None, rev=None, **opts):
210 '''reverse effect of earlier changeset
210 '''reverse effect of earlier changeset
211
211
212 Prepare a new changeset with the effect of REV undone in the
212 Prepare a new changeset with the effect of REV undone in the
213 current working directory.
213 current working directory.
214
214
215 If REV is the parent of the working directory, then this new changeset
215 If REV is the parent of the working directory, then this new changeset
216 is committed automatically. Otherwise, hg needs to merge the
216 is committed automatically. Otherwise, hg needs to merge the
217 changes and the merged result is left uncommitted.
217 changes and the merged result is left uncommitted.
218
218
219 By default, the pending changeset will have one parent,
219 By default, the pending changeset will have one parent,
220 maintaining a linear history. With --merge, the pending changeset
220 maintaining a linear history. With --merge, the pending changeset
221 will instead have two parents: the old parent of the working
221 will instead have two parents: the old parent of the working
222 directory and a new child of REV that simply undoes REV.
222 directory and a new child of REV that simply undoes REV.
223
223
224 Before version 1.7, the behavior without --merge was equivalent to
224 Before version 1.7, the behavior without --merge was equivalent to
225 specifying --merge followed by :hg:`update --clean .` to cancel
225 specifying --merge followed by :hg:`update --clean .` to cancel
226 the merge and leave the child of REV as a head to be merged
226 the merge and leave the child of REV as a head to be merged
227 separately.
227 separately.
228
228
229 See :hg:`help dates` for a list of formats valid for -d/--date.
229 See :hg:`help dates` for a list of formats valid for -d/--date.
230
230
231 Returns 0 on success.
231 Returns 0 on success.
232 '''
232 '''
233 if rev and node:
233 if rev and node:
234 raise util.Abort(_("please specify just one revision"))
234 raise util.Abort(_("please specify just one revision"))
235
235
236 if not rev:
236 if not rev:
237 rev = node
237 rev = node
238
238
239 if not rev:
239 if not rev:
240 raise util.Abort(_("please specify a revision to backout"))
240 raise util.Abort(_("please specify a revision to backout"))
241
241
242 date = opts.get('date')
242 date = opts.get('date')
243 if date:
243 if date:
244 opts['date'] = util.parsedate(date)
244 opts['date'] = util.parsedate(date)
245
245
246 cmdutil.bailifchanged(repo)
246 cmdutil.bailifchanged(repo)
247 node = cmdutil.revsingle(repo, rev).node()
247 node = cmdutil.revsingle(repo, rev).node()
248
248
249 op1, op2 = repo.dirstate.parents()
249 op1, op2 = repo.dirstate.parents()
250 a = repo.changelog.ancestor(op1, node)
250 a = repo.changelog.ancestor(op1, node)
251 if a != node:
251 if a != node:
252 raise util.Abort(_('cannot backout change on a different branch'))
252 raise util.Abort(_('cannot backout change on a different branch'))
253
253
254 p1, p2 = repo.changelog.parents(node)
254 p1, p2 = repo.changelog.parents(node)
255 if p1 == nullid:
255 if p1 == nullid:
256 raise util.Abort(_('cannot backout a change with no parents'))
256 raise util.Abort(_('cannot backout a change with no parents'))
257 if p2 != nullid:
257 if p2 != nullid:
258 if not opts.get('parent'):
258 if not opts.get('parent'):
259 raise util.Abort(_('cannot backout a merge changeset without '
259 raise util.Abort(_('cannot backout a merge changeset without '
260 '--parent'))
260 '--parent'))
261 p = repo.lookup(opts['parent'])
261 p = repo.lookup(opts['parent'])
262 if p not in (p1, p2):
262 if p not in (p1, p2):
263 raise util.Abort(_('%s is not a parent of %s') %
263 raise util.Abort(_('%s is not a parent of %s') %
264 (short(p), short(node)))
264 (short(p), short(node)))
265 parent = p
265 parent = p
266 else:
266 else:
267 if opts.get('parent'):
267 if opts.get('parent'):
268 raise util.Abort(_('cannot use --parent on non-merge changeset'))
268 raise util.Abort(_('cannot use --parent on non-merge changeset'))
269 parent = p1
269 parent = p1
270
270
271 # the backout should appear on the same branch
271 # the backout should appear on the same branch
272 branch = repo.dirstate.branch()
272 branch = repo.dirstate.branch()
273 hg.clean(repo, node, show_stats=False)
273 hg.clean(repo, node, show_stats=False)
274 repo.dirstate.setbranch(branch)
274 repo.dirstate.setbranch(branch)
275 revert_opts = opts.copy()
275 revert_opts = opts.copy()
276 revert_opts['date'] = None
276 revert_opts['date'] = None
277 revert_opts['all'] = True
277 revert_opts['all'] = True
278 revert_opts['rev'] = hex(parent)
278 revert_opts['rev'] = hex(parent)
279 revert_opts['no_backup'] = None
279 revert_opts['no_backup'] = None
280 revert(ui, repo, **revert_opts)
280 revert(ui, repo, **revert_opts)
281 if not opts.get('merge') and op1 != node:
281 if not opts.get('merge') and op1 != node:
282 try:
282 try:
283 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
283 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
284 return hg.update(repo, op1)
284 return hg.update(repo, op1)
285 finally:
285 finally:
286 ui.setconfig('ui', 'forcemerge', '')
286 ui.setconfig('ui', 'forcemerge', '')
287
287
288 commit_opts = opts.copy()
288 commit_opts = opts.copy()
289 commit_opts['addremove'] = False
289 commit_opts['addremove'] = False
290 if not commit_opts['message'] and not commit_opts['logfile']:
290 if not commit_opts['message'] and not commit_opts['logfile']:
291 # we don't translate commit messages
291 # we don't translate commit messages
292 commit_opts['message'] = "Backed out changeset %s" % short(node)
292 commit_opts['message'] = "Backed out changeset %s" % short(node)
293 commit_opts['force_editor'] = True
293 commit_opts['force_editor'] = True
294 commit(ui, repo, **commit_opts)
294 commit(ui, repo, **commit_opts)
295 def nice(node):
295 def nice(node):
296 return '%d:%s' % (repo.changelog.rev(node), short(node))
296 return '%d:%s' % (repo.changelog.rev(node), short(node))
297 ui.status(_('changeset %s backs out changeset %s\n') %
297 ui.status(_('changeset %s backs out changeset %s\n') %
298 (nice(repo.changelog.tip()), nice(node)))
298 (nice(repo.changelog.tip()), nice(node)))
299 if opts.get('merge') and op1 != node:
299 if opts.get('merge') and op1 != node:
300 hg.clean(repo, op1, show_stats=False)
300 hg.clean(repo, op1, show_stats=False)
301 ui.status(_('merging with changeset %s\n')
301 ui.status(_('merging with changeset %s\n')
302 % nice(repo.changelog.tip()))
302 % nice(repo.changelog.tip()))
303 try:
303 try:
304 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
304 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
305 return hg.merge(repo, hex(repo.changelog.tip()))
305 return hg.merge(repo, hex(repo.changelog.tip()))
306 finally:
306 finally:
307 ui.setconfig('ui', 'forcemerge', '')
307 ui.setconfig('ui', 'forcemerge', '')
308 return 0
308 return 0
309
309
310 def bisect(ui, repo, rev=None, extra=None, command=None,
310 def bisect(ui, repo, rev=None, extra=None, command=None,
311 reset=None, good=None, bad=None, skip=None, extend=None,
311 reset=None, good=None, bad=None, skip=None, extend=None,
312 noupdate=None):
312 noupdate=None):
313 """subdivision search of changesets
313 """subdivision search of changesets
314
314
315 This command helps to find changesets which introduce problems. To
315 This command helps to find changesets which introduce problems. To
316 use, mark the earliest changeset you know exhibits the problem as
316 use, mark the earliest changeset you know exhibits the problem as
317 bad, then mark the latest changeset which is free from the problem
317 bad, then mark the latest changeset which is free from the problem
318 as good. Bisect will update your working directory to a revision
318 as good. Bisect will update your working directory to a revision
319 for testing (unless the -U/--noupdate option is specified). Once
319 for testing (unless the -U/--noupdate option is specified). Once
320 you have performed tests, mark the working directory as good or
320 you have performed tests, mark the working directory as good or
321 bad, and bisect will either update to another candidate changeset
321 bad, and bisect will either update to another candidate changeset
322 or announce that it has found the bad revision.
322 or announce that it has found the bad revision.
323
323
324 As a shortcut, you can also use the revision argument to mark a
324 As a shortcut, you can also use the revision argument to mark a
325 revision as good or bad without checking it out first.
325 revision as good or bad without checking it out first.
326
326
327 If you supply a command, it will be used for automatic bisection.
327 If you supply a command, it will be used for automatic bisection.
328 Its exit status will be used to mark revisions as good or bad:
328 Its exit status will be used to mark revisions as good or bad:
329 status 0 means good, 125 means to skip the revision, 127
329 status 0 means good, 125 means to skip the revision, 127
330 (command not found) will abort the bisection, and any other
330 (command not found) will abort the bisection, and any other
331 non-zero exit status means the revision is bad.
331 non-zero exit status means the revision is bad.
332
332
333 Returns 0 on success.
333 Returns 0 on success.
334 """
334 """
335 def extendbisectrange(nodes, good):
335 def extendbisectrange(nodes, good):
336 # bisect is incomplete when it ends on a merge node and
336 # bisect is incomplete when it ends on a merge node and
337 # one of the parent was not checked.
337 # one of the parent was not checked.
338 parents = repo[nodes[0]].parents()
338 parents = repo[nodes[0]].parents()
339 if len(parents) > 1:
339 if len(parents) > 1:
340 side = good and state['bad'] or state['good']
340 side = good and state['bad'] or state['good']
341 num = len(set(i.node() for i in parents) & set(side))
341 num = len(set(i.node() for i in parents) & set(side))
342 if num == 1:
342 if num == 1:
343 return parents[0].ancestor(parents[1])
343 return parents[0].ancestor(parents[1])
344 return None
344 return None
345
345
346 def print_result(nodes, good):
346 def print_result(nodes, good):
347 displayer = cmdutil.show_changeset(ui, repo, {})
347 displayer = cmdutil.show_changeset(ui, repo, {})
348 if len(nodes) == 1:
348 if len(nodes) == 1:
349 # narrowed it down to a single revision
349 # narrowed it down to a single revision
350 if good:
350 if good:
351 ui.write(_("The first good revision is:\n"))
351 ui.write(_("The first good revision is:\n"))
352 else:
352 else:
353 ui.write(_("The first bad revision is:\n"))
353 ui.write(_("The first bad revision is:\n"))
354 displayer.show(repo[nodes[0]])
354 displayer.show(repo[nodes[0]])
355 extendnode = extendbisectrange(nodes, good)
355 extendnode = extendbisectrange(nodes, good)
356 if extendnode is not None:
356 if extendnode is not None:
357 ui.write(_('Not all ancestors of this changeset have been'
357 ui.write(_('Not all ancestors of this changeset have been'
358 ' checked.\nUse bisect --extend to continue the '
358 ' checked.\nUse bisect --extend to continue the '
359 'bisection from\nthe common ancestor, %s.\n')
359 'bisection from\nthe common ancestor, %s.\n')
360 % extendnode)
360 % extendnode)
361 else:
361 else:
362 # multiple possible revisions
362 # multiple possible revisions
363 if good:
363 if good:
364 ui.write(_("Due to skipped revisions, the first "
364 ui.write(_("Due to skipped revisions, the first "
365 "good revision could be any of:\n"))
365 "good revision could be any of:\n"))
366 else:
366 else:
367 ui.write(_("Due to skipped revisions, the first "
367 ui.write(_("Due to skipped revisions, the first "
368 "bad revision could be any of:\n"))
368 "bad revision could be any of:\n"))
369 for n in nodes:
369 for n in nodes:
370 displayer.show(repo[n])
370 displayer.show(repo[n])
371 displayer.close()
371 displayer.close()
372
372
373 def check_state(state, interactive=True):
373 def check_state(state, interactive=True):
374 if not state['good'] or not state['bad']:
374 if not state['good'] or not state['bad']:
375 if (good or bad or skip or reset) and interactive:
375 if (good or bad or skip or reset) and interactive:
376 return
376 return
377 if not state['good']:
377 if not state['good']:
378 raise util.Abort(_('cannot bisect (no known good revisions)'))
378 raise util.Abort(_('cannot bisect (no known good revisions)'))
379 else:
379 else:
380 raise util.Abort(_('cannot bisect (no known bad revisions)'))
380 raise util.Abort(_('cannot bisect (no known bad revisions)'))
381 return True
381 return True
382
382
383 # backward compatibility
383 # backward compatibility
384 if rev in "good bad reset init".split():
384 if rev in "good bad reset init".split():
385 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
385 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
386 cmd, rev, extra = rev, extra, None
386 cmd, rev, extra = rev, extra, None
387 if cmd == "good":
387 if cmd == "good":
388 good = True
388 good = True
389 elif cmd == "bad":
389 elif cmd == "bad":
390 bad = True
390 bad = True
391 else:
391 else:
392 reset = True
392 reset = True
393 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
393 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
394 raise util.Abort(_('incompatible arguments'))
394 raise util.Abort(_('incompatible arguments'))
395
395
396 if reset:
396 if reset:
397 p = repo.join("bisect.state")
397 p = repo.join("bisect.state")
398 if os.path.exists(p):
398 if os.path.exists(p):
399 os.unlink(p)
399 os.unlink(p)
400 return
400 return
401
401
402 state = hbisect.load_state(repo)
402 state = hbisect.load_state(repo)
403
403
404 if command:
404 if command:
405 changesets = 1
405 changesets = 1
406 try:
406 try:
407 while changesets:
407 while changesets:
408 # update state
408 # update state
409 status = util.system(command)
409 status = util.system(command)
410 if status == 125:
410 if status == 125:
411 transition = "skip"
411 transition = "skip"
412 elif status == 0:
412 elif status == 0:
413 transition = "good"
413 transition = "good"
414 # status < 0 means process was killed
414 # status < 0 means process was killed
415 elif status == 127:
415 elif status == 127:
416 raise util.Abort(_("failed to execute %s") % command)
416 raise util.Abort(_("failed to execute %s") % command)
417 elif status < 0:
417 elif status < 0:
418 raise util.Abort(_("%s killed") % command)
418 raise util.Abort(_("%s killed") % command)
419 else:
419 else:
420 transition = "bad"
420 transition = "bad"
421 ctx = cmdutil.revsingle(repo, rev)
421 ctx = cmdutil.revsingle(repo, rev)
422 rev = None # clear for future iterations
422 rev = None # clear for future iterations
423 state[transition].append(ctx.node())
423 state[transition].append(ctx.node())
424 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
424 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
425 check_state(state, interactive=False)
425 check_state(state, interactive=False)
426 # bisect
426 # bisect
427 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
427 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
428 # update to next check
428 # update to next check
429 cmdutil.bailifchanged(repo)
429 cmdutil.bailifchanged(repo)
430 hg.clean(repo, nodes[0], show_stats=False)
430 hg.clean(repo, nodes[0], show_stats=False)
431 finally:
431 finally:
432 hbisect.save_state(repo, state)
432 hbisect.save_state(repo, state)
433 print_result(nodes, good)
433 print_result(nodes, good)
434 return
434 return
435
435
436 # update state
436 # update state
437
437
438 if rev:
438 if rev:
439 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
439 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
440 else:
440 else:
441 nodes = [repo.lookup('.')]
441 nodes = [repo.lookup('.')]
442
442
443 if good or bad or skip:
443 if good or bad or skip:
444 if good:
444 if good:
445 state['good'] += nodes
445 state['good'] += nodes
446 elif bad:
446 elif bad:
447 state['bad'] += nodes
447 state['bad'] += nodes
448 elif skip:
448 elif skip:
449 state['skip'] += nodes
449 state['skip'] += nodes
450 hbisect.save_state(repo, state)
450 hbisect.save_state(repo, state)
451
451
452 if not check_state(state):
452 if not check_state(state):
453 return
453 return
454
454
455 # actually bisect
455 # actually bisect
456 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
456 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
457 if extend:
457 if extend:
458 if not changesets:
458 if not changesets:
459 extendnode = extendbisectrange(nodes, good)
459 extendnode = extendbisectrange(nodes, good)
460 if extendnode is not None:
460 if extendnode is not None:
461 ui.write(_("Extending search to changeset %d:%s\n"
461 ui.write(_("Extending search to changeset %d:%s\n"
462 % (extendnode.rev(), extendnode)))
462 % (extendnode.rev(), extendnode)))
463 if noupdate:
463 if noupdate:
464 return
464 return
465 cmdutil.bailifchanged(repo)
465 cmdutil.bailifchanged(repo)
466 return hg.clean(repo, extendnode.node())
466 return hg.clean(repo, extendnode.node())
467 raise util.Abort(_("nothing to extend"))
467 raise util.Abort(_("nothing to extend"))
468
468
469 if changesets == 0:
469 if changesets == 0:
470 print_result(nodes, good)
470 print_result(nodes, good)
471 else:
471 else:
472 assert len(nodes) == 1 # only a single node can be tested next
472 assert len(nodes) == 1 # only a single node can be tested next
473 node = nodes[0]
473 node = nodes[0]
474 # compute the approximate number of remaining tests
474 # compute the approximate number of remaining tests
475 tests, size = 0, 2
475 tests, size = 0, 2
476 while size <= changesets:
476 while size <= changesets:
477 tests, size = tests + 1, size * 2
477 tests, size = tests + 1, size * 2
478 rev = repo.changelog.rev(node)
478 rev = repo.changelog.rev(node)
479 ui.write(_("Testing changeset %d:%s "
479 ui.write(_("Testing changeset %d:%s "
480 "(%d changesets remaining, ~%d tests)\n")
480 "(%d changesets remaining, ~%d tests)\n")
481 % (rev, short(node), changesets, tests))
481 % (rev, short(node), changesets, tests))
482 if not noupdate:
482 if not noupdate:
483 cmdutil.bailifchanged(repo)
483 cmdutil.bailifchanged(repo)
484 return hg.clean(repo, node)
484 return hg.clean(repo, node)
485
485
486 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
486 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
487 rename=None, inactive=False):
487 rename=None, inactive=False):
488 '''track a line of development with movable markers
488 '''track a line of development with movable markers
489
489
490 Bookmarks are pointers to certain commits that move when
490 Bookmarks are pointers to certain commits that move when
491 committing. Bookmarks are local. They can be renamed, copied and
491 committing. Bookmarks are local. They can be renamed, copied and
492 deleted. It is possible to use bookmark names in :hg:`merge` and
492 deleted. It is possible to use bookmark names in :hg:`merge` and
493 :hg:`update` to merge and update respectively to a given bookmark.
493 :hg:`update` to merge and update respectively to a given bookmark.
494
494
495 You can use :hg:`bookmark NAME` to set a bookmark on the working
495 You can use :hg:`bookmark NAME` to set a bookmark on the working
496 directory's parent revision with the given name. If you specify
496 directory's parent revision with the given name. If you specify
497 a revision using -r REV (where REV may be an existing bookmark),
497 a revision using -r REV (where REV may be an existing bookmark),
498 the bookmark is assigned to that revision.
498 the bookmark is assigned to that revision.
499
499
500 Bookmarks can be pushed and pulled between repositories (see :hg:`help
500 Bookmarks can be pushed and pulled between repositories (see :hg:`help
501 push` and :hg:`help pull`). This requires both the local and remote
501 push` and :hg:`help pull`). This requires both the local and remote
502 repositories to support bookmarks. For versions prior to 1.8, this means
502 repositories to support bookmarks. For versions prior to 1.8, this means
503 the bookmarks extension must be enabled.
503 the bookmarks extension must be enabled.
504 '''
504 '''
505 hexfn = ui.debugflag and hex or short
505 hexfn = ui.debugflag and hex or short
506 marks = repo._bookmarks
506 marks = repo._bookmarks
507 cur = repo.changectx('.').node()
507 cur = repo.changectx('.').node()
508
508
509 if rename:
509 if rename:
510 if rename not in marks:
510 if rename not in marks:
511 raise util.Abort(_("bookmark '%s' does not exist") % rename)
511 raise util.Abort(_("bookmark '%s' does not exist") % rename)
512 if mark in marks and not force:
512 if mark in marks and not force:
513 raise util.Abort(_("bookmark '%s' already exists "
513 raise util.Abort(_("bookmark '%s' already exists "
514 "(use -f to force)") % mark)
514 "(use -f to force)") % mark)
515 if mark is None:
515 if mark is None:
516 raise util.Abort(_("new bookmark name required"))
516 raise util.Abort(_("new bookmark name required"))
517 marks[mark] = marks[rename]
517 marks[mark] = marks[rename]
518 if repo._bookmarkcurrent == rename and not inactive:
518 if repo._bookmarkcurrent == rename and not inactive:
519 bookmarks.setcurrent(repo, mark)
519 bookmarks.setcurrent(repo, mark)
520 del marks[rename]
520 del marks[rename]
521 bookmarks.write(repo)
521 bookmarks.write(repo)
522 return
522 return
523
523
524 if delete:
524 if delete:
525 if mark is None:
525 if mark is None:
526 raise util.Abort(_("bookmark name required"))
526 raise util.Abort(_("bookmark name required"))
527 if mark not in marks:
527 if mark not in marks:
528 raise util.Abort(_("bookmark '%s' does not exist") % mark)
528 raise util.Abort(_("bookmark '%s' does not exist") % mark)
529 if mark == repo._bookmarkcurrent:
529 if mark == repo._bookmarkcurrent:
530 bookmarks.setcurrent(repo, None)
530 bookmarks.setcurrent(repo, None)
531 del marks[mark]
531 del marks[mark]
532 bookmarks.write(repo)
532 bookmarks.write(repo)
533 return
533 return
534
534
535 if mark is not None:
535 if mark is not None:
536 if "\n" in mark:
536 if "\n" in mark:
537 raise util.Abort(_("bookmark name cannot contain newlines"))
537 raise util.Abort(_("bookmark name cannot contain newlines"))
538 mark = mark.strip()
538 mark = mark.strip()
539 if not mark:
539 if not mark:
540 raise util.Abort(_("bookmark names cannot consist entirely of "
540 raise util.Abort(_("bookmark names cannot consist entirely of "
541 "whitespace"))
541 "whitespace"))
542 if inactive and mark == repo._bookmarkcurrent:
542 if inactive and mark == repo._bookmarkcurrent:
543 bookmarks.setcurrent(repo, None)
543 bookmarks.setcurrent(repo, None)
544 return
544 return
545 if mark in marks and not force:
545 if mark in marks and not force:
546 raise util.Abort(_("bookmark '%s' already exists "
546 raise util.Abort(_("bookmark '%s' already exists "
547 "(use -f to force)") % mark)
547 "(use -f to force)") % mark)
548 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
548 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
549 and not force):
549 and not force):
550 raise util.Abort(
550 raise util.Abort(
551 _("a bookmark cannot have the name of an existing branch"))
551 _("a bookmark cannot have the name of an existing branch"))
552 if rev:
552 if rev:
553 marks[mark] = repo.lookup(rev)
553 marks[mark] = repo.lookup(rev)
554 else:
554 else:
555 marks[mark] = repo.changectx('.').node()
555 marks[mark] = repo.changectx('.').node()
556 if not inactive and repo.changectx('.').node() == marks[mark]:
556 if not inactive and repo.changectx('.').node() == marks[mark]:
557 bookmarks.setcurrent(repo, mark)
557 bookmarks.setcurrent(repo, mark)
558 bookmarks.write(repo)
558 bookmarks.write(repo)
559 return
559 return
560
560
561 if mark is None:
561 if mark is None:
562 if rev:
562 if rev:
563 raise util.Abort(_("bookmark name required"))
563 raise util.Abort(_("bookmark name required"))
564 if len(marks) == 0:
564 if len(marks) == 0:
565 ui.status(_("no bookmarks set\n"))
565 ui.status(_("no bookmarks set\n"))
566 else:
566 else:
567 for bmark, n in sorted(marks.iteritems()):
567 for bmark, n in sorted(marks.iteritems()):
568 current = repo._bookmarkcurrent
568 current = repo._bookmarkcurrent
569 if bmark == current and n == cur:
569 if bmark == current and n == cur:
570 prefix, label = '*', 'bookmarks.current'
570 prefix, label = '*', 'bookmarks.current'
571 else:
571 else:
572 prefix, label = ' ', ''
572 prefix, label = ' ', ''
573
573
574 if ui.quiet:
574 if ui.quiet:
575 ui.write("%s\n" % bmark, label=label)
575 ui.write("%s\n" % bmark, label=label)
576 else:
576 else:
577 ui.write(" %s %-25s %d:%s\n" % (
577 ui.write(" %s %-25s %d:%s\n" % (
578 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
578 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
579 label=label)
579 label=label)
580 return
580 return
581
581
582 def branch(ui, repo, label=None, **opts):
582 def branch(ui, repo, label=None, **opts):
583 """set or show the current branch name
583 """set or show the current branch name
584
584
585 With no argument, show the current branch name. With one argument,
585 With no argument, show the current branch name. With one argument,
586 set the working directory branch name (the branch will not exist
586 set the working directory branch name (the branch will not exist
587 in the repository until the next commit). Standard practice
587 in the repository until the next commit). Standard practice
588 recommends that primary development take place on the 'default'
588 recommends that primary development take place on the 'default'
589 branch.
589 branch.
590
590
591 Unless -f/--force is specified, branch will not let you set a
591 Unless -f/--force is specified, branch will not let you set a
592 branch name that already exists, even if it's inactive.
592 branch name that already exists, even if it's inactive.
593
593
594 Use -C/--clean to reset the working directory branch to that of
594 Use -C/--clean to reset the working directory branch to that of
595 the parent of the working directory, negating a previous branch
595 the parent of the working directory, negating a previous branch
596 change.
596 change.
597
597
598 Use the command :hg:`update` to switch to an existing branch. Use
598 Use the command :hg:`update` to switch to an existing branch. Use
599 :hg:`commit --close-branch` to mark this branch as closed.
599 :hg:`commit --close-branch` to mark this branch as closed.
600
600
601 Returns 0 on success.
601 Returns 0 on success.
602 """
602 """
603
603
604 if opts.get('clean'):
604 if opts.get('clean'):
605 label = repo[None].p1().branch()
605 label = repo[None].p1().branch()
606 repo.dirstate.setbranch(label)
606 repo.dirstate.setbranch(label)
607 ui.status(_('reset working directory to branch %s\n') % label)
607 ui.status(_('reset working directory to branch %s\n') % label)
608 elif label:
608 elif label:
609 if not opts.get('force') and label in repo.branchtags():
609 if not opts.get('force') and label in repo.branchtags():
610 if label not in [p.branch() for p in repo.parents()]:
610 if label not in [p.branch() for p in repo.parents()]:
611 raise util.Abort(_('a branch of the same name already exists'),
611 raise util.Abort(_('a branch of the same name already exists'),
612 # i18n: "it" refers to an existing branch
612 # i18n: "it" refers to an existing branch
613 hint=_("use 'hg update' to switch to it"))
613 hint=_("use 'hg update' to switch to it"))
614 repo.dirstate.setbranch(label)
614 repo.dirstate.setbranch(label)
615 ui.status(_('marked working directory as branch %s\n') % label)
615 ui.status(_('marked working directory as branch %s\n') % label)
616 else:
616 else:
617 ui.write("%s\n" % repo.dirstate.branch())
617 ui.write("%s\n" % repo.dirstate.branch())
618
618
619 def branches(ui, repo, active=False, closed=False):
619 def branches(ui, repo, active=False, closed=False):
620 """list repository named branches
620 """list repository named branches
621
621
622 List the repository's named branches, indicating which ones are
622 List the repository's named branches, indicating which ones are
623 inactive. If -c/--closed is specified, also list branches which have
623 inactive. If -c/--closed is specified, also list branches which have
624 been marked closed (see :hg:`commit --close-branch`).
624 been marked closed (see :hg:`commit --close-branch`).
625
625
626 If -a/--active is specified, only show active branches. A branch
626 If -a/--active is specified, only show active branches. A branch
627 is considered active if it contains repository heads.
627 is considered active if it contains repository heads.
628
628
629 Use the command :hg:`update` to switch to an existing branch.
629 Use the command :hg:`update` to switch to an existing branch.
630
630
631 Returns 0.
631 Returns 0.
632 """
632 """
633
633
634 hexfunc = ui.debugflag and hex or short
634 hexfunc = ui.debugflag and hex or short
635 activebranches = [repo[n].branch() for n in repo.heads()]
635 activebranches = [repo[n].branch() for n in repo.heads()]
636 def testactive(tag, node):
636 def testactive(tag, node):
637 realhead = tag in activebranches
637 realhead = tag in activebranches
638 open = node in repo.branchheads(tag, closed=False)
638 open = node in repo.branchheads(tag, closed=False)
639 return realhead and open
639 return realhead and open
640 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
640 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
641 for tag, node in repo.branchtags().items()],
641 for tag, node in repo.branchtags().items()],
642 reverse=True)
642 reverse=True)
643
643
644 for isactive, node, tag in branches:
644 for isactive, node, tag in branches:
645 if (not active) or isactive:
645 if (not active) or isactive:
646 if ui.quiet:
646 if ui.quiet:
647 ui.write("%s\n" % tag)
647 ui.write("%s\n" % tag)
648 else:
648 else:
649 hn = repo.lookup(node)
649 hn = repo.lookup(node)
650 if isactive:
650 if isactive:
651 label = 'branches.active'
651 label = 'branches.active'
652 notice = ''
652 notice = ''
653 elif hn not in repo.branchheads(tag, closed=False):
653 elif hn not in repo.branchheads(tag, closed=False):
654 if not closed:
654 if not closed:
655 continue
655 continue
656 label = 'branches.closed'
656 label = 'branches.closed'
657 notice = _(' (closed)')
657 notice = _(' (closed)')
658 else:
658 else:
659 label = 'branches.inactive'
659 label = 'branches.inactive'
660 notice = _(' (inactive)')
660 notice = _(' (inactive)')
661 if tag == repo.dirstate.branch():
661 if tag == repo.dirstate.branch():
662 label = 'branches.current'
662 label = 'branches.current'
663 rev = str(node).rjust(31 - encoding.colwidth(tag))
663 rev = str(node).rjust(31 - encoding.colwidth(tag))
664 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
664 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
665 tag = ui.label(tag, label)
665 tag = ui.label(tag, label)
666 ui.write("%s %s%s\n" % (tag, rev, notice))
666 ui.write("%s %s%s\n" % (tag, rev, notice))
667
667
668 def bundle(ui, repo, fname, dest=None, **opts):
668 def bundle(ui, repo, fname, dest=None, **opts):
669 """create a changegroup file
669 """create a changegroup file
670
670
671 Generate a compressed changegroup file collecting changesets not
671 Generate a compressed changegroup file collecting changesets not
672 known to be in another repository.
672 known to be in another repository.
673
673
674 If you omit the destination repository, then hg assumes the
674 If you omit the destination repository, then hg assumes the
675 destination will have all the nodes you specify with --base
675 destination will have all the nodes you specify with --base
676 parameters. To create a bundle containing all changesets, use
676 parameters. To create a bundle containing all changesets, use
677 -a/--all (or --base null).
677 -a/--all (or --base null).
678
678
679 You can change compression method with the -t/--type option.
679 You can change compression method with the -t/--type option.
680 The available compression methods are: none, bzip2, and
680 The available compression methods are: none, bzip2, and
681 gzip (by default, bundles are compressed using bzip2).
681 gzip (by default, bundles are compressed using bzip2).
682
682
683 The bundle file can then be transferred using conventional means
683 The bundle file can then be transferred using conventional means
684 and applied to another repository with the unbundle or pull
684 and applied to another repository with the unbundle or pull
685 command. This is useful when direct push and pull are not
685 command. This is useful when direct push and pull are not
686 available or when exporting an entire repository is undesirable.
686 available or when exporting an entire repository is undesirable.
687
687
688 Applying bundles preserves all changeset contents including
688 Applying bundles preserves all changeset contents including
689 permissions, copy/rename information, and revision history.
689 permissions, copy/rename information, and revision history.
690
690
691 Returns 0 on success, 1 if no changes found.
691 Returns 0 on success, 1 if no changes found.
692 """
692 """
693 revs = None
693 revs = None
694 if 'rev' in opts:
694 if 'rev' in opts:
695 revs = cmdutil.revrange(repo, opts['rev'])
695 revs = cmdutil.revrange(repo, opts['rev'])
696
696
697 if opts.get('all'):
697 if opts.get('all'):
698 base = ['null']
698 base = ['null']
699 else:
699 else:
700 base = cmdutil.revrange(repo, opts.get('base'))
700 base = cmdutil.revrange(repo, opts.get('base'))
701 if base:
701 if base:
702 if dest:
702 if dest:
703 raise util.Abort(_("--base is incompatible with specifying "
703 raise util.Abort(_("--base is incompatible with specifying "
704 "a destination"))
704 "a destination"))
705 common = [repo.lookup(rev) for rev in base]
705 common = [repo.lookup(rev) for rev in base]
706 heads = revs and map(repo.lookup, revs) or revs
706 heads = revs and map(repo.lookup, revs) or revs
707 else:
707 else:
708 dest = ui.expandpath(dest or 'default-push', dest or 'default')
708 dest = ui.expandpath(dest or 'default-push', dest or 'default')
709 dest, branches = hg.parseurl(dest, opts.get('branch'))
709 dest, branches = hg.parseurl(dest, opts.get('branch'))
710 other = hg.repository(hg.remoteui(repo, opts), dest)
710 other = hg.repository(hg.remoteui(repo, opts), dest)
711 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
711 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
712 heads = revs and map(repo.lookup, revs) or revs
712 heads = revs and map(repo.lookup, revs) or revs
713 common, outheads = discovery.findcommonoutgoing(repo, other,
713 common, outheads = discovery.findcommonoutgoing(repo, other,
714 onlyheads=heads,
714 onlyheads=heads,
715 force=opts.get('force'))
715 force=opts.get('force'))
716
716
717 cg = repo.getbundle('bundle', common=common, heads=heads)
717 cg = repo.getbundle('bundle', common=common, heads=heads)
718 if not cg:
718 if not cg:
719 ui.status(_("no changes found\n"))
719 ui.status(_("no changes found\n"))
720 return 1
720 return 1
721
721
722 bundletype = opts.get('type', 'bzip2').lower()
722 bundletype = opts.get('type', 'bzip2').lower()
723 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
723 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
724 bundletype = btypes.get(bundletype)
724 bundletype = btypes.get(bundletype)
725 if bundletype not in changegroup.bundletypes:
725 if bundletype not in changegroup.bundletypes:
726 raise util.Abort(_('unknown bundle type specified with --type'))
726 raise util.Abort(_('unknown bundle type specified with --type'))
727
727
728 changegroup.writebundle(cg, fname, bundletype)
728 changegroup.writebundle(cg, fname, bundletype)
729
729
730 def cat(ui, repo, file1, *pats, **opts):
730 def cat(ui, repo, file1, *pats, **opts):
731 """output the current or given revision of files
731 """output the current or given revision of files
732
732
733 Print the specified files as they were at the given revision. If
733 Print the specified files as they were at the given revision. If
734 no revision is given, the parent of the working directory is used,
734 no revision is given, the parent of the working directory is used,
735 or tip if no revision is checked out.
735 or tip if no revision is checked out.
736
736
737 Output may be to a file, in which case the name of the file is
737 Output may be to a file, in which case the name of the file is
738 given using a format string. The formatting rules are the same as
738 given using a format string. The formatting rules are the same as
739 for the export command, with the following additions:
739 for the export command, with the following additions:
740
740
741 :``%s``: basename of file being printed
741 :``%s``: basename of file being printed
742 :``%d``: dirname of file being printed, or '.' if in repository root
742 :``%d``: dirname of file being printed, or '.' if in repository root
743 :``%p``: root-relative path name of file being printed
743 :``%p``: root-relative path name of file being printed
744
744
745 Returns 0 on success.
745 Returns 0 on success.
746 """
746 """
747 ctx = cmdutil.revsingle(repo, opts.get('rev'))
747 ctx = cmdutil.revsingle(repo, opts.get('rev'))
748 err = 1
748 err = 1
749 m = cmdutil.match(repo, (file1,) + pats, opts)
749 m = cmdutil.match(repo, (file1,) + pats, opts)
750 for abs in ctx.walk(m):
750 for abs in ctx.walk(m):
751 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
751 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
752 data = ctx[abs].data()
752 data = ctx[abs].data()
753 if opts.get('decode'):
753 if opts.get('decode'):
754 data = repo.wwritedata(abs, data)
754 data = repo.wwritedata(abs, data)
755 fp.write(data)
755 fp.write(data)
756 fp.close()
756 fp.close()
757 err = 0
757 err = 0
758 return err
758 return err
759
759
760 def clone(ui, source, dest=None, **opts):
760 def clone(ui, source, dest=None, **opts):
761 """make a copy of an existing repository
761 """make a copy of an existing repository
762
762
763 Create a copy of an existing repository in a new directory.
763 Create a copy of an existing repository in a new directory.
764
764
765 If no destination directory name is specified, it defaults to the
765 If no destination directory name is specified, it defaults to the
766 basename of the source.
766 basename of the source.
767
767
768 The location of the source is added to the new repository's
768 The location of the source is added to the new repository's
769 ``.hg/hgrc`` file, as the default to be used for future pulls.
769 ``.hg/hgrc`` file, as the default to be used for future pulls.
770
770
771 See :hg:`help urls` for valid source format details.
771 See :hg:`help urls` for valid source format details.
772
772
773 It is possible to specify an ``ssh://`` URL as the destination, but no
773 It is possible to specify an ``ssh://`` URL as the destination, but no
774 ``.hg/hgrc`` and working directory will be created on the remote side.
774 ``.hg/hgrc`` and working directory will be created on the remote side.
775 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
775 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
776
776
777 A set of changesets (tags, or branch names) to pull may be specified
777 A set of changesets (tags, or branch names) to pull may be specified
778 by listing each changeset (tag, or branch name) with -r/--rev.
778 by listing each changeset (tag, or branch name) with -r/--rev.
779 If -r/--rev is used, the cloned repository will contain only a subset
779 If -r/--rev is used, the cloned repository will contain only a subset
780 of the changesets of the source repository. Only the set of changesets
780 of the changesets of the source repository. Only the set of changesets
781 defined by all -r/--rev options (including all their ancestors)
781 defined by all -r/--rev options (including all their ancestors)
782 will be pulled into the destination repository.
782 will be pulled into the destination repository.
783 No subsequent changesets (including subsequent tags) will be present
783 No subsequent changesets (including subsequent tags) will be present
784 in the destination.
784 in the destination.
785
785
786 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
786 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
787 local source repositories.
787 local source repositories.
788
788
789 For efficiency, hardlinks are used for cloning whenever the source
789 For efficiency, hardlinks are used for cloning whenever the source
790 and destination are on the same filesystem (note this applies only
790 and destination are on the same filesystem (note this applies only
791 to the repository data, not to the working directory). Some
791 to the repository data, not to the working directory). Some
792 filesystems, such as AFS, implement hardlinking incorrectly, but
792 filesystems, such as AFS, implement hardlinking incorrectly, but
793 do not report errors. In these cases, use the --pull option to
793 do not report errors. In these cases, use the --pull option to
794 avoid hardlinking.
794 avoid hardlinking.
795
795
796 In some cases, you can clone repositories and the working directory
796 In some cases, you can clone repositories and the working directory
797 using full hardlinks with ::
797 using full hardlinks with ::
798
798
799 $ cp -al REPO REPOCLONE
799 $ cp -al REPO REPOCLONE
800
800
801 This is the fastest way to clone, but it is not always safe. The
801 This is the fastest way to clone, but it is not always safe. The
802 operation is not atomic (making sure REPO is not modified during
802 operation is not atomic (making sure REPO is not modified during
803 the operation is up to you) and you have to make sure your editor
803 the operation is up to you) and you have to make sure your editor
804 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
804 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
805 this is not compatible with certain extensions that place their
805 this is not compatible with certain extensions that place their
806 metadata under the .hg directory, such as mq.
806 metadata under the .hg directory, such as mq.
807
807
808 Mercurial will update the working directory to the first applicable
808 Mercurial will update the working directory to the first applicable
809 revision from this list:
809 revision from this list:
810
810
811 a) null if -U or the source repository has no changesets
811 a) null if -U or the source repository has no changesets
812 b) if -u . and the source repository is local, the first parent of
812 b) if -u . and the source repository is local, the first parent of
813 the source repository's working directory
813 the source repository's working directory
814 c) the changeset specified with -u (if a branch name, this means the
814 c) the changeset specified with -u (if a branch name, this means the
815 latest head of that branch)
815 latest head of that branch)
816 d) the changeset specified with -r
816 d) the changeset specified with -r
817 e) the tipmost head specified with -b
817 e) the tipmost head specified with -b
818 f) the tipmost head specified with the url#branch source syntax
818 f) the tipmost head specified with the url#branch source syntax
819 g) the tipmost head of the default branch
819 g) the tipmost head of the default branch
820 h) tip
820 h) tip
821
821
822 Returns 0 on success.
822 Returns 0 on success.
823 """
823 """
824 if opts.get('noupdate') and opts.get('updaterev'):
824 if opts.get('noupdate') and opts.get('updaterev'):
825 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
825 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
826
826
827 r = hg.clone(hg.remoteui(ui, opts), source, dest,
827 r = hg.clone(hg.remoteui(ui, opts), source, dest,
828 pull=opts.get('pull'),
828 pull=opts.get('pull'),
829 stream=opts.get('uncompressed'),
829 stream=opts.get('uncompressed'),
830 rev=opts.get('rev'),
830 rev=opts.get('rev'),
831 update=opts.get('updaterev') or not opts.get('noupdate'),
831 update=opts.get('updaterev') or not opts.get('noupdate'),
832 branch=opts.get('branch'))
832 branch=opts.get('branch'))
833
833
834 return r is None
834 return r is None
835
835
836 def commit(ui, repo, *pats, **opts):
836 def commit(ui, repo, *pats, **opts):
837 """commit the specified files or all outstanding changes
837 """commit the specified files or all outstanding changes
838
838
839 Commit changes to the given files into the repository. Unlike a
839 Commit changes to the given files into the repository. Unlike a
840 centralized SCM, this operation is a local operation. See
840 centralized SCM, this operation is a local operation. See
841 :hg:`push` for a way to actively distribute your changes.
841 :hg:`push` for a way to actively distribute your changes.
842
842
843 If a list of files is omitted, all changes reported by :hg:`status`
843 If a list of files is omitted, all changes reported by :hg:`status`
844 will be committed.
844 will be committed.
845
845
846 If you are committing the result of a merge, do not provide any
846 If you are committing the result of a merge, do not provide any
847 filenames or -I/-X filters.
847 filenames or -I/-X filters.
848
848
849 If no commit message is specified, Mercurial starts your
849 If no commit message is specified, Mercurial starts your
850 configured editor where you can enter a message. In case your
850 configured editor where you can enter a message. In case your
851 commit fails, you will find a backup of your message in
851 commit fails, you will find a backup of your message in
852 ``.hg/last-message.txt``.
852 ``.hg/last-message.txt``.
853
853
854 See :hg:`help dates` for a list of formats valid for -d/--date.
854 See :hg:`help dates` for a list of formats valid for -d/--date.
855
855
856 Returns 0 on success, 1 if nothing changed.
856 Returns 0 on success, 1 if nothing changed.
857 """
857 """
858 extra = {}
858 extra = {}
859 if opts.get('close_branch'):
859 if opts.get('close_branch'):
860 if repo['.'].node() not in repo.branchheads():
860 if repo['.'].node() not in repo.branchheads():
861 # The topo heads set is included in the branch heads set of the
861 # The topo heads set is included in the branch heads set of the
862 # current branch, so it's sufficient to test branchheads
862 # current branch, so it's sufficient to test branchheads
863 raise util.Abort(_('can only close branch heads'))
863 raise util.Abort(_('can only close branch heads'))
864 extra['close'] = 1
864 extra['close'] = 1
865 e = cmdutil.commiteditor
865 e = cmdutil.commiteditor
866 if opts.get('force_editor'):
866 if opts.get('force_editor'):
867 e = cmdutil.commitforceeditor
867 e = cmdutil.commitforceeditor
868
868
869 def commitfunc(ui, repo, message, match, opts):
869 def commitfunc(ui, repo, message, match, opts):
870 return repo.commit(message, opts.get('user'), opts.get('date'), match,
870 return repo.commit(message, opts.get('user'), opts.get('date'), match,
871 editor=e, extra=extra)
871 editor=e, extra=extra)
872
872
873 branch = repo[None].branch()
873 branch = repo[None].branch()
874 bheads = repo.branchheads(branch)
874 bheads = repo.branchheads(branch)
875
875
876 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
876 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
877 if not node:
877 if not node:
878 stat = repo.status(match=cmdutil.match(repo, pats, opts))
878 stat = repo.status(match=cmdutil.match(repo, pats, opts))
879 if stat[3]:
879 if stat[3]:
880 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
880 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
881 % len(stat[3]))
881 % len(stat[3]))
882 else:
882 else:
883 ui.status(_("nothing changed\n"))
883 ui.status(_("nothing changed\n"))
884 return 1
884 return 1
885
885
886 ctx = repo[node]
886 ctx = repo[node]
887 parents = ctx.parents()
887 parents = ctx.parents()
888
888
889 if bheads and not [x for x in parents
889 if bheads and not [x for x in parents
890 if x.node() in bheads and x.branch() == branch]:
890 if x.node() in bheads and x.branch() == branch]:
891 ui.status(_('created new head\n'))
891 ui.status(_('created new head\n'))
892 # The message is not printed for initial roots. For the other
892 # The message is not printed for initial roots. For the other
893 # changesets, it is printed in the following situations:
893 # changesets, it is printed in the following situations:
894 #
894 #
895 # Par column: for the 2 parents with ...
895 # Par column: for the 2 parents with ...
896 # N: null or no parent
896 # N: null or no parent
897 # B: parent is on another named branch
897 # B: parent is on another named branch
898 # C: parent is a regular non head changeset
898 # C: parent is a regular non head changeset
899 # H: parent was a branch head of the current branch
899 # H: parent was a branch head of the current branch
900 # Msg column: whether we print "created new head" message
900 # Msg column: whether we print "created new head" message
901 # In the following, it is assumed that there already exists some
901 # In the following, it is assumed that there already exists some
902 # initial branch heads of the current branch, otherwise nothing is
902 # initial branch heads of the current branch, otherwise nothing is
903 # printed anyway.
903 # printed anyway.
904 #
904 #
905 # Par Msg Comment
905 # Par Msg Comment
906 # NN y additional topo root
906 # NN y additional topo root
907 #
907 #
908 # BN y additional branch root
908 # BN y additional branch root
909 # CN y additional topo head
909 # CN y additional topo head
910 # HN n usual case
910 # HN n usual case
911 #
911 #
912 # BB y weird additional branch root
912 # BB y weird additional branch root
913 # CB y branch merge
913 # CB y branch merge
914 # HB n merge with named branch
914 # HB n merge with named branch
915 #
915 #
916 # CC y additional head from merge
916 # CC y additional head from merge
917 # CH n merge with a head
917 # CH n merge with a head
918 #
918 #
919 # HH n head merge: head count decreases
919 # HH n head merge: head count decreases
920
920
921 if not opts.get('close_branch'):
921 if not opts.get('close_branch'):
922 for r in parents:
922 for r in parents:
923 if r.extra().get('close') and r.branch() == branch:
923 if r.extra().get('close') and r.branch() == branch:
924 ui.status(_('reopening closed branch head %d\n') % r)
924 ui.status(_('reopening closed branch head %d\n') % r)
925
925
926 if ui.debugflag:
926 if ui.debugflag:
927 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
927 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
928 elif ui.verbose:
928 elif ui.verbose:
929 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
929 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
930
930
931 def copy(ui, repo, *pats, **opts):
931 def copy(ui, repo, *pats, **opts):
932 """mark files as copied for the next commit
932 """mark files as copied for the next commit
933
933
934 Mark dest as having copies of source files. If dest is a
934 Mark dest as having copies of source files. If dest is a
935 directory, copies are put in that directory. If dest is a file,
935 directory, copies are put in that directory. If dest is a file,
936 the source must be a single file.
936 the source must be a single file.
937
937
938 By default, this command copies the contents of files as they
938 By default, this command copies the contents of files as they
939 exist in the working directory. If invoked with -A/--after, the
939 exist in the working directory. If invoked with -A/--after, the
940 operation is recorded, but no copying is performed.
940 operation is recorded, but no copying is performed.
941
941
942 This command takes effect with the next commit. To undo a copy
942 This command takes effect with the next commit. To undo a copy
943 before that, see :hg:`revert`.
943 before that, see :hg:`revert`.
944
944
945 Returns 0 on success, 1 if errors are encountered.
945 Returns 0 on success, 1 if errors are encountered.
946 """
946 """
947 wlock = repo.wlock(False)
947 wlock = repo.wlock(False)
948 try:
948 try:
949 return cmdutil.copy(ui, repo, pats, opts)
949 return cmdutil.copy(ui, repo, pats, opts)
950 finally:
950 finally:
951 wlock.release()
951 wlock.release()
952
952
953 def debugancestor(ui, repo, *args):
953 def debugancestor(ui, repo, *args):
954 """find the ancestor revision of two revisions in a given index"""
954 """find the ancestor revision of two revisions in a given index"""
955 if len(args) == 3:
955 if len(args) == 3:
956 index, rev1, rev2 = args
956 index, rev1, rev2 = args
957 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
957 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
958 lookup = r.lookup
958 lookup = r.lookup
959 elif len(args) == 2:
959 elif len(args) == 2:
960 if not repo:
960 if not repo:
961 raise util.Abort(_("there is no Mercurial repository here "
961 raise util.Abort(_("there is no Mercurial repository here "
962 "(.hg not found)"))
962 "(.hg not found)"))
963 rev1, rev2 = args
963 rev1, rev2 = args
964 r = repo.changelog
964 r = repo.changelog
965 lookup = repo.lookup
965 lookup = repo.lookup
966 else:
966 else:
967 raise util.Abort(_('either two or three arguments required'))
967 raise util.Abort(_('either two or three arguments required'))
968 a = r.ancestor(lookup(rev1), lookup(rev2))
968 a = r.ancestor(lookup(rev1), lookup(rev2))
969 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
969 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
970
970
971 def debugbuilddag(ui, repo, text=None,
971 def debugbuilddag(ui, repo, text=None,
972 mergeable_file=False,
972 mergeable_file=False,
973 overwritten_file=False,
973 overwritten_file=False,
974 new_file=False):
974 new_file=False):
975 """builds a repo with a given DAG from scratch in the current empty repo
975 """builds a repo with a given DAG from scratch in the current empty repo
976
976
977 The description of the DAG is read from stdin if not given on the
977 The description of the DAG is read from stdin if not given on the
978 command line.
978 command line.
979
979
980 Elements:
980 Elements:
981
981
982 - "+n" is a linear run of n nodes based on the current default parent
982 - "+n" is a linear run of n nodes based on the current default parent
983 - "." is a single node based on the current default parent
983 - "." is a single node based on the current default parent
984 - "$" resets the default parent to null (implied at the start);
984 - "$" resets the default parent to null (implied at the start);
985 otherwise the default parent is always the last node created
985 otherwise the default parent is always the last node created
986 - "<p" sets the default parent to the backref p
986 - "<p" sets the default parent to the backref p
987 - "*p" is a fork at parent p, which is a backref
987 - "*p" is a fork at parent p, which is a backref
988 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
988 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
989 - "/p2" is a merge of the preceding node and p2
989 - "/p2" is a merge of the preceding node and p2
990 - ":tag" defines a local tag for the preceding node
990 - ":tag" defines a local tag for the preceding node
991 - "@branch" sets the named branch for subsequent nodes
991 - "@branch" sets the named branch for subsequent nodes
992 - "#...\\n" is a comment up to the end of the line
992 - "#...\\n" is a comment up to the end of the line
993
993
994 Whitespace between the above elements is ignored.
994 Whitespace between the above elements is ignored.
995
995
996 A backref is either
996 A backref is either
997
997
998 - a number n, which references the node curr-n, where curr is the current
998 - a number n, which references the node curr-n, where curr is the current
999 node, or
999 node, or
1000 - the name of a local tag you placed earlier using ":tag", or
1000 - the name of a local tag you placed earlier using ":tag", or
1001 - empty to denote the default parent.
1001 - empty to denote the default parent.
1002
1002
1003 All string valued-elements are either strictly alphanumeric, or must
1003 All string valued-elements are either strictly alphanumeric, or must
1004 be enclosed in double quotes ("..."), with "\\" as escape character.
1004 be enclosed in double quotes ("..."), with "\\" as escape character.
1005 """
1005 """
1006
1006
1007 if text is None:
1007 if text is None:
1008 ui.status(_("reading DAG from stdin\n"))
1008 ui.status(_("reading DAG from stdin\n"))
1009 text = sys.stdin.read()
1009 text = sys.stdin.read()
1010
1010
1011 cl = repo.changelog
1011 cl = repo.changelog
1012 if len(cl) > 0:
1012 if len(cl) > 0:
1013 raise util.Abort(_('repository is not empty'))
1013 raise util.Abort(_('repository is not empty'))
1014
1014
1015 # determine number of revs in DAG
1015 # determine number of revs in DAG
1016 total = 0
1016 total = 0
1017 for type, data in dagparser.parsedag(text):
1017 for type, data in dagparser.parsedag(text):
1018 if type == 'n':
1018 if type == 'n':
1019 total += 1
1019 total += 1
1020
1020
1021 if mergeable_file:
1021 if mergeable_file:
1022 linesperrev = 2
1022 linesperrev = 2
1023 # make a file with k lines per rev
1023 # make a file with k lines per rev
1024 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1024 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1025 initialmergedlines.append("")
1025 initialmergedlines.append("")
1026
1026
1027 tags = []
1027 tags = []
1028
1028
1029 tr = repo.transaction("builddag")
1029 tr = repo.transaction("builddag")
1030 try:
1030 try:
1031
1031
1032 at = -1
1032 at = -1
1033 atbranch = 'default'
1033 atbranch = 'default'
1034 nodeids = []
1034 nodeids = []
1035 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1035 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1036 for type, data in dagparser.parsedag(text):
1036 for type, data in dagparser.parsedag(text):
1037 if type == 'n':
1037 if type == 'n':
1038 ui.note('node %s\n' % str(data))
1038 ui.note('node %s\n' % str(data))
1039 id, ps = data
1039 id, ps = data
1040
1040
1041 files = []
1041 files = []
1042 fctxs = {}
1042 fctxs = {}
1043
1043
1044 p2 = None
1044 p2 = None
1045 if mergeable_file:
1045 if mergeable_file:
1046 fn = "mf"
1046 fn = "mf"
1047 p1 = repo[ps[0]]
1047 p1 = repo[ps[0]]
1048 if len(ps) > 1:
1048 if len(ps) > 1:
1049 p2 = repo[ps[1]]
1049 p2 = repo[ps[1]]
1050 pa = p1.ancestor(p2)
1050 pa = p1.ancestor(p2)
1051 base, local, other = [x[fn].data() for x in pa, p1, p2]
1051 base, local, other = [x[fn].data() for x in pa, p1, p2]
1052 m3 = simplemerge.Merge3Text(base, local, other)
1052 m3 = simplemerge.Merge3Text(base, local, other)
1053 ml = [l.strip() for l in m3.merge_lines()]
1053 ml = [l.strip() for l in m3.merge_lines()]
1054 ml.append("")
1054 ml.append("")
1055 elif at > 0:
1055 elif at > 0:
1056 ml = p1[fn].data().split("\n")
1056 ml = p1[fn].data().split("\n")
1057 else:
1057 else:
1058 ml = initialmergedlines
1058 ml = initialmergedlines
1059 ml[id * linesperrev] += " r%i" % id
1059 ml[id * linesperrev] += " r%i" % id
1060 mergedtext = "\n".join(ml)
1060 mergedtext = "\n".join(ml)
1061 files.append(fn)
1061 files.append(fn)
1062 fctxs[fn] = context.memfilectx(fn, mergedtext)
1062 fctxs[fn] = context.memfilectx(fn, mergedtext)
1063
1063
1064 if overwritten_file:
1064 if overwritten_file:
1065 fn = "of"
1065 fn = "of"
1066 files.append(fn)
1066 files.append(fn)
1067 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1067 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1068
1068
1069 if new_file:
1069 if new_file:
1070 fn = "nf%i" % id
1070 fn = "nf%i" % id
1071 files.append(fn)
1071 files.append(fn)
1072 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1072 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1073 if len(ps) > 1:
1073 if len(ps) > 1:
1074 if not p2:
1074 if not p2:
1075 p2 = repo[ps[1]]
1075 p2 = repo[ps[1]]
1076 for fn in p2:
1076 for fn in p2:
1077 if fn.startswith("nf"):
1077 if fn.startswith("nf"):
1078 files.append(fn)
1078 files.append(fn)
1079 fctxs[fn] = p2[fn]
1079 fctxs[fn] = p2[fn]
1080
1080
1081 def fctxfn(repo, cx, path):
1081 def fctxfn(repo, cx, path):
1082 return fctxs.get(path)
1082 return fctxs.get(path)
1083
1083
1084 if len(ps) == 0 or ps[0] < 0:
1084 if len(ps) == 0 or ps[0] < 0:
1085 pars = [None, None]
1085 pars = [None, None]
1086 elif len(ps) == 1:
1086 elif len(ps) == 1:
1087 pars = [nodeids[ps[0]], None]
1087 pars = [nodeids[ps[0]], None]
1088 else:
1088 else:
1089 pars = [nodeids[p] for p in ps]
1089 pars = [nodeids[p] for p in ps]
1090 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1090 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1091 date=(id, 0),
1091 date=(id, 0),
1092 user="debugbuilddag",
1092 user="debugbuilddag",
1093 extra={'branch': atbranch})
1093 extra={'branch': atbranch})
1094 nodeid = repo.commitctx(cx)
1094 nodeid = repo.commitctx(cx)
1095 nodeids.append(nodeid)
1095 nodeids.append(nodeid)
1096 at = id
1096 at = id
1097 elif type == 'l':
1097 elif type == 'l':
1098 id, name = data
1098 id, name = data
1099 ui.note('tag %s\n' % name)
1099 ui.note('tag %s\n' % name)
1100 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1100 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1101 elif type == 'a':
1101 elif type == 'a':
1102 ui.note('branch %s\n' % data)
1102 ui.note('branch %s\n' % data)
1103 atbranch = data
1103 atbranch = data
1104 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1104 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1105 tr.close()
1105 tr.close()
1106 finally:
1106 finally:
1107 ui.progress(_('building'), None)
1107 ui.progress(_('building'), None)
1108 tr.release()
1108 tr.release()
1109
1109
1110 if tags:
1110 if tags:
1111 repo.opener.write("localtags", "".join(tags))
1111 repo.opener.write("localtags", "".join(tags))
1112
1112
1113 def debugcommands(ui, cmd='', *args):
1113 def debugcommands(ui, cmd='', *args):
1114 """list all available commands and options"""
1114 """list all available commands and options"""
1115 for cmd, vals in sorted(table.iteritems()):
1115 for cmd, vals in sorted(table.iteritems()):
1116 cmd = cmd.split('|')[0].strip('^')
1116 cmd = cmd.split('|')[0].strip('^')
1117 opts = ', '.join([i[1] for i in vals[1]])
1117 opts = ', '.join([i[1] for i in vals[1]])
1118 ui.write('%s: %s\n' % (cmd, opts))
1118 ui.write('%s: %s\n' % (cmd, opts))
1119
1119
1120 def debugcomplete(ui, cmd='', **opts):
1120 def debugcomplete(ui, cmd='', **opts):
1121 """returns the completion list associated with the given command"""
1121 """returns the completion list associated with the given command"""
1122
1122
1123 if opts.get('options'):
1123 if opts.get('options'):
1124 options = []
1124 options = []
1125 otables = [globalopts]
1125 otables = [globalopts]
1126 if cmd:
1126 if cmd:
1127 aliases, entry = cmdutil.findcmd(cmd, table, False)
1127 aliases, entry = cmdutil.findcmd(cmd, table, False)
1128 otables.append(entry[1])
1128 otables.append(entry[1])
1129 for t in otables:
1129 for t in otables:
1130 for o in t:
1130 for o in t:
1131 if "(DEPRECATED)" in o[3]:
1131 if "(DEPRECATED)" in o[3]:
1132 continue
1132 continue
1133 if o[0]:
1133 if o[0]:
1134 options.append('-%s' % o[0])
1134 options.append('-%s' % o[0])
1135 options.append('--%s' % o[1])
1135 options.append('--%s' % o[1])
1136 ui.write("%s\n" % "\n".join(options))
1136 ui.write("%s\n" % "\n".join(options))
1137 return
1137 return
1138
1138
1139 cmdlist = cmdutil.findpossible(cmd, table)
1139 cmdlist = cmdutil.findpossible(cmd, table)
1140 if ui.verbose:
1140 if ui.verbose:
1141 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1141 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1142 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1142 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1143
1143
1144 def debugfsinfo(ui, path = "."):
1144 def debugfsinfo(ui, path = "."):
1145 """show information detected about current filesystem"""
1145 """show information detected about current filesystem"""
1146 util.writefile('.debugfsinfo', '')
1146 util.writefile('.debugfsinfo', '')
1147 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1147 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1148 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1148 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1149 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1149 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1150 and 'yes' or 'no'))
1150 and 'yes' or 'no'))
1151 os.unlink('.debugfsinfo')
1151 os.unlink('.debugfsinfo')
1152
1152
1153 def debugrebuildstate(ui, repo, rev="tip"):
1153 def debugrebuildstate(ui, repo, rev="tip"):
1154 """rebuild the dirstate as it would look like for the given revision"""
1154 """rebuild the dirstate as it would look like for the given revision"""
1155 ctx = cmdutil.revsingle(repo, rev)
1155 ctx = cmdutil.revsingle(repo, rev)
1156 wlock = repo.wlock()
1156 wlock = repo.wlock()
1157 try:
1157 try:
1158 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1158 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1159 finally:
1159 finally:
1160 wlock.release()
1160 wlock.release()
1161
1161
1162 def debugcheckstate(ui, repo):
1162 def debugcheckstate(ui, repo):
1163 """validate the correctness of the current dirstate"""
1163 """validate the correctness of the current dirstate"""
1164 parent1, parent2 = repo.dirstate.parents()
1164 parent1, parent2 = repo.dirstate.parents()
1165 m1 = repo[parent1].manifest()
1165 m1 = repo[parent1].manifest()
1166 m2 = repo[parent2].manifest()
1166 m2 = repo[parent2].manifest()
1167 errors = 0
1167 errors = 0
1168 for f in repo.dirstate:
1168 for f in repo.dirstate:
1169 state = repo.dirstate[f]
1169 state = repo.dirstate[f]
1170 if state in "nr" and f not in m1:
1170 if state in "nr" and f not in m1:
1171 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1171 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1172 errors += 1
1172 errors += 1
1173 if state in "a" and f in m1:
1173 if state in "a" and f in m1:
1174 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1174 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1175 errors += 1
1175 errors += 1
1176 if state in "m" and f not in m1 and f not in m2:
1176 if state in "m" and f not in m1 and f not in m2:
1177 ui.warn(_("%s in state %s, but not in either manifest\n") %
1177 ui.warn(_("%s in state %s, but not in either manifest\n") %
1178 (f, state))
1178 (f, state))
1179 errors += 1
1179 errors += 1
1180 for f in m1:
1180 for f in m1:
1181 state = repo.dirstate[f]
1181 state = repo.dirstate[f]
1182 if state not in "nrm":
1182 if state not in "nrm":
1183 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1183 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1184 errors += 1
1184 errors += 1
1185 if errors:
1185 if errors:
1186 error = _(".hg/dirstate inconsistent with current parent's manifest")
1186 error = _(".hg/dirstate inconsistent with current parent's manifest")
1187 raise util.Abort(error)
1187 raise util.Abort(error)
1188
1188
1189 def showconfig(ui, repo, *values, **opts):
1189 def showconfig(ui, repo, *values, **opts):
1190 """show combined config settings from all hgrc files
1190 """show combined config settings from all hgrc files
1191
1191
1192 With no arguments, print names and values of all config items.
1192 With no arguments, print names and values of all config items.
1193
1193
1194 With one argument of the form section.name, print just the value
1194 With one argument of the form section.name, print just the value
1195 of that config item.
1195 of that config item.
1196
1196
1197 With multiple arguments, print names and values of all config
1197 With multiple arguments, print names and values of all config
1198 items with matching section names.
1198 items with matching section names.
1199
1199
1200 With --debug, the source (filename and line number) is printed
1200 With --debug, the source (filename and line number) is printed
1201 for each config item.
1201 for each config item.
1202
1202
1203 Returns 0 on success.
1203 Returns 0 on success.
1204 """
1204 """
1205
1205
1206 for f in scmutil.rcpath():
1206 for f in scmutil.rcpath():
1207 ui.debug(_('read config from: %s\n') % f)
1207 ui.debug(_('read config from: %s\n') % f)
1208 untrusted = bool(opts.get('untrusted'))
1208 untrusted = bool(opts.get('untrusted'))
1209 if values:
1209 if values:
1210 sections = [v for v in values if '.' not in v]
1210 sections = [v for v in values if '.' not in v]
1211 items = [v for v in values if '.' in v]
1211 items = [v for v in values if '.' in v]
1212 if len(items) > 1 or items and sections:
1212 if len(items) > 1 or items and sections:
1213 raise util.Abort(_('only one config item permitted'))
1213 raise util.Abort(_('only one config item permitted'))
1214 for section, name, value in ui.walkconfig(untrusted=untrusted):
1214 for section, name, value in ui.walkconfig(untrusted=untrusted):
1215 value = str(value).replace('\n', '\\n')
1215 value = str(value).replace('\n', '\\n')
1216 sectname = section + '.' + name
1216 sectname = section + '.' + name
1217 if values:
1217 if values:
1218 for v in values:
1218 for v in values:
1219 if v == section:
1219 if v == section:
1220 ui.debug('%s: ' %
1220 ui.debug('%s: ' %
1221 ui.configsource(section, name, untrusted))
1221 ui.configsource(section, name, untrusted))
1222 ui.write('%s=%s\n' % (sectname, value))
1222 ui.write('%s=%s\n' % (sectname, value))
1223 elif v == sectname:
1223 elif v == sectname:
1224 ui.debug('%s: ' %
1224 ui.debug('%s: ' %
1225 ui.configsource(section, name, untrusted))
1225 ui.configsource(section, name, untrusted))
1226 ui.write(value, '\n')
1226 ui.write(value, '\n')
1227 else:
1227 else:
1228 ui.debug('%s: ' %
1228 ui.debug('%s: ' %
1229 ui.configsource(section, name, untrusted))
1229 ui.configsource(section, name, untrusted))
1230 ui.write('%s=%s\n' % (sectname, value))
1230 ui.write('%s=%s\n' % (sectname, value))
1231
1231
1232 def debugknown(ui, repopath, *ids, **opts):
1232 def debugknown(ui, repopath, *ids, **opts):
1233 """test whether node ids are known to a repo
1233 """test whether node ids are known to a repo
1234
1234
1235 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1235 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1236 indicating unknown/known.
1236 indicating unknown/known.
1237 """
1237 """
1238 repo = hg.repository(ui, repopath)
1238 repo = hg.repository(ui, repopath)
1239 if not repo.capable('known'):
1239 if not repo.capable('known'):
1240 raise util.Abort("known() not supported by target repository")
1240 raise util.Abort("known() not supported by target repository")
1241 flags = repo.known([bin(s) for s in ids])
1241 flags = repo.known([bin(s) for s in ids])
1242 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1242 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1243
1243
1244 def debugbundle(ui, bundlepath, all=None, **opts):
1244 def debugbundle(ui, bundlepath, all=None, **opts):
1245 """lists the contents of a bundle"""
1245 """lists the contents of a bundle"""
1246 f = url.open(ui, bundlepath)
1246 f = url.open(ui, bundlepath)
1247 try:
1247 try:
1248 gen = changegroup.readbundle(f, bundlepath)
1248 gen = changegroup.readbundle(f, bundlepath)
1249 if all:
1249 if all:
1250 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1250 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1251
1251
1252 def showchunks(named):
1252 def showchunks(named):
1253 ui.write("\n%s\n" % named)
1253 ui.write("\n%s\n" % named)
1254 chain = None
1254 chain = None
1255 while 1:
1255 while 1:
1256 chunkdata = gen.deltachunk(chain)
1256 chunkdata = gen.deltachunk(chain)
1257 if not chunkdata:
1257 if not chunkdata:
1258 break
1258 break
1259 node = chunkdata['node']
1259 node = chunkdata['node']
1260 p1 = chunkdata['p1']
1260 p1 = chunkdata['p1']
1261 p2 = chunkdata['p2']
1261 p2 = chunkdata['p2']
1262 cs = chunkdata['cs']
1262 cs = chunkdata['cs']
1263 deltabase = chunkdata['deltabase']
1263 deltabase = chunkdata['deltabase']
1264 delta = chunkdata['delta']
1264 delta = chunkdata['delta']
1265 ui.write("%s %s %s %s %s %s\n" %
1265 ui.write("%s %s %s %s %s %s\n" %
1266 (hex(node), hex(p1), hex(p2),
1266 (hex(node), hex(p1), hex(p2),
1267 hex(cs), hex(deltabase), len(delta)))
1267 hex(cs), hex(deltabase), len(delta)))
1268 chain = node
1268 chain = node
1269
1269
1270 chunkdata = gen.changelogheader()
1270 chunkdata = gen.changelogheader()
1271 showchunks("changelog")
1271 showchunks("changelog")
1272 chunkdata = gen.manifestheader()
1272 chunkdata = gen.manifestheader()
1273 showchunks("manifest")
1273 showchunks("manifest")
1274 while 1:
1274 while 1:
1275 chunkdata = gen.filelogheader()
1275 chunkdata = gen.filelogheader()
1276 if not chunkdata:
1276 if not chunkdata:
1277 break
1277 break
1278 fname = chunkdata['filename']
1278 fname = chunkdata['filename']
1279 showchunks(fname)
1279 showchunks(fname)
1280 else:
1280 else:
1281 chunkdata = gen.changelogheader()
1281 chunkdata = gen.changelogheader()
1282 chain = None
1282 chain = None
1283 while 1:
1283 while 1:
1284 chunkdata = gen.deltachunk(chain)
1284 chunkdata = gen.deltachunk(chain)
1285 if not chunkdata:
1285 if not chunkdata:
1286 break
1286 break
1287 node = chunkdata['node']
1287 node = chunkdata['node']
1288 ui.write("%s\n" % hex(node))
1288 ui.write("%s\n" % hex(node))
1289 chain = node
1289 chain = node
1290 finally:
1290 finally:
1291 f.close()
1291 f.close()
1292
1292
1293 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1293 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1294 """retrieves a bundle from a repo
1294 """retrieves a bundle from a repo
1295
1295
1296 Every ID must be a full-length hex node id string. Saves the bundle to the
1296 Every ID must be a full-length hex node id string. Saves the bundle to the
1297 given file.
1297 given file.
1298 """
1298 """
1299 repo = hg.repository(ui, repopath)
1299 repo = hg.repository(ui, repopath)
1300 if not repo.capable('getbundle'):
1300 if not repo.capable('getbundle'):
1301 raise util.Abort("getbundle() not supported by target repository")
1301 raise util.Abort("getbundle() not supported by target repository")
1302 args = {}
1302 args = {}
1303 if common:
1303 if common:
1304 args['common'] = [bin(s) for s in common]
1304 args['common'] = [bin(s) for s in common]
1305 if head:
1305 if head:
1306 args['heads'] = [bin(s) for s in head]
1306 args['heads'] = [bin(s) for s in head]
1307 bundle = repo.getbundle('debug', **args)
1307 bundle = repo.getbundle('debug', **args)
1308
1308
1309 bundletype = opts.get('type', 'bzip2').lower()
1309 bundletype = opts.get('type', 'bzip2').lower()
1310 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1310 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1311 bundletype = btypes.get(bundletype)
1311 bundletype = btypes.get(bundletype)
1312 if bundletype not in changegroup.bundletypes:
1312 if bundletype not in changegroup.bundletypes:
1313 raise util.Abort(_('unknown bundle type specified with --type'))
1313 raise util.Abort(_('unknown bundle type specified with --type'))
1314 changegroup.writebundle(bundle, bundlepath, bundletype)
1314 changegroup.writebundle(bundle, bundlepath, bundletype)
1315
1315
1316 def debugpushkey(ui, repopath, namespace, *keyinfo):
1316 def debugpushkey(ui, repopath, namespace, *keyinfo):
1317 '''access the pushkey key/value protocol
1317 '''access the pushkey key/value protocol
1318
1318
1319 With two args, list the keys in the given namespace.
1319 With two args, list the keys in the given namespace.
1320
1320
1321 With five args, set a key to new if it currently is set to old.
1321 With five args, set a key to new if it currently is set to old.
1322 Reports success or failure.
1322 Reports success or failure.
1323 '''
1323 '''
1324
1324
1325 target = hg.repository(ui, repopath)
1325 target = hg.repository(ui, repopath)
1326 if keyinfo:
1326 if keyinfo:
1327 key, old, new = keyinfo
1327 key, old, new = keyinfo
1328 r = target.pushkey(namespace, key, old, new)
1328 r = target.pushkey(namespace, key, old, new)
1329 ui.status(str(r) + '\n')
1329 ui.status(str(r) + '\n')
1330 return not r
1330 return not r
1331 else:
1331 else:
1332 for k, v in target.listkeys(namespace).iteritems():
1332 for k, v in target.listkeys(namespace).iteritems():
1333 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1333 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1334 v.encode('string-escape')))
1334 v.encode('string-escape')))
1335
1335
1336 def debugrevspec(ui, repo, expr):
1336 def debugrevspec(ui, repo, expr):
1337 '''parse and apply a revision specification'''
1337 '''parse and apply a revision specification'''
1338 if ui.verbose:
1338 if ui.verbose:
1339 tree = revset.parse(expr)[0]
1339 tree = revset.parse(expr)[0]
1340 ui.note(tree, "\n")
1340 ui.note(tree, "\n")
1341 newtree = revset.findaliases(ui, tree)
1341 newtree = revset.findaliases(ui, tree)
1342 if newtree != tree:
1342 if newtree != tree:
1343 ui.note(newtree, "\n")
1343 ui.note(newtree, "\n")
1344 func = revset.match(ui, expr)
1344 func = revset.match(ui, expr)
1345 for c in func(repo, range(len(repo))):
1345 for c in func(repo, range(len(repo))):
1346 ui.write("%s\n" % c)
1346 ui.write("%s\n" % c)
1347
1347
1348 def debugsetparents(ui, repo, rev1, rev2=None):
1348 def debugsetparents(ui, repo, rev1, rev2=None):
1349 """manually set the parents of the current working directory
1349 """manually set the parents of the current working directory
1350
1350
1351 This is useful for writing repository conversion tools, but should
1351 This is useful for writing repository conversion tools, but should
1352 be used with care.
1352 be used with care.
1353
1353
1354 Returns 0 on success.
1354 Returns 0 on success.
1355 """
1355 """
1356
1356
1357 r1 = cmdutil.revsingle(repo, rev1).node()
1357 r1 = cmdutil.revsingle(repo, rev1).node()
1358 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1358 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1359
1359
1360 wlock = repo.wlock()
1360 wlock = repo.wlock()
1361 try:
1361 try:
1362 repo.dirstate.setparents(r1, r2)
1362 repo.dirstate.setparents(r1, r2)
1363 finally:
1363 finally:
1364 wlock.release()
1364 wlock.release()
1365
1365
1366 def debugstate(ui, repo, nodates=None, datesort=None):
1366 def debugstate(ui, repo, nodates=None, datesort=None):
1367 """show the contents of the current dirstate"""
1367 """show the contents of the current dirstate"""
1368 timestr = ""
1368 timestr = ""
1369 showdate = not nodates
1369 showdate = not nodates
1370 if datesort:
1370 if datesort:
1371 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
1371 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
1372 else:
1372 else:
1373 keyfunc = None # sort by filename
1373 keyfunc = None # sort by filename
1374 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
1374 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
1375 if showdate:
1375 if showdate:
1376 if ent[3] == -1:
1376 if ent[3] == -1:
1377 # Pad or slice to locale representation
1377 # Pad or slice to locale representation
1378 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1378 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1379 time.localtime(0)))
1379 time.localtime(0)))
1380 timestr = 'unset'
1380 timestr = 'unset'
1381 timestr = (timestr[:locale_len] +
1381 timestr = (timestr[:locale_len] +
1382 ' ' * (locale_len - len(timestr)))
1382 ' ' * (locale_len - len(timestr)))
1383 else:
1383 else:
1384 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1384 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1385 time.localtime(ent[3]))
1385 time.localtime(ent[3]))
1386 if ent[1] & 020000:
1386 if ent[1] & 020000:
1387 mode = 'lnk'
1387 mode = 'lnk'
1388 else:
1388 else:
1389 mode = '%3o' % (ent[1] & 0777)
1389 mode = '%3o' % (ent[1] & 0777)
1390 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1390 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1391 for f in repo.dirstate.copies():
1391 for f in repo.dirstate.copies():
1392 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1392 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1393
1393
1394 def debugsub(ui, repo, rev=None):
1394 def debugsub(ui, repo, rev=None):
1395 ctx = cmdutil.revsingle(repo, rev, None)
1395 ctx = cmdutil.revsingle(repo, rev, None)
1396 for k, v in sorted(ctx.substate.items()):
1396 for k, v in sorted(ctx.substate.items()):
1397 ui.write('path %s\n' % k)
1397 ui.write('path %s\n' % k)
1398 ui.write(' source %s\n' % v[0])
1398 ui.write(' source %s\n' % v[0])
1399 ui.write(' revision %s\n' % v[1])
1399 ui.write(' revision %s\n' % v[1])
1400
1400
1401 def debugdag(ui, repo, file_=None, *revs, **opts):
1401 def debugdag(ui, repo, file_=None, *revs, **opts):
1402 """format the changelog or an index DAG as a concise textual description
1402 """format the changelog or an index DAG as a concise textual description
1403
1403
1404 If you pass a revlog index, the revlog's DAG is emitted. If you list
1404 If you pass a revlog index, the revlog's DAG is emitted. If you list
1405 revision numbers, they get labelled in the output as rN.
1405 revision numbers, they get labelled in the output as rN.
1406
1406
1407 Otherwise, the changelog DAG of the current repo is emitted.
1407 Otherwise, the changelog DAG of the current repo is emitted.
1408 """
1408 """
1409 spaces = opts.get('spaces')
1409 spaces = opts.get('spaces')
1410 dots = opts.get('dots')
1410 dots = opts.get('dots')
1411 if file_:
1411 if file_:
1412 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1412 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1413 revs = set((int(r) for r in revs))
1413 revs = set((int(r) for r in revs))
1414 def events():
1414 def events():
1415 for r in rlog:
1415 for r in rlog:
1416 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1416 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1417 if r in revs:
1417 if r in revs:
1418 yield 'l', (r, "r%i" % r)
1418 yield 'l', (r, "r%i" % r)
1419 elif repo:
1419 elif repo:
1420 cl = repo.changelog
1420 cl = repo.changelog
1421 tags = opts.get('tags')
1421 tags = opts.get('tags')
1422 branches = opts.get('branches')
1422 branches = opts.get('branches')
1423 if tags:
1423 if tags:
1424 labels = {}
1424 labels = {}
1425 for l, n in repo.tags().items():
1425 for l, n in repo.tags().items():
1426 labels.setdefault(cl.rev(n), []).append(l)
1426 labels.setdefault(cl.rev(n), []).append(l)
1427 def events():
1427 def events():
1428 b = "default"
1428 b = "default"
1429 for r in cl:
1429 for r in cl:
1430 if branches:
1430 if branches:
1431 newb = cl.read(cl.node(r))[5]['branch']
1431 newb = cl.read(cl.node(r))[5]['branch']
1432 if newb != b:
1432 if newb != b:
1433 yield 'a', newb
1433 yield 'a', newb
1434 b = newb
1434 b = newb
1435 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1435 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1436 if tags:
1436 if tags:
1437 ls = labels.get(r)
1437 ls = labels.get(r)
1438 if ls:
1438 if ls:
1439 for l in ls:
1439 for l in ls:
1440 yield 'l', (r, l)
1440 yield 'l', (r, l)
1441 else:
1441 else:
1442 raise util.Abort(_('need repo for changelog dag'))
1442 raise util.Abort(_('need repo for changelog dag'))
1443
1443
1444 for line in dagparser.dagtextlines(events(),
1444 for line in dagparser.dagtextlines(events(),
1445 addspaces=spaces,
1445 addspaces=spaces,
1446 wraplabels=True,
1446 wraplabels=True,
1447 wrapannotations=True,
1447 wrapannotations=True,
1448 wrapnonlinear=dots,
1448 wrapnonlinear=dots,
1449 usedots=dots,
1449 usedots=dots,
1450 maxlinewidth=70):
1450 maxlinewidth=70):
1451 ui.write(line)
1451 ui.write(line)
1452 ui.write("\n")
1452 ui.write("\n")
1453
1453
1454 def debugdata(ui, repo, file_, rev):
1454 def debugdata(ui, repo, file_, rev):
1455 """dump the contents of a data file revision"""
1455 """dump the contents of a data file revision"""
1456 r = None
1456 r = None
1457 if repo:
1457 if repo:
1458 filelog = repo.file(file_)
1458 filelog = repo.file(file_)
1459 if len(filelog):
1459 if len(filelog):
1460 r = filelog
1460 r = filelog
1461 if not r:
1461 if not r:
1462 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
1462 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
1463 file_[:-2] + ".i")
1463 file_[:-2] + ".i")
1464 try:
1464 try:
1465 ui.write(r.revision(r.lookup(rev)))
1465 ui.write(r.revision(r.lookup(rev)))
1466 except KeyError:
1466 except KeyError:
1467 raise util.Abort(_('invalid revision identifier %s') % rev)
1467 raise util.Abort(_('invalid revision identifier %s') % rev)
1468
1468
1469 def debugdate(ui, date, range=None, **opts):
1469 def debugdate(ui, date, range=None, **opts):
1470 """parse and display a date"""
1470 """parse and display a date"""
1471 if opts["extended"]:
1471 if opts["extended"]:
1472 d = util.parsedate(date, util.extendeddateformats)
1472 d = util.parsedate(date, util.extendeddateformats)
1473 else:
1473 else:
1474 d = util.parsedate(date)
1474 d = util.parsedate(date)
1475 ui.write("internal: %s %s\n" % d)
1475 ui.write("internal: %s %s\n" % d)
1476 ui.write("standard: %s\n" % util.datestr(d))
1476 ui.write("standard: %s\n" % util.datestr(d))
1477 if range:
1477 if range:
1478 m = util.matchdate(range)
1478 m = util.matchdate(range)
1479 ui.write("match: %s\n" % m(d[0]))
1479 ui.write("match: %s\n" % m(d[0]))
1480
1480
1481 def debugignore(ui, repo, *values, **opts):
1481 def debugignore(ui, repo, *values, **opts):
1482 """display the combined ignore pattern"""
1482 """display the combined ignore pattern"""
1483 ignore = repo.dirstate._ignore
1483 ignore = repo.dirstate._ignore
1484 if hasattr(ignore, 'includepat'):
1484 if hasattr(ignore, 'includepat'):
1485 ui.write("%s\n" % ignore.includepat)
1485 ui.write("%s\n" % ignore.includepat)
1486 else:
1486 else:
1487 raise util.Abort(_("no ignore patterns found"))
1487 raise util.Abort(_("no ignore patterns found"))
1488
1488
1489 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1489 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1490 """runs the changeset discovery protocol in isolation"""
1490 """runs the changeset discovery protocol in isolation"""
1491 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1491 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1492 remote = hg.repository(hg.remoteui(repo, opts), remoteurl)
1492 remote = hg.repository(hg.remoteui(repo, opts), remoteurl)
1493 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1493 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1494
1494
1495 # make sure tests are repeatable
1495 # make sure tests are repeatable
1496 random.seed(12323)
1496 random.seed(12323)
1497
1497
1498 def doit(localheads, remoteheads):
1498 def doit(localheads, remoteheads):
1499 if opts.get('old'):
1499 if opts.get('old'):
1500 if localheads:
1500 if localheads:
1501 raise util.Abort('cannot use localheads with old style discovery')
1501 raise util.Abort('cannot use localheads with old style discovery')
1502 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1502 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1503 force=True)
1503 force=True)
1504 common = set(common)
1504 common = set(common)
1505 if not opts.get('nonheads'):
1505 if not opts.get('nonheads'):
1506 ui.write("unpruned common: %s\n" % " ".join([short(n)
1506 ui.write("unpruned common: %s\n" % " ".join([short(n)
1507 for n in common]))
1507 for n in common]))
1508 dag = dagutil.revlogdag(repo.changelog)
1508 dag = dagutil.revlogdag(repo.changelog)
1509 all = dag.ancestorset(dag.internalizeall(common))
1509 all = dag.ancestorset(dag.internalizeall(common))
1510 common = dag.externalizeall(dag.headsetofconnecteds(all))
1510 common = dag.externalizeall(dag.headsetofconnecteds(all))
1511 else:
1511 else:
1512 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1512 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1513 common = set(common)
1513 common = set(common)
1514 rheads = set(hds)
1514 rheads = set(hds)
1515 lheads = set(repo.heads())
1515 lheads = set(repo.heads())
1516 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1516 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1517 if lheads <= common:
1517 if lheads <= common:
1518 ui.write("local is subset\n")
1518 ui.write("local is subset\n")
1519 elif rheads <= common:
1519 elif rheads <= common:
1520 ui.write("remote is subset\n")
1520 ui.write("remote is subset\n")
1521
1521
1522 serverlogs = opts.get('serverlog')
1522 serverlogs = opts.get('serverlog')
1523 if serverlogs:
1523 if serverlogs:
1524 for filename in serverlogs:
1524 for filename in serverlogs:
1525 logfile = open(filename, 'r')
1525 logfile = open(filename, 'r')
1526 try:
1526 try:
1527 line = logfile.readline()
1527 line = logfile.readline()
1528 while line:
1528 while line:
1529 parts = line.strip().split(';')
1529 parts = line.strip().split(';')
1530 op = parts[1]
1530 op = parts[1]
1531 if op == 'cg':
1531 if op == 'cg':
1532 pass
1532 pass
1533 elif op == 'cgss':
1533 elif op == 'cgss':
1534 doit(parts[2].split(' '), parts[3].split(' '))
1534 doit(parts[2].split(' '), parts[3].split(' '))
1535 elif op == 'unb':
1535 elif op == 'unb':
1536 doit(parts[3].split(' '), parts[2].split(' '))
1536 doit(parts[3].split(' '), parts[2].split(' '))
1537 line = logfile.readline()
1537 line = logfile.readline()
1538 finally:
1538 finally:
1539 logfile.close()
1539 logfile.close()
1540
1540
1541 else:
1541 else:
1542 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1542 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1543 opts.get('remote_head'))
1543 opts.get('remote_head'))
1544 localrevs = opts.get('local_head')
1544 localrevs = opts.get('local_head')
1545 doit(localrevs, remoterevs)
1545 doit(localrevs, remoterevs)
1546
1546
1547
1547
1548 def debugindex(ui, repo, file_, **opts):
1548 def debugindex(ui, repo, file_, **opts):
1549 """dump the contents of an index file"""
1549 """dump the contents of an index file"""
1550 r = None
1550 r = None
1551 if repo:
1551 if repo:
1552 filelog = repo.file(file_)
1552 filelog = repo.file(file_)
1553 if len(filelog):
1553 if len(filelog):
1554 r = filelog
1554 r = filelog
1555
1555
1556 format = opts.get('format', 0)
1556 format = opts.get('format', 0)
1557 if format not in (0, 1):
1557 if format not in (0, 1):
1558 raise util.Abort(_("unknown format %d") % format)
1558 raise util.Abort(_("unknown format %d") % format)
1559
1559
1560 if not r:
1560 if not r:
1561 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1561 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1562
1562
1563 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1563 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1564 if generaldelta:
1564 if generaldelta:
1565 basehdr = ' delta'
1565 basehdr = ' delta'
1566 else:
1566 else:
1567 basehdr = ' base'
1567 basehdr = ' base'
1568
1568
1569 if format == 0:
1569 if format == 0:
1570 ui.write(" rev offset length " + basehdr + " linkrev"
1570 ui.write(" rev offset length " + basehdr + " linkrev"
1571 " nodeid p1 p2\n")
1571 " nodeid p1 p2\n")
1572 elif format == 1:
1572 elif format == 1:
1573 ui.write(" rev flag offset length"
1573 ui.write(" rev flag offset length"
1574 " size " + basehdr + " link p1 p2 nodeid\n")
1574 " size " + basehdr + " link p1 p2 nodeid\n")
1575
1575
1576 for i in r:
1576 for i in r:
1577 node = r.node(i)
1577 node = r.node(i)
1578 if generaldelta:
1578 if generaldelta:
1579 base = r.deltaparent(i)
1579 base = r.deltaparent(i)
1580 else:
1580 else:
1581 base = r.chainbase(i)
1581 base = r.chainbase(i)
1582 if format == 0:
1582 if format == 0:
1583 try:
1583 try:
1584 pp = r.parents(node)
1584 pp = r.parents(node)
1585 except:
1585 except:
1586 pp = [nullid, nullid]
1586 pp = [nullid, nullid]
1587 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1587 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1588 i, r.start(i), r.length(i), base, r.linkrev(i),
1588 i, r.start(i), r.length(i), base, r.linkrev(i),
1589 short(node), short(pp[0]), short(pp[1])))
1589 short(node), short(pp[0]), short(pp[1])))
1590 elif format == 1:
1590 elif format == 1:
1591 pr = r.parentrevs(i)
1591 pr = r.parentrevs(i)
1592 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1592 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1593 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1593 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1594 base, r.linkrev(i), pr[0], pr[1], short(node)))
1594 base, r.linkrev(i), pr[0], pr[1], short(node)))
1595
1595
1596 def debugindexdot(ui, repo, file_):
1596 def debugindexdot(ui, repo, file_):
1597 """dump an index DAG as a graphviz dot file"""
1597 """dump an index DAG as a graphviz dot file"""
1598 r = None
1598 r = None
1599 if repo:
1599 if repo:
1600 filelog = repo.file(file_)
1600 filelog = repo.file(file_)
1601 if len(filelog):
1601 if len(filelog):
1602 r = filelog
1602 r = filelog
1603 if not r:
1603 if not r:
1604 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1604 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1605 ui.write("digraph G {\n")
1605 ui.write("digraph G {\n")
1606 for i in r:
1606 for i in r:
1607 node = r.node(i)
1607 node = r.node(i)
1608 pp = r.parents(node)
1608 pp = r.parents(node)
1609 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1609 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1610 if pp[1] != nullid:
1610 if pp[1] != nullid:
1611 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1611 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1612 ui.write("}\n")
1612 ui.write("}\n")
1613
1613
1614 def debuginstall(ui):
1614 def debuginstall(ui):
1615 '''test Mercurial installation
1615 '''test Mercurial installation
1616
1616
1617 Returns 0 on success.
1617 Returns 0 on success.
1618 '''
1618 '''
1619
1619
1620 def writetemp(contents):
1620 def writetemp(contents):
1621 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1621 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1622 f = os.fdopen(fd, "wb")
1622 f = os.fdopen(fd, "wb")
1623 f.write(contents)
1623 f.write(contents)
1624 f.close()
1624 f.close()
1625 return name
1625 return name
1626
1626
1627 problems = 0
1627 problems = 0
1628
1628
1629 # encoding
1629 # encoding
1630 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1630 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1631 try:
1631 try:
1632 encoding.fromlocal("test")
1632 encoding.fromlocal("test")
1633 except util.Abort, inst:
1633 except util.Abort, inst:
1634 ui.write(" %s\n" % inst)
1634 ui.write(" %s\n" % inst)
1635 ui.write(_(" (check that your locale is properly set)\n"))
1635 ui.write(_(" (check that your locale is properly set)\n"))
1636 problems += 1
1636 problems += 1
1637
1637
1638 # compiled modules
1638 # compiled modules
1639 ui.status(_("Checking installed modules (%s)...\n")
1639 ui.status(_("Checking installed modules (%s)...\n")
1640 % os.path.dirname(__file__))
1640 % os.path.dirname(__file__))
1641 try:
1641 try:
1642 import bdiff, mpatch, base85, osutil
1642 import bdiff, mpatch, base85, osutil
1643 except Exception, inst:
1643 except Exception, inst:
1644 ui.write(" %s\n" % inst)
1644 ui.write(" %s\n" % inst)
1645 ui.write(_(" One or more extensions could not be found"))
1645 ui.write(_(" One or more extensions could not be found"))
1646 ui.write(_(" (check that you compiled the extensions)\n"))
1646 ui.write(_(" (check that you compiled the extensions)\n"))
1647 problems += 1
1647 problems += 1
1648
1648
1649 # templates
1649 # templates
1650 ui.status(_("Checking templates...\n"))
1650 ui.status(_("Checking templates...\n"))
1651 try:
1651 try:
1652 import templater
1652 import templater
1653 templater.templater(templater.templatepath("map-cmdline.default"))
1653 templater.templater(templater.templatepath("map-cmdline.default"))
1654 except Exception, inst:
1654 except Exception, inst:
1655 ui.write(" %s\n" % inst)
1655 ui.write(" %s\n" % inst)
1656 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1656 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1657 problems += 1
1657 problems += 1
1658
1658
1659 # editor
1659 # editor
1660 ui.status(_("Checking commit editor...\n"))
1660 ui.status(_("Checking commit editor...\n"))
1661 editor = ui.geteditor()
1661 editor = ui.geteditor()
1662 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1662 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1663 if not cmdpath:
1663 if not cmdpath:
1664 if editor == 'vi':
1664 if editor == 'vi':
1665 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1665 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1666 ui.write(_(" (specify a commit editor in your configuration"
1666 ui.write(_(" (specify a commit editor in your configuration"
1667 " file)\n"))
1667 " file)\n"))
1668 else:
1668 else:
1669 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1669 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1670 ui.write(_(" (specify a commit editor in your configuration"
1670 ui.write(_(" (specify a commit editor in your configuration"
1671 " file)\n"))
1671 " file)\n"))
1672 problems += 1
1672 problems += 1
1673
1673
1674 # check username
1674 # check username
1675 ui.status(_("Checking username...\n"))
1675 ui.status(_("Checking username...\n"))
1676 try:
1676 try:
1677 ui.username()
1677 ui.username()
1678 except util.Abort, e:
1678 except util.Abort, e:
1679 ui.write(" %s\n" % e)
1679 ui.write(" %s\n" % e)
1680 ui.write(_(" (specify a username in your configuration file)\n"))
1680 ui.write(_(" (specify a username in your configuration file)\n"))
1681 problems += 1
1681 problems += 1
1682
1682
1683 if not problems:
1683 if not problems:
1684 ui.status(_("No problems detected\n"))
1684 ui.status(_("No problems detected\n"))
1685 else:
1685 else:
1686 ui.write(_("%s problems detected,"
1686 ui.write(_("%s problems detected,"
1687 " please check your install!\n") % problems)
1687 " please check your install!\n") % problems)
1688
1688
1689 return problems
1689 return problems
1690
1690
1691 def debugrename(ui, repo, file1, *pats, **opts):
1691 def debugrename(ui, repo, file1, *pats, **opts):
1692 """dump rename information"""
1692 """dump rename information"""
1693
1693
1694 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1694 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1695 m = cmdutil.match(repo, (file1,) + pats, opts)
1695 m = cmdutil.match(repo, (file1,) + pats, opts)
1696 for abs in ctx.walk(m):
1696 for abs in ctx.walk(m):
1697 fctx = ctx[abs]
1697 fctx = ctx[abs]
1698 o = fctx.filelog().renamed(fctx.filenode())
1698 o = fctx.filelog().renamed(fctx.filenode())
1699 rel = m.rel(abs)
1699 rel = m.rel(abs)
1700 if o:
1700 if o:
1701 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1701 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1702 else:
1702 else:
1703 ui.write(_("%s not renamed\n") % rel)
1703 ui.write(_("%s not renamed\n") % rel)
1704
1704
1705 def debugwalk(ui, repo, *pats, **opts):
1705 def debugwalk(ui, repo, *pats, **opts):
1706 """show how files match on given patterns"""
1706 """show how files match on given patterns"""
1707 m = cmdutil.match(repo, pats, opts)
1707 m = cmdutil.match(repo, pats, opts)
1708 items = list(repo.walk(m))
1708 items = list(repo.walk(m))
1709 if not items:
1709 if not items:
1710 return
1710 return
1711 fmt = 'f %%-%ds %%-%ds %%s' % (
1711 fmt = 'f %%-%ds %%-%ds %%s' % (
1712 max([len(abs) for abs in items]),
1712 max([len(abs) for abs in items]),
1713 max([len(m.rel(abs)) for abs in items]))
1713 max([len(m.rel(abs)) for abs in items]))
1714 for abs in items:
1714 for abs in items:
1715 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1715 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1716 ui.write("%s\n" % line.rstrip())
1716 ui.write("%s\n" % line.rstrip())
1717
1717
1718 def debugwireargs(ui, repopath, *vals, **opts):
1718 def debugwireargs(ui, repopath, *vals, **opts):
1719 repo = hg.repository(hg.remoteui(ui, opts), repopath)
1719 repo = hg.repository(hg.remoteui(ui, opts), repopath)
1720 for opt in remoteopts:
1720 for opt in remoteopts:
1721 del opts[opt[1]]
1721 del opts[opt[1]]
1722 args = {}
1722 args = {}
1723 for k, v in opts.iteritems():
1723 for k, v in opts.iteritems():
1724 if v:
1724 if v:
1725 args[k] = v
1725 args[k] = v
1726 # run twice to check that we don't mess up the stream for the next command
1726 # run twice to check that we don't mess up the stream for the next command
1727 res1 = repo.debugwireargs(*vals, **args)
1727 res1 = repo.debugwireargs(*vals, **args)
1728 res2 = repo.debugwireargs(*vals, **args)
1728 res2 = repo.debugwireargs(*vals, **args)
1729 ui.write("%s\n" % res1)
1729 ui.write("%s\n" % res1)
1730 if res1 != res2:
1730 if res1 != res2:
1731 ui.warn("%s\n" % res2)
1731 ui.warn("%s\n" % res2)
1732
1732
1733 def diff(ui, repo, *pats, **opts):
1733 def diff(ui, repo, *pats, **opts):
1734 """diff repository (or selected files)
1734 """diff repository (or selected files)
1735
1735
1736 Show differences between revisions for the specified files.
1736 Show differences between revisions for the specified files.
1737
1737
1738 Differences between files are shown using the unified diff format.
1738 Differences between files are shown using the unified diff format.
1739
1739
1740 .. note::
1740 .. note::
1741 diff may generate unexpected results for merges, as it will
1741 diff may generate unexpected results for merges, as it will
1742 default to comparing against the working directory's first
1742 default to comparing against the working directory's first
1743 parent changeset if no revisions are specified.
1743 parent changeset if no revisions are specified.
1744
1744
1745 When two revision arguments are given, then changes are shown
1745 When two revision arguments are given, then changes are shown
1746 between those revisions. If only one revision is specified then
1746 between those revisions. If only one revision is specified then
1747 that revision is compared to the working directory, and, when no
1747 that revision is compared to the working directory, and, when no
1748 revisions are specified, the working directory files are compared
1748 revisions are specified, the working directory files are compared
1749 to its parent.
1749 to its parent.
1750
1750
1751 Alternatively you can specify -c/--change with a revision to see
1751 Alternatively you can specify -c/--change with a revision to see
1752 the changes in that changeset relative to its first parent.
1752 the changes in that changeset relative to its first parent.
1753
1753
1754 Without the -a/--text option, diff will avoid generating diffs of
1754 Without the -a/--text option, diff will avoid generating diffs of
1755 files it detects as binary. With -a, diff will generate a diff
1755 files it detects as binary. With -a, diff will generate a diff
1756 anyway, probably with undesirable results.
1756 anyway, probably with undesirable results.
1757
1757
1758 Use the -g/--git option to generate diffs in the git extended diff
1758 Use the -g/--git option to generate diffs in the git extended diff
1759 format. For more information, read :hg:`help diffs`.
1759 format. For more information, read :hg:`help diffs`.
1760
1760
1761 Returns 0 on success.
1761 Returns 0 on success.
1762 """
1762 """
1763
1763
1764 revs = opts.get('rev')
1764 revs = opts.get('rev')
1765 change = opts.get('change')
1765 change = opts.get('change')
1766 stat = opts.get('stat')
1766 stat = opts.get('stat')
1767 reverse = opts.get('reverse')
1767 reverse = opts.get('reverse')
1768
1768
1769 if revs and change:
1769 if revs and change:
1770 msg = _('cannot specify --rev and --change at the same time')
1770 msg = _('cannot specify --rev and --change at the same time')
1771 raise util.Abort(msg)
1771 raise util.Abort(msg)
1772 elif change:
1772 elif change:
1773 node2 = cmdutil.revsingle(repo, change, None).node()
1773 node2 = cmdutil.revsingle(repo, change, None).node()
1774 node1 = repo[node2].p1().node()
1774 node1 = repo[node2].p1().node()
1775 else:
1775 else:
1776 node1, node2 = cmdutil.revpair(repo, revs)
1776 node1, node2 = cmdutil.revpair(repo, revs)
1777
1777
1778 if reverse:
1778 if reverse:
1779 node1, node2 = node2, node1
1779 node1, node2 = node2, node1
1780
1780
1781 diffopts = patch.diffopts(ui, opts)
1781 diffopts = patch.diffopts(ui, opts)
1782 m = cmdutil.match(repo, pats, opts)
1782 m = cmdutil.match(repo, pats, opts)
1783 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1783 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1784 listsubrepos=opts.get('subrepos'))
1784 listsubrepos=opts.get('subrepos'))
1785
1785
1786 def export(ui, repo, *changesets, **opts):
1786 def export(ui, repo, *changesets, **opts):
1787 """dump the header and diffs for one or more changesets
1787 """dump the header and diffs for one or more changesets
1788
1788
1789 Print the changeset header and diffs for one or more revisions.
1789 Print the changeset header and diffs for one or more revisions.
1790
1790
1791 The information shown in the changeset header is: author, date,
1791 The information shown in the changeset header is: author, date,
1792 branch name (if non-default), changeset hash, parent(s) and commit
1792 branch name (if non-default), changeset hash, parent(s) and commit
1793 comment.
1793 comment.
1794
1794
1795 .. note::
1795 .. note::
1796 export may generate unexpected diff output for merge
1796 export may generate unexpected diff output for merge
1797 changesets, as it will compare the merge changeset against its
1797 changesets, as it will compare the merge changeset against its
1798 first parent only.
1798 first parent only.
1799
1799
1800 Output may be to a file, in which case the name of the file is
1800 Output may be to a file, in which case the name of the file is
1801 given using a format string. The formatting rules are as follows:
1801 given using a format string. The formatting rules are as follows:
1802
1802
1803 :``%%``: literal "%" character
1803 :``%%``: literal "%" character
1804 :``%H``: changeset hash (40 hexadecimal digits)
1804 :``%H``: changeset hash (40 hexadecimal digits)
1805 :``%N``: number of patches being generated
1805 :``%N``: number of patches being generated
1806 :``%R``: changeset revision number
1806 :``%R``: changeset revision number
1807 :``%b``: basename of the exporting repository
1807 :``%b``: basename of the exporting repository
1808 :``%h``: short-form changeset hash (12 hexadecimal digits)
1808 :``%h``: short-form changeset hash (12 hexadecimal digits)
1809 :``%n``: zero-padded sequence number, starting at 1
1809 :``%n``: zero-padded sequence number, starting at 1
1810 :``%r``: zero-padded changeset revision number
1810 :``%r``: zero-padded changeset revision number
1811
1811
1812 Without the -a/--text option, export will avoid generating diffs
1812 Without the -a/--text option, export will avoid generating diffs
1813 of files it detects as binary. With -a, export will generate a
1813 of files it detects as binary. With -a, export will generate a
1814 diff anyway, probably with undesirable results.
1814 diff anyway, probably with undesirable results.
1815
1815
1816 Use the -g/--git option to generate diffs in the git extended diff
1816 Use the -g/--git option to generate diffs in the git extended diff
1817 format. See :hg:`help diffs` for more information.
1817 format. See :hg:`help diffs` for more information.
1818
1818
1819 With the --switch-parent option, the diff will be against the
1819 With the --switch-parent option, the diff will be against the
1820 second parent. It can be useful to review a merge.
1820 second parent. It can be useful to review a merge.
1821
1821
1822 Returns 0 on success.
1822 Returns 0 on success.
1823 """
1823 """
1824 changesets += tuple(opts.get('rev', []))
1824 changesets += tuple(opts.get('rev', []))
1825 if not changesets:
1825 if not changesets:
1826 raise util.Abort(_("export requires at least one changeset"))
1826 raise util.Abort(_("export requires at least one changeset"))
1827 revs = cmdutil.revrange(repo, changesets)
1827 revs = cmdutil.revrange(repo, changesets)
1828 if len(revs) > 1:
1828 if len(revs) > 1:
1829 ui.note(_('exporting patches:\n'))
1829 ui.note(_('exporting patches:\n'))
1830 else:
1830 else:
1831 ui.note(_('exporting patch:\n'))
1831 ui.note(_('exporting patch:\n'))
1832 cmdutil.export(repo, revs, template=opts.get('output'),
1832 cmdutil.export(repo, revs, template=opts.get('output'),
1833 switch_parent=opts.get('switch_parent'),
1833 switch_parent=opts.get('switch_parent'),
1834 opts=patch.diffopts(ui, opts))
1834 opts=patch.diffopts(ui, opts))
1835
1835
1836 def forget(ui, repo, *pats, **opts):
1836 def forget(ui, repo, *pats, **opts):
1837 """forget the specified files on the next commit
1837 """forget the specified files on the next commit
1838
1838
1839 Mark the specified files so they will no longer be tracked
1839 Mark the specified files so they will no longer be tracked
1840 after the next commit.
1840 after the next commit.
1841
1841
1842 This only removes files from the current branch, not from the
1842 This only removes files from the current branch, not from the
1843 entire project history, and it does not delete them from the
1843 entire project history, and it does not delete them from the
1844 working directory.
1844 working directory.
1845
1845
1846 To undo a forget before the next commit, see :hg:`add`.
1846 To undo a forget before the next commit, see :hg:`add`.
1847
1847
1848 Returns 0 on success.
1848 Returns 0 on success.
1849 """
1849 """
1850
1850
1851 if not pats:
1851 if not pats:
1852 raise util.Abort(_('no files specified'))
1852 raise util.Abort(_('no files specified'))
1853
1853
1854 m = cmdutil.match(repo, pats, opts)
1854 m = cmdutil.match(repo, pats, opts)
1855 s = repo.status(match=m, clean=True)
1855 s = repo.status(match=m, clean=True)
1856 forget = sorted(s[0] + s[1] + s[3] + s[6])
1856 forget = sorted(s[0] + s[1] + s[3] + s[6])
1857 errs = 0
1857 errs = 0
1858
1858
1859 for f in m.files():
1859 for f in m.files():
1860 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1860 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1861 ui.warn(_('not removing %s: file is already untracked\n')
1861 ui.warn(_('not removing %s: file is already untracked\n')
1862 % m.rel(f))
1862 % m.rel(f))
1863 errs = 1
1863 errs = 1
1864
1864
1865 for f in forget:
1865 for f in forget:
1866 if ui.verbose or not m.exact(f):
1866 if ui.verbose or not m.exact(f):
1867 ui.status(_('removing %s\n') % m.rel(f))
1867 ui.status(_('removing %s\n') % m.rel(f))
1868
1868
1869 repo[None].remove(forget, unlink=False)
1869 repo[None].remove(forget, unlink=False)
1870 return errs
1870 return errs
1871
1871
1872 def grep(ui, repo, pattern, *pats, **opts):
1872 def grep(ui, repo, pattern, *pats, **opts):
1873 """search for a pattern in specified files and revisions
1873 """search for a pattern in specified files and revisions
1874
1874
1875 Search revisions of files for a regular expression.
1875 Search revisions of files for a regular expression.
1876
1876
1877 This command behaves differently than Unix grep. It only accepts
1877 This command behaves differently than Unix grep. It only accepts
1878 Python/Perl regexps. It searches repository history, not the
1878 Python/Perl regexps. It searches repository history, not the
1879 working directory. It always prints the revision number in which a
1879 working directory. It always prints the revision number in which a
1880 match appears.
1880 match appears.
1881
1881
1882 By default, grep only prints output for the first revision of a
1882 By default, grep only prints output for the first revision of a
1883 file in which it finds a match. To get it to print every revision
1883 file in which it finds a match. To get it to print every revision
1884 that contains a change in match status ("-" for a match that
1884 that contains a change in match status ("-" for a match that
1885 becomes a non-match, or "+" for a non-match that becomes a match),
1885 becomes a non-match, or "+" for a non-match that becomes a match),
1886 use the --all flag.
1886 use the --all flag.
1887
1887
1888 Returns 0 if a match is found, 1 otherwise.
1888 Returns 0 if a match is found, 1 otherwise.
1889 """
1889 """
1890 reflags = 0
1890 reflags = 0
1891 if opts.get('ignore_case'):
1891 if opts.get('ignore_case'):
1892 reflags |= re.I
1892 reflags |= re.I
1893 try:
1893 try:
1894 regexp = re.compile(pattern, reflags)
1894 regexp = re.compile(pattern, reflags)
1895 except re.error, inst:
1895 except re.error, inst:
1896 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1896 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1897 return 1
1897 return 1
1898 sep, eol = ':', '\n'
1898 sep, eol = ':', '\n'
1899 if opts.get('print0'):
1899 if opts.get('print0'):
1900 sep = eol = '\0'
1900 sep = eol = '\0'
1901
1901
1902 getfile = util.lrucachefunc(repo.file)
1902 getfile = util.lrucachefunc(repo.file)
1903
1903
1904 def matchlines(body):
1904 def matchlines(body):
1905 begin = 0
1905 begin = 0
1906 linenum = 0
1906 linenum = 0
1907 while True:
1907 while True:
1908 match = regexp.search(body, begin)
1908 match = regexp.search(body, begin)
1909 if not match:
1909 if not match:
1910 break
1910 break
1911 mstart, mend = match.span()
1911 mstart, mend = match.span()
1912 linenum += body.count('\n', begin, mstart) + 1
1912 linenum += body.count('\n', begin, mstart) + 1
1913 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1913 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1914 begin = body.find('\n', mend) + 1 or len(body)
1914 begin = body.find('\n', mend) + 1 or len(body)
1915 lend = begin - 1
1915 lend = begin - 1
1916 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1916 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1917
1917
1918 class linestate(object):
1918 class linestate(object):
1919 def __init__(self, line, linenum, colstart, colend):
1919 def __init__(self, line, linenum, colstart, colend):
1920 self.line = line
1920 self.line = line
1921 self.linenum = linenum
1921 self.linenum = linenum
1922 self.colstart = colstart
1922 self.colstart = colstart
1923 self.colend = colend
1923 self.colend = colend
1924
1924
1925 def __hash__(self):
1925 def __hash__(self):
1926 return hash((self.linenum, self.line))
1926 return hash((self.linenum, self.line))
1927
1927
1928 def __eq__(self, other):
1928 def __eq__(self, other):
1929 return self.line == other.line
1929 return self.line == other.line
1930
1930
1931 matches = {}
1931 matches = {}
1932 copies = {}
1932 copies = {}
1933 def grepbody(fn, rev, body):
1933 def grepbody(fn, rev, body):
1934 matches[rev].setdefault(fn, [])
1934 matches[rev].setdefault(fn, [])
1935 m = matches[rev][fn]
1935 m = matches[rev][fn]
1936 for lnum, cstart, cend, line in matchlines(body):
1936 for lnum, cstart, cend, line in matchlines(body):
1937 s = linestate(line, lnum, cstart, cend)
1937 s = linestate(line, lnum, cstart, cend)
1938 m.append(s)
1938 m.append(s)
1939
1939
1940 def difflinestates(a, b):
1940 def difflinestates(a, b):
1941 sm = difflib.SequenceMatcher(None, a, b)
1941 sm = difflib.SequenceMatcher(None, a, b)
1942 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1942 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1943 if tag == 'insert':
1943 if tag == 'insert':
1944 for i in xrange(blo, bhi):
1944 for i in xrange(blo, bhi):
1945 yield ('+', b[i])
1945 yield ('+', b[i])
1946 elif tag == 'delete':
1946 elif tag == 'delete':
1947 for i in xrange(alo, ahi):
1947 for i in xrange(alo, ahi):
1948 yield ('-', a[i])
1948 yield ('-', a[i])
1949 elif tag == 'replace':
1949 elif tag == 'replace':
1950 for i in xrange(alo, ahi):
1950 for i in xrange(alo, ahi):
1951 yield ('-', a[i])
1951 yield ('-', a[i])
1952 for i in xrange(blo, bhi):
1952 for i in xrange(blo, bhi):
1953 yield ('+', b[i])
1953 yield ('+', b[i])
1954
1954
1955 def display(fn, ctx, pstates, states):
1955 def display(fn, ctx, pstates, states):
1956 rev = ctx.rev()
1956 rev = ctx.rev()
1957 datefunc = ui.quiet and util.shortdate or util.datestr
1957 datefunc = ui.quiet and util.shortdate or util.datestr
1958 found = False
1958 found = False
1959 filerevmatches = {}
1959 filerevmatches = {}
1960 def binary():
1960 def binary():
1961 flog = getfile(fn)
1961 flog = getfile(fn)
1962 return util.binary(flog.read(ctx.filenode(fn)))
1962 return util.binary(flog.read(ctx.filenode(fn)))
1963
1963
1964 if opts.get('all'):
1964 if opts.get('all'):
1965 iter = difflinestates(pstates, states)
1965 iter = difflinestates(pstates, states)
1966 else:
1966 else:
1967 iter = [('', l) for l in states]
1967 iter = [('', l) for l in states]
1968 for change, l in iter:
1968 for change, l in iter:
1969 cols = [fn, str(rev)]
1969 cols = [fn, str(rev)]
1970 before, match, after = None, None, None
1970 before, match, after = None, None, None
1971 if opts.get('line_number'):
1971 if opts.get('line_number'):
1972 cols.append(str(l.linenum))
1972 cols.append(str(l.linenum))
1973 if opts.get('all'):
1973 if opts.get('all'):
1974 cols.append(change)
1974 cols.append(change)
1975 if opts.get('user'):
1975 if opts.get('user'):
1976 cols.append(ui.shortuser(ctx.user()))
1976 cols.append(ui.shortuser(ctx.user()))
1977 if opts.get('date'):
1977 if opts.get('date'):
1978 cols.append(datefunc(ctx.date()))
1978 cols.append(datefunc(ctx.date()))
1979 if opts.get('files_with_matches'):
1979 if opts.get('files_with_matches'):
1980 c = (fn, rev)
1980 c = (fn, rev)
1981 if c in filerevmatches:
1981 if c in filerevmatches:
1982 continue
1982 continue
1983 filerevmatches[c] = 1
1983 filerevmatches[c] = 1
1984 else:
1984 else:
1985 before = l.line[:l.colstart]
1985 before = l.line[:l.colstart]
1986 match = l.line[l.colstart:l.colend]
1986 match = l.line[l.colstart:l.colend]
1987 after = l.line[l.colend:]
1987 after = l.line[l.colend:]
1988 ui.write(sep.join(cols))
1988 ui.write(sep.join(cols))
1989 if before is not None:
1989 if before is not None:
1990 if not opts.get('text') and binary():
1990 if not opts.get('text') and binary():
1991 ui.write(sep + " Binary file matches")
1991 ui.write(sep + " Binary file matches")
1992 else:
1992 else:
1993 ui.write(sep + before)
1993 ui.write(sep + before)
1994 ui.write(match, label='grep.match')
1994 ui.write(match, label='grep.match')
1995 ui.write(after)
1995 ui.write(after)
1996 ui.write(eol)
1996 ui.write(eol)
1997 found = True
1997 found = True
1998 return found
1998 return found
1999
1999
2000 skip = {}
2000 skip = {}
2001 revfiles = {}
2001 revfiles = {}
2002 matchfn = cmdutil.match(repo, pats, opts)
2002 matchfn = cmdutil.match(repo, pats, opts)
2003 found = False
2003 found = False
2004 follow = opts.get('follow')
2004 follow = opts.get('follow')
2005
2005
2006 def prep(ctx, fns):
2006 def prep(ctx, fns):
2007 rev = ctx.rev()
2007 rev = ctx.rev()
2008 pctx = ctx.p1()
2008 pctx = ctx.p1()
2009 parent = pctx.rev()
2009 parent = pctx.rev()
2010 matches.setdefault(rev, {})
2010 matches.setdefault(rev, {})
2011 matches.setdefault(parent, {})
2011 matches.setdefault(parent, {})
2012 files = revfiles.setdefault(rev, [])
2012 files = revfiles.setdefault(rev, [])
2013 for fn in fns:
2013 for fn in fns:
2014 flog = getfile(fn)
2014 flog = getfile(fn)
2015 try:
2015 try:
2016 fnode = ctx.filenode(fn)
2016 fnode = ctx.filenode(fn)
2017 except error.LookupError:
2017 except error.LookupError:
2018 continue
2018 continue
2019
2019
2020 copied = flog.renamed(fnode)
2020 copied = flog.renamed(fnode)
2021 copy = follow and copied and copied[0]
2021 copy = follow and copied and copied[0]
2022 if copy:
2022 if copy:
2023 copies.setdefault(rev, {})[fn] = copy
2023 copies.setdefault(rev, {})[fn] = copy
2024 if fn in skip:
2024 if fn in skip:
2025 if copy:
2025 if copy:
2026 skip[copy] = True
2026 skip[copy] = True
2027 continue
2027 continue
2028 files.append(fn)
2028 files.append(fn)
2029
2029
2030 if fn not in matches[rev]:
2030 if fn not in matches[rev]:
2031 grepbody(fn, rev, flog.read(fnode))
2031 grepbody(fn, rev, flog.read(fnode))
2032
2032
2033 pfn = copy or fn
2033 pfn = copy or fn
2034 if pfn not in matches[parent]:
2034 if pfn not in matches[parent]:
2035 try:
2035 try:
2036 fnode = pctx.filenode(pfn)
2036 fnode = pctx.filenode(pfn)
2037 grepbody(pfn, parent, flog.read(fnode))
2037 grepbody(pfn, parent, flog.read(fnode))
2038 except error.LookupError:
2038 except error.LookupError:
2039 pass
2039 pass
2040
2040
2041 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2041 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2042 rev = ctx.rev()
2042 rev = ctx.rev()
2043 parent = ctx.p1().rev()
2043 parent = ctx.p1().rev()
2044 for fn in sorted(revfiles.get(rev, [])):
2044 for fn in sorted(revfiles.get(rev, [])):
2045 states = matches[rev][fn]
2045 states = matches[rev][fn]
2046 copy = copies.get(rev, {}).get(fn)
2046 copy = copies.get(rev, {}).get(fn)
2047 if fn in skip:
2047 if fn in skip:
2048 if copy:
2048 if copy:
2049 skip[copy] = True
2049 skip[copy] = True
2050 continue
2050 continue
2051 pstates = matches.get(parent, {}).get(copy or fn, [])
2051 pstates = matches.get(parent, {}).get(copy or fn, [])
2052 if pstates or states:
2052 if pstates or states:
2053 r = display(fn, ctx, pstates, states)
2053 r = display(fn, ctx, pstates, states)
2054 found = found or r
2054 found = found or r
2055 if r and not opts.get('all'):
2055 if r and not opts.get('all'):
2056 skip[fn] = True
2056 skip[fn] = True
2057 if copy:
2057 if copy:
2058 skip[copy] = True
2058 skip[copy] = True
2059 del matches[rev]
2059 del matches[rev]
2060 del revfiles[rev]
2060 del revfiles[rev]
2061
2061
2062 return not found
2062 return not found
2063
2063
2064 def heads(ui, repo, *branchrevs, **opts):
2064 def heads(ui, repo, *branchrevs, **opts):
2065 """show current repository heads or show branch heads
2065 """show current repository heads or show branch heads
2066
2066
2067 With no arguments, show all repository branch heads.
2067 With no arguments, show all repository branch heads.
2068
2068
2069 Repository "heads" are changesets with no child changesets. They are
2069 Repository "heads" are changesets with no child changesets. They are
2070 where development generally takes place and are the usual targets
2070 where development generally takes place and are the usual targets
2071 for update and merge operations. Branch heads are changesets that have
2071 for update and merge operations. Branch heads are changesets that have
2072 no child changeset on the same branch.
2072 no child changeset on the same branch.
2073
2073
2074 If one or more REVs are given, only branch heads on the branches
2074 If one or more REVs are given, only branch heads on the branches
2075 associated with the specified changesets are shown.
2075 associated with the specified changesets are shown.
2076
2076
2077 If -c/--closed is specified, also show branch heads marked closed
2077 If -c/--closed is specified, also show branch heads marked closed
2078 (see :hg:`commit --close-branch`).
2078 (see :hg:`commit --close-branch`).
2079
2079
2080 If STARTREV is specified, only those heads that are descendants of
2080 If STARTREV is specified, only those heads that are descendants of
2081 STARTREV will be displayed.
2081 STARTREV will be displayed.
2082
2082
2083 If -t/--topo is specified, named branch mechanics will be ignored and only
2083 If -t/--topo is specified, named branch mechanics will be ignored and only
2084 changesets without children will be shown.
2084 changesets without children will be shown.
2085
2085
2086 Returns 0 if matching heads are found, 1 if not.
2086 Returns 0 if matching heads are found, 1 if not.
2087 """
2087 """
2088
2088
2089 start = None
2089 start = None
2090 if 'rev' in opts:
2090 if 'rev' in opts:
2091 start = cmdutil.revsingle(repo, opts['rev'], None).node()
2091 start = cmdutil.revsingle(repo, opts['rev'], None).node()
2092
2092
2093 if opts.get('topo'):
2093 if opts.get('topo'):
2094 heads = [repo[h] for h in repo.heads(start)]
2094 heads = [repo[h] for h in repo.heads(start)]
2095 else:
2095 else:
2096 heads = []
2096 heads = []
2097 for b, ls in repo.branchmap().iteritems():
2097 for b, ls in repo.branchmap().iteritems():
2098 if start is None:
2098 if start is None:
2099 heads += [repo[h] for h in ls]
2099 heads += [repo[h] for h in ls]
2100 continue
2100 continue
2101 startrev = repo.changelog.rev(start)
2101 startrev = repo.changelog.rev(start)
2102 descendants = set(repo.changelog.descendants(startrev))
2102 descendants = set(repo.changelog.descendants(startrev))
2103 descendants.add(startrev)
2103 descendants.add(startrev)
2104 rev = repo.changelog.rev
2104 rev = repo.changelog.rev
2105 heads += [repo[h] for h in ls if rev(h) in descendants]
2105 heads += [repo[h] for h in ls if rev(h) in descendants]
2106
2106
2107 if branchrevs:
2107 if branchrevs:
2108 branches = set(repo[br].branch() for br in branchrevs)
2108 branches = set(repo[br].branch() for br in branchrevs)
2109 heads = [h for h in heads if h.branch() in branches]
2109 heads = [h for h in heads if h.branch() in branches]
2110
2110
2111 if not opts.get('closed'):
2111 if not opts.get('closed'):
2112 heads = [h for h in heads if not h.extra().get('close')]
2112 heads = [h for h in heads if not h.extra().get('close')]
2113
2113
2114 if opts.get('active') and branchrevs:
2114 if opts.get('active') and branchrevs:
2115 dagheads = repo.heads(start)
2115 dagheads = repo.heads(start)
2116 heads = [h for h in heads if h.node() in dagheads]
2116 heads = [h for h in heads if h.node() in dagheads]
2117
2117
2118 if branchrevs:
2118 if branchrevs:
2119 haveheads = set(h.branch() for h in heads)
2119 haveheads = set(h.branch() for h in heads)
2120 if branches - haveheads:
2120 if branches - haveheads:
2121 headless = ', '.join(b for b in branches - haveheads)
2121 headless = ', '.join(b for b in branches - haveheads)
2122 msg = _('no open branch heads found on branches %s')
2122 msg = _('no open branch heads found on branches %s')
2123 if opts.get('rev'):
2123 if opts.get('rev'):
2124 msg += _(' (started at %s)' % opts['rev'])
2124 msg += _(' (started at %s)' % opts['rev'])
2125 ui.warn((msg + '\n') % headless)
2125 ui.warn((msg + '\n') % headless)
2126
2126
2127 if not heads:
2127 if not heads:
2128 return 1
2128 return 1
2129
2129
2130 heads = sorted(heads, key=lambda x: -x.rev())
2130 heads = sorted(heads, key=lambda x: -x.rev())
2131 displayer = cmdutil.show_changeset(ui, repo, opts)
2131 displayer = cmdutil.show_changeset(ui, repo, opts)
2132 for ctx in heads:
2132 for ctx in heads:
2133 displayer.show(ctx)
2133 displayer.show(ctx)
2134 displayer.close()
2134 displayer.close()
2135
2135
2136 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True, **opts):
2136 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True, **opts):
2137 """show help for a given topic or a help overview
2137 """show help for a given topic or a help overview
2138
2138
2139 With no arguments, print a list of commands with short help messages.
2139 With no arguments, print a list of commands with short help messages.
2140
2140
2141 Given a topic, extension, or command name, print help for that
2141 Given a topic, extension, or command name, print help for that
2142 topic.
2142 topic.
2143
2143
2144 Returns 0 if successful.
2144 Returns 0 if successful.
2145 """
2145 """
2146 option_lists = []
2146 option_lists = []
2147 textwidth = min(ui.termwidth(), 80) - 2
2147 textwidth = min(ui.termwidth(), 80) - 2
2148
2148
2149 def addglobalopts(aliases):
2149 def addglobalopts(aliases):
2150 if ui.verbose:
2150 if ui.verbose:
2151 option_lists.append((_("global options:"), globalopts))
2151 option_lists.append((_("global options:"), globalopts))
2152 if name == 'shortlist':
2152 if name == 'shortlist':
2153 option_lists.append((_('use "hg help" for the full list '
2153 option_lists.append((_('use "hg help" for the full list '
2154 'of commands'), ()))
2154 'of commands'), ()))
2155 else:
2155 else:
2156 if name == 'shortlist':
2156 if name == 'shortlist':
2157 msg = _('use "hg help" for the full list of commands '
2157 msg = _('use "hg help" for the full list of commands '
2158 'or "hg -v" for details')
2158 'or "hg -v" for details')
2159 elif name and not full:
2159 elif name and not full:
2160 msg = _('use "hg help %s" to show the full help text' % name)
2160 msg = _('use "hg help %s" to show the full help text' % name)
2161 elif aliases:
2161 elif aliases:
2162 msg = _('use "hg -v help%s" to show builtin aliases and '
2162 msg = _('use "hg -v help%s" to show builtin aliases and '
2163 'global options') % (name and " " + name or "")
2163 'global options') % (name and " " + name or "")
2164 else:
2164 else:
2165 msg = _('use "hg -v help %s" to show global options') % name
2165 msg = _('use "hg -v help %s" to show global options') % name
2166 option_lists.append((msg, ()))
2166 option_lists.append((msg, ()))
2167
2167
2168 def helpcmd(name):
2168 def helpcmd(name):
2169 if with_version:
2169 if with_version:
2170 version_(ui)
2170 version_(ui)
2171 ui.write('\n')
2171 ui.write('\n')
2172
2172
2173 try:
2173 try:
2174 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2174 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2175 except error.AmbiguousCommand, inst:
2175 except error.AmbiguousCommand, inst:
2176 # py3k fix: except vars can't be used outside the scope of the
2176 # py3k fix: except vars can't be used outside the scope of the
2177 # except block, nor can be used inside a lambda. python issue4617
2177 # except block, nor can be used inside a lambda. python issue4617
2178 prefix = inst.args[0]
2178 prefix = inst.args[0]
2179 select = lambda c: c.lstrip('^').startswith(prefix)
2179 select = lambda c: c.lstrip('^').startswith(prefix)
2180 helplist(_('list of commands:\n\n'), select)
2180 helplist(_('list of commands:\n\n'), select)
2181 return
2181 return
2182
2182
2183 # check if it's an invalid alias and display its error if it is
2183 # check if it's an invalid alias and display its error if it is
2184 if getattr(entry[0], 'badalias', False):
2184 if getattr(entry[0], 'badalias', False):
2185 if not unknowncmd:
2185 if not unknowncmd:
2186 entry[0](ui)
2186 entry[0](ui)
2187 return
2187 return
2188
2188
2189 # synopsis
2189 # synopsis
2190 if len(entry) > 2:
2190 if len(entry) > 2:
2191 if entry[2].startswith('hg'):
2191 if entry[2].startswith('hg'):
2192 ui.write("%s\n" % entry[2])
2192 ui.write("%s\n" % entry[2])
2193 else:
2193 else:
2194 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2194 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2195 else:
2195 else:
2196 ui.write('hg %s\n' % aliases[0])
2196 ui.write('hg %s\n' % aliases[0])
2197
2197
2198 # aliases
2198 # aliases
2199 if full and not ui.quiet and len(aliases) > 1:
2199 if full and not ui.quiet and len(aliases) > 1:
2200 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2200 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2201
2201
2202 # description
2202 # description
2203 doc = gettext(entry[0].__doc__)
2203 doc = gettext(entry[0].__doc__)
2204 if not doc:
2204 if not doc:
2205 doc = _("(no help text available)")
2205 doc = _("(no help text available)")
2206 if hasattr(entry[0], 'definition'): # aliased command
2206 if hasattr(entry[0], 'definition'): # aliased command
2207 if entry[0].definition.startswith('!'): # shell alias
2207 if entry[0].definition.startswith('!'): # shell alias
2208 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2208 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2209 else:
2209 else:
2210 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2210 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2211 if ui.quiet or not full:
2211 if ui.quiet or not full:
2212 doc = doc.splitlines()[0]
2212 doc = doc.splitlines()[0]
2213 keep = ui.verbose and ['verbose'] or []
2213 keep = ui.verbose and ['verbose'] or []
2214 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2214 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2215 ui.write("\n%s\n" % formatted)
2215 ui.write("\n%s\n" % formatted)
2216 if pruned:
2216 if pruned:
2217 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2217 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2218
2218
2219 if not ui.quiet:
2219 if not ui.quiet:
2220 # options
2220 # options
2221 if entry[1]:
2221 if entry[1]:
2222 option_lists.append((_("options:\n"), entry[1]))
2222 option_lists.append((_("options:\n"), entry[1]))
2223
2223
2224 addglobalopts(False)
2224 addglobalopts(False)
2225
2225
2226 # check if this command shadows a non-trivial (multi-line)
2226 # check if this command shadows a non-trivial (multi-line)
2227 # extension help text
2227 # extension help text
2228 try:
2228 try:
2229 mod = extensions.find(name)
2229 mod = extensions.find(name)
2230 doc = gettext(mod.__doc__) or ''
2230 doc = gettext(mod.__doc__) or ''
2231 if '\n' in doc.strip():
2231 if '\n' in doc.strip():
2232 msg = _('use "hg help -e %s" to show help for '
2232 msg = _('use "hg help -e %s" to show help for '
2233 'the %s extension') % (name, name)
2233 'the %s extension') % (name, name)
2234 ui.write('\n%s\n' % msg)
2234 ui.write('\n%s\n' % msg)
2235 except KeyError:
2235 except KeyError:
2236 pass
2236 pass
2237
2237
2238 def helplist(header, select=None):
2238 def helplist(header, select=None):
2239 h = {}
2239 h = {}
2240 cmds = {}
2240 cmds = {}
2241 for c, e in table.iteritems():
2241 for c, e in table.iteritems():
2242 f = c.split("|", 1)[0]
2242 f = c.split("|", 1)[0]
2243 if select and not select(f):
2243 if select and not select(f):
2244 continue
2244 continue
2245 if (not select and name != 'shortlist' and
2245 if (not select and name != 'shortlist' and
2246 e[0].__module__ != __name__):
2246 e[0].__module__ != __name__):
2247 continue
2247 continue
2248 if name == "shortlist" and not f.startswith("^"):
2248 if name == "shortlist" and not f.startswith("^"):
2249 continue
2249 continue
2250 f = f.lstrip("^")
2250 f = f.lstrip("^")
2251 if not ui.debugflag and f.startswith("debug"):
2251 if not ui.debugflag and f.startswith("debug"):
2252 continue
2252 continue
2253 doc = e[0].__doc__
2253 doc = e[0].__doc__
2254 if doc and 'DEPRECATED' in doc and not ui.verbose:
2254 if doc and 'DEPRECATED' in doc and not ui.verbose:
2255 continue
2255 continue
2256 doc = gettext(doc)
2256 doc = gettext(doc)
2257 if not doc:
2257 if not doc:
2258 doc = _("(no help text available)")
2258 doc = _("(no help text available)")
2259 h[f] = doc.splitlines()[0].rstrip()
2259 h[f] = doc.splitlines()[0].rstrip()
2260 cmds[f] = c.lstrip("^")
2260 cmds[f] = c.lstrip("^")
2261
2261
2262 if not h:
2262 if not h:
2263 ui.status(_('no commands defined\n'))
2263 ui.status(_('no commands defined\n'))
2264 return
2264 return
2265
2265
2266 ui.status(header)
2266 ui.status(header)
2267 fns = sorted(h)
2267 fns = sorted(h)
2268 m = max(map(len, fns))
2268 m = max(map(len, fns))
2269 for f in fns:
2269 for f in fns:
2270 if ui.verbose:
2270 if ui.verbose:
2271 commands = cmds[f].replace("|",", ")
2271 commands = cmds[f].replace("|",", ")
2272 ui.write(" %s:\n %s\n"%(commands, h[f]))
2272 ui.write(" %s:\n %s\n"%(commands, h[f]))
2273 else:
2273 else:
2274 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2274 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2275 initindent=' %-*s ' % (m, f),
2275 initindent=' %-*s ' % (m, f),
2276 hangindent=' ' * (m + 4))))
2276 hangindent=' ' * (m + 4))))
2277
2277
2278 if not ui.quiet:
2278 if not ui.quiet:
2279 addglobalopts(True)
2279 addglobalopts(True)
2280
2280
2281 def helptopic(name):
2281 def helptopic(name):
2282 for names, header, doc in help.helptable:
2282 for names, header, doc in help.helptable:
2283 if name in names:
2283 if name in names:
2284 break
2284 break
2285 else:
2285 else:
2286 raise error.UnknownCommand(name)
2286 raise error.UnknownCommand(name)
2287
2287
2288 # description
2288 # description
2289 if not doc:
2289 if not doc:
2290 doc = _("(no help text available)")
2290 doc = _("(no help text available)")
2291 if hasattr(doc, '__call__'):
2291 if hasattr(doc, '__call__'):
2292 doc = doc()
2292 doc = doc()
2293
2293
2294 ui.write("%s\n\n" % header)
2294 ui.write("%s\n\n" % header)
2295 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2295 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2296 try:
2296 try:
2297 cmdutil.findcmd(name, table)
2297 cmdutil.findcmd(name, table)
2298 ui.write(_('\nuse "hg help -c %s" to see help for '
2298 ui.write(_('\nuse "hg help -c %s" to see help for '
2299 'the %s command\n') % (name, name))
2299 'the %s command\n') % (name, name))
2300 except error.UnknownCommand:
2300 except error.UnknownCommand:
2301 pass
2301 pass
2302
2302
2303 def helpext(name):
2303 def helpext(name):
2304 try:
2304 try:
2305 mod = extensions.find(name)
2305 mod = extensions.find(name)
2306 doc = gettext(mod.__doc__) or _('no help text available')
2306 doc = gettext(mod.__doc__) or _('no help text available')
2307 except KeyError:
2307 except KeyError:
2308 mod = None
2308 mod = None
2309 doc = extensions.disabledext(name)
2309 doc = extensions.disabledext(name)
2310 if not doc:
2310 if not doc:
2311 raise error.UnknownCommand(name)
2311 raise error.UnknownCommand(name)
2312
2312
2313 if '\n' not in doc:
2313 if '\n' not in doc:
2314 head, tail = doc, ""
2314 head, tail = doc, ""
2315 else:
2315 else:
2316 head, tail = doc.split('\n', 1)
2316 head, tail = doc.split('\n', 1)
2317 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2317 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2318 if tail:
2318 if tail:
2319 ui.write(minirst.format(tail, textwidth))
2319 ui.write(minirst.format(tail, textwidth))
2320 ui.status('\n\n')
2320 ui.status('\n\n')
2321
2321
2322 if mod:
2322 if mod:
2323 try:
2323 try:
2324 ct = mod.cmdtable
2324 ct = mod.cmdtable
2325 except AttributeError:
2325 except AttributeError:
2326 ct = {}
2326 ct = {}
2327 modcmds = set([c.split('|', 1)[0] for c in ct])
2327 modcmds = set([c.split('|', 1)[0] for c in ct])
2328 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2328 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2329 else:
2329 else:
2330 ui.write(_('use "hg help extensions" for information on enabling '
2330 ui.write(_('use "hg help extensions" for information on enabling '
2331 'extensions\n'))
2331 'extensions\n'))
2332
2332
2333 def helpextcmd(name):
2333 def helpextcmd(name):
2334 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2334 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2335 doc = gettext(mod.__doc__).splitlines()[0]
2335 doc = gettext(mod.__doc__).splitlines()[0]
2336
2336
2337 msg = help.listexts(_("'%s' is provided by the following "
2337 msg = help.listexts(_("'%s' is provided by the following "
2338 "extension:") % cmd, {ext: doc}, len(ext),
2338 "extension:") % cmd, {ext: doc}, len(ext),
2339 indent=4)
2339 indent=4)
2340 ui.write(minirst.format(msg, textwidth))
2340 ui.write(minirst.format(msg, textwidth))
2341 ui.write('\n\n')
2341 ui.write('\n\n')
2342 ui.write(_('use "hg help extensions" for information on enabling '
2342 ui.write(_('use "hg help extensions" for information on enabling '
2343 'extensions\n'))
2343 'extensions\n'))
2344
2344
2345 help.addtopichook('revsets', revset.makedoc)
2345 help.addtopichook('revsets', revset.makedoc)
2346 help.addtopichook('templates', templatekw.makedoc)
2346 help.addtopichook('templates', templatekw.makedoc)
2347 help.addtopichook('templates', templatefilters.makedoc)
2347 help.addtopichook('templates', templatefilters.makedoc)
2348
2348
2349 if name and name != 'shortlist':
2349 if name and name != 'shortlist':
2350 i = None
2350 i = None
2351 if unknowncmd:
2351 if unknowncmd:
2352 queries = (helpextcmd,)
2352 queries = (helpextcmd,)
2353 elif opts.get('extension'):
2353 elif opts.get('extension'):
2354 queries = (helpext,)
2354 queries = (helpext,)
2355 elif opts.get('command'):
2355 elif opts.get('command'):
2356 queries = (helpcmd,)
2356 queries = (helpcmd,)
2357 else:
2357 else:
2358 queries = (helptopic, helpcmd, helpext, helpextcmd)
2358 queries = (helptopic, helpcmd, helpext, helpextcmd)
2359 for f in queries:
2359 for f in queries:
2360 try:
2360 try:
2361 f(name)
2361 f(name)
2362 i = None
2362 i = None
2363 break
2363 break
2364 except error.UnknownCommand, inst:
2364 except error.UnknownCommand, inst:
2365 i = inst
2365 i = inst
2366 if i:
2366 if i:
2367 raise i
2367 raise i
2368
2368
2369 else:
2369 else:
2370 # program name
2370 # program name
2371 if ui.verbose or with_version:
2371 if ui.verbose or with_version:
2372 version_(ui)
2372 version_(ui)
2373 else:
2373 else:
2374 ui.status(_("Mercurial Distributed SCM\n"))
2374 ui.status(_("Mercurial Distributed SCM\n"))
2375 ui.status('\n')
2375 ui.status('\n')
2376
2376
2377 # list of commands
2377 # list of commands
2378 if name == "shortlist":
2378 if name == "shortlist":
2379 header = _('basic commands:\n\n')
2379 header = _('basic commands:\n\n')
2380 else:
2380 else:
2381 header = _('list of commands:\n\n')
2381 header = _('list of commands:\n\n')
2382
2382
2383 helplist(header)
2383 helplist(header)
2384 if name != 'shortlist':
2384 if name != 'shortlist':
2385 exts, maxlength = extensions.enabled()
2385 exts, maxlength = extensions.enabled()
2386 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2386 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2387 if text:
2387 if text:
2388 ui.write("\n%s\n" % minirst.format(text, textwidth))
2388 ui.write("\n%s\n" % minirst.format(text, textwidth))
2389
2389
2390 # list all option lists
2390 # list all option lists
2391 opt_output = []
2391 opt_output = []
2392 multioccur = False
2392 multioccur = False
2393 for title, options in option_lists:
2393 for title, options in option_lists:
2394 opt_output.append(("\n%s" % title, None))
2394 opt_output.append(("\n%s" % title, None))
2395 for option in options:
2395 for option in options:
2396 if len(option) == 5:
2396 if len(option) == 5:
2397 shortopt, longopt, default, desc, optlabel = option
2397 shortopt, longopt, default, desc, optlabel = option
2398 else:
2398 else:
2399 shortopt, longopt, default, desc = option
2399 shortopt, longopt, default, desc = option
2400 optlabel = _("VALUE") # default label
2400 optlabel = _("VALUE") # default label
2401
2401
2402 if _("DEPRECATED") in desc and not ui.verbose:
2402 if _("DEPRECATED") in desc and not ui.verbose:
2403 continue
2403 continue
2404 if isinstance(default, list):
2404 if isinstance(default, list):
2405 numqualifier = " %s [+]" % optlabel
2405 numqualifier = " %s [+]" % optlabel
2406 multioccur = True
2406 multioccur = True
2407 elif (default is not None) and not isinstance(default, bool):
2407 elif (default is not None) and not isinstance(default, bool):
2408 numqualifier = " %s" % optlabel
2408 numqualifier = " %s" % optlabel
2409 else:
2409 else:
2410 numqualifier = ""
2410 numqualifier = ""
2411 opt_output.append(("%2s%s" %
2411 opt_output.append(("%2s%s" %
2412 (shortopt and "-%s" % shortopt,
2412 (shortopt and "-%s" % shortopt,
2413 longopt and " --%s%s" %
2413 longopt and " --%s%s" %
2414 (longopt, numqualifier)),
2414 (longopt, numqualifier)),
2415 "%s%s" % (desc,
2415 "%s%s" % (desc,
2416 default
2416 default
2417 and _(" (default: %s)") % default
2417 and _(" (default: %s)") % default
2418 or "")))
2418 or "")))
2419 if multioccur:
2419 if multioccur:
2420 msg = _("\n[+] marked option can be specified multiple times")
2420 msg = _("\n[+] marked option can be specified multiple times")
2421 if ui.verbose and name != 'shortlist':
2421 if ui.verbose and name != 'shortlist':
2422 opt_output.append((msg, None))
2422 opt_output.append((msg, None))
2423 else:
2423 else:
2424 opt_output.insert(-1, (msg, None))
2424 opt_output.insert(-1, (msg, None))
2425
2425
2426 if not name:
2426 if not name:
2427 ui.write(_("\nadditional help topics:\n\n"))
2427 ui.write(_("\nadditional help topics:\n\n"))
2428 topics = []
2428 topics = []
2429 for names, header, doc in help.helptable:
2429 for names, header, doc in help.helptable:
2430 topics.append((sorted(names, key=len, reverse=True)[0], header))
2430 topics.append((sorted(names, key=len, reverse=True)[0], header))
2431 topics_len = max([len(s[0]) for s in topics])
2431 topics_len = max([len(s[0]) for s in topics])
2432 for t, desc in topics:
2432 for t, desc in topics:
2433 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2433 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2434
2434
2435 if opt_output:
2435 if opt_output:
2436 colwidth = encoding.colwidth
2436 colwidth = encoding.colwidth
2437 # normalize: (opt or message, desc or None, width of opt)
2437 # normalize: (opt or message, desc or None, width of opt)
2438 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2438 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2439 for opt, desc in opt_output]
2439 for opt, desc in opt_output]
2440 hanging = max([e[2] for e in entries])
2440 hanging = max([e[2] for e in entries])
2441 for opt, desc, width in entries:
2441 for opt, desc, width in entries:
2442 if desc:
2442 if desc:
2443 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2443 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2444 hangindent = ' ' * (hanging + 3)
2444 hangindent = ' ' * (hanging + 3)
2445 ui.write('%s\n' % (util.wrap(desc, textwidth,
2445 ui.write('%s\n' % (util.wrap(desc, textwidth,
2446 initindent=initindent,
2446 initindent=initindent,
2447 hangindent=hangindent)))
2447 hangindent=hangindent)))
2448 else:
2448 else:
2449 ui.write("%s\n" % opt)
2449 ui.write("%s\n" % opt)
2450
2450
2451 def identify(ui, repo, source=None, rev=None,
2451 def identify(ui, repo, source=None, rev=None,
2452 num=None, id=None, branch=None, tags=None, bookmarks=None):
2452 num=None, id=None, branch=None, tags=None, bookmarks=None):
2453 """identify the working copy or specified revision
2453 """identify the working copy or specified revision
2454
2454
2455 Print a summary identifying the repository state at REV using one or
2455 Print a summary identifying the repository state at REV using one or
2456 two parent hash identifiers, followed by a "+" if the working
2456 two parent hash identifiers, followed by a "+" if the working
2457 directory has uncommitted changes, the branch name (if not default),
2457 directory has uncommitted changes, the branch name (if not default),
2458 a list of tags, and a list of bookmarks.
2458 a list of tags, and a list of bookmarks.
2459
2459
2460 When REV is not given, print a summary of the current state of the
2460 When REV is not given, print a summary of the current state of the
2461 repository.
2461 repository.
2462
2462
2463 Specifying a path to a repository root or Mercurial bundle will
2463 Specifying a path to a repository root or Mercurial bundle will
2464 cause lookup to operate on that repository/bundle.
2464 cause lookup to operate on that repository/bundle.
2465
2465
2466 Returns 0 if successful.
2466 Returns 0 if successful.
2467 """
2467 """
2468
2468
2469 if not repo and not source:
2469 if not repo and not source:
2470 raise util.Abort(_("there is no Mercurial repository here "
2470 raise util.Abort(_("there is no Mercurial repository here "
2471 "(.hg not found)"))
2471 "(.hg not found)"))
2472
2472
2473 hexfunc = ui.debugflag and hex or short
2473 hexfunc = ui.debugflag and hex or short
2474 default = not (num or id or branch or tags or bookmarks)
2474 default = not (num or id or branch or tags or bookmarks)
2475 output = []
2475 output = []
2476 revs = []
2476 revs = []
2477
2477
2478 if source:
2478 if source:
2479 source, branches = hg.parseurl(ui.expandpath(source))
2479 source, branches = hg.parseurl(ui.expandpath(source))
2480 repo = hg.repository(ui, source)
2480 repo = hg.repository(ui, source)
2481 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2481 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2482
2482
2483 if not repo.local():
2483 if not repo.local():
2484 if num or branch or tags:
2484 if num or branch or tags:
2485 raise util.Abort(
2485 raise util.Abort(
2486 _("can't query remote revision number, branch, or tags"))
2486 _("can't query remote revision number, branch, or tags"))
2487 if not rev and revs:
2487 if not rev and revs:
2488 rev = revs[0]
2488 rev = revs[0]
2489 if not rev:
2489 if not rev:
2490 rev = "tip"
2490 rev = "tip"
2491
2491
2492 remoterev = repo.lookup(rev)
2492 remoterev = repo.lookup(rev)
2493 if default or id:
2493 if default or id:
2494 output = [hexfunc(remoterev)]
2494 output = [hexfunc(remoterev)]
2495
2495
2496 def getbms():
2496 def getbms():
2497 bms = []
2497 bms = []
2498
2498
2499 if 'bookmarks' in repo.listkeys('namespaces'):
2499 if 'bookmarks' in repo.listkeys('namespaces'):
2500 hexremoterev = hex(remoterev)
2500 hexremoterev = hex(remoterev)
2501 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2501 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2502 if bmr == hexremoterev]
2502 if bmr == hexremoterev]
2503
2503
2504 return bms
2504 return bms
2505
2505
2506 if bookmarks:
2506 if bookmarks:
2507 output.extend(getbms())
2507 output.extend(getbms())
2508 elif default and not ui.quiet:
2508 elif default and not ui.quiet:
2509 # multiple bookmarks for a single parent separated by '/'
2509 # multiple bookmarks for a single parent separated by '/'
2510 bm = '/'.join(getbms())
2510 bm = '/'.join(getbms())
2511 if bm:
2511 if bm:
2512 output.append(bm)
2512 output.append(bm)
2513 else:
2513 else:
2514 if not rev:
2514 if not rev:
2515 ctx = repo[None]
2515 ctx = repo[None]
2516 parents = ctx.parents()
2516 parents = ctx.parents()
2517 changed = ""
2517 changed = ""
2518 if default or id or num:
2518 if default or id or num:
2519 changed = util.any(repo.status()) and "+" or ""
2519 changed = util.any(repo.status()) and "+" or ""
2520 if default or id:
2520 if default or id:
2521 output = ["%s%s" %
2521 output = ["%s%s" %
2522 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2522 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2523 if num:
2523 if num:
2524 output.append("%s%s" %
2524 output.append("%s%s" %
2525 ('+'.join([str(p.rev()) for p in parents]), changed))
2525 ('+'.join([str(p.rev()) for p in parents]), changed))
2526 else:
2526 else:
2527 ctx = cmdutil.revsingle(repo, rev)
2527 ctx = cmdutil.revsingle(repo, rev)
2528 if default or id:
2528 if default or id:
2529 output = [hexfunc(ctx.node())]
2529 output = [hexfunc(ctx.node())]
2530 if num:
2530 if num:
2531 output.append(str(ctx.rev()))
2531 output.append(str(ctx.rev()))
2532
2532
2533 if default and not ui.quiet:
2533 if default and not ui.quiet:
2534 b = ctx.branch()
2534 b = ctx.branch()
2535 if b != 'default':
2535 if b != 'default':
2536 output.append("(%s)" % b)
2536 output.append("(%s)" % b)
2537
2537
2538 # multiple tags for a single parent separated by '/'
2538 # multiple tags for a single parent separated by '/'
2539 t = '/'.join(ctx.tags())
2539 t = '/'.join(ctx.tags())
2540 if t:
2540 if t:
2541 output.append(t)
2541 output.append(t)
2542
2542
2543 # multiple bookmarks for a single parent separated by '/'
2543 # multiple bookmarks for a single parent separated by '/'
2544 bm = '/'.join(ctx.bookmarks())
2544 bm = '/'.join(ctx.bookmarks())
2545 if bm:
2545 if bm:
2546 output.append(bm)
2546 output.append(bm)
2547 else:
2547 else:
2548 if branch:
2548 if branch:
2549 output.append(ctx.branch())
2549 output.append(ctx.branch())
2550
2550
2551 if tags:
2551 if tags:
2552 output.extend(ctx.tags())
2552 output.extend(ctx.tags())
2553
2553
2554 if bookmarks:
2554 if bookmarks:
2555 output.extend(ctx.bookmarks())
2555 output.extend(ctx.bookmarks())
2556
2556
2557 ui.write("%s\n" % ' '.join(output))
2557 ui.write("%s\n" % ' '.join(output))
2558
2558
2559 def import_(ui, repo, patch1, *patches, **opts):
2559 def import_(ui, repo, patch1, *patches, **opts):
2560 """import an ordered set of patches
2560 """import an ordered set of patches
2561
2561
2562 Import a list of patches and commit them individually (unless
2562 Import a list of patches and commit them individually (unless
2563 --no-commit is specified).
2563 --no-commit is specified).
2564
2564
2565 If there are outstanding changes in the working directory, import
2565 If there are outstanding changes in the working directory, import
2566 will abort unless given the -f/--force flag.
2566 will abort unless given the -f/--force flag.
2567
2567
2568 You can import a patch straight from a mail message. Even patches
2568 You can import a patch straight from a mail message. Even patches
2569 as attachments work (to use the body part, it must have type
2569 as attachments work (to use the body part, it must have type
2570 text/plain or text/x-patch). From and Subject headers of email
2570 text/plain or text/x-patch). From and Subject headers of email
2571 message are used as default committer and commit message. All
2571 message are used as default committer and commit message. All
2572 text/plain body parts before first diff are added to commit
2572 text/plain body parts before first diff are added to commit
2573 message.
2573 message.
2574
2574
2575 If the imported patch was generated by :hg:`export`, user and
2575 If the imported patch was generated by :hg:`export`, user and
2576 description from patch override values from message headers and
2576 description from patch override values from message headers and
2577 body. Values given on command line with -m/--message and -u/--user
2577 body. Values given on command line with -m/--message and -u/--user
2578 override these.
2578 override these.
2579
2579
2580 If --exact is specified, import will set the working directory to
2580 If --exact is specified, import will set the working directory to
2581 the parent of each patch before applying it, and will abort if the
2581 the parent of each patch before applying it, and will abort if the
2582 resulting changeset has a different ID than the one recorded in
2582 resulting changeset has a different ID than the one recorded in
2583 the patch. This may happen due to character set problems or other
2583 the patch. This may happen due to character set problems or other
2584 deficiencies in the text patch format.
2584 deficiencies in the text patch format.
2585
2585
2586 With -s/--similarity, hg will attempt to discover renames and
2586 With -s/--similarity, hg will attempt to discover renames and
2587 copies in the patch in the same way as 'addremove'.
2587 copies in the patch in the same way as 'addremove'.
2588
2588
2589 To read a patch from standard input, use "-" as the patch name. If
2589 To read a patch from standard input, use "-" as the patch name. If
2590 a URL is specified, the patch will be downloaded from it.
2590 a URL is specified, the patch will be downloaded from it.
2591 See :hg:`help dates` for a list of formats valid for -d/--date.
2591 See :hg:`help dates` for a list of formats valid for -d/--date.
2592
2592
2593 Returns 0 on success.
2593 Returns 0 on success.
2594 """
2594 """
2595 patches = (patch1,) + patches
2595 patches = (patch1,) + patches
2596
2596
2597 date = opts.get('date')
2597 date = opts.get('date')
2598 if date:
2598 if date:
2599 opts['date'] = util.parsedate(date)
2599 opts['date'] = util.parsedate(date)
2600
2600
2601 try:
2601 try:
2602 sim = float(opts.get('similarity') or 0)
2602 sim = float(opts.get('similarity') or 0)
2603 except ValueError:
2603 except ValueError:
2604 raise util.Abort(_('similarity must be a number'))
2604 raise util.Abort(_('similarity must be a number'))
2605 if sim < 0 or sim > 100:
2605 if sim < 0 or sim > 100:
2606 raise util.Abort(_('similarity must be between 0 and 100'))
2606 raise util.Abort(_('similarity must be between 0 and 100'))
2607
2607
2608 if opts.get('exact') or not opts.get('force'):
2608 if opts.get('exact') or not opts.get('force'):
2609 cmdutil.bailifchanged(repo)
2609 cmdutil.bailifchanged(repo)
2610
2610
2611 d = opts["base"]
2611 d = opts["base"]
2612 strip = opts["strip"]
2612 strip = opts["strip"]
2613 wlock = lock = None
2613 wlock = lock = None
2614 msgs = []
2614 msgs = []
2615
2615
2616 def tryone(ui, hunk):
2616 def tryone(ui, hunk):
2617 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2617 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2618 patch.extract(ui, hunk)
2618 patch.extract(ui, hunk)
2619
2619
2620 if not tmpname:
2620 if not tmpname:
2621 return None
2621 return None
2622 commitid = _('to working directory')
2622 commitid = _('to working directory')
2623
2623
2624 try:
2624 try:
2625 cmdline_message = cmdutil.logmessage(opts)
2625 cmdline_message = cmdutil.logmessage(opts)
2626 if cmdline_message:
2626 if cmdline_message:
2627 # pickup the cmdline msg
2627 # pickup the cmdline msg
2628 message = cmdline_message
2628 message = cmdline_message
2629 elif message:
2629 elif message:
2630 # pickup the patch msg
2630 # pickup the patch msg
2631 message = message.strip()
2631 message = message.strip()
2632 else:
2632 else:
2633 # launch the editor
2633 # launch the editor
2634 message = None
2634 message = None
2635 ui.debug('message:\n%s\n' % message)
2635 ui.debug('message:\n%s\n' % message)
2636
2636
2637 wp = repo.parents()
2637 wp = repo.parents()
2638 if opts.get('exact'):
2638 if opts.get('exact'):
2639 if not nodeid or not p1:
2639 if not nodeid or not p1:
2640 raise util.Abort(_('not a Mercurial patch'))
2640 raise util.Abort(_('not a Mercurial patch'))
2641 p1 = repo.lookup(p1)
2641 p1 = repo.lookup(p1)
2642 p2 = repo.lookup(p2 or hex(nullid))
2642 p2 = repo.lookup(p2 or hex(nullid))
2643
2643
2644 if p1 != wp[0].node():
2644 if p1 != wp[0].node():
2645 hg.clean(repo, p1)
2645 hg.clean(repo, p1)
2646 repo.dirstate.setparents(p1, p2)
2646 repo.dirstate.setparents(p1, p2)
2647 elif p2:
2647 elif p2:
2648 try:
2648 try:
2649 p1 = repo.lookup(p1)
2649 p1 = repo.lookup(p1)
2650 p2 = repo.lookup(p2)
2650 p2 = repo.lookup(p2)
2651 if p1 == wp[0].node():
2651 if p1 == wp[0].node():
2652 repo.dirstate.setparents(p1, p2)
2652 repo.dirstate.setparents(p1, p2)
2653 except error.RepoError:
2653 except error.RepoError:
2654 pass
2654 pass
2655 if opts.get('exact') or opts.get('import_branch'):
2655 if opts.get('exact') or opts.get('import_branch'):
2656 repo.dirstate.setbranch(branch or 'default')
2656 repo.dirstate.setbranch(branch or 'default')
2657
2657
2658 files = {}
2658 files = {}
2659 patch.patch(ui, repo, tmpname, strip=strip, cwd=repo.root,
2659 patch.patch(ui, repo, tmpname, strip=strip, cwd=repo.root,
2660 files=files, eolmode=None, similarity=sim / 100.0)
2660 files=files, eolmode=None, similarity=sim / 100.0)
2661 files = list(files)
2661 files = list(files)
2662 if opts.get('no_commit'):
2662 if opts.get('no_commit'):
2663 if message:
2663 if message:
2664 msgs.append(message)
2664 msgs.append(message)
2665 else:
2665 else:
2666 if opts.get('exact'):
2666 if opts.get('exact'):
2667 m = None
2667 m = None
2668 else:
2668 else:
2669 m = cmdutil.matchfiles(repo, files or [])
2669 m = cmdutil.matchfiles(repo, files or [])
2670 n = repo.commit(message, opts.get('user') or user,
2670 n = repo.commit(message, opts.get('user') or user,
2671 opts.get('date') or date, match=m,
2671 opts.get('date') or date, match=m,
2672 editor=cmdutil.commiteditor)
2672 editor=cmdutil.commiteditor)
2673 if opts.get('exact'):
2673 if opts.get('exact'):
2674 if hex(n) != nodeid:
2674 if hex(n) != nodeid:
2675 repo.rollback()
2675 repo.rollback()
2676 raise util.Abort(_('patch is damaged'
2676 raise util.Abort(_('patch is damaged'
2677 ' or loses information'))
2677 ' or loses information'))
2678 # Force a dirstate write so that the next transaction
2678 # Force a dirstate write so that the next transaction
2679 # backups an up-do-date file.
2679 # backups an up-do-date file.
2680 repo.dirstate.write()
2680 repo.dirstate.write()
2681 if n:
2681 if n:
2682 commitid = short(n)
2682 commitid = short(n)
2683
2683
2684 return commitid
2684 return commitid
2685 finally:
2685 finally:
2686 os.unlink(tmpname)
2686 os.unlink(tmpname)
2687
2687
2688 try:
2688 try:
2689 wlock = repo.wlock()
2689 wlock = repo.wlock()
2690 lock = repo.lock()
2690 lock = repo.lock()
2691 lastcommit = None
2691 lastcommit = None
2692 for p in patches:
2692 for p in patches:
2693 pf = os.path.join(d, p)
2693 pf = os.path.join(d, p)
2694
2694
2695 if pf == '-':
2695 if pf == '-':
2696 ui.status(_("applying patch from stdin\n"))
2696 ui.status(_("applying patch from stdin\n"))
2697 pf = sys.stdin
2697 pf = sys.stdin
2698 else:
2698 else:
2699 ui.status(_("applying %s\n") % p)
2699 ui.status(_("applying %s\n") % p)
2700 pf = url.open(ui, pf)
2700 pf = url.open(ui, pf)
2701
2701
2702 haspatch = False
2702 haspatch = False
2703 for hunk in patch.split(pf):
2703 for hunk in patch.split(pf):
2704 commitid = tryone(ui, hunk)
2704 commitid = tryone(ui, hunk)
2705 if commitid:
2705 if commitid:
2706 haspatch = True
2706 haspatch = True
2707 if lastcommit:
2707 if lastcommit:
2708 ui.status(_('applied %s\n') % lastcommit)
2708 ui.status(_('applied %s\n') % lastcommit)
2709 lastcommit = commitid
2709 lastcommit = commitid
2710
2710
2711 if not haspatch:
2711 if not haspatch:
2712 raise util.Abort(_('no diffs found'))
2712 raise util.Abort(_('no diffs found'))
2713
2713
2714 if msgs:
2714 if msgs:
2715 repo.opener.write('last-message.txt', '\n* * *\n'.join(msgs))
2715 repo.opener.write('last-message.txt', '\n* * *\n'.join(msgs))
2716 finally:
2716 finally:
2717 release(lock, wlock)
2717 release(lock, wlock)
2718
2718
2719 def incoming(ui, repo, source="default", **opts):
2719 def incoming(ui, repo, source="default", **opts):
2720 """show new changesets found in source
2720 """show new changesets found in source
2721
2721
2722 Show new changesets found in the specified path/URL or the default
2722 Show new changesets found in the specified path/URL or the default
2723 pull location. These are the changesets that would have been pulled
2723 pull location. These are the changesets that would have been pulled
2724 if a pull at the time you issued this command.
2724 if a pull at the time you issued this command.
2725
2725
2726 For remote repository, using --bundle avoids downloading the
2726 For remote repository, using --bundle avoids downloading the
2727 changesets twice if the incoming is followed by a pull.
2727 changesets twice if the incoming is followed by a pull.
2728
2728
2729 See pull for valid source format details.
2729 See pull for valid source format details.
2730
2730
2731 Returns 0 if there are incoming changes, 1 otherwise.
2731 Returns 0 if there are incoming changes, 1 otherwise.
2732 """
2732 """
2733 if opts.get('bundle') and opts.get('subrepos'):
2733 if opts.get('bundle') and opts.get('subrepos'):
2734 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2734 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2735
2735
2736 if opts.get('bookmarks'):
2736 if opts.get('bookmarks'):
2737 source, branches = hg.parseurl(ui.expandpath(source),
2737 source, branches = hg.parseurl(ui.expandpath(source),
2738 opts.get('branch'))
2738 opts.get('branch'))
2739 other = hg.repository(hg.remoteui(repo, opts), source)
2739 other = hg.repository(hg.remoteui(repo, opts), source)
2740 if 'bookmarks' not in other.listkeys('namespaces'):
2740 if 'bookmarks' not in other.listkeys('namespaces'):
2741 ui.warn(_("remote doesn't support bookmarks\n"))
2741 ui.warn(_("remote doesn't support bookmarks\n"))
2742 return 0
2742 return 0
2743 ui.status(_('comparing with %s\n') % util.hidepassword(source))
2743 ui.status(_('comparing with %s\n') % util.hidepassword(source))
2744 return bookmarks.diff(ui, repo, other)
2744 return bookmarks.diff(ui, repo, other)
2745
2745
2746 ret = hg.incoming(ui, repo, source, opts)
2746 ret = hg.incoming(ui, repo, source, opts)
2747 return ret
2747 return ret
2748
2748
2749 def init(ui, dest=".", **opts):
2749 def init(ui, dest=".", **opts):
2750 """create a new repository in the given directory
2750 """create a new repository in the given directory
2751
2751
2752 Initialize a new repository in the given directory. If the given
2752 Initialize a new repository in the given directory. If the given
2753 directory does not exist, it will be created.
2753 directory does not exist, it will be created.
2754
2754
2755 If no directory is given, the current directory is used.
2755 If no directory is given, the current directory is used.
2756
2756
2757 It is possible to specify an ``ssh://`` URL as the destination.
2757 It is possible to specify an ``ssh://`` URL as the destination.
2758 See :hg:`help urls` for more information.
2758 See :hg:`help urls` for more information.
2759
2759
2760 Returns 0 on success.
2760 Returns 0 on success.
2761 """
2761 """
2762 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2762 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2763
2763
2764 def locate(ui, repo, *pats, **opts):
2764 def locate(ui, repo, *pats, **opts):
2765 """locate files matching specific patterns
2765 """locate files matching specific patterns
2766
2766
2767 Print files under Mercurial control in the working directory whose
2767 Print files under Mercurial control in the working directory whose
2768 names match the given patterns.
2768 names match the given patterns.
2769
2769
2770 By default, this command searches all directories in the working
2770 By default, this command searches all directories in the working
2771 directory. To search just the current directory and its
2771 directory. To search just the current directory and its
2772 subdirectories, use "--include .".
2772 subdirectories, use "--include .".
2773
2773
2774 If no patterns are given to match, this command prints the names
2774 If no patterns are given to match, this command prints the names
2775 of all files under Mercurial control in the working directory.
2775 of all files under Mercurial control in the working directory.
2776
2776
2777 If you want to feed the output of this command into the "xargs"
2777 If you want to feed the output of this command into the "xargs"
2778 command, use the -0 option to both this command and "xargs". This
2778 command, use the -0 option to both this command and "xargs". This
2779 will avoid the problem of "xargs" treating single filenames that
2779 will avoid the problem of "xargs" treating single filenames that
2780 contain whitespace as multiple filenames.
2780 contain whitespace as multiple filenames.
2781
2781
2782 Returns 0 if a match is found, 1 otherwise.
2782 Returns 0 if a match is found, 1 otherwise.
2783 """
2783 """
2784 end = opts.get('print0') and '\0' or '\n'
2784 end = opts.get('print0') and '\0' or '\n'
2785 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2785 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2786
2786
2787 ret = 1
2787 ret = 1
2788 m = cmdutil.match(repo, pats, opts, default='relglob')
2788 m = cmdutil.match(repo, pats, opts, default='relglob')
2789 m.bad = lambda x, y: False
2789 m.bad = lambda x, y: False
2790 for abs in repo[rev].walk(m):
2790 for abs in repo[rev].walk(m):
2791 if not rev and abs not in repo.dirstate:
2791 if not rev and abs not in repo.dirstate:
2792 continue
2792 continue
2793 if opts.get('fullpath'):
2793 if opts.get('fullpath'):
2794 ui.write(repo.wjoin(abs), end)
2794 ui.write(repo.wjoin(abs), end)
2795 else:
2795 else:
2796 ui.write(((pats and m.rel(abs)) or abs), end)
2796 ui.write(((pats and m.rel(abs)) or abs), end)
2797 ret = 0
2797 ret = 0
2798
2798
2799 return ret
2799 return ret
2800
2800
2801 def log(ui, repo, *pats, **opts):
2801 def log(ui, repo, *pats, **opts):
2802 """show revision history of entire repository or files
2802 """show revision history of entire repository or files
2803
2803
2804 Print the revision history of the specified files or the entire
2804 Print the revision history of the specified files or the entire
2805 project.
2805 project.
2806
2806
2807 File history is shown without following rename or copy history of
2807 File history is shown without following rename or copy history of
2808 files. Use -f/--follow with a filename to follow history across
2808 files. Use -f/--follow with a filename to follow history across
2809 renames and copies. --follow without a filename will only show
2809 renames and copies. --follow without a filename will only show
2810 ancestors or descendants of the starting revision. --follow-first
2810 ancestors or descendants of the starting revision. --follow-first
2811 only follows the first parent of merge revisions.
2811 only follows the first parent of merge revisions.
2812
2812
2813 If no revision range is specified, the default is ``tip:0`` unless
2813 If no revision range is specified, the default is ``tip:0`` unless
2814 --follow is set, in which case the working directory parent is
2814 --follow is set, in which case the working directory parent is
2815 used as the starting revision. You can specify a revision set for
2815 used as the starting revision. You can specify a revision set for
2816 log, see :hg:`help revsets` for more information.
2816 log, see :hg:`help revsets` for more information.
2817
2817
2818 See :hg:`help dates` for a list of formats valid for -d/--date.
2818 See :hg:`help dates` for a list of formats valid for -d/--date.
2819
2819
2820 By default this command prints revision number and changeset id,
2820 By default this command prints revision number and changeset id,
2821 tags, non-trivial parents, user, date and time, and a summary for
2821 tags, non-trivial parents, user, date and time, and a summary for
2822 each commit. When the -v/--verbose switch is used, the list of
2822 each commit. When the -v/--verbose switch is used, the list of
2823 changed files and full commit message are shown.
2823 changed files and full commit message are shown.
2824
2824
2825 .. note::
2825 .. note::
2826 log -p/--patch may generate unexpected diff output for merge
2826 log -p/--patch may generate unexpected diff output for merge
2827 changesets, as it will only compare the merge changeset against
2827 changesets, as it will only compare the merge changeset against
2828 its first parent. Also, only files different from BOTH parents
2828 its first parent. Also, only files different from BOTH parents
2829 will appear in files:.
2829 will appear in files:.
2830
2830
2831 Returns 0 on success.
2831 Returns 0 on success.
2832 """
2832 """
2833
2833
2834 matchfn = cmdutil.match(repo, pats, opts)
2834 matchfn = cmdutil.match(repo, pats, opts)
2835 limit = cmdutil.loglimit(opts)
2835 limit = cmdutil.loglimit(opts)
2836 count = 0
2836 count = 0
2837
2837
2838 endrev = None
2838 endrev = None
2839 if opts.get('copies') and opts.get('rev'):
2839 if opts.get('copies') and opts.get('rev'):
2840 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2840 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2841
2841
2842 df = False
2842 df = False
2843 if opts["date"]:
2843 if opts["date"]:
2844 df = util.matchdate(opts["date"])
2844 df = util.matchdate(opts["date"])
2845
2845
2846 branches = opts.get('branch', []) + opts.get('only_branch', [])
2846 branches = opts.get('branch', []) + opts.get('only_branch', [])
2847 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2847 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2848
2848
2849 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2849 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2850 def prep(ctx, fns):
2850 def prep(ctx, fns):
2851 rev = ctx.rev()
2851 rev = ctx.rev()
2852 parents = [p for p in repo.changelog.parentrevs(rev)
2852 parents = [p for p in repo.changelog.parentrevs(rev)
2853 if p != nullrev]
2853 if p != nullrev]
2854 if opts.get('no_merges') and len(parents) == 2:
2854 if opts.get('no_merges') and len(parents) == 2:
2855 return
2855 return
2856 if opts.get('only_merges') and len(parents) != 2:
2856 if opts.get('only_merges') and len(parents) != 2:
2857 return
2857 return
2858 if opts.get('branch') and ctx.branch() not in opts['branch']:
2858 if opts.get('branch') and ctx.branch() not in opts['branch']:
2859 return
2859 return
2860 if df and not df(ctx.date()[0]):
2860 if df and not df(ctx.date()[0]):
2861 return
2861 return
2862 if opts['user'] and not [k for k in opts['user']
2862 if opts['user'] and not [k for k in opts['user']
2863 if k.lower() in ctx.user().lower()]:
2863 if k.lower() in ctx.user().lower()]:
2864 return
2864 return
2865 if opts.get('keyword'):
2865 if opts.get('keyword'):
2866 for k in [kw.lower() for kw in opts['keyword']]:
2866 for k in [kw.lower() for kw in opts['keyword']]:
2867 if (k in ctx.user().lower() or
2867 if (k in ctx.user().lower() or
2868 k in ctx.description().lower() or
2868 k in ctx.description().lower() or
2869 k in " ".join(ctx.files()).lower()):
2869 k in " ".join(ctx.files()).lower()):
2870 break
2870 break
2871 else:
2871 else:
2872 return
2872 return
2873
2873
2874 copies = None
2874 copies = None
2875 if opts.get('copies') and rev:
2875 if opts.get('copies') and rev:
2876 copies = []
2876 copies = []
2877 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2877 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2878 for fn in ctx.files():
2878 for fn in ctx.files():
2879 rename = getrenamed(fn, rev)
2879 rename = getrenamed(fn, rev)
2880 if rename:
2880 if rename:
2881 copies.append((fn, rename[0]))
2881 copies.append((fn, rename[0]))
2882
2882
2883 revmatchfn = None
2883 revmatchfn = None
2884 if opts.get('patch') or opts.get('stat'):
2884 if opts.get('patch') or opts.get('stat'):
2885 if opts.get('follow') or opts.get('follow_first'):
2885 if opts.get('follow') or opts.get('follow_first'):
2886 # note: this might be wrong when following through merges
2886 # note: this might be wrong when following through merges
2887 revmatchfn = cmdutil.match(repo, fns, default='path')
2887 revmatchfn = cmdutil.match(repo, fns, default='path')
2888 else:
2888 else:
2889 revmatchfn = matchfn
2889 revmatchfn = matchfn
2890
2890
2891 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2891 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2892
2892
2893 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2893 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2894 if count == limit:
2894 if count == limit:
2895 break
2895 break
2896 if displayer.flush(ctx.rev()):
2896 if displayer.flush(ctx.rev()):
2897 count += 1
2897 count += 1
2898 displayer.close()
2898 displayer.close()
2899
2899
2900 def manifest(ui, repo, node=None, rev=None):
2900 def manifest(ui, repo, node=None, rev=None):
2901 """output the current or given revision of the project manifest
2901 """output the current or given revision of the project manifest
2902
2902
2903 Print a list of version controlled files for the given revision.
2903 Print a list of version controlled files for the given revision.
2904 If no revision is given, the first parent of the working directory
2904 If no revision is given, the first parent of the working directory
2905 is used, or the null revision if no revision is checked out.
2905 is used, or the null revision if no revision is checked out.
2906
2906
2907 With -v, print file permissions, symlink and executable bits.
2907 With -v, print file permissions, symlink and executable bits.
2908 With --debug, print file revision hashes.
2908 With --debug, print file revision hashes.
2909
2909
2910 Returns 0 on success.
2910 Returns 0 on success.
2911 """
2911 """
2912
2912
2913 if rev and node:
2913 if rev and node:
2914 raise util.Abort(_("please specify just one revision"))
2914 raise util.Abort(_("please specify just one revision"))
2915
2915
2916 if not node:
2916 if not node:
2917 node = rev
2917 node = rev
2918
2918
2919 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2919 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2920 ctx = cmdutil.revsingle(repo, node)
2920 ctx = cmdutil.revsingle(repo, node)
2921 for f in ctx:
2921 for f in ctx:
2922 if ui.debugflag:
2922 if ui.debugflag:
2923 ui.write("%40s " % hex(ctx.manifest()[f]))
2923 ui.write("%40s " % hex(ctx.manifest()[f]))
2924 if ui.verbose:
2924 if ui.verbose:
2925 ui.write(decor[ctx.flags(f)])
2925 ui.write(decor[ctx.flags(f)])
2926 ui.write("%s\n" % f)
2926 ui.write("%s\n" % f)
2927
2927
2928 def merge(ui, repo, node=None, **opts):
2928 def merge(ui, repo, node=None, **opts):
2929 """merge working directory with another revision
2929 """merge working directory with another revision
2930
2930
2931 The current working directory is updated with all changes made in
2931 The current working directory is updated with all changes made in
2932 the requested revision since the last common predecessor revision.
2932 the requested revision since the last common predecessor revision.
2933
2933
2934 Files that changed between either parent are marked as changed for
2934 Files that changed between either parent are marked as changed for
2935 the next commit and a commit must be performed before any further
2935 the next commit and a commit must be performed before any further
2936 updates to the repository are allowed. The next commit will have
2936 updates to the repository are allowed. The next commit will have
2937 two parents.
2937 two parents.
2938
2938
2939 ``--tool`` can be used to specify the merge tool used for file
2939 ``--tool`` can be used to specify the merge tool used for file
2940 merges. It overrides the HGMERGE environment variable and your
2940 merges. It overrides the HGMERGE environment variable and your
2941 configuration files. See :hg:`help merge-tools` for options.
2941 configuration files. See :hg:`help merge-tools` for options.
2942
2942
2943 If no revision is specified, the working directory's parent is a
2943 If no revision is specified, the working directory's parent is a
2944 head revision, and the current branch contains exactly one other
2944 head revision, and the current branch contains exactly one other
2945 head, the other head is merged with by default. Otherwise, an
2945 head, the other head is merged with by default. Otherwise, an
2946 explicit revision with which to merge with must be provided.
2946 explicit revision with which to merge with must be provided.
2947
2947
2948 :hg:`resolve` must be used to resolve unresolved files.
2948 :hg:`resolve` must be used to resolve unresolved files.
2949
2949
2950 To undo an uncommitted merge, use :hg:`update --clean .` which
2950 To undo an uncommitted merge, use :hg:`update --clean .` which
2951 will check out a clean copy of the original merge parent, losing
2951 will check out a clean copy of the original merge parent, losing
2952 all changes.
2952 all changes.
2953
2953
2954 Returns 0 on success, 1 if there are unresolved files.
2954 Returns 0 on success, 1 if there are unresolved files.
2955 """
2955 """
2956
2956
2957 if opts.get('rev') and node:
2957 if opts.get('rev') and node:
2958 raise util.Abort(_("please specify just one revision"))
2958 raise util.Abort(_("please specify just one revision"))
2959 if not node:
2959 if not node:
2960 node = opts.get('rev')
2960 node = opts.get('rev')
2961
2961
2962 if not node:
2962 if not node:
2963 branch = repo[None].branch()
2963 branch = repo[None].branch()
2964 bheads = repo.branchheads(branch)
2964 bheads = repo.branchheads(branch)
2965 if len(bheads) > 2:
2965 if len(bheads) > 2:
2966 raise util.Abort(_("branch '%s' has %d heads - "
2966 raise util.Abort(_("branch '%s' has %d heads - "
2967 "please merge with an explicit rev")
2967 "please merge with an explicit rev")
2968 % (branch, len(bheads)),
2968 % (branch, len(bheads)),
2969 hint=_("run 'hg heads .' to see heads"))
2969 hint=_("run 'hg heads .' to see heads"))
2970
2970
2971 parent = repo.dirstate.p1()
2971 parent = repo.dirstate.p1()
2972 if len(bheads) == 1:
2972 if len(bheads) == 1:
2973 if len(repo.heads()) > 1:
2973 if len(repo.heads()) > 1:
2974 raise util.Abort(_("branch '%s' has one head - "
2974 raise util.Abort(_("branch '%s' has one head - "
2975 "please merge with an explicit rev")
2975 "please merge with an explicit rev")
2976 % branch,
2976 % branch,
2977 hint=_("run 'hg heads' to see all heads"))
2977 hint=_("run 'hg heads' to see all heads"))
2978 msg = _('there is nothing to merge')
2978 msg = _('there is nothing to merge')
2979 if parent != repo.lookup(repo[None].branch()):
2979 if parent != repo.lookup(repo[None].branch()):
2980 msg = _('%s - use "hg update" instead') % msg
2980 msg = _('%s - use "hg update" instead') % msg
2981 raise util.Abort(msg)
2981 raise util.Abort(msg)
2982
2982
2983 if parent not in bheads:
2983 if parent not in bheads:
2984 raise util.Abort(_('working directory not at a head revision'),
2984 raise util.Abort(_('working directory not at a head revision'),
2985 hint=_("use 'hg update' or merge with an "
2985 hint=_("use 'hg update' or merge with an "
2986 "explicit revision"))
2986 "explicit revision"))
2987 node = parent == bheads[0] and bheads[-1] or bheads[0]
2987 node = parent == bheads[0] and bheads[-1] or bheads[0]
2988 else:
2988 else:
2989 node = cmdutil.revsingle(repo, node).node()
2989 node = cmdutil.revsingle(repo, node).node()
2990
2990
2991 if opts.get('preview'):
2991 if opts.get('preview'):
2992 # find nodes that are ancestors of p2 but not of p1
2992 # find nodes that are ancestors of p2 but not of p1
2993 p1 = repo.lookup('.')
2993 p1 = repo.lookup('.')
2994 p2 = repo.lookup(node)
2994 p2 = repo.lookup(node)
2995 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2995 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2996
2996
2997 displayer = cmdutil.show_changeset(ui, repo, opts)
2997 displayer = cmdutil.show_changeset(ui, repo, opts)
2998 for node in nodes:
2998 for node in nodes:
2999 displayer.show(repo[node])
2999 displayer.show(repo[node])
3000 displayer.close()
3000 displayer.close()
3001 return 0
3001 return 0
3002
3002
3003 try:
3003 try:
3004 # ui.forcemerge is an internal variable, do not document
3004 # ui.forcemerge is an internal variable, do not document
3005 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3005 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3006 return hg.merge(repo, node, force=opts.get('force'))
3006 return hg.merge(repo, node, force=opts.get('force'))
3007 finally:
3007 finally:
3008 ui.setconfig('ui', 'forcemerge', '')
3008 ui.setconfig('ui', 'forcemerge', '')
3009
3009
3010 def outgoing(ui, repo, dest=None, **opts):
3010 def outgoing(ui, repo, dest=None, **opts):
3011 """show changesets not found in the destination
3011 """show changesets not found in the destination
3012
3012
3013 Show changesets not found in the specified destination repository
3013 Show changesets not found in the specified destination repository
3014 or the default push location. These are the changesets that would
3014 or the default push location. These are the changesets that would
3015 be pushed if a push was requested.
3015 be pushed if a push was requested.
3016
3016
3017 See pull for details of valid destination formats.
3017 See pull for details of valid destination formats.
3018
3018
3019 Returns 0 if there are outgoing changes, 1 otherwise.
3019 Returns 0 if there are outgoing changes, 1 otherwise.
3020 """
3020 """
3021
3021
3022 if opts.get('bookmarks'):
3022 if opts.get('bookmarks'):
3023 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3023 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3024 dest, branches = hg.parseurl(dest, opts.get('branch'))
3024 dest, branches = hg.parseurl(dest, opts.get('branch'))
3025 other = hg.repository(hg.remoteui(repo, opts), dest)
3025 other = hg.repository(hg.remoteui(repo, opts), dest)
3026 if 'bookmarks' not in other.listkeys('namespaces'):
3026 if 'bookmarks' not in other.listkeys('namespaces'):
3027 ui.warn(_("remote doesn't support bookmarks\n"))
3027 ui.warn(_("remote doesn't support bookmarks\n"))
3028 return 0
3028 return 0
3029 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3029 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3030 return bookmarks.diff(ui, other, repo)
3030 return bookmarks.diff(ui, other, repo)
3031
3031
3032 ret = hg.outgoing(ui, repo, dest, opts)
3032 ret = hg.outgoing(ui, repo, dest, opts)
3033 return ret
3033 return ret
3034
3034
3035 def parents(ui, repo, file_=None, **opts):
3035 def parents(ui, repo, file_=None, **opts):
3036 """show the parents of the working directory or revision
3036 """show the parents of the working directory or revision
3037
3037
3038 Print the working directory's parent revisions. If a revision is
3038 Print the working directory's parent revisions. If a revision is
3039 given via -r/--rev, the parent of that revision will be printed.
3039 given via -r/--rev, the parent of that revision will be printed.
3040 If a file argument is given, the revision in which the file was
3040 If a file argument is given, the revision in which the file was
3041 last changed (before the working directory revision or the
3041 last changed (before the working directory revision or the
3042 argument to --rev if given) is printed.
3042 argument to --rev if given) is printed.
3043
3043
3044 Returns 0 on success.
3044 Returns 0 on success.
3045 """
3045 """
3046
3046
3047 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
3047 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
3048
3048
3049 if file_:
3049 if file_:
3050 m = cmdutil.match(repo, (file_,), opts)
3050 m = cmdutil.match(repo, (file_,), opts)
3051 if m.anypats() or len(m.files()) != 1:
3051 if m.anypats() or len(m.files()) != 1:
3052 raise util.Abort(_('can only specify an explicit filename'))
3052 raise util.Abort(_('can only specify an explicit filename'))
3053 file_ = m.files()[0]
3053 file_ = m.files()[0]
3054 filenodes = []
3054 filenodes = []
3055 for cp in ctx.parents():
3055 for cp in ctx.parents():
3056 if not cp:
3056 if not cp:
3057 continue
3057 continue
3058 try:
3058 try:
3059 filenodes.append(cp.filenode(file_))
3059 filenodes.append(cp.filenode(file_))
3060 except error.LookupError:
3060 except error.LookupError:
3061 pass
3061 pass
3062 if not filenodes:
3062 if not filenodes:
3063 raise util.Abort(_("'%s' not found in manifest!") % file_)
3063 raise util.Abort(_("'%s' not found in manifest!") % file_)
3064 fl = repo.file(file_)
3064 fl = repo.file(file_)
3065 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3065 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3066 else:
3066 else:
3067 p = [cp.node() for cp in ctx.parents()]
3067 p = [cp.node() for cp in ctx.parents()]
3068
3068
3069 displayer = cmdutil.show_changeset(ui, repo, opts)
3069 displayer = cmdutil.show_changeset(ui, repo, opts)
3070 for n in p:
3070 for n in p:
3071 if n != nullid:
3071 if n != nullid:
3072 displayer.show(repo[n])
3072 displayer.show(repo[n])
3073 displayer.close()
3073 displayer.close()
3074
3074
3075 def paths(ui, repo, search=None):
3075 def paths(ui, repo, search=None):
3076 """show aliases for remote repositories
3076 """show aliases for remote repositories
3077
3077
3078 Show definition of symbolic path name NAME. If no name is given,
3078 Show definition of symbolic path name NAME. If no name is given,
3079 show definition of all available names.
3079 show definition of all available names.
3080
3080
3081 Path names are defined in the [paths] section of your
3081 Path names are defined in the [paths] section of your
3082 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3082 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3083 repository, ``.hg/hgrc`` is used, too.
3083 repository, ``.hg/hgrc`` is used, too.
3084
3084
3085 The path names ``default`` and ``default-push`` have a special
3085 The path names ``default`` and ``default-push`` have a special
3086 meaning. When performing a push or pull operation, they are used
3086 meaning. When performing a push or pull operation, they are used
3087 as fallbacks if no location is specified on the command-line.
3087 as fallbacks if no location is specified on the command-line.
3088 When ``default-push`` is set, it will be used for push and
3088 When ``default-push`` is set, it will be used for push and
3089 ``default`` will be used for pull; otherwise ``default`` is used
3089 ``default`` will be used for pull; otherwise ``default`` is used
3090 as the fallback for both. When cloning a repository, the clone
3090 as the fallback for both. When cloning a repository, the clone
3091 source is written as ``default`` in ``.hg/hgrc``. Note that
3091 source is written as ``default`` in ``.hg/hgrc``. Note that
3092 ``default`` and ``default-push`` apply to all inbound (e.g.
3092 ``default`` and ``default-push`` apply to all inbound (e.g.
3093 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3093 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3094 :hg:`bundle`) operations.
3094 :hg:`bundle`) operations.
3095
3095
3096 See :hg:`help urls` for more information.
3096 See :hg:`help urls` for more information.
3097
3097
3098 Returns 0 on success.
3098 Returns 0 on success.
3099 """
3099 """
3100 if search:
3100 if search:
3101 for name, path in ui.configitems("paths"):
3101 for name, path in ui.configitems("paths"):
3102 if name == search:
3102 if name == search:
3103 ui.write("%s\n" % util.hidepassword(path))
3103 ui.write("%s\n" % util.hidepassword(path))
3104 return
3104 return
3105 ui.warn(_("not found!\n"))
3105 ui.warn(_("not found!\n"))
3106 return 1
3106 return 1
3107 else:
3107 else:
3108 for name, path in ui.configitems("paths"):
3108 for name, path in ui.configitems("paths"):
3109 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3109 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3110
3110
3111 def postincoming(ui, repo, modheads, optupdate, checkout):
3111 def postincoming(ui, repo, modheads, optupdate, checkout):
3112 if modheads == 0:
3112 if modheads == 0:
3113 return
3113 return
3114 if optupdate:
3114 if optupdate:
3115 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
3115 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
3116 return hg.update(repo, checkout)
3116 return hg.update(repo, checkout)
3117 else:
3117 else:
3118 ui.status(_("not updating, since new heads added\n"))
3118 ui.status(_("not updating, since new heads added\n"))
3119 if modheads > 1:
3119 if modheads > 1:
3120 currentbranchheads = len(repo.branchheads())
3120 currentbranchheads = len(repo.branchheads())
3121 if currentbranchheads == modheads:
3121 if currentbranchheads == modheads:
3122 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3122 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3123 elif currentbranchheads > 1:
3123 elif currentbranchheads > 1:
3124 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3124 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3125 else:
3125 else:
3126 ui.status(_("(run 'hg heads' to see heads)\n"))
3126 ui.status(_("(run 'hg heads' to see heads)\n"))
3127 else:
3127 else:
3128 ui.status(_("(run 'hg update' to get a working copy)\n"))
3128 ui.status(_("(run 'hg update' to get a working copy)\n"))
3129
3129
3130 def pull(ui, repo, source="default", **opts):
3130 def pull(ui, repo, source="default", **opts):
3131 """pull changes from the specified source
3131 """pull changes from the specified source
3132
3132
3133 Pull changes from a remote repository to a local one.
3133 Pull changes from a remote repository to a local one.
3134
3134
3135 This finds all changes from the repository at the specified path
3135 This finds all changes from the repository at the specified path
3136 or URL and adds them to a local repository (the current one unless
3136 or URL and adds them to a local repository (the current one unless
3137 -R is specified). By default, this does not update the copy of the
3137 -R is specified). By default, this does not update the copy of the
3138 project in the working directory.
3138 project in the working directory.
3139
3139
3140 Use :hg:`incoming` if you want to see what would have been added
3140 Use :hg:`incoming` if you want to see what would have been added
3141 by a pull at the time you issued this command. If you then decide
3141 by a pull at the time you issued this command. If you then decide
3142 to add those changes to the repository, you should use :hg:`pull
3142 to add those changes to the repository, you should use :hg:`pull
3143 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3143 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3144
3144
3145 If SOURCE is omitted, the 'default' path will be used.
3145 If SOURCE is omitted, the 'default' path will be used.
3146 See :hg:`help urls` for more information.
3146 See :hg:`help urls` for more information.
3147
3147
3148 Returns 0 on success, 1 if an update had unresolved files.
3148 Returns 0 on success, 1 if an update had unresolved files.
3149 """
3149 """
3150 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3150 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3151 other = hg.repository(hg.remoteui(repo, opts), source)
3151 other = hg.repository(hg.remoteui(repo, opts), source)
3152 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3152 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3153 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3153 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3154
3154
3155 if opts.get('bookmark'):
3155 if opts.get('bookmark'):
3156 if not revs:
3156 if not revs:
3157 revs = []
3157 revs = []
3158 rb = other.listkeys('bookmarks')
3158 rb = other.listkeys('bookmarks')
3159 for b in opts['bookmark']:
3159 for b in opts['bookmark']:
3160 if b not in rb:
3160 if b not in rb:
3161 raise util.Abort(_('remote bookmark %s not found!') % b)
3161 raise util.Abort(_('remote bookmark %s not found!') % b)
3162 revs.append(rb[b])
3162 revs.append(rb[b])
3163
3163
3164 if revs:
3164 if revs:
3165 try:
3165 try:
3166 revs = [other.lookup(rev) for rev in revs]
3166 revs = [other.lookup(rev) for rev in revs]
3167 except error.CapabilityError:
3167 except error.CapabilityError:
3168 err = _("other repository doesn't support revision lookup, "
3168 err = _("other repository doesn't support revision lookup, "
3169 "so a rev cannot be specified.")
3169 "so a rev cannot be specified.")
3170 raise util.Abort(err)
3170 raise util.Abort(err)
3171
3171
3172 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3172 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3173 bookmarks.updatefromremote(ui, repo, other)
3173 bookmarks.updatefromremote(ui, repo, other)
3174 if checkout:
3174 if checkout:
3175 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3175 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3176 repo._subtoppath = source
3176 repo._subtoppath = source
3177 try:
3177 try:
3178 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3178 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3179
3179
3180 finally:
3180 finally:
3181 del repo._subtoppath
3181 del repo._subtoppath
3182
3182
3183 # update specified bookmarks
3183 # update specified bookmarks
3184 if opts.get('bookmark'):
3184 if opts.get('bookmark'):
3185 for b in opts['bookmark']:
3185 for b in opts['bookmark']:
3186 # explicit pull overrides local bookmark if any
3186 # explicit pull overrides local bookmark if any
3187 ui.status(_("importing bookmark %s\n") % b)
3187 ui.status(_("importing bookmark %s\n") % b)
3188 repo._bookmarks[b] = repo[rb[b]].node()
3188 repo._bookmarks[b] = repo[rb[b]].node()
3189 bookmarks.write(repo)
3189 bookmarks.write(repo)
3190
3190
3191 return ret
3191 return ret
3192
3192
3193 def push(ui, repo, dest=None, **opts):
3193 def push(ui, repo, dest=None, **opts):
3194 """push changes to the specified destination
3194 """push changes to the specified destination
3195
3195
3196 Push changesets from the local repository to the specified
3196 Push changesets from the local repository to the specified
3197 destination.
3197 destination.
3198
3198
3199 This operation is symmetrical to pull: it is identical to a pull
3199 This operation is symmetrical to pull: it is identical to a pull
3200 in the destination repository from the current one.
3200 in the destination repository from the current one.
3201
3201
3202 By default, push will not allow creation of new heads at the
3202 By default, push will not allow creation of new heads at the
3203 destination, since multiple heads would make it unclear which head
3203 destination, since multiple heads would make it unclear which head
3204 to use. In this situation, it is recommended to pull and merge
3204 to use. In this situation, it is recommended to pull and merge
3205 before pushing.
3205 before pushing.
3206
3206
3207 Use --new-branch if you want to allow push to create a new named
3207 Use --new-branch if you want to allow push to create a new named
3208 branch that is not present at the destination. This allows you to
3208 branch that is not present at the destination. This allows you to
3209 only create a new branch without forcing other changes.
3209 only create a new branch without forcing other changes.
3210
3210
3211 Use -f/--force to override the default behavior and push all
3211 Use -f/--force to override the default behavior and push all
3212 changesets on all branches.
3212 changesets on all branches.
3213
3213
3214 If -r/--rev is used, the specified revision and all its ancestors
3214 If -r/--rev is used, the specified revision and all its ancestors
3215 will be pushed to the remote repository.
3215 will be pushed to the remote repository.
3216
3216
3217 Please see :hg:`help urls` for important details about ``ssh://``
3217 Please see :hg:`help urls` for important details about ``ssh://``
3218 URLs. If DESTINATION is omitted, a default path will be used.
3218 URLs. If DESTINATION is omitted, a default path will be used.
3219
3219
3220 Returns 0 if push was successful, 1 if nothing to push.
3220 Returns 0 if push was successful, 1 if nothing to push.
3221 """
3221 """
3222
3222
3223 if opts.get('bookmark'):
3223 if opts.get('bookmark'):
3224 for b in opts['bookmark']:
3224 for b in opts['bookmark']:
3225 # translate -B options to -r so changesets get pushed
3225 # translate -B options to -r so changesets get pushed
3226 if b in repo._bookmarks:
3226 if b in repo._bookmarks:
3227 opts.setdefault('rev', []).append(b)
3227 opts.setdefault('rev', []).append(b)
3228 else:
3228 else:
3229 # if we try to push a deleted bookmark, translate it to null
3229 # if we try to push a deleted bookmark, translate it to null
3230 # this lets simultaneous -r, -b options continue working
3230 # this lets simultaneous -r, -b options continue working
3231 opts.setdefault('rev', []).append("null")
3231 opts.setdefault('rev', []).append("null")
3232
3232
3233 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3233 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3234 dest, branches = hg.parseurl(dest, opts.get('branch'))
3234 dest, branches = hg.parseurl(dest, opts.get('branch'))
3235 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3235 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3236 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3236 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3237 other = hg.repository(hg.remoteui(repo, opts), dest)
3237 other = hg.repository(hg.remoteui(repo, opts), dest)
3238 if revs:
3238 if revs:
3239 revs = [repo.lookup(rev) for rev in revs]
3239 revs = [repo.lookup(rev) for rev in revs]
3240
3240
3241 repo._subtoppath = dest
3241 repo._subtoppath = dest
3242 try:
3242 try:
3243 # push subrepos depth-first for coherent ordering
3243 # push subrepos depth-first for coherent ordering
3244 c = repo['']
3244 c = repo['']
3245 subs = c.substate # only repos that are committed
3245 subs = c.substate # only repos that are committed
3246 for s in sorted(subs):
3246 for s in sorted(subs):
3247 if not c.sub(s).push(opts.get('force')):
3247 if not c.sub(s).push(opts.get('force')):
3248 return False
3248 return False
3249 finally:
3249 finally:
3250 del repo._subtoppath
3250 del repo._subtoppath
3251 result = repo.push(other, opts.get('force'), revs=revs,
3251 result = repo.push(other, opts.get('force'), revs=revs,
3252 newbranch=opts.get('new_branch'))
3252 newbranch=opts.get('new_branch'))
3253
3253
3254 result = (result == 0)
3254 result = (result == 0)
3255
3255
3256 if opts.get('bookmark'):
3256 if opts.get('bookmark'):
3257 rb = other.listkeys('bookmarks')
3257 rb = other.listkeys('bookmarks')
3258 for b in opts['bookmark']:
3258 for b in opts['bookmark']:
3259 # explicit push overrides remote bookmark if any
3259 # explicit push overrides remote bookmark if any
3260 if b in repo._bookmarks:
3260 if b in repo._bookmarks:
3261 ui.status(_("exporting bookmark %s\n") % b)
3261 ui.status(_("exporting bookmark %s\n") % b)
3262 new = repo[b].hex()
3262 new = repo[b].hex()
3263 elif b in rb:
3263 elif b in rb:
3264 ui.status(_("deleting remote bookmark %s\n") % b)
3264 ui.status(_("deleting remote bookmark %s\n") % b)
3265 new = '' # delete
3265 new = '' # delete
3266 else:
3266 else:
3267 ui.warn(_('bookmark %s does not exist on the local '
3267 ui.warn(_('bookmark %s does not exist on the local '
3268 'or remote repository!\n') % b)
3268 'or remote repository!\n') % b)
3269 return 2
3269 return 2
3270 old = rb.get(b, '')
3270 old = rb.get(b, '')
3271 r = other.pushkey('bookmarks', b, old, new)
3271 r = other.pushkey('bookmarks', b, old, new)
3272 if not r:
3272 if not r:
3273 ui.warn(_('updating bookmark %s failed!\n') % b)
3273 ui.warn(_('updating bookmark %s failed!\n') % b)
3274 if not result:
3274 if not result:
3275 result = 2
3275 result = 2
3276
3276
3277 return result
3277 return result
3278
3278
3279 def recover(ui, repo):
3279 def recover(ui, repo):
3280 """roll back an interrupted transaction
3280 """roll back an interrupted transaction
3281
3281
3282 Recover from an interrupted commit or pull.
3282 Recover from an interrupted commit or pull.
3283
3283
3284 This command tries to fix the repository status after an
3284 This command tries to fix the repository status after an
3285 interrupted operation. It should only be necessary when Mercurial
3285 interrupted operation. It should only be necessary when Mercurial
3286 suggests it.
3286 suggests it.
3287
3287
3288 Returns 0 if successful, 1 if nothing to recover or verify fails.
3288 Returns 0 if successful, 1 if nothing to recover or verify fails.
3289 """
3289 """
3290 if repo.recover():
3290 if repo.recover():
3291 return hg.verify(repo)
3291 return hg.verify(repo)
3292 return 1
3292 return 1
3293
3293
3294 def remove(ui, repo, *pats, **opts):
3294 def remove(ui, repo, *pats, **opts):
3295 """remove the specified files on the next commit
3295 """remove the specified files on the next commit
3296
3296
3297 Schedule the indicated files for removal from the repository.
3297 Schedule the indicated files for removal from the repository.
3298
3298
3299 This only removes files from the current branch, not from the
3299 This only removes files from the current branch, not from the
3300 entire project history. -A/--after can be used to remove only
3300 entire project history. -A/--after can be used to remove only
3301 files that have already been deleted, -f/--force can be used to
3301 files that have already been deleted, -f/--force can be used to
3302 force deletion, and -Af can be used to remove files from the next
3302 force deletion, and -Af can be used to remove files from the next
3303 revision without deleting them from the working directory.
3303 revision without deleting them from the working directory.
3304
3304
3305 The following table details the behavior of remove for different
3305 The following table details the behavior of remove for different
3306 file states (columns) and option combinations (rows). The file
3306 file states (columns) and option combinations (rows). The file
3307 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3307 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3308 reported by :hg:`status`). The actions are Warn, Remove (from
3308 reported by :hg:`status`). The actions are Warn, Remove (from
3309 branch) and Delete (from disk)::
3309 branch) and Delete (from disk)::
3310
3310
3311 A C M !
3311 A C M !
3312 none W RD W R
3312 none W RD W R
3313 -f R RD RD R
3313 -f R RD RD R
3314 -A W W W R
3314 -A W W W R
3315 -Af R R R R
3315 -Af R R R R
3316
3316
3317 This command schedules the files to be removed at the next commit.
3317 This command schedules the files to be removed at the next commit.
3318 To undo a remove before that, see :hg:`revert`.
3318 To undo a remove before that, see :hg:`revert`.
3319
3319
3320 Returns 0 on success, 1 if any warnings encountered.
3320 Returns 0 on success, 1 if any warnings encountered.
3321 """
3321 """
3322
3322
3323 ret = 0
3323 ret = 0
3324 after, force = opts.get('after'), opts.get('force')
3324 after, force = opts.get('after'), opts.get('force')
3325 if not pats and not after:
3325 if not pats and not after:
3326 raise util.Abort(_('no files specified'))
3326 raise util.Abort(_('no files specified'))
3327
3327
3328 m = cmdutil.match(repo, pats, opts)
3328 m = cmdutil.match(repo, pats, opts)
3329 s = repo.status(match=m, clean=True)
3329 s = repo.status(match=m, clean=True)
3330 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3330 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3331
3331
3332 for f in m.files():
3332 for f in m.files():
3333 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3333 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3334 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3334 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3335 ret = 1
3335 ret = 1
3336
3336
3337 if force:
3337 if force:
3338 remove, forget = modified + deleted + clean, added
3338 remove, forget = modified + deleted + clean, added
3339 elif after:
3339 elif after:
3340 remove, forget = deleted, []
3340 remove, forget = deleted, []
3341 for f in modified + added + clean:
3341 for f in modified + added + clean:
3342 ui.warn(_('not removing %s: file still exists (use -f'
3342 ui.warn(_('not removing %s: file still exists (use -f'
3343 ' to force removal)\n') % m.rel(f))
3343 ' to force removal)\n') % m.rel(f))
3344 ret = 1
3344 ret = 1
3345 else:
3345 else:
3346 remove, forget = deleted + clean, []
3346 remove, forget = deleted + clean, []
3347 for f in modified:
3347 for f in modified:
3348 ui.warn(_('not removing %s: file is modified (use -f'
3348 ui.warn(_('not removing %s: file is modified (use -f'
3349 ' to force removal)\n') % m.rel(f))
3349 ' to force removal)\n') % m.rel(f))
3350 ret = 1
3350 ret = 1
3351 for f in added:
3351 for f in added:
3352 ui.warn(_('not removing %s: file has been marked for add (use -f'
3352 ui.warn(_('not removing %s: file has been marked for add (use -f'
3353 ' to force removal)\n') % m.rel(f))
3353 ' to force removal)\n') % m.rel(f))
3354 ret = 1
3354 ret = 1
3355
3355
3356 for f in sorted(remove + forget):
3356 for f in sorted(remove + forget):
3357 if ui.verbose or not m.exact(f):
3357 if ui.verbose or not m.exact(f):
3358 ui.status(_('removing %s\n') % m.rel(f))
3358 ui.status(_('removing %s\n') % m.rel(f))
3359
3359
3360 repo[None].forget(forget)
3360 repo[None].forget(forget)
3361 repo[None].remove(remove, unlink=not after)
3361 repo[None].remove(remove, unlink=not after)
3362 return ret
3362 return ret
3363
3363
3364 def rename(ui, repo, *pats, **opts):
3364 def rename(ui, repo, *pats, **opts):
3365 """rename files; equivalent of copy + remove
3365 """rename files; equivalent of copy + remove
3366
3366
3367 Mark dest as copies of sources; mark sources for deletion. If dest
3367 Mark dest as copies of sources; mark sources for deletion. If dest
3368 is a directory, copies are put in that directory. If dest is a
3368 is a directory, copies are put in that directory. If dest is a
3369 file, there can only be one source.
3369 file, there can only be one source.
3370
3370
3371 By default, this command copies the contents of files as they
3371 By default, this command copies the contents of files as they
3372 exist in the working directory. If invoked with -A/--after, the
3372 exist in the working directory. If invoked with -A/--after, the
3373 operation is recorded, but no copying is performed.
3373 operation is recorded, but no copying is performed.
3374
3374
3375 This command takes effect at the next commit. To undo a rename
3375 This command takes effect at the next commit. To undo a rename
3376 before that, see :hg:`revert`.
3376 before that, see :hg:`revert`.
3377
3377
3378 Returns 0 on success, 1 if errors are encountered.
3378 Returns 0 on success, 1 if errors are encountered.
3379 """
3379 """
3380 wlock = repo.wlock(False)
3380 wlock = repo.wlock(False)
3381 try:
3381 try:
3382 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3382 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3383 finally:
3383 finally:
3384 wlock.release()
3384 wlock.release()
3385
3385
3386 def resolve(ui, repo, *pats, **opts):
3386 def resolve(ui, repo, *pats, **opts):
3387 """redo merges or set/view the merge status of files
3387 """redo merges or set/view the merge status of files
3388
3388
3389 Merges with unresolved conflicts are often the result of
3389 Merges with unresolved conflicts are often the result of
3390 non-interactive merging using the ``internal:merge`` configuration
3390 non-interactive merging using the ``internal:merge`` configuration
3391 setting, or a command-line merge tool like ``diff3``. The resolve
3391 setting, or a command-line merge tool like ``diff3``. The resolve
3392 command is used to manage the files involved in a merge, after
3392 command is used to manage the files involved in a merge, after
3393 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3393 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3394 working directory must have two parents).
3394 working directory must have two parents).
3395
3395
3396 The resolve command can be used in the following ways:
3396 The resolve command can be used in the following ways:
3397
3397
3398 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3398 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3399 files, discarding any previous merge attempts. Re-merging is not
3399 files, discarding any previous merge attempts. Re-merging is not
3400 performed for files already marked as resolved. Use ``--all/-a``
3400 performed for files already marked as resolved. Use ``--all/-a``
3401 to selects all unresolved files. ``--tool`` can be used to specify
3401 to selects all unresolved files. ``--tool`` can be used to specify
3402 the merge tool used for the given files. It overrides the HGMERGE
3402 the merge tool used for the given files. It overrides the HGMERGE
3403 environment variable and your configuration files.
3403 environment variable and your configuration files.
3404
3404
3405 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3405 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3406 (e.g. after having manually fixed-up the files). The default is
3406 (e.g. after having manually fixed-up the files). The default is
3407 to mark all unresolved files.
3407 to mark all unresolved files.
3408
3408
3409 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3409 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3410 default is to mark all resolved files.
3410 default is to mark all resolved files.
3411
3411
3412 - :hg:`resolve -l`: list files which had or still have conflicts.
3412 - :hg:`resolve -l`: list files which had or still have conflicts.
3413 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3413 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3414
3414
3415 Note that Mercurial will not let you commit files with unresolved
3415 Note that Mercurial will not let you commit files with unresolved
3416 merge conflicts. You must use :hg:`resolve -m ...` before you can
3416 merge conflicts. You must use :hg:`resolve -m ...` before you can
3417 commit after a conflicting merge.
3417 commit after a conflicting merge.
3418
3418
3419 Returns 0 on success, 1 if any files fail a resolve attempt.
3419 Returns 0 on success, 1 if any files fail a resolve attempt.
3420 """
3420 """
3421
3421
3422 all, mark, unmark, show, nostatus = \
3422 all, mark, unmark, show, nostatus = \
3423 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3423 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3424
3424
3425 if (show and (mark or unmark)) or (mark and unmark):
3425 if (show and (mark or unmark)) or (mark and unmark):
3426 raise util.Abort(_("too many options specified"))
3426 raise util.Abort(_("too many options specified"))
3427 if pats and all:
3427 if pats and all:
3428 raise util.Abort(_("can't specify --all and patterns"))
3428 raise util.Abort(_("can't specify --all and patterns"))
3429 if not (all or pats or show or mark or unmark):
3429 if not (all or pats or show or mark or unmark):
3430 raise util.Abort(_('no files or directories specified; '
3430 raise util.Abort(_('no files or directories specified; '
3431 'use --all to remerge all files'))
3431 'use --all to remerge all files'))
3432
3432
3433 ms = mergemod.mergestate(repo)
3433 ms = mergemod.mergestate(repo)
3434 m = cmdutil.match(repo, pats, opts)
3434 m = cmdutil.match(repo, pats, opts)
3435 ret = 0
3435 ret = 0
3436
3436
3437 for f in ms:
3437 for f in ms:
3438 if m(f):
3438 if m(f):
3439 if show:
3439 if show:
3440 if nostatus:
3440 if nostatus:
3441 ui.write("%s\n" % f)
3441 ui.write("%s\n" % f)
3442 else:
3442 else:
3443 ui.write("%s %s\n" % (ms[f].upper(), f),
3443 ui.write("%s %s\n" % (ms[f].upper(), f),
3444 label='resolve.' +
3444 label='resolve.' +
3445 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3445 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3446 elif mark:
3446 elif mark:
3447 ms.mark(f, "r")
3447 ms.mark(f, "r")
3448 elif unmark:
3448 elif unmark:
3449 ms.mark(f, "u")
3449 ms.mark(f, "u")
3450 else:
3450 else:
3451 wctx = repo[None]
3451 wctx = repo[None]
3452 mctx = wctx.parents()[-1]
3452 mctx = wctx.parents()[-1]
3453
3453
3454 # backup pre-resolve (merge uses .orig for its own purposes)
3454 # backup pre-resolve (merge uses .orig for its own purposes)
3455 a = repo.wjoin(f)
3455 a = repo.wjoin(f)
3456 util.copyfile(a, a + ".resolve")
3456 util.copyfile(a, a + ".resolve")
3457
3457
3458 try:
3458 try:
3459 # resolve file
3459 # resolve file
3460 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3460 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3461 if ms.resolve(f, wctx, mctx):
3461 if ms.resolve(f, wctx, mctx):
3462 ret = 1
3462 ret = 1
3463 finally:
3463 finally:
3464 ui.setconfig('ui', 'forcemerge', '')
3464 ui.setconfig('ui', 'forcemerge', '')
3465
3465
3466 # replace filemerge's .orig file with our resolve file
3466 # replace filemerge's .orig file with our resolve file
3467 util.rename(a + ".resolve", a + ".orig")
3467 util.rename(a + ".resolve", a + ".orig")
3468
3468
3469 ms.commit()
3469 ms.commit()
3470 return ret
3470 return ret
3471
3471
3472 def revert(ui, repo, *pats, **opts):
3472 def revert(ui, repo, *pats, **opts):
3473 """restore individual files or directories to an earlier state
3473 """restore individual files or directories to an earlier state
3474
3474
3475 .. note::
3475 .. note::
3476 This command is most likely not what you are looking for.
3476 This command is most likely not what you are looking for.
3477 Revert will partially overwrite content in the working
3477 Revert will partially overwrite content in the working
3478 directory without changing the working directory parents. Use
3478 directory without changing the working directory parents. Use
3479 :hg:`update -r rev` to check out earlier revisions, or
3479 :hg:`update -r rev` to check out earlier revisions, or
3480 :hg:`update --clean .` to undo a merge which has added another
3480 :hg:`update --clean .` to undo a merge which has added another
3481 parent.
3481 parent.
3482
3482
3483 With no revision specified, revert the named files or directories
3483 With no revision specified, revert the named files or directories
3484 to the contents they had in the parent of the working directory.
3484 to the contents they had in the parent of the working directory.
3485 This restores the contents of the affected files to an unmodified
3485 This restores the contents of the affected files to an unmodified
3486 state and unschedules adds, removes, copies, and renames. If the
3486 state and unschedules adds, removes, copies, and renames. If the
3487 working directory has two parents, you must explicitly specify a
3487 working directory has two parents, you must explicitly specify a
3488 revision.
3488 revision.
3489
3489
3490 Using the -r/--rev option, revert the given files or directories
3490 Using the -r/--rev option, revert the given files or directories
3491 to their contents as of a specific revision. This can be helpful
3491 to their contents as of a specific revision. This can be helpful
3492 to "roll back" some or all of an earlier change. See :hg:`help
3492 to "roll back" some or all of an earlier change. See :hg:`help
3493 dates` for a list of formats valid for -d/--date.
3493 dates` for a list of formats valid for -d/--date.
3494
3494
3495 Revert modifies the working directory. It does not commit any
3495 Revert modifies the working directory. It does not commit any
3496 changes, or change the parent of the working directory. If you
3496 changes, or change the parent of the working directory. If you
3497 revert to a revision other than the parent of the working
3497 revert to a revision other than the parent of the working
3498 directory, the reverted files will thus appear modified
3498 directory, the reverted files will thus appear modified
3499 afterwards.
3499 afterwards.
3500
3500
3501 If a file has been deleted, it is restored. Files scheduled for
3501 If a file has been deleted, it is restored. Files scheduled for
3502 addition are just unscheduled and left as they are. If the
3502 addition are just unscheduled and left as they are. If the
3503 executable mode of a file was changed, it is reset.
3503 executable mode of a file was changed, it is reset.
3504
3504
3505 If names are given, all files matching the names are reverted.
3505 If names are given, all files matching the names are reverted.
3506 If no arguments are given, no files are reverted.
3506 If no arguments are given, no files are reverted.
3507
3507
3508 Modified files are saved with a .orig suffix before reverting.
3508 Modified files are saved with a .orig suffix before reverting.
3509 To disable these backups, use --no-backup.
3509 To disable these backups, use --no-backup.
3510
3510
3511 Returns 0 on success.
3511 Returns 0 on success.
3512 """
3512 """
3513
3513
3514 if opts.get("date"):
3514 if opts.get("date"):
3515 if opts.get("rev"):
3515 if opts.get("rev"):
3516 raise util.Abort(_("you can't specify a revision and a date"))
3516 raise util.Abort(_("you can't specify a revision and a date"))
3517 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3517 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3518
3518
3519 parent, p2 = repo.dirstate.parents()
3519 parent, p2 = repo.dirstate.parents()
3520 if not opts.get('rev') and p2 != nullid:
3520 if not opts.get('rev') and p2 != nullid:
3521 raise util.Abort(_('uncommitted merge - '
3521 raise util.Abort(_('uncommitted merge - '
3522 'use "hg update", see "hg help revert"'))
3522 'use "hg update", see "hg help revert"'))
3523
3523
3524 if not pats and not opts.get('all'):
3524 if not pats and not opts.get('all'):
3525 raise util.Abort(_('no files or directories specified; '
3525 raise util.Abort(_('no files or directories specified; '
3526 'use --all to revert the whole repo'))
3526 'use --all to revert the whole repo'))
3527
3527
3528 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3528 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3529 node = ctx.node()
3529 node = ctx.node()
3530 mf = ctx.manifest()
3530 mf = ctx.manifest()
3531 if node == parent:
3531 if node == parent:
3532 pmf = mf
3532 pmf = mf
3533 else:
3533 else:
3534 pmf = None
3534 pmf = None
3535
3535
3536 # need all matching names in dirstate and manifest of target rev,
3536 # need all matching names in dirstate and manifest of target rev,
3537 # so have to walk both. do not print errors if files exist in one
3537 # so have to walk both. do not print errors if files exist in one
3538 # but not other.
3538 # but not other.
3539
3539
3540 names = {}
3540 names = {}
3541
3541
3542 wlock = repo.wlock()
3542 wlock = repo.wlock()
3543 try:
3543 try:
3544 # walk dirstate.
3544 # walk dirstate.
3545
3545
3546 m = cmdutil.match(repo, pats, opts)
3546 m = cmdutil.match(repo, pats, opts)
3547 m.bad = lambda x, y: False
3547 m.bad = lambda x, y: False
3548 for abs in repo.walk(m):
3548 for abs in repo.walk(m):
3549 names[abs] = m.rel(abs), m.exact(abs)
3549 names[abs] = m.rel(abs), m.exact(abs)
3550
3550
3551 # walk target manifest.
3551 # walk target manifest.
3552
3552
3553 def badfn(path, msg):
3553 def badfn(path, msg):
3554 if path in names:
3554 if path in names:
3555 return
3555 return
3556 path_ = path + '/'
3556 path_ = path + '/'
3557 for f in names:
3557 for f in names:
3558 if f.startswith(path_):
3558 if f.startswith(path_):
3559 return
3559 return
3560 ui.warn("%s: %s\n" % (m.rel(path), msg))
3560 ui.warn("%s: %s\n" % (m.rel(path), msg))
3561
3561
3562 m = cmdutil.match(repo, pats, opts)
3562 m = cmdutil.match(repo, pats, opts)
3563 m.bad = badfn
3563 m.bad = badfn
3564 for abs in repo[node].walk(m):
3564 for abs in repo[node].walk(m):
3565 if abs not in names:
3565 if abs not in names:
3566 names[abs] = m.rel(abs), m.exact(abs)
3566 names[abs] = m.rel(abs), m.exact(abs)
3567
3567
3568 m = cmdutil.matchfiles(repo, names)
3568 m = cmdutil.matchfiles(repo, names)
3569 changes = repo.status(match=m)[:4]
3569 changes = repo.status(match=m)[:4]
3570 modified, added, removed, deleted = map(set, changes)
3570 modified, added, removed, deleted = map(set, changes)
3571
3571
3572 # if f is a rename, also revert the source
3572 # if f is a rename, also revert the source
3573 cwd = repo.getcwd()
3573 cwd = repo.getcwd()
3574 for f in added:
3574 for f in added:
3575 src = repo.dirstate.copied(f)
3575 src = repo.dirstate.copied(f)
3576 if src and src not in names and repo.dirstate[src] == 'r':
3576 if src and src not in names and repo.dirstate[src] == 'r':
3577 removed.add(src)
3577 removed.add(src)
3578 names[src] = (repo.pathto(src, cwd), True)
3578 names[src] = (repo.pathto(src, cwd), True)
3579
3579
3580 def removeforget(abs):
3580 def removeforget(abs):
3581 if repo.dirstate[abs] == 'a':
3581 if repo.dirstate[abs] == 'a':
3582 return _('forgetting %s\n')
3582 return _('forgetting %s\n')
3583 return _('removing %s\n')
3583 return _('removing %s\n')
3584
3584
3585 revert = ([], _('reverting %s\n'))
3585 revert = ([], _('reverting %s\n'))
3586 add = ([], _('adding %s\n'))
3586 add = ([], _('adding %s\n'))
3587 remove = ([], removeforget)
3587 remove = ([], removeforget)
3588 undelete = ([], _('undeleting %s\n'))
3588 undelete = ([], _('undeleting %s\n'))
3589
3589
3590 disptable = (
3590 disptable = (
3591 # dispatch table:
3591 # dispatch table:
3592 # file state
3592 # file state
3593 # action if in target manifest
3593 # action if in target manifest
3594 # action if not in target manifest
3594 # action if not in target manifest
3595 # make backup if in target manifest
3595 # make backup if in target manifest
3596 # make backup if not in target manifest
3596 # make backup if not in target manifest
3597 (modified, revert, remove, True, True),
3597 (modified, revert, remove, True, True),
3598 (added, revert, remove, True, False),
3598 (added, revert, remove, True, False),
3599 (removed, undelete, None, False, False),
3599 (removed, undelete, None, False, False),
3600 (deleted, revert, remove, False, False),
3600 (deleted, revert, remove, False, False),
3601 )
3601 )
3602
3602
3603 for abs, (rel, exact) in sorted(names.items()):
3603 for abs, (rel, exact) in sorted(names.items()):
3604 mfentry = mf.get(abs)
3604 mfentry = mf.get(abs)
3605 target = repo.wjoin(abs)
3605 target = repo.wjoin(abs)
3606 def handle(xlist, dobackup):
3606 def handle(xlist, dobackup):
3607 xlist[0].append(abs)
3607 xlist[0].append(abs)
3608 if (dobackup and not opts.get('no_backup') and
3608 if (dobackup and not opts.get('no_backup') and
3609 os.path.lexists(target)):
3609 os.path.lexists(target)):
3610 bakname = "%s.orig" % rel
3610 bakname = "%s.orig" % rel
3611 ui.note(_('saving current version of %s as %s\n') %
3611 ui.note(_('saving current version of %s as %s\n') %
3612 (rel, bakname))
3612 (rel, bakname))
3613 if not opts.get('dry_run'):
3613 if not opts.get('dry_run'):
3614 util.rename(target, bakname)
3614 util.rename(target, bakname)
3615 if ui.verbose or not exact:
3615 if ui.verbose or not exact:
3616 msg = xlist[1]
3616 msg = xlist[1]
3617 if not isinstance(msg, basestring):
3617 if not isinstance(msg, basestring):
3618 msg = msg(abs)
3618 msg = msg(abs)
3619 ui.status(msg % rel)
3619 ui.status(msg % rel)
3620 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3620 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3621 if abs not in table:
3621 if abs not in table:
3622 continue
3622 continue
3623 # file has changed in dirstate
3623 # file has changed in dirstate
3624 if mfentry:
3624 if mfentry:
3625 handle(hitlist, backuphit)
3625 handle(hitlist, backuphit)
3626 elif misslist is not None:
3626 elif misslist is not None:
3627 handle(misslist, backupmiss)
3627 handle(misslist, backupmiss)
3628 break
3628 break
3629 else:
3629 else:
3630 if abs not in repo.dirstate:
3630 if abs not in repo.dirstate:
3631 if mfentry:
3631 if mfentry:
3632 handle(add, True)
3632 handle(add, True)
3633 elif exact:
3633 elif exact:
3634 ui.warn(_('file not managed: %s\n') % rel)
3634 ui.warn(_('file not managed: %s\n') % rel)
3635 continue
3635 continue
3636 # file has not changed in dirstate
3636 # file has not changed in dirstate
3637 if node == parent:
3637 if node == parent:
3638 if exact:
3638 if exact:
3639 ui.warn(_('no changes needed to %s\n') % rel)
3639 ui.warn(_('no changes needed to %s\n') % rel)
3640 continue
3640 continue
3641 if pmf is None:
3641 if pmf is None:
3642 # only need parent manifest in this unlikely case,
3642 # only need parent manifest in this unlikely case,
3643 # so do not read by default
3643 # so do not read by default
3644 pmf = repo[parent].manifest()
3644 pmf = repo[parent].manifest()
3645 if abs in pmf:
3645 if abs in pmf:
3646 if mfentry:
3646 if mfentry:
3647 # if version of file is same in parent and target
3647 # if version of file is same in parent and target
3648 # manifests, do nothing
3648 # manifests, do nothing
3649 if (pmf[abs] != mfentry or
3649 if (pmf[abs] != mfentry or
3650 pmf.flags(abs) != mf.flags(abs)):
3650 pmf.flags(abs) != mf.flags(abs)):
3651 handle(revert, False)
3651 handle(revert, False)
3652 else:
3652 else:
3653 handle(remove, False)
3653 handle(remove, False)
3654
3654
3655 if not opts.get('dry_run'):
3655 if not opts.get('dry_run'):
3656 def checkout(f):
3656 def checkout(f):
3657 fc = ctx[f]
3657 fc = ctx[f]
3658 repo.wwrite(f, fc.data(), fc.flags())
3658 repo.wwrite(f, fc.data(), fc.flags())
3659
3659
3660 audit_path = scmutil.pathauditor(repo.root)
3660 audit_path = scmutil.pathauditor(repo.root)
3661 for f in remove[0]:
3661 for f in remove[0]:
3662 if repo.dirstate[f] == 'a':
3662 if repo.dirstate[f] == 'a':
3663 repo.dirstate.forget(f)
3663 repo.dirstate.forget(f)
3664 continue
3664 continue
3665 audit_path(f)
3665 audit_path(f)
3666 try:
3666 try:
3667 util.unlinkpath(repo.wjoin(f))
3667 util.unlinkpath(repo.wjoin(f))
3668 except OSError:
3668 except OSError:
3669 pass
3669 pass
3670 repo.dirstate.remove(f)
3670 repo.dirstate.remove(f)
3671
3671
3672 normal = None
3672 normal = None
3673 if node == parent:
3673 if node == parent:
3674 # We're reverting to our parent. If possible, we'd like status
3674 # We're reverting to our parent. If possible, we'd like status
3675 # to report the file as clean. We have to use normallookup for
3675 # to report the file as clean. We have to use normallookup for
3676 # merges to avoid losing information about merged/dirty files.
3676 # merges to avoid losing information about merged/dirty files.
3677 if p2 != nullid:
3677 if p2 != nullid:
3678 normal = repo.dirstate.normallookup
3678 normal = repo.dirstate.normallookup
3679 else:
3679 else:
3680 normal = repo.dirstate.normal
3680 normal = repo.dirstate.normal
3681 for f in revert[0]:
3681 for f in revert[0]:
3682 checkout(f)
3682 checkout(f)
3683 if normal:
3683 if normal:
3684 normal(f)
3684 normal(f)
3685
3685
3686 for f in add[0]:
3686 for f in add[0]:
3687 checkout(f)
3687 checkout(f)
3688 repo.dirstate.add(f)
3688 repo.dirstate.add(f)
3689
3689
3690 normal = repo.dirstate.normallookup
3690 normal = repo.dirstate.normallookup
3691 if node == parent and p2 == nullid:
3691 if node == parent and p2 == nullid:
3692 normal = repo.dirstate.normal
3692 normal = repo.dirstate.normal
3693 for f in undelete[0]:
3693 for f in undelete[0]:
3694 checkout(f)
3694 checkout(f)
3695 normal(f)
3695 normal(f)
3696
3696
3697 finally:
3697 finally:
3698 wlock.release()
3698 wlock.release()
3699
3699
3700 def rollback(ui, repo, **opts):
3700 def rollback(ui, repo, **opts):
3701 """roll back the last transaction (dangerous)
3701 """roll back the last transaction (dangerous)
3702
3702
3703 This command should be used with care. There is only one level of
3703 This command should be used with care. There is only one level of
3704 rollback, and there is no way to undo a rollback. It will also
3704 rollback, and there is no way to undo a rollback. It will also
3705 restore the dirstate at the time of the last transaction, losing
3705 restore the dirstate at the time of the last transaction, losing
3706 any dirstate changes since that time. This command does not alter
3706 any dirstate changes since that time. This command does not alter
3707 the working directory.
3707 the working directory.
3708
3708
3709 Transactions are used to encapsulate the effects of all commands
3709 Transactions are used to encapsulate the effects of all commands
3710 that create new changesets or propagate existing changesets into a
3710 that create new changesets or propagate existing changesets into a
3711 repository. For example, the following commands are transactional,
3711 repository. For example, the following commands are transactional,
3712 and their effects can be rolled back:
3712 and their effects can be rolled back:
3713
3713
3714 - commit
3714 - commit
3715 - import
3715 - import
3716 - pull
3716 - pull
3717 - push (with this repository as the destination)
3717 - push (with this repository as the destination)
3718 - unbundle
3718 - unbundle
3719
3719
3720 This command is not intended for use on public repositories. Once
3720 This command is not intended for use on public repositories. Once
3721 changes are visible for pull by other users, rolling a transaction
3721 changes are visible for pull by other users, rolling a transaction
3722 back locally is ineffective (someone else may already have pulled
3722 back locally is ineffective (someone else may already have pulled
3723 the changes). Furthermore, a race is possible with readers of the
3723 the changes). Furthermore, a race is possible with readers of the
3724 repository; for example an in-progress pull from the repository
3724 repository; for example an in-progress pull from the repository
3725 may fail if a rollback is performed.
3725 may fail if a rollback is performed.
3726
3726
3727 Returns 0 on success, 1 if no rollback data is available.
3727 Returns 0 on success, 1 if no rollback data is available.
3728 """
3728 """
3729 return repo.rollback(opts.get('dry_run'))
3729 return repo.rollback(opts.get('dry_run'))
3730
3730
3731 def root(ui, repo):
3731 def root(ui, repo):
3732 """print the root (top) of the current working directory
3732 """print the root (top) of the current working directory
3733
3733
3734 Print the root directory of the current repository.
3734 Print the root directory of the current repository.
3735
3735
3736 Returns 0 on success.
3736 Returns 0 on success.
3737 """
3737 """
3738 ui.write(repo.root + "\n")
3738 ui.write(repo.root + "\n")
3739
3739
3740 def serve(ui, repo, **opts):
3740 def serve(ui, repo, **opts):
3741 """start stand-alone webserver
3741 """start stand-alone webserver
3742
3742
3743 Start a local HTTP repository browser and pull server. You can use
3743 Start a local HTTP repository browser and pull server. You can use
3744 this for ad-hoc sharing and browsing of repositories. It is
3744 this for ad-hoc sharing and browsing of repositories. It is
3745 recommended to use a real web server to serve a repository for
3745 recommended to use a real web server to serve a repository for
3746 longer periods of time.
3746 longer periods of time.
3747
3747
3748 Please note that the server does not implement access control.
3748 Please note that the server does not implement access control.
3749 This means that, by default, anybody can read from the server and
3749 This means that, by default, anybody can read from the server and
3750 nobody can write to it by default. Set the ``web.allow_push``
3750 nobody can write to it by default. Set the ``web.allow_push``
3751 option to ``*`` to allow everybody to push to the server. You
3751 option to ``*`` to allow everybody to push to the server. You
3752 should use a real web server if you need to authenticate users.
3752 should use a real web server if you need to authenticate users.
3753
3753
3754 By default, the server logs accesses to stdout and errors to
3754 By default, the server logs accesses to stdout and errors to
3755 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3755 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3756 files.
3756 files.
3757
3757
3758 To have the server choose a free port number to listen on, specify
3758 To have the server choose a free port number to listen on, specify
3759 a port number of 0; in this case, the server will print the port
3759 a port number of 0; in this case, the server will print the port
3760 number it uses.
3760 number it uses.
3761
3761
3762 Returns 0 on success.
3762 Returns 0 on success.
3763 """
3763 """
3764
3764
3765 if opts["stdio"]:
3765 if opts["stdio"]:
3766 if repo is None:
3766 if repo is None:
3767 raise error.RepoError(_("There is no Mercurial repository here"
3767 raise error.RepoError(_("There is no Mercurial repository here"
3768 " (.hg not found)"))
3768 " (.hg not found)"))
3769 s = sshserver.sshserver(ui, repo)
3769 s = sshserver.sshserver(ui, repo)
3770 s.serve_forever()
3770 s.serve_forever()
3771
3771
3772 # this way we can check if something was given in the command-line
3772 # this way we can check if something was given in the command-line
3773 if opts.get('port'):
3773 if opts.get('port'):
3774 opts['port'] = util.getport(opts.get('port'))
3774 opts['port'] = util.getport(opts.get('port'))
3775
3775
3776 baseui = repo and repo.baseui or ui
3776 baseui = repo and repo.baseui or ui
3777 optlist = ("name templates style address port prefix ipv6"
3777 optlist = ("name templates style address port prefix ipv6"
3778 " accesslog errorlog certificate encoding")
3778 " accesslog errorlog certificate encoding")
3779 for o in optlist.split():
3779 for o in optlist.split():
3780 val = opts.get(o, '')
3780 val = opts.get(o, '')
3781 if val in (None, ''): # should check against default options instead
3781 if val in (None, ''): # should check against default options instead
3782 continue
3782 continue
3783 baseui.setconfig("web", o, val)
3783 baseui.setconfig("web", o, val)
3784 if repo and repo.ui != baseui:
3784 if repo and repo.ui != baseui:
3785 repo.ui.setconfig("web", o, val)
3785 repo.ui.setconfig("web", o, val)
3786
3786
3787 o = opts.get('web_conf') or opts.get('webdir_conf')
3787 o = opts.get('web_conf') or opts.get('webdir_conf')
3788 if not o:
3788 if not o:
3789 if not repo:
3789 if not repo:
3790 raise error.RepoError(_("There is no Mercurial repository"
3790 raise error.RepoError(_("There is no Mercurial repository"
3791 " here (.hg not found)"))
3791 " here (.hg not found)"))
3792 o = repo.root
3792 o = repo.root
3793
3793
3794 app = hgweb.hgweb(o, baseui=ui)
3794 app = hgweb.hgweb(o, baseui=ui)
3795
3795
3796 class service(object):
3796 class service(object):
3797 def init(self):
3797 def init(self):
3798 util.setsignalhandler()
3798 util.setsignalhandler()
3799 self.httpd = hgweb.server.create_server(ui, app)
3799 self.httpd = hgweb.server.create_server(ui, app)
3800
3800
3801 if opts['port'] and not ui.verbose:
3801 if opts['port'] and not ui.verbose:
3802 return
3802 return
3803
3803
3804 if self.httpd.prefix:
3804 if self.httpd.prefix:
3805 prefix = self.httpd.prefix.strip('/') + '/'
3805 prefix = self.httpd.prefix.strip('/') + '/'
3806 else:
3806 else:
3807 prefix = ''
3807 prefix = ''
3808
3808
3809 port = ':%d' % self.httpd.port
3809 port = ':%d' % self.httpd.port
3810 if port == ':80':
3810 if port == ':80':
3811 port = ''
3811 port = ''
3812
3812
3813 bindaddr = self.httpd.addr
3813 bindaddr = self.httpd.addr
3814 if bindaddr == '0.0.0.0':
3814 if bindaddr == '0.0.0.0':
3815 bindaddr = '*'
3815 bindaddr = '*'
3816 elif ':' in bindaddr: # IPv6
3816 elif ':' in bindaddr: # IPv6
3817 bindaddr = '[%s]' % bindaddr
3817 bindaddr = '[%s]' % bindaddr
3818
3818
3819 fqaddr = self.httpd.fqaddr
3819 fqaddr = self.httpd.fqaddr
3820 if ':' in fqaddr:
3820 if ':' in fqaddr:
3821 fqaddr = '[%s]' % fqaddr
3821 fqaddr = '[%s]' % fqaddr
3822 if opts['port']:
3822 if opts['port']:
3823 write = ui.status
3823 write = ui.status
3824 else:
3824 else:
3825 write = ui.write
3825 write = ui.write
3826 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3826 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3827 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3827 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3828
3828
3829 def run(self):
3829 def run(self):
3830 self.httpd.serve_forever()
3830 self.httpd.serve_forever()
3831
3831
3832 service = service()
3832 service = service()
3833
3833
3834 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3834 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3835
3835
3836 def status(ui, repo, *pats, **opts):
3836 def status(ui, repo, *pats, **opts):
3837 """show changed files in the working directory
3837 """show changed files in the working directory
3838
3838
3839 Show status of files in the repository. If names are given, only
3839 Show status of files in the repository. If names are given, only
3840 files that match are shown. Files that are clean or ignored or
3840 files that match are shown. Files that are clean or ignored or
3841 the source of a copy/move operation, are not listed unless
3841 the source of a copy/move operation, are not listed unless
3842 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3842 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3843 Unless options described with "show only ..." are given, the
3843 Unless options described with "show only ..." are given, the
3844 options -mardu are used.
3844 options -mardu are used.
3845
3845
3846 Option -q/--quiet hides untracked (unknown and ignored) files
3846 Option -q/--quiet hides untracked (unknown and ignored) files
3847 unless explicitly requested with -u/--unknown or -i/--ignored.
3847 unless explicitly requested with -u/--unknown or -i/--ignored.
3848
3848
3849 .. note::
3849 .. note::
3850 status may appear to disagree with diff if permissions have
3850 status may appear to disagree with diff if permissions have
3851 changed or a merge has occurred. The standard diff format does
3851 changed or a merge has occurred. The standard diff format does
3852 not report permission changes and diff only reports changes
3852 not report permission changes and diff only reports changes
3853 relative to one merge parent.
3853 relative to one merge parent.
3854
3854
3855 If one revision is given, it is used as the base revision.
3855 If one revision is given, it is used as the base revision.
3856 If two revisions are given, the differences between them are
3856 If two revisions are given, the differences between them are
3857 shown. The --change option can also be used as a shortcut to list
3857 shown. The --change option can also be used as a shortcut to list
3858 the changed files of a revision from its first parent.
3858 the changed files of a revision from its first parent.
3859
3859
3860 The codes used to show the status of files are::
3860 The codes used to show the status of files are::
3861
3861
3862 M = modified
3862 M = modified
3863 A = added
3863 A = added
3864 R = removed
3864 R = removed
3865 C = clean
3865 C = clean
3866 ! = missing (deleted by non-hg command, but still tracked)
3866 ! = missing (deleted by non-hg command, but still tracked)
3867 ? = not tracked
3867 ? = not tracked
3868 I = ignored
3868 I = ignored
3869 = origin of the previous file listed as A (added)
3869 = origin of the previous file listed as A (added)
3870
3870
3871 Returns 0 on success.
3871 Returns 0 on success.
3872 """
3872 """
3873
3873
3874 revs = opts.get('rev')
3874 revs = opts.get('rev')
3875 change = opts.get('change')
3875 change = opts.get('change')
3876
3876
3877 if revs and change:
3877 if revs and change:
3878 msg = _('cannot specify --rev and --change at the same time')
3878 msg = _('cannot specify --rev and --change at the same time')
3879 raise util.Abort(msg)
3879 raise util.Abort(msg)
3880 elif change:
3880 elif change:
3881 node2 = repo.lookup(change)
3881 node2 = repo.lookup(change)
3882 node1 = repo[node2].p1().node()
3882 node1 = repo[node2].p1().node()
3883 else:
3883 else:
3884 node1, node2 = cmdutil.revpair(repo, revs)
3884 node1, node2 = cmdutil.revpair(repo, revs)
3885
3885
3886 cwd = (pats and repo.getcwd()) or ''
3886 cwd = (pats and repo.getcwd()) or ''
3887 end = opts.get('print0') and '\0' or '\n'
3887 end = opts.get('print0') and '\0' or '\n'
3888 copy = {}
3888 copy = {}
3889 states = 'modified added removed deleted unknown ignored clean'.split()
3889 states = 'modified added removed deleted unknown ignored clean'.split()
3890 show = [k for k in states if opts.get(k)]
3890 show = [k for k in states if opts.get(k)]
3891 if opts.get('all'):
3891 if opts.get('all'):
3892 show += ui.quiet and (states[:4] + ['clean']) or states
3892 show += ui.quiet and (states[:4] + ['clean']) or states
3893 if not show:
3893 if not show:
3894 show = ui.quiet and states[:4] or states[:5]
3894 show = ui.quiet and states[:4] or states[:5]
3895
3895
3896 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3896 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3897 'ignored' in show, 'clean' in show, 'unknown' in show,
3897 'ignored' in show, 'clean' in show, 'unknown' in show,
3898 opts.get('subrepos'))
3898 opts.get('subrepos'))
3899 changestates = zip(states, 'MAR!?IC', stat)
3899 changestates = zip(states, 'MAR!?IC', stat)
3900
3900
3901 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3901 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3902 ctxn = repo[nullid]
3902 ctxn = repo[nullid]
3903 ctx1 = repo[node1]
3903 ctx1 = repo[node1]
3904 ctx2 = repo[node2]
3904 ctx2 = repo[node2]
3905 added = stat[1]
3905 added = stat[1]
3906 if node2 is None:
3906 if node2 is None:
3907 added = stat[0] + stat[1] # merged?
3907 added = stat[0] + stat[1] # merged?
3908
3908
3909 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3909 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3910 if k in added:
3910 if k in added:
3911 copy[k] = v
3911 copy[k] = v
3912 elif v in added:
3912 elif v in added:
3913 copy[v] = k
3913 copy[v] = k
3914
3914
3915 for state, char, files in changestates:
3915 for state, char, files in changestates:
3916 if state in show:
3916 if state in show:
3917 format = "%s %%s%s" % (char, end)
3917 format = "%s %%s%s" % (char, end)
3918 if opts.get('no_status'):
3918 if opts.get('no_status'):
3919 format = "%%s%s" % end
3919 format = "%%s%s" % end
3920
3920
3921 for f in files:
3921 for f in files:
3922 ui.write(format % repo.pathto(f, cwd),
3922 ui.write(format % repo.pathto(f, cwd),
3923 label='status.' + state)
3923 label='status.' + state)
3924 if f in copy:
3924 if f in copy:
3925 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3925 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3926 label='status.copied')
3926 label='status.copied')
3927
3927
3928 def summary(ui, repo, **opts):
3928 def summary(ui, repo, **opts):
3929 """summarize working directory state
3929 """summarize working directory state
3930
3930
3931 This generates a brief summary of the working directory state,
3931 This generates a brief summary of the working directory state,
3932 including parents, branch, commit status, and available updates.
3932 including parents, branch, commit status, and available updates.
3933
3933
3934 With the --remote option, this will check the default paths for
3934 With the --remote option, this will check the default paths for
3935 incoming and outgoing changes. This can be time-consuming.
3935 incoming and outgoing changes. This can be time-consuming.
3936
3936
3937 Returns 0 on success.
3937 Returns 0 on success.
3938 """
3938 """
3939
3939
3940 ctx = repo[None]
3940 ctx = repo[None]
3941 parents = ctx.parents()
3941 parents = ctx.parents()
3942 pnode = parents[0].node()
3942 pnode = parents[0].node()
3943
3943
3944 for p in parents:
3944 for p in parents:
3945 # label with log.changeset (instead of log.parent) since this
3945 # label with log.changeset (instead of log.parent) since this
3946 # shows a working directory parent *changeset*:
3946 # shows a working directory parent *changeset*:
3947 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3947 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3948 label='log.changeset')
3948 label='log.changeset')
3949 ui.write(' '.join(p.tags()), label='log.tag')
3949 ui.write(' '.join(p.tags()), label='log.tag')
3950 if p.bookmarks():
3950 if p.bookmarks():
3951 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
3951 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
3952 if p.rev() == -1:
3952 if p.rev() == -1:
3953 if not len(repo):
3953 if not len(repo):
3954 ui.write(_(' (empty repository)'))
3954 ui.write(_(' (empty repository)'))
3955 else:
3955 else:
3956 ui.write(_(' (no revision checked out)'))
3956 ui.write(_(' (no revision checked out)'))
3957 ui.write('\n')
3957 ui.write('\n')
3958 if p.description():
3958 if p.description():
3959 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3959 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3960 label='log.summary')
3960 label='log.summary')
3961
3961
3962 branch = ctx.branch()
3962 branch = ctx.branch()
3963 bheads = repo.branchheads(branch)
3963 bheads = repo.branchheads(branch)
3964 m = _('branch: %s\n') % branch
3964 m = _('branch: %s\n') % branch
3965 if branch != 'default':
3965 if branch != 'default':
3966 ui.write(m, label='log.branch')
3966 ui.write(m, label='log.branch')
3967 else:
3967 else:
3968 ui.status(m, label='log.branch')
3968 ui.status(m, label='log.branch')
3969
3969
3970 st = list(repo.status(unknown=True))[:6]
3970 st = list(repo.status(unknown=True))[:6]
3971
3971
3972 c = repo.dirstate.copies()
3972 c = repo.dirstate.copies()
3973 copied, renamed = [], []
3973 copied, renamed = [], []
3974 for d, s in c.iteritems():
3974 for d, s in c.iteritems():
3975 if s in st[2]:
3975 if s in st[2]:
3976 st[2].remove(s)
3976 st[2].remove(s)
3977 renamed.append(d)
3977 renamed.append(d)
3978 else:
3978 else:
3979 copied.append(d)
3979 copied.append(d)
3980 if d in st[1]:
3980 if d in st[1]:
3981 st[1].remove(d)
3981 st[1].remove(d)
3982 st.insert(3, renamed)
3982 st.insert(3, renamed)
3983 st.insert(4, copied)
3983 st.insert(4, copied)
3984
3984
3985 ms = mergemod.mergestate(repo)
3985 ms = mergemod.mergestate(repo)
3986 st.append([f for f in ms if ms[f] == 'u'])
3986 st.append([f for f in ms if ms[f] == 'u'])
3987
3987
3988 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3988 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3989 st.append(subs)
3989 st.append(subs)
3990
3990
3991 labels = [ui.label(_('%d modified'), 'status.modified'),
3991 labels = [ui.label(_('%d modified'), 'status.modified'),
3992 ui.label(_('%d added'), 'status.added'),
3992 ui.label(_('%d added'), 'status.added'),
3993 ui.label(_('%d removed'), 'status.removed'),
3993 ui.label(_('%d removed'), 'status.removed'),
3994 ui.label(_('%d renamed'), 'status.copied'),
3994 ui.label(_('%d renamed'), 'status.copied'),
3995 ui.label(_('%d copied'), 'status.copied'),
3995 ui.label(_('%d copied'), 'status.copied'),
3996 ui.label(_('%d deleted'), 'status.deleted'),
3996 ui.label(_('%d deleted'), 'status.deleted'),
3997 ui.label(_('%d unknown'), 'status.unknown'),
3997 ui.label(_('%d unknown'), 'status.unknown'),
3998 ui.label(_('%d ignored'), 'status.ignored'),
3998 ui.label(_('%d ignored'), 'status.ignored'),
3999 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3999 ui.label(_('%d unresolved'), 'resolve.unresolved'),
4000 ui.label(_('%d subrepos'), 'status.modified')]
4000 ui.label(_('%d subrepos'), 'status.modified')]
4001 t = []
4001 t = []
4002 for s, l in zip(st, labels):
4002 for s, l in zip(st, labels):
4003 if s:
4003 if s:
4004 t.append(l % len(s))
4004 t.append(l % len(s))
4005
4005
4006 t = ', '.join(t)
4006 t = ', '.join(t)
4007 cleanworkdir = False
4007 cleanworkdir = False
4008
4008
4009 if len(parents) > 1:
4009 if len(parents) > 1:
4010 t += _(' (merge)')
4010 t += _(' (merge)')
4011 elif branch != parents[0].branch():
4011 elif branch != parents[0].branch():
4012 t += _(' (new branch)')
4012 t += _(' (new branch)')
4013 elif (parents[0].extra().get('close') and
4013 elif (parents[0].extra().get('close') and
4014 pnode in repo.branchheads(branch, closed=True)):
4014 pnode in repo.branchheads(branch, closed=True)):
4015 t += _(' (head closed)')
4015 t += _(' (head closed)')
4016 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4016 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4017 t += _(' (clean)')
4017 t += _(' (clean)')
4018 cleanworkdir = True
4018 cleanworkdir = True
4019 elif pnode not in bheads:
4019 elif pnode not in bheads:
4020 t += _(' (new branch head)')
4020 t += _(' (new branch head)')
4021
4021
4022 if cleanworkdir:
4022 if cleanworkdir:
4023 ui.status(_('commit: %s\n') % t.strip())
4023 ui.status(_('commit: %s\n') % t.strip())
4024 else:
4024 else:
4025 ui.write(_('commit: %s\n') % t.strip())
4025 ui.write(_('commit: %s\n') % t.strip())
4026
4026
4027 # all ancestors of branch heads - all ancestors of parent = new csets
4027 # all ancestors of branch heads - all ancestors of parent = new csets
4028 new = [0] * len(repo)
4028 new = [0] * len(repo)
4029 cl = repo.changelog
4029 cl = repo.changelog
4030 for a in [cl.rev(n) for n in bheads]:
4030 for a in [cl.rev(n) for n in bheads]:
4031 new[a] = 1
4031 new[a] = 1
4032 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
4032 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
4033 new[a] = 1
4033 new[a] = 1
4034 for a in [p.rev() for p in parents]:
4034 for a in [p.rev() for p in parents]:
4035 if a >= 0:
4035 if a >= 0:
4036 new[a] = 0
4036 new[a] = 0
4037 for a in cl.ancestors(*[p.rev() for p in parents]):
4037 for a in cl.ancestors(*[p.rev() for p in parents]):
4038 new[a] = 0
4038 new[a] = 0
4039 new = sum(new)
4039 new = sum(new)
4040
4040
4041 if new == 0:
4041 if new == 0:
4042 ui.status(_('update: (current)\n'))
4042 ui.status(_('update: (current)\n'))
4043 elif pnode not in bheads:
4043 elif pnode not in bheads:
4044 ui.write(_('update: %d new changesets (update)\n') % new)
4044 ui.write(_('update: %d new changesets (update)\n') % new)
4045 else:
4045 else:
4046 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4046 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4047 (new, len(bheads)))
4047 (new, len(bheads)))
4048
4048
4049 if opts.get('remote'):
4049 if opts.get('remote'):
4050 t = []
4050 t = []
4051 source, branches = hg.parseurl(ui.expandpath('default'))
4051 source, branches = hg.parseurl(ui.expandpath('default'))
4052 other = hg.repository(hg.remoteui(repo, {}), source)
4052 other = hg.repository(hg.remoteui(repo, {}), source)
4053 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4053 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4054 ui.debug('comparing with %s\n' % util.hidepassword(source))
4054 ui.debug('comparing with %s\n' % util.hidepassword(source))
4055 repo.ui.pushbuffer()
4055 repo.ui.pushbuffer()
4056 commoninc = discovery.findcommonincoming(repo, other)
4056 commoninc = discovery.findcommonincoming(repo, other)
4057 _common, incoming, _rheads = commoninc
4057 _common, incoming, _rheads = commoninc
4058 repo.ui.popbuffer()
4058 repo.ui.popbuffer()
4059 if incoming:
4059 if incoming:
4060 t.append(_('1 or more incoming'))
4060 t.append(_('1 or more incoming'))
4061
4061
4062 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4062 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4063 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4063 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4064 if source != dest:
4064 if source != dest:
4065 other = hg.repository(hg.remoteui(repo, {}), dest)
4065 other = hg.repository(hg.remoteui(repo, {}), dest)
4066 commoninc = None
4066 commoninc = None
4067 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4067 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4068 repo.ui.pushbuffer()
4068 repo.ui.pushbuffer()
4069 common, outheads = discovery.findcommonoutgoing(repo, other,
4069 common, outheads = discovery.findcommonoutgoing(repo, other,
4070 commoninc=commoninc)
4070 commoninc=commoninc)
4071 repo.ui.popbuffer()
4071 repo.ui.popbuffer()
4072 o = repo.changelog.findmissing(common=common, heads=outheads)
4072 o = repo.changelog.findmissing(common=common, heads=outheads)
4073 if o:
4073 if o:
4074 t.append(_('%d outgoing') % len(o))
4074 t.append(_('%d outgoing') % len(o))
4075 if 'bookmarks' in other.listkeys('namespaces'):
4075 if 'bookmarks' in other.listkeys('namespaces'):
4076 lmarks = repo.listkeys('bookmarks')
4076 lmarks = repo.listkeys('bookmarks')
4077 rmarks = other.listkeys('bookmarks')
4077 rmarks = other.listkeys('bookmarks')
4078 diff = set(rmarks) - set(lmarks)
4078 diff = set(rmarks) - set(lmarks)
4079 if len(diff) > 0:
4079 if len(diff) > 0:
4080 t.append(_('%d incoming bookmarks') % len(diff))
4080 t.append(_('%d incoming bookmarks') % len(diff))
4081 diff = set(lmarks) - set(rmarks)
4081 diff = set(lmarks) - set(rmarks)
4082 if len(diff) > 0:
4082 if len(diff) > 0:
4083 t.append(_('%d outgoing bookmarks') % len(diff))
4083 t.append(_('%d outgoing bookmarks') % len(diff))
4084
4084
4085 if t:
4085 if t:
4086 ui.write(_('remote: %s\n') % (', '.join(t)))
4086 ui.write(_('remote: %s\n') % (', '.join(t)))
4087 else:
4087 else:
4088 ui.status(_('remote: (synced)\n'))
4088 ui.status(_('remote: (synced)\n'))
4089
4089
4090 def tag(ui, repo, name1, *names, **opts):
4090 def tag(ui, repo, name1, *names, **opts):
4091 """add one or more tags for the current or given revision
4091 """add one or more tags for the current or given revision
4092
4092
4093 Name a particular revision using <name>.
4093 Name a particular revision using <name>.
4094
4094
4095 Tags are used to name particular revisions of the repository and are
4095 Tags are used to name particular revisions of the repository and are
4096 very useful to compare different revisions, to go back to significant
4096 very useful to compare different revisions, to go back to significant
4097 earlier versions or to mark branch points as releases, etc. Changing
4097 earlier versions or to mark branch points as releases, etc. Changing
4098 an existing tag is normally disallowed; use -f/--force to override.
4098 an existing tag is normally disallowed; use -f/--force to override.
4099
4099
4100 If no revision is given, the parent of the working directory is
4100 If no revision is given, the parent of the working directory is
4101 used, or tip if no revision is checked out.
4101 used, or tip if no revision is checked out.
4102
4102
4103 To facilitate version control, distribution, and merging of tags,
4103 To facilitate version control, distribution, and merging of tags,
4104 they are stored as a file named ".hgtags" which is managed similarly
4104 they are stored as a file named ".hgtags" which is managed similarly
4105 to other project files and can be hand-edited if necessary. This
4105 to other project files and can be hand-edited if necessary. This
4106 also means that tagging creates a new commit. The file
4106 also means that tagging creates a new commit. The file
4107 ".hg/localtags" is used for local tags (not shared among
4107 ".hg/localtags" is used for local tags (not shared among
4108 repositories).
4108 repositories).
4109
4109
4110 Tag commits are usually made at the head of a branch. If the parent
4110 Tag commits are usually made at the head of a branch. If the parent
4111 of the working directory is not a branch head, :hg:`tag` aborts; use
4111 of the working directory is not a branch head, :hg:`tag` aborts; use
4112 -f/--force to force the tag commit to be based on a non-head
4112 -f/--force to force the tag commit to be based on a non-head
4113 changeset.
4113 changeset.
4114
4114
4115 See :hg:`help dates` for a list of formats valid for -d/--date.
4115 See :hg:`help dates` for a list of formats valid for -d/--date.
4116
4116
4117 Since tag names have priority over branch names during revision
4117 Since tag names have priority over branch names during revision
4118 lookup, using an existing branch name as a tag name is discouraged.
4118 lookup, using an existing branch name as a tag name is discouraged.
4119
4119
4120 Returns 0 on success.
4120 Returns 0 on success.
4121 """
4121 """
4122
4122
4123 rev_ = "."
4123 rev_ = "."
4124 names = [t.strip() for t in (name1,) + names]
4124 names = [t.strip() for t in (name1,) + names]
4125 if len(names) != len(set(names)):
4125 if len(names) != len(set(names)):
4126 raise util.Abort(_('tag names must be unique'))
4126 raise util.Abort(_('tag names must be unique'))
4127 for n in names:
4127 for n in names:
4128 if n in ['tip', '.', 'null']:
4128 if n in ['tip', '.', 'null']:
4129 raise util.Abort(_("the name '%s' is reserved") % n)
4129 raise util.Abort(_("the name '%s' is reserved") % n)
4130 if not n:
4130 if not n:
4131 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4131 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4132 if opts.get('rev') and opts.get('remove'):
4132 if opts.get('rev') and opts.get('remove'):
4133 raise util.Abort(_("--rev and --remove are incompatible"))
4133 raise util.Abort(_("--rev and --remove are incompatible"))
4134 if opts.get('rev'):
4134 if opts.get('rev'):
4135 rev_ = opts['rev']
4135 rev_ = opts['rev']
4136 message = opts.get('message')
4136 message = opts.get('message')
4137 if opts.get('remove'):
4137 if opts.get('remove'):
4138 expectedtype = opts.get('local') and 'local' or 'global'
4138 expectedtype = opts.get('local') and 'local' or 'global'
4139 for n in names:
4139 for n in names:
4140 if not repo.tagtype(n):
4140 if not repo.tagtype(n):
4141 raise util.Abort(_("tag '%s' does not exist") % n)
4141 raise util.Abort(_("tag '%s' does not exist") % n)
4142 if repo.tagtype(n) != expectedtype:
4142 if repo.tagtype(n) != expectedtype:
4143 if expectedtype == 'global':
4143 if expectedtype == 'global':
4144 raise util.Abort(_("tag '%s' is not a global tag") % n)
4144 raise util.Abort(_("tag '%s' is not a global tag") % n)
4145 else:
4145 else:
4146 raise util.Abort(_("tag '%s' is not a local tag") % n)
4146 raise util.Abort(_("tag '%s' is not a local tag") % n)
4147 rev_ = nullid
4147 rev_ = nullid
4148 if not message:
4148 if not message:
4149 # we don't translate commit messages
4149 # we don't translate commit messages
4150 message = 'Removed tag %s' % ', '.join(names)
4150 message = 'Removed tag %s' % ', '.join(names)
4151 elif not opts.get('force'):
4151 elif not opts.get('force'):
4152 for n in names:
4152 for n in names:
4153 if n in repo.tags():
4153 if n in repo.tags():
4154 raise util.Abort(_("tag '%s' already exists "
4154 raise util.Abort(_("tag '%s' already exists "
4155 "(use -f to force)") % n)
4155 "(use -f to force)") % n)
4156 if not opts.get('local'):
4156 if not opts.get('local'):
4157 p1, p2 = repo.dirstate.parents()
4157 p1, p2 = repo.dirstate.parents()
4158 if p2 != nullid:
4158 if p2 != nullid:
4159 raise util.Abort(_('uncommitted merge'))
4159 raise util.Abort(_('uncommitted merge'))
4160 bheads = repo.branchheads()
4160 bheads = repo.branchheads()
4161 if not opts.get('force') and bheads and p1 not in bheads:
4161 if not opts.get('force') and bheads and p1 not in bheads:
4162 raise util.Abort(_('not at a branch head (use -f to force)'))
4162 raise util.Abort(_('not at a branch head (use -f to force)'))
4163 r = cmdutil.revsingle(repo, rev_).node()
4163 r = cmdutil.revsingle(repo, rev_).node()
4164
4164
4165 if not message:
4165 if not message:
4166 # we don't translate commit messages
4166 # we don't translate commit messages
4167 message = ('Added tag %s for changeset %s' %
4167 message = ('Added tag %s for changeset %s' %
4168 (', '.join(names), short(r)))
4168 (', '.join(names), short(r)))
4169
4169
4170 date = opts.get('date')
4170 date = opts.get('date')
4171 if date:
4171 if date:
4172 date = util.parsedate(date)
4172 date = util.parsedate(date)
4173
4173
4174 if opts.get('edit'):
4174 if opts.get('edit'):
4175 message = ui.edit(message, ui.username())
4175 message = ui.edit(message, ui.username())
4176
4176
4177 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4177 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4178
4178
4179 def tags(ui, repo):
4179 def tags(ui, repo):
4180 """list repository tags
4180 """list repository tags
4181
4181
4182 This lists both regular and local tags. When the -v/--verbose
4182 This lists both regular and local tags. When the -v/--verbose
4183 switch is used, a third column "local" is printed for local tags.
4183 switch is used, a third column "local" is printed for local tags.
4184
4184
4185 Returns 0 on success.
4185 Returns 0 on success.
4186 """
4186 """
4187
4187
4188 hexfunc = ui.debugflag and hex or short
4188 hexfunc = ui.debugflag and hex or short
4189 tagtype = ""
4189 tagtype = ""
4190
4190
4191 for t, n in reversed(repo.tagslist()):
4191 for t, n in reversed(repo.tagslist()):
4192 if ui.quiet:
4192 if ui.quiet:
4193 ui.write("%s\n" % t)
4193 ui.write("%s\n" % t)
4194 continue
4194 continue
4195
4195
4196 hn = hexfunc(n)
4196 hn = hexfunc(n)
4197 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4197 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4198 spaces = " " * (30 - encoding.colwidth(t))
4198 spaces = " " * (30 - encoding.colwidth(t))
4199
4199
4200 if ui.verbose:
4200 if ui.verbose:
4201 if repo.tagtype(t) == 'local':
4201 if repo.tagtype(t) == 'local':
4202 tagtype = " local"
4202 tagtype = " local"
4203 else:
4203 else:
4204 tagtype = ""
4204 tagtype = ""
4205 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4205 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4206
4206
4207 def tip(ui, repo, **opts):
4207 def tip(ui, repo, **opts):
4208 """show the tip revision
4208 """show the tip revision
4209
4209
4210 The tip revision (usually just called the tip) is the changeset
4210 The tip revision (usually just called the tip) is the changeset
4211 most recently added to the repository (and therefore the most
4211 most recently added to the repository (and therefore the most
4212 recently changed head).
4212 recently changed head).
4213
4213
4214 If you have just made a commit, that commit will be the tip. If
4214 If you have just made a commit, that commit will be the tip. If
4215 you have just pulled changes from another repository, the tip of
4215 you have just pulled changes from another repository, the tip of
4216 that repository becomes the current tip. The "tip" tag is special
4216 that repository becomes the current tip. The "tip" tag is special
4217 and cannot be renamed or assigned to a different changeset.
4217 and cannot be renamed or assigned to a different changeset.
4218
4218
4219 Returns 0 on success.
4219 Returns 0 on success.
4220 """
4220 """
4221 displayer = cmdutil.show_changeset(ui, repo, opts)
4221 displayer = cmdutil.show_changeset(ui, repo, opts)
4222 displayer.show(repo[len(repo) - 1])
4222 displayer.show(repo[len(repo) - 1])
4223 displayer.close()
4223 displayer.close()
4224
4224
4225 def unbundle(ui, repo, fname1, *fnames, **opts):
4225 def unbundle(ui, repo, fname1, *fnames, **opts):
4226 """apply one or more changegroup files
4226 """apply one or more changegroup files
4227
4227
4228 Apply one or more compressed changegroup files generated by the
4228 Apply one or more compressed changegroup files generated by the
4229 bundle command.
4229 bundle command.
4230
4230
4231 Returns 0 on success, 1 if an update has unresolved files.
4231 Returns 0 on success, 1 if an update has unresolved files.
4232 """
4232 """
4233 fnames = (fname1,) + fnames
4233 fnames = (fname1,) + fnames
4234
4234
4235 lock = repo.lock()
4235 lock = repo.lock()
4236 wc = repo['.']
4236 wc = repo['.']
4237 try:
4237 try:
4238 for fname in fnames:
4238 for fname in fnames:
4239 f = url.open(ui, fname)
4239 f = url.open(ui, fname)
4240 gen = changegroup.readbundle(f, fname)
4240 gen = changegroup.readbundle(f, fname)
4241 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4241 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4242 lock=lock)
4242 lock=lock)
4243 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
4243 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
4244 finally:
4244 finally:
4245 lock.release()
4245 lock.release()
4246 return postincoming(ui, repo, modheads, opts.get('update'), None)
4246 return postincoming(ui, repo, modheads, opts.get('update'), None)
4247
4247
4248 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4248 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4249 """update working directory (or switch revisions)
4249 """update working directory (or switch revisions)
4250
4250
4251 Update the repository's working directory to the specified
4251 Update the repository's working directory to the specified
4252 changeset. If no changeset is specified, update to the tip of the
4252 changeset. If no changeset is specified, update to the tip of the
4253 current named branch.
4253 current named branch.
4254
4254
4255 If the changeset is not a descendant of the working directory's
4255 If the changeset is not a descendant of the working directory's
4256 parent, the update is aborted. With the -c/--check option, the
4256 parent, the update is aborted. With the -c/--check option, the
4257 working directory is checked for uncommitted changes; if none are
4257 working directory is checked for uncommitted changes; if none are
4258 found, the working directory is updated to the specified
4258 found, the working directory is updated to the specified
4259 changeset.
4259 changeset.
4260
4260
4261 The following rules apply when the working directory contains
4261 The following rules apply when the working directory contains
4262 uncommitted changes:
4262 uncommitted changes:
4263
4263
4264 1. If neither -c/--check nor -C/--clean is specified, and if
4264 1. If neither -c/--check nor -C/--clean is specified, and if
4265 the requested changeset is an ancestor or descendant of
4265 the requested changeset is an ancestor or descendant of
4266 the working directory's parent, the uncommitted changes
4266 the working directory's parent, the uncommitted changes
4267 are merged into the requested changeset and the merged
4267 are merged into the requested changeset and the merged
4268 result is left uncommitted. If the requested changeset is
4268 result is left uncommitted. If the requested changeset is
4269 not an ancestor or descendant (that is, it is on another
4269 not an ancestor or descendant (that is, it is on another
4270 branch), the update is aborted and the uncommitted changes
4270 branch), the update is aborted and the uncommitted changes
4271 are preserved.
4271 are preserved.
4272
4272
4273 2. With the -c/--check option, the update is aborted and the
4273 2. With the -c/--check option, the update is aborted and the
4274 uncommitted changes are preserved.
4274 uncommitted changes are preserved.
4275
4275
4276 3. With the -C/--clean option, uncommitted changes are discarded and
4276 3. With the -C/--clean option, uncommitted changes are discarded and
4277 the working directory is updated to the requested changeset.
4277 the working directory is updated to the requested changeset.
4278
4278
4279 Use null as the changeset to remove the working directory (like
4279 Use null as the changeset to remove the working directory (like
4280 :hg:`clone -U`).
4280 :hg:`clone -U`).
4281
4281
4282 If you want to update just one file to an older changeset, use
4282 If you want to update just one file to an older changeset, use
4283 :hg:`revert`.
4283 :hg:`revert`.
4284
4284
4285 See :hg:`help dates` for a list of formats valid for -d/--date.
4285 See :hg:`help dates` for a list of formats valid for -d/--date.
4286
4286
4287 Returns 0 on success, 1 if there are unresolved files.
4287 Returns 0 on success, 1 if there are unresolved files.
4288 """
4288 """
4289 if rev and node:
4289 if rev and node:
4290 raise util.Abort(_("please specify just one revision"))
4290 raise util.Abort(_("please specify just one revision"))
4291
4291
4292 if rev is None or rev == '':
4292 if rev is None or rev == '':
4293 rev = node
4293 rev = node
4294
4294
4295 # if we defined a bookmark, we have to remember the original bookmark name
4295 # if we defined a bookmark, we have to remember the original bookmark name
4296 brev = rev
4296 brev = rev
4297 rev = cmdutil.revsingle(repo, rev, rev).rev()
4297 rev = cmdutil.revsingle(repo, rev, rev).rev()
4298
4298
4299 if check and clean:
4299 if check and clean:
4300 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4300 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4301
4301
4302 if check:
4302 if check:
4303 # we could use dirty() but we can ignore merge and branch trivia
4303 # we could use dirty() but we can ignore merge and branch trivia
4304 c = repo[None]
4304 c = repo[None]
4305 if c.modified() or c.added() or c.removed():
4305 if c.modified() or c.added() or c.removed():
4306 raise util.Abort(_("uncommitted local changes"))
4306 raise util.Abort(_("uncommitted local changes"))
4307
4307
4308 if date:
4308 if date:
4309 if rev is not None:
4309 if rev is not None:
4310 raise util.Abort(_("you can't specify a revision and a date"))
4310 raise util.Abort(_("you can't specify a revision and a date"))
4311 rev = cmdutil.finddate(ui, repo, date)
4311 rev = cmdutil.finddate(ui, repo, date)
4312
4312
4313 if clean or check:
4313 if clean or check:
4314 ret = hg.clean(repo, rev)
4314 ret = hg.clean(repo, rev)
4315 else:
4315 else:
4316 ret = hg.update(repo, rev)
4316 ret = hg.update(repo, rev)
4317
4317
4318 if brev in repo._bookmarks:
4318 if brev in repo._bookmarks:
4319 bookmarks.setcurrent(repo, brev)
4319 bookmarks.setcurrent(repo, brev)
4320
4320
4321 return ret
4321 return ret
4322
4322
4323 def verify(ui, repo):
4323 def verify(ui, repo):
4324 """verify the integrity of the repository
4324 """verify the integrity of the repository
4325
4325
4326 Verify the integrity of the current repository.
4326 Verify the integrity of the current repository.
4327
4327
4328 This will perform an extensive check of the repository's
4328 This will perform an extensive check of the repository's
4329 integrity, validating the hashes and checksums of each entry in
4329 integrity, validating the hashes and checksums of each entry in
4330 the changelog, manifest, and tracked files, as well as the
4330 the changelog, manifest, and tracked files, as well as the
4331 integrity of their crosslinks and indices.
4331 integrity of their crosslinks and indices.
4332
4332
4333 Returns 0 on success, 1 if errors are encountered.
4333 Returns 0 on success, 1 if errors are encountered.
4334 """
4334 """
4335 return hg.verify(repo)
4335 return hg.verify(repo)
4336
4336
4337 def version_(ui):
4337 def version_(ui):
4338 """output version and copyright information"""
4338 """output version and copyright information"""
4339 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4339 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4340 % util.version())
4340 % util.version())
4341 ui.status(_(
4341 ui.status(_(
4342 "(see http://mercurial.selenic.com for more information)\n"
4342 "(see http://mercurial.selenic.com for more information)\n"
4343 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
4343 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
4344 "This is free software; see the source for copying conditions. "
4344 "This is free software; see the source for copying conditions. "
4345 "There is NO\nwarranty; "
4345 "There is NO\nwarranty; "
4346 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
4346 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
4347 ))
4347 ))
4348
4348
4349 # Command options and aliases are listed here, alphabetically
4349 # Command options and aliases are listed here, alphabetically
4350
4350
4351 globalopts = [
4351 globalopts = [
4352 ('R', 'repository', '',
4352 ('R', 'repository', '',
4353 _('repository root directory or name of overlay bundle file'),
4353 _('repository root directory or name of overlay bundle file'),
4354 _('REPO')),
4354 _('REPO')),
4355 ('', 'cwd', '',
4355 ('', 'cwd', '',
4356 _('change working directory'), _('DIR')),
4356 _('change working directory'), _('DIR')),
4357 ('y', 'noninteractive', None,
4357 ('y', 'noninteractive', None,
4358 _('do not prompt, assume \'yes\' for any required answers')),
4358 _('do not prompt, assume \'yes\' for any required answers')),
4359 ('q', 'quiet', None, _('suppress output')),
4359 ('q', 'quiet', None, _('suppress output')),
4360 ('v', 'verbose', None, _('enable additional output')),
4360 ('v', 'verbose', None, _('enable additional output')),
4361 ('', 'config', [],
4361 ('', 'config', [],
4362 _('set/override config option (use \'section.name=value\')'),
4362 _('set/override config option (use \'section.name=value\')'),
4363 _('CONFIG')),
4363 _('CONFIG')),
4364 ('', 'debug', None, _('enable debugging output')),
4364 ('', 'debug', None, _('enable debugging output')),
4365 ('', 'debugger', None, _('start debugger')),
4365 ('', 'debugger', None, _('start debugger')),
4366 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
4366 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
4367 _('ENCODE')),
4367 _('ENCODE')),
4368 ('', 'encodingmode', encoding.encodingmode,
4368 ('', 'encodingmode', encoding.encodingmode,
4369 _('set the charset encoding mode'), _('MODE')),
4369 _('set the charset encoding mode'), _('MODE')),
4370 ('', 'traceback', None, _('always print a traceback on exception')),
4370 ('', 'traceback', None, _('always print a traceback on exception')),
4371 ('', 'time', None, _('time how long the command takes')),
4371 ('', 'time', None, _('time how long the command takes')),
4372 ('', 'profile', None, _('print command execution profile')),
4372 ('', 'profile', None, _('print command execution profile')),
4373 ('', 'version', None, _('output version information and exit')),
4373 ('', 'version', None, _('output version information and exit')),
4374 ('h', 'help', None, _('display help and exit')),
4374 ('h', 'help', None, _('display help and exit')),
4375 ]
4375 ]
4376
4376
4377 dryrunopts = [('n', 'dry-run', None,
4377 dryrunopts = [('n', 'dry-run', None,
4378 _('do not perform actions, just print output'))]
4378 _('do not perform actions, just print output'))]
4379
4379
4380 remoteopts = [
4380 remoteopts = [
4381 ('e', 'ssh', '',
4381 ('e', 'ssh', '',
4382 _('specify ssh command to use'), _('CMD')),
4382 _('specify ssh command to use'), _('CMD')),
4383 ('', 'remotecmd', '',
4383 ('', 'remotecmd', '',
4384 _('specify hg command to run on the remote side'), _('CMD')),
4384 _('specify hg command to run on the remote side'), _('CMD')),
4385 ('', 'insecure', None,
4385 ('', 'insecure', None,
4386 _('do not verify server certificate (ignoring web.cacerts config)')),
4386 _('do not verify server certificate (ignoring web.cacerts config)')),
4387 ]
4387 ]
4388
4388
4389 walkopts = [
4389 walkopts = [
4390 ('I', 'include', [],
4390 ('I', 'include', [],
4391 _('include names matching the given patterns'), _('PATTERN')),
4391 _('include names matching the given patterns'), _('PATTERN')),
4392 ('X', 'exclude', [],
4392 ('X', 'exclude', [],
4393 _('exclude names matching the given patterns'), _('PATTERN')),
4393 _('exclude names matching the given patterns'), _('PATTERN')),
4394 ]
4394 ]
4395
4395
4396 commitopts = [
4396 commitopts = [
4397 ('m', 'message', '',
4397 ('m', 'message', '',
4398 _('use text as commit message'), _('TEXT')),
4398 _('use text as commit message'), _('TEXT')),
4399 ('l', 'logfile', '',
4399 ('l', 'logfile', '',
4400 _('read commit message from file'), _('FILE')),
4400 _('read commit message from file'), _('FILE')),
4401 ]
4401 ]
4402
4402
4403 commitopts2 = [
4403 commitopts2 = [
4404 ('d', 'date', '',
4404 ('d', 'date', '',
4405 _('record the specified date as commit date'), _('DATE')),
4405 _('record the specified date as commit date'), _('DATE')),
4406 ('u', 'user', '',
4406 ('u', 'user', '',
4407 _('record the specified user as committer'), _('USER')),
4407 _('record the specified user as committer'), _('USER')),
4408 ]
4408 ]
4409
4409
4410 templateopts = [
4410 templateopts = [
4411 ('', 'style', '',
4411 ('', 'style', '',
4412 _('display using template map file'), _('STYLE')),
4412 _('display using template map file'), _('STYLE')),
4413 ('', 'template', '',
4413 ('', 'template', '',
4414 _('display with template'), _('TEMPLATE')),
4414 _('display with template'), _('TEMPLATE')),
4415 ]
4415 ]
4416
4416
4417 logopts = [
4417 logopts = [
4418 ('p', 'patch', None, _('show patch')),
4418 ('p', 'patch', None, _('show patch')),
4419 ('g', 'git', None, _('use git extended diff format')),
4419 ('g', 'git', None, _('use git extended diff format')),
4420 ('l', 'limit', '',
4420 ('l', 'limit', '',
4421 _('limit number of changes displayed'), _('NUM')),
4421 _('limit number of changes displayed'), _('NUM')),
4422 ('M', 'no-merges', None, _('do not show merges')),
4422 ('M', 'no-merges', None, _('do not show merges')),
4423 ('', 'stat', None, _('output diffstat-style summary of changes')),
4423 ('', 'stat', None, _('output diffstat-style summary of changes')),
4424 ] + templateopts
4424 ] + templateopts
4425
4425
4426 diffopts = [
4426 diffopts = [
4427 ('a', 'text', None, _('treat all files as text')),
4427 ('a', 'text', None, _('treat all files as text')),
4428 ('g', 'git', None, _('use git extended diff format')),
4428 ('g', 'git', None, _('use git extended diff format')),
4429 ('', 'nodates', None, _('omit dates from diff headers'))
4429 ('', 'nodates', None, _('omit dates from diff headers'))
4430 ]
4430 ]
4431
4431
4432 diffopts2 = [
4432 diffopts2 = [
4433 ('p', 'show-function', None, _('show which function each change is in')),
4433 ('p', 'show-function', None, _('show which function each change is in')),
4434 ('', 'reverse', None, _('produce a diff that undoes the changes')),
4434 ('', 'reverse', None, _('produce a diff that undoes the changes')),
4435 ('w', 'ignore-all-space', None,
4435 ('w', 'ignore-all-space', None,
4436 _('ignore white space when comparing lines')),
4436 _('ignore white space when comparing lines')),
4437 ('b', 'ignore-space-change', None,
4437 ('b', 'ignore-space-change', None,
4438 _('ignore changes in the amount of white space')),
4438 _('ignore changes in the amount of white space')),
4439 ('B', 'ignore-blank-lines', None,
4439 ('B', 'ignore-blank-lines', None,
4440 _('ignore changes whose lines are all blank')),
4440 _('ignore changes whose lines are all blank')),
4441 ('U', 'unified', '',
4441 ('U', 'unified', '',
4442 _('number of lines of context to show'), _('NUM')),
4442 _('number of lines of context to show'), _('NUM')),
4443 ('', 'stat', None, _('output diffstat-style summary of changes')),
4443 ('', 'stat', None, _('output diffstat-style summary of changes')),
4444 ]
4444 ]
4445
4445
4446 similarityopts = [
4446 similarityopts = [
4447 ('s', 'similarity', '',
4447 ('s', 'similarity', '',
4448 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4448 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4449 ]
4449 ]
4450
4450
4451 subrepoopts = [
4451 subrepoopts = [
4452 ('S', 'subrepos', None,
4452 ('S', 'subrepos', None,
4453 _('recurse into subrepositories'))
4453 _('recurse into subrepositories'))
4454 ]
4454 ]
4455
4455
4456 table = {
4456 table = {
4457 "^add": (add, walkopts + subrepoopts + dryrunopts,
4457 "^add": (add, walkopts + subrepoopts + dryrunopts,
4458 _('[OPTION]... [FILE]...')),
4458 _('[OPTION]... [FILE]...')),
4459 "addremove":
4459 "addremove":
4460 (addremove, similarityopts + walkopts + dryrunopts,
4460 (addremove, similarityopts + walkopts + dryrunopts,
4461 _('[OPTION]... [FILE]...')),
4461 _('[OPTION]... [FILE]...')),
4462 "^annotate|blame":
4462 "^annotate|blame":
4463 (annotate,
4463 (annotate,
4464 [('r', 'rev', '',
4464 [('r', 'rev', '',
4465 _('annotate the specified revision'), _('REV')),
4465 _('annotate the specified revision'), _('REV')),
4466 ('', 'follow', None,
4466 ('', 'follow', None,
4467 _('follow copies/renames and list the filename (DEPRECATED)')),
4467 _('follow copies/renames and list the filename (DEPRECATED)')),
4468 ('', 'no-follow', None, _("don't follow copies and renames")),
4468 ('', 'no-follow', None, _("don't follow copies and renames")),
4469 ('a', 'text', None, _('treat all files as text')),
4469 ('a', 'text', None, _('treat all files as text')),
4470 ('u', 'user', None, _('list the author (long with -v)')),
4470 ('u', 'user', None, _('list the author (long with -v)')),
4471 ('f', 'file', None, _('list the filename')),
4471 ('f', 'file', None, _('list the filename')),
4472 ('d', 'date', None, _('list the date (short with -q)')),
4472 ('d', 'date', None, _('list the date (short with -q)')),
4473 ('n', 'number', None, _('list the revision number (default)')),
4473 ('n', 'number', None, _('list the revision number (default)')),
4474 ('c', 'changeset', None, _('list the changeset')),
4474 ('c', 'changeset', None, _('list the changeset')),
4475 ('l', 'line-number', None,
4475 ('l', 'line-number', None,
4476 _('show line number at the first appearance'))
4476 _('show line number at the first appearance'))
4477 ] + walkopts,
4477 ] + walkopts,
4478 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4478 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4479 "archive":
4479 "archive":
4480 (archive,
4480 (archive,
4481 [('', 'no-decode', None, _('do not pass files through decoders')),
4481 [('', 'no-decode', None, _('do not pass files through decoders')),
4482 ('p', 'prefix', '',
4482 ('p', 'prefix', '',
4483 _('directory prefix for files in archive'), _('PREFIX')),
4483 _('directory prefix for files in archive'), _('PREFIX')),
4484 ('r', 'rev', '',
4484 ('r', 'rev', '',
4485 _('revision to distribute'), _('REV')),
4485 _('revision to distribute'), _('REV')),
4486 ('t', 'type', '',
4486 ('t', 'type', '',
4487 _('type of distribution to create'), _('TYPE')),
4487 _('type of distribution to create'), _('TYPE')),
4488 ] + subrepoopts + walkopts,
4488 ] + subrepoopts + walkopts,
4489 _('[OPTION]... DEST')),
4489 _('[OPTION]... DEST')),
4490 "backout":
4490 "backout":
4491 (backout,
4491 (backout,
4492 [('', 'merge', None,
4492 [('', 'merge', None,
4493 _('merge with old dirstate parent after backout')),
4493 _('merge with old dirstate parent after backout')),
4494 ('', 'parent', '',
4494 ('', 'parent', '',
4495 _('parent to choose when backing out merge'), _('REV')),
4495 _('parent to choose when backing out merge'), _('REV')),
4496 ('t', 'tool', '',
4496 ('t', 'tool', '',
4497 _('specify merge tool')),
4497 _('specify merge tool')),
4498 ('r', 'rev', '',
4498 ('r', 'rev', '',
4499 _('revision to backout'), _('REV')),
4499 _('revision to backout'), _('REV')),
4500 ] + walkopts + commitopts + commitopts2,
4500 ] + walkopts + commitopts + commitopts2,
4501 _('[OPTION]... [-r] REV')),
4501 _('[OPTION]... [-r] REV')),
4502 "bisect":
4502 "bisect":
4503 (bisect,
4503 (bisect,
4504 [('r', 'reset', False, _('reset bisect state')),
4504 [('r', 'reset', False, _('reset bisect state')),
4505 ('g', 'good', False, _('mark changeset good')),
4505 ('g', 'good', False, _('mark changeset good')),
4506 ('b', 'bad', False, _('mark changeset bad')),
4506 ('b', 'bad', False, _('mark changeset bad')),
4507 ('s', 'skip', False, _('skip testing changeset')),
4507 ('s', 'skip', False, _('skip testing changeset')),
4508 ('e', 'extend', False, _('extend the bisect range')),
4508 ('e', 'extend', False, _('extend the bisect range')),
4509 ('c', 'command', '',
4509 ('c', 'command', '',
4510 _('use command to check changeset state'), _('CMD')),
4510 _('use command to check changeset state'), _('CMD')),
4511 ('U', 'noupdate', False, _('do not update to target'))],
4511 ('U', 'noupdate', False, _('do not update to target'))],
4512 _("[-gbsr] [-U] [-c CMD] [REV]")),
4512 _("[-gbsr] [-U] [-c CMD] [REV]")),
4513 "bookmarks":
4513 "bookmarks":
4514 (bookmark,
4514 (bookmark,
4515 [('f', 'force', False, _('force')),
4515 [('f', 'force', False, _('force')),
4516 ('r', 'rev', '', _('revision'), _('REV')),
4516 ('r', 'rev', '', _('revision'), _('REV')),
4517 ('d', 'delete', False, _('delete a given bookmark')),
4517 ('d', 'delete', False, _('delete a given bookmark')),
4518 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
4518 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
4519 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
4519 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
4520 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]')),
4520 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]')),
4521 "branch":
4521 "branch":
4522 (branch,
4522 (branch,
4523 [('f', 'force', None,
4523 [('f', 'force', None,
4524 _('set branch name even if it shadows an existing branch')),
4524 _('set branch name even if it shadows an existing branch')),
4525 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4525 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4526 _('[-fC] [NAME]')),
4526 _('[-fC] [NAME]')),
4527 "branches":
4527 "branches":
4528 (branches,
4528 (branches,
4529 [('a', 'active', False,
4529 [('a', 'active', False,
4530 _('show only branches that have unmerged heads')),
4530 _('show only branches that have unmerged heads')),
4531 ('c', 'closed', False,
4531 ('c', 'closed', False,
4532 _('show normal and closed branches'))],
4532 _('show normal and closed branches'))],
4533 _('[-ac]')),
4533 _('[-ac]')),
4534 "bundle":
4534 "bundle":
4535 (bundle,
4535 (bundle,
4536 [('f', 'force', None,
4536 [('f', 'force', None,
4537 _('run even when the destination is unrelated')),
4537 _('run even when the destination is unrelated')),
4538 ('r', 'rev', [],
4538 ('r', 'rev', [],
4539 _('a changeset intended to be added to the destination'),
4539 _('a changeset intended to be added to the destination'),
4540 _('REV')),
4540 _('REV')),
4541 ('b', 'branch', [],
4541 ('b', 'branch', [],
4542 _('a specific branch you would like to bundle'),
4542 _('a specific branch you would like to bundle'),
4543 _('BRANCH')),
4543 _('BRANCH')),
4544 ('', 'base', [],
4544 ('', 'base', [],
4545 _('a base changeset assumed to be available at the destination'),
4545 _('a base changeset assumed to be available at the destination'),
4546 _('REV')),
4546 _('REV')),
4547 ('a', 'all', None, _('bundle all changesets in the repository')),
4547 ('a', 'all', None, _('bundle all changesets in the repository')),
4548 ('t', 'type', 'bzip2',
4548 ('t', 'type', 'bzip2',
4549 _('bundle compression type to use'), _('TYPE')),
4549 _('bundle compression type to use'), _('TYPE')),
4550 ] + remoteopts,
4550 ] + remoteopts,
4551 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4551 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4552 "cat":
4552 "cat":
4553 (cat,
4553 (cat,
4554 [('o', 'output', '',
4554 [('o', 'output', '',
4555 _('print output to file with formatted name'), _('FORMAT')),
4555 _('print output to file with formatted name'), _('FORMAT')),
4556 ('r', 'rev', '',
4556 ('r', 'rev', '',
4557 _('print the given revision'), _('REV')),
4557 _('print the given revision'), _('REV')),
4558 ('', 'decode', None, _('apply any matching decode filter')),
4558 ('', 'decode', None, _('apply any matching decode filter')),
4559 ] + walkopts,
4559 ] + walkopts,
4560 _('[OPTION]... FILE...')),
4560 _('[OPTION]... FILE...')),
4561 "^clone":
4561 "^clone":
4562 (clone,
4562 (clone,
4563 [('U', 'noupdate', None,
4563 [('U', 'noupdate', None,
4564 _('the clone will include an empty working copy (only a repository)')),
4564 _('the clone will include an empty working copy (only a repository)')),
4565 ('u', 'updaterev', '',
4565 ('u', 'updaterev', '',
4566 _('revision, tag or branch to check out'), _('REV')),
4566 _('revision, tag or branch to check out'), _('REV')),
4567 ('r', 'rev', [],
4567 ('r', 'rev', [],
4568 _('include the specified changeset'), _('REV')),
4568 _('include the specified changeset'), _('REV')),
4569 ('b', 'branch', [],
4569 ('b', 'branch', [],
4570 _('clone only the specified branch'), _('BRANCH')),
4570 _('clone only the specified branch'), _('BRANCH')),
4571 ('', 'pull', None, _('use pull protocol to copy metadata')),
4571 ('', 'pull', None, _('use pull protocol to copy metadata')),
4572 ('', 'uncompressed', None,
4572 ('', 'uncompressed', None,
4573 _('use uncompressed transfer (fast over LAN)')),
4573 _('use uncompressed transfer (fast over LAN)')),
4574 ] + remoteopts,
4574 ] + remoteopts,
4575 _('[OPTION]... SOURCE [DEST]')),
4575 _('[OPTION]... SOURCE [DEST]')),
4576 "^commit|ci":
4576 "^commit|ci":
4577 (commit,
4577 (commit,
4578 [('A', 'addremove', None,
4578 [('A', 'addremove', None,
4579 _('mark new/missing files as added/removed before committing')),
4579 _('mark new/missing files as added/removed before committing')),
4580 ('', 'close-branch', None,
4580 ('', 'close-branch', None,
4581 _('mark a branch as closed, hiding it from the branch list')),
4581 _('mark a branch as closed, hiding it from the branch list')),
4582 ] + walkopts + commitopts + commitopts2,
4582 ] + walkopts + commitopts + commitopts2,
4583 _('[OPTION]... [FILE]...')),
4583 _('[OPTION]... [FILE]...')),
4584 "copy|cp":
4584 "copy|cp":
4585 (copy,
4585 (copy,
4586 [('A', 'after', None, _('record a copy that has already occurred')),
4586 [('A', 'after', None, _('record a copy that has already occurred')),
4587 ('f', 'force', None,
4587 ('f', 'force', None,
4588 _('forcibly copy over an existing managed file')),
4588 _('forcibly copy over an existing managed file')),
4589 ] + walkopts + dryrunopts,
4589 ] + walkopts + dryrunopts,
4590 _('[OPTION]... [SOURCE]... DEST')),
4590 _('[OPTION]... [SOURCE]... DEST')),
4591 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4591 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4592 "debugbuilddag":
4592 "debugbuilddag":
4593 (debugbuilddag,
4593 (debugbuilddag,
4594 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4594 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4595 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4595 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4596 ('n', 'new-file', None, _('add new file at each rev')),
4596 ('n', 'new-file', None, _('add new file at each rev')),
4597 ],
4597 ],
4598 _('[OPTION]... [TEXT]')),
4598 _('[OPTION]... [TEXT]')),
4599 "debugbundle":
4599 "debugbundle":
4600 (debugbundle,
4600 (debugbundle,
4601 [('a', 'all', None, _('show all details')),
4601 [('a', 'all', None, _('show all details')),
4602 ],
4602 ],
4603 _('FILE')),
4603 _('FILE')),
4604 "debugcheckstate": (debugcheckstate, [], ''),
4604 "debugcheckstate": (debugcheckstate, [], ''),
4605 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4605 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4606 "debugcomplete":
4606 "debugcomplete":
4607 (debugcomplete,
4607 (debugcomplete,
4608 [('o', 'options', None, _('show the command options'))],
4608 [('o', 'options', None, _('show the command options'))],
4609 _('[-o] CMD')),
4609 _('[-o] CMD')),
4610 "debugdag":
4610 "debugdag":
4611 (debugdag,
4611 (debugdag,
4612 [('t', 'tags', None, _('use tags as labels')),
4612 [('t', 'tags', None, _('use tags as labels')),
4613 ('b', 'branches', None, _('annotate with branch names')),
4613 ('b', 'branches', None, _('annotate with branch names')),
4614 ('', 'dots', None, _('use dots for runs')),
4614 ('', 'dots', None, _('use dots for runs')),
4615 ('s', 'spaces', None, _('separate elements by spaces')),
4615 ('s', 'spaces', None, _('separate elements by spaces')),
4616 ],
4616 ],
4617 _('[OPTION]... [FILE [REV]...]')),
4617 _('[OPTION]... [FILE [REV]...]')),
4618 "debugdate":
4618 "debugdate":
4619 (debugdate,
4619 (debugdate,
4620 [('e', 'extended', None, _('try extended date formats'))],
4620 [('e', 'extended', None, _('try extended date formats'))],
4621 _('[-e] DATE [RANGE]')),
4621 _('[-e] DATE [RANGE]')),
4622 "debugdata": (debugdata, [], _('FILE REV')),
4622 "debugdata": (debugdata, [], _('FILE REV')),
4623 "debugdiscovery": (debugdiscovery,
4623 "debugdiscovery": (debugdiscovery,
4624 [('', 'old', None,
4624 [('', 'old', None,
4625 _('use old-style discovery')),
4625 _('use old-style discovery')),
4626 ('', 'nonheads', None,
4626 ('', 'nonheads', None,
4627 _('use old-style discovery with non-heads included')),
4627 _('use old-style discovery with non-heads included')),
4628 ] + remoteopts,
4628 ] + remoteopts,
4629 _('[-l REV] [-r REV] [-b BRANCH]...'
4629 _('[-l REV] [-r REV] [-b BRANCH]...'
4630 ' [OTHER]')),
4630 ' [OTHER]')),
4631 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4631 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4632 "debuggetbundle":
4632 "debuggetbundle":
4633 (debuggetbundle,
4633 (debuggetbundle,
4634 [('H', 'head', [], _('id of head node'), _('ID')),
4634 [('H', 'head', [], _('id of head node'), _('ID')),
4635 ('C', 'common', [], _('id of common node'), _('ID')),
4635 ('C', 'common', [], _('id of common node'), _('ID')),
4636 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
4636 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
4637 ],
4637 ],
4638 _('REPO FILE [-H|-C ID]...')),
4638 _('REPO FILE [-H|-C ID]...')),
4639 "debugignore": (debugignore, [], ''),
4639 "debugignore": (debugignore, [], ''),
4640 "debugindex": (debugindex,
4640 "debugindex": (debugindex,
4641 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4641 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4642 _('FILE')),
4642 _('FILE')),
4643 "debugindexdot": (debugindexdot, [], _('FILE')),
4643 "debugindexdot": (debugindexdot, [], _('FILE')),
4644 "debuginstall": (debuginstall, [], ''),
4644 "debuginstall": (debuginstall, [], ''),
4645 "debugknown": (debugknown, [], _('REPO ID...')),
4645 "debugknown": (debugknown, [], _('REPO ID...')),
4646 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4646 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4647 "debugrebuildstate":
4647 "debugrebuildstate":
4648 (debugrebuildstate,
4648 (debugrebuildstate,
4649 [('r', 'rev', '',
4649 [('r', 'rev', '',
4650 _('revision to rebuild to'), _('REV'))],
4650 _('revision to rebuild to'), _('REV'))],
4651 _('[-r REV] [REV]')),
4651 _('[-r REV] [REV]')),
4652 "debugrename":
4652 "debugrename":
4653 (debugrename,
4653 (debugrename,
4654 [('r', 'rev', '',
4654 [('r', 'rev', '',
4655 _('revision to debug'), _('REV'))],
4655 _('revision to debug'), _('REV'))],
4656 _('[-r REV] FILE')),
4656 _('[-r REV] FILE')),
4657 "debugrevspec":
4657 "debugrevspec":
4658 (debugrevspec, [], ('REVSPEC')),
4658 (debugrevspec, [], ('REVSPEC')),
4659 "debugsetparents":
4659 "debugsetparents":
4660 (debugsetparents, [], _('REV1 [REV2]')),
4660 (debugsetparents, [], _('REV1 [REV2]')),
4661 "debugstate":
4661 "debugstate":
4662 (debugstate,
4662 (debugstate,
4663 [('', 'nodates', None, _('do not display the saved mtime')),
4663 [('', 'nodates', None, _('do not display the saved mtime')),
4664 ('', 'datesort', None, _('sort by saved mtime'))],
4664 ('', 'datesort', None, _('sort by saved mtime'))],
4665 _('[OPTION]...')),
4665 _('[OPTION]...')),
4666 "debugsub":
4666 "debugsub":
4667 (debugsub,
4667 (debugsub,
4668 [('r', 'rev', '',
4668 [('r', 'rev', '',
4669 _('revision to check'), _('REV'))],
4669 _('revision to check'), _('REV'))],
4670 _('[-r REV] [REV]')),
4670 _('[-r REV] [REV]')),
4671 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4671 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4672 "debugwireargs":
4672 "debugwireargs":
4673 (debugwireargs,
4673 (debugwireargs,
4674 [('', 'three', '', 'three'),
4674 [('', 'three', '', 'three'),
4675 ('', 'four', '', 'four'),
4675 ('', 'four', '', 'four'),
4676 ('', 'five', '', 'five'),
4676 ('', 'five', '', 'five'),
4677 ] + remoteopts,
4677 ] + remoteopts,
4678 _('REPO [OPTIONS]... [ONE [TWO]]')),
4678 _('REPO [OPTIONS]... [ONE [TWO]]')),
4679 "^diff":
4679 "^diff":
4680 (diff,
4680 (diff,
4681 [('r', 'rev', [],
4681 [('r', 'rev', [],
4682 _('revision'), _('REV')),
4682 _('revision'), _('REV')),
4683 ('c', 'change', '',
4683 ('c', 'change', '',
4684 _('change made by revision'), _('REV'))
4684 _('change made by revision'), _('REV'))
4685 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4685 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4686 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4686 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4687 "^export":
4687 "^export":
4688 (export,
4688 (export,
4689 [('o', 'output', '',
4689 [('o', 'output', '',
4690 _('print output to file with formatted name'), _('FORMAT')),
4690 _('print output to file with formatted name'), _('FORMAT')),
4691 ('', 'switch-parent', None, _('diff against the second parent')),
4691 ('', 'switch-parent', None, _('diff against the second parent')),
4692 ('r', 'rev', [],
4692 ('r', 'rev', [],
4693 _('revisions to export'), _('REV')),
4693 _('revisions to export'), _('REV')),
4694 ] + diffopts,
4694 ] + diffopts,
4695 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4695 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4696 "^forget":
4696 "^forget":
4697 (forget,
4697 (forget,
4698 [] + walkopts,
4698 [] + walkopts,
4699 _('[OPTION]... FILE...')),
4699 _('[OPTION]... FILE...')),
4700 "grep":
4700 "grep":
4701 (grep,
4701 (grep,
4702 [('0', 'print0', None, _('end fields with NUL')),
4702 [('0', 'print0', None, _('end fields with NUL')),
4703 ('', 'all', None, _('print all revisions that match')),
4703 ('', 'all', None, _('print all revisions that match')),
4704 ('a', 'text', None, _('treat all files as text')),
4704 ('a', 'text', None, _('treat all files as text')),
4705 ('f', 'follow', None,
4705 ('f', 'follow', None,
4706 _('follow changeset history,'
4706 _('follow changeset history,'
4707 ' or file history across copies and renames')),
4707 ' or file history across copies and renames')),
4708 ('i', 'ignore-case', None, _('ignore case when matching')),
4708 ('i', 'ignore-case', None, _('ignore case when matching')),
4709 ('l', 'files-with-matches', None,
4709 ('l', 'files-with-matches', None,
4710 _('print only filenames and revisions that match')),
4710 _('print only filenames and revisions that match')),
4711 ('n', 'line-number', None, _('print matching line numbers')),
4711 ('n', 'line-number', None, _('print matching line numbers')),
4712 ('r', 'rev', [],
4712 ('r', 'rev', [],
4713 _('only search files changed within revision range'), _('REV')),
4713 _('only search files changed within revision range'), _('REV')),
4714 ('u', 'user', None, _('list the author (long with -v)')),
4714 ('u', 'user', None, _('list the author (long with -v)')),
4715 ('d', 'date', None, _('list the date (short with -q)')),
4715 ('d', 'date', None, _('list the date (short with -q)')),
4716 ] + walkopts,
4716 ] + walkopts,
4717 _('[OPTION]... PATTERN [FILE]...')),
4717 _('[OPTION]... PATTERN [FILE]...')),
4718 "heads":
4718 "heads":
4719 (heads,
4719 (heads,
4720 [('r', 'rev', '',
4720 [('r', 'rev', '',
4721 _('show only heads which are descendants of STARTREV'),
4721 _('show only heads which are descendants of STARTREV'),
4722 _('STARTREV')),
4722 _('STARTREV')),
4723 ('t', 'topo', False, _('show topological heads only')),
4723 ('t', 'topo', False, _('show topological heads only')),
4724 ('a', 'active', False,
4724 ('a', 'active', False,
4725 _('show active branchheads only (DEPRECATED)')),
4725 _('show active branchheads only (DEPRECATED)')),
4726 ('c', 'closed', False,
4726 ('c', 'closed', False,
4727 _('show normal and closed branch heads')),
4727 _('show normal and closed branch heads')),
4728 ] + templateopts,
4728 ] + templateopts,
4729 _('[-ac] [-r STARTREV] [REV]...')),
4729 _('[-ac] [-r STARTREV] [REV]...')),
4730 "help": (help_,
4730 "help": (help_,
4731 [('e', 'extension', None, _('show only help for extensions')),
4731 [('e', 'extension', None, _('show only help for extensions')),
4732 ('c', 'command', None, _('show only help for commands'))],
4732 ('c', 'command', None, _('show only help for commands'))],
4733 _('[-ec] [TOPIC]')),
4733 _('[-ec] [TOPIC]')),
4734 "identify|id":
4734 "identify|id":
4735 (identify,
4735 (identify,
4736 [('r', 'rev', '',
4736 [('r', 'rev', '',
4737 _('identify the specified revision'), _('REV')),
4737 _('identify the specified revision'), _('REV')),
4738 ('n', 'num', None, _('show local revision number')),
4738 ('n', 'num', None, _('show local revision number')),
4739 ('i', 'id', None, _('show global revision id')),
4739 ('i', 'id', None, _('show global revision id')),
4740 ('b', 'branch', None, _('show branch')),
4740 ('b', 'branch', None, _('show branch')),
4741 ('t', 'tags', None, _('show tags')),
4741 ('t', 'tags', None, _('show tags')),
4742 ('B', 'bookmarks', None, _('show bookmarks'))],
4742 ('B', 'bookmarks', None, _('show bookmarks'))],
4743 _('[-nibtB] [-r REV] [SOURCE]')),
4743 _('[-nibtB] [-r REV] [SOURCE]')),
4744 "import|patch":
4744 "import|patch":
4745 (import_,
4745 (import_,
4746 [('p', 'strip', 1,
4746 [('p', 'strip', 1,
4747 _('directory strip option for patch. This has the same '
4747 _('directory strip option for patch. This has the same '
4748 'meaning as the corresponding patch option'),
4748 'meaning as the corresponding patch option'),
4749 _('NUM')),
4749 _('NUM')),
4750 ('b', 'base', '',
4750 ('b', 'base', '',
4751 _('base path'), _('PATH')),
4751 _('base path'), _('PATH')),
4752 ('f', 'force', None,
4752 ('f', 'force', None,
4753 _('skip check for outstanding uncommitted changes')),
4753 _('skip check for outstanding uncommitted changes')),
4754 ('', 'no-commit', None,
4754 ('', 'no-commit', None,
4755 _("don't commit, just update the working directory")),
4755 _("don't commit, just update the working directory")),
4756 ('', 'exact', None,
4756 ('', 'exact', None,
4757 _('apply patch to the nodes from which it was generated')),
4757 _('apply patch to the nodes from which it was generated')),
4758 ('', 'import-branch', None,
4758 ('', 'import-branch', None,
4759 _('use any branch information in patch (implied by --exact)'))] +
4759 _('use any branch information in patch (implied by --exact)'))] +
4760 commitopts + commitopts2 + similarityopts,
4760 commitopts + commitopts2 + similarityopts,
4761 _('[OPTION]... PATCH...')),
4761 _('[OPTION]... PATCH...')),
4762 "incoming|in":
4762 "incoming|in":
4763 (incoming,
4763 (incoming,
4764 [('f', 'force', None,
4764 [('f', 'force', None,
4765 _('run even if remote repository is unrelated')),
4765 _('run even if remote repository is unrelated')),
4766 ('n', 'newest-first', None, _('show newest record first')),
4766 ('n', 'newest-first', None, _('show newest record first')),
4767 ('', 'bundle', '',
4767 ('', 'bundle', '',
4768 _('file to store the bundles into'), _('FILE')),
4768 _('file to store the bundles into'), _('FILE')),
4769 ('r', 'rev', [],
4769 ('r', 'rev', [],
4770 _('a remote changeset intended to be added'), _('REV')),
4770 _('a remote changeset intended to be added'), _('REV')),
4771 ('B', 'bookmarks', False, _("compare bookmarks")),
4771 ('B', 'bookmarks', False, _("compare bookmarks")),
4772 ('b', 'branch', [],
4772 ('b', 'branch', [],
4773 _('a specific branch you would like to pull'), _('BRANCH')),
4773 _('a specific branch you would like to pull'), _('BRANCH')),
4774 ] + logopts + remoteopts + subrepoopts,
4774 ] + logopts + remoteopts + subrepoopts,
4775 _('[-p] [-n] [-M] [-f] [-r REV]...'
4775 _('[-p] [-n] [-M] [-f] [-r REV]...'
4776 ' [--bundle FILENAME] [SOURCE]')),
4776 ' [--bundle FILENAME] [SOURCE]')),
4777 "^init":
4777 "^init":
4778 (init,
4778 (init,
4779 remoteopts,
4779 remoteopts,
4780 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4780 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4781 "locate":
4781 "locate":
4782 (locate,
4782 (locate,
4783 [('r', 'rev', '',
4783 [('r', 'rev', '',
4784 _('search the repository as it is in REV'), _('REV')),
4784 _('search the repository as it is in REV'), _('REV')),
4785 ('0', 'print0', None,
4785 ('0', 'print0', None,
4786 _('end filenames with NUL, for use with xargs')),
4786 _('end filenames with NUL, for use with xargs')),
4787 ('f', 'fullpath', None,
4787 ('f', 'fullpath', None,
4788 _('print complete paths from the filesystem root')),
4788 _('print complete paths from the filesystem root')),
4789 ] + walkopts,
4789 ] + walkopts,
4790 _('[OPTION]... [PATTERN]...')),
4790 _('[OPTION]... [PATTERN]...')),
4791 "^log|history":
4791 "^log|history":
4792 (log,
4792 (log,
4793 [('f', 'follow', None,
4793 [('f', 'follow', None,
4794 _('follow changeset history,'
4794 _('follow changeset history,'
4795 ' or file history across copies and renames')),
4795 ' or file history across copies and renames')),
4796 ('', 'follow-first', None,
4796 ('', 'follow-first', None,
4797 _('only follow the first parent of merge changesets')),
4797 _('only follow the first parent of merge changesets')),
4798 ('d', 'date', '',
4798 ('d', 'date', '',
4799 _('show revisions matching date spec'), _('DATE')),
4799 _('show revisions matching date spec'), _('DATE')),
4800 ('C', 'copies', None, _('show copied files')),
4800 ('C', 'copies', None, _('show copied files')),
4801 ('k', 'keyword', [],
4801 ('k', 'keyword', [],
4802 _('do case-insensitive search for a given text'), _('TEXT')),
4802 _('do case-insensitive search for a given text'), _('TEXT')),
4803 ('r', 'rev', [],
4803 ('r', 'rev', [],
4804 _('show the specified revision or range'), _('REV')),
4804 _('show the specified revision or range'), _('REV')),
4805 ('', 'removed', None, _('include revisions where files were removed')),
4805 ('', 'removed', None, _('include revisions where files were removed')),
4806 ('m', 'only-merges', None, _('show only merges')),
4806 ('m', 'only-merges', None, _('show only merges')),
4807 ('u', 'user', [],
4807 ('u', 'user', [],
4808 _('revisions committed by user'), _('USER')),
4808 _('revisions committed by user'), _('USER')),
4809 ('', 'only-branch', [],
4809 ('', 'only-branch', [],
4810 _('show only changesets within the given named branch (DEPRECATED)'),
4810 _('show only changesets within the given named branch (DEPRECATED)'),
4811 _('BRANCH')),
4811 _('BRANCH')),
4812 ('b', 'branch', [],
4812 ('b', 'branch', [],
4813 _('show changesets within the given named branch'), _('BRANCH')),
4813 _('show changesets within the given named branch'), _('BRANCH')),
4814 ('P', 'prune', [],
4814 ('P', 'prune', [],
4815 _('do not display revision or any of its ancestors'), _('REV')),
4815 _('do not display revision or any of its ancestors'), _('REV')),
4816 ] + logopts + walkopts,
4816 ] + logopts + walkopts,
4817 _('[OPTION]... [FILE]')),
4817 _('[OPTION]... [FILE]')),
4818 "manifest":
4818 "manifest":
4819 (manifest,
4819 (manifest,
4820 [('r', 'rev', '',
4820 [('r', 'rev', '',
4821 _('revision to display'), _('REV'))],
4821 _('revision to display'), _('REV'))],
4822 _('[-r REV]')),
4822 _('[-r REV]')),
4823 "^merge":
4823 "^merge":
4824 (merge,
4824 (merge,
4825 [('f', 'force', None, _('force a merge with outstanding changes')),
4825 [('f', 'force', None, _('force a merge with outstanding changes')),
4826 ('t', 'tool', '', _('specify merge tool')),
4826 ('t', 'tool', '', _('specify merge tool')),
4827 ('r', 'rev', '',
4827 ('r', 'rev', '',
4828 _('revision to merge'), _('REV')),
4828 _('revision to merge'), _('REV')),
4829 ('P', 'preview', None,
4829 ('P', 'preview', None,
4830 _('review revisions to merge (no merge is performed)'))],
4830 _('review revisions to merge (no merge is performed)'))],
4831 _('[-P] [-f] [[-r] REV]')),
4831 _('[-P] [-f] [[-r] REV]')),
4832 "outgoing|out":
4832 "outgoing|out":
4833 (outgoing,
4833 (outgoing,
4834 [('f', 'force', None,
4834 [('f', 'force', None,
4835 _('run even when the destination is unrelated')),
4835 _('run even when the destination is unrelated')),
4836 ('r', 'rev', [],
4836 ('r', 'rev', [],
4837 _('a changeset intended to be included in the destination'),
4837 _('a changeset intended to be included in the destination'),
4838 _('REV')),
4838 _('REV')),
4839 ('n', 'newest-first', None, _('show newest record first')),
4839 ('n', 'newest-first', None, _('show newest record first')),
4840 ('B', 'bookmarks', False, _("compare bookmarks")),
4840 ('B', 'bookmarks', False, _("compare bookmarks")),
4841 ('b', 'branch', [],
4841 ('b', 'branch', [],
4842 _('a specific branch you would like to push'), _('BRANCH')),
4842 _('a specific branch you would like to push'), _('BRANCH')),
4843 ] + logopts + remoteopts + subrepoopts,
4843 ] + logopts + remoteopts + subrepoopts,
4844 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4844 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4845 "parents":
4845 "parents":
4846 (parents,
4846 (parents,
4847 [('r', 'rev', '',
4847 [('r', 'rev', '',
4848 _('show parents of the specified revision'), _('REV')),
4848 _('show parents of the specified revision'), _('REV')),
4849 ] + templateopts,
4849 ] + templateopts,
4850 _('[-r REV] [FILE]')),
4850 _('[-r REV] [FILE]')),
4851 "paths": (paths, [], _('[NAME]')),
4851 "paths": (paths, [], _('[NAME]')),
4852 "^pull":
4852 "^pull":
4853 (pull,
4853 (pull,
4854 [('u', 'update', None,
4854 [('u', 'update', None,
4855 _('update to new branch head if changesets were pulled')),
4855 _('update to new branch head if changesets were pulled')),
4856 ('f', 'force', None,
4856 ('f', 'force', None,
4857 _('run even when remote repository is unrelated')),
4857 _('run even when remote repository is unrelated')),
4858 ('r', 'rev', [],
4858 ('r', 'rev', [],
4859 _('a remote changeset intended to be added'), _('REV')),
4859 _('a remote changeset intended to be added'), _('REV')),
4860 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4860 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4861 ('b', 'branch', [],
4861 ('b', 'branch', [],
4862 _('a specific branch you would like to pull'), _('BRANCH')),
4862 _('a specific branch you would like to pull'), _('BRANCH')),
4863 ] + remoteopts,
4863 ] + remoteopts,
4864 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4864 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4865 "^push":
4865 "^push":
4866 (push,
4866 (push,
4867 [('f', 'force', None, _('force push')),
4867 [('f', 'force', None, _('force push')),
4868 ('r', 'rev', [],
4868 ('r', 'rev', [],
4869 _('a changeset intended to be included in the destination'),
4869 _('a changeset intended to be included in the destination'),
4870 _('REV')),
4870 _('REV')),
4871 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4871 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4872 ('b', 'branch', [],
4872 ('b', 'branch', [],
4873 _('a specific branch you would like to push'), _('BRANCH')),
4873 _('a specific branch you would like to push'), _('BRANCH')),
4874 ('', 'new-branch', False, _('allow pushing a new branch')),
4874 ('', 'new-branch', False, _('allow pushing a new branch')),
4875 ] + remoteopts,
4875 ] + remoteopts,
4876 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4876 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4877 "recover": (recover, []),
4877 "recover": (recover, []),
4878 "^remove|rm":
4878 "^remove|rm":
4879 (remove,
4879 (remove,
4880 [('A', 'after', None, _('record delete for missing files')),
4880 [('A', 'after', None, _('record delete for missing files')),
4881 ('f', 'force', None,
4881 ('f', 'force', None,
4882 _('remove (and delete) file even if added or modified')),
4882 _('remove (and delete) file even if added or modified')),
4883 ] + walkopts,
4883 ] + walkopts,
4884 _('[OPTION]... FILE...')),
4884 _('[OPTION]... FILE...')),
4885 "rename|move|mv":
4885 "rename|move|mv":
4886 (rename,
4886 (rename,
4887 [('A', 'after', None, _('record a rename that has already occurred')),
4887 [('A', 'after', None, _('record a rename that has already occurred')),
4888 ('f', 'force', None,
4888 ('f', 'force', None,
4889 _('forcibly copy over an existing managed file')),
4889 _('forcibly copy over an existing managed file')),
4890 ] + walkopts + dryrunopts,
4890 ] + walkopts + dryrunopts,
4891 _('[OPTION]... SOURCE... DEST')),
4891 _('[OPTION]... SOURCE... DEST')),
4892 "resolve":
4892 "resolve":
4893 (resolve,
4893 (resolve,
4894 [('a', 'all', None, _('select all unresolved files')),
4894 [('a', 'all', None, _('select all unresolved files')),
4895 ('l', 'list', None, _('list state of files needing merge')),
4895 ('l', 'list', None, _('list state of files needing merge')),
4896 ('m', 'mark', None, _('mark files as resolved')),
4896 ('m', 'mark', None, _('mark files as resolved')),
4897 ('u', 'unmark', None, _('mark files as unresolved')),
4897 ('u', 'unmark', None, _('mark files as unresolved')),
4898 ('t', 'tool', '', _('specify merge tool')),
4898 ('t', 'tool', '', _('specify merge tool')),
4899 ('n', 'no-status', None, _('hide status prefix'))]
4899 ('n', 'no-status', None, _('hide status prefix'))]
4900 + walkopts,
4900 + walkopts,
4901 _('[OPTION]... [FILE]...')),
4901 _('[OPTION]... [FILE]...')),
4902 "revert":
4902 "revert":
4903 (revert,
4903 (revert,
4904 [('a', 'all', None, _('revert all changes when no arguments given')),
4904 [('a', 'all', None, _('revert all changes when no arguments given')),
4905 ('d', 'date', '',
4905 ('d', 'date', '',
4906 _('tipmost revision matching date'), _('DATE')),
4906 _('tipmost revision matching date'), _('DATE')),
4907 ('r', 'rev', '',
4907 ('r', 'rev', '',
4908 _('revert to the specified revision'), _('REV')),
4908 _('revert to the specified revision'), _('REV')),
4909 ('', 'no-backup', None, _('do not save backup copies of files')),
4909 ('', 'no-backup', None, _('do not save backup copies of files')),
4910 ] + walkopts + dryrunopts,
4910 ] + walkopts + dryrunopts,
4911 _('[OPTION]... [-r REV] [NAME]...')),
4911 _('[OPTION]... [-r REV] [NAME]...')),
4912 "rollback": (rollback, dryrunopts),
4912 "rollback": (rollback, dryrunopts),
4913 "root": (root, []),
4913 "root": (root, []),
4914 "^serve":
4914 "^serve":
4915 (serve,
4915 (serve,
4916 [('A', 'accesslog', '',
4916 [('A', 'accesslog', '',
4917 _('name of access log file to write to'), _('FILE')),
4917 _('name of access log file to write to'), _('FILE')),
4918 ('d', 'daemon', None, _('run server in background')),
4918 ('d', 'daemon', None, _('run server in background')),
4919 ('', 'daemon-pipefds', '',
4919 ('', 'daemon-pipefds', '',
4920 _('used internally by daemon mode'), _('NUM')),
4920 _('used internally by daemon mode'), _('NUM')),
4921 ('E', 'errorlog', '',
4921 ('E', 'errorlog', '',
4922 _('name of error log file to write to'), _('FILE')),
4922 _('name of error log file to write to'), _('FILE')),
4923 # use string type, then we can check if something was passed
4923 # use string type, then we can check if something was passed
4924 ('p', 'port', '',
4924 ('p', 'port', '',
4925 _('port to listen on (default: 8000)'), _('PORT')),
4925 _('port to listen on (default: 8000)'), _('PORT')),
4926 ('a', 'address', '',
4926 ('a', 'address', '',
4927 _('address to listen on (default: all interfaces)'), _('ADDR')),
4927 _('address to listen on (default: all interfaces)'), _('ADDR')),
4928 ('', 'prefix', '',
4928 ('', 'prefix', '',
4929 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4929 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4930 ('n', 'name', '',
4930 ('n', 'name', '',
4931 _('name to show in web pages (default: working directory)'),
4931 _('name to show in web pages (default: working directory)'),
4932 _('NAME')),
4932 _('NAME')),
4933 ('', 'web-conf', '',
4933 ('', 'web-conf', '',
4934 _('name of the hgweb config file (see "hg help hgweb")'),
4934 _('name of the hgweb config file (see "hg help hgweb")'),
4935 _('FILE')),
4935 _('FILE')),
4936 ('', 'webdir-conf', '',
4936 ('', 'webdir-conf', '',
4937 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4937 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4938 ('', 'pid-file', '',
4938 ('', 'pid-file', '',
4939 _('name of file to write process ID to'), _('FILE')),
4939 _('name of file to write process ID to'), _('FILE')),
4940 ('', 'stdio', None, _('for remote clients')),
4940 ('', 'stdio', None, _('for remote clients')),
4941 ('t', 'templates', '',
4941 ('t', 'templates', '',
4942 _('web templates to use'), _('TEMPLATE')),
4942 _('web templates to use'), _('TEMPLATE')),
4943 ('', 'style', '',
4943 ('', 'style', '',
4944 _('template style to use'), _('STYLE')),
4944 _('template style to use'), _('STYLE')),
4945 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4945 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4946 ('', 'certificate', '',
4946 ('', 'certificate', '',
4947 _('SSL certificate file'), _('FILE'))],
4947 _('SSL certificate file'), _('FILE'))],
4948 _('[OPTION]...')),
4948 _('[OPTION]...')),
4949 "showconfig|debugconfig":
4949 "showconfig|debugconfig":
4950 (showconfig,
4950 (showconfig,
4951 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4951 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4952 _('[-u] [NAME]...')),
4952 _('[-u] [NAME]...')),
4953 "^summary|sum":
4953 "^summary|sum":
4954 (summary,
4954 (summary,
4955 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4955 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4956 "^status|st":
4956 "^status|st":
4957 (status,
4957 (status,
4958 [('A', 'all', None, _('show status of all files')),
4958 [('A', 'all', None, _('show status of all files')),
4959 ('m', 'modified', None, _('show only modified files')),
4959 ('m', 'modified', None, _('show only modified files')),
4960 ('a', 'added', None, _('show only added files')),
4960 ('a', 'added', None, _('show only added files')),
4961 ('r', 'removed', None, _('show only removed files')),
4961 ('r', 'removed', None, _('show only removed files')),
4962 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4962 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4963 ('c', 'clean', None, _('show only files without changes')),
4963 ('c', 'clean', None, _('show only files without changes')),
4964 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4964 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4965 ('i', 'ignored', None, _('show only ignored files')),
4965 ('i', 'ignored', None, _('show only ignored files')),
4966 ('n', 'no-status', None, _('hide status prefix')),
4966 ('n', 'no-status', None, _('hide status prefix')),
4967 ('C', 'copies', None, _('show source of copied files')),
4967 ('C', 'copies', None, _('show source of copied files')),
4968 ('0', 'print0', None,
4968 ('0', 'print0', None,
4969 _('end filenames with NUL, for use with xargs')),
4969 _('end filenames with NUL, for use with xargs')),
4970 ('', 'rev', [],
4970 ('', 'rev', [],
4971 _('show difference from revision'), _('REV')),
4971 _('show difference from revision'), _('REV')),
4972 ('', 'change', '',
4972 ('', 'change', '',
4973 _('list the changed files of a revision'), _('REV')),
4973 _('list the changed files of a revision'), _('REV')),
4974 ] + walkopts + subrepoopts,
4974 ] + walkopts + subrepoopts,
4975 _('[OPTION]... [FILE]...')),
4975 _('[OPTION]... [FILE]...')),
4976 "tag":
4976 "tag":
4977 (tag,
4977 (tag,
4978 [('f', 'force', None, _('force tag')),
4978 [('f', 'force', None, _('force tag')),
4979 ('l', 'local', None, _('make the tag local')),
4979 ('l', 'local', None, _('make the tag local')),
4980 ('r', 'rev', '',
4980 ('r', 'rev', '',
4981 _('revision to tag'), _('REV')),
4981 _('revision to tag'), _('REV')),
4982 ('', 'remove', None, _('remove a tag')),
4982 ('', 'remove', None, _('remove a tag')),
4983 # -l/--local is already there, commitopts cannot be used
4983 # -l/--local is already there, commitopts cannot be used
4984 ('e', 'edit', None, _('edit commit message')),
4984 ('e', 'edit', None, _('edit commit message')),
4985 ('m', 'message', '',
4985 ('m', 'message', '',
4986 _('use <text> as commit message'), _('TEXT')),
4986 _('use <text> as commit message'), _('TEXT')),
4987 ] + commitopts2,
4987 ] + commitopts2,
4988 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4988 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4989 "tags": (tags, [], ''),
4989 "tags": (tags, [], ''),
4990 "tip":
4990 "tip":
4991 (tip,
4991 (tip,
4992 [('p', 'patch', None, _('show patch')),
4992 [('p', 'patch', None, _('show patch')),
4993 ('g', 'git', None, _('use git extended diff format')),
4993 ('g', 'git', None, _('use git extended diff format')),
4994 ] + templateopts,
4994 ] + templateopts,
4995 _('[-p] [-g]')),
4995 _('[-p] [-g]')),
4996 "unbundle":
4996 "unbundle":
4997 (unbundle,
4997 (unbundle,
4998 [('u', 'update', None,
4998 [('u', 'update', None,
4999 _('update to new branch head if changesets were unbundled'))],
4999 _('update to new branch head if changesets were unbundled'))],
5000 _('[-u] FILE...')),
5000 _('[-u] FILE...')),
5001 "^update|up|checkout|co":
5001 "^update|up|checkout|co":
5002 (update,
5002 (update,
5003 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5003 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5004 ('c', 'check', None,
5004 ('c', 'check', None,
5005 _('update across branches if no uncommitted changes')),
5005 _('update across branches if no uncommitted changes')),
5006 ('d', 'date', '',
5006 ('d', 'date', '',
5007 _('tipmost revision matching date'), _('DATE')),
5007 _('tipmost revision matching date'), _('DATE')),
5008 ('r', 'rev', '',
5008 ('r', 'rev', '',
5009 _('revision'), _('REV'))],
5009 _('revision'), _('REV'))],
5010 _('[-c] [-C] [-d DATE] [[-r] REV]')),
5010 _('[-c] [-C] [-d DATE] [[-r] REV]')),
5011 "verify": (verify, []),
5011 "verify": (verify, []),
5012 "version": (version_, []),
5012 "version": (version_, []),
5013 }
5013 }
5014
5014
5015 norepo = ("clone init version help debugcommands debugcomplete"
5015 norepo = ("clone init version help debugcommands debugcomplete"
5016 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5016 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5017 " debugknown debuggetbundle debugbundle")
5017 " debugknown debuggetbundle debugbundle")
5018 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5018 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5019 " debugdata debugindex debugindexdot")
5019 " debugdata debugindex debugindexdot")
General Comments 0
You need to be logged in to leave comments. Login now