##// END OF EJS Templates
help: miscellaneous language fixes
timeless -
r7807:bd8f4463 default
parent child Browse files
Show More
@@ -1,480 +1,480 b''
1 1 '''sending Mercurial changesets as a series of patch emails
2 2
3 3 The series is started off with a "[PATCH 0 of N]" introduction,
4 4 which describes the series as a whole.
5 5
6 6 Each patch email has a Subject line of "[PATCH M of N] ...", using
7 7 the first line of the changeset description as the subject text.
8 8 The message contains two or three body parts:
9 9
10 10 The remainder of the changeset description.
11 11
12 12 [Optional] The result of running diffstat on the patch.
13 13
14 14 The patch itself, as generated by "hg export".
15 15
16 16 Each message refers to all of its predecessors using the In-Reply-To
17 17 and References headers, so they will show up as a sequence in
18 18 threaded mail and news readers, and in mail archives.
19 19
20 20 For each changeset, you will be prompted with a diffstat summary and
21 21 the changeset summary, so you can be sure you are sending the right changes.
22 22
23 23 To enable this extension:
24 24
25 25 [extensions]
26 26 hgext.patchbomb =
27 27
28 28 To configure other defaults, add a section like this to your hgrc file:
29 29
30 30 [email]
31 31 from = My Name <my@email>
32 32 to = recipient1, recipient2, ...
33 33 cc = cc1, cc2, ...
34 34 bcc = bcc1, bcc2, ...
35 35
36 36 Then you can use the "hg email" command to mail a series of changesets
37 37 as a patchbomb.
38 38
39 39 To avoid sending patches prematurely, it is a good idea to first run
40 40 the "email" command with the "-n" option (test only). You will be
41 41 prompted for an email recipient address, a subject an an introductory
42 42 message describing the patches of your patchbomb. Then when all is
43 43 done, patchbomb messages are displayed. If PAGER environment variable
44 44 is set, your pager will be fired up once for each patchbomb message, so
45 45 you can verify everything is alright.
46 46
47 47 The "-m" (mbox) option is also very useful. Instead of previewing
48 48 each patchbomb message in a pager or sending the messages directly,
49 49 it will create a UNIX mailbox file with the patch emails. This
50 50 mailbox file can be previewed with any mail user agent which supports
51 UNIX mbox files, i.e. with mutt:
51 UNIX mbox files, e.g. with mutt:
52 52
53 53 % mutt -R -f mbox
54 54
55 55 When you are previewing the patchbomb messages, you can use `formail'
56 56 (a utility that is commonly installed as part of the procmail package),
57 57 to send each message out:
58 58
59 59 % formail -s sendmail -bm -t < mbox
60 60
61 61 That should be all. Now your patchbomb is on its way out.
62 62
63 63 You can also either configure the method option in the email section
64 64 to be a sendmail compatable mailer or fill out the [smtp] section so
65 65 that the patchbomb extension can automatically send patchbombs directly
66 66 from the commandline. See the [email] and [smtp] sections in hgrc(5)
67 67 for details.'''
68 68
69 69 import os, errno, socket, tempfile, cStringIO
70 70 import email.MIMEMultipart, email.MIMEBase
71 71 import email.Utils, email.Encoders, email.Generator
72 72 from mercurial import cmdutil, commands, hg, mail, patch, util
73 73 from mercurial.i18n import _
74 74 from mercurial.node import bin
75 75
76 76 def prompt(ui, prompt, default=None, rest=': ', empty_ok=False):
77 77 if not ui.interactive:
78 78 return default
79 79 if default:
80 80 prompt += ' [%s]' % default
81 81 prompt += rest
82 82 while True:
83 83 r = ui.prompt(prompt, default=default)
84 84 if r:
85 85 return r
86 86 if default is not None:
87 87 return default
88 88 if empty_ok:
89 89 return r
90 90 ui.warn(_('Please enter a valid value.\n'))
91 91
92 92 def cdiffstat(ui, summary, patchlines):
93 93 s = patch.diffstat(patchlines)
94 94 if summary:
95 95 ui.write(summary, '\n')
96 96 ui.write(s, '\n')
97 97 ans = prompt(ui, _('does the diffstat above look okay? '), 'y')
98 98 if not ans.lower().startswith('y'):
99 99 raise util.Abort(_('diffstat rejected'))
100 100 return s
101 101
102 102 def makepatch(ui, repo, patch, opts, _charsets, idx, total, patchname=None):
103 103
104 104 desc = []
105 105 node = None
106 106 body = ''
107 107
108 108 for line in patch:
109 109 if line.startswith('#'):
110 110 if line.startswith('# Node ID'):
111 111 node = line.split()[-1]
112 112 continue
113 113 if line.startswith('diff -r') or line.startswith('diff --git'):
114 114 break
115 115 desc.append(line)
116 116
117 117 if not patchname and not node:
118 118 raise ValueError
119 119
120 120 if opts.get('attach'):
121 121 body = ('\n'.join(desc[1:]).strip() or
122 122 'Patch subject is complete summary.')
123 123 body += '\n\n\n'
124 124
125 125 if opts.get('plain'):
126 126 while patch and patch[0].startswith('# '):
127 127 patch.pop(0)
128 128 if patch:
129 129 patch.pop(0)
130 130 while patch and not patch[0].strip():
131 131 patch.pop(0)
132 132
133 133 if opts.get('diffstat'):
134 134 body += cdiffstat(ui, '\n'.join(desc), patch) + '\n\n'
135 135
136 136 if opts.get('attach') or opts.get('inline'):
137 137 msg = email.MIMEMultipart.MIMEMultipart()
138 138 if body:
139 139 msg.attach(mail.mimeencode(ui, body, _charsets, opts.get('test')))
140 140 p = mail.mimetextpatch('\n'.join(patch), 'x-patch', opts.get('test'))
141 141 binnode = bin(node)
142 142 # if node is mq patch, it will have patch file name as tag
143 143 if not patchname:
144 144 patchtags = [t for t in repo.nodetags(binnode)
145 145 if t.endswith('.patch') or t.endswith('.diff')]
146 146 if patchtags:
147 147 patchname = patchtags[0]
148 148 elif total > 1:
149 149 patchname = cmdutil.make_filename(repo, '%b-%n.patch',
150 150 binnode, seqno=idx, total=total)
151 151 else:
152 152 patchname = cmdutil.make_filename(repo, '%b.patch', binnode)
153 153 disposition = 'inline'
154 154 if opts.get('attach'):
155 155 disposition = 'attachment'
156 156 p['Content-Disposition'] = disposition + '; filename=' + patchname
157 157 msg.attach(p)
158 158 else:
159 159 body += '\n'.join(patch)
160 160 msg = mail.mimetextpatch(body, display=opts.get('test'))
161 161
162 162 subj = desc[0].strip().rstrip('. ')
163 163 if total == 1 and not opts.get('intro'):
164 164 subj = '[PATCH] ' + (opts.get('subject') or subj)
165 165 else:
166 166 tlen = len(str(total))
167 167 subj = '[PATCH %0*d of %d] %s' % (tlen, idx, total, subj)
168 168 msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test'))
169 169 msg['X-Mercurial-Node'] = node
170 170 return msg, subj
171 171
172 172 def patchbomb(ui, repo, *revs, **opts):
173 173 '''send changesets by email
174 174
175 175 By default, diffs are sent in the format generated by hg export,
176 176 one per message. The series starts with a "[PATCH 0 of N]"
177 177 introduction, which describes the series as a whole.
178 178
179 179 Each patch email has a Subject line of "[PATCH M of N] ...", using
180 180 the first line of the changeset description as the subject text.
181 181 The message contains two or three body parts. First, the rest of
182 182 the changeset description. Next, (optionally) if the diffstat
183 183 program is installed, the result of running diffstat on the patch.
184 184 Finally, the patch itself, as generated by "hg export".
185 185
186 186 With --outgoing, emails will be generated for patches not
187 187 found in the destination repository (or only those which are
188 188 ancestors of the specified revisions if any are provided)
189 189
190 190 With --bundle, changesets are selected as for --outgoing,
191 191 but a single email containing a binary Mercurial bundle as an
192 192 attachment will be sent.
193 193
194 194 Examples:
195 195
196 196 hg email -r 3000 # send patch 3000 only
197 197 hg email -r 3000 -r 3001 # send patches 3000 and 3001
198 198 hg email -r 3000:3005 # send patches 3000 through 3005
199 199 hg email 3000 # send patch 3000 (deprecated)
200 200
201 201 hg email -o # send all patches not in default
202 202 hg email -o DEST # send all patches not in DEST
203 203 hg email -o -r 3000 # send all ancestors of 3000 not in default
204 204 hg email -o -r 3000 DEST # send all ancestors of 3000 not in DEST
205 205
206 206 hg email -b # send bundle of all patches not in default
207 207 hg email -b DEST # send bundle of all patches not in DEST
208 208 hg email -b -r 3000 # bundle of all ancestors of 3000 not in default
209 209 hg email -b -r 3000 DEST # bundle of all ancestors of 3000 not in DEST
210 210
211 211 Before using this command, you will need to enable email in your hgrc.
212 212 See the [email] section in hgrc(5) for details.
213 213 '''
214 214
215 215 _charsets = mail._charsets(ui)
216 216
217 217 def outgoing(dest, revs):
218 218 '''Return the revisions present locally but not in dest'''
219 219 dest = ui.expandpath(dest or 'default-push', dest or 'default')
220 220 revs = [repo.lookup(rev) for rev in revs]
221 221 other = hg.repository(ui, dest)
222 222 ui.status(_('comparing with %s\n') % dest)
223 223 o = repo.findoutgoing(other)
224 224 if not o:
225 225 ui.status(_("no changes found\n"))
226 226 return []
227 227 o = repo.changelog.nodesbetween(o, revs or None)[0]
228 228 return [str(repo.changelog.rev(r)) for r in o]
229 229
230 230 def getpatches(revs):
231 231 for r in cmdutil.revrange(repo, revs):
232 232 output = cStringIO.StringIO()
233 233 p = patch.export(repo, [r], fp=output,
234 234 opts=patch.diffopts(ui, opts))
235 235 yield output.getvalue().split('\n')
236 236
237 237 def getbundle(dest):
238 238 tmpdir = tempfile.mkdtemp(prefix='hg-email-bundle-')
239 239 tmpfn = os.path.join(tmpdir, 'bundle')
240 240 try:
241 241 commands.bundle(ui, repo, tmpfn, dest, **opts)
242 242 return open(tmpfn, 'rb').read()
243 243 finally:
244 244 try:
245 245 os.unlink(tmpfn)
246 246 except:
247 247 pass
248 248 os.rmdir(tmpdir)
249 249
250 250 if not (opts.get('test') or opts.get('mbox')):
251 251 # really sending
252 252 mail.validateconfig(ui)
253 253
254 254 if not (revs or opts.get('rev')
255 255 or opts.get('outgoing') or opts.get('bundle')
256 256 or opts.get('patches')):
257 257 raise util.Abort(_('specify at least one changeset with -r or -o'))
258 258
259 259 cmdutil.setremoteconfig(ui, opts)
260 260 if opts.get('outgoing') and opts.get('bundle'):
261 261 raise util.Abort(_("--outgoing mode always on with --bundle;"
262 262 " do not re-specify --outgoing"))
263 263
264 264 if opts.get('outgoing') or opts.get('bundle'):
265 265 if len(revs) > 1:
266 266 raise util.Abort(_("too many destinations"))
267 267 dest = revs and revs[0] or None
268 268 revs = []
269 269
270 270 if opts.get('rev'):
271 271 if revs:
272 272 raise util.Abort(_('use only one form to specify the revision'))
273 273 revs = opts.get('rev')
274 274
275 275 if opts.get('outgoing'):
276 276 revs = outgoing(dest, opts.get('rev'))
277 277 if opts.get('bundle'):
278 278 opts['revs'] = revs
279 279
280 280 # start
281 281 if opts.get('date'):
282 282 start_time = util.parsedate(opts.get('date'))
283 283 else:
284 284 start_time = util.makedate()
285 285
286 286 def genmsgid(id):
287 287 return '<%s.%s@%s>' % (id[:20], int(start_time[0]), socket.getfqdn())
288 288
289 289 def getdescription(body, sender):
290 290 if opts.get('desc'):
291 291 body = open(opts.get('desc')).read()
292 292 else:
293 293 ui.write(_('\nWrite the introductory message for the '
294 294 'patch series.\n\n'))
295 295 body = ui.edit(body, sender)
296 296 return body
297 297
298 298 def getpatchmsgs(patches, patchnames=None):
299 299 jumbo = []
300 300 msgs = []
301 301
302 302 ui.write(_('This patch series consists of %d patches.\n\n')
303 303 % len(patches))
304 304
305 305 name = None
306 306 for i, p in enumerate(patches):
307 307 jumbo.extend(p)
308 308 if patchnames:
309 309 name = patchnames[i]
310 310 msg = makepatch(ui, repo, p, opts, _charsets, i + 1,
311 311 len(patches), name)
312 312 msgs.append(msg)
313 313
314 314 if len(patches) > 1 or opts.get('intro'):
315 315 tlen = len(str(len(patches)))
316 316
317 317 subj = '[PATCH %0*d of %d] %s' % (
318 318 tlen, 0, len(patches),
319 319 opts.get('subject') or
320 320 prompt(ui, 'Subject:',
321 321 rest=' [PATCH %0*d of %d] ' % (tlen, 0, len(patches))))
322 322
323 323 body = ''
324 324 if opts.get('diffstat'):
325 325 d = cdiffstat(ui, _('Final summary:\n'), jumbo)
326 326 if d:
327 327 body = '\n' + d
328 328
329 329 body = getdescription(body, sender)
330 330 msg = mail.mimeencode(ui, body, _charsets, opts.get('test'))
331 331 msg['Subject'] = mail.headencode(ui, subj, _charsets,
332 332 opts.get('test'))
333 333
334 334 msgs.insert(0, (msg, subj))
335 335 return msgs
336 336
337 337 def getbundlemsgs(bundle):
338 338 subj = (opts.get('subject')
339 339 or prompt(ui, 'Subject:', 'A bundle for your repository'))
340 340
341 341 body = getdescription('', sender)
342 342 msg = email.MIMEMultipart.MIMEMultipart()
343 343 if body:
344 344 msg.attach(mail.mimeencode(ui, body, _charsets, opts.get('test')))
345 345 datapart = email.MIMEBase.MIMEBase('application', 'x-mercurial-bundle')
346 346 datapart.set_payload(bundle)
347 347 datapart.add_header('Content-Disposition', 'attachment',
348 348 filename='bundle.hg')
349 349 email.Encoders.encode_base64(datapart)
350 350 msg.attach(datapart)
351 351 msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test'))
352 352 return [(msg, subj)]
353 353
354 354 sender = (opts.get('from') or ui.config('email', 'from') or
355 355 ui.config('patchbomb', 'from') or
356 356 prompt(ui, 'From', ui.username()))
357 357
358 358 # internal option used by pbranches
359 359 patches = opts.get('patches')
360 360 if patches:
361 361 msgs = getpatchmsgs(patches, opts.get('patchnames'))
362 362 elif opts.get('bundle'):
363 363 msgs = getbundlemsgs(getbundle(dest))
364 364 else:
365 365 msgs = getpatchmsgs(list(getpatches(revs)))
366 366
367 367 def getaddrs(opt, prpt, default = None):
368 368 addrs = opts.get(opt) or (ui.config('email', opt) or
369 369 ui.config('patchbomb', opt) or
370 370 prompt(ui, prpt, default)).split(',')
371 371 return [mail.addressencode(ui, a.strip(), _charsets, opts.get('test'))
372 372 for a in addrs if a.strip()]
373 373
374 374 to = getaddrs('to', 'To')
375 375 cc = getaddrs('cc', 'Cc', '')
376 376
377 377 bcc = opts.get('bcc') or (ui.config('email', 'bcc') or
378 378 ui.config('patchbomb', 'bcc') or '').split(',')
379 379 bcc = [mail.addressencode(ui, a.strip(), _charsets, opts.get('test'))
380 380 for a in bcc if a.strip()]
381 381
382 382 ui.write('\n')
383 383
384 384 parent = None
385 385
386 386 sender_addr = email.Utils.parseaddr(sender)[1]
387 387 sender = mail.addressencode(ui, sender, _charsets, opts.get('test'))
388 388 sendmail = None
389 389 for m, subj in msgs:
390 390 try:
391 391 m['Message-Id'] = genmsgid(m['X-Mercurial-Node'])
392 392 except TypeError:
393 393 m['Message-Id'] = genmsgid('patchbomb')
394 394 if parent:
395 395 m['In-Reply-To'] = parent
396 396 m['References'] = parent
397 397 else:
398 398 parent = m['Message-Id']
399 399 m['Date'] = util.datestr(start_time, "%a, %d %b %Y %H:%M:%S %1%2")
400 400
401 401 start_time = (start_time[0] + 1, start_time[1])
402 402 m['From'] = sender
403 403 m['To'] = ', '.join(to)
404 404 if cc:
405 405 m['Cc'] = ', '.join(cc)
406 406 if bcc:
407 407 m['Bcc'] = ', '.join(bcc)
408 408 if opts.get('test'):
409 409 ui.status(_('Displaying '), subj, ' ...\n')
410 410 ui.flush()
411 411 if 'PAGER' in os.environ:
412 412 fp = util.popen(os.environ['PAGER'], 'w')
413 413 else:
414 414 fp = ui
415 415 generator = email.Generator.Generator(fp, mangle_from_=False)
416 416 try:
417 417 generator.flatten(m, 0)
418 418 fp.write('\n')
419 419 except IOError, inst:
420 420 if inst.errno != errno.EPIPE:
421 421 raise
422 422 if fp is not ui:
423 423 fp.close()
424 424 elif opts.get('mbox'):
425 425 ui.status(_('Writing '), subj, ' ...\n')
426 426 fp = open(opts.get('mbox'), 'In-Reply-To' in m and 'ab+' or 'wb+')
427 427 generator = email.Generator.Generator(fp, mangle_from_=True)
428 428 date = util.datestr(start_time, '%a %b %d %H:%M:%S %Y')
429 429 fp.write('From %s %s\n' % (sender_addr, date))
430 430 generator.flatten(m, 0)
431 431 fp.write('\n\n')
432 432 fp.close()
433 433 else:
434 434 if not sendmail:
435 435 sendmail = mail.connect(ui)
436 436 ui.status(_('Sending '), subj, ' ...\n')
437 437 # Exim does not remove the Bcc field
438 438 del m['Bcc']
439 439 fp = cStringIO.StringIO()
440 440 generator = email.Generator.Generator(fp, mangle_from_=False)
441 441 generator.flatten(m, 0)
442 442 sendmail(sender, to + bcc + cc, fp.getvalue())
443 443
444 444 emailopts = [
445 445 ('a', 'attach', None, _('send patches as attachments')),
446 446 ('i', 'inline', None, _('send patches as inline attachments')),
447 ('', 'bcc', [], _('email addresses of blind copy recipients')),
447 ('', 'bcc', [], _('email addresses of blind carbon copy recipients')),
448 448 ('c', 'cc', [], _('email addresses of copy recipients')),
449 449 ('d', 'diffstat', None, _('add diffstat output to messages')),
450 450 ('', 'date', '', _('use the given date as the sending date')),
451 451 ('', 'desc', '', _('use the given file as the series description')),
452 452 ('f', 'from', '', _('email address of sender')),
453 453 ('n', 'test', None, _('print messages that would be sent')),
454 454 ('m', 'mbox', '',
455 455 _('write messages to mbox file instead of sending them')),
456 456 ('s', 'subject', '',
457 457 _('subject of first message (intro or single patch)')),
458 458 ('t', 'to', [], _('email addresses of recipients')),
459 459 ]
460 460
461 461
462 462 cmdtable = {
463 463 "email":
464 464 (patchbomb,
465 465 [('g', 'git', None, _('use git extended diff format')),
466 466 ('', 'plain', None, _('omit hg patch header')),
467 467 ('o', 'outgoing', None,
468 468 _('send changes not found in the target repository')),
469 469 ('b', 'bundle', None,
470 470 _('send changes not in target as a binary bundle')),
471 471 ('r', 'rev', [], _('a revision to send')),
472 472 ('', 'force', None,
473 473 _('run even when remote repository is unrelated (with -b)')),
474 474 ('', 'base', [],
475 475 _('a base changeset to specify instead of a destination (with -b)')),
476 476 ('', 'intro', None,
477 477 _('send an introduction email for a single patch')),
478 478 ] + emailopts + commands.remoteopts,
479 479 _('hg email [OPTION]... [DEST]...'))
480 480 }
@@ -1,221 +1,221 b''
1 1 # changelog.py - changelog class for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from node import bin, hex, nullid
9 9 from i18n import _
10 10 import util, error, revlog
11 11
12 12 def _string_escape(text):
13 13 """
14 14 >>> d = {'nl': chr(10), 'bs': chr(92), 'cr': chr(13), 'nul': chr(0)}
15 15 >>> s = "ab%(nl)scd%(bs)s%(bs)sn%(nul)sab%(cr)scd%(bs)s%(nl)s" % d
16 16 >>> s
17 17 'ab\\ncd\\\\\\\\n\\x00ab\\rcd\\\\\\n'
18 18 >>> res = _string_escape(s)
19 19 >>> s == res.decode('string_escape')
20 20 True
21 21 """
22 22 # subset of the string_escape codec
23 23 text = text.replace('\\', '\\\\').replace('\n', '\\n').replace('\r', '\\r')
24 24 return text.replace('\0', '\\0')
25 25
26 26 class appender:
27 '''the changelog index must be update last on disk, so we use this class
27 '''the changelog index must be updated last on disk, so we use this class
28 28 to delay writes to it'''
29 29 def __init__(self, fp, buf):
30 30 self.data = buf
31 31 self.fp = fp
32 32 self.offset = fp.tell()
33 33 self.size = util.fstat(fp).st_size
34 34
35 35 def end(self):
36 36 return self.size + len("".join(self.data))
37 37 def tell(self):
38 38 return self.offset
39 39 def flush(self):
40 40 pass
41 41 def close(self):
42 42 self.fp.close()
43 43
44 44 def seek(self, offset, whence=0):
45 45 '''virtual file offset spans real file and data'''
46 46 if whence == 0:
47 47 self.offset = offset
48 48 elif whence == 1:
49 49 self.offset += offset
50 50 elif whence == 2:
51 51 self.offset = self.end() + offset
52 52 if self.offset < self.size:
53 53 self.fp.seek(self.offset)
54 54
55 55 def read(self, count=-1):
56 56 '''only trick here is reads that span real file and data'''
57 57 ret = ""
58 58 if self.offset < self.size:
59 59 s = self.fp.read(count)
60 60 ret = s
61 61 self.offset += len(s)
62 62 if count > 0:
63 63 count -= len(s)
64 64 if count != 0:
65 65 doff = self.offset - self.size
66 66 self.data.insert(0, "".join(self.data))
67 67 del self.data[1:]
68 68 s = self.data[0][doff:doff+count]
69 69 self.offset += len(s)
70 70 ret += s
71 71 return ret
72 72
73 73 def write(self, s):
74 74 self.data.append(str(s))
75 75 self.offset += len(s)
76 76
77 77 class changelog(revlog.revlog):
78 78 def __init__(self, opener):
79 79 revlog.revlog.__init__(self, opener, "00changelog.i")
80 80
81 81 def delayupdate(self):
82 82 "delay visibility of index updates to other readers"
83 83 self._realopener = self.opener
84 84 self.opener = self._delayopener
85 85 self._delaycount = len(self)
86 86 self._delaybuf = []
87 87 self._delayname = None
88 88
89 89 def finalize(self, tr):
90 90 "finalize index updates"
91 91 self.opener = self._realopener
92 92 # move redirected index data back into place
93 93 if self._delayname:
94 94 util.rename(self._delayname + ".a", self._delayname)
95 95 elif self._delaybuf:
96 96 fp = self.opener(self.indexfile, 'a')
97 97 fp.write("".join(self._delaybuf))
98 98 fp.close()
99 99 self._delaybuf = []
100 100 # split when we're done
101 101 self.checkinlinesize(tr)
102 102
103 103 def _delayopener(self, name, mode='r'):
104 104 fp = self._realopener(name, mode)
105 105 # only divert the index
106 106 if not name == self.indexfile:
107 107 return fp
108 108 # if we're doing an initial clone, divert to another file
109 109 if self._delaycount == 0:
110 110 self._delayname = fp.name
111 111 if not len(self):
112 112 # make sure to truncate the file
113 113 mode = mode.replace('a', 'w')
114 114 return self._realopener(name + ".a", mode)
115 115 # otherwise, divert to memory
116 116 return appender(fp, self._delaybuf)
117 117
118 118 def readpending(self, file):
119 119 r = revlog.revlog(self.opener, file)
120 120 self.index = r.index
121 121 self.nodemap = r.nodemap
122 122 self._chunkcache = r._chunkcache
123 123
124 124 def writepending(self):
125 125 "create a file containing the unfinalized state for pretxnchangegroup"
126 126 if self._delaybuf:
127 127 # make a temporary copy of the index
128 128 fp1 = self._realopener(self.indexfile)
129 129 fp2 = self._realopener(self.indexfile + ".a", "w")
130 130 fp2.write(fp1.read())
131 131 # add pending data
132 132 fp2.write("".join(self._delaybuf))
133 133 fp2.close()
134 134 # switch modes so finalize can simply rename
135 135 self._delaybuf = []
136 136 self._delayname = fp1.name
137 137
138 138 if self._delayname:
139 139 return True
140 140
141 141 return False
142 142
143 143 def checkinlinesize(self, tr, fp=None):
144 144 if self.opener == self._delayopener:
145 145 return
146 146 return revlog.revlog.checkinlinesize(self, tr, fp)
147 147
148 148 def decode_extra(self, text):
149 149 extra = {}
150 150 for l in text.split('\0'):
151 151 if l:
152 152 k, v = l.decode('string_escape').split(':', 1)
153 153 extra[k] = v
154 154 return extra
155 155
156 156 def encode_extra(self, d):
157 157 # keys must be sorted to produce a deterministic changelog entry
158 158 items = [_string_escape('%s:%s' % (k, d[k])) for k in util.sort(d)]
159 159 return "\0".join(items)
160 160
161 161 def read(self, node):
162 162 """
163 163 format used:
164 164 nodeid\n : manifest node in ascii
165 165 user\n : user, no \n or \r allowed
166 166 time tz extra\n : date (time is int or float, timezone is int)
167 167 : extra is metadatas, encoded and separated by '\0'
168 168 : older versions ignore it
169 169 files\n\n : files modified by the cset, no \n or \r allowed
170 170 (.*) : comment (free text, ideally utf-8)
171 171
172 172 changelog v0 doesn't use extra
173 173 """
174 174 text = self.revision(node)
175 175 if not text:
176 176 return (nullid, "", (0, 0), [], "", {'branch': 'default'})
177 177 last = text.index("\n\n")
178 178 desc = util.tolocal(text[last + 2:])
179 179 l = text[:last].split('\n')
180 180 manifest = bin(l[0])
181 181 user = util.tolocal(l[1])
182 182
183 183 extra_data = l[2].split(' ', 2)
184 184 if len(extra_data) != 3:
185 185 time = float(extra_data.pop(0))
186 186 try:
187 187 # various tools did silly things with the time zone field.
188 188 timezone = int(extra_data[0])
189 189 except:
190 190 timezone = 0
191 191 extra = {}
192 192 else:
193 193 time, timezone, extra = extra_data
194 194 time, timezone = float(time), int(timezone)
195 195 extra = self.decode_extra(extra)
196 196 if not extra.get('branch'):
197 197 extra['branch'] = 'default'
198 198 files = l[3:]
199 199 return (manifest, user, (time, timezone), files, desc, extra)
200 200
201 201 def add(self, manifest, files, desc, transaction, p1=None, p2=None,
202 202 user=None, date=None, extra={}):
203 203
204 204 user = user.strip()
205 205 if "\n" in user:
206 206 raise error.RevlogError(_("username %s contains a newline")
207 207 % repr(user))
208 208 user, desc = util.fromlocal(user), util.fromlocal(desc)
209 209
210 210 if date:
211 211 parseddate = "%d %d" % util.parsedate(date)
212 212 else:
213 213 parseddate = "%d %d" % util.makedate()
214 214 if extra and extra.get("branch") in ("default", ""):
215 215 del extra["branch"]
216 216 if extra:
217 217 extra = self.encode_extra(extra)
218 218 parseddate = "%s %s" % (parseddate, extra)
219 219 l = [hex(manifest), user, parseddate] + util.sort(files) + ["", desc]
220 220 text = "\n".join(l)
221 221 return self.addrevision(text, transaction, len(self), p1, p2)
@@ -1,1187 +1,1187 b''
1 1 # cmdutil.py - help for command processing in mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from node import hex, nullid, nullrev, short
9 9 from i18n import _
10 10 import os, sys, bisect, stat
11 11 import mdiff, bdiff, util, templater, templatefilters, patch, errno, error
12 12 import match as _match
13 13
14 14 revrangesep = ':'
15 15
16 16 def findpossible(cmd, table, strict=False):
17 17 """
18 18 Return cmd -> (aliases, command table entry)
19 19 for each matching command.
20 20 Return debug commands (or their aliases) only if no normal command matches.
21 21 """
22 22 choice = {}
23 23 debugchoice = {}
24 24 for e in table.keys():
25 25 aliases = e.lstrip("^").split("|")
26 26 found = None
27 27 if cmd in aliases:
28 28 found = cmd
29 29 elif not strict:
30 30 for a in aliases:
31 31 if a.startswith(cmd):
32 32 found = a
33 33 break
34 34 if found is not None:
35 35 if aliases[0].startswith("debug") or found.startswith("debug"):
36 36 debugchoice[found] = (aliases, table[e])
37 37 else:
38 38 choice[found] = (aliases, table[e])
39 39
40 40 if not choice and debugchoice:
41 41 choice = debugchoice
42 42
43 43 return choice
44 44
45 45 def findcmd(cmd, table, strict=True):
46 46 """Return (aliases, command table entry) for command string."""
47 47 choice = findpossible(cmd, table, strict)
48 48
49 49 if cmd in choice:
50 50 return choice[cmd]
51 51
52 52 if len(choice) > 1:
53 53 clist = choice.keys()
54 54 clist.sort()
55 55 raise error.AmbiguousCommand(cmd, clist)
56 56
57 57 if choice:
58 58 return choice.values()[0]
59 59
60 60 raise error.UnknownCommand(cmd)
61 61
62 62 def bail_if_changed(repo):
63 63 if repo.dirstate.parents()[1] != nullid:
64 64 raise util.Abort(_('outstanding uncommitted merge'))
65 65 modified, added, removed, deleted = repo.status()[:4]
66 66 if modified or added or removed or deleted:
67 67 raise util.Abort(_("outstanding uncommitted changes"))
68 68
69 69 def logmessage(opts):
70 70 """ get the log message according to -m and -l option """
71 71 message = opts.get('message')
72 72 logfile = opts.get('logfile')
73 73
74 74 if message and logfile:
75 75 raise util.Abort(_('options --message and --logfile are mutually '
76 76 'exclusive'))
77 77 if not message and logfile:
78 78 try:
79 79 if logfile == '-':
80 80 message = sys.stdin.read()
81 81 else:
82 82 message = open(logfile).read()
83 83 except IOError, inst:
84 84 raise util.Abort(_("can't read commit message '%s': %s") %
85 85 (logfile, inst.strerror))
86 86 return message
87 87
88 88 def loglimit(opts):
89 89 """get the log limit according to option -l/--limit"""
90 90 limit = opts.get('limit')
91 91 if limit:
92 92 try:
93 93 limit = int(limit)
94 94 except ValueError:
95 95 raise util.Abort(_('limit must be a positive integer'))
96 96 if limit <= 0: raise util.Abort(_('limit must be positive'))
97 97 else:
98 98 limit = sys.maxint
99 99 return limit
100 100
101 101 def setremoteconfig(ui, opts):
102 102 "copy remote options to ui tree"
103 103 if opts.get('ssh'):
104 104 ui.setconfig("ui", "ssh", opts['ssh'])
105 105 if opts.get('remotecmd'):
106 106 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
107 107
108 108 def revpair(repo, revs):
109 109 '''return pair of nodes, given list of revisions. second item can
110 110 be None, meaning use working dir.'''
111 111
112 112 def revfix(repo, val, defval):
113 113 if not val and val != 0 and defval is not None:
114 114 val = defval
115 115 return repo.lookup(val)
116 116
117 117 if not revs:
118 118 return repo.dirstate.parents()[0], None
119 119 end = None
120 120 if len(revs) == 1:
121 121 if revrangesep in revs[0]:
122 122 start, end = revs[0].split(revrangesep, 1)
123 123 start = revfix(repo, start, 0)
124 124 end = revfix(repo, end, len(repo) - 1)
125 125 else:
126 126 start = revfix(repo, revs[0], None)
127 127 elif len(revs) == 2:
128 128 if revrangesep in revs[0] or revrangesep in revs[1]:
129 129 raise util.Abort(_('too many revisions specified'))
130 130 start = revfix(repo, revs[0], None)
131 131 end = revfix(repo, revs[1], None)
132 132 else:
133 133 raise util.Abort(_('too many revisions specified'))
134 134 return start, end
135 135
136 136 def revrange(repo, revs):
137 137 """Yield revision as strings from a list of revision specifications."""
138 138
139 139 def revfix(repo, val, defval):
140 140 if not val and val != 0 and defval is not None:
141 141 return defval
142 142 return repo.changelog.rev(repo.lookup(val))
143 143
144 144 seen, l = {}, []
145 145 for spec in revs:
146 146 if revrangesep in spec:
147 147 start, end = spec.split(revrangesep, 1)
148 148 start = revfix(repo, start, 0)
149 149 end = revfix(repo, end, len(repo) - 1)
150 150 step = start > end and -1 or 1
151 151 for rev in xrange(start, end+step, step):
152 152 if rev in seen:
153 153 continue
154 154 seen[rev] = 1
155 155 l.append(rev)
156 156 else:
157 157 rev = revfix(repo, spec, None)
158 158 if rev in seen:
159 159 continue
160 160 seen[rev] = 1
161 161 l.append(rev)
162 162
163 163 return l
164 164
165 165 def make_filename(repo, pat, node,
166 166 total=None, seqno=None, revwidth=None, pathname=None):
167 167 node_expander = {
168 168 'H': lambda: hex(node),
169 169 'R': lambda: str(repo.changelog.rev(node)),
170 170 'h': lambda: short(node),
171 171 }
172 172 expander = {
173 173 '%': lambda: '%',
174 174 'b': lambda: os.path.basename(repo.root),
175 175 }
176 176
177 177 try:
178 178 if node:
179 179 expander.update(node_expander)
180 180 if node:
181 181 expander['r'] = (lambda:
182 182 str(repo.changelog.rev(node)).zfill(revwidth or 0))
183 183 if total is not None:
184 184 expander['N'] = lambda: str(total)
185 185 if seqno is not None:
186 186 expander['n'] = lambda: str(seqno)
187 187 if total is not None and seqno is not None:
188 188 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
189 189 if pathname is not None:
190 190 expander['s'] = lambda: os.path.basename(pathname)
191 191 expander['d'] = lambda: os.path.dirname(pathname) or '.'
192 192 expander['p'] = lambda: pathname
193 193
194 194 newname = []
195 195 patlen = len(pat)
196 196 i = 0
197 197 while i < patlen:
198 198 c = pat[i]
199 199 if c == '%':
200 200 i += 1
201 201 c = pat[i]
202 202 c = expander[c]()
203 203 newname.append(c)
204 204 i += 1
205 205 return ''.join(newname)
206 206 except KeyError, inst:
207 207 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
208 208 inst.args[0])
209 209
210 210 def make_file(repo, pat, node=None,
211 211 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
212 212
213 213 writable = 'w' in mode or 'a' in mode
214 214
215 215 if not pat or pat == '-':
216 216 return writable and sys.stdout or sys.stdin
217 217 if hasattr(pat, 'write') and writable:
218 218 return pat
219 219 if hasattr(pat, 'read') and 'r' in mode:
220 220 return pat
221 221 return open(make_filename(repo, pat, node, total, seqno, revwidth,
222 222 pathname),
223 223 mode)
224 224
225 225 def match(repo, pats=[], opts={}, globbed=False, default='relpath'):
226 226 if not globbed and default == 'relpath':
227 227 pats = util.expand_glob(pats or [])
228 228 m = _match.match(repo.root, repo.getcwd(), pats,
229 229 opts.get('include'), opts.get('exclude'), default)
230 230 def badfn(f, msg):
231 231 repo.ui.warn("%s: %s\n" % (m.rel(f), msg))
232 232 return False
233 233 m.bad = badfn
234 234 return m
235 235
236 236 def matchall(repo):
237 237 return _match.always(repo.root, repo.getcwd())
238 238
239 239 def matchfiles(repo, files):
240 240 return _match.exact(repo.root, repo.getcwd(), files)
241 241
242 242 def findrenames(repo, added=None, removed=None, threshold=0.5):
243 243 '''find renamed files -- yields (before, after, score) tuples'''
244 244 if added is None or removed is None:
245 245 added, removed = repo.status()[1:3]
246 246 ctx = repo['.']
247 247 for a in added:
248 248 aa = repo.wread(a)
249 249 bestname, bestscore = None, threshold
250 250 for r in removed:
251 251 rr = ctx.filectx(r).data()
252 252
253 253 # bdiff.blocks() returns blocks of matching lines
254 254 # count the number of bytes in each
255 255 equal = 0
256 256 alines = mdiff.splitnewlines(aa)
257 257 matches = bdiff.blocks(aa, rr)
258 258 for x1,x2,y1,y2 in matches:
259 259 for line in alines[x1:x2]:
260 260 equal += len(line)
261 261
262 262 lengths = len(aa) + len(rr)
263 263 if lengths:
264 264 myscore = equal*2.0 / lengths
265 265 if myscore >= bestscore:
266 266 bestname, bestscore = r, myscore
267 267 if bestname:
268 268 yield bestname, a, bestscore
269 269
270 270 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
271 271 if dry_run is None:
272 272 dry_run = opts.get('dry_run')
273 273 if similarity is None:
274 274 similarity = float(opts.get('similarity') or 0)
275 275 add, remove = [], []
276 276 mapping = {}
277 277 audit_path = util.path_auditor(repo.root)
278 278 m = match(repo, pats, opts)
279 279 for abs in repo.walk(m):
280 280 target = repo.wjoin(abs)
281 281 good = True
282 282 try:
283 283 audit_path(abs)
284 284 except:
285 285 good = False
286 286 rel = m.rel(abs)
287 287 exact = m.exact(abs)
288 288 if good and abs not in repo.dirstate:
289 289 add.append(abs)
290 290 mapping[abs] = rel, m.exact(abs)
291 291 if repo.ui.verbose or not exact:
292 292 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
293 293 if repo.dirstate[abs] != 'r' and (not good or not util.lexists(target)
294 294 or (os.path.isdir(target) and not os.path.islink(target))):
295 295 remove.append(abs)
296 296 mapping[abs] = rel, exact
297 297 if repo.ui.verbose or not exact:
298 298 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
299 299 if not dry_run:
300 300 repo.remove(remove)
301 301 repo.add(add)
302 302 if similarity > 0:
303 303 for old, new, score in findrenames(repo, add, remove, similarity):
304 304 oldrel, oldexact = mapping[old]
305 305 newrel, newexact = mapping[new]
306 306 if repo.ui.verbose or not oldexact or not newexact:
307 307 repo.ui.status(_('recording removal of %s as rename to %s '
308 308 '(%d%% similar)\n') %
309 309 (oldrel, newrel, score * 100))
310 310 if not dry_run:
311 311 repo.copy(old, new)
312 312
313 313 def copy(ui, repo, pats, opts, rename=False):
314 314 # called with the repo lock held
315 315 #
316 316 # hgsep => pathname that uses "/" to separate directories
317 317 # ossep => pathname that uses os.sep to separate directories
318 318 cwd = repo.getcwd()
319 319 targets = {}
320 320 after = opts.get("after")
321 321 dryrun = opts.get("dry_run")
322 322
323 323 def walkpat(pat):
324 324 srcs = []
325 325 m = match(repo, [pat], opts, globbed=True)
326 326 for abs in repo.walk(m):
327 327 state = repo.dirstate[abs]
328 328 rel = m.rel(abs)
329 329 exact = m.exact(abs)
330 330 if state in '?r':
331 331 if exact and state == '?':
332 332 ui.warn(_('%s: not copying - file is not managed\n') % rel)
333 333 if exact and state == 'r':
334 334 ui.warn(_('%s: not copying - file has been marked for'
335 335 ' remove\n') % rel)
336 336 continue
337 337 # abs: hgsep
338 338 # rel: ossep
339 339 srcs.append((abs, rel, exact))
340 340 return srcs
341 341
342 342 # abssrc: hgsep
343 343 # relsrc: ossep
344 344 # otarget: ossep
345 345 def copyfile(abssrc, relsrc, otarget, exact):
346 346 abstarget = util.canonpath(repo.root, cwd, otarget)
347 347 reltarget = repo.pathto(abstarget, cwd)
348 348 target = repo.wjoin(abstarget)
349 349 src = repo.wjoin(abssrc)
350 350 state = repo.dirstate[abstarget]
351 351
352 352 # check for collisions
353 353 prevsrc = targets.get(abstarget)
354 354 if prevsrc is not None:
355 355 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
356 356 (reltarget, repo.pathto(abssrc, cwd),
357 357 repo.pathto(prevsrc, cwd)))
358 358 return
359 359
360 360 # check for overwrites
361 361 exists = os.path.exists(target)
362 362 if (not after and exists or after and state in 'mn'):
363 363 if not opts['force']:
364 364 ui.warn(_('%s: not overwriting - file exists\n') %
365 365 reltarget)
366 366 return
367 367
368 368 if after:
369 369 if not exists:
370 370 return
371 371 elif not dryrun:
372 372 try:
373 373 if exists:
374 374 os.unlink(target)
375 375 targetdir = os.path.dirname(target) or '.'
376 376 if not os.path.isdir(targetdir):
377 377 os.makedirs(targetdir)
378 378 util.copyfile(src, target)
379 379 except IOError, inst:
380 380 if inst.errno == errno.ENOENT:
381 381 ui.warn(_('%s: deleted in working copy\n') % relsrc)
382 382 else:
383 383 ui.warn(_('%s: cannot copy - %s\n') %
384 384 (relsrc, inst.strerror))
385 385 return True # report a failure
386 386
387 387 if ui.verbose or not exact:
388 388 action = rename and "moving" or "copying"
389 389 ui.status(_('%s %s to %s\n') % (action, relsrc, reltarget))
390 390
391 391 targets[abstarget] = abssrc
392 392
393 393 # fix up dirstate
394 394 origsrc = repo.dirstate.copied(abssrc) or abssrc
395 395 if abstarget == origsrc: # copying back a copy?
396 396 if state not in 'mn' and not dryrun:
397 397 repo.dirstate.normallookup(abstarget)
398 398 else:
399 399 if repo.dirstate[origsrc] == 'a' and origsrc == abssrc:
400 400 if not ui.quiet:
401 401 ui.warn(_("%s has not been committed yet, so no copy "
402 402 "data will be stored for %s.\n")
403 403 % (repo.pathto(origsrc, cwd), reltarget))
404 404 if repo.dirstate[abstarget] in '?r' and not dryrun:
405 405 repo.add([abstarget])
406 406 elif not dryrun:
407 407 repo.copy(origsrc, abstarget)
408 408
409 409 if rename and not dryrun:
410 410 repo.remove([abssrc], not after)
411 411
412 412 # pat: ossep
413 413 # dest ossep
414 414 # srcs: list of (hgsep, hgsep, ossep, bool)
415 415 # return: function that takes hgsep and returns ossep
416 416 def targetpathfn(pat, dest, srcs):
417 417 if os.path.isdir(pat):
418 418 abspfx = util.canonpath(repo.root, cwd, pat)
419 419 abspfx = util.localpath(abspfx)
420 420 if destdirexists:
421 421 striplen = len(os.path.split(abspfx)[0])
422 422 else:
423 423 striplen = len(abspfx)
424 424 if striplen:
425 425 striplen += len(os.sep)
426 426 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
427 427 elif destdirexists:
428 428 res = lambda p: os.path.join(dest,
429 429 os.path.basename(util.localpath(p)))
430 430 else:
431 431 res = lambda p: dest
432 432 return res
433 433
434 434 # pat: ossep
435 435 # dest ossep
436 436 # srcs: list of (hgsep, hgsep, ossep, bool)
437 437 # return: function that takes hgsep and returns ossep
438 438 def targetpathafterfn(pat, dest, srcs):
439 439 if util.patkind(pat, None)[0]:
440 440 # a mercurial pattern
441 441 res = lambda p: os.path.join(dest,
442 442 os.path.basename(util.localpath(p)))
443 443 else:
444 444 abspfx = util.canonpath(repo.root, cwd, pat)
445 445 if len(abspfx) < len(srcs[0][0]):
446 446 # A directory. Either the target path contains the last
447 447 # component of the source path or it does not.
448 448 def evalpath(striplen):
449 449 score = 0
450 450 for s in srcs:
451 451 t = os.path.join(dest, util.localpath(s[0])[striplen:])
452 452 if os.path.exists(t):
453 453 score += 1
454 454 return score
455 455
456 456 abspfx = util.localpath(abspfx)
457 457 striplen = len(abspfx)
458 458 if striplen:
459 459 striplen += len(os.sep)
460 460 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
461 461 score = evalpath(striplen)
462 462 striplen1 = len(os.path.split(abspfx)[0])
463 463 if striplen1:
464 464 striplen1 += len(os.sep)
465 465 if evalpath(striplen1) > score:
466 466 striplen = striplen1
467 467 res = lambda p: os.path.join(dest,
468 468 util.localpath(p)[striplen:])
469 469 else:
470 470 # a file
471 471 if destdirexists:
472 472 res = lambda p: os.path.join(dest,
473 473 os.path.basename(util.localpath(p)))
474 474 else:
475 475 res = lambda p: dest
476 476 return res
477 477
478 478
479 479 pats = util.expand_glob(pats)
480 480 if not pats:
481 481 raise util.Abort(_('no source or destination specified'))
482 482 if len(pats) == 1:
483 483 raise util.Abort(_('no destination specified'))
484 484 dest = pats.pop()
485 485 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
486 486 if not destdirexists:
487 487 if len(pats) > 1 or util.patkind(pats[0], None)[0]:
488 488 raise util.Abort(_('with multiple sources, destination must be an '
489 489 'existing directory'))
490 490 if util.endswithsep(dest):
491 491 raise util.Abort(_('destination %s is not a directory') % dest)
492 492
493 493 tfn = targetpathfn
494 494 if after:
495 495 tfn = targetpathafterfn
496 496 copylist = []
497 497 for pat in pats:
498 498 srcs = walkpat(pat)
499 499 if not srcs:
500 500 continue
501 501 copylist.append((tfn(pat, dest, srcs), srcs))
502 502 if not copylist:
503 503 raise util.Abort(_('no files to copy'))
504 504
505 505 errors = 0
506 506 for targetpath, srcs in copylist:
507 507 for abssrc, relsrc, exact in srcs:
508 508 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
509 509 errors += 1
510 510
511 511 if errors:
512 512 ui.warn(_('(consider using --after)\n'))
513 513
514 514 return errors
515 515
516 516 def service(opts, parentfn=None, initfn=None, runfn=None):
517 517 '''Run a command as a service.'''
518 518
519 519 if opts['daemon'] and not opts['daemon_pipefds']:
520 520 rfd, wfd = os.pipe()
521 521 args = sys.argv[:]
522 522 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
523 523 # Don't pass --cwd to the child process, because we've already
524 524 # changed directory.
525 525 for i in xrange(1,len(args)):
526 526 if args[i].startswith('--cwd='):
527 527 del args[i]
528 528 break
529 529 elif args[i].startswith('--cwd'):
530 530 del args[i:i+2]
531 531 break
532 532 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
533 533 args[0], args)
534 534 os.close(wfd)
535 535 os.read(rfd, 1)
536 536 if parentfn:
537 537 return parentfn(pid)
538 538 else:
539 539 os._exit(0)
540 540
541 541 if initfn:
542 542 initfn()
543 543
544 544 if opts['pid_file']:
545 545 fp = open(opts['pid_file'], 'w')
546 546 fp.write(str(os.getpid()) + '\n')
547 547 fp.close()
548 548
549 549 if opts['daemon_pipefds']:
550 550 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
551 551 os.close(rfd)
552 552 try:
553 553 os.setsid()
554 554 except AttributeError:
555 555 pass
556 556 os.write(wfd, 'y')
557 557 os.close(wfd)
558 558 sys.stdout.flush()
559 559 sys.stderr.flush()
560 560 fd = os.open(util.nulldev, os.O_RDWR)
561 561 if fd != 0: os.dup2(fd, 0)
562 562 if fd != 1: os.dup2(fd, 1)
563 563 if fd != 2: os.dup2(fd, 2)
564 564 if fd not in (0, 1, 2): os.close(fd)
565 565
566 566 if runfn:
567 567 return runfn()
568 568
569 569 class changeset_printer(object):
570 570 '''show changeset information when templating not requested.'''
571 571
572 572 def __init__(self, ui, repo, patch, diffopts, buffered):
573 573 self.ui = ui
574 574 self.repo = repo
575 575 self.buffered = buffered
576 576 self.patch = patch
577 577 self.diffopts = diffopts
578 578 self.header = {}
579 579 self.hunk = {}
580 580 self.lastheader = None
581 581
582 582 def flush(self, rev):
583 583 if rev in self.header:
584 584 h = self.header[rev]
585 585 if h != self.lastheader:
586 586 self.lastheader = h
587 587 self.ui.write(h)
588 588 del self.header[rev]
589 589 if rev in self.hunk:
590 590 self.ui.write(self.hunk[rev])
591 591 del self.hunk[rev]
592 592 return 1
593 593 return 0
594 594
595 595 def show(self, ctx, copies=(), **props):
596 596 if self.buffered:
597 597 self.ui.pushbuffer()
598 598 self._show(ctx, copies, props)
599 599 self.hunk[ctx.rev()] = self.ui.popbuffer()
600 600 else:
601 601 self._show(ctx, copies, props)
602 602
603 603 def _show(self, ctx, copies, props):
604 604 '''show a single changeset or file revision'''
605 605 changenode = ctx.node()
606 606 rev = ctx.rev()
607 607
608 608 if self.ui.quiet:
609 609 self.ui.write("%d:%s\n" % (rev, short(changenode)))
610 610 return
611 611
612 612 log = self.repo.changelog
613 613 changes = log.read(changenode)
614 614 date = util.datestr(changes[2])
615 615 extra = changes[5]
616 616 branch = extra.get("branch")
617 617
618 618 hexfunc = self.ui.debugflag and hex or short
619 619
620 620 parents = [(p, hexfunc(log.node(p)))
621 621 for p in self._meaningful_parentrevs(log, rev)]
622 622
623 623 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
624 624
625 625 # don't show the default branch name
626 626 if branch != 'default':
627 627 branch = util.tolocal(branch)
628 628 self.ui.write(_("branch: %s\n") % branch)
629 629 for tag in self.repo.nodetags(changenode):
630 630 self.ui.write(_("tag: %s\n") % tag)
631 631 for parent in parents:
632 632 self.ui.write(_("parent: %d:%s\n") % parent)
633 633
634 634 if self.ui.debugflag:
635 635 self.ui.write(_("manifest: %d:%s\n") %
636 636 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
637 637 self.ui.write(_("user: %s\n") % changes[1])
638 638 self.ui.write(_("date: %s\n") % date)
639 639
640 640 if self.ui.debugflag:
641 641 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
642 642 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
643 643 files):
644 644 if value:
645 645 self.ui.write("%-12s %s\n" % (key, " ".join(value)))
646 646 elif changes[3] and self.ui.verbose:
647 647 self.ui.write(_("files: %s\n") % " ".join(changes[3]))
648 648 if copies and self.ui.verbose:
649 649 copies = ['%s (%s)' % c for c in copies]
650 650 self.ui.write(_("copies: %s\n") % ' '.join(copies))
651 651
652 652 if extra and self.ui.debugflag:
653 653 for key, value in util.sort(extra.items()):
654 654 self.ui.write(_("extra: %s=%s\n")
655 655 % (key, value.encode('string_escape')))
656 656
657 657 description = changes[4].strip()
658 658 if description:
659 659 if self.ui.verbose:
660 660 self.ui.write(_("description:\n"))
661 661 self.ui.write(description)
662 662 self.ui.write("\n\n")
663 663 else:
664 664 self.ui.write(_("summary: %s\n") %
665 665 description.splitlines()[0])
666 666 self.ui.write("\n")
667 667
668 668 self.showpatch(changenode)
669 669
670 670 def showpatch(self, node):
671 671 if self.patch:
672 672 prev = self.repo.changelog.parents(node)[0]
673 673 chunks = patch.diff(self.repo, prev, node, match=self.patch,
674 674 opts=patch.diffopts(self.ui, self.diffopts))
675 675 for chunk in chunks:
676 676 self.ui.write(chunk)
677 677 self.ui.write("\n")
678 678
679 679 def _meaningful_parentrevs(self, log, rev):
680 680 """Return list of meaningful (or all if debug) parentrevs for rev.
681 681
682 682 For merges (two non-nullrev revisions) both parents are meaningful.
683 683 Otherwise the first parent revision is considered meaningful if it
684 684 is not the preceding revision.
685 685 """
686 686 parents = log.parentrevs(rev)
687 687 if not self.ui.debugflag and parents[1] == nullrev:
688 688 if parents[0] >= rev - 1:
689 689 parents = []
690 690 else:
691 691 parents = [parents[0]]
692 692 return parents
693 693
694 694
695 695 class changeset_templater(changeset_printer):
696 696 '''format changeset information.'''
697 697
698 698 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
699 699 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
700 700 filters = templatefilters.filters.copy()
701 701 filters['formatnode'] = (ui.debugflag and (lambda x: x)
702 702 or (lambda x: x[:12]))
703 703 self.t = templater.templater(mapfile, filters,
704 704 cache={
705 705 'parent': '{rev}:{node|formatnode} ',
706 706 'manifest': '{rev}:{node|formatnode}',
707 707 'filecopy': '{name} ({source})'})
708 708
709 709 def use_template(self, t):
710 710 '''set template string to use'''
711 711 self.t.cache['changeset'] = t
712 712
713 713 def _show(self, ctx, copies, props):
714 714 '''show a single changeset or file revision'''
715 715 changenode = ctx.node()
716 716 rev = ctx.rev()
717 717
718 718 log = self.repo.changelog
719 719 changes = log.read(changenode)
720 720
721 721 def showlist(name, values, plural=None, **args):
722 722 '''expand set of values.
723 723 name is name of key in template map.
724 724 values is list of strings or dicts.
725 725 plural is plural of name, if not simply name + 's'.
726 726
727 727 expansion works like this, given name 'foo'.
728 728
729 729 if values is empty, expand 'no_foos'.
730 730
731 731 if 'foo' not in template map, return values as a string,
732 732 joined by space.
733 733
734 734 expand 'start_foos'.
735 735
736 736 for each value, expand 'foo'. if 'last_foo' in template
737 737 map, expand it instead of 'foo' for last key.
738 738
739 739 expand 'end_foos'.
740 740 '''
741 741 if plural: names = plural
742 742 else: names = name + 's'
743 743 if not values:
744 744 noname = 'no_' + names
745 745 if noname in self.t:
746 746 yield self.t(noname, **args)
747 747 return
748 748 if name not in self.t:
749 749 if isinstance(values[0], str):
750 750 yield ' '.join(values)
751 751 else:
752 752 for v in values:
753 753 yield dict(v, **args)
754 754 return
755 755 startname = 'start_' + names
756 756 if startname in self.t:
757 757 yield self.t(startname, **args)
758 758 vargs = args.copy()
759 759 def one(v, tag=name):
760 760 try:
761 761 vargs.update(v)
762 762 except (AttributeError, ValueError):
763 763 try:
764 764 for a, b in v:
765 765 vargs[a] = b
766 766 except ValueError:
767 767 vargs[name] = v
768 768 return self.t(tag, **vargs)
769 769 lastname = 'last_' + name
770 770 if lastname in self.t:
771 771 last = values.pop()
772 772 else:
773 773 last = None
774 774 for v in values:
775 775 yield one(v)
776 776 if last is not None:
777 777 yield one(last, tag=lastname)
778 778 endname = 'end_' + names
779 779 if endname in self.t:
780 780 yield self.t(endname, **args)
781 781
782 782 def showbranches(**args):
783 783 branch = changes[5].get("branch")
784 784 if branch != 'default':
785 785 branch = util.tolocal(branch)
786 786 return showlist('branch', [branch], plural='branches', **args)
787 787
788 788 def showparents(**args):
789 789 parents = [[('rev', p), ('node', hex(log.node(p)))]
790 790 for p in self._meaningful_parentrevs(log, rev)]
791 791 return showlist('parent', parents, **args)
792 792
793 793 def showtags(**args):
794 794 return showlist('tag', self.repo.nodetags(changenode), **args)
795 795
796 796 def showextras(**args):
797 797 for key, value in util.sort(changes[5].items()):
798 798 args = args.copy()
799 799 args.update(dict(key=key, value=value))
800 800 yield self.t('extra', **args)
801 801
802 802 def showcopies(**args):
803 803 c = [{'name': x[0], 'source': x[1]} for x in copies]
804 804 return showlist('file_copy', c, plural='file_copies', **args)
805 805
806 806 files = []
807 807 def getfiles():
808 808 if not files:
809 809 files[:] = self.repo.status(
810 810 log.parents(changenode)[0], changenode)[:3]
811 811 return files
812 812 def showfiles(**args):
813 813 return showlist('file', changes[3], **args)
814 814 def showmods(**args):
815 815 return showlist('file_mod', getfiles()[0], **args)
816 816 def showadds(**args):
817 817 return showlist('file_add', getfiles()[1], **args)
818 818 def showdels(**args):
819 819 return showlist('file_del', getfiles()[2], **args)
820 820 def showmanifest(**args):
821 821 args = args.copy()
822 822 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
823 823 node=hex(changes[0])))
824 824 return self.t('manifest', **args)
825 825
826 826 defprops = {
827 827 'author': changes[1],
828 828 'branches': showbranches,
829 829 'date': changes[2],
830 830 'desc': changes[4].strip(),
831 831 'file_adds': showadds,
832 832 'file_dels': showdels,
833 833 'file_mods': showmods,
834 834 'files': showfiles,
835 835 'file_copies': showcopies,
836 836 'manifest': showmanifest,
837 837 'node': hex(changenode),
838 838 'parents': showparents,
839 839 'rev': rev,
840 840 'tags': showtags,
841 841 'extras': showextras,
842 842 }
843 843 props = props.copy()
844 844 props.update(defprops)
845 845
846 846 try:
847 847 if self.ui.debugflag and 'header_debug' in self.t:
848 848 key = 'header_debug'
849 849 elif self.ui.quiet and 'header_quiet' in self.t:
850 850 key = 'header_quiet'
851 851 elif self.ui.verbose and 'header_verbose' in self.t:
852 852 key = 'header_verbose'
853 853 elif 'header' in self.t:
854 854 key = 'header'
855 855 else:
856 856 key = ''
857 857 if key:
858 858 h = templater.stringify(self.t(key, **props))
859 859 if self.buffered:
860 860 self.header[rev] = h
861 861 else:
862 862 self.ui.write(h)
863 863 if self.ui.debugflag and 'changeset_debug' in self.t:
864 864 key = 'changeset_debug'
865 865 elif self.ui.quiet and 'changeset_quiet' in self.t:
866 866 key = 'changeset_quiet'
867 867 elif self.ui.verbose and 'changeset_verbose' in self.t:
868 868 key = 'changeset_verbose'
869 869 else:
870 870 key = 'changeset'
871 871 self.ui.write(templater.stringify(self.t(key, **props)))
872 872 self.showpatch(changenode)
873 873 except KeyError, inst:
874 874 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
875 875 inst.args[0]))
876 876 except SyntaxError, inst:
877 877 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
878 878
879 879 def show_changeset(ui, repo, opts, buffered=False, matchfn=False):
880 880 """show one changeset using template or regular display.
881 881
882 882 Display format will be the first non-empty hit of:
883 883 1. option 'template'
884 884 2. option 'style'
885 885 3. [ui] setting 'logtemplate'
886 886 4. [ui] setting 'style'
887 887 If all of these values are either the unset or the empty string,
888 888 regular display via changeset_printer() is done.
889 889 """
890 890 # options
891 891 patch = False
892 892 if opts.get('patch'):
893 893 patch = matchfn or matchall(repo)
894 894
895 895 tmpl = opts.get('template')
896 896 mapfile = None
897 897 if tmpl:
898 898 tmpl = templater.parsestring(tmpl, quoted=False)
899 899 else:
900 900 mapfile = opts.get('style')
901 901 # ui settings
902 902 if not mapfile:
903 903 tmpl = ui.config('ui', 'logtemplate')
904 904 if tmpl:
905 905 tmpl = templater.parsestring(tmpl)
906 906 else:
907 907 mapfile = ui.config('ui', 'style')
908 908
909 909 if tmpl or mapfile:
910 910 if mapfile:
911 911 if not os.path.split(mapfile)[0]:
912 912 mapname = (templater.templatepath('map-cmdline.' + mapfile)
913 913 or templater.templatepath(mapfile))
914 914 if mapname: mapfile = mapname
915 915 try:
916 916 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
917 917 except SyntaxError, inst:
918 918 raise util.Abort(inst.args[0])
919 919 if tmpl: t.use_template(tmpl)
920 920 return t
921 921 return changeset_printer(ui, repo, patch, opts, buffered)
922 922
923 923 def finddate(ui, repo, date):
924 924 """Find the tipmost changeset that matches the given date spec"""
925 925 df = util.matchdate(date)
926 926 get = util.cachefunc(lambda r: repo[r].changeset())
927 927 changeiter, matchfn = walkchangerevs(ui, repo, [], get, {'rev':None})
928 928 results = {}
929 929 for st, rev, fns in changeiter:
930 930 if st == 'add':
931 931 d = get(rev)[2]
932 932 if df(d[0]):
933 933 results[rev] = d
934 934 elif st == 'iter':
935 935 if rev in results:
936 936 ui.status(_("Found revision %s from %s\n") %
937 937 (rev, util.datestr(results[rev])))
938 938 return str(rev)
939 939
940 940 raise util.Abort(_("revision matching date not found"))
941 941
942 942 def walkchangerevs(ui, repo, pats, change, opts):
943 '''Iterate over files and the revs they changed in.
943 '''Iterate over files and the revs in which they changed.
944 944
945 945 Callers most commonly need to iterate backwards over the history
946 it is interested in. Doing so has awful (quadratic-looking)
946 in which they are interested. Doing so has awful (quadratic-looking)
947 947 performance, so we use iterators in a "windowed" way.
948 948
949 949 We walk a window of revisions in the desired order. Within the
950 950 window, we first walk forwards to gather data, then in the desired
951 951 order (usually backwards) to display it.
952 952
953 953 This function returns an (iterator, matchfn) tuple. The iterator
954 954 yields 3-tuples. They will be of one of the following forms:
955 955
956 956 "window", incrementing, lastrev: stepping through a window,
957 957 positive if walking forwards through revs, last rev in the
958 958 sequence iterated over - use to reset state for the current window
959 959
960 960 "add", rev, fns: out-of-order traversal of the given file names
961 961 fns, which changed during revision rev - use to gather data for
962 962 possible display
963 963
964 964 "iter", rev, None: in-order traversal of the revs earlier iterated
965 965 over with "add" - use to display data'''
966 966
967 967 def increasing_windows(start, end, windowsize=8, sizelimit=512):
968 968 if start < end:
969 969 while start < end:
970 970 yield start, min(windowsize, end-start)
971 971 start += windowsize
972 972 if windowsize < sizelimit:
973 973 windowsize *= 2
974 974 else:
975 975 while start > end:
976 976 yield start, min(windowsize, start-end-1)
977 977 start -= windowsize
978 978 if windowsize < sizelimit:
979 979 windowsize *= 2
980 980
981 981 m = match(repo, pats, opts)
982 982 follow = opts.get('follow') or opts.get('follow_first')
983 983
984 984 if not len(repo):
985 985 return [], m
986 986
987 987 if follow:
988 988 defrange = '%s:0' % repo['.'].rev()
989 989 else:
990 990 defrange = '-1:0'
991 991 revs = revrange(repo, opts['rev'] or [defrange])
992 992 wanted = {}
993 993 slowpath = m.anypats() or (m.files() and opts.get('removed'))
994 994 fncache = {}
995 995
996 996 if not slowpath and not m.files():
997 997 # No files, no patterns. Display all revs.
998 998 wanted = dict.fromkeys(revs)
999 999 copies = []
1000 1000 if not slowpath:
1001 1001 # Only files, no patterns. Check the history of each file.
1002 1002 def filerevgen(filelog, node):
1003 1003 cl_count = len(repo)
1004 1004 if node is None:
1005 1005 last = len(filelog) - 1
1006 1006 else:
1007 1007 last = filelog.rev(node)
1008 1008 for i, window in increasing_windows(last, nullrev):
1009 1009 revs = []
1010 1010 for j in xrange(i - window, i + 1):
1011 1011 n = filelog.node(j)
1012 1012 revs.append((filelog.linkrev(j),
1013 1013 follow and filelog.renamed(n)))
1014 1014 revs.reverse()
1015 1015 for rev in revs:
1016 1016 # only yield rev for which we have the changelog, it can
1017 1017 # happen while doing "hg log" during a pull or commit
1018 1018 if rev[0] < cl_count:
1019 1019 yield rev
1020 1020 def iterfiles():
1021 1021 for filename in m.files():
1022 1022 yield filename, None
1023 1023 for filename_node in copies:
1024 1024 yield filename_node
1025 1025 minrev, maxrev = min(revs), max(revs)
1026 1026 for file_, node in iterfiles():
1027 1027 filelog = repo.file(file_)
1028 1028 if not len(filelog):
1029 1029 if node is None:
1030 1030 # A zero count may be a directory or deleted file, so
1031 1031 # try to find matching entries on the slow path.
1032 1032 if follow:
1033 1033 raise util.Abort(_('cannot follow nonexistent file: "%s"') % file_)
1034 1034 slowpath = True
1035 1035 break
1036 1036 else:
1037 1037 ui.warn(_('%s:%s copy source revision cannot be found!\n')
1038 1038 % (file_, short(node)))
1039 1039 continue
1040 1040 for rev, copied in filerevgen(filelog, node):
1041 1041 if rev <= maxrev:
1042 1042 if rev < minrev:
1043 1043 break
1044 1044 fncache.setdefault(rev, [])
1045 1045 fncache[rev].append(file_)
1046 1046 wanted[rev] = 1
1047 1047 if follow and copied:
1048 1048 copies.append(copied)
1049 1049 if slowpath:
1050 1050 if follow:
1051 1051 raise util.Abort(_('can only follow copies/renames for explicit '
1052 1052 'file names'))
1053 1053
1054 1054 # The slow path checks files modified in every changeset.
1055 1055 def changerevgen():
1056 1056 for i, window in increasing_windows(len(repo) - 1, nullrev):
1057 1057 for j in xrange(i - window, i + 1):
1058 1058 yield j, change(j)[3]
1059 1059
1060 1060 for rev, changefiles in changerevgen():
1061 1061 matches = filter(m, changefiles)
1062 1062 if matches:
1063 1063 fncache[rev] = matches
1064 1064 wanted[rev] = 1
1065 1065
1066 1066 class followfilter:
1067 1067 def __init__(self, onlyfirst=False):
1068 1068 self.startrev = nullrev
1069 1069 self.roots = []
1070 1070 self.onlyfirst = onlyfirst
1071 1071
1072 1072 def match(self, rev):
1073 1073 def realparents(rev):
1074 1074 if self.onlyfirst:
1075 1075 return repo.changelog.parentrevs(rev)[0:1]
1076 1076 else:
1077 1077 return filter(lambda x: x != nullrev,
1078 1078 repo.changelog.parentrevs(rev))
1079 1079
1080 1080 if self.startrev == nullrev:
1081 1081 self.startrev = rev
1082 1082 return True
1083 1083
1084 1084 if rev > self.startrev:
1085 1085 # forward: all descendants
1086 1086 if not self.roots:
1087 1087 self.roots.append(self.startrev)
1088 1088 for parent in realparents(rev):
1089 1089 if parent in self.roots:
1090 1090 self.roots.append(rev)
1091 1091 return True
1092 1092 else:
1093 1093 # backwards: all parents
1094 1094 if not self.roots:
1095 1095 self.roots.extend(realparents(self.startrev))
1096 1096 if rev in self.roots:
1097 1097 self.roots.remove(rev)
1098 1098 self.roots.extend(realparents(rev))
1099 1099 return True
1100 1100
1101 1101 return False
1102 1102
1103 1103 # it might be worthwhile to do this in the iterator if the rev range
1104 1104 # is descending and the prune args are all within that range
1105 1105 for rev in opts.get('prune', ()):
1106 1106 rev = repo.changelog.rev(repo.lookup(rev))
1107 1107 ff = followfilter()
1108 1108 stop = min(revs[0], revs[-1])
1109 1109 for x in xrange(rev, stop-1, -1):
1110 1110 if ff.match(x) and x in wanted:
1111 1111 del wanted[x]
1112 1112
1113 1113 def iterate():
1114 1114 if follow and not m.files():
1115 1115 ff = followfilter(onlyfirst=opts.get('follow_first'))
1116 1116 def want(rev):
1117 1117 if ff.match(rev) and rev in wanted:
1118 1118 return True
1119 1119 return False
1120 1120 else:
1121 1121 def want(rev):
1122 1122 return rev in wanted
1123 1123
1124 1124 for i, window in increasing_windows(0, len(revs)):
1125 1125 yield 'window', revs[0] < revs[-1], revs[-1]
1126 1126 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
1127 1127 for rev in util.sort(list(nrevs)):
1128 1128 fns = fncache.get(rev)
1129 1129 if not fns:
1130 1130 def fns_generator():
1131 1131 for f in change(rev)[3]:
1132 1132 if m(f):
1133 1133 yield f
1134 1134 fns = fns_generator()
1135 1135 yield 'add', rev, fns
1136 1136 for rev in nrevs:
1137 1137 yield 'iter', rev, None
1138 1138 return iterate(), m
1139 1139
1140 1140 def commit(ui, repo, commitfunc, pats, opts):
1141 1141 '''commit the specified files or all outstanding changes'''
1142 1142 date = opts.get('date')
1143 1143 if date:
1144 1144 opts['date'] = util.parsedate(date)
1145 1145 message = logmessage(opts)
1146 1146
1147 1147 # extract addremove carefully -- this function can be called from a command
1148 1148 # that doesn't support addremove
1149 1149 if opts.get('addremove'):
1150 1150 addremove(repo, pats, opts)
1151 1151
1152 1152 m = match(repo, pats, opts)
1153 1153 if pats:
1154 1154 modified, added, removed = repo.status(match=m)[:3]
1155 1155 files = util.sort(modified + added + removed)
1156 1156
1157 1157 def is_dir(f):
1158 1158 name = f + '/'
1159 1159 i = bisect.bisect(files, name)
1160 1160 return i < len(files) and files[i].startswith(name)
1161 1161
1162 1162 for f in m.files():
1163 1163 if f == '.':
1164 1164 continue
1165 1165 if f not in files:
1166 1166 rf = repo.wjoin(f)
1167 1167 rel = repo.pathto(f)
1168 1168 try:
1169 1169 mode = os.lstat(rf)[stat.ST_MODE]
1170 1170 except OSError:
1171 1171 if is_dir(f): # deleted directory ?
1172 1172 continue
1173 1173 raise util.Abort(_("file %s not found!") % rel)
1174 1174 if stat.S_ISDIR(mode):
1175 1175 if not is_dir(f):
1176 1176 raise util.Abort(_("no match under directory %s!")
1177 1177 % rel)
1178 1178 elif not (stat.S_ISREG(mode) or stat.S_ISLNK(mode)):
1179 1179 raise util.Abort(_("can't commit %s: "
1180 1180 "unsupported file type!") % rel)
1181 1181 elif f not in repo.dirstate:
1182 1182 raise util.Abort(_("file %s not tracked!") % rel)
1183 1183 m = matchfiles(repo, files)
1184 1184 try:
1185 1185 return commitfunc(ui, repo, message, m, opts)
1186 1186 except ValueError, inst:
1187 1187 raise util.Abort(str(inst))
@@ -1,3416 +1,3416 b''
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from node import hex, nullid, nullrev, short
9 9 from i18n import _, gettext
10 10 import os, re, sys
11 11 import hg, util, revlog, bundlerepo, extensions, copies, context, error
12 12 import difflib, patch, time, help, mdiff, tempfile, url
13 13 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
14 14 import merge as merge_
15 15
16 16 # Commands start here, listed alphabetically
17 17
18 18 def add(ui, repo, *pats, **opts):
19 19 """add the specified files on the next commit
20 20
21 21 Schedule files to be version controlled and added to the repository.
22 22
23 23 The files will be added to the repository at the next commit. To
24 24 undo an add before that, see hg revert.
25 25
26 If no names are given, add all files in the repository.
26 If no names are given, add all files to the repository.
27 27 """
28 28
29 29 rejected = None
30 30 exacts = {}
31 31 names = []
32 32 m = cmdutil.match(repo, pats, opts)
33 33 m.bad = lambda x,y: True
34 34 for abs in repo.walk(m):
35 35 if m.exact(abs):
36 36 if ui.verbose:
37 37 ui.status(_('adding %s\n') % m.rel(abs))
38 38 names.append(abs)
39 39 exacts[abs] = 1
40 40 elif abs not in repo.dirstate:
41 41 ui.status(_('adding %s\n') % m.rel(abs))
42 42 names.append(abs)
43 43 if not opts.get('dry_run'):
44 44 rejected = repo.add(names)
45 45 rejected = [p for p in rejected if p in exacts]
46 46 return rejected and 1 or 0
47 47
48 48 def addremove(ui, repo, *pats, **opts):
49 49 """add all new files, delete all missing files
50 50
51 51 Add all new files and remove all missing files from the repository.
52 52
53 53 New files are ignored if they match any of the patterns in .hgignore. As
54 54 with add, these changes take effect at the next commit.
55 55
56 56 Use the -s option to detect renamed files. With a parameter > 0,
57 57 this compares every removed file with every added file and records
58 58 those similar enough as renames. This option takes a percentage
59 59 between 0 (disabled) and 100 (files must be identical) as its
60 60 parameter. Detecting renamed files this way can be expensive.
61 61 """
62 62 try:
63 63 sim = float(opts.get('similarity') or 0)
64 64 except ValueError:
65 65 raise util.Abort(_('similarity must be a number'))
66 66 if sim < 0 or sim > 100:
67 67 raise util.Abort(_('similarity must be between 0 and 100'))
68 68 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
69 69
70 70 def annotate(ui, repo, *pats, **opts):
71 71 """show changeset information per file line
72 72
73 73 List changes in files, showing the revision id responsible for each line
74 74
75 75 This command is useful to discover who did a change or when a change took
76 76 place.
77 77
78 78 Without the -a option, annotate will avoid processing files it
79 79 detects as binary. With -a, annotate will generate an annotation
80 80 anyway, probably with undesirable results.
81 81 """
82 82 datefunc = ui.quiet and util.shortdate or util.datestr
83 83 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
84 84
85 85 if not pats:
86 86 raise util.Abort(_('at least one file name or pattern required'))
87 87
88 88 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
89 89 ('number', lambda x: str(x[0].rev())),
90 90 ('changeset', lambda x: short(x[0].node())),
91 91 ('date', getdate),
92 92 ('follow', lambda x: x[0].path()),
93 93 ]
94 94
95 95 if (not opts.get('user') and not opts.get('changeset') and not opts.get('date')
96 96 and not opts.get('follow')):
97 97 opts['number'] = 1
98 98
99 99 linenumber = opts.get('line_number') is not None
100 100 if (linenumber and (not opts.get('changeset')) and (not opts.get('number'))):
101 101 raise util.Abort(_('at least one of -n/-c is required for -l'))
102 102
103 103 funcmap = [func for op, func in opmap if opts.get(op)]
104 104 if linenumber:
105 105 lastfunc = funcmap[-1]
106 106 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
107 107
108 108 ctx = repo[opts.get('rev')]
109 109
110 110 m = cmdutil.match(repo, pats, opts)
111 111 for abs in ctx.walk(m):
112 112 fctx = ctx[abs]
113 113 if not opts.get('text') and util.binary(fctx.data()):
114 114 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
115 115 continue
116 116
117 117 lines = fctx.annotate(follow=opts.get('follow'),
118 118 linenumber=linenumber)
119 119 pieces = []
120 120
121 121 for f in funcmap:
122 122 l = [f(n) for n, dummy in lines]
123 123 if l:
124 124 ml = max(map(len, l))
125 125 pieces.append(["%*s" % (ml, x) for x in l])
126 126
127 127 if pieces:
128 128 for p, l in zip(zip(*pieces), lines):
129 129 ui.write("%s: %s" % (" ".join(p), l[1]))
130 130
131 131 def archive(ui, repo, dest, **opts):
132 132 '''create unversioned archive of a repository revision
133 133
134 134 By default, the revision used is the parent of the working
135 135 directory; use "-r" to specify a different revision.
136 136
137 137 To specify the type of archive to create, use "-t". Valid
138 138 types are:
139 139
140 140 "files" (default): a directory full of files
141 141 "tar": tar archive, uncompressed
142 142 "tbz2": tar archive, compressed using bzip2
143 143 "tgz": tar archive, compressed using gzip
144 144 "uzip": zip archive, uncompressed
145 145 "zip": zip archive, compressed using deflate
146 146
147 147 The exact name of the destination archive or directory is given
148 148 using a format string; see "hg help export" for details.
149 149
150 150 Each member added to an archive file has a directory prefix
151 151 prepended. Use "-p" to specify a format string for the prefix.
152 152 The default is the basename of the archive, with suffixes removed.
153 153 '''
154 154
155 155 ctx = repo[opts.get('rev')]
156 156 if not ctx:
157 157 raise util.Abort(_('no working directory: please specify a revision'))
158 158 node = ctx.node()
159 159 dest = cmdutil.make_filename(repo, dest, node)
160 160 if os.path.realpath(dest) == repo.root:
161 161 raise util.Abort(_('repository root cannot be destination'))
162 162 matchfn = cmdutil.match(repo, [], opts)
163 163 kind = opts.get('type') or 'files'
164 164 prefix = opts.get('prefix')
165 165 if dest == '-':
166 166 if kind == 'files':
167 167 raise util.Abort(_('cannot archive plain files to stdout'))
168 168 dest = sys.stdout
169 169 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
170 170 prefix = cmdutil.make_filename(repo, prefix, node)
171 171 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
172 172 matchfn, prefix)
173 173
174 174 def backout(ui, repo, node=None, rev=None, **opts):
175 175 '''reverse effect of earlier changeset
176 176
177 177 Commit the backed out changes as a new changeset. The new
178 178 changeset is a child of the backed out changeset.
179 179
180 180 If you back out a changeset other than the tip, a new head is
181 181 created. This head will be the new tip and you should merge this
182 182 backout changeset with another head (current one by default).
183 183
184 184 The --merge option remembers the parent of the working directory
185 185 before starting the backout, then merges the new head with that
186 186 changeset afterwards. This saves you from doing the merge by
187 hand. The result of this merge is not committed, as for a normal
187 hand. The result of this merge is not committed, as with a normal
188 188 merge.
189 189
190 190 See \'hg help dates\' for a list of formats valid for -d/--date.
191 191 '''
192 192 if rev and node:
193 193 raise util.Abort(_("please specify just one revision"))
194 194
195 195 if not rev:
196 196 rev = node
197 197
198 198 if not rev:
199 199 raise util.Abort(_("please specify a revision to backout"))
200 200
201 201 date = opts.get('date')
202 202 if date:
203 203 opts['date'] = util.parsedate(date)
204 204
205 205 cmdutil.bail_if_changed(repo)
206 206 node = repo.lookup(rev)
207 207
208 208 op1, op2 = repo.dirstate.parents()
209 209 a = repo.changelog.ancestor(op1, node)
210 210 if a != node:
211 211 raise util.Abort(_('cannot back out change on a different branch'))
212 212
213 213 p1, p2 = repo.changelog.parents(node)
214 214 if p1 == nullid:
215 215 raise util.Abort(_('cannot back out a change with no parents'))
216 216 if p2 != nullid:
217 217 if not opts.get('parent'):
218 218 raise util.Abort(_('cannot back out a merge changeset without '
219 219 '--parent'))
220 220 p = repo.lookup(opts['parent'])
221 221 if p not in (p1, p2):
222 222 raise util.Abort(_('%s is not a parent of %s') %
223 223 (short(p), short(node)))
224 224 parent = p
225 225 else:
226 226 if opts.get('parent'):
227 227 raise util.Abort(_('cannot use --parent on non-merge changeset'))
228 228 parent = p1
229 229
230 230 # the backout should appear on the same branch
231 231 branch = repo.dirstate.branch()
232 232 hg.clean(repo, node, show_stats=False)
233 233 repo.dirstate.setbranch(branch)
234 234 revert_opts = opts.copy()
235 235 revert_opts['date'] = None
236 236 revert_opts['all'] = True
237 237 revert_opts['rev'] = hex(parent)
238 238 revert_opts['no_backup'] = None
239 239 revert(ui, repo, **revert_opts)
240 240 commit_opts = opts.copy()
241 241 commit_opts['addremove'] = False
242 242 if not commit_opts['message'] and not commit_opts['logfile']:
243 243 commit_opts['message'] = _("Backed out changeset %s") % (short(node))
244 244 commit_opts['force_editor'] = True
245 245 commit(ui, repo, **commit_opts)
246 246 def nice(node):
247 247 return '%d:%s' % (repo.changelog.rev(node), short(node))
248 248 ui.status(_('changeset %s backs out changeset %s\n') %
249 249 (nice(repo.changelog.tip()), nice(node)))
250 250 if op1 != node:
251 251 hg.clean(repo, op1, show_stats=False)
252 252 if opts.get('merge'):
253 253 ui.status(_('merging with changeset %s\n') % nice(repo.changelog.tip()))
254 254 hg.merge(repo, hex(repo.changelog.tip()))
255 255 else:
256 256 ui.status(_('the backout changeset is a new head - '
257 257 'do not forget to merge\n'))
258 258 ui.status(_('(use "backout --merge" '
259 259 'if you want to auto-merge)\n'))
260 260
261 261 def bisect(ui, repo, rev=None, extra=None, command=None,
262 262 reset=None, good=None, bad=None, skip=None, noupdate=None):
263 263 """subdivision search of changesets
264 264
265 265 This command helps to find changesets which introduce problems.
266 266 To use, mark the earliest changeset you know exhibits the problem
267 267 as bad, then mark the latest changeset which is free from the
268 268 problem as good. Bisect will update your working directory to a
269 269 revision for testing (unless the --noupdate option is specified).
270 270 Once you have performed tests, mark the working directory as bad
271 271 or good and bisect will either update to another candidate changeset
272 272 or announce that it has found the bad revision.
273 273
274 274 As a shortcut, you can also use the revision argument to mark a
275 275 revision as good or bad without checking it out first.
276 276
277 277 If you supply a command it will be used for automatic bisection. Its exit
278 278 status will be used as flag to mark revision as bad or good. In case exit
279 279 status is 0 the revision is marked as good, 125 - skipped, 127 (command not
280 found) - bisection will be aborted and any other status bigger than 0 will
280 found) - bisection will be aborted; any other status bigger than 0 will
281 281 mark revision as bad.
282 282 """
283 283 def print_result(nodes, good):
284 284 displayer = cmdutil.show_changeset(ui, repo, {})
285 285 transition = (good and "good" or "bad")
286 286 if len(nodes) == 1:
287 287 # narrowed it down to a single revision
288 288 ui.write(_("The first %s revision is:\n") % transition)
289 289 displayer.show(repo[nodes[0]])
290 290 else:
291 291 # multiple possible revisions
292 292 ui.write(_("Due to skipped revisions, the first "
293 293 "%s revision could be any of:\n") % transition)
294 294 for n in nodes:
295 295 displayer.show(repo[n])
296 296
297 297 def check_state(state, interactive=True):
298 298 if not state['good'] or not state['bad']:
299 299 if (good or bad or skip or reset) and interactive:
300 300 return
301 301 if not state['good']:
302 302 raise util.Abort(_('cannot bisect (no known good revisions)'))
303 303 else:
304 304 raise util.Abort(_('cannot bisect (no known bad revisions)'))
305 305 return True
306 306
307 307 # backward compatibility
308 308 if rev in "good bad reset init".split():
309 309 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
310 310 cmd, rev, extra = rev, extra, None
311 311 if cmd == "good":
312 312 good = True
313 313 elif cmd == "bad":
314 314 bad = True
315 315 else:
316 316 reset = True
317 317 elif extra or good + bad + skip + reset + bool(command) > 1:
318 318 raise util.Abort(_('incompatible arguments'))
319 319
320 320 if reset:
321 321 p = repo.join("bisect.state")
322 322 if os.path.exists(p):
323 323 os.unlink(p)
324 324 return
325 325
326 326 state = hbisect.load_state(repo)
327 327
328 328 if command:
329 329 commandpath = util.find_exe(command)
330 330 changesets = 1
331 331 try:
332 332 while changesets:
333 333 # update state
334 334 status = os.spawnl(os.P_WAIT, commandpath)
335 335 if status == 125:
336 336 transition = "skip"
337 337 elif status == 0:
338 338 transition = "good"
339 339 # status < 0 means process was killed
340 340 elif status == 127:
341 341 raise util.Abort(_("failed to execute %s") % command)
342 342 elif status < 0:
343 343 raise util.Abort(_("%s killed") % command)
344 344 else:
345 345 transition = "bad"
346 346 node = repo.lookup(rev or '.')
347 347 state[transition].append(node)
348 348 ui.note(_('Changeset %s: %s\n') % (short(node), transition))
349 349 check_state(state, interactive=False)
350 350 # bisect
351 351 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
352 352 # update to next check
353 353 cmdutil.bail_if_changed(repo)
354 354 hg.clean(repo, nodes[0], show_stats=False)
355 355 finally:
356 356 hbisect.save_state(repo, state)
357 357 return print_result(nodes, not status)
358 358
359 359 # update state
360 360 node = repo.lookup(rev or '.')
361 361 if good:
362 362 state['good'].append(node)
363 363 elif bad:
364 364 state['bad'].append(node)
365 365 elif skip:
366 366 state['skip'].append(node)
367 367
368 368 hbisect.save_state(repo, state)
369 369
370 370 if not check_state(state):
371 371 return
372 372
373 373 # actually bisect
374 374 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
375 375 if changesets == 0:
376 376 print_result(nodes, good)
377 377 else:
378 378 assert len(nodes) == 1 # only a single node can be tested next
379 379 node = nodes[0]
380 380 # compute the approximate number of remaining tests
381 381 tests, size = 0, 2
382 382 while size <= changesets:
383 383 tests, size = tests + 1, size * 2
384 384 rev = repo.changelog.rev(node)
385 385 ui.write(_("Testing changeset %s:%s "
386 386 "(%s changesets remaining, ~%s tests)\n")
387 387 % (rev, short(node), changesets, tests))
388 388 if not noupdate:
389 389 cmdutil.bail_if_changed(repo)
390 390 return hg.clean(repo, node)
391 391
392 392 def branch(ui, repo, label=None, **opts):
393 393 """set or show the current branch name
394 394
395 395 With no argument, show the current branch name. With one argument,
396 396 set the working directory branch name (the branch does not exist in
397 397 the repository until the next commit).
398 398
399 399 Unless --force is specified, branch will not let you set a
400 400 branch name that shadows an existing branch.
401 401
402 402 Use --clean to reset the working directory branch to that of the
403 403 parent of the working directory, negating a previous branch change.
404 404
405 405 Use the command 'hg update' to switch to an existing branch.
406 406 """
407 407
408 408 if opts.get('clean'):
409 409 label = repo[None].parents()[0].branch()
410 410 repo.dirstate.setbranch(label)
411 411 ui.status(_('reset working directory to branch %s\n') % label)
412 412 elif label:
413 413 if not opts.get('force') and label in repo.branchtags():
414 414 if label not in [p.branch() for p in repo.parents()]:
415 415 raise util.Abort(_('a branch of the same name already exists'
416 416 ' (use --force to override)'))
417 417 repo.dirstate.setbranch(util.fromlocal(label))
418 418 ui.status(_('marked working directory as branch %s\n') % label)
419 419 else:
420 420 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
421 421
422 422 def branches(ui, repo, active=False):
423 423 """list repository named branches
424 424
425 425 List the repository's named branches, indicating which ones are
426 426 inactive. If active is specified, only show active branches.
427 427
428 428 A branch is considered active if it contains repository heads.
429 429
430 430 Use the command 'hg update' to switch to an existing branch.
431 431 """
432 432 hexfunc = ui.debugflag and hex or short
433 433 activebranches = [util.tolocal(repo[n].branch())
434 434 for n in repo.heads(closed=False)]
435 435 branches = util.sort([(tag in activebranches, repo.changelog.rev(node), tag)
436 436 for tag, node in repo.branchtags().items()])
437 437 branches.reverse()
438 438
439 439 for isactive, node, tag in branches:
440 440 if (not active) or isactive:
441 441 if ui.quiet:
442 442 ui.write("%s\n" % tag)
443 443 else:
444 444 hn = repo.lookup(node)
445 445 if isactive:
446 446 notice = ''
447 447 elif hn not in repo.branchheads(tag, closed=False):
448 448 notice = ' (closed)'
449 449 else:
450 450 notice = ' (inactive)'
451 451 rev = str(node).rjust(31 - util.colwidth(tag))
452 452 data = tag, rev, hexfunc(hn), notice
453 453 ui.write("%s %s:%s%s\n" % data)
454 454
455 455 def bundle(ui, repo, fname, dest=None, **opts):
456 456 """create a changegroup file
457 457
458 458 Generate a compressed changegroup file collecting changesets not
459 found in the other repository.
459 known to be in another repository.
460 460
461 461 If no destination repository is specified the destination is
462 462 assumed to have all the nodes specified by one or more --base
463 463 parameters. To create a bundle containing all changesets, use
464 464 --all (or --base null). To change the compression method applied,
465 465 use the -t option (by default, bundles are compressed using bz2).
466 466
467 467 The bundle file can then be transferred using conventional means and
468 468 applied to another repository with the unbundle or pull command.
469 469 This is useful when direct push and pull are not available or when
470 470 exporting an entire repository is undesirable.
471 471
472 472 Applying bundles preserves all changeset contents including
473 473 permissions, copy/rename information, and revision history.
474 474 """
475 475 revs = opts.get('rev') or None
476 476 if revs:
477 477 revs = [repo.lookup(rev) for rev in revs]
478 478 if opts.get('all'):
479 479 base = ['null']
480 480 else:
481 481 base = opts.get('base')
482 482 if base:
483 483 if dest:
484 484 raise util.Abort(_("--base is incompatible with specifiying "
485 485 "a destination"))
486 486 base = [repo.lookup(rev) for rev in base]
487 487 # create the right base
488 488 # XXX: nodesbetween / changegroup* should be "fixed" instead
489 489 o = []
490 490 has = {nullid: None}
491 491 for n in base:
492 492 has.update(repo.changelog.reachable(n))
493 493 if revs:
494 494 visit = list(revs)
495 495 else:
496 496 visit = repo.changelog.heads()
497 497 seen = {}
498 498 while visit:
499 499 n = visit.pop(0)
500 500 parents = [p for p in repo.changelog.parents(n) if p not in has]
501 501 if len(parents) == 0:
502 502 o.insert(0, n)
503 503 else:
504 504 for p in parents:
505 505 if p not in seen:
506 506 seen[p] = 1
507 507 visit.append(p)
508 508 else:
509 509 cmdutil.setremoteconfig(ui, opts)
510 510 dest, revs, checkout = hg.parseurl(
511 511 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
512 512 other = hg.repository(ui, dest)
513 513 o = repo.findoutgoing(other, force=opts.get('force'))
514 514
515 515 if revs:
516 516 cg = repo.changegroupsubset(o, revs, 'bundle')
517 517 else:
518 518 cg = repo.changegroup(o, 'bundle')
519 519
520 520 bundletype = opts.get('type', 'bzip2').lower()
521 521 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
522 522 bundletype = btypes.get(bundletype)
523 523 if bundletype not in changegroup.bundletypes:
524 524 raise util.Abort(_('unknown bundle type specified with --type'))
525 525
526 526 changegroup.writebundle(cg, fname, bundletype)
527 527
528 528 def cat(ui, repo, file1, *pats, **opts):
529 529 """output the current or given revision of files
530 530
531 531 Print the specified files as they were at the given revision.
532 532 If no revision is given, the parent of the working directory is used,
533 533 or tip if no revision is checked out.
534 534
535 535 Output may be to a file, in which case the name of the file is
536 536 given using a format string. The formatting rules are the same as
537 537 for the export command, with the following additions:
538 538
539 539 %s basename of file being printed
540 540 %d dirname of file being printed, or '.' if in repo root
541 541 %p root-relative path name of file being printed
542 542 """
543 543 ctx = repo[opts.get('rev')]
544 544 err = 1
545 545 m = cmdutil.match(repo, (file1,) + pats, opts)
546 546 for abs in ctx.walk(m):
547 547 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
548 548 data = ctx[abs].data()
549 549 if opts.get('decode'):
550 550 data = repo.wwritedata(abs, data)
551 551 fp.write(data)
552 552 err = 0
553 553 return err
554 554
555 555 def clone(ui, source, dest=None, **opts):
556 556 """make a copy of an existing repository
557 557
558 558 Create a copy of an existing repository in a new directory.
559 559
560 560 If no destination directory name is specified, it defaults to the
561 561 basename of the source.
562 562
563 563 The location of the source is added to the new repository's
564 564 .hg/hgrc file, as the default to be used for future pulls.
565 565
566 566 For efficiency, hardlinks are used for cloning whenever the source
567 567 and destination are on the same filesystem (note this applies only
568 568 to the repository data, not to the checked out files). Some
569 569 filesystems, such as AFS, implement hardlinking incorrectly, but
570 570 do not report errors. In these cases, use the --pull option to
571 571 avoid hardlinking.
572 572
573 573 In some cases, you can clone repositories and checked out files
574 574 using full hardlinks with
575 575
576 576 $ cp -al REPO REPOCLONE
577 577
578 578 This is the fastest way to clone, but it is not always safe. The
579 579 operation is not atomic (making sure REPO is not modified during
580 580 the operation is up to you) and you have to make sure your editor
581 581 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
582 582 this is not compatible with certain extensions that place their
583 583 metadata under the .hg directory, such as mq.
584 584
585 585 If you use the -r option to clone up to a specific revision, no
586 586 subsequent revisions will be present in the cloned repository.
587 587 This option implies --pull, even on local repositories.
588 588
589 589 If the -U option is used, the new clone will contain only a repository
590 590 (.hg) and no working copy (the working copy parent is the null revision).
591 591
592 592 See 'hg help urls' for valid source format details.
593 593
594 594 It is possible to specify an ssh:// URL as the destination, but no
595 595 .hg/hgrc and working directory will be created on the remote side.
596 596 Look at the help text for urls for important details about ssh:// URLs.
597 597 """
598 598 cmdutil.setremoteconfig(ui, opts)
599 599 hg.clone(ui, source, dest,
600 600 pull=opts.get('pull'),
601 601 stream=opts.get('uncompressed'),
602 602 rev=opts.get('rev'),
603 603 update=not opts.get('noupdate'))
604 604
605 605 def commit(ui, repo, *pats, **opts):
606 606 """commit the specified files or all outstanding changes
607 607
608 608 Commit changes to the given files into the repository.
609 609
610 610 If a list of files is omitted, all changes reported by "hg status"
611 611 will be committed.
612 612
613 613 If you are committing the result of a merge, do not provide any
614 614 file names or -I/-X filters.
615 615
616 616 If no commit message is specified, the configured editor is started to
617 enter a message.
617 prompt you for a message.
618 618
619 619 See 'hg help dates' for a list of formats valid for -d/--date.
620 620 """
621 621 extra = {}
622 622 if opts.get('close_branch'):
623 623 extra['close'] = 1
624 624 def commitfunc(ui, repo, message, match, opts):
625 625 return repo.commit(match.files(), message, opts.get('user'),
626 626 opts.get('date'), match, force_editor=opts.get('force_editor'),
627 627 extra=extra)
628 628
629 629 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
630 630 if not node:
631 631 return
632 632 cl = repo.changelog
633 633 rev = cl.rev(node)
634 634 parents = cl.parentrevs(rev)
635 635 if rev - 1 in parents:
636 636 # one of the parents was the old tip
637 637 pass
638 638 elif (parents == (nullrev, nullrev) or
639 639 len(cl.heads(cl.node(parents[0]))) > 1 and
640 640 (parents[1] == nullrev or len(cl.heads(cl.node(parents[1]))) > 1)):
641 641 ui.status(_('created new head\n'))
642 642
643 643 if ui.debugflag:
644 644 ui.write(_('committed changeset %d:%s\n') % (rev,hex(node)))
645 645 elif ui.verbose:
646 646 ui.write(_('committed changeset %d:%s\n') % (rev,short(node)))
647 647
648 648 ms = merge_.mergestate(repo)
649 649 ms.reset(node)
650 650
651 651 def copy(ui, repo, *pats, **opts):
652 652 """mark files as copied for the next commit
653 653
654 654 Mark dest as having copies of source files. If dest is a
655 655 directory, copies are put in that directory. If dest is a file,
656 there can only be one source.
656 the source must be a single file.
657 657
658 658 By default, this command copies the contents of files as they
659 659 stand in the working directory. If invoked with --after, the
660 660 operation is recorded, but no copying is performed.
661 661
662 This command takes effect in the next commit. To undo a copy
662 This command takes effect with the next commit. To undo a copy
663 663 before that, see hg revert.
664 664 """
665 665 wlock = repo.wlock(False)
666 666 try:
667 667 return cmdutil.copy(ui, repo, pats, opts)
668 668 finally:
669 669 del wlock
670 670
671 671 def debugancestor(ui, repo, *args):
672 672 """find the ancestor revision of two revisions in a given index"""
673 673 if len(args) == 3:
674 674 index, rev1, rev2 = args
675 675 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
676 676 lookup = r.lookup
677 677 elif len(args) == 2:
678 678 if not repo:
679 679 raise util.Abort(_("There is no Mercurial repository here "
680 680 "(.hg not found)"))
681 681 rev1, rev2 = args
682 682 r = repo.changelog
683 683 lookup = repo.lookup
684 684 else:
685 685 raise util.Abort(_('either two or three arguments required'))
686 686 a = r.ancestor(lookup(rev1), lookup(rev2))
687 687 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
688 688
689 689 def debugcomplete(ui, cmd='', **opts):
690 690 """returns the completion list associated with the given command"""
691 691
692 692 if opts.get('options'):
693 693 options = []
694 694 otables = [globalopts]
695 695 if cmd:
696 696 aliases, entry = cmdutil.findcmd(cmd, table, False)
697 697 otables.append(entry[1])
698 698 for t in otables:
699 699 for o in t:
700 700 if o[0]:
701 701 options.append('-%s' % o[0])
702 702 options.append('--%s' % o[1])
703 703 ui.write("%s\n" % "\n".join(options))
704 704 return
705 705
706 706 cmdlist = cmdutil.findpossible(cmd, table)
707 707 if ui.verbose:
708 708 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
709 709 ui.write("%s\n" % "\n".join(util.sort(cmdlist)))
710 710
711 711 def debugfsinfo(ui, path = "."):
712 712 file('.debugfsinfo', 'w').write('')
713 713 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
714 714 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
715 715 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
716 716 and 'yes' or 'no'))
717 717 os.unlink('.debugfsinfo')
718 718
719 719 def debugrebuildstate(ui, repo, rev="tip"):
720 720 """rebuild the dirstate as it would look like for the given revision"""
721 721 ctx = repo[rev]
722 722 wlock = repo.wlock()
723 723 try:
724 724 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
725 725 finally:
726 726 del wlock
727 727
728 728 def debugcheckstate(ui, repo):
729 729 """validate the correctness of the current dirstate"""
730 730 parent1, parent2 = repo.dirstate.parents()
731 731 m1 = repo[parent1].manifest()
732 732 m2 = repo[parent2].manifest()
733 733 errors = 0
734 734 for f in repo.dirstate:
735 735 state = repo.dirstate[f]
736 736 if state in "nr" and f not in m1:
737 737 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
738 738 errors += 1
739 739 if state in "a" and f in m1:
740 740 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
741 741 errors += 1
742 742 if state in "m" and f not in m1 and f not in m2:
743 743 ui.warn(_("%s in state %s, but not in either manifest\n") %
744 744 (f, state))
745 745 errors += 1
746 746 for f in m1:
747 747 state = repo.dirstate[f]
748 748 if state not in "nrm":
749 749 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
750 750 errors += 1
751 751 if errors:
752 752 error = _(".hg/dirstate inconsistent with current parent's manifest")
753 753 raise util.Abort(error)
754 754
755 755 def showconfig(ui, repo, *values, **opts):
756 756 """show combined config settings from all hgrc files
757 757
758 758 With no args, print names and values of all config items.
759 759
760 760 With one arg of the form section.name, print just the value of
761 761 that config item.
762 762
763 763 With multiple args, print names and values of all config items
764 764 with matching section names."""
765 765
766 766 untrusted = bool(opts.get('untrusted'))
767 767 if values:
768 768 if len([v for v in values if '.' in v]) > 1:
769 769 raise util.Abort(_('only one config item permitted'))
770 770 for section, name, value in ui.walkconfig(untrusted=untrusted):
771 771 sectname = section + '.' + name
772 772 if values:
773 773 for v in values:
774 774 if v == section:
775 775 ui.write('%s=%s\n' % (sectname, value))
776 776 elif v == sectname:
777 777 ui.write(value, '\n')
778 778 else:
779 779 ui.write('%s=%s\n' % (sectname, value))
780 780
781 781 def debugsetparents(ui, repo, rev1, rev2=None):
782 782 """manually set the parents of the current working directory
783 783
784 784 This is useful for writing repository conversion tools, but should
785 785 be used with care.
786 786 """
787 787
788 788 if not rev2:
789 789 rev2 = hex(nullid)
790 790
791 791 wlock = repo.wlock()
792 792 try:
793 793 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
794 794 finally:
795 795 del wlock
796 796
797 797 def debugstate(ui, repo, nodates=None):
798 798 """show the contents of the current dirstate"""
799 799 timestr = ""
800 800 showdate = not nodates
801 801 for file_, ent in util.sort(repo.dirstate._map.iteritems()):
802 802 if showdate:
803 803 if ent[3] == -1:
804 804 # Pad or slice to locale representation
805 805 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(0)))
806 806 timestr = 'unset'
807 807 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
808 808 else:
809 809 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(ent[3]))
810 810 if ent[1] & 020000:
811 811 mode = 'lnk'
812 812 else:
813 813 mode = '%3o' % (ent[1] & 0777)
814 814 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
815 815 for f in repo.dirstate.copies():
816 816 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
817 817
818 818 def debugdata(ui, file_, rev):
819 819 """dump the contents of a data file revision"""
820 820 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
821 821 try:
822 822 ui.write(r.revision(r.lookup(rev)))
823 823 except KeyError:
824 824 raise util.Abort(_('invalid revision identifier %s') % rev)
825 825
826 826 def debugdate(ui, date, range=None, **opts):
827 827 """parse and display a date"""
828 828 if opts["extended"]:
829 829 d = util.parsedate(date, util.extendeddateformats)
830 830 else:
831 831 d = util.parsedate(date)
832 832 ui.write("internal: %s %s\n" % d)
833 833 ui.write("standard: %s\n" % util.datestr(d))
834 834 if range:
835 835 m = util.matchdate(range)
836 836 ui.write("match: %s\n" % m(d[0]))
837 837
838 838 def debugindex(ui, file_):
839 839 """dump the contents of an index file"""
840 840 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
841 841 ui.write(" rev offset length base linkrev"
842 842 " nodeid p1 p2\n")
843 843 for i in r:
844 844 node = r.node(i)
845 845 try:
846 846 pp = r.parents(node)
847 847 except:
848 848 pp = [nullid, nullid]
849 849 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
850 850 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
851 851 short(node), short(pp[0]), short(pp[1])))
852 852
853 853 def debugindexdot(ui, file_):
854 854 """dump an index DAG as a .dot file"""
855 855 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
856 856 ui.write("digraph G {\n")
857 857 for i in r:
858 858 node = r.node(i)
859 859 pp = r.parents(node)
860 860 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
861 861 if pp[1] != nullid:
862 862 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
863 863 ui.write("}\n")
864 864
865 865 def debuginstall(ui):
866 866 '''test Mercurial installation'''
867 867
868 868 def writetemp(contents):
869 869 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
870 870 f = os.fdopen(fd, "wb")
871 871 f.write(contents)
872 872 f.close()
873 873 return name
874 874
875 875 problems = 0
876 876
877 877 # encoding
878 878 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
879 879 try:
880 880 util.fromlocal("test")
881 881 except util.Abort, inst:
882 882 ui.write(" %s\n" % inst)
883 883 ui.write(_(" (check that your locale is properly set)\n"))
884 884 problems += 1
885 885
886 886 # compiled modules
887 887 ui.status(_("Checking extensions...\n"))
888 888 try:
889 889 import bdiff, mpatch, base85
890 890 except Exception, inst:
891 891 ui.write(" %s\n" % inst)
892 892 ui.write(_(" One or more extensions could not be found"))
893 893 ui.write(_(" (check that you compiled the extensions)\n"))
894 894 problems += 1
895 895
896 896 # templates
897 897 ui.status(_("Checking templates...\n"))
898 898 try:
899 899 import templater
900 900 t = templater.templater(templater.templatepath("map-cmdline.default"))
901 901 except Exception, inst:
902 902 ui.write(" %s\n" % inst)
903 903 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
904 904 problems += 1
905 905
906 906 # patch
907 907 ui.status(_("Checking patch...\n"))
908 908 patchproblems = 0
909 909 a = "1\n2\n3\n4\n"
910 910 b = "1\n2\n3\ninsert\n4\n"
911 911 fa = writetemp(a)
912 912 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
913 913 os.path.basename(fa))
914 914 fd = writetemp(d)
915 915
916 916 files = {}
917 917 try:
918 918 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
919 919 except util.Abort, e:
920 920 ui.write(_(" patch call failed:\n"))
921 921 ui.write(" " + str(e) + "\n")
922 922 patchproblems += 1
923 923 else:
924 924 if list(files) != [os.path.basename(fa)]:
925 925 ui.write(_(" unexpected patch output!\n"))
926 926 patchproblems += 1
927 927 a = file(fa).read()
928 928 if a != b:
929 929 ui.write(_(" patch test failed!\n"))
930 930 patchproblems += 1
931 931
932 932 if patchproblems:
933 933 if ui.config('ui', 'patch'):
934 934 ui.write(_(" (Current patch tool may be incompatible with patch,"
935 935 " or misconfigured. Please check your .hgrc file)\n"))
936 936 else:
937 937 ui.write(_(" Internal patcher failure, please report this error"
938 938 " to http://www.selenic.com/mercurial/bts\n"))
939 939 problems += patchproblems
940 940
941 941 os.unlink(fa)
942 942 os.unlink(fd)
943 943
944 944 # editor
945 945 ui.status(_("Checking commit editor...\n"))
946 946 editor = ui.geteditor()
947 947 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
948 948 if not cmdpath:
949 949 if editor == 'vi':
950 950 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
951 951 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
952 952 else:
953 953 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
954 954 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
955 955 problems += 1
956 956
957 957 # check username
958 958 ui.status(_("Checking username...\n"))
959 959 user = os.environ.get("HGUSER")
960 960 if user is None:
961 961 user = ui.config("ui", "username")
962 962 if user is None:
963 963 user = os.environ.get("EMAIL")
964 964 if not user:
965 965 ui.warn(" ")
966 966 ui.username()
967 967 ui.write(_(" (specify a username in your .hgrc file)\n"))
968 968
969 969 if not problems:
970 970 ui.status(_("No problems detected\n"))
971 971 else:
972 972 ui.write(_("%s problems detected,"
973 973 " please check your install!\n") % problems)
974 974
975 975 return problems
976 976
977 977 def debugrename(ui, repo, file1, *pats, **opts):
978 978 """dump rename information"""
979 979
980 980 ctx = repo[opts.get('rev')]
981 981 m = cmdutil.match(repo, (file1,) + pats, opts)
982 982 for abs in ctx.walk(m):
983 983 fctx = ctx[abs]
984 984 o = fctx.filelog().renamed(fctx.filenode())
985 985 rel = m.rel(abs)
986 986 if o:
987 987 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
988 988 else:
989 989 ui.write(_("%s not renamed\n") % rel)
990 990
991 991 def debugwalk(ui, repo, *pats, **opts):
992 992 """show how files match on given patterns"""
993 993 m = cmdutil.match(repo, pats, opts)
994 994 items = list(repo.walk(m))
995 995 if not items:
996 996 return
997 997 fmt = 'f %%-%ds %%-%ds %%s' % (
998 998 max([len(abs) for abs in items]),
999 999 max([len(m.rel(abs)) for abs in items]))
1000 1000 for abs in items:
1001 1001 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1002 1002 ui.write("%s\n" % line.rstrip())
1003 1003
1004 1004 def diff(ui, repo, *pats, **opts):
1005 1005 """diff repository (or selected files)
1006 1006
1007 1007 Show differences between revisions for the specified files.
1008 1008
1009 1009 Differences between files are shown using the unified diff format.
1010 1010
1011 1011 NOTE: diff may generate unexpected results for merges, as it will
1012 1012 default to comparing against the working directory's first parent
1013 1013 changeset if no revisions are specified.
1014 1014
1015 1015 When two revision arguments are given, then changes are shown
1016 1016 between those revisions. If only one revision is specified then
1017 1017 that revision is compared to the working directory, and, when no
1018 1018 revisions are specified, the working directory files are compared
1019 1019 to its parent.
1020 1020
1021 1021 Without the -a option, diff will avoid generating diffs of files
1022 1022 it detects as binary. With -a, diff will generate a diff anyway,
1023 1023 probably with undesirable results.
1024 1024
1025 1025 Use the --git option to generate diffs in the git extended diff
1026 format. Read the diffs help topic for more information.
1026 format. For more information, read hg help diffs.
1027 1027 """
1028 1028
1029 1029 revs = opts.get('rev')
1030 1030 change = opts.get('change')
1031 1031
1032 1032 if revs and change:
1033 1033 msg = _('cannot specify --rev and --change at the same time')
1034 1034 raise util.Abort(msg)
1035 1035 elif change:
1036 1036 node2 = repo.lookup(change)
1037 1037 node1 = repo[node2].parents()[0].node()
1038 1038 else:
1039 1039 node1, node2 = cmdutil.revpair(repo, revs)
1040 1040
1041 1041 m = cmdutil.match(repo, pats, opts)
1042 1042 it = patch.diff(repo, node1, node2, match=m, opts=patch.diffopts(ui, opts))
1043 1043 for chunk in it:
1044 1044 repo.ui.write(chunk)
1045 1045
1046 1046 def export(ui, repo, *changesets, **opts):
1047 1047 """dump the header and diffs for one or more changesets
1048 1048
1049 1049 Print the changeset header and diffs for one or more revisions.
1050 1050
1051 1051 The information shown in the changeset header is: author,
1052 1052 changeset hash, parent(s) and commit comment.
1053 1053
1054 1054 NOTE: export may generate unexpected diff output for merge changesets,
1055 1055 as it will compare the merge changeset against its first parent only.
1056 1056
1057 1057 Output may be to a file, in which case the name of the file is
1058 1058 given using a format string. The formatting rules are as follows:
1059 1059
1060 1060 %% literal "%" character
1061 1061 %H changeset hash (40 bytes of hexadecimal)
1062 1062 %N number of patches being generated
1063 1063 %R changeset revision number
1064 1064 %b basename of the exporting repository
1065 1065 %h short-form changeset hash (12 bytes of hexadecimal)
1066 1066 %n zero-padded sequence number, starting at 1
1067 1067 %r zero-padded changeset revision number
1068 1068
1069 1069 Without the -a option, export will avoid generating diffs of files
1070 1070 it detects as binary. With -a, export will generate a diff anyway,
1071 1071 probably with undesirable results.
1072 1072
1073 1073 Use the --git option to generate diffs in the git extended diff
1074 1074 format. Read the diffs help topic for more information.
1075 1075
1076 1076 With the --switch-parent option, the diff will be against the second
1077 1077 parent. It can be useful to review a merge.
1078 1078 """
1079 1079 if not changesets:
1080 1080 raise util.Abort(_("export requires at least one changeset"))
1081 1081 revs = cmdutil.revrange(repo, changesets)
1082 1082 if len(revs) > 1:
1083 1083 ui.note(_('exporting patches:\n'))
1084 1084 else:
1085 1085 ui.note(_('exporting patch:\n'))
1086 1086 patch.export(repo, revs, template=opts.get('output'),
1087 1087 switch_parent=opts.get('switch_parent'),
1088 1088 opts=patch.diffopts(ui, opts))
1089 1089
1090 1090 def grep(ui, repo, pattern, *pats, **opts):
1091 1091 """search for a pattern in specified files and revisions
1092 1092
1093 1093 Search revisions of files for a regular expression.
1094 1094
1095 1095 This command behaves differently than Unix grep. It only accepts
1096 1096 Python/Perl regexps. It searches repository history, not the
1097 1097 working directory. It always prints the revision number in which
1098 1098 a match appears.
1099 1099
1100 1100 By default, grep only prints output for the first revision of a
1101 1101 file in which it finds a match. To get it to print every revision
1102 1102 that contains a change in match status ("-" for a match that
1103 1103 becomes a non-match, or "+" for a non-match that becomes a match),
1104 1104 use the --all flag.
1105 1105 """
1106 1106 reflags = 0
1107 1107 if opts.get('ignore_case'):
1108 1108 reflags |= re.I
1109 1109 try:
1110 1110 regexp = re.compile(pattern, reflags)
1111 1111 except Exception, inst:
1112 1112 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1113 1113 return None
1114 1114 sep, eol = ':', '\n'
1115 1115 if opts.get('print0'):
1116 1116 sep = eol = '\0'
1117 1117
1118 1118 fcache = {}
1119 1119 def getfile(fn):
1120 1120 if fn not in fcache:
1121 1121 fcache[fn] = repo.file(fn)
1122 1122 return fcache[fn]
1123 1123
1124 1124 def matchlines(body):
1125 1125 begin = 0
1126 1126 linenum = 0
1127 1127 while True:
1128 1128 match = regexp.search(body, begin)
1129 1129 if not match:
1130 1130 break
1131 1131 mstart, mend = match.span()
1132 1132 linenum += body.count('\n', begin, mstart) + 1
1133 1133 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1134 1134 begin = body.find('\n', mend) + 1 or len(body)
1135 1135 lend = begin - 1
1136 1136 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1137 1137
1138 1138 class linestate(object):
1139 1139 def __init__(self, line, linenum, colstart, colend):
1140 1140 self.line = line
1141 1141 self.linenum = linenum
1142 1142 self.colstart = colstart
1143 1143 self.colend = colend
1144 1144
1145 1145 def __hash__(self):
1146 1146 return hash((self.linenum, self.line))
1147 1147
1148 1148 def __eq__(self, other):
1149 1149 return self.line == other.line
1150 1150
1151 1151 matches = {}
1152 1152 copies = {}
1153 1153 def grepbody(fn, rev, body):
1154 1154 matches[rev].setdefault(fn, [])
1155 1155 m = matches[rev][fn]
1156 1156 for lnum, cstart, cend, line in matchlines(body):
1157 1157 s = linestate(line, lnum, cstart, cend)
1158 1158 m.append(s)
1159 1159
1160 1160 def difflinestates(a, b):
1161 1161 sm = difflib.SequenceMatcher(None, a, b)
1162 1162 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1163 1163 if tag == 'insert':
1164 1164 for i in xrange(blo, bhi):
1165 1165 yield ('+', b[i])
1166 1166 elif tag == 'delete':
1167 1167 for i in xrange(alo, ahi):
1168 1168 yield ('-', a[i])
1169 1169 elif tag == 'replace':
1170 1170 for i in xrange(alo, ahi):
1171 1171 yield ('-', a[i])
1172 1172 for i in xrange(blo, bhi):
1173 1173 yield ('+', b[i])
1174 1174
1175 1175 prev = {}
1176 1176 def display(fn, rev, states, prevstates):
1177 1177 datefunc = ui.quiet and util.shortdate or util.datestr
1178 1178 found = False
1179 1179 filerevmatches = {}
1180 1180 r = prev.get(fn, -1)
1181 1181 if opts.get('all'):
1182 1182 iter = difflinestates(states, prevstates)
1183 1183 else:
1184 1184 iter = [('', l) for l in prevstates]
1185 1185 for change, l in iter:
1186 1186 cols = [fn, str(r)]
1187 1187 if opts.get('line_number'):
1188 1188 cols.append(str(l.linenum))
1189 1189 if opts.get('all'):
1190 1190 cols.append(change)
1191 1191 if opts.get('user'):
1192 1192 cols.append(ui.shortuser(get(r)[1]))
1193 1193 if opts.get('date'):
1194 1194 cols.append(datefunc(get(r)[2]))
1195 1195 if opts.get('files_with_matches'):
1196 1196 c = (fn, r)
1197 1197 if c in filerevmatches:
1198 1198 continue
1199 1199 filerevmatches[c] = 1
1200 1200 else:
1201 1201 cols.append(l.line)
1202 1202 ui.write(sep.join(cols), eol)
1203 1203 found = True
1204 1204 return found
1205 1205
1206 1206 fstate = {}
1207 1207 skip = {}
1208 1208 get = util.cachefunc(lambda r: repo[r].changeset())
1209 1209 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1210 1210 found = False
1211 1211 follow = opts.get('follow')
1212 1212 for st, rev, fns in changeiter:
1213 1213 if st == 'window':
1214 1214 matches.clear()
1215 1215 elif st == 'add':
1216 1216 ctx = repo[rev]
1217 1217 matches[rev] = {}
1218 1218 for fn in fns:
1219 1219 if fn in skip:
1220 1220 continue
1221 1221 try:
1222 1222 grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn)))
1223 1223 fstate.setdefault(fn, [])
1224 1224 if follow:
1225 1225 copied = getfile(fn).renamed(ctx.filenode(fn))
1226 1226 if copied:
1227 1227 copies.setdefault(rev, {})[fn] = copied[0]
1228 1228 except error.LookupError:
1229 1229 pass
1230 1230 elif st == 'iter':
1231 1231 for fn, m in util.sort(matches[rev].items()):
1232 1232 copy = copies.get(rev, {}).get(fn)
1233 1233 if fn in skip:
1234 1234 if copy:
1235 1235 skip[copy] = True
1236 1236 continue
1237 1237 if fn in prev or fstate[fn]:
1238 1238 r = display(fn, rev, m, fstate[fn])
1239 1239 found = found or r
1240 1240 if r and not opts.get('all'):
1241 1241 skip[fn] = True
1242 1242 if copy:
1243 1243 skip[copy] = True
1244 1244 fstate[fn] = m
1245 1245 if copy:
1246 1246 fstate[copy] = m
1247 1247 prev[fn] = rev
1248 1248
1249 1249 for fn, state in util.sort(fstate.items()):
1250 1250 if fn in skip:
1251 1251 continue
1252 1252 if fn not in copies.get(prev[fn], {}):
1253 1253 found = display(fn, rev, {}, state) or found
1254 1254 return (not found and 1) or 0
1255 1255
1256 1256 def heads(ui, repo, *branchrevs, **opts):
1257 1257 """show current repository heads or show branch heads
1258 1258
1259 1259 With no arguments, show all repository head changesets.
1260 1260
1261 1261 If branch or revisions names are given this will show the heads of
1262 1262 the specified branches or the branches those revisions are tagged
1263 1263 with.
1264 1264
1265 1265 Repository "heads" are changesets that don't have child
1266 1266 changesets. They are where development generally takes place and
1267 1267 are the usual targets for update and merge operations.
1268 1268
1269 1269 Branch heads are changesets that have a given branch tag, but have
1270 1270 no child changesets with that tag. They are usually where
1271 1271 development on the given branch takes place.
1272 1272 """
1273 1273 if opts.get('rev'):
1274 1274 start = repo.lookup(opts['rev'])
1275 1275 else:
1276 1276 start = None
1277 1277 closed = not opts.get('active')
1278 1278 if not branchrevs:
1279 1279 # Assume we're looking repo-wide heads if no revs were specified.
1280 1280 heads = repo.heads(start, closed=closed)
1281 1281 else:
1282 1282 heads = []
1283 1283 visitedset = util.set()
1284 1284 for branchrev in branchrevs:
1285 1285 branch = repo[branchrev].branch()
1286 1286 if branch in visitedset:
1287 1287 continue
1288 1288 visitedset.add(branch)
1289 1289 bheads = repo.branchheads(branch, start, closed=closed)
1290 1290 if not bheads:
1291 1291 if branch != branchrev:
1292 1292 ui.warn(_("no changes on branch %s containing %s are "
1293 1293 "reachable from %s\n")
1294 1294 % (branch, branchrev, opts.get('rev')))
1295 1295 else:
1296 1296 ui.warn(_("no changes on branch %s are reachable from %s\n")
1297 1297 % (branch, opts.get('rev')))
1298 1298 heads.extend(bheads)
1299 1299 if not heads:
1300 1300 return 1
1301 1301 displayer = cmdutil.show_changeset(ui, repo, opts)
1302 1302 for n in heads:
1303 1303 displayer.show(repo[n])
1304 1304
1305 1305 def help_(ui, name=None, with_version=False):
1306 1306 """show help for a given topic or a help overview
1307 1307
1308 1308 With no arguments, print a list of commands and short help.
1309 1309
1310 1310 Given a topic, extension, or command name, print help for that topic."""
1311 1311 option_lists = []
1312 1312
1313 1313 def addglobalopts(aliases):
1314 1314 if ui.verbose:
1315 1315 option_lists.append((_("global options:"), globalopts))
1316 1316 if name == 'shortlist':
1317 1317 option_lists.append((_('use "hg help" for the full list '
1318 1318 'of commands'), ()))
1319 1319 else:
1320 1320 if name == 'shortlist':
1321 1321 msg = _('use "hg help" for the full list of commands '
1322 1322 'or "hg -v" for details')
1323 1323 elif aliases:
1324 1324 msg = _('use "hg -v help%s" to show aliases and '
1325 1325 'global options') % (name and " " + name or "")
1326 1326 else:
1327 1327 msg = _('use "hg -v help %s" to show global options') % name
1328 1328 option_lists.append((msg, ()))
1329 1329
1330 1330 def helpcmd(name):
1331 1331 if with_version:
1332 1332 version_(ui)
1333 1333 ui.write('\n')
1334 1334
1335 1335 try:
1336 1336 aliases, i = cmdutil.findcmd(name, table, False)
1337 1337 except error.AmbiguousCommand, inst:
1338 1338 select = lambda c: c.lstrip('^').startswith(inst.args[0])
1339 1339 helplist(_('list of commands:\n\n'), select)
1340 1340 return
1341 1341
1342 1342 # synopsis
1343 1343 if len(i) > 2:
1344 1344 if i[2].startswith('hg'):
1345 1345 ui.write("%s\n" % i[2])
1346 1346 else:
1347 1347 ui.write('hg %s %s\n' % (aliases[0], i[2]))
1348 1348 else:
1349 1349 ui.write('hg %s\n' % aliases[0])
1350 1350
1351 1351 # aliases
1352 1352 if not ui.quiet and len(aliases) > 1:
1353 1353 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1354 1354
1355 1355 # description
1356 1356 doc = gettext(i[0].__doc__)
1357 1357 if not doc:
1358 1358 doc = _("(no help text available)")
1359 1359 if ui.quiet:
1360 1360 doc = doc.splitlines(0)[0]
1361 1361 ui.write("\n%s\n" % doc.rstrip())
1362 1362
1363 1363 if not ui.quiet:
1364 1364 # options
1365 1365 if i[1]:
1366 1366 option_lists.append((_("options:\n"), i[1]))
1367 1367
1368 1368 addglobalopts(False)
1369 1369
1370 1370 def helplist(header, select=None):
1371 1371 h = {}
1372 1372 cmds = {}
1373 1373 for c, e in table.iteritems():
1374 1374 f = c.split("|", 1)[0]
1375 1375 if select and not select(f):
1376 1376 continue
1377 1377 if (not select and name != 'shortlist' and
1378 1378 e[0].__module__ != __name__):
1379 1379 continue
1380 1380 if name == "shortlist" and not f.startswith("^"):
1381 1381 continue
1382 1382 f = f.lstrip("^")
1383 1383 if not ui.debugflag and f.startswith("debug"):
1384 1384 continue
1385 1385 doc = gettext(e[0].__doc__)
1386 1386 if not doc:
1387 1387 doc = _("(no help text available)")
1388 1388 h[f] = doc.splitlines(0)[0].rstrip()
1389 1389 cmds[f] = c.lstrip("^")
1390 1390
1391 1391 if not h:
1392 1392 ui.status(_('no commands defined\n'))
1393 1393 return
1394 1394
1395 1395 ui.status(header)
1396 1396 fns = util.sort(h)
1397 1397 m = max(map(len, fns))
1398 1398 for f in fns:
1399 1399 if ui.verbose:
1400 1400 commands = cmds[f].replace("|",", ")
1401 1401 ui.write(" %s:\n %s\n"%(commands, h[f]))
1402 1402 else:
1403 1403 ui.write(' %-*s %s\n' % (m, f, h[f]))
1404 1404
1405 1405 exts = list(extensions.extensions())
1406 1406 if exts and name != 'shortlist':
1407 1407 ui.write(_('\nenabled extensions:\n\n'))
1408 1408 maxlength = 0
1409 1409 exthelps = []
1410 1410 for ename, ext in exts:
1411 1411 doc = (ext.__doc__ or _('(no help text available)'))
1412 1412 ename = ename.split('.')[-1]
1413 1413 maxlength = max(len(ename), maxlength)
1414 1414 exthelps.append((ename, doc.splitlines(0)[0].strip()))
1415 1415 for ename, text in exthelps:
1416 1416 ui.write(_(' %s %s\n') % (ename.ljust(maxlength), text))
1417 1417
1418 1418 if not ui.quiet:
1419 1419 addglobalopts(True)
1420 1420
1421 1421 def helptopic(name):
1422 1422 for names, header, doc in help.helptable:
1423 1423 if name in names:
1424 1424 break
1425 1425 else:
1426 1426 raise error.UnknownCommand(name)
1427 1427
1428 1428 # description
1429 1429 if not doc:
1430 1430 doc = _("(no help text available)")
1431 1431 if callable(doc):
1432 1432 doc = doc()
1433 1433
1434 1434 ui.write("%s\n" % header)
1435 1435 ui.write("%s\n" % doc.rstrip())
1436 1436
1437 1437 def helpext(name):
1438 1438 try:
1439 1439 mod = extensions.find(name)
1440 1440 except KeyError:
1441 1441 raise error.UnknownCommand(name)
1442 1442
1443 1443 doc = gettext(mod.__doc__) or _('no help text available')
1444 1444 doc = doc.splitlines(0)
1445 1445 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1446 1446 for d in doc[1:]:
1447 1447 ui.write(d, '\n')
1448 1448
1449 1449 ui.status('\n')
1450 1450
1451 1451 try:
1452 1452 ct = mod.cmdtable
1453 1453 except AttributeError:
1454 1454 ct = {}
1455 1455
1456 1456 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1457 1457 helplist(_('list of commands:\n\n'), modcmds.has_key)
1458 1458
1459 1459 if name and name != 'shortlist':
1460 1460 i = None
1461 1461 for f in (helptopic, helpcmd, helpext):
1462 1462 try:
1463 1463 f(name)
1464 1464 i = None
1465 1465 break
1466 1466 except error.UnknownCommand, inst:
1467 1467 i = inst
1468 1468 if i:
1469 1469 raise i
1470 1470
1471 1471 else:
1472 1472 # program name
1473 1473 if ui.verbose or with_version:
1474 1474 version_(ui)
1475 1475 else:
1476 1476 ui.status(_("Mercurial Distributed SCM\n"))
1477 1477 ui.status('\n')
1478 1478
1479 1479 # list of commands
1480 1480 if name == "shortlist":
1481 1481 header = _('basic commands:\n\n')
1482 1482 else:
1483 1483 header = _('list of commands:\n\n')
1484 1484
1485 1485 helplist(header)
1486 1486
1487 1487 # list all option lists
1488 1488 opt_output = []
1489 1489 for title, options in option_lists:
1490 1490 opt_output.append(("\n%s" % title, None))
1491 1491 for shortopt, longopt, default, desc in options:
1492 1492 if "DEPRECATED" in desc and not ui.verbose: continue
1493 1493 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1494 1494 longopt and " --%s" % longopt),
1495 1495 "%s%s" % (desc,
1496 1496 default
1497 1497 and _(" (default: %s)") % default
1498 1498 or "")))
1499 1499
1500 1500 if not name:
1501 1501 ui.write(_("\nadditional help topics:\n\n"))
1502 1502 topics = []
1503 1503 for names, header, doc in help.helptable:
1504 1504 names = [(-len(name), name) for name in names]
1505 1505 names.sort()
1506 1506 topics.append((names[0][1], header))
1507 1507 topics_len = max([len(s[0]) for s in topics])
1508 1508 for t, desc in topics:
1509 1509 ui.write(" %-*s %s\n" % (topics_len, t, desc))
1510 1510
1511 1511 if opt_output:
1512 1512 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1513 1513 for first, second in opt_output:
1514 1514 if second:
1515 1515 ui.write(" %-*s %s\n" % (opts_len, first, second))
1516 1516 else:
1517 1517 ui.write("%s\n" % first)
1518 1518
1519 1519 def identify(ui, repo, source=None,
1520 1520 rev=None, num=None, id=None, branch=None, tags=None):
1521 1521 """identify the working copy or specified revision
1522 1522
1523 1523 With no revision, print a summary of the current state of the repo.
1524 1524
1525 1525 With a path, do a lookup in another repository.
1526 1526
1527 1527 This summary identifies the repository state using one or two parent
1528 1528 hash identifiers, followed by a "+" if there are uncommitted changes
1529 1529 in the working directory, a list of tags for this revision and a branch
1530 1530 name for non-default branches.
1531 1531 """
1532 1532
1533 1533 if not repo and not source:
1534 1534 raise util.Abort(_("There is no Mercurial repository here "
1535 1535 "(.hg not found)"))
1536 1536
1537 1537 hexfunc = ui.debugflag and hex or short
1538 1538 default = not (num or id or branch or tags)
1539 1539 output = []
1540 1540
1541 1541 revs = []
1542 1542 if source:
1543 1543 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1544 1544 repo = hg.repository(ui, source)
1545 1545
1546 1546 if not repo.local():
1547 1547 if not rev and revs:
1548 1548 rev = revs[0]
1549 1549 if not rev:
1550 1550 rev = "tip"
1551 1551 if num or branch or tags:
1552 1552 raise util.Abort(
1553 1553 "can't query remote revision number, branch, or tags")
1554 1554 output = [hexfunc(repo.lookup(rev))]
1555 1555 elif not rev:
1556 1556 ctx = repo[None]
1557 1557 parents = ctx.parents()
1558 1558 changed = False
1559 1559 if default or id or num:
1560 1560 changed = ctx.files() + ctx.deleted()
1561 1561 if default or id:
1562 1562 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1563 1563 (changed) and "+" or "")]
1564 1564 if num:
1565 1565 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1566 1566 (changed) and "+" or ""))
1567 1567 else:
1568 1568 ctx = repo[rev]
1569 1569 if default or id:
1570 1570 output = [hexfunc(ctx.node())]
1571 1571 if num:
1572 1572 output.append(str(ctx.rev()))
1573 1573
1574 1574 if repo.local() and default and not ui.quiet:
1575 1575 b = util.tolocal(ctx.branch())
1576 1576 if b != 'default':
1577 1577 output.append("(%s)" % b)
1578 1578
1579 1579 # multiple tags for a single parent separated by '/'
1580 1580 t = "/".join(ctx.tags())
1581 1581 if t:
1582 1582 output.append(t)
1583 1583
1584 1584 if branch:
1585 1585 output.append(util.tolocal(ctx.branch()))
1586 1586
1587 1587 if tags:
1588 1588 output.extend(ctx.tags())
1589 1589
1590 1590 ui.write("%s\n" % ' '.join(output))
1591 1591
1592 1592 def import_(ui, repo, patch1, *patches, **opts):
1593 1593 """import an ordered set of patches
1594 1594
1595 1595 Import a list of patches and commit them individually.
1596 1596
1597 1597 If there are outstanding changes in the working directory, import
1598 1598 will abort unless given the -f flag.
1599 1599
1600 1600 You can import a patch straight from a mail message. Even patches
1601 1601 as attachments work (body part must be type text/plain or
1602 1602 text/x-patch to be used). From and Subject headers of email
1603 1603 message are used as default committer and commit message. All
1604 1604 text/plain body parts before first diff are added to commit
1605 1605 message.
1606 1606
1607 1607 If the imported patch was generated by hg export, user and description
1608 1608 from patch override values from message headers and body. Values
1609 1609 given on command line with -m and -u override these.
1610 1610
1611 1611 If --exact is specified, import will set the working directory
1612 1612 to the parent of each patch before applying it, and will abort
1613 1613 if the resulting changeset has a different ID than the one
1614 1614 recorded in the patch. This may happen due to character set
1615 1615 problems or other deficiencies in the text patch format.
1616 1616
1617 1617 With --similarity, hg will attempt to discover renames and copies
1618 1618 in the patch in the same way as 'addremove'.
1619 1619
1620 1620 To read a patch from standard input, use patch name "-".
1621 1621 See 'hg help dates' for a list of formats valid for -d/--date.
1622 1622 """
1623 1623 patches = (patch1,) + patches
1624 1624
1625 1625 date = opts.get('date')
1626 1626 if date:
1627 1627 opts['date'] = util.parsedate(date)
1628 1628
1629 1629 try:
1630 1630 sim = float(opts.get('similarity') or 0)
1631 1631 except ValueError:
1632 1632 raise util.Abort(_('similarity must be a number'))
1633 1633 if sim < 0 or sim > 100:
1634 1634 raise util.Abort(_('similarity must be between 0 and 100'))
1635 1635
1636 1636 if opts.get('exact') or not opts.get('force'):
1637 1637 cmdutil.bail_if_changed(repo)
1638 1638
1639 1639 d = opts["base"]
1640 1640 strip = opts["strip"]
1641 1641 wlock = lock = None
1642 1642 try:
1643 1643 wlock = repo.wlock()
1644 1644 lock = repo.lock()
1645 1645 for p in patches:
1646 1646 pf = os.path.join(d, p)
1647 1647
1648 1648 if pf == '-':
1649 1649 ui.status(_("applying patch from stdin\n"))
1650 1650 pf = sys.stdin
1651 1651 else:
1652 1652 ui.status(_("applying %s\n") % p)
1653 1653 pf = url.open(ui, pf)
1654 1654 data = patch.extract(ui, pf)
1655 1655 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1656 1656
1657 1657 if tmpname is None:
1658 1658 raise util.Abort(_('no diffs found'))
1659 1659
1660 1660 try:
1661 1661 cmdline_message = cmdutil.logmessage(opts)
1662 1662 if cmdline_message:
1663 1663 # pickup the cmdline msg
1664 1664 message = cmdline_message
1665 1665 elif message:
1666 1666 # pickup the patch msg
1667 1667 message = message.strip()
1668 1668 else:
1669 1669 # launch the editor
1670 1670 message = None
1671 1671 ui.debug(_('message:\n%s\n') % message)
1672 1672
1673 1673 wp = repo.parents()
1674 1674 if opts.get('exact'):
1675 1675 if not nodeid or not p1:
1676 1676 raise util.Abort(_('not a mercurial patch'))
1677 1677 p1 = repo.lookup(p1)
1678 1678 p2 = repo.lookup(p2 or hex(nullid))
1679 1679
1680 1680 if p1 != wp[0].node():
1681 1681 hg.clean(repo, p1)
1682 1682 repo.dirstate.setparents(p1, p2)
1683 1683 elif p2:
1684 1684 try:
1685 1685 p1 = repo.lookup(p1)
1686 1686 p2 = repo.lookup(p2)
1687 1687 if p1 == wp[0].node():
1688 1688 repo.dirstate.setparents(p1, p2)
1689 1689 except error.RepoError:
1690 1690 pass
1691 1691 if opts.get('exact') or opts.get('import_branch'):
1692 1692 repo.dirstate.setbranch(branch or 'default')
1693 1693
1694 1694 files = {}
1695 1695 try:
1696 1696 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1697 1697 files=files)
1698 1698 finally:
1699 1699 files = patch.updatedir(ui, repo, files, similarity=sim/100.)
1700 1700 if not opts.get('no_commit'):
1701 1701 n = repo.commit(files, message, opts.get('user') or user,
1702 1702 opts.get('date') or date)
1703 1703 if opts.get('exact'):
1704 1704 if hex(n) != nodeid:
1705 1705 repo.rollback()
1706 1706 raise util.Abort(_('patch is damaged'
1707 1707 ' or loses information'))
1708 1708 # Force a dirstate write so that the next transaction
1709 1709 # backups an up-do-date file.
1710 1710 repo.dirstate.write()
1711 1711 finally:
1712 1712 os.unlink(tmpname)
1713 1713 finally:
1714 1714 del lock, wlock
1715 1715
1716 1716 def incoming(ui, repo, source="default", **opts):
1717 1717 """show new changesets found in source
1718 1718
1719 1719 Show new changesets found in the specified path/URL or the default
1720 1720 pull location. These are the changesets that would be pulled if a pull
1721 1721 was requested.
1722 1722
1723 1723 For remote repository, using --bundle avoids downloading the changesets
1724 1724 twice if the incoming is followed by a pull.
1725 1725
1726 1726 See pull for valid source format details.
1727 1727 """
1728 1728 limit = cmdutil.loglimit(opts)
1729 1729 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
1730 1730 cmdutil.setremoteconfig(ui, opts)
1731 1731
1732 1732 other = hg.repository(ui, source)
1733 1733 ui.status(_('comparing with %s\n') % url.hidepassword(source))
1734 1734 if revs:
1735 1735 revs = [other.lookup(rev) for rev in revs]
1736 1736 common, incoming, rheads = repo.findcommonincoming(other, heads=revs,
1737 1737 force=opts["force"])
1738 1738 if not incoming:
1739 1739 try:
1740 1740 os.unlink(opts["bundle"])
1741 1741 except:
1742 1742 pass
1743 1743 ui.status(_("no changes found\n"))
1744 1744 return 1
1745 1745
1746 1746 cleanup = None
1747 1747 try:
1748 1748 fname = opts["bundle"]
1749 1749 if fname or not other.local():
1750 1750 # create a bundle (uncompressed if other repo is not local)
1751 1751
1752 1752 if revs is None and other.capable('changegroupsubset'):
1753 1753 revs = rheads
1754 1754
1755 1755 if revs is None:
1756 1756 cg = other.changegroup(incoming, "incoming")
1757 1757 else:
1758 1758 cg = other.changegroupsubset(incoming, revs, 'incoming')
1759 1759 bundletype = other.local() and "HG10BZ" or "HG10UN"
1760 1760 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1761 1761 # keep written bundle?
1762 1762 if opts["bundle"]:
1763 1763 cleanup = None
1764 1764 if not other.local():
1765 1765 # use the created uncompressed bundlerepo
1766 1766 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1767 1767
1768 1768 o = other.changelog.nodesbetween(incoming, revs)[0]
1769 1769 if opts.get('newest_first'):
1770 1770 o.reverse()
1771 1771 displayer = cmdutil.show_changeset(ui, other, opts)
1772 1772 count = 0
1773 1773 for n in o:
1774 1774 if count >= limit:
1775 1775 break
1776 1776 parents = [p for p in other.changelog.parents(n) if p != nullid]
1777 1777 if opts.get('no_merges') and len(parents) == 2:
1778 1778 continue
1779 1779 count += 1
1780 1780 displayer.show(other[n])
1781 1781 finally:
1782 1782 if hasattr(other, 'close'):
1783 1783 other.close()
1784 1784 if cleanup:
1785 1785 os.unlink(cleanup)
1786 1786
1787 1787 def init(ui, dest=".", **opts):
1788 1788 """create a new repository in the given directory
1789 1789
1790 1790 Initialize a new repository in the given directory. If the given
1791 1791 directory does not exist, it is created.
1792 1792
1793 1793 If no directory is given, the current directory is used.
1794 1794
1795 1795 It is possible to specify an ssh:// URL as the destination.
1796 1796 See 'hg help urls' for more information.
1797 1797 """
1798 1798 cmdutil.setremoteconfig(ui, opts)
1799 1799 hg.repository(ui, dest, create=1)
1800 1800
1801 1801 def locate(ui, repo, *pats, **opts):
1802 1802 """locate files matching specific patterns
1803 1803
1804 1804 Print all files under Mercurial control whose names match the
1805 1805 given patterns.
1806 1806
1807 1807 This command searches the entire repository by default. To search
1808 1808 just the current directory and its subdirectories, use
1809 1809 "--include .".
1810 1810
1811 1811 If no patterns are given to match, this command prints all file
1812 1812 names.
1813 1813
1814 1814 If you want to feed the output of this command into the "xargs"
1815 1815 command, use the "-0" option to both this command and "xargs".
1816 1816 This will avoid the problem of "xargs" treating single filenames
1817 1817 that contain white space as multiple filenames.
1818 1818 """
1819 1819 end = opts.get('print0') and '\0' or '\n'
1820 1820 rev = opts.get('rev') or None
1821 1821
1822 1822 ret = 1
1823 1823 m = cmdutil.match(repo, pats, opts, default='relglob')
1824 1824 m.bad = lambda x,y: False
1825 1825 for abs in repo[rev].walk(m):
1826 1826 if not rev and abs not in repo.dirstate:
1827 1827 continue
1828 1828 if opts.get('fullpath'):
1829 1829 ui.write(repo.wjoin(abs), end)
1830 1830 else:
1831 1831 ui.write(((pats and m.rel(abs)) or abs), end)
1832 1832 ret = 0
1833 1833
1834 1834 return ret
1835 1835
1836 1836 def log(ui, repo, *pats, **opts):
1837 1837 """show revision history of entire repository or files
1838 1838
1839 1839 Print the revision history of the specified files or the entire
1840 1840 project.
1841 1841
1842 1842 File history is shown without following rename or copy history of
1843 1843 files. Use -f/--follow with a file name to follow history across
1844 1844 renames and copies. --follow without a file name will only show
1845 1845 ancestors or descendants of the starting revision. --follow-first
1846 1846 only follows the first parent of merge revisions.
1847 1847
1848 1848 If no revision range is specified, the default is tip:0 unless
1849 1849 --follow is set, in which case the working directory parent is
1850 1850 used as the starting revision.
1851 1851
1852 1852 See 'hg help dates' for a list of formats valid for -d/--date.
1853 1853
1854 1854 By default this command outputs: changeset id and hash, tags,
1855 1855 non-trivial parents, user, date and time, and a summary for each
1856 1856 commit. When the -v/--verbose switch is used, the list of changed
1857 1857 files and full commit message is shown.
1858 1858
1859 1859 NOTE: log -p may generate unexpected diff output for merge
1860 changesets, as it will compare the merge changeset against its
1861 first parent only. Also, the files: list will only reflect files
1860 changesets, as it will only compare the merge changeset against
1861 its first parent. Also, the files: list will only reflect files
1862 1862 that are different from BOTH parents.
1863 1863
1864 1864 """
1865 1865
1866 1866 get = util.cachefunc(lambda r: repo[r].changeset())
1867 1867 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1868 1868
1869 1869 limit = cmdutil.loglimit(opts)
1870 1870 count = 0
1871 1871
1872 1872 if opts.get('copies') and opts.get('rev'):
1873 1873 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
1874 1874 else:
1875 1875 endrev = len(repo)
1876 1876 rcache = {}
1877 1877 ncache = {}
1878 1878 def getrenamed(fn, rev):
1879 1879 '''looks up all renames for a file (up to endrev) the first
1880 1880 time the file is given. It indexes on the changerev and only
1881 1881 parses the manifest if linkrev != changerev.
1882 1882 Returns rename info for fn at changerev rev.'''
1883 1883 if fn not in rcache:
1884 1884 rcache[fn] = {}
1885 1885 ncache[fn] = {}
1886 1886 fl = repo.file(fn)
1887 1887 for i in fl:
1888 1888 node = fl.node(i)
1889 1889 lr = fl.linkrev(i)
1890 1890 renamed = fl.renamed(node)
1891 1891 rcache[fn][lr] = renamed
1892 1892 if renamed:
1893 1893 ncache[fn][node] = renamed
1894 1894 if lr >= endrev:
1895 1895 break
1896 1896 if rev in rcache[fn]:
1897 1897 return rcache[fn][rev]
1898 1898
1899 1899 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1900 1900 # filectx logic.
1901 1901
1902 1902 try:
1903 1903 return repo[rev][fn].renamed()
1904 1904 except error.LookupError:
1905 1905 pass
1906 1906 return None
1907 1907
1908 1908 df = False
1909 1909 if opts["date"]:
1910 1910 df = util.matchdate(opts["date"])
1911 1911
1912 1912 only_branches = opts.get('only_branch')
1913 1913
1914 1914 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1915 1915 for st, rev, fns in changeiter:
1916 1916 if st == 'add':
1917 1917 parents = [p for p in repo.changelog.parentrevs(rev)
1918 1918 if p != nullrev]
1919 1919 if opts.get('no_merges') and len(parents) == 2:
1920 1920 continue
1921 1921 if opts.get('only_merges') and len(parents) != 2:
1922 1922 continue
1923 1923
1924 1924 if only_branches:
1925 1925 revbranch = get(rev)[5]['branch']
1926 1926 if revbranch not in only_branches:
1927 1927 continue
1928 1928
1929 1929 if df:
1930 1930 changes = get(rev)
1931 1931 if not df(changes[2][0]):
1932 1932 continue
1933 1933
1934 1934 if opts.get('keyword'):
1935 1935 changes = get(rev)
1936 1936 miss = 0
1937 1937 for k in [kw.lower() for kw in opts['keyword']]:
1938 1938 if not (k in changes[1].lower() or
1939 1939 k in changes[4].lower() or
1940 1940 k in " ".join(changes[3]).lower()):
1941 1941 miss = 1
1942 1942 break
1943 1943 if miss:
1944 1944 continue
1945 1945
1946 1946 if opts['user']:
1947 1947 changes = get(rev)
1948 1948 miss = 0
1949 1949 for k in opts['user']:
1950 1950 if k != changes[1]:
1951 1951 miss = 1
1952 1952 break
1953 1953 if miss:
1954 1954 continue
1955 1955
1956 1956 copies = []
1957 1957 if opts.get('copies') and rev:
1958 1958 for fn in get(rev)[3]:
1959 1959 rename = getrenamed(fn, rev)
1960 1960 if rename:
1961 1961 copies.append((fn, rename[0]))
1962 1962 displayer.show(context.changectx(repo, rev), copies=copies)
1963 1963 elif st == 'iter':
1964 1964 if count == limit: break
1965 1965 if displayer.flush(rev):
1966 1966 count += 1
1967 1967
1968 1968 def manifest(ui, repo, node=None, rev=None):
1969 1969 """output the current or given revision of the project manifest
1970 1970
1971 1971 Print a list of version controlled files for the given revision.
1972 1972 If no revision is given, the parent of the working directory is used,
1973 1973 or tip if no revision is checked out.
1974 1974
1975 1975 The manifest is the list of files being version controlled. If no revision
1976 1976 is given then the first parent of the working directory is used.
1977 1977
1978 1978 With -v flag, print file permissions, symlink and executable bits. With
1979 1979 --debug flag, print file revision hashes.
1980 1980 """
1981 1981
1982 1982 if rev and node:
1983 1983 raise util.Abort(_("please specify just one revision"))
1984 1984
1985 1985 if not node:
1986 1986 node = rev
1987 1987
1988 1988 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
1989 1989 ctx = repo[node]
1990 1990 for f in ctx:
1991 1991 if ui.debugflag:
1992 1992 ui.write("%40s " % hex(ctx.manifest()[f]))
1993 1993 if ui.verbose:
1994 1994 ui.write(decor[ctx.flags(f)])
1995 1995 ui.write("%s\n" % f)
1996 1996
1997 1997 def merge(ui, repo, node=None, force=None, rev=None):
1998 1998 """merge working directory with another revision
1999 1999
2000 2000 Merge the contents of the current working directory and the
2001 2001 requested revision. Files that changed between either parent are
2002 2002 marked as changed for the next commit and a commit must be
2003 2003 performed before any further updates are allowed.
2004 2004
2005 2005 If no revision is specified, the working directory's parent is a
2006 2006 head revision, and the current branch contains exactly one other head,
2007 2007 the other head is merged with by default. Otherwise, an explicit
2008 2008 revision to merge with must be provided.
2009 2009 """
2010 2010
2011 2011 if rev and node:
2012 2012 raise util.Abort(_("please specify just one revision"))
2013 2013 if not node:
2014 2014 node = rev
2015 2015
2016 2016 if not node:
2017 2017 branch = repo.changectx(None).branch()
2018 2018 bheads = repo.branchheads(branch)
2019 2019 if len(bheads) > 2:
2020 2020 raise util.Abort(_("branch '%s' has %d heads - "
2021 2021 "please merge with an explicit rev") %
2022 2022 (branch, len(bheads)))
2023 2023
2024 2024 parent = repo.dirstate.parents()[0]
2025 2025 if len(bheads) == 1:
2026 2026 if len(repo.heads()) > 1:
2027 2027 raise util.Abort(_("branch '%s' has one head - "
2028 2028 "please merge with an explicit rev") %
2029 2029 branch)
2030 2030 msg = _('there is nothing to merge')
2031 2031 if parent != repo.lookup(repo[None].branch()):
2032 2032 msg = _('%s - use "hg update" instead') % msg
2033 2033 raise util.Abort(msg)
2034 2034
2035 2035 if parent not in bheads:
2036 2036 raise util.Abort(_('working dir not at a head rev - '
2037 2037 'use "hg update" or merge with an explicit rev'))
2038 2038 node = parent == bheads[0] and bheads[-1] or bheads[0]
2039 2039 return hg.merge(repo, node, force=force)
2040 2040
2041 2041 def outgoing(ui, repo, dest=None, **opts):
2042 2042 """show changesets not found in destination
2043 2043
2044 2044 Show changesets not found in the specified destination repository or
2045 2045 the default push location. These are the changesets that would be pushed
2046 2046 if a push was requested.
2047 2047
2048 2048 See pull for valid destination format details.
2049 2049 """
2050 2050 limit = cmdutil.loglimit(opts)
2051 2051 dest, revs, checkout = hg.parseurl(
2052 2052 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
2053 2053 cmdutil.setremoteconfig(ui, opts)
2054 2054 if revs:
2055 2055 revs = [repo.lookup(rev) for rev in revs]
2056 2056
2057 2057 other = hg.repository(ui, dest)
2058 2058 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2059 2059 o = repo.findoutgoing(other, force=opts.get('force'))
2060 2060 if not o:
2061 2061 ui.status(_("no changes found\n"))
2062 2062 return 1
2063 2063 o = repo.changelog.nodesbetween(o, revs)[0]
2064 2064 if opts.get('newest_first'):
2065 2065 o.reverse()
2066 2066 displayer = cmdutil.show_changeset(ui, repo, opts)
2067 2067 count = 0
2068 2068 for n in o:
2069 2069 if count >= limit:
2070 2070 break
2071 2071 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2072 2072 if opts.get('no_merges') and len(parents) == 2:
2073 2073 continue
2074 2074 count += 1
2075 2075 displayer.show(repo[n])
2076 2076
2077 2077 def parents(ui, repo, file_=None, **opts):
2078 2078 """show the parents of the working dir or revision
2079 2079
2080 2080 Print the working directory's parent revisions. If a
2081 2081 revision is given via --rev, the parent of that revision
2082 2082 will be printed. If a file argument is given, revision in
2083 2083 which the file was last changed (before the working directory
2084 2084 revision or the argument to --rev if given) is printed.
2085 2085 """
2086 2086 rev = opts.get('rev')
2087 2087 if rev:
2088 2088 ctx = repo[rev]
2089 2089 else:
2090 2090 ctx = repo[None]
2091 2091
2092 2092 if file_:
2093 2093 m = cmdutil.match(repo, (file_,), opts)
2094 2094 if m.anypats() or len(m.files()) != 1:
2095 2095 raise util.Abort(_('can only specify an explicit file name'))
2096 2096 file_ = m.files()[0]
2097 2097 filenodes = []
2098 2098 for cp in ctx.parents():
2099 2099 if not cp:
2100 2100 continue
2101 2101 try:
2102 2102 filenodes.append(cp.filenode(file_))
2103 2103 except error.LookupError:
2104 2104 pass
2105 2105 if not filenodes:
2106 2106 raise util.Abort(_("'%s' not found in manifest!") % file_)
2107 2107 fl = repo.file(file_)
2108 2108 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2109 2109 else:
2110 2110 p = [cp.node() for cp in ctx.parents()]
2111 2111
2112 2112 displayer = cmdutil.show_changeset(ui, repo, opts)
2113 2113 for n in p:
2114 2114 if n != nullid:
2115 2115 displayer.show(repo[n])
2116 2116
2117 2117 def paths(ui, repo, search=None):
2118 2118 """show aliases for remote repositories
2119 2119
2120 2120 Show definition of symbolic path name NAME. If no name is given, show
2121 2121 definition of available names.
2122 2122
2123 2123 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2124 2124 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2125 2125
2126 2126 See 'hg help urls' for more information.
2127 2127 """
2128 2128 if search:
2129 2129 for name, path in ui.configitems("paths"):
2130 2130 if name == search:
2131 2131 ui.write("%s\n" % url.hidepassword(path))
2132 2132 return
2133 2133 ui.warn(_("not found!\n"))
2134 2134 return 1
2135 2135 else:
2136 2136 for name, path in ui.configitems("paths"):
2137 2137 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2138 2138
2139 2139 def postincoming(ui, repo, modheads, optupdate, checkout):
2140 2140 if modheads == 0:
2141 2141 return
2142 2142 if optupdate:
2143 2143 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2144 2144 return hg.update(repo, checkout)
2145 2145 else:
2146 2146 ui.status(_("not updating, since new heads added\n"))
2147 2147 if modheads > 1:
2148 2148 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2149 2149 else:
2150 2150 ui.status(_("(run 'hg update' to get a working copy)\n"))
2151 2151
2152 2152 def pull(ui, repo, source="default", **opts):
2153 2153 """pull changes from the specified source
2154 2154
2155 2155 Pull changes from a remote repository to a local one.
2156 2156
2157 2157 This finds all changes from the repository at the specified path
2158 2158 or URL and adds them to the local repository. By default, this
2159 2159 does not update the copy of the project in the working directory.
2160 2160
2161 2161 If SOURCE is omitted, the 'default' path will be used.
2162 2162 See 'hg help urls' for more information.
2163 2163 """
2164 2164 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
2165 2165 cmdutil.setremoteconfig(ui, opts)
2166 2166
2167 2167 other = hg.repository(ui, source)
2168 2168 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2169 2169 if revs:
2170 2170 try:
2171 2171 revs = [other.lookup(rev) for rev in revs]
2172 2172 except error.CapabilityError:
2173 2173 err = _("Other repository doesn't support revision lookup, "
2174 2174 "so a rev cannot be specified.")
2175 2175 raise util.Abort(err)
2176 2176
2177 2177 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2178 2178 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2179 2179
2180 2180 def push(ui, repo, dest=None, **opts):
2181 2181 """push changes to the specified destination
2182 2182
2183 2183 Push changes from the local repository to the given destination.
2184 2184
2185 2185 This is the symmetrical operation for pull. It helps to move
2186 2186 changes from the current repository to a different one. If the
2187 2187 destination is local this is identical to a pull in that directory
2188 2188 from the current one.
2189 2189
2190 2190 By default, push will refuse to run if it detects the result would
2191 2191 increase the number of remote heads. This generally indicates the
2192 2192 the client has forgotten to pull and merge before pushing.
2193 2193
2194 2194 If -r is used, the named changeset and all its ancestors will be pushed
2195 2195 to the remote repository.
2196 2196
2197 2197 Look at the help text for urls for important details about ssh:// URLs.
2198 2198 If DESTINATION is omitted, a default path will be used.
2199 2199 See 'hg help urls' for more information.
2200 2200 """
2201 2201 dest, revs, checkout = hg.parseurl(
2202 2202 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
2203 2203 cmdutil.setremoteconfig(ui, opts)
2204 2204
2205 2205 other = hg.repository(ui, dest)
2206 2206 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2207 2207 if revs:
2208 2208 revs = [repo.lookup(rev) for rev in revs]
2209 2209 r = repo.push(other, opts.get('force'), revs=revs)
2210 2210 return r == 0
2211 2211
2212 2212 def rawcommit(ui, repo, *pats, **opts):
2213 2213 """raw commit interface (DEPRECATED)
2214 2214
2215 2215 (DEPRECATED)
2216 2216 Lowlevel commit, for use in helper scripts.
2217 2217
2218 2218 This command is not intended to be used by normal users, as it is
2219 2219 primarily useful for importing from other SCMs.
2220 2220
2221 2221 This command is now deprecated and will be removed in a future
2222 2222 release, please use debugsetparents and commit instead.
2223 2223 """
2224 2224
2225 2225 ui.warn(_("(the rawcommit command is deprecated)\n"))
2226 2226
2227 2227 message = cmdutil.logmessage(opts)
2228 2228
2229 2229 files = cmdutil.match(repo, pats, opts).files()
2230 2230 if opts.get('files'):
2231 2231 files += open(opts['files']).read().splitlines()
2232 2232
2233 2233 parents = [repo.lookup(p) for p in opts['parent']]
2234 2234
2235 2235 try:
2236 2236 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2237 2237 except ValueError, inst:
2238 2238 raise util.Abort(str(inst))
2239 2239
2240 2240 def recover(ui, repo):
2241 2241 """roll back an interrupted transaction
2242 2242
2243 2243 Recover from an interrupted commit or pull.
2244 2244
2245 2245 This command tries to fix the repository status after an interrupted
2246 2246 operation. It should only be necessary when Mercurial suggests it.
2247 2247 """
2248 2248 if repo.recover():
2249 2249 return hg.verify(repo)
2250 2250 return 1
2251 2251
2252 2252 def remove(ui, repo, *pats, **opts):
2253 2253 """remove the specified files on the next commit
2254 2254
2255 2255 Schedule the indicated files for removal from the repository.
2256 2256
2257 2257 This only removes files from the current branch, not from the entire
2258 2258 project history. -A can be used to remove only files that have already
2259 2259 been deleted, -f can be used to force deletion, and -Af can be used
2260 2260 to remove files from the next revision without deleting them.
2261 2261
2262 2262 The following table details the behavior of remove for different file
2263 2263 states (columns) and option combinations (rows). The file states are
2264 2264 Added, Clean, Modified and Missing (as reported by hg status). The
2265 2265 actions are Warn, Remove (from branch) and Delete (from disk).
2266 2266
2267 2267 A C M !
2268 2268 none W RD W R
2269 2269 -f R RD RD R
2270 2270 -A W W W R
2271 2271 -Af R R R R
2272 2272
2273 2273 This command schedules the files to be removed at the next commit.
2274 2274 To undo a remove before that, see hg revert.
2275 2275 """
2276 2276
2277 2277 after, force = opts.get('after'), opts.get('force')
2278 2278 if not pats and not after:
2279 2279 raise util.Abort(_('no files specified'))
2280 2280
2281 2281 m = cmdutil.match(repo, pats, opts)
2282 2282 s = repo.status(match=m, clean=True)
2283 2283 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2284 2284
2285 2285 def warn(files, reason):
2286 2286 for f in files:
2287 2287 ui.warn(_('not removing %s: file %s (use -f to force removal)\n')
2288 2288 % (m.rel(f), reason))
2289 2289
2290 2290 if force:
2291 2291 remove, forget = modified + deleted + clean, added
2292 2292 elif after:
2293 2293 remove, forget = deleted, []
2294 2294 warn(modified + added + clean, _('still exists'))
2295 2295 else:
2296 2296 remove, forget = deleted + clean, []
2297 2297 warn(modified, _('is modified'))
2298 2298 warn(added, _('has been marked for add'))
2299 2299
2300 2300 for f in util.sort(remove + forget):
2301 2301 if ui.verbose or not m.exact(f):
2302 2302 ui.status(_('removing %s\n') % m.rel(f))
2303 2303
2304 2304 repo.forget(forget)
2305 2305 repo.remove(remove, unlink=not after)
2306 2306
2307 2307 def rename(ui, repo, *pats, **opts):
2308 2308 """rename files; equivalent of copy + remove
2309 2309
2310 2310 Mark dest as copies of sources; mark sources for deletion. If
2311 2311 dest is a directory, copies are put in that directory. If dest is
2312 2312 a file, there can only be one source.
2313 2313
2314 2314 By default, this command copies the contents of files as they
2315 stand in the working directory. If invoked with --after, the
2315 exist in the working directory. If invoked with --after, the
2316 2316 operation is recorded, but no copying is performed.
2317 2317
2318 This command takes effect in the next commit. To undo a rename
2318 This command takes effect at the next commit. To undo a rename
2319 2319 before that, see hg revert.
2320 2320 """
2321 2321 wlock = repo.wlock(False)
2322 2322 try:
2323 2323 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2324 2324 finally:
2325 2325 del wlock
2326 2326
2327 2327 def resolve(ui, repo, *pats, **opts):
2328 2328 """retry file merges from a merge or update
2329 2329
2330 2330 This command will cleanly retry unresolved file merges using file
2331 2331 revisions preserved from the last update or merge. To attempt to
2332 2332 resolve all unresolved files, use the -a switch.
2333 2333
2334 2334 This command will also allow listing resolved files and manually
2335 2335 marking and unmarking files as resolved.
2336 2336
2337 2337 The codes used to show the status of files are:
2338 2338 U = unresolved
2339 2339 R = resolved
2340 2340 """
2341 2341
2342 2342 all, mark, unmark, show = [opts.get(o) for o in 'all mark unmark list'.split()]
2343 2343
2344 2344 if (show and (mark or unmark)) or (mark and unmark):
2345 2345 raise util.Abort(_("too many options specified"))
2346 2346 if pats and all:
2347 2347 raise util.Abort(_("can't specify --all and patterns"))
2348 2348 if not (all or pats or show or mark or unmark):
2349 2349 raise util.Abort(_('no files or directories specified; '
2350 2350 'use --all to remerge all files'))
2351 2351
2352 2352 ms = merge_.mergestate(repo)
2353 2353 m = cmdutil.match(repo, pats, opts)
2354 2354
2355 2355 for f in ms:
2356 2356 if m(f):
2357 2357 if show:
2358 2358 ui.write("%s %s\n" % (ms[f].upper(), f))
2359 2359 elif mark:
2360 2360 ms.mark(f, "r")
2361 2361 elif unmark:
2362 2362 ms.mark(f, "u")
2363 2363 else:
2364 2364 wctx = repo[None]
2365 2365 mctx = wctx.parents()[-1]
2366 2366 ms.resolve(f, wctx, mctx)
2367 2367
2368 2368 def revert(ui, repo, *pats, **opts):
2369 2369 """restore individual files or dirs to an earlier state
2370 2370
2371 2371 (use update -r to check out earlier revisions, revert does not
2372 2372 change the working dir parents)
2373 2373
2374 2374 With no revision specified, revert the named files or directories
2375 2375 to the contents they had in the parent of the working directory.
2376 2376 This restores the contents of the affected files to an unmodified
2377 2377 state and unschedules adds, removes, copies, and renames. If the
2378 2378 working directory has two parents, you must explicitly specify the
2379 2379 revision to revert to.
2380 2380
2381 2381 Using the -r option, revert the given files or directories to their
2382 2382 contents as of a specific revision. This can be helpful to "roll
2383 2383 back" some or all of an earlier change.
2384 2384 See 'hg help dates' for a list of formats valid for -d/--date.
2385 2385
2386 2386 Revert modifies the working directory. It does not commit any
2387 2387 changes, or change the parent of the working directory. If you
2388 2388 revert to a revision other than the parent of the working
2389 2389 directory, the reverted files will thus appear modified
2390 2390 afterwards.
2391 2391
2392 2392 If a file has been deleted, it is restored. If the executable
2393 2393 mode of a file was changed, it is reset.
2394 2394
2395 2395 If names are given, all files matching the names are reverted.
2396 2396 If no arguments are given, no files are reverted.
2397 2397
2398 2398 Modified files are saved with a .orig suffix before reverting.
2399 2399 To disable these backups, use --no-backup.
2400 2400 """
2401 2401
2402 2402 if opts["date"]:
2403 2403 if opts["rev"]:
2404 2404 raise util.Abort(_("you can't specify a revision and a date"))
2405 2405 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2406 2406
2407 2407 if not pats and not opts.get('all'):
2408 2408 raise util.Abort(_('no files or directories specified; '
2409 2409 'use --all to revert the whole repo'))
2410 2410
2411 2411 parent, p2 = repo.dirstate.parents()
2412 2412 if not opts.get('rev') and p2 != nullid:
2413 2413 raise util.Abort(_('uncommitted merge - please provide a '
2414 2414 'specific revision'))
2415 2415 ctx = repo[opts.get('rev')]
2416 2416 node = ctx.node()
2417 2417 mf = ctx.manifest()
2418 2418 if node == parent:
2419 2419 pmf = mf
2420 2420 else:
2421 2421 pmf = None
2422 2422
2423 2423 # need all matching names in dirstate and manifest of target rev,
2424 2424 # so have to walk both. do not print errors if files exist in one
2425 2425 # but not other.
2426 2426
2427 2427 names = {}
2428 2428
2429 2429 wlock = repo.wlock()
2430 2430 try:
2431 2431 # walk dirstate.
2432 2432 files = []
2433 2433
2434 2434 m = cmdutil.match(repo, pats, opts)
2435 2435 m.bad = lambda x,y: False
2436 2436 for abs in repo.walk(m):
2437 2437 names[abs] = m.rel(abs), m.exact(abs)
2438 2438
2439 2439 # walk target manifest.
2440 2440
2441 2441 def badfn(path, msg):
2442 2442 if path in names:
2443 2443 return False
2444 2444 path_ = path + '/'
2445 2445 for f in names:
2446 2446 if f.startswith(path_):
2447 2447 return False
2448 2448 repo.ui.warn("%s: %s\n" % (m.rel(path), msg))
2449 2449 return False
2450 2450
2451 2451 m = cmdutil.match(repo, pats, opts)
2452 2452 m.bad = badfn
2453 2453 for abs in repo[node].walk(m):
2454 2454 if abs not in names:
2455 2455 names[abs] = m.rel(abs), m.exact(abs)
2456 2456
2457 2457 m = cmdutil.matchfiles(repo, names)
2458 2458 changes = repo.status(match=m)[:4]
2459 2459 modified, added, removed, deleted = map(dict.fromkeys, changes)
2460 2460
2461 2461 # if f is a rename, also revert the source
2462 2462 cwd = repo.getcwd()
2463 2463 for f in added:
2464 2464 src = repo.dirstate.copied(f)
2465 2465 if src and src not in names and repo.dirstate[src] == 'r':
2466 2466 removed[src] = None
2467 2467 names[src] = (repo.pathto(src, cwd), True)
2468 2468
2469 2469 def removeforget(abs):
2470 2470 if repo.dirstate[abs] == 'a':
2471 2471 return _('forgetting %s\n')
2472 2472 return _('removing %s\n')
2473 2473
2474 2474 revert = ([], _('reverting %s\n'))
2475 2475 add = ([], _('adding %s\n'))
2476 2476 remove = ([], removeforget)
2477 2477 undelete = ([], _('undeleting %s\n'))
2478 2478
2479 2479 disptable = (
2480 2480 # dispatch table:
2481 2481 # file state
2482 2482 # action if in target manifest
2483 2483 # action if not in target manifest
2484 2484 # make backup if in target manifest
2485 2485 # make backup if not in target manifest
2486 2486 (modified, revert, remove, True, True),
2487 2487 (added, revert, remove, True, False),
2488 2488 (removed, undelete, None, False, False),
2489 2489 (deleted, revert, remove, False, False),
2490 2490 )
2491 2491
2492 2492 for abs, (rel, exact) in util.sort(names.items()):
2493 2493 mfentry = mf.get(abs)
2494 2494 target = repo.wjoin(abs)
2495 2495 def handle(xlist, dobackup):
2496 2496 xlist[0].append(abs)
2497 2497 if dobackup and not opts.get('no_backup') and util.lexists(target):
2498 2498 bakname = "%s.orig" % rel
2499 2499 ui.note(_('saving current version of %s as %s\n') %
2500 2500 (rel, bakname))
2501 2501 if not opts.get('dry_run'):
2502 2502 util.copyfile(target, bakname)
2503 2503 if ui.verbose or not exact:
2504 2504 msg = xlist[1]
2505 2505 if not isinstance(msg, basestring):
2506 2506 msg = msg(abs)
2507 2507 ui.status(msg % rel)
2508 2508 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2509 2509 if abs not in table: continue
2510 2510 # file has changed in dirstate
2511 2511 if mfentry:
2512 2512 handle(hitlist, backuphit)
2513 2513 elif misslist is not None:
2514 2514 handle(misslist, backupmiss)
2515 2515 break
2516 2516 else:
2517 2517 if abs not in repo.dirstate:
2518 2518 if mfentry:
2519 2519 handle(add, True)
2520 2520 elif exact:
2521 2521 ui.warn(_('file not managed: %s\n') % rel)
2522 2522 continue
2523 2523 # file has not changed in dirstate
2524 2524 if node == parent:
2525 2525 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2526 2526 continue
2527 2527 if pmf is None:
2528 2528 # only need parent manifest in this unlikely case,
2529 2529 # so do not read by default
2530 2530 pmf = repo[parent].manifest()
2531 2531 if abs in pmf:
2532 2532 if mfentry:
2533 2533 # if version of file is same in parent and target
2534 2534 # manifests, do nothing
2535 2535 if (pmf[abs] != mfentry or
2536 2536 pmf.flags(abs) != mf.flags(abs)):
2537 2537 handle(revert, False)
2538 2538 else:
2539 2539 handle(remove, False)
2540 2540
2541 2541 if not opts.get('dry_run'):
2542 2542 def checkout(f):
2543 2543 fc = ctx[f]
2544 2544 repo.wwrite(f, fc.data(), fc.flags())
2545 2545
2546 2546 audit_path = util.path_auditor(repo.root)
2547 2547 for f in remove[0]:
2548 2548 if repo.dirstate[f] == 'a':
2549 2549 repo.dirstate.forget(f)
2550 2550 continue
2551 2551 audit_path(f)
2552 2552 try:
2553 2553 util.unlink(repo.wjoin(f))
2554 2554 except OSError:
2555 2555 pass
2556 2556 repo.dirstate.remove(f)
2557 2557
2558 2558 normal = None
2559 2559 if node == parent:
2560 2560 # We're reverting to our parent. If possible, we'd like status
2561 2561 # to report the file as clean. We have to use normallookup for
2562 2562 # merges to avoid losing information about merged/dirty files.
2563 2563 if p2 != nullid:
2564 2564 normal = repo.dirstate.normallookup
2565 2565 else:
2566 2566 normal = repo.dirstate.normal
2567 2567 for f in revert[0]:
2568 2568 checkout(f)
2569 2569 if normal:
2570 2570 normal(f)
2571 2571
2572 2572 for f in add[0]:
2573 2573 checkout(f)
2574 2574 repo.dirstate.add(f)
2575 2575
2576 2576 normal = repo.dirstate.normallookup
2577 2577 if node == parent and p2 == nullid:
2578 2578 normal = repo.dirstate.normal
2579 2579 for f in undelete[0]:
2580 2580 checkout(f)
2581 2581 normal(f)
2582 2582
2583 2583 finally:
2584 2584 del wlock
2585 2585
2586 2586 def rollback(ui, repo):
2587 2587 """roll back the last transaction
2588 2588
2589 2589 This command should be used with care. There is only one level of
2590 2590 rollback, and there is no way to undo a rollback. It will also
2591 2591 restore the dirstate at the time of the last transaction, losing
2592 2592 any dirstate changes since that time.
2593 2593
2594 2594 Transactions are used to encapsulate the effects of all commands
2595 2595 that create new changesets or propagate existing changesets into a
2596 2596 repository. For example, the following commands are transactional,
2597 2597 and their effects can be rolled back:
2598 2598
2599 2599 commit
2600 2600 import
2601 2601 pull
2602 2602 push (with this repository as destination)
2603 2603 unbundle
2604 2604
2605 2605 This command is not intended for use on public repositories. Once
2606 2606 changes are visible for pull by other users, rolling a transaction
2607 2607 back locally is ineffective (someone else may already have pulled
2608 2608 the changes). Furthermore, a race is possible with readers of the
2609 2609 repository; for example an in-progress pull from the repository
2610 2610 may fail if a rollback is performed.
2611 2611 """
2612 2612 repo.rollback()
2613 2613
2614 2614 def root(ui, repo):
2615 2615 """print the root (top) of the current working dir
2616 2616
2617 2617 Print the root directory of the current repository.
2618 2618 """
2619 2619 ui.write(repo.root + "\n")
2620 2620
2621 2621 def serve(ui, repo, **opts):
2622 2622 """export the repository via HTTP
2623 2623
2624 2624 Start a local HTTP repository browser and pull server.
2625 2625
2626 2626 By default, the server logs accesses to stdout and errors to
2627 2627 stderr. Use the "-A" and "-E" options to log to files.
2628 2628 """
2629 2629
2630 2630 if opts["stdio"]:
2631 2631 if repo is None:
2632 2632 raise error.RepoError(_("There is no Mercurial repository here"
2633 2633 " (.hg not found)"))
2634 2634 s = sshserver.sshserver(ui, repo)
2635 2635 s.serve_forever()
2636 2636
2637 2637 parentui = ui.parentui or ui
2638 2638 optlist = ("name templates style address port prefix ipv6"
2639 2639 " accesslog errorlog webdir_conf certificate")
2640 2640 for o in optlist.split():
2641 2641 if opts[o]:
2642 2642 parentui.setconfig("web", o, str(opts[o]))
2643 2643 if (repo is not None) and (repo.ui != parentui):
2644 2644 repo.ui.setconfig("web", o, str(opts[o]))
2645 2645
2646 2646 if repo is None and not ui.config("web", "webdir_conf"):
2647 2647 raise error.RepoError(_("There is no Mercurial repository here"
2648 2648 " (.hg not found)"))
2649 2649
2650 2650 class service:
2651 2651 def init(self):
2652 2652 util.set_signal_handler()
2653 2653 self.httpd = hgweb.server.create_server(parentui, repo)
2654 2654
2655 2655 if not ui.verbose: return
2656 2656
2657 2657 if self.httpd.prefix:
2658 2658 prefix = self.httpd.prefix.strip('/') + '/'
2659 2659 else:
2660 2660 prefix = ''
2661 2661
2662 2662 port = ':%d' % self.httpd.port
2663 2663 if port == ':80':
2664 2664 port = ''
2665 2665
2666 2666 bindaddr = self.httpd.addr
2667 2667 if bindaddr == '0.0.0.0':
2668 2668 bindaddr = '*'
2669 2669 elif ':' in bindaddr: # IPv6
2670 2670 bindaddr = '[%s]' % bindaddr
2671 2671
2672 2672 fqaddr = self.httpd.fqaddr
2673 2673 if ':' in fqaddr:
2674 2674 fqaddr = '[%s]' % fqaddr
2675 2675 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2676 2676 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2677 2677
2678 2678 def run(self):
2679 2679 self.httpd.serve_forever()
2680 2680
2681 2681 service = service()
2682 2682
2683 2683 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2684 2684
2685 2685 def status(ui, repo, *pats, **opts):
2686 2686 """show changed files in the working directory
2687 2687
2688 2688 Show status of files in the repository. If names are given, only
2689 2689 files that match are shown. Files that are clean or ignored or
2690 2690 source of a copy/move operation, are not listed unless -c (clean),
2691 2691 -i (ignored), -C (copies) or -A is given. Unless options described
2692 2692 with "show only ..." are given, the options -mardu are used.
2693 2693
2694 2694 Option -q/--quiet hides untracked (unknown and ignored) files
2695 2695 unless explicitly requested with -u/--unknown or -i/-ignored.
2696 2696
2697 2697 NOTE: status may appear to disagree with diff if permissions have
2698 2698 changed or a merge has occurred. The standard diff format does not
2699 2699 report permission changes and diff only reports changes relative
2700 2700 to one merge parent.
2701 2701
2702 2702 If one revision is given, it is used as the base revision.
2703 2703 If two revisions are given, the difference between them is shown.
2704 2704
2705 2705 The codes used to show the status of files are:
2706 2706 M = modified
2707 2707 A = added
2708 2708 R = removed
2709 2709 C = clean
2710 2710 ! = deleted, but still tracked
2711 2711 ? = not tracked
2712 2712 I = ignored
2713 2713 = the previous added file was copied from here
2714 2714 """
2715 2715
2716 2716 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2717 2717 cwd = (pats and repo.getcwd()) or ''
2718 2718 end = opts.get('print0') and '\0' or '\n'
2719 2719 copy = {}
2720 2720 states = 'modified added removed deleted unknown ignored clean'.split()
2721 2721 show = [k for k in states if opts.get(k)]
2722 2722 if opts.get('all'):
2723 2723 show += ui.quiet and (states[:4] + ['clean']) or states
2724 2724 if not show:
2725 2725 show = ui.quiet and states[:4] or states[:5]
2726 2726
2727 2727 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
2728 2728 'ignored' in show, 'clean' in show, 'unknown' in show)
2729 2729 changestates = zip(states, 'MAR!?IC', stat)
2730 2730
2731 2731 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
2732 2732 ctxn = repo[nullid]
2733 2733 ctx1 = repo[node1]
2734 2734 ctx2 = repo[node2]
2735 2735 added = stat[1]
2736 2736 if node2 is None:
2737 2737 added = stat[0] + stat[1] # merged?
2738 2738
2739 2739 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
2740 2740 if k in added:
2741 2741 copy[k] = v
2742 2742 elif v in added:
2743 2743 copy[v] = k
2744 2744
2745 2745 for state, char, files in changestates:
2746 2746 if state in show:
2747 2747 format = "%s %%s%s" % (char, end)
2748 2748 if opts.get('no_status'):
2749 2749 format = "%%s%s" % end
2750 2750
2751 2751 for f in files:
2752 2752 ui.write(format % repo.pathto(f, cwd))
2753 2753 if f in copy:
2754 2754 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end))
2755 2755
2756 2756 def tag(ui, repo, name1, *names, **opts):
2757 2757 """add one or more tags for the current or given revision
2758 2758
2759 2759 Name a particular revision using <name>.
2760 2760
2761 2761 Tags are used to name particular revisions of the repository and are
2762 2762 very useful to compare different revisions, to go back to significant
2763 2763 earlier versions or to mark branch points as releases, etc.
2764 2764
2765 2765 If no revision is given, the parent of the working directory is used,
2766 2766 or tip if no revision is checked out.
2767 2767
2768 2768 To facilitate version control, distribution, and merging of tags,
2769 2769 they are stored as a file named ".hgtags" which is managed
2770 2770 similarly to other project files and can be hand-edited if
2771 2771 necessary. The file '.hg/localtags' is used for local tags (not
2772 2772 shared among repositories).
2773 2773
2774 2774 See 'hg help dates' for a list of formats valid for -d/--date.
2775 2775 """
2776 2776
2777 2777 rev_ = "."
2778 2778 names = (name1,) + names
2779 2779 if len(names) != len(dict.fromkeys(names)):
2780 2780 raise util.Abort(_('tag names must be unique'))
2781 2781 for n in names:
2782 2782 if n in ['tip', '.', 'null']:
2783 2783 raise util.Abort(_('the name \'%s\' is reserved') % n)
2784 2784 if opts.get('rev') and opts.get('remove'):
2785 2785 raise util.Abort(_("--rev and --remove are incompatible"))
2786 2786 if opts.get('rev'):
2787 2787 rev_ = opts['rev']
2788 2788 message = opts.get('message')
2789 2789 if opts.get('remove'):
2790 2790 expectedtype = opts.get('local') and 'local' or 'global'
2791 2791 for n in names:
2792 2792 if not repo.tagtype(n):
2793 2793 raise util.Abort(_('tag \'%s\' does not exist') % n)
2794 2794 if repo.tagtype(n) != expectedtype:
2795 2795 raise util.Abort(_('tag \'%s\' is not a %s tag') %
2796 2796 (n, expectedtype))
2797 2797 rev_ = nullid
2798 2798 if not message:
2799 2799 message = _('Removed tag %s') % ', '.join(names)
2800 2800 elif not opts.get('force'):
2801 2801 for n in names:
2802 2802 if n in repo.tags():
2803 2803 raise util.Abort(_('tag \'%s\' already exists '
2804 2804 '(use -f to force)') % n)
2805 2805 if not rev_ and repo.dirstate.parents()[1] != nullid:
2806 2806 raise util.Abort(_('uncommitted merge - please provide a '
2807 2807 'specific revision'))
2808 2808 r = repo[rev_].node()
2809 2809
2810 2810 if not message:
2811 2811 message = (_('Added tag %s for changeset %s') %
2812 2812 (', '.join(names), short(r)))
2813 2813
2814 2814 date = opts.get('date')
2815 2815 if date:
2816 2816 date = util.parsedate(date)
2817 2817
2818 2818 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
2819 2819
2820 2820 def tags(ui, repo):
2821 2821 """list repository tags
2822 2822
2823 2823 This lists both regular and local tags. When the -v/--verbose switch
2824 2824 is used, a third column "local" is printed for local tags.
2825 2825 """
2826 2826
2827 2827 l = repo.tagslist()
2828 2828 l.reverse()
2829 2829 hexfunc = ui.debugflag and hex or short
2830 2830 tagtype = ""
2831 2831
2832 2832 for t, n in l:
2833 2833 if ui.quiet:
2834 2834 ui.write("%s\n" % t)
2835 2835 continue
2836 2836
2837 2837 try:
2838 2838 hn = hexfunc(n)
2839 2839 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2840 2840 except error.LookupError:
2841 2841 r = " ?:%s" % hn
2842 2842 else:
2843 2843 spaces = " " * (30 - util.colwidth(t))
2844 2844 if ui.verbose:
2845 2845 if repo.tagtype(t) == 'local':
2846 2846 tagtype = " local"
2847 2847 else:
2848 2848 tagtype = ""
2849 2849 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2850 2850
2851 2851 def tip(ui, repo, **opts):
2852 2852 """show the tip revision
2853 2853
2854 2854 The tip revision (usually just called the tip) is the most
2855 2855 recently added changeset in the repository, the most recently
2856 2856 changed head.
2857 2857
2858 2858 If you have just made a commit, that commit will be the tip. If
2859 2859 you have just pulled changes from another repository, the tip of
2860 2860 that repository becomes the current tip. The "tip" tag is special
2861 2861 and cannot be renamed or assigned to a different changeset.
2862 2862 """
2863 2863 cmdutil.show_changeset(ui, repo, opts).show(repo[len(repo) - 1])
2864 2864
2865 2865 def unbundle(ui, repo, fname1, *fnames, **opts):
2866 2866 """apply one or more changegroup files
2867 2867
2868 2868 Apply one or more compressed changegroup files generated by the
2869 2869 bundle command.
2870 2870 """
2871 2871 fnames = (fname1,) + fnames
2872 2872
2873 2873 lock = None
2874 2874 try:
2875 2875 lock = repo.lock()
2876 2876 for fname in fnames:
2877 2877 f = url.open(ui, fname)
2878 2878 gen = changegroup.readbundle(f, fname)
2879 2879 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2880 2880 finally:
2881 2881 del lock
2882 2882
2883 2883 return postincoming(ui, repo, modheads, opts.get('update'), None)
2884 2884
2885 2885 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2886 2886 """update working directory
2887 2887
2888 2888 Update the repository's working directory to the specified revision,
2889 2889 or the tip of the current branch if none is specified. Use null as
2890 2890 the revision to remove the working copy (like 'hg clone -U').
2891 2891
2892 2892 When the working dir contains no uncommitted changes, it will be
2893 2893 replaced by the state of the requested revision from the repo. When
2894 2894 the requested revision is on a different branch, the working dir
2895 2895 will additionally be switched to that branch.
2896 2896
2897 2897 When there are uncommitted changes, use option -C to discard them,
2898 2898 forcibly replacing the state of the working dir with the requested
2899 2899 revision.
2900 2900
2901 2901 When there are uncommitted changes and option -C is not used, and
2902 2902 the parent revision and requested revision are on the same branch,
2903 2903 and one of them is an ancestor of the other, then the new working
2904 2904 directory will contain the requested revision merged with the
2905 2905 uncommitted changes. Otherwise, the update will fail with a
2906 2906 suggestion to use 'merge' or 'update -C' instead.
2907 2907
2908 2908 If you want to update just one file to an older revision, use revert.
2909 2909
2910 2910 See 'hg help dates' for a list of formats valid for --date.
2911 2911 """
2912 2912 if rev and node:
2913 2913 raise util.Abort(_("please specify just one revision"))
2914 2914
2915 2915 if not rev:
2916 2916 rev = node
2917 2917
2918 2918 if date:
2919 2919 if rev:
2920 2920 raise util.Abort(_("you can't specify a revision and a date"))
2921 2921 rev = cmdutil.finddate(ui, repo, date)
2922 2922
2923 2923 if clean:
2924 2924 return hg.clean(repo, rev)
2925 2925 else:
2926 2926 return hg.update(repo, rev)
2927 2927
2928 2928 def verify(ui, repo):
2929 2929 """verify the integrity of the repository
2930 2930
2931 2931 Verify the integrity of the current repository.
2932 2932
2933 2933 This will perform an extensive check of the repository's
2934 2934 integrity, validating the hashes and checksums of each entry in
2935 2935 the changelog, manifest, and tracked files, as well as the
2936 2936 integrity of their crosslinks and indices.
2937 2937 """
2938 2938 return hg.verify(repo)
2939 2939
2940 2940 def version_(ui):
2941 2941 """output version and copyright information"""
2942 2942 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2943 2943 % util.version())
2944 2944 ui.status(_(
2945 2945 "\nCopyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others\n"
2946 2946 "This is free software; see the source for copying conditions. "
2947 2947 "There is NO\nwarranty; "
2948 2948 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2949 2949 ))
2950 2950
2951 2951 # Command options and aliases are listed here, alphabetically
2952 2952
2953 2953 globalopts = [
2954 2954 ('R', 'repository', '',
2955 2955 _('repository root directory or symbolic path name')),
2956 2956 ('', 'cwd', '', _('change working directory')),
2957 2957 ('y', 'noninteractive', None,
2958 2958 _('do not prompt, assume \'yes\' for any required answers')),
2959 2959 ('q', 'quiet', None, _('suppress output')),
2960 2960 ('v', 'verbose', None, _('enable additional output')),
2961 2961 ('', 'config', [], _('set/override config option')),
2962 2962 ('', 'debug', None, _('enable debugging output')),
2963 2963 ('', 'debugger', None, _('start debugger')),
2964 2964 ('', 'encoding', util._encoding, _('set the charset encoding')),
2965 2965 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2966 2966 ('', 'lsprof', None, _('print improved command execution profile')),
2967 2967 ('', 'traceback', None, _('print traceback on exception')),
2968 2968 ('', 'time', None, _('time how long the command takes')),
2969 2969 ('', 'profile', None, _('print command execution profile')),
2970 2970 ('', 'version', None, _('output version information and exit')),
2971 2971 ('h', 'help', None, _('display help and exit')),
2972 2972 ]
2973 2973
2974 2974 dryrunopts = [('n', 'dry-run', None,
2975 2975 _('do not perform actions, just print output'))]
2976 2976
2977 2977 remoteopts = [
2978 2978 ('e', 'ssh', '', _('specify ssh command to use')),
2979 2979 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2980 2980 ]
2981 2981
2982 2982 walkopts = [
2983 2983 ('I', 'include', [], _('include names matching the given patterns')),
2984 2984 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2985 2985 ]
2986 2986
2987 2987 commitopts = [
2988 2988 ('m', 'message', '', _('use <text> as commit message')),
2989 2989 ('l', 'logfile', '', _('read commit message from <file>')),
2990 2990 ]
2991 2991
2992 2992 commitopts2 = [
2993 2993 ('d', 'date', '', _('record datecode as commit date')),
2994 2994 ('u', 'user', '', _('record user as committer')),
2995 2995 ]
2996 2996
2997 2997 templateopts = [
2998 2998 ('', 'style', '', _('display using template map file')),
2999 2999 ('', 'template', '', _('display with template')),
3000 3000 ]
3001 3001
3002 3002 logopts = [
3003 3003 ('p', 'patch', None, _('show patch')),
3004 3004 ('g', 'git', None, _('use git extended diff format')),
3005 3005 ('l', 'limit', '', _('limit number of changes displayed')),
3006 3006 ('M', 'no-merges', None, _('do not show merges')),
3007 3007 ] + templateopts
3008 3008
3009 3009 diffopts = [
3010 3010 ('a', 'text', None, _('treat all files as text')),
3011 3011 ('g', 'git', None, _('use git extended diff format')),
3012 3012 ('', 'nodates', None, _("don't include dates in diff headers"))
3013 3013 ]
3014 3014
3015 3015 diffopts2 = [
3016 3016 ('p', 'show-function', None, _('show which function each change is in')),
3017 3017 ('w', 'ignore-all-space', None,
3018 3018 _('ignore white space when comparing lines')),
3019 3019 ('b', 'ignore-space-change', None,
3020 3020 _('ignore changes in the amount of white space')),
3021 3021 ('B', 'ignore-blank-lines', None,
3022 3022 _('ignore changes whose lines are all blank')),
3023 3023 ('U', 'unified', '', _('number of lines of context to show'))
3024 3024 ]
3025 3025
3026 3026 similarityopts = [
3027 3027 ('s', 'similarity', '',
3028 3028 _('guess renamed files by similarity (0<=s<=100)'))
3029 3029 ]
3030 3030
3031 3031 table = {
3032 3032 "^add": (add, walkopts + dryrunopts, _('[OPTION]... [FILE]...')),
3033 3033 "addremove":
3034 3034 (addremove, similarityopts + walkopts + dryrunopts,
3035 3035 _('[OPTION]... [FILE]...')),
3036 3036 "^annotate|blame":
3037 3037 (annotate,
3038 3038 [('r', 'rev', '', _('annotate the specified revision')),
3039 3039 ('f', 'follow', None, _('follow file copies and renames')),
3040 3040 ('a', 'text', None, _('treat all files as text')),
3041 3041 ('u', 'user', None, _('list the author (long with -v)')),
3042 3042 ('d', 'date', None, _('list the date (short with -q)')),
3043 3043 ('n', 'number', None, _('list the revision number (default)')),
3044 3044 ('c', 'changeset', None, _('list the changeset')),
3045 3045 ('l', 'line-number', None,
3046 3046 _('show line number at the first appearance'))
3047 3047 ] + walkopts,
3048 3048 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3049 3049 "archive":
3050 3050 (archive,
3051 3051 [('', 'no-decode', None, _('do not pass files through decoders')),
3052 3052 ('p', 'prefix', '', _('directory prefix for files in archive')),
3053 3053 ('r', 'rev', '', _('revision to distribute')),
3054 3054 ('t', 'type', '', _('type of distribution to create')),
3055 3055 ] + walkopts,
3056 3056 _('[OPTION]... DEST')),
3057 3057 "backout":
3058 3058 (backout,
3059 3059 [('', 'merge', None,
3060 3060 _('merge with old dirstate parent after backout')),
3061 3061 ('', 'parent', '', _('parent to choose when backing out merge')),
3062 3062 ('r', 'rev', '', _('revision to backout')),
3063 3063 ] + walkopts + commitopts + commitopts2,
3064 3064 _('[OPTION]... [-r] REV')),
3065 3065 "bisect":
3066 3066 (bisect,
3067 3067 [('r', 'reset', False, _('reset bisect state')),
3068 3068 ('g', 'good', False, _('mark changeset good')),
3069 3069 ('b', 'bad', False, _('mark changeset bad')),
3070 3070 ('s', 'skip', False, _('skip testing changeset')),
3071 3071 ('c', 'command', '', _('use command to check changeset state')),
3072 3072 ('U', 'noupdate', False, _('do not update to target'))],
3073 3073 _("[-gbsr] [-c CMD] [REV]")),
3074 3074 "branch":
3075 3075 (branch,
3076 3076 [('f', 'force', None,
3077 3077 _('set branch name even if it shadows an existing branch')),
3078 3078 ('C', 'clean', None, _('reset branch name to parent branch name'))],
3079 3079 _('[-fC] [NAME]')),
3080 3080 "branches":
3081 3081 (branches,
3082 3082 [('a', 'active', False,
3083 3083 _('show only branches that have unmerged heads'))],
3084 3084 _('[-a]')),
3085 3085 "bundle":
3086 3086 (bundle,
3087 3087 [('f', 'force', None,
3088 3088 _('run even when remote repository is unrelated')),
3089 3089 ('r', 'rev', [],
3090 3090 _('a changeset up to which you would like to bundle')),
3091 3091 ('', 'base', [],
3092 3092 _('a base changeset to specify instead of a destination')),
3093 3093 ('a', 'all', None, _('bundle all changesets in the repository')),
3094 3094 ('t', 'type', 'bzip2', _('bundle compression type to use')),
3095 3095 ] + remoteopts,
3096 3096 _('[-f] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
3097 3097 "cat":
3098 3098 (cat,
3099 3099 [('o', 'output', '', _('print output to file with formatted name')),
3100 3100 ('r', 'rev', '', _('print the given revision')),
3101 3101 ('', 'decode', None, _('apply any matching decode filter')),
3102 3102 ] + walkopts,
3103 3103 _('[OPTION]... FILE...')),
3104 3104 "^clone":
3105 3105 (clone,
3106 3106 [('U', 'noupdate', None,
3107 3107 _('the clone will only contain a repository (no working copy)')),
3108 3108 ('r', 'rev', [],
3109 3109 _('a changeset you would like to have after cloning')),
3110 3110 ('', 'pull', None, _('use pull protocol to copy metadata')),
3111 3111 ('', 'uncompressed', None,
3112 3112 _('use uncompressed transfer (fast over LAN)')),
3113 3113 ] + remoteopts,
3114 3114 _('[OPTION]... SOURCE [DEST]')),
3115 3115 "^commit|ci":
3116 3116 (commit,
3117 3117 [('A', 'addremove', None,
3118 3118 _('mark new/missing files as added/removed before committing')),
3119 3119 ('', 'close-branch', None,
3120 3120 _('mark a branch as closed, hiding it from the branch list')),
3121 3121 ] + walkopts + commitopts + commitopts2,
3122 3122 _('[OPTION]... [FILE]...')),
3123 3123 "copy|cp":
3124 3124 (copy,
3125 3125 [('A', 'after', None, _('record a copy that has already occurred')),
3126 3126 ('f', 'force', None,
3127 3127 _('forcibly copy over an existing managed file')),
3128 3128 ] + walkopts + dryrunopts,
3129 3129 _('[OPTION]... [SOURCE]... DEST')),
3130 3130 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
3131 3131 "debugcheckstate": (debugcheckstate, []),
3132 3132 "debugcomplete":
3133 3133 (debugcomplete,
3134 3134 [('o', 'options', None, _('show the command options'))],
3135 3135 _('[-o] CMD')),
3136 3136 "debugdate":
3137 3137 (debugdate,
3138 3138 [('e', 'extended', None, _('try extended date formats'))],
3139 3139 _('[-e] DATE [RANGE]')),
3140 3140 "debugdata": (debugdata, [], _('FILE REV')),
3141 3141 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
3142 3142 "debugindex": (debugindex, [], _('FILE')),
3143 3143 "debugindexdot": (debugindexdot, [], _('FILE')),
3144 3144 "debuginstall": (debuginstall, []),
3145 3145 "debugrawcommit|rawcommit":
3146 3146 (rawcommit,
3147 3147 [('p', 'parent', [], _('parent')),
3148 3148 ('F', 'files', '', _('file list'))
3149 3149 ] + commitopts + commitopts2,
3150 3150 _('[OPTION]... [FILE]...')),
3151 3151 "debugrebuildstate":
3152 3152 (debugrebuildstate,
3153 3153 [('r', 'rev', '', _('revision to rebuild to'))],
3154 3154 _('[-r REV] [REV]')),
3155 3155 "debugrename":
3156 3156 (debugrename,
3157 3157 [('r', 'rev', '', _('revision to debug'))],
3158 3158 _('[-r REV] FILE')),
3159 3159 "debugsetparents":
3160 3160 (debugsetparents, [], _('REV1 [REV2]')),
3161 3161 "debugstate":
3162 3162 (debugstate,
3163 3163 [('', 'nodates', None, _('do not display the saved mtime'))],
3164 3164 _('[OPTION]...')),
3165 3165 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
3166 3166 "^diff":
3167 3167 (diff,
3168 3168 [('r', 'rev', [], _('revision')),
3169 3169 ('c', 'change', '', _('change made by revision'))
3170 3170 ] + diffopts + diffopts2 + walkopts,
3171 3171 _('[OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
3172 3172 "^export":
3173 3173 (export,
3174 3174 [('o', 'output', '', _('print output to file with formatted name')),
3175 3175 ('', 'switch-parent', None, _('diff against the second parent'))
3176 3176 ] + diffopts,
3177 3177 _('[OPTION]... [-o OUTFILESPEC] REV...')),
3178 3178 "grep":
3179 3179 (grep,
3180 3180 [('0', 'print0', None, _('end fields with NUL')),
3181 3181 ('', 'all', None, _('print all revisions that match')),
3182 3182 ('f', 'follow', None,
3183 3183 _('follow changeset history, or file history across copies and renames')),
3184 3184 ('i', 'ignore-case', None, _('ignore case when matching')),
3185 3185 ('l', 'files-with-matches', None,
3186 3186 _('print only filenames and revs that match')),
3187 3187 ('n', 'line-number', None, _('print matching line numbers')),
3188 3188 ('r', 'rev', [], _('search in given revision range')),
3189 3189 ('u', 'user', None, _('list the author (long with -v)')),
3190 3190 ('d', 'date', None, _('list the date (short with -q)')),
3191 3191 ] + walkopts,
3192 3192 _('[OPTION]... PATTERN [FILE]...')),
3193 3193 "heads":
3194 3194 (heads,
3195 3195 [('r', 'rev', '', _('show only heads which are descendants of rev')),
3196 3196 ('a', 'active', False,
3197 3197 _('show only the active heads from open branches')),
3198 3198 ] + templateopts,
3199 3199 _('[-r REV] [REV]...')),
3200 3200 "help": (help_, [], _('[TOPIC]')),
3201 3201 "identify|id":
3202 3202 (identify,
3203 3203 [('r', 'rev', '', _('identify the specified rev')),
3204 3204 ('n', 'num', None, _('show local revision number')),
3205 3205 ('i', 'id', None, _('show global revision id')),
3206 3206 ('b', 'branch', None, _('show branch')),
3207 3207 ('t', 'tags', None, _('show tags'))],
3208 3208 _('[-nibt] [-r REV] [SOURCE]')),
3209 3209 "import|patch":
3210 3210 (import_,
3211 3211 [('p', 'strip', 1,
3212 3212 _('directory strip option for patch. This has the same\n'
3213 3213 'meaning as the corresponding patch option')),
3214 3214 ('b', 'base', '', _('base path')),
3215 3215 ('f', 'force', None,
3216 3216 _('skip check for outstanding uncommitted changes')),
3217 3217 ('', 'no-commit', None, _("don't commit, just update the working directory")),
3218 3218 ('', 'exact', None,
3219 3219 _('apply patch to the nodes from which it was generated')),
3220 3220 ('', 'import-branch', None,
3221 3221 _('Use any branch information in patch (implied by --exact)'))] +
3222 3222 commitopts + commitopts2 + similarityopts,
3223 3223 _('[OPTION]... PATCH...')),
3224 3224 "incoming|in":
3225 3225 (incoming,
3226 3226 [('f', 'force', None,
3227 3227 _('run even when remote repository is unrelated')),
3228 3228 ('n', 'newest-first', None, _('show newest record first')),
3229 3229 ('', 'bundle', '', _('file to store the bundles into')),
3230 3230 ('r', 'rev', [],
3231 3231 _('a specific revision up to which you would like to pull')),
3232 3232 ] + logopts + remoteopts,
3233 3233 _('[-p] [-n] [-M] [-f] [-r REV]...'
3234 3234 ' [--bundle FILENAME] [SOURCE]')),
3235 3235 "^init":
3236 3236 (init,
3237 3237 remoteopts,
3238 3238 _('[-e CMD] [--remotecmd CMD] [DEST]')),
3239 3239 "locate":
3240 3240 (locate,
3241 3241 [('r', 'rev', '', _('search the repository as it stood at rev')),
3242 3242 ('0', 'print0', None,
3243 3243 _('end filenames with NUL, for use with xargs')),
3244 3244 ('f', 'fullpath', None,
3245 3245 _('print complete paths from the filesystem root')),
3246 3246 ] + walkopts,
3247 3247 _('[OPTION]... [PATTERN]...')),
3248 3248 "^log|history":
3249 3249 (log,
3250 3250 [('f', 'follow', None,
3251 3251 _('follow changeset history, or file history across copies and renames')),
3252 3252 ('', 'follow-first', None,
3253 3253 _('only follow the first parent of merge changesets')),
3254 3254 ('d', 'date', '', _('show revs matching date spec')),
3255 3255 ('C', 'copies', None, _('show copied files')),
3256 3256 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3257 3257 ('r', 'rev', [], _('show the specified revision or range')),
3258 3258 ('', 'removed', None, _('include revs where files were removed')),
3259 3259 ('m', 'only-merges', None, _('show only merges')),
3260 3260 ('u', 'user', [], _('revs committed by user')),
3261 3261 ('b', 'only-branch', [],
3262 3262 _('show only changesets within the given named branch')),
3263 3263 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3264 3264 ] + logopts + walkopts,
3265 3265 _('[OPTION]... [FILE]')),
3266 3266 "manifest":
3267 3267 (manifest,
3268 3268 [('r', 'rev', '', _('revision to display'))],
3269 3269 _('[-r REV]')),
3270 3270 "^merge":
3271 3271 (merge,
3272 3272 [('f', 'force', None, _('force a merge with outstanding changes')),
3273 3273 ('r', 'rev', '', _('revision to merge')),
3274 3274 ],
3275 3275 _('[-f] [[-r] REV]')),
3276 3276 "outgoing|out":
3277 3277 (outgoing,
3278 3278 [('f', 'force', None,
3279 3279 _('run even when remote repository is unrelated')),
3280 3280 ('r', 'rev', [],
3281 3281 _('a specific revision up to which you would like to push')),
3282 3282 ('n', 'newest-first', None, _('show newest record first')),
3283 3283 ] + logopts + remoteopts,
3284 3284 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3285 3285 "^parents":
3286 3286 (parents,
3287 3287 [('r', 'rev', '', _('show parents from the specified rev')),
3288 3288 ] + templateopts,
3289 3289 _('hg parents [-r REV] [FILE]')),
3290 3290 "paths": (paths, [], _('[NAME]')),
3291 3291 "^pull":
3292 3292 (pull,
3293 3293 [('u', 'update', None,
3294 3294 _('update to new tip if changesets were pulled')),
3295 3295 ('f', 'force', None,
3296 3296 _('run even when remote repository is unrelated')),
3297 3297 ('r', 'rev', [],
3298 3298 _('a specific revision up to which you would like to pull')),
3299 3299 ] + remoteopts,
3300 3300 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3301 3301 "^push":
3302 3302 (push,
3303 3303 [('f', 'force', None, _('force push')),
3304 3304 ('r', 'rev', [],
3305 3305 _('a specific revision up to which you would like to push')),
3306 3306 ] + remoteopts,
3307 3307 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3308 3308 "recover": (recover, []),
3309 3309 "^remove|rm":
3310 3310 (remove,
3311 3311 [('A', 'after', None, _('record delete for missing files')),
3312 3312 ('f', 'force', None,
3313 3313 _('remove (and delete) file even if added or modified')),
3314 3314 ] + walkopts,
3315 3315 _('[OPTION]... FILE...')),
3316 3316 "rename|mv":
3317 3317 (rename,
3318 3318 [('A', 'after', None, _('record a rename that has already occurred')),
3319 3319 ('f', 'force', None,
3320 3320 _('forcibly copy over an existing managed file')),
3321 3321 ] + walkopts + dryrunopts,
3322 3322 _('[OPTION]... SOURCE... DEST')),
3323 3323 "resolve":
3324 3324 (resolve,
3325 3325 [('a', 'all', None, _('remerge all unresolved files')),
3326 3326 ('l', 'list', None, _('list state of files needing merge')),
3327 3327 ('m', 'mark', None, _('mark files as resolved')),
3328 3328 ('u', 'unmark', None, _('unmark files as resolved'))]
3329 3329 + walkopts,
3330 3330 _('[OPTION]... [FILE]...')),
3331 3331 "revert":
3332 3332 (revert,
3333 3333 [('a', 'all', None, _('revert all changes when no arguments given')),
3334 3334 ('d', 'date', '', _('tipmost revision matching date')),
3335 3335 ('r', 'rev', '', _('revision to revert to')),
3336 3336 ('', 'no-backup', None, _('do not save backup copies of files')),
3337 3337 ] + walkopts + dryrunopts,
3338 3338 _('[OPTION]... [-r REV] [NAME]...')),
3339 3339 "rollback": (rollback, []),
3340 3340 "root": (root, []),
3341 3341 "^serve":
3342 3342 (serve,
3343 3343 [('A', 'accesslog', '', _('name of access log file to write to')),
3344 3344 ('d', 'daemon', None, _('run server in background')),
3345 3345 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3346 3346 ('E', 'errorlog', '', _('name of error log file to write to')),
3347 3347 ('p', 'port', 0, _('port to listen on (default: 8000)')),
3348 3348 ('a', 'address', '', _('address to listen on (default: all interfaces)')),
3349 3349 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3350 3350 ('n', 'name', '',
3351 3351 _('name to show in web pages (default: working dir)')),
3352 3352 ('', 'webdir-conf', '', _('name of the webdir config file'
3353 3353 ' (serve more than one repo)')),
3354 3354 ('', 'pid-file', '', _('name of file to write process ID to')),
3355 3355 ('', 'stdio', None, _('for remote clients')),
3356 3356 ('t', 'templates', '', _('web templates to use')),
3357 3357 ('', 'style', '', _('template style to use')),
3358 3358 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3359 3359 ('', 'certificate', '', _('SSL certificate file'))],
3360 3360 _('[OPTION]...')),
3361 3361 "showconfig|debugconfig":
3362 3362 (showconfig,
3363 3363 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3364 3364 _('[-u] [NAME]...')),
3365 3365 "^status|st":
3366 3366 (status,
3367 3367 [('A', 'all', None, _('show status of all files')),
3368 3368 ('m', 'modified', None, _('show only modified files')),
3369 3369 ('a', 'added', None, _('show only added files')),
3370 3370 ('r', 'removed', None, _('show only removed files')),
3371 3371 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3372 3372 ('c', 'clean', None, _('show only files without changes')),
3373 3373 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3374 3374 ('i', 'ignored', None, _('show only ignored files')),
3375 3375 ('n', 'no-status', None, _('hide status prefix')),
3376 3376 ('C', 'copies', None, _('show source of copied files')),
3377 3377 ('0', 'print0', None,
3378 3378 _('end filenames with NUL, for use with xargs')),
3379 3379 ('', 'rev', [], _('show difference from revision')),
3380 3380 ] + walkopts,
3381 3381 _('[OPTION]... [FILE]...')),
3382 3382 "tag":
3383 3383 (tag,
3384 3384 [('f', 'force', None, _('replace existing tag')),
3385 3385 ('l', 'local', None, _('make the tag local')),
3386 3386 ('r', 'rev', '', _('revision to tag')),
3387 3387 ('', 'remove', None, _('remove a tag')),
3388 3388 # -l/--local is already there, commitopts cannot be used
3389 3389 ('m', 'message', '', _('use <text> as commit message')),
3390 3390 ] + commitopts2,
3391 3391 _('[-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
3392 3392 "tags": (tags, []),
3393 3393 "tip":
3394 3394 (tip,
3395 3395 [('p', 'patch', None, _('show patch')),
3396 3396 ('g', 'git', None, _('use git extended diff format')),
3397 3397 ] + templateopts,
3398 3398 _('[-p]')),
3399 3399 "unbundle":
3400 3400 (unbundle,
3401 3401 [('u', 'update', None,
3402 3402 _('update to new tip if changesets were unbundled'))],
3403 3403 _('[-u] FILE...')),
3404 3404 "^update|up|checkout|co":
3405 3405 (update,
3406 3406 [('C', 'clean', None, _('overwrite locally modified files (no backup)')),
3407 3407 ('d', 'date', '', _('tipmost revision matching date')),
3408 3408 ('r', 'rev', '', _('revision'))],
3409 3409 _('[-C] [-d DATE] [[-r] REV]')),
3410 3410 "verify": (verify, []),
3411 3411 "version": (version_, []),
3412 3412 }
3413 3413
3414 3414 norepo = ("clone init version help debugcomplete debugdata"
3415 3415 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3416 3416 optionalrepo = ("identify paths serve showconfig debugancestor")
@@ -1,340 +1,340 b''
1 1 Mercurial Distributed SCM
2 2
3 3 basic commands:
4 4
5 5 add add the specified files on the next commit
6 6 annotate show changeset information per file line
7 7 clone make a copy of an existing repository
8 8 commit commit the specified files or all outstanding changes
9 9 diff diff repository (or selected files)
10 10 export dump the header and diffs for one or more changesets
11 11 init create a new repository in the given directory
12 12 log show revision history of entire repository or files
13 13 merge merge working directory with another revision
14 14 parents show the parents of the working dir or revision
15 15 pull pull changes from the specified source
16 16 push push changes to the specified destination
17 17 remove remove the specified files on the next commit
18 18 serve export the repository via HTTP
19 19 status show changed files in the working directory
20 20 update update working directory
21 21
22 22 use "hg help" for the full list of commands or "hg -v" for details
23 23 add add the specified files on the next commit
24 24 annotate show changeset information per file line
25 25 clone make a copy of an existing repository
26 26 commit commit the specified files or all outstanding changes
27 27 diff diff repository (or selected files)
28 28 export dump the header and diffs for one or more changesets
29 29 init create a new repository in the given directory
30 30 log show revision history of entire repository or files
31 31 merge merge working directory with another revision
32 32 parents show the parents of the working dir or revision
33 33 pull pull changes from the specified source
34 34 push push changes to the specified destination
35 35 remove remove the specified files on the next commit
36 36 serve export the repository via HTTP
37 37 status show changed files in the working directory
38 38 update update working directory
39 39 Mercurial Distributed SCM
40 40
41 41 list of commands:
42 42
43 43 add add the specified files on the next commit
44 44 addremove add all new files, delete all missing files
45 45 annotate show changeset information per file line
46 46 archive create unversioned archive of a repository revision
47 47 backout reverse effect of earlier changeset
48 48 bisect subdivision search of changesets
49 49 branch set or show the current branch name
50 50 branches list repository named branches
51 51 bundle create a changegroup file
52 52 cat output the current or given revision of files
53 53 clone make a copy of an existing repository
54 54 commit commit the specified files or all outstanding changes
55 55 copy mark files as copied for the next commit
56 56 diff diff repository (or selected files)
57 57 export dump the header and diffs for one or more changesets
58 58 grep search for a pattern in specified files and revisions
59 59 heads show current repository heads or show branch heads
60 60 help show help for a given topic or a help overview
61 61 identify identify the working copy or specified revision
62 62 import import an ordered set of patches
63 63 incoming show new changesets found in source
64 64 init create a new repository in the given directory
65 65 locate locate files matching specific patterns
66 66 log show revision history of entire repository or files
67 67 manifest output the current or given revision of the project manifest
68 68 merge merge working directory with another revision
69 69 outgoing show changesets not found in destination
70 70 parents show the parents of the working dir or revision
71 71 paths show aliases for remote repositories
72 72 pull pull changes from the specified source
73 73 push push changes to the specified destination
74 74 recover roll back an interrupted transaction
75 75 remove remove the specified files on the next commit
76 76 rename rename files; equivalent of copy + remove
77 77 resolve retry file merges from a merge or update
78 78 revert restore individual files or dirs to an earlier state
79 79 rollback roll back the last transaction
80 80 root print the root (top) of the current working dir
81 81 serve export the repository via HTTP
82 82 showconfig show combined config settings from all hgrc files
83 83 status show changed files in the working directory
84 84 tag add one or more tags for the current or given revision
85 85 tags list repository tags
86 86 tip show the tip revision
87 87 unbundle apply one or more changegroup files
88 88 update update working directory
89 89 verify verify the integrity of the repository
90 90 version output version and copyright information
91 91
92 92 additional help topics:
93 93
94 94 dates Date Formats
95 95 patterns File Name Patterns
96 96 environment Environment Variables
97 97 revisions Specifying Single Revisions
98 98 multirevs Specifying Multiple Revisions
99 99 diffs Diff Formats
100 100 templating Template Usage
101 101 urls Url Paths
102 102
103 103 use "hg -v help" to show aliases and global options
104 104 add add the specified files on the next commit
105 105 addremove add all new files, delete all missing files
106 106 annotate show changeset information per file line
107 107 archive create unversioned archive of a repository revision
108 108 backout reverse effect of earlier changeset
109 109 bisect subdivision search of changesets
110 110 branch set or show the current branch name
111 111 branches list repository named branches
112 112 bundle create a changegroup file
113 113 cat output the current or given revision of files
114 114 clone make a copy of an existing repository
115 115 commit commit the specified files or all outstanding changes
116 116 copy mark files as copied for the next commit
117 117 diff diff repository (or selected files)
118 118 export dump the header and diffs for one or more changesets
119 119 grep search for a pattern in specified files and revisions
120 120 heads show current repository heads or show branch heads
121 121 help show help for a given topic or a help overview
122 122 identify identify the working copy or specified revision
123 123 import import an ordered set of patches
124 124 incoming show new changesets found in source
125 125 init create a new repository in the given directory
126 126 locate locate files matching specific patterns
127 127 log show revision history of entire repository or files
128 128 manifest output the current or given revision of the project manifest
129 129 merge merge working directory with another revision
130 130 outgoing show changesets not found in destination
131 131 parents show the parents of the working dir or revision
132 132 paths show aliases for remote repositories
133 133 pull pull changes from the specified source
134 134 push push changes to the specified destination
135 135 recover roll back an interrupted transaction
136 136 remove remove the specified files on the next commit
137 137 rename rename files; equivalent of copy + remove
138 138 resolve retry file merges from a merge or update
139 139 revert restore individual files or dirs to an earlier state
140 140 rollback roll back the last transaction
141 141 root print the root (top) of the current working dir
142 142 serve export the repository via HTTP
143 143 showconfig show combined config settings from all hgrc files
144 144 status show changed files in the working directory
145 145 tag add one or more tags for the current or given revision
146 146 tags list repository tags
147 147 tip show the tip revision
148 148 unbundle apply one or more changegroup files
149 149 update update working directory
150 150 verify verify the integrity of the repository
151 151 version output version and copyright information
152 152
153 153 additional help topics:
154 154
155 155 dates Date Formats
156 156 patterns File Name Patterns
157 157 environment Environment Variables
158 158 revisions Specifying Single Revisions
159 159 multirevs Specifying Multiple Revisions
160 160 diffs Diff Formats
161 161 templating Template Usage
162 162 urls Url Paths
163 163 hg add [OPTION]... [FILE]...
164 164
165 165 add the specified files on the next commit
166 166
167 167 Schedule files to be version controlled and added to the repository.
168 168
169 169 The files will be added to the repository at the next commit. To
170 170 undo an add before that, see hg revert.
171 171
172 If no names are given, add all files in the repository.
172 If no names are given, add all files to the repository.
173 173
174 174 options:
175 175
176 176 -I --include include names matching the given patterns
177 177 -X --exclude exclude names matching the given patterns
178 178 -n --dry-run do not perform actions, just print output
179 179
180 180 use "hg -v help add" to show global options
181 181 hg add: option --skjdfks not recognized
182 182 hg add [OPTION]... [FILE]...
183 183
184 184 add the specified files on the next commit
185 185
186 186 Schedule files to be version controlled and added to the repository.
187 187
188 188 The files will be added to the repository at the next commit. To
189 189 undo an add before that, see hg revert.
190 190
191 If no names are given, add all files in the repository.
191 If no names are given, add all files to the repository.
192 192
193 193 options:
194 194
195 195 -I --include include names matching the given patterns
196 196 -X --exclude exclude names matching the given patterns
197 197 -n --dry-run do not perform actions, just print output
198 198
199 199 use "hg -v help add" to show global options
200 200 hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...
201 201
202 202 diff repository (or selected files)
203 203
204 204 Show differences between revisions for the specified files.
205 205
206 206 Differences between files are shown using the unified diff format.
207 207
208 208 NOTE: diff may generate unexpected results for merges, as it will
209 209 default to comparing against the working directory's first parent
210 210 changeset if no revisions are specified.
211 211
212 212 When two revision arguments are given, then changes are shown
213 213 between those revisions. If only one revision is specified then
214 214 that revision is compared to the working directory, and, when no
215 215 revisions are specified, the working directory files are compared
216 216 to its parent.
217 217
218 218 Without the -a option, diff will avoid generating diffs of files
219 219 it detects as binary. With -a, diff will generate a diff anyway,
220 220 probably with undesirable results.
221 221
222 222 Use the --git option to generate diffs in the git extended diff
223 format. Read the diffs help topic for more information.
223 format. For more information, read hg help diffs.
224 224
225 225 options:
226 226
227 227 -r --rev revision
228 228 -c --change change made by revision
229 229 -a --text treat all files as text
230 230 -g --git use git extended diff format
231 231 --nodates don't include dates in diff headers
232 232 -p --show-function show which function each change is in
233 233 -w --ignore-all-space ignore white space when comparing lines
234 234 -b --ignore-space-change ignore changes in the amount of white space
235 235 -B --ignore-blank-lines ignore changes whose lines are all blank
236 236 -U --unified number of lines of context to show
237 237 -I --include include names matching the given patterns
238 238 -X --exclude exclude names matching the given patterns
239 239
240 240 use "hg -v help diff" to show global options
241 241 hg status [OPTION]... [FILE]...
242 242
243 243 aliases: st
244 244
245 245 show changed files in the working directory
246 246
247 247 Show status of files in the repository. If names are given, only
248 248 files that match are shown. Files that are clean or ignored or
249 249 source of a copy/move operation, are not listed unless -c (clean),
250 250 -i (ignored), -C (copies) or -A is given. Unless options described
251 251 with "show only ..." are given, the options -mardu are used.
252 252
253 253 Option -q/--quiet hides untracked (unknown and ignored) files
254 254 unless explicitly requested with -u/--unknown or -i/-ignored.
255 255
256 256 NOTE: status may appear to disagree with diff if permissions have
257 257 changed or a merge has occurred. The standard diff format does not
258 258 report permission changes and diff only reports changes relative
259 259 to one merge parent.
260 260
261 261 If one revision is given, it is used as the base revision.
262 262 If two revisions are given, the difference between them is shown.
263 263
264 264 The codes used to show the status of files are:
265 265 M = modified
266 266 A = added
267 267 R = removed
268 268 C = clean
269 269 ! = deleted, but still tracked
270 270 ? = not tracked
271 271 I = ignored
272 272 = the previous added file was copied from here
273 273
274 274 options:
275 275
276 276 -A --all show status of all files
277 277 -m --modified show only modified files
278 278 -a --added show only added files
279 279 -r --removed show only removed files
280 280 -d --deleted show only deleted (but tracked) files
281 281 -c --clean show only files without changes
282 282 -u --unknown show only unknown (not tracked) files
283 283 -i --ignored show only ignored files
284 284 -n --no-status hide status prefix
285 285 -C --copies show source of copied files
286 286 -0 --print0 end filenames with NUL, for use with xargs
287 287 --rev show difference from revision
288 288 -I --include include names matching the given patterns
289 289 -X --exclude exclude names matching the given patterns
290 290
291 291 use "hg -v help status" to show global options
292 292 hg status [OPTION]... [FILE]...
293 293
294 294 show changed files in the working directory
295 295 hg: unknown command 'foo'
296 296 Mercurial Distributed SCM
297 297
298 298 basic commands:
299 299
300 300 add add the specified files on the next commit
301 301 annotate show changeset information per file line
302 302 clone make a copy of an existing repository
303 303 commit commit the specified files or all outstanding changes
304 304 diff diff repository (or selected files)
305 305 export dump the header and diffs for one or more changesets
306 306 init create a new repository in the given directory
307 307 log show revision history of entire repository or files
308 308 merge merge working directory with another revision
309 309 parents show the parents of the working dir or revision
310 310 pull pull changes from the specified source
311 311 push push changes to the specified destination
312 312 remove remove the specified files on the next commit
313 313 serve export the repository via HTTP
314 314 status show changed files in the working directory
315 315 update update working directory
316 316
317 317 use "hg help" for the full list of commands or "hg -v" for details
318 318 hg: unknown command 'skjdfks'
319 319 Mercurial Distributed SCM
320 320
321 321 basic commands:
322 322
323 323 add add the specified files on the next commit
324 324 annotate show changeset information per file line
325 325 clone make a copy of an existing repository
326 326 commit commit the specified files or all outstanding changes
327 327 diff diff repository (or selected files)
328 328 export dump the header and diffs for one or more changesets
329 329 init create a new repository in the given directory
330 330 log show revision history of entire repository or files
331 331 merge merge working directory with another revision
332 332 parents show the parents of the working dir or revision
333 333 pull pull changes from the specified source
334 334 push push changes to the specified destination
335 335 remove remove the specified files on the next commit
336 336 serve export the repository via HTTP
337 337 status show changed files in the working directory
338 338 update update working directory
339 339
340 340 use "hg help" for the full list of commands or "hg -v" for details
General Comments 0
You need to be logged in to leave comments. Login now