##// END OF EJS Templates
graft: add --continue support
Matt Mackall -
r15241:e4d13563 default
parent child Browse files
Show More
@@ -1,5570 +1,5607 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 of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from node import hex, bin, nullid, nullrev, short
9 9 from lock import release
10 10 from i18n import _, gettext
11 11 import os, re, difflib, time, tempfile, errno
12 12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 13 import patch, help, url, encoding, templatekw, discovery
14 14 import archival, changegroup, cmdutil, hbisect
15 15 import sshserver, hgweb, hgweb.server, commandserver
16 16 import merge as mergemod
17 17 import minirst, revset, fileset
18 18 import dagparser, context, simplemerge
19 19 import random, setdiscovery, treediscovery, dagutil
20 20
21 21 table = {}
22 22
23 23 command = cmdutil.command(table)
24 24
25 25 # common command options
26 26
27 27 globalopts = [
28 28 ('R', 'repository', '',
29 29 _('repository root directory or name of overlay bundle file'),
30 30 _('REPO')),
31 31 ('', 'cwd', '',
32 32 _('change working directory'), _('DIR')),
33 33 ('y', 'noninteractive', None,
34 34 _('do not prompt, automatically pick the first choice for all prompts')),
35 35 ('q', 'quiet', None, _('suppress output')),
36 36 ('v', 'verbose', None, _('enable additional output')),
37 37 ('', 'config', [],
38 38 _('set/override config option (use \'section.name=value\')'),
39 39 _('CONFIG')),
40 40 ('', 'debug', None, _('enable debugging output')),
41 41 ('', 'debugger', None, _('start debugger')),
42 42 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 43 _('ENCODE')),
44 44 ('', 'encodingmode', encoding.encodingmode,
45 45 _('set the charset encoding mode'), _('MODE')),
46 46 ('', 'traceback', None, _('always print a traceback on exception')),
47 47 ('', 'time', None, _('time how long the command takes')),
48 48 ('', 'profile', None, _('print command execution profile')),
49 49 ('', 'version', None, _('output version information and exit')),
50 50 ('h', 'help', None, _('display help and exit')),
51 51 ]
52 52
53 53 dryrunopts = [('n', 'dry-run', None,
54 54 _('do not perform actions, just print output'))]
55 55
56 56 remoteopts = [
57 57 ('e', 'ssh', '',
58 58 _('specify ssh command to use'), _('CMD')),
59 59 ('', 'remotecmd', '',
60 60 _('specify hg command to run on the remote side'), _('CMD')),
61 61 ('', 'insecure', None,
62 62 _('do not verify server certificate (ignoring web.cacerts config)')),
63 63 ]
64 64
65 65 walkopts = [
66 66 ('I', 'include', [],
67 67 _('include names matching the given patterns'), _('PATTERN')),
68 68 ('X', 'exclude', [],
69 69 _('exclude names matching the given patterns'), _('PATTERN')),
70 70 ]
71 71
72 72 commitopts = [
73 73 ('m', 'message', '',
74 74 _('use text as commit message'), _('TEXT')),
75 75 ('l', 'logfile', '',
76 76 _('read commit message from file'), _('FILE')),
77 77 ]
78 78
79 79 commitopts2 = [
80 80 ('d', 'date', '',
81 81 _('record the specified date as commit date'), _('DATE')),
82 82 ('u', 'user', '',
83 83 _('record the specified user as committer'), _('USER')),
84 84 ]
85 85
86 86 templateopts = [
87 87 ('', 'style', '',
88 88 _('display using template map file'), _('STYLE')),
89 89 ('', 'template', '',
90 90 _('display with template'), _('TEMPLATE')),
91 91 ]
92 92
93 93 logopts = [
94 94 ('p', 'patch', None, _('show patch')),
95 95 ('g', 'git', None, _('use git extended diff format')),
96 96 ('l', 'limit', '',
97 97 _('limit number of changes displayed'), _('NUM')),
98 98 ('M', 'no-merges', None, _('do not show merges')),
99 99 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 100 ] + templateopts
101 101
102 102 diffopts = [
103 103 ('a', 'text', None, _('treat all files as text')),
104 104 ('g', 'git', None, _('use git extended diff format')),
105 105 ('', 'nodates', None, _('omit dates from diff headers'))
106 106 ]
107 107
108 108 diffopts2 = [
109 109 ('p', 'show-function', None, _('show which function each change is in')),
110 110 ('', 'reverse', None, _('produce a diff that undoes the changes')),
111 111 ('w', 'ignore-all-space', None,
112 112 _('ignore white space when comparing lines')),
113 113 ('b', 'ignore-space-change', None,
114 114 _('ignore changes in the amount of white space')),
115 115 ('B', 'ignore-blank-lines', None,
116 116 _('ignore changes whose lines are all blank')),
117 117 ('U', 'unified', '',
118 118 _('number of lines of context to show'), _('NUM')),
119 119 ('', 'stat', None, _('output diffstat-style summary of changes')),
120 120 ]
121 121
122 122 mergetoolopts = [
123 123 ('t', 'tool', '', _('specify merge tool')),
124 124 ]
125 125
126 126 similarityopts = [
127 127 ('s', 'similarity', '',
128 128 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
129 129 ]
130 130
131 131 subrepoopts = [
132 132 ('S', 'subrepos', None,
133 133 _('recurse into subrepositories'))
134 134 ]
135 135
136 136 # Commands start here, listed alphabetically
137 137
138 138 @command('^add',
139 139 walkopts + subrepoopts + dryrunopts,
140 140 _('[OPTION]... [FILE]...'))
141 141 def add(ui, repo, *pats, **opts):
142 142 """add the specified files on the next commit
143 143
144 144 Schedule files to be version controlled and added to the
145 145 repository.
146 146
147 147 The files will be added to the repository at the next commit. To
148 148 undo an add before that, see :hg:`forget`.
149 149
150 150 If no names are given, add all files to the repository.
151 151
152 152 .. container:: verbose
153 153
154 154 An example showing how new (unknown) files are added
155 155 automatically by :hg:`add`::
156 156
157 157 $ ls
158 158 foo.c
159 159 $ hg status
160 160 ? foo.c
161 161 $ hg add
162 162 adding foo.c
163 163 $ hg status
164 164 A foo.c
165 165
166 166 Returns 0 if all files are successfully added.
167 167 """
168 168
169 169 m = scmutil.match(repo[None], pats, opts)
170 170 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
171 171 opts.get('subrepos'), prefix="")
172 172 return rejected and 1 or 0
173 173
174 174 @command('addremove',
175 175 similarityopts + walkopts + dryrunopts,
176 176 _('[OPTION]... [FILE]...'))
177 177 def addremove(ui, repo, *pats, **opts):
178 178 """add all new files, delete all missing files
179 179
180 180 Add all new files and remove all missing files from the
181 181 repository.
182 182
183 183 New files are ignored if they match any of the patterns in
184 184 ``.hgignore``. As with add, these changes take effect at the next
185 185 commit.
186 186
187 187 Use the -s/--similarity option to detect renamed files. With a
188 188 parameter greater than 0, this compares every removed file with
189 189 every added file and records those similar enough as renames. This
190 190 option takes a percentage between 0 (disabled) and 100 (files must
191 191 be identical) as its parameter. Detecting renamed files this way
192 192 can be expensive. After using this option, :hg:`status -C` can be
193 193 used to check which files were identified as moved or renamed.
194 194
195 195 Returns 0 if all files are successfully added.
196 196 """
197 197 try:
198 198 sim = float(opts.get('similarity') or 100)
199 199 except ValueError:
200 200 raise util.Abort(_('similarity must be a number'))
201 201 if sim < 0 or sim > 100:
202 202 raise util.Abort(_('similarity must be between 0 and 100'))
203 203 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
204 204
205 205 @command('^annotate|blame',
206 206 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
207 207 ('', 'follow', None,
208 208 _('follow copies/renames and list the filename (DEPRECATED)')),
209 209 ('', 'no-follow', None, _("don't follow copies and renames")),
210 210 ('a', 'text', None, _('treat all files as text')),
211 211 ('u', 'user', None, _('list the author (long with -v)')),
212 212 ('f', 'file', None, _('list the filename')),
213 213 ('d', 'date', None, _('list the date (short with -q)')),
214 214 ('n', 'number', None, _('list the revision number (default)')),
215 215 ('c', 'changeset', None, _('list the changeset')),
216 216 ('l', 'line-number', None, _('show line number at the first appearance'))
217 217 ] + walkopts,
218 218 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
219 219 def annotate(ui, repo, *pats, **opts):
220 220 """show changeset information by line for each file
221 221
222 222 List changes in files, showing the revision id responsible for
223 223 each line
224 224
225 225 This command is useful for discovering when a change was made and
226 226 by whom.
227 227
228 228 Without the -a/--text option, annotate will avoid processing files
229 229 it detects as binary. With -a, annotate will annotate the file
230 230 anyway, although the results will probably be neither useful
231 231 nor desirable.
232 232
233 233 Returns 0 on success.
234 234 """
235 235 if opts.get('follow'):
236 236 # --follow is deprecated and now just an alias for -f/--file
237 237 # to mimic the behavior of Mercurial before version 1.5
238 238 opts['file'] = True
239 239
240 240 datefunc = ui.quiet and util.shortdate or util.datestr
241 241 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
242 242
243 243 if not pats:
244 244 raise util.Abort(_('at least one filename or pattern is required'))
245 245
246 246 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
247 247 ('number', ' ', lambda x: str(x[0].rev())),
248 248 ('changeset', ' ', lambda x: short(x[0].node())),
249 249 ('date', ' ', getdate),
250 250 ('file', ' ', lambda x: x[0].path()),
251 251 ('line_number', ':', lambda x: str(x[1])),
252 252 ]
253 253
254 254 if (not opts.get('user') and not opts.get('changeset')
255 255 and not opts.get('date') and not opts.get('file')):
256 256 opts['number'] = True
257 257
258 258 linenumber = opts.get('line_number') is not None
259 259 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
260 260 raise util.Abort(_('at least one of -n/-c is required for -l'))
261 261
262 262 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
263 263 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
264 264
265 265 def bad(x, y):
266 266 raise util.Abort("%s: %s" % (x, y))
267 267
268 268 ctx = scmutil.revsingle(repo, opts.get('rev'))
269 269 m = scmutil.match(ctx, pats, opts)
270 270 m.bad = bad
271 271 follow = not opts.get('no_follow')
272 272 for abs in ctx.walk(m):
273 273 fctx = ctx[abs]
274 274 if not opts.get('text') and util.binary(fctx.data()):
275 275 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
276 276 continue
277 277
278 278 lines = fctx.annotate(follow=follow, linenumber=linenumber)
279 279 pieces = []
280 280
281 281 for f, sep in funcmap:
282 282 l = [f(n) for n, dummy in lines]
283 283 if l:
284 284 sized = [(x, encoding.colwidth(x)) for x in l]
285 285 ml = max([w for x, w in sized])
286 286 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
287 287 for x, w in sized])
288 288
289 289 if pieces:
290 290 for p, l in zip(zip(*pieces), lines):
291 291 ui.write("%s: %s" % ("".join(p), l[1]))
292 292
293 293 @command('archive',
294 294 [('', 'no-decode', None, _('do not pass files through decoders')),
295 295 ('p', 'prefix', '', _('directory prefix for files in archive'),
296 296 _('PREFIX')),
297 297 ('r', 'rev', '', _('revision to distribute'), _('REV')),
298 298 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
299 299 ] + subrepoopts + walkopts,
300 300 _('[OPTION]... DEST'))
301 301 def archive(ui, repo, dest, **opts):
302 302 '''create an unversioned archive of a repository revision
303 303
304 304 By default, the revision used is the parent of the working
305 305 directory; use -r/--rev to specify a different revision.
306 306
307 307 The archive type is automatically detected based on file
308 308 extension (or override using -t/--type).
309 309
310 310 .. container:: verbose
311 311
312 312 Examples:
313 313
314 314 - create a zip file containing the 1.0 release::
315 315
316 316 hg archive -r 1.0 project-1.0.zip
317 317
318 318 - create a tarball excluding .hg files::
319 319
320 320 hg archive project.tar.gz -X ".hg*"
321 321
322 322 Valid types are:
323 323
324 324 :``files``: a directory full of files (default)
325 325 :``tar``: tar archive, uncompressed
326 326 :``tbz2``: tar archive, compressed using bzip2
327 327 :``tgz``: tar archive, compressed using gzip
328 328 :``uzip``: zip archive, uncompressed
329 329 :``zip``: zip archive, compressed using deflate
330 330
331 331 The exact name of the destination archive or directory is given
332 332 using a format string; see :hg:`help export` for details.
333 333
334 334 Each member added to an archive file has a directory prefix
335 335 prepended. Use -p/--prefix to specify a format string for the
336 336 prefix. The default is the basename of the archive, with suffixes
337 337 removed.
338 338
339 339 Returns 0 on success.
340 340 '''
341 341
342 342 ctx = scmutil.revsingle(repo, opts.get('rev'))
343 343 if not ctx:
344 344 raise util.Abort(_('no working directory: please specify a revision'))
345 345 node = ctx.node()
346 346 dest = cmdutil.makefilename(repo, dest, node)
347 347 if os.path.realpath(dest) == repo.root:
348 348 raise util.Abort(_('repository root cannot be destination'))
349 349
350 350 kind = opts.get('type') or archival.guesskind(dest) or 'files'
351 351 prefix = opts.get('prefix')
352 352
353 353 if dest == '-':
354 354 if kind == 'files':
355 355 raise util.Abort(_('cannot archive plain files to stdout'))
356 356 dest = cmdutil.makefileobj(repo, dest)
357 357 if not prefix:
358 358 prefix = os.path.basename(repo.root) + '-%h'
359 359
360 360 prefix = cmdutil.makefilename(repo, prefix, node)
361 361 matchfn = scmutil.match(ctx, [], opts)
362 362 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
363 363 matchfn, prefix, subrepos=opts.get('subrepos'))
364 364
365 365 @command('backout',
366 366 [('', 'merge', None, _('merge with old dirstate parent after backout')),
367 367 ('', 'parent', '',
368 368 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
369 369 ('r', 'rev', '', _('revision to backout'), _('REV')),
370 370 ] + mergetoolopts + walkopts + commitopts + commitopts2,
371 371 _('[OPTION]... [-r] REV'))
372 372 def backout(ui, repo, node=None, rev=None, **opts):
373 373 '''reverse effect of earlier changeset
374 374
375 375 Prepare a new changeset with the effect of REV undone in the
376 376 current working directory.
377 377
378 378 If REV is the parent of the working directory, then this new changeset
379 379 is committed automatically. Otherwise, hg needs to merge the
380 380 changes and the merged result is left uncommitted.
381 381
382 382 .. note::
383 383 backout cannot be used to fix either an unwanted or
384 384 incorrect merge.
385 385
386 386 .. container:: verbose
387 387
388 388 By default, the pending changeset will have one parent,
389 389 maintaining a linear history. With --merge, the pending
390 390 changeset will instead have two parents: the old parent of the
391 391 working directory and a new child of REV that simply undoes REV.
392 392
393 393 Before version 1.7, the behavior without --merge was equivalent
394 394 to specifying --merge followed by :hg:`update --clean .` to
395 395 cancel the merge and leave the child of REV as a head to be
396 396 merged separately.
397 397
398 398 See :hg:`help dates` for a list of formats valid for -d/--date.
399 399
400 400 Returns 0 on success.
401 401 '''
402 402 if rev and node:
403 403 raise util.Abort(_("please specify just one revision"))
404 404
405 405 if not rev:
406 406 rev = node
407 407
408 408 if not rev:
409 409 raise util.Abort(_("please specify a revision to backout"))
410 410
411 411 date = opts.get('date')
412 412 if date:
413 413 opts['date'] = util.parsedate(date)
414 414
415 415 cmdutil.bailifchanged(repo)
416 416 node = scmutil.revsingle(repo, rev).node()
417 417
418 418 op1, op2 = repo.dirstate.parents()
419 419 a = repo.changelog.ancestor(op1, node)
420 420 if a != node:
421 421 raise util.Abort(_('cannot backout change on a different branch'))
422 422
423 423 p1, p2 = repo.changelog.parents(node)
424 424 if p1 == nullid:
425 425 raise util.Abort(_('cannot backout a change with no parents'))
426 426 if p2 != nullid:
427 427 if not opts.get('parent'):
428 428 raise util.Abort(_('cannot backout a merge changeset'))
429 429 p = repo.lookup(opts['parent'])
430 430 if p not in (p1, p2):
431 431 raise util.Abort(_('%s is not a parent of %s') %
432 432 (short(p), short(node)))
433 433 parent = p
434 434 else:
435 435 if opts.get('parent'):
436 436 raise util.Abort(_('cannot use --parent on non-merge changeset'))
437 437 parent = p1
438 438
439 439 # the backout should appear on the same branch
440 440 branch = repo.dirstate.branch()
441 441 hg.clean(repo, node, show_stats=False)
442 442 repo.dirstate.setbranch(branch)
443 443 revert_opts = opts.copy()
444 444 revert_opts['date'] = None
445 445 revert_opts['all'] = True
446 446 revert_opts['rev'] = hex(parent)
447 447 revert_opts['no_backup'] = None
448 448 revert(ui, repo, **revert_opts)
449 449 if not opts.get('merge') and op1 != node:
450 450 try:
451 451 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
452 452 return hg.update(repo, op1)
453 453 finally:
454 454 ui.setconfig('ui', 'forcemerge', '')
455 455
456 456 commit_opts = opts.copy()
457 457 commit_opts['addremove'] = False
458 458 if not commit_opts['message'] and not commit_opts['logfile']:
459 459 # we don't translate commit messages
460 460 commit_opts['message'] = "Backed out changeset %s" % short(node)
461 461 commit_opts['force_editor'] = True
462 462 commit(ui, repo, **commit_opts)
463 463 def nice(node):
464 464 return '%d:%s' % (repo.changelog.rev(node), short(node))
465 465 ui.status(_('changeset %s backs out changeset %s\n') %
466 466 (nice(repo.changelog.tip()), nice(node)))
467 467 if opts.get('merge') and op1 != node:
468 468 hg.clean(repo, op1, show_stats=False)
469 469 ui.status(_('merging with changeset %s\n')
470 470 % nice(repo.changelog.tip()))
471 471 try:
472 472 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
473 473 return hg.merge(repo, hex(repo.changelog.tip()))
474 474 finally:
475 475 ui.setconfig('ui', 'forcemerge', '')
476 476 return 0
477 477
478 478 @command('bisect',
479 479 [('r', 'reset', False, _('reset bisect state')),
480 480 ('g', 'good', False, _('mark changeset good')),
481 481 ('b', 'bad', False, _('mark changeset bad')),
482 482 ('s', 'skip', False, _('skip testing changeset')),
483 483 ('e', 'extend', False, _('extend the bisect range')),
484 484 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
485 485 ('U', 'noupdate', False, _('do not update to target'))],
486 486 _("[-gbsr] [-U] [-c CMD] [REV]"))
487 487 def bisect(ui, repo, rev=None, extra=None, command=None,
488 488 reset=None, good=None, bad=None, skip=None, extend=None,
489 489 noupdate=None):
490 490 """subdivision search of changesets
491 491
492 492 This command helps to find changesets which introduce problems. To
493 493 use, mark the earliest changeset you know exhibits the problem as
494 494 bad, then mark the latest changeset which is free from the problem
495 495 as good. Bisect will update your working directory to a revision
496 496 for testing (unless the -U/--noupdate option is specified). Once
497 497 you have performed tests, mark the working directory as good or
498 498 bad, and bisect will either update to another candidate changeset
499 499 or announce that it has found the bad revision.
500 500
501 501 As a shortcut, you can also use the revision argument to mark a
502 502 revision as good or bad without checking it out first.
503 503
504 504 If you supply a command, it will be used for automatic bisection.
505 505 Its exit status will be used to mark revisions as good or bad:
506 506 status 0 means good, 125 means to skip the revision, 127
507 507 (command not found) will abort the bisection, and any other
508 508 non-zero exit status means the revision is bad.
509 509
510 510 .. container:: verbose
511 511
512 512 Some examples:
513 513
514 514 - start a bisection with known bad revision 12, and good revision 34::
515 515
516 516 hg bisect --bad 34
517 517 hg bisect --good 12
518 518
519 519 - advance the current bisection by marking current revision as good or
520 520 bad::
521 521
522 522 hg bisect --good
523 523 hg bisect --bad
524 524
525 525 - mark the current revision, or a known revision, to be skipped (eg. if
526 526 that revision is not usable because of another issue)::
527 527
528 528 hg bisect --skip
529 529 hg bisect --skip 23
530 530
531 531 - forget the current bisection::
532 532
533 533 hg bisect --reset
534 534
535 535 - use 'make && make tests' to automatically find the first broken
536 536 revision::
537 537
538 538 hg bisect --reset
539 539 hg bisect --bad 34
540 540 hg bisect --good 12
541 541 hg bisect --command 'make && make tests'
542 542
543 543 - see all changesets whose states are already known in the current
544 544 bisection::
545 545
546 546 hg log -r "bisect(pruned)"
547 547
548 548 - see all changesets that took part in the current bisection::
549 549
550 550 hg log -r "bisect(range)"
551 551
552 552 - with the graphlog extension, you can even get a nice graph::
553 553
554 554 hg log --graph -r "bisect(range)"
555 555
556 556 See :hg:`help revsets` for more about the `bisect()` keyword.
557 557
558 558 Returns 0 on success.
559 559 """
560 560 def extendbisectrange(nodes, good):
561 561 # bisect is incomplete when it ends on a merge node and
562 562 # one of the parent was not checked.
563 563 parents = repo[nodes[0]].parents()
564 564 if len(parents) > 1:
565 565 side = good and state['bad'] or state['good']
566 566 num = len(set(i.node() for i in parents) & set(side))
567 567 if num == 1:
568 568 return parents[0].ancestor(parents[1])
569 569 return None
570 570
571 571 def print_result(nodes, good):
572 572 displayer = cmdutil.show_changeset(ui, repo, {})
573 573 if len(nodes) == 1:
574 574 # narrowed it down to a single revision
575 575 if good:
576 576 ui.write(_("The first good revision is:\n"))
577 577 else:
578 578 ui.write(_("The first bad revision is:\n"))
579 579 displayer.show(repo[nodes[0]])
580 580 extendnode = extendbisectrange(nodes, good)
581 581 if extendnode is not None:
582 582 ui.write(_('Not all ancestors of this changeset have been'
583 583 ' checked.\nUse bisect --extend to continue the '
584 584 'bisection from\nthe common ancestor, %s.\n')
585 585 % extendnode)
586 586 else:
587 587 # multiple possible revisions
588 588 if good:
589 589 ui.write(_("Due to skipped revisions, the first "
590 590 "good revision could be any of:\n"))
591 591 else:
592 592 ui.write(_("Due to skipped revisions, the first "
593 593 "bad revision could be any of:\n"))
594 594 for n in nodes:
595 595 displayer.show(repo[n])
596 596 displayer.close()
597 597
598 598 def check_state(state, interactive=True):
599 599 if not state['good'] or not state['bad']:
600 600 if (good or bad or skip or reset) and interactive:
601 601 return
602 602 if not state['good']:
603 603 raise util.Abort(_('cannot bisect (no known good revisions)'))
604 604 else:
605 605 raise util.Abort(_('cannot bisect (no known bad revisions)'))
606 606 return True
607 607
608 608 # backward compatibility
609 609 if rev in "good bad reset init".split():
610 610 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
611 611 cmd, rev, extra = rev, extra, None
612 612 if cmd == "good":
613 613 good = True
614 614 elif cmd == "bad":
615 615 bad = True
616 616 else:
617 617 reset = True
618 618 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
619 619 raise util.Abort(_('incompatible arguments'))
620 620
621 621 if reset:
622 622 p = repo.join("bisect.state")
623 623 if os.path.exists(p):
624 624 os.unlink(p)
625 625 return
626 626
627 627 state = hbisect.load_state(repo)
628 628
629 629 if command:
630 630 changesets = 1
631 631 try:
632 632 while changesets:
633 633 # update state
634 634 status = util.system(command, out=ui.fout)
635 635 if status == 125:
636 636 transition = "skip"
637 637 elif status == 0:
638 638 transition = "good"
639 639 # status < 0 means process was killed
640 640 elif status == 127:
641 641 raise util.Abort(_("failed to execute %s") % command)
642 642 elif status < 0:
643 643 raise util.Abort(_("%s killed") % command)
644 644 else:
645 645 transition = "bad"
646 646 ctx = scmutil.revsingle(repo, rev)
647 647 rev = None # clear for future iterations
648 648 state[transition].append(ctx.node())
649 649 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
650 650 check_state(state, interactive=False)
651 651 # bisect
652 652 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
653 653 # update to next check
654 654 cmdutil.bailifchanged(repo)
655 655 hg.clean(repo, nodes[0], show_stats=False)
656 656 finally:
657 657 hbisect.save_state(repo, state)
658 658 print_result(nodes, good)
659 659 return
660 660
661 661 # update state
662 662
663 663 if rev:
664 664 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
665 665 else:
666 666 nodes = [repo.lookup('.')]
667 667
668 668 if good or bad or skip:
669 669 if good:
670 670 state['good'] += nodes
671 671 elif bad:
672 672 state['bad'] += nodes
673 673 elif skip:
674 674 state['skip'] += nodes
675 675 hbisect.save_state(repo, state)
676 676
677 677 if not check_state(state):
678 678 return
679 679
680 680 # actually bisect
681 681 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
682 682 if extend:
683 683 if not changesets:
684 684 extendnode = extendbisectrange(nodes, good)
685 685 if extendnode is not None:
686 686 ui.write(_("Extending search to changeset %d:%s\n"
687 687 % (extendnode.rev(), extendnode)))
688 688 if noupdate:
689 689 return
690 690 cmdutil.bailifchanged(repo)
691 691 return hg.clean(repo, extendnode.node())
692 692 raise util.Abort(_("nothing to extend"))
693 693
694 694 if changesets == 0:
695 695 print_result(nodes, good)
696 696 else:
697 697 assert len(nodes) == 1 # only a single node can be tested next
698 698 node = nodes[0]
699 699 # compute the approximate number of remaining tests
700 700 tests, size = 0, 2
701 701 while size <= changesets:
702 702 tests, size = tests + 1, size * 2
703 703 rev = repo.changelog.rev(node)
704 704 ui.write(_("Testing changeset %d:%s "
705 705 "(%d changesets remaining, ~%d tests)\n")
706 706 % (rev, short(node), changesets, tests))
707 707 if not noupdate:
708 708 cmdutil.bailifchanged(repo)
709 709 return hg.clean(repo, node)
710 710
711 711 @command('bookmarks',
712 712 [('f', 'force', False, _('force')),
713 713 ('r', 'rev', '', _('revision'), _('REV')),
714 714 ('d', 'delete', False, _('delete a given bookmark')),
715 715 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
716 716 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
717 717 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
718 718 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
719 719 rename=None, inactive=False):
720 720 '''track a line of development with movable markers
721 721
722 722 Bookmarks are pointers to certain commits that move when
723 723 committing. Bookmarks are local. They can be renamed, copied and
724 724 deleted. It is possible to use bookmark names in :hg:`merge` and
725 725 :hg:`update` to merge and update respectively to a given bookmark.
726 726
727 727 You can use :hg:`bookmark NAME` to set a bookmark on the working
728 728 directory's parent revision with the given name. If you specify
729 729 a revision using -r REV (where REV may be an existing bookmark),
730 730 the bookmark is assigned to that revision.
731 731
732 732 Bookmarks can be pushed and pulled between repositories (see :hg:`help
733 733 push` and :hg:`help pull`). This requires both the local and remote
734 734 repositories to support bookmarks. For versions prior to 1.8, this means
735 735 the bookmarks extension must be enabled.
736 736 '''
737 737 hexfn = ui.debugflag and hex or short
738 738 marks = repo._bookmarks
739 739 cur = repo.changectx('.').node()
740 740
741 741 if rename:
742 742 if rename not in marks:
743 743 raise util.Abort(_("bookmark '%s' does not exist") % rename)
744 744 if mark in marks and not force:
745 745 raise util.Abort(_("bookmark '%s' already exists "
746 746 "(use -f to force)") % mark)
747 747 if mark is None:
748 748 raise util.Abort(_("new bookmark name required"))
749 749 marks[mark] = marks[rename]
750 750 if repo._bookmarkcurrent == rename and not inactive:
751 751 bookmarks.setcurrent(repo, mark)
752 752 del marks[rename]
753 753 bookmarks.write(repo)
754 754 return
755 755
756 756 if delete:
757 757 if mark is None:
758 758 raise util.Abort(_("bookmark name required"))
759 759 if mark not in marks:
760 760 raise util.Abort(_("bookmark '%s' does not exist") % mark)
761 761 if mark == repo._bookmarkcurrent:
762 762 bookmarks.setcurrent(repo, None)
763 763 del marks[mark]
764 764 bookmarks.write(repo)
765 765 return
766 766
767 767 if mark is not None:
768 768 if "\n" in mark:
769 769 raise util.Abort(_("bookmark name cannot contain newlines"))
770 770 mark = mark.strip()
771 771 if not mark:
772 772 raise util.Abort(_("bookmark names cannot consist entirely of "
773 773 "whitespace"))
774 774 if inactive and mark == repo._bookmarkcurrent:
775 775 bookmarks.setcurrent(repo, None)
776 776 return
777 777 if mark in marks and not force:
778 778 raise util.Abort(_("bookmark '%s' already exists "
779 779 "(use -f to force)") % mark)
780 780 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
781 781 and not force):
782 782 raise util.Abort(
783 783 _("a bookmark cannot have the name of an existing branch"))
784 784 if rev:
785 785 marks[mark] = repo.lookup(rev)
786 786 else:
787 787 marks[mark] = repo.changectx('.').node()
788 788 if not inactive and repo.changectx('.').node() == marks[mark]:
789 789 bookmarks.setcurrent(repo, mark)
790 790 bookmarks.write(repo)
791 791 return
792 792
793 793 if mark is None:
794 794 if rev:
795 795 raise util.Abort(_("bookmark name required"))
796 796 if len(marks) == 0:
797 797 ui.status(_("no bookmarks set\n"))
798 798 else:
799 799 for bmark, n in sorted(marks.iteritems()):
800 800 current = repo._bookmarkcurrent
801 801 if bmark == current and n == cur:
802 802 prefix, label = '*', 'bookmarks.current'
803 803 else:
804 804 prefix, label = ' ', ''
805 805
806 806 if ui.quiet:
807 807 ui.write("%s\n" % bmark, label=label)
808 808 else:
809 809 ui.write(" %s %-25s %d:%s\n" % (
810 810 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
811 811 label=label)
812 812 return
813 813
814 814 @command('branch',
815 815 [('f', 'force', None,
816 816 _('set branch name even if it shadows an existing branch')),
817 817 ('C', 'clean', None, _('reset branch name to parent branch name'))],
818 818 _('[-fC] [NAME]'))
819 819 def branch(ui, repo, label=None, **opts):
820 820 """set or show the current branch name
821 821
822 822 With no argument, show the current branch name. With one argument,
823 823 set the working directory branch name (the branch will not exist
824 824 in the repository until the next commit). Standard practice
825 825 recommends that primary development take place on the 'default'
826 826 branch.
827 827
828 828 Unless -f/--force is specified, branch will not let you set a
829 829 branch name that already exists, even if it's inactive.
830 830
831 831 Use -C/--clean to reset the working directory branch to that of
832 832 the parent of the working directory, negating a previous branch
833 833 change.
834 834
835 835 Use the command :hg:`update` to switch to an existing branch. Use
836 836 :hg:`commit --close-branch` to mark this branch as closed.
837 837
838 838 .. note::
839 839 Branch names are permanent. Use :hg:`bookmark` to create a
840 840 light-weight bookmark instead. See :hg:`help glossary` for more
841 841 information about named branches and bookmarks.
842 842
843 843 Returns 0 on success.
844 844 """
845 845
846 846 if opts.get('clean'):
847 847 label = repo[None].p1().branch()
848 848 repo.dirstate.setbranch(label)
849 849 ui.status(_('reset working directory to branch %s\n') % label)
850 850 elif label:
851 851 if not opts.get('force') and label in repo.branchtags():
852 852 if label not in [p.branch() for p in repo.parents()]:
853 853 raise util.Abort(_('a branch of the same name already exists'),
854 854 # i18n: "it" refers to an existing branch
855 855 hint=_("use 'hg update' to switch to it"))
856 856 repo.dirstate.setbranch(label)
857 857 ui.status(_('marked working directory as branch %s\n') % label)
858 858 else:
859 859 ui.write("%s\n" % repo.dirstate.branch())
860 860
861 861 @command('branches',
862 862 [('a', 'active', False, _('show only branches that have unmerged heads')),
863 863 ('c', 'closed', False, _('show normal and closed branches'))],
864 864 _('[-ac]'))
865 865 def branches(ui, repo, active=False, closed=False):
866 866 """list repository named branches
867 867
868 868 List the repository's named branches, indicating which ones are
869 869 inactive. If -c/--closed is specified, also list branches which have
870 870 been marked closed (see :hg:`commit --close-branch`).
871 871
872 872 If -a/--active is specified, only show active branches. A branch
873 873 is considered active if it contains repository heads.
874 874
875 875 Use the command :hg:`update` to switch to an existing branch.
876 876
877 877 Returns 0.
878 878 """
879 879
880 880 hexfunc = ui.debugflag and hex or short
881 881 activebranches = [repo[n].branch() for n in repo.heads()]
882 882 def testactive(tag, node):
883 883 realhead = tag in activebranches
884 884 open = node in repo.branchheads(tag, closed=False)
885 885 return realhead and open
886 886 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
887 887 for tag, node in repo.branchtags().items()],
888 888 reverse=True)
889 889
890 890 for isactive, node, tag in branches:
891 891 if (not active) or isactive:
892 892 if ui.quiet:
893 893 ui.write("%s\n" % tag)
894 894 else:
895 895 hn = repo.lookup(node)
896 896 if isactive:
897 897 label = 'branches.active'
898 898 notice = ''
899 899 elif hn not in repo.branchheads(tag, closed=False):
900 900 if not closed:
901 901 continue
902 902 label = 'branches.closed'
903 903 notice = _(' (closed)')
904 904 else:
905 905 label = 'branches.inactive'
906 906 notice = _(' (inactive)')
907 907 if tag == repo.dirstate.branch():
908 908 label = 'branches.current'
909 909 rev = str(node).rjust(31 - encoding.colwidth(tag))
910 910 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
911 911 tag = ui.label(tag, label)
912 912 ui.write("%s %s%s\n" % (tag, rev, notice))
913 913
914 914 @command('bundle',
915 915 [('f', 'force', None, _('run even when the destination is unrelated')),
916 916 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
917 917 _('REV')),
918 918 ('b', 'branch', [], _('a specific branch you would like to bundle'),
919 919 _('BRANCH')),
920 920 ('', 'base', [],
921 921 _('a base changeset assumed to be available at the destination'),
922 922 _('REV')),
923 923 ('a', 'all', None, _('bundle all changesets in the repository')),
924 924 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
925 925 ] + remoteopts,
926 926 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
927 927 def bundle(ui, repo, fname, dest=None, **opts):
928 928 """create a changegroup file
929 929
930 930 Generate a compressed changegroup file collecting changesets not
931 931 known to be in another repository.
932 932
933 933 If you omit the destination repository, then hg assumes the
934 934 destination will have all the nodes you specify with --base
935 935 parameters. To create a bundle containing all changesets, use
936 936 -a/--all (or --base null).
937 937
938 938 You can change compression method with the -t/--type option.
939 939 The available compression methods are: none, bzip2, and
940 940 gzip (by default, bundles are compressed using bzip2).
941 941
942 942 The bundle file can then be transferred using conventional means
943 943 and applied to another repository with the unbundle or pull
944 944 command. This is useful when direct push and pull are not
945 945 available or when exporting an entire repository is undesirable.
946 946
947 947 Applying bundles preserves all changeset contents including
948 948 permissions, copy/rename information, and revision history.
949 949
950 950 Returns 0 on success, 1 if no changes found.
951 951 """
952 952 revs = None
953 953 if 'rev' in opts:
954 954 revs = scmutil.revrange(repo, opts['rev'])
955 955
956 956 if opts.get('all'):
957 957 base = ['null']
958 958 else:
959 959 base = scmutil.revrange(repo, opts.get('base'))
960 960 if base:
961 961 if dest:
962 962 raise util.Abort(_("--base is incompatible with specifying "
963 963 "a destination"))
964 964 common = [repo.lookup(rev) for rev in base]
965 965 heads = revs and map(repo.lookup, revs) or revs
966 966 else:
967 967 dest = ui.expandpath(dest or 'default-push', dest or 'default')
968 968 dest, branches = hg.parseurl(dest, opts.get('branch'))
969 969 other = hg.peer(repo, opts, dest)
970 970 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
971 971 heads = revs and map(repo.lookup, revs) or revs
972 972 common, outheads = discovery.findcommonoutgoing(repo, other,
973 973 onlyheads=heads,
974 974 force=opts.get('force'))
975 975
976 976 cg = repo.getbundle('bundle', common=common, heads=heads)
977 977 if not cg:
978 978 ui.status(_("no changes found\n"))
979 979 return 1
980 980
981 981 bundletype = opts.get('type', 'bzip2').lower()
982 982 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
983 983 bundletype = btypes.get(bundletype)
984 984 if bundletype not in changegroup.bundletypes:
985 985 raise util.Abort(_('unknown bundle type specified with --type'))
986 986
987 987 changegroup.writebundle(cg, fname, bundletype)
988 988
989 989 @command('cat',
990 990 [('o', 'output', '',
991 991 _('print output to file with formatted name'), _('FORMAT')),
992 992 ('r', 'rev', '', _('print the given revision'), _('REV')),
993 993 ('', 'decode', None, _('apply any matching decode filter')),
994 994 ] + walkopts,
995 995 _('[OPTION]... FILE...'))
996 996 def cat(ui, repo, file1, *pats, **opts):
997 997 """output the current or given revision of files
998 998
999 999 Print the specified files as they were at the given revision. If
1000 1000 no revision is given, the parent of the working directory is used,
1001 1001 or tip if no revision is checked out.
1002 1002
1003 1003 Output may be to a file, in which case the name of the file is
1004 1004 given using a format string. The formatting rules are the same as
1005 1005 for the export command, with the following additions:
1006 1006
1007 1007 :``%s``: basename of file being printed
1008 1008 :``%d``: dirname of file being printed, or '.' if in repository root
1009 1009 :``%p``: root-relative path name of file being printed
1010 1010
1011 1011 Returns 0 on success.
1012 1012 """
1013 1013 ctx = scmutil.revsingle(repo, opts.get('rev'))
1014 1014 err = 1
1015 1015 m = scmutil.match(ctx, (file1,) + pats, opts)
1016 1016 for abs in ctx.walk(m):
1017 1017 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1018 1018 pathname=abs)
1019 1019 data = ctx[abs].data()
1020 1020 if opts.get('decode'):
1021 1021 data = repo.wwritedata(abs, data)
1022 1022 fp.write(data)
1023 1023 fp.close()
1024 1024 err = 0
1025 1025 return err
1026 1026
1027 1027 @command('^clone',
1028 1028 [('U', 'noupdate', None,
1029 1029 _('the clone will include an empty working copy (only a repository)')),
1030 1030 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1031 1031 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1032 1032 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1033 1033 ('', 'pull', None, _('use pull protocol to copy metadata')),
1034 1034 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1035 1035 ] + remoteopts,
1036 1036 _('[OPTION]... SOURCE [DEST]'))
1037 1037 def clone(ui, source, dest=None, **opts):
1038 1038 """make a copy of an existing repository
1039 1039
1040 1040 Create a copy of an existing repository in a new directory.
1041 1041
1042 1042 If no destination directory name is specified, it defaults to the
1043 1043 basename of the source.
1044 1044
1045 1045 The location of the source is added to the new repository's
1046 1046 ``.hg/hgrc`` file, as the default to be used for future pulls.
1047 1047
1048 1048 Only local paths and ``ssh://`` URLs are supported as
1049 1049 destinations. For ``ssh://`` destinations, no working directory or
1050 1050 ``.hg/hgrc`` will be created on the remote side.
1051 1051
1052 1052 To pull only a subset of changesets, specify one or more revisions
1053 1053 identifiers with -r/--rev or branches with -b/--branch. The
1054 1054 resulting clone will contain only the specified changesets and
1055 1055 their ancestors. These options (or 'clone src#rev dest') imply
1056 1056 --pull, even for local source repositories. Note that specifying a
1057 1057 tag will include the tagged changeset but not the changeset
1058 1058 containing the tag.
1059 1059
1060 1060 To check out a particular version, use -u/--update, or
1061 1061 -U/--noupdate to create a clone with no working directory.
1062 1062
1063 1063 .. container:: verbose
1064 1064
1065 1065 For efficiency, hardlinks are used for cloning whenever the
1066 1066 source and destination are on the same filesystem (note this
1067 1067 applies only to the repository data, not to the working
1068 1068 directory). Some filesystems, such as AFS, implement hardlinking
1069 1069 incorrectly, but do not report errors. In these cases, use the
1070 1070 --pull option to avoid hardlinking.
1071 1071
1072 1072 In some cases, you can clone repositories and the working
1073 1073 directory using full hardlinks with ::
1074 1074
1075 1075 $ cp -al REPO REPOCLONE
1076 1076
1077 1077 This is the fastest way to clone, but it is not always safe. The
1078 1078 operation is not atomic (making sure REPO is not modified during
1079 1079 the operation is up to you) and you have to make sure your
1080 1080 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1081 1081 so). Also, this is not compatible with certain extensions that
1082 1082 place their metadata under the .hg directory, such as mq.
1083 1083
1084 1084 Mercurial will update the working directory to the first applicable
1085 1085 revision from this list:
1086 1086
1087 1087 a) null if -U or the source repository has no changesets
1088 1088 b) if -u . and the source repository is local, the first parent of
1089 1089 the source repository's working directory
1090 1090 c) the changeset specified with -u (if a branch name, this means the
1091 1091 latest head of that branch)
1092 1092 d) the changeset specified with -r
1093 1093 e) the tipmost head specified with -b
1094 1094 f) the tipmost head specified with the url#branch source syntax
1095 1095 g) the tipmost head of the default branch
1096 1096 h) tip
1097 1097
1098 1098 Examples:
1099 1099
1100 1100 - clone a remote repository to a new directory named hg/::
1101 1101
1102 1102 hg clone http://selenic.com/hg
1103 1103
1104 1104 - create a lightweight local clone::
1105 1105
1106 1106 hg clone project/ project-feature/
1107 1107
1108 1108 - clone from an absolute path on an ssh server (note double-slash)::
1109 1109
1110 1110 hg clone ssh://user@server//home/projects/alpha/
1111 1111
1112 1112 - do a high-speed clone over a LAN while checking out a
1113 1113 specified version::
1114 1114
1115 1115 hg clone --uncompressed http://server/repo -u 1.5
1116 1116
1117 1117 - create a repository without changesets after a particular revision::
1118 1118
1119 1119 hg clone -r 04e544 experimental/ good/
1120 1120
1121 1121 - clone (and track) a particular named branch::
1122 1122
1123 1123 hg clone http://selenic.com/hg#stable
1124 1124
1125 1125 See :hg:`help urls` for details on specifying URLs.
1126 1126
1127 1127 Returns 0 on success.
1128 1128 """
1129 1129 if opts.get('noupdate') and opts.get('updaterev'):
1130 1130 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1131 1131
1132 1132 r = hg.clone(ui, opts, source, dest,
1133 1133 pull=opts.get('pull'),
1134 1134 stream=opts.get('uncompressed'),
1135 1135 rev=opts.get('rev'),
1136 1136 update=opts.get('updaterev') or not opts.get('noupdate'),
1137 1137 branch=opts.get('branch'))
1138 1138
1139 1139 return r is None
1140 1140
1141 1141 @command('^commit|ci',
1142 1142 [('A', 'addremove', None,
1143 1143 _('mark new/missing files as added/removed before committing')),
1144 1144 ('', 'close-branch', None,
1145 1145 _('mark a branch as closed, hiding it from the branch list')),
1146 1146 ] + walkopts + commitopts + commitopts2,
1147 1147 _('[OPTION]... [FILE]...'))
1148 1148 def commit(ui, repo, *pats, **opts):
1149 1149 """commit the specified files or all outstanding changes
1150 1150
1151 1151 Commit changes to the given files into the repository. Unlike a
1152 1152 centralized SCM, this operation is a local operation. See
1153 1153 :hg:`push` for a way to actively distribute your changes.
1154 1154
1155 1155 If a list of files is omitted, all changes reported by :hg:`status`
1156 1156 will be committed.
1157 1157
1158 1158 If you are committing the result of a merge, do not provide any
1159 1159 filenames or -I/-X filters.
1160 1160
1161 1161 If no commit message is specified, Mercurial starts your
1162 1162 configured editor where you can enter a message. In case your
1163 1163 commit fails, you will find a backup of your message in
1164 1164 ``.hg/last-message.txt``.
1165 1165
1166 1166 See :hg:`help dates` for a list of formats valid for -d/--date.
1167 1167
1168 1168 Returns 0 on success, 1 if nothing changed.
1169 1169 """
1170 1170 extra = {}
1171 1171 if opts.get('close_branch'):
1172 1172 if repo['.'].node() not in repo.branchheads():
1173 1173 # The topo heads set is included in the branch heads set of the
1174 1174 # current branch, so it's sufficient to test branchheads
1175 1175 raise util.Abort(_('can only close branch heads'))
1176 1176 extra['close'] = 1
1177 1177 e = cmdutil.commiteditor
1178 1178 if opts.get('force_editor'):
1179 1179 e = cmdutil.commitforceeditor
1180 1180
1181 1181 def commitfunc(ui, repo, message, match, opts):
1182 1182 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1183 1183 editor=e, extra=extra)
1184 1184
1185 1185 branch = repo[None].branch()
1186 1186 bheads = repo.branchheads(branch)
1187 1187
1188 1188 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1189 1189 if not node:
1190 1190 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1191 1191 if stat[3]:
1192 1192 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1193 1193 % len(stat[3]))
1194 1194 else:
1195 1195 ui.status(_("nothing changed\n"))
1196 1196 return 1
1197 1197
1198 1198 ctx = repo[node]
1199 1199 parents = ctx.parents()
1200 1200
1201 1201 if (bheads and node not in bheads and not
1202 1202 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1203 1203 ui.status(_('created new head\n'))
1204 1204 # The message is not printed for initial roots. For the other
1205 1205 # changesets, it is printed in the following situations:
1206 1206 #
1207 1207 # Par column: for the 2 parents with ...
1208 1208 # N: null or no parent
1209 1209 # B: parent is on another named branch
1210 1210 # C: parent is a regular non head changeset
1211 1211 # H: parent was a branch head of the current branch
1212 1212 # Msg column: whether we print "created new head" message
1213 1213 # In the following, it is assumed that there already exists some
1214 1214 # initial branch heads of the current branch, otherwise nothing is
1215 1215 # printed anyway.
1216 1216 #
1217 1217 # Par Msg Comment
1218 1218 # NN y additional topo root
1219 1219 #
1220 1220 # BN y additional branch root
1221 1221 # CN y additional topo head
1222 1222 # HN n usual case
1223 1223 #
1224 1224 # BB y weird additional branch root
1225 1225 # CB y branch merge
1226 1226 # HB n merge with named branch
1227 1227 #
1228 1228 # CC y additional head from merge
1229 1229 # CH n merge with a head
1230 1230 #
1231 1231 # HH n head merge: head count decreases
1232 1232
1233 1233 if not opts.get('close_branch'):
1234 1234 for r in parents:
1235 1235 if r.extra().get('close') and r.branch() == branch:
1236 1236 ui.status(_('reopening closed branch head %d\n') % r)
1237 1237
1238 1238 if ui.debugflag:
1239 1239 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1240 1240 elif ui.verbose:
1241 1241 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1242 1242
1243 1243 @command('copy|cp',
1244 1244 [('A', 'after', None, _('record a copy that has already occurred')),
1245 1245 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1246 1246 ] + walkopts + dryrunopts,
1247 1247 _('[OPTION]... [SOURCE]... DEST'))
1248 1248 def copy(ui, repo, *pats, **opts):
1249 1249 """mark files as copied for the next commit
1250 1250
1251 1251 Mark dest as having copies of source files. If dest is a
1252 1252 directory, copies are put in that directory. If dest is a file,
1253 1253 the source must be a single file.
1254 1254
1255 1255 By default, this command copies the contents of files as they
1256 1256 exist in the working directory. If invoked with -A/--after, the
1257 1257 operation is recorded, but no copying is performed.
1258 1258
1259 1259 This command takes effect with the next commit. To undo a copy
1260 1260 before that, see :hg:`revert`.
1261 1261
1262 1262 Returns 0 on success, 1 if errors are encountered.
1263 1263 """
1264 1264 wlock = repo.wlock(False)
1265 1265 try:
1266 1266 return cmdutil.copy(ui, repo, pats, opts)
1267 1267 finally:
1268 1268 wlock.release()
1269 1269
1270 1270 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1271 1271 def debugancestor(ui, repo, *args):
1272 1272 """find the ancestor revision of two revisions in a given index"""
1273 1273 if len(args) == 3:
1274 1274 index, rev1, rev2 = args
1275 1275 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1276 1276 lookup = r.lookup
1277 1277 elif len(args) == 2:
1278 1278 if not repo:
1279 1279 raise util.Abort(_("there is no Mercurial repository here "
1280 1280 "(.hg not found)"))
1281 1281 rev1, rev2 = args
1282 1282 r = repo.changelog
1283 1283 lookup = repo.lookup
1284 1284 else:
1285 1285 raise util.Abort(_('either two or three arguments required'))
1286 1286 a = r.ancestor(lookup(rev1), lookup(rev2))
1287 1287 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1288 1288
1289 1289 @command('debugbuilddag',
1290 1290 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1291 1291 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1292 1292 ('n', 'new-file', None, _('add new file at each rev'))],
1293 1293 _('[OPTION]... [TEXT]'))
1294 1294 def debugbuilddag(ui, repo, text=None,
1295 1295 mergeable_file=False,
1296 1296 overwritten_file=False,
1297 1297 new_file=False):
1298 1298 """builds a repo with a given DAG from scratch in the current empty repo
1299 1299
1300 1300 The description of the DAG is read from stdin if not given on the
1301 1301 command line.
1302 1302
1303 1303 Elements:
1304 1304
1305 1305 - "+n" is a linear run of n nodes based on the current default parent
1306 1306 - "." is a single node based on the current default parent
1307 1307 - "$" resets the default parent to null (implied at the start);
1308 1308 otherwise the default parent is always the last node created
1309 1309 - "<p" sets the default parent to the backref p
1310 1310 - "*p" is a fork at parent p, which is a backref
1311 1311 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1312 1312 - "/p2" is a merge of the preceding node and p2
1313 1313 - ":tag" defines a local tag for the preceding node
1314 1314 - "@branch" sets the named branch for subsequent nodes
1315 1315 - "#...\\n" is a comment up to the end of the line
1316 1316
1317 1317 Whitespace between the above elements is ignored.
1318 1318
1319 1319 A backref is either
1320 1320
1321 1321 - a number n, which references the node curr-n, where curr is the current
1322 1322 node, or
1323 1323 - the name of a local tag you placed earlier using ":tag", or
1324 1324 - empty to denote the default parent.
1325 1325
1326 1326 All string valued-elements are either strictly alphanumeric, or must
1327 1327 be enclosed in double quotes ("..."), with "\\" as escape character.
1328 1328 """
1329 1329
1330 1330 if text is None:
1331 1331 ui.status(_("reading DAG from stdin\n"))
1332 1332 text = ui.fin.read()
1333 1333
1334 1334 cl = repo.changelog
1335 1335 if len(cl) > 0:
1336 1336 raise util.Abort(_('repository is not empty'))
1337 1337
1338 1338 # determine number of revs in DAG
1339 1339 total = 0
1340 1340 for type, data in dagparser.parsedag(text):
1341 1341 if type == 'n':
1342 1342 total += 1
1343 1343
1344 1344 if mergeable_file:
1345 1345 linesperrev = 2
1346 1346 # make a file with k lines per rev
1347 1347 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1348 1348 initialmergedlines.append("")
1349 1349
1350 1350 tags = []
1351 1351
1352 1352 tr = repo.transaction("builddag")
1353 1353 try:
1354 1354
1355 1355 at = -1
1356 1356 atbranch = 'default'
1357 1357 nodeids = []
1358 1358 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1359 1359 for type, data in dagparser.parsedag(text):
1360 1360 if type == 'n':
1361 1361 ui.note('node %s\n' % str(data))
1362 1362 id, ps = data
1363 1363
1364 1364 files = []
1365 1365 fctxs = {}
1366 1366
1367 1367 p2 = None
1368 1368 if mergeable_file:
1369 1369 fn = "mf"
1370 1370 p1 = repo[ps[0]]
1371 1371 if len(ps) > 1:
1372 1372 p2 = repo[ps[1]]
1373 1373 pa = p1.ancestor(p2)
1374 1374 base, local, other = [x[fn].data() for x in pa, p1, p2]
1375 1375 m3 = simplemerge.Merge3Text(base, local, other)
1376 1376 ml = [l.strip() for l in m3.merge_lines()]
1377 1377 ml.append("")
1378 1378 elif at > 0:
1379 1379 ml = p1[fn].data().split("\n")
1380 1380 else:
1381 1381 ml = initialmergedlines
1382 1382 ml[id * linesperrev] += " r%i" % id
1383 1383 mergedtext = "\n".join(ml)
1384 1384 files.append(fn)
1385 1385 fctxs[fn] = context.memfilectx(fn, mergedtext)
1386 1386
1387 1387 if overwritten_file:
1388 1388 fn = "of"
1389 1389 files.append(fn)
1390 1390 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1391 1391
1392 1392 if new_file:
1393 1393 fn = "nf%i" % id
1394 1394 files.append(fn)
1395 1395 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1396 1396 if len(ps) > 1:
1397 1397 if not p2:
1398 1398 p2 = repo[ps[1]]
1399 1399 for fn in p2:
1400 1400 if fn.startswith("nf"):
1401 1401 files.append(fn)
1402 1402 fctxs[fn] = p2[fn]
1403 1403
1404 1404 def fctxfn(repo, cx, path):
1405 1405 return fctxs.get(path)
1406 1406
1407 1407 if len(ps) == 0 or ps[0] < 0:
1408 1408 pars = [None, None]
1409 1409 elif len(ps) == 1:
1410 1410 pars = [nodeids[ps[0]], None]
1411 1411 else:
1412 1412 pars = [nodeids[p] for p in ps]
1413 1413 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1414 1414 date=(id, 0),
1415 1415 user="debugbuilddag",
1416 1416 extra={'branch': atbranch})
1417 1417 nodeid = repo.commitctx(cx)
1418 1418 nodeids.append(nodeid)
1419 1419 at = id
1420 1420 elif type == 'l':
1421 1421 id, name = data
1422 1422 ui.note('tag %s\n' % name)
1423 1423 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1424 1424 elif type == 'a':
1425 1425 ui.note('branch %s\n' % data)
1426 1426 atbranch = data
1427 1427 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1428 1428 tr.close()
1429 1429 finally:
1430 1430 ui.progress(_('building'), None)
1431 1431 tr.release()
1432 1432
1433 1433 if tags:
1434 1434 repo.opener.write("localtags", "".join(tags))
1435 1435
1436 1436 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1437 1437 def debugbundle(ui, bundlepath, all=None, **opts):
1438 1438 """lists the contents of a bundle"""
1439 1439 f = url.open(ui, bundlepath)
1440 1440 try:
1441 1441 gen = changegroup.readbundle(f, bundlepath)
1442 1442 if all:
1443 1443 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1444 1444
1445 1445 def showchunks(named):
1446 1446 ui.write("\n%s\n" % named)
1447 1447 chain = None
1448 1448 while True:
1449 1449 chunkdata = gen.deltachunk(chain)
1450 1450 if not chunkdata:
1451 1451 break
1452 1452 node = chunkdata['node']
1453 1453 p1 = chunkdata['p1']
1454 1454 p2 = chunkdata['p2']
1455 1455 cs = chunkdata['cs']
1456 1456 deltabase = chunkdata['deltabase']
1457 1457 delta = chunkdata['delta']
1458 1458 ui.write("%s %s %s %s %s %s\n" %
1459 1459 (hex(node), hex(p1), hex(p2),
1460 1460 hex(cs), hex(deltabase), len(delta)))
1461 1461 chain = node
1462 1462
1463 1463 chunkdata = gen.changelogheader()
1464 1464 showchunks("changelog")
1465 1465 chunkdata = gen.manifestheader()
1466 1466 showchunks("manifest")
1467 1467 while True:
1468 1468 chunkdata = gen.filelogheader()
1469 1469 if not chunkdata:
1470 1470 break
1471 1471 fname = chunkdata['filename']
1472 1472 showchunks(fname)
1473 1473 else:
1474 1474 chunkdata = gen.changelogheader()
1475 1475 chain = None
1476 1476 while True:
1477 1477 chunkdata = gen.deltachunk(chain)
1478 1478 if not chunkdata:
1479 1479 break
1480 1480 node = chunkdata['node']
1481 1481 ui.write("%s\n" % hex(node))
1482 1482 chain = node
1483 1483 finally:
1484 1484 f.close()
1485 1485
1486 1486 @command('debugcheckstate', [], '')
1487 1487 def debugcheckstate(ui, repo):
1488 1488 """validate the correctness of the current dirstate"""
1489 1489 parent1, parent2 = repo.dirstate.parents()
1490 1490 m1 = repo[parent1].manifest()
1491 1491 m2 = repo[parent2].manifest()
1492 1492 errors = 0
1493 1493 for f in repo.dirstate:
1494 1494 state = repo.dirstate[f]
1495 1495 if state in "nr" and f not in m1:
1496 1496 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1497 1497 errors += 1
1498 1498 if state in "a" and f in m1:
1499 1499 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1500 1500 errors += 1
1501 1501 if state in "m" and f not in m1 and f not in m2:
1502 1502 ui.warn(_("%s in state %s, but not in either manifest\n") %
1503 1503 (f, state))
1504 1504 errors += 1
1505 1505 for f in m1:
1506 1506 state = repo.dirstate[f]
1507 1507 if state not in "nrm":
1508 1508 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1509 1509 errors += 1
1510 1510 if errors:
1511 1511 error = _(".hg/dirstate inconsistent with current parent's manifest")
1512 1512 raise util.Abort(error)
1513 1513
1514 1514 @command('debugcommands', [], _('[COMMAND]'))
1515 1515 def debugcommands(ui, cmd='', *args):
1516 1516 """list all available commands and options"""
1517 1517 for cmd, vals in sorted(table.iteritems()):
1518 1518 cmd = cmd.split('|')[0].strip('^')
1519 1519 opts = ', '.join([i[1] for i in vals[1]])
1520 1520 ui.write('%s: %s\n' % (cmd, opts))
1521 1521
1522 1522 @command('debugcomplete',
1523 1523 [('o', 'options', None, _('show the command options'))],
1524 1524 _('[-o] CMD'))
1525 1525 def debugcomplete(ui, cmd='', **opts):
1526 1526 """returns the completion list associated with the given command"""
1527 1527
1528 1528 if opts.get('options'):
1529 1529 options = []
1530 1530 otables = [globalopts]
1531 1531 if cmd:
1532 1532 aliases, entry = cmdutil.findcmd(cmd, table, False)
1533 1533 otables.append(entry[1])
1534 1534 for t in otables:
1535 1535 for o in t:
1536 1536 if "(DEPRECATED)" in o[3]:
1537 1537 continue
1538 1538 if o[0]:
1539 1539 options.append('-%s' % o[0])
1540 1540 options.append('--%s' % o[1])
1541 1541 ui.write("%s\n" % "\n".join(options))
1542 1542 return
1543 1543
1544 1544 cmdlist = cmdutil.findpossible(cmd, table)
1545 1545 if ui.verbose:
1546 1546 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1547 1547 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1548 1548
1549 1549 @command('debugdag',
1550 1550 [('t', 'tags', None, _('use tags as labels')),
1551 1551 ('b', 'branches', None, _('annotate with branch names')),
1552 1552 ('', 'dots', None, _('use dots for runs')),
1553 1553 ('s', 'spaces', None, _('separate elements by spaces'))],
1554 1554 _('[OPTION]... [FILE [REV]...]'))
1555 1555 def debugdag(ui, repo, file_=None, *revs, **opts):
1556 1556 """format the changelog or an index DAG as a concise textual description
1557 1557
1558 1558 If you pass a revlog index, the revlog's DAG is emitted. If you list
1559 1559 revision numbers, they get labelled in the output as rN.
1560 1560
1561 1561 Otherwise, the changelog DAG of the current repo is emitted.
1562 1562 """
1563 1563 spaces = opts.get('spaces')
1564 1564 dots = opts.get('dots')
1565 1565 if file_:
1566 1566 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1567 1567 revs = set((int(r) for r in revs))
1568 1568 def events():
1569 1569 for r in rlog:
1570 1570 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1571 1571 if r in revs:
1572 1572 yield 'l', (r, "r%i" % r)
1573 1573 elif repo:
1574 1574 cl = repo.changelog
1575 1575 tags = opts.get('tags')
1576 1576 branches = opts.get('branches')
1577 1577 if tags:
1578 1578 labels = {}
1579 1579 for l, n in repo.tags().items():
1580 1580 labels.setdefault(cl.rev(n), []).append(l)
1581 1581 def events():
1582 1582 b = "default"
1583 1583 for r in cl:
1584 1584 if branches:
1585 1585 newb = cl.read(cl.node(r))[5]['branch']
1586 1586 if newb != b:
1587 1587 yield 'a', newb
1588 1588 b = newb
1589 1589 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1590 1590 if tags:
1591 1591 ls = labels.get(r)
1592 1592 if ls:
1593 1593 for l in ls:
1594 1594 yield 'l', (r, l)
1595 1595 else:
1596 1596 raise util.Abort(_('need repo for changelog dag'))
1597 1597
1598 1598 for line in dagparser.dagtextlines(events(),
1599 1599 addspaces=spaces,
1600 1600 wraplabels=True,
1601 1601 wrapannotations=True,
1602 1602 wrapnonlinear=dots,
1603 1603 usedots=dots,
1604 1604 maxlinewidth=70):
1605 1605 ui.write(line)
1606 1606 ui.write("\n")
1607 1607
1608 1608 @command('debugdata',
1609 1609 [('c', 'changelog', False, _('open changelog')),
1610 1610 ('m', 'manifest', False, _('open manifest'))],
1611 1611 _('-c|-m|FILE REV'))
1612 1612 def debugdata(ui, repo, file_, rev = None, **opts):
1613 1613 """dump the contents of a data file revision"""
1614 1614 if opts.get('changelog') or opts.get('manifest'):
1615 1615 file_, rev = None, file_
1616 1616 elif rev is None:
1617 1617 raise error.CommandError('debugdata', _('invalid arguments'))
1618 1618 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1619 1619 try:
1620 1620 ui.write(r.revision(r.lookup(rev)))
1621 1621 except KeyError:
1622 1622 raise util.Abort(_('invalid revision identifier %s') % rev)
1623 1623
1624 1624 @command('debugdate',
1625 1625 [('e', 'extended', None, _('try extended date formats'))],
1626 1626 _('[-e] DATE [RANGE]'))
1627 1627 def debugdate(ui, date, range=None, **opts):
1628 1628 """parse and display a date"""
1629 1629 if opts["extended"]:
1630 1630 d = util.parsedate(date, util.extendeddateformats)
1631 1631 else:
1632 1632 d = util.parsedate(date)
1633 1633 ui.write("internal: %s %s\n" % d)
1634 1634 ui.write("standard: %s\n" % util.datestr(d))
1635 1635 if range:
1636 1636 m = util.matchdate(range)
1637 1637 ui.write("match: %s\n" % m(d[0]))
1638 1638
1639 1639 @command('debugdiscovery',
1640 1640 [('', 'old', None, _('use old-style discovery')),
1641 1641 ('', 'nonheads', None,
1642 1642 _('use old-style discovery with non-heads included')),
1643 1643 ] + remoteopts,
1644 1644 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1645 1645 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1646 1646 """runs the changeset discovery protocol in isolation"""
1647 1647 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1648 1648 remote = hg.peer(repo, opts, remoteurl)
1649 1649 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1650 1650
1651 1651 # make sure tests are repeatable
1652 1652 random.seed(12323)
1653 1653
1654 1654 def doit(localheads, remoteheads):
1655 1655 if opts.get('old'):
1656 1656 if localheads:
1657 1657 raise util.Abort('cannot use localheads with old style discovery')
1658 1658 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1659 1659 force=True)
1660 1660 common = set(common)
1661 1661 if not opts.get('nonheads'):
1662 1662 ui.write("unpruned common: %s\n" % " ".join([short(n)
1663 1663 for n in common]))
1664 1664 dag = dagutil.revlogdag(repo.changelog)
1665 1665 all = dag.ancestorset(dag.internalizeall(common))
1666 1666 common = dag.externalizeall(dag.headsetofconnecteds(all))
1667 1667 else:
1668 1668 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1669 1669 common = set(common)
1670 1670 rheads = set(hds)
1671 1671 lheads = set(repo.heads())
1672 1672 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1673 1673 if lheads <= common:
1674 1674 ui.write("local is subset\n")
1675 1675 elif rheads <= common:
1676 1676 ui.write("remote is subset\n")
1677 1677
1678 1678 serverlogs = opts.get('serverlog')
1679 1679 if serverlogs:
1680 1680 for filename in serverlogs:
1681 1681 logfile = open(filename, 'r')
1682 1682 try:
1683 1683 line = logfile.readline()
1684 1684 while line:
1685 1685 parts = line.strip().split(';')
1686 1686 op = parts[1]
1687 1687 if op == 'cg':
1688 1688 pass
1689 1689 elif op == 'cgss':
1690 1690 doit(parts[2].split(' '), parts[3].split(' '))
1691 1691 elif op == 'unb':
1692 1692 doit(parts[3].split(' '), parts[2].split(' '))
1693 1693 line = logfile.readline()
1694 1694 finally:
1695 1695 logfile.close()
1696 1696
1697 1697 else:
1698 1698 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1699 1699 opts.get('remote_head'))
1700 1700 localrevs = opts.get('local_head')
1701 1701 doit(localrevs, remoterevs)
1702 1702
1703 1703 @command('debugfileset', [], ('REVSPEC'))
1704 1704 def debugfileset(ui, repo, expr):
1705 1705 '''parse and apply a fileset specification'''
1706 1706 if ui.verbose:
1707 1707 tree = fileset.parse(expr)[0]
1708 1708 ui.note(tree, "\n")
1709 1709
1710 1710 for f in fileset.getfileset(repo[None], expr):
1711 1711 ui.write("%s\n" % f)
1712 1712
1713 1713 @command('debugfsinfo', [], _('[PATH]'))
1714 1714 def debugfsinfo(ui, path = "."):
1715 1715 """show information detected about current filesystem"""
1716 1716 util.writefile('.debugfsinfo', '')
1717 1717 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1718 1718 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1719 1719 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1720 1720 and 'yes' or 'no'))
1721 1721 os.unlink('.debugfsinfo')
1722 1722
1723 1723 @command('debuggetbundle',
1724 1724 [('H', 'head', [], _('id of head node'), _('ID')),
1725 1725 ('C', 'common', [], _('id of common node'), _('ID')),
1726 1726 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1727 1727 _('REPO FILE [-H|-C ID]...'))
1728 1728 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1729 1729 """retrieves a bundle from a repo
1730 1730
1731 1731 Every ID must be a full-length hex node id string. Saves the bundle to the
1732 1732 given file.
1733 1733 """
1734 1734 repo = hg.peer(ui, opts, repopath)
1735 1735 if not repo.capable('getbundle'):
1736 1736 raise util.Abort("getbundle() not supported by target repository")
1737 1737 args = {}
1738 1738 if common:
1739 1739 args['common'] = [bin(s) for s in common]
1740 1740 if head:
1741 1741 args['heads'] = [bin(s) for s in head]
1742 1742 bundle = repo.getbundle('debug', **args)
1743 1743
1744 1744 bundletype = opts.get('type', 'bzip2').lower()
1745 1745 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1746 1746 bundletype = btypes.get(bundletype)
1747 1747 if bundletype not in changegroup.bundletypes:
1748 1748 raise util.Abort(_('unknown bundle type specified with --type'))
1749 1749 changegroup.writebundle(bundle, bundlepath, bundletype)
1750 1750
1751 1751 @command('debugignore', [], '')
1752 1752 def debugignore(ui, repo, *values, **opts):
1753 1753 """display the combined ignore pattern"""
1754 1754 ignore = repo.dirstate._ignore
1755 1755 includepat = getattr(ignore, 'includepat', None)
1756 1756 if includepat is not None:
1757 1757 ui.write("%s\n" % includepat)
1758 1758 else:
1759 1759 raise util.Abort(_("no ignore patterns found"))
1760 1760
1761 1761 @command('debugindex',
1762 1762 [('c', 'changelog', False, _('open changelog')),
1763 1763 ('m', 'manifest', False, _('open manifest')),
1764 1764 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1765 1765 _('[-f FORMAT] -c|-m|FILE'))
1766 1766 def debugindex(ui, repo, file_ = None, **opts):
1767 1767 """dump the contents of an index file"""
1768 1768 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1769 1769 format = opts.get('format', 0)
1770 1770 if format not in (0, 1):
1771 1771 raise util.Abort(_("unknown format %d") % format)
1772 1772
1773 1773 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1774 1774 if generaldelta:
1775 1775 basehdr = ' delta'
1776 1776 else:
1777 1777 basehdr = ' base'
1778 1778
1779 1779 if format == 0:
1780 1780 ui.write(" rev offset length " + basehdr + " linkrev"
1781 1781 " nodeid p1 p2\n")
1782 1782 elif format == 1:
1783 1783 ui.write(" rev flag offset length"
1784 1784 " size " + basehdr + " link p1 p2 nodeid\n")
1785 1785
1786 1786 for i in r:
1787 1787 node = r.node(i)
1788 1788 if generaldelta:
1789 1789 base = r.deltaparent(i)
1790 1790 else:
1791 1791 base = r.chainbase(i)
1792 1792 if format == 0:
1793 1793 try:
1794 1794 pp = r.parents(node)
1795 1795 except:
1796 1796 pp = [nullid, nullid]
1797 1797 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1798 1798 i, r.start(i), r.length(i), base, r.linkrev(i),
1799 1799 short(node), short(pp[0]), short(pp[1])))
1800 1800 elif format == 1:
1801 1801 pr = r.parentrevs(i)
1802 1802 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1803 1803 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1804 1804 base, r.linkrev(i), pr[0], pr[1], short(node)))
1805 1805
1806 1806 @command('debugindexdot', [], _('FILE'))
1807 1807 def debugindexdot(ui, repo, file_):
1808 1808 """dump an index DAG as a graphviz dot file"""
1809 1809 r = None
1810 1810 if repo:
1811 1811 filelog = repo.file(file_)
1812 1812 if len(filelog):
1813 1813 r = filelog
1814 1814 if not r:
1815 1815 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1816 1816 ui.write("digraph G {\n")
1817 1817 for i in r:
1818 1818 node = r.node(i)
1819 1819 pp = r.parents(node)
1820 1820 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1821 1821 if pp[1] != nullid:
1822 1822 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1823 1823 ui.write("}\n")
1824 1824
1825 1825 @command('debuginstall', [], '')
1826 1826 def debuginstall(ui):
1827 1827 '''test Mercurial installation
1828 1828
1829 1829 Returns 0 on success.
1830 1830 '''
1831 1831
1832 1832 def writetemp(contents):
1833 1833 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1834 1834 f = os.fdopen(fd, "wb")
1835 1835 f.write(contents)
1836 1836 f.close()
1837 1837 return name
1838 1838
1839 1839 problems = 0
1840 1840
1841 1841 # encoding
1842 1842 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1843 1843 try:
1844 1844 encoding.fromlocal("test")
1845 1845 except util.Abort, inst:
1846 1846 ui.write(" %s\n" % inst)
1847 1847 ui.write(_(" (check that your locale is properly set)\n"))
1848 1848 problems += 1
1849 1849
1850 1850 # compiled modules
1851 1851 ui.status(_("Checking installed modules (%s)...\n")
1852 1852 % os.path.dirname(__file__))
1853 1853 try:
1854 1854 import bdiff, mpatch, base85, osutil
1855 1855 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1856 1856 except Exception, inst:
1857 1857 ui.write(" %s\n" % inst)
1858 1858 ui.write(_(" One or more extensions could not be found"))
1859 1859 ui.write(_(" (check that you compiled the extensions)\n"))
1860 1860 problems += 1
1861 1861
1862 1862 # templates
1863 1863 import templater
1864 1864 p = templater.templatepath()
1865 1865 ui.status(_("Checking templates (%s)...\n") % ' '.join(p))
1866 1866 try:
1867 1867 templater.templater(templater.templatepath("map-cmdline.default"))
1868 1868 except Exception, inst:
1869 1869 ui.write(" %s\n" % inst)
1870 1870 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1871 1871 problems += 1
1872 1872
1873 1873 # editor
1874 1874 ui.status(_("Checking commit editor...\n"))
1875 1875 editor = ui.geteditor()
1876 1876 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1877 1877 if not cmdpath:
1878 1878 if editor == 'vi':
1879 1879 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1880 1880 ui.write(_(" (specify a commit editor in your configuration"
1881 1881 " file)\n"))
1882 1882 else:
1883 1883 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1884 1884 ui.write(_(" (specify a commit editor in your configuration"
1885 1885 " file)\n"))
1886 1886 problems += 1
1887 1887
1888 1888 # check username
1889 1889 ui.status(_("Checking username...\n"))
1890 1890 try:
1891 1891 ui.username()
1892 1892 except util.Abort, e:
1893 1893 ui.write(" %s\n" % e)
1894 1894 ui.write(_(" (specify a username in your configuration file)\n"))
1895 1895 problems += 1
1896 1896
1897 1897 if not problems:
1898 1898 ui.status(_("No problems detected\n"))
1899 1899 else:
1900 1900 ui.write(_("%s problems detected,"
1901 1901 " please check your install!\n") % problems)
1902 1902
1903 1903 return problems
1904 1904
1905 1905 @command('debugknown', [], _('REPO ID...'))
1906 1906 def debugknown(ui, repopath, *ids, **opts):
1907 1907 """test whether node ids are known to a repo
1908 1908
1909 1909 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1910 1910 indicating unknown/known.
1911 1911 """
1912 1912 repo = hg.peer(ui, opts, repopath)
1913 1913 if not repo.capable('known'):
1914 1914 raise util.Abort("known() not supported by target repository")
1915 1915 flags = repo.known([bin(s) for s in ids])
1916 1916 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1917 1917
1918 1918 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1919 1919 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1920 1920 '''access the pushkey key/value protocol
1921 1921
1922 1922 With two args, list the keys in the given namespace.
1923 1923
1924 1924 With five args, set a key to new if it currently is set to old.
1925 1925 Reports success or failure.
1926 1926 '''
1927 1927
1928 1928 target = hg.peer(ui, {}, repopath)
1929 1929 if keyinfo:
1930 1930 key, old, new = keyinfo
1931 1931 r = target.pushkey(namespace, key, old, new)
1932 1932 ui.status(str(r) + '\n')
1933 1933 return not r
1934 1934 else:
1935 1935 for k, v in target.listkeys(namespace).iteritems():
1936 1936 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1937 1937 v.encode('string-escape')))
1938 1938
1939 1939 @command('debugrebuildstate',
1940 1940 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1941 1941 _('[-r REV] [REV]'))
1942 1942 def debugrebuildstate(ui, repo, rev="tip"):
1943 1943 """rebuild the dirstate as it would look like for the given revision"""
1944 1944 ctx = scmutil.revsingle(repo, rev)
1945 1945 wlock = repo.wlock()
1946 1946 try:
1947 1947 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1948 1948 finally:
1949 1949 wlock.release()
1950 1950
1951 1951 @command('debugrename',
1952 1952 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1953 1953 _('[-r REV] FILE'))
1954 1954 def debugrename(ui, repo, file1, *pats, **opts):
1955 1955 """dump rename information"""
1956 1956
1957 1957 ctx = scmutil.revsingle(repo, opts.get('rev'))
1958 1958 m = scmutil.match(ctx, (file1,) + pats, opts)
1959 1959 for abs in ctx.walk(m):
1960 1960 fctx = ctx[abs]
1961 1961 o = fctx.filelog().renamed(fctx.filenode())
1962 1962 rel = m.rel(abs)
1963 1963 if o:
1964 1964 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1965 1965 else:
1966 1966 ui.write(_("%s not renamed\n") % rel)
1967 1967
1968 1968 @command('debugrevlog',
1969 1969 [('c', 'changelog', False, _('open changelog')),
1970 1970 ('m', 'manifest', False, _('open manifest')),
1971 1971 ('d', 'dump', False, _('dump index data'))],
1972 1972 _('-c|-m|FILE'))
1973 1973 def debugrevlog(ui, repo, file_ = None, **opts):
1974 1974 """show data and statistics about a revlog"""
1975 1975 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1976 1976
1977 1977 if opts.get("dump"):
1978 1978 numrevs = len(r)
1979 1979 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1980 1980 " rawsize totalsize compression heads\n")
1981 1981 ts = 0
1982 1982 heads = set()
1983 1983 for rev in xrange(numrevs):
1984 1984 dbase = r.deltaparent(rev)
1985 1985 if dbase == -1:
1986 1986 dbase = rev
1987 1987 cbase = r.chainbase(rev)
1988 1988 p1, p2 = r.parentrevs(rev)
1989 1989 rs = r.rawsize(rev)
1990 1990 ts = ts + rs
1991 1991 heads -= set(r.parentrevs(rev))
1992 1992 heads.add(rev)
1993 1993 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1994 1994 (rev, p1, p2, r.start(rev), r.end(rev),
1995 1995 r.start(dbase), r.start(cbase),
1996 1996 r.start(p1), r.start(p2),
1997 1997 rs, ts, ts / r.end(rev), len(heads)))
1998 1998 return 0
1999 1999
2000 2000 v = r.version
2001 2001 format = v & 0xFFFF
2002 2002 flags = []
2003 2003 gdelta = False
2004 2004 if v & revlog.REVLOGNGINLINEDATA:
2005 2005 flags.append('inline')
2006 2006 if v & revlog.REVLOGGENERALDELTA:
2007 2007 gdelta = True
2008 2008 flags.append('generaldelta')
2009 2009 if not flags:
2010 2010 flags = ['(none)']
2011 2011
2012 2012 nummerges = 0
2013 2013 numfull = 0
2014 2014 numprev = 0
2015 2015 nump1 = 0
2016 2016 nump2 = 0
2017 2017 numother = 0
2018 2018 nump1prev = 0
2019 2019 nump2prev = 0
2020 2020 chainlengths = []
2021 2021
2022 2022 datasize = [None, 0, 0L]
2023 2023 fullsize = [None, 0, 0L]
2024 2024 deltasize = [None, 0, 0L]
2025 2025
2026 2026 def addsize(size, l):
2027 2027 if l[0] is None or size < l[0]:
2028 2028 l[0] = size
2029 2029 if size > l[1]:
2030 2030 l[1] = size
2031 2031 l[2] += size
2032 2032
2033 2033 numrevs = len(r)
2034 2034 for rev in xrange(numrevs):
2035 2035 p1, p2 = r.parentrevs(rev)
2036 2036 delta = r.deltaparent(rev)
2037 2037 if format > 0:
2038 2038 addsize(r.rawsize(rev), datasize)
2039 2039 if p2 != nullrev:
2040 2040 nummerges += 1
2041 2041 size = r.length(rev)
2042 2042 if delta == nullrev:
2043 2043 chainlengths.append(0)
2044 2044 numfull += 1
2045 2045 addsize(size, fullsize)
2046 2046 else:
2047 2047 chainlengths.append(chainlengths[delta] + 1)
2048 2048 addsize(size, deltasize)
2049 2049 if delta == rev - 1:
2050 2050 numprev += 1
2051 2051 if delta == p1:
2052 2052 nump1prev += 1
2053 2053 elif delta == p2:
2054 2054 nump2prev += 1
2055 2055 elif delta == p1:
2056 2056 nump1 += 1
2057 2057 elif delta == p2:
2058 2058 nump2 += 1
2059 2059 elif delta != nullrev:
2060 2060 numother += 1
2061 2061
2062 2062 numdeltas = numrevs - numfull
2063 2063 numoprev = numprev - nump1prev - nump2prev
2064 2064 totalrawsize = datasize[2]
2065 2065 datasize[2] /= numrevs
2066 2066 fulltotal = fullsize[2]
2067 2067 fullsize[2] /= numfull
2068 2068 deltatotal = deltasize[2]
2069 2069 deltasize[2] /= numrevs - numfull
2070 2070 totalsize = fulltotal + deltatotal
2071 2071 avgchainlen = sum(chainlengths) / numrevs
2072 2072 compratio = totalrawsize / totalsize
2073 2073
2074 2074 basedfmtstr = '%%%dd\n'
2075 2075 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2076 2076
2077 2077 def dfmtstr(max):
2078 2078 return basedfmtstr % len(str(max))
2079 2079 def pcfmtstr(max, padding=0):
2080 2080 return basepcfmtstr % (len(str(max)), ' ' * padding)
2081 2081
2082 2082 def pcfmt(value, total):
2083 2083 return (value, 100 * float(value) / total)
2084 2084
2085 2085 ui.write('format : %d\n' % format)
2086 2086 ui.write('flags : %s\n' % ', '.join(flags))
2087 2087
2088 2088 ui.write('\n')
2089 2089 fmt = pcfmtstr(totalsize)
2090 2090 fmt2 = dfmtstr(totalsize)
2091 2091 ui.write('revisions : ' + fmt2 % numrevs)
2092 2092 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2093 2093 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2094 2094 ui.write('revisions : ' + fmt2 % numrevs)
2095 2095 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2096 2096 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2097 2097 ui.write('revision size : ' + fmt2 % totalsize)
2098 2098 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2099 2099 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2100 2100
2101 2101 ui.write('\n')
2102 2102 fmt = dfmtstr(max(avgchainlen, compratio))
2103 2103 ui.write('avg chain length : ' + fmt % avgchainlen)
2104 2104 ui.write('compression ratio : ' + fmt % compratio)
2105 2105
2106 2106 if format > 0:
2107 2107 ui.write('\n')
2108 2108 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2109 2109 % tuple(datasize))
2110 2110 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2111 2111 % tuple(fullsize))
2112 2112 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2113 2113 % tuple(deltasize))
2114 2114
2115 2115 if numdeltas > 0:
2116 2116 ui.write('\n')
2117 2117 fmt = pcfmtstr(numdeltas)
2118 2118 fmt2 = pcfmtstr(numdeltas, 4)
2119 2119 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2120 2120 if numprev > 0:
2121 2121 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2122 2122 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2123 2123 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2124 2124 if gdelta:
2125 2125 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2126 2126 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2127 2127 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2128 2128
2129 2129 @command('debugrevspec', [], ('REVSPEC'))
2130 2130 def debugrevspec(ui, repo, expr):
2131 2131 '''parse and apply a revision specification'''
2132 2132 if ui.verbose:
2133 2133 tree = revset.parse(expr)[0]
2134 2134 ui.note(tree, "\n")
2135 2135 newtree = revset.findaliases(ui, tree)
2136 2136 if newtree != tree:
2137 2137 ui.note(newtree, "\n")
2138 2138 func = revset.match(ui, expr)
2139 2139 for c in func(repo, range(len(repo))):
2140 2140 ui.write("%s\n" % c)
2141 2141
2142 2142 @command('debugsetparents', [], _('REV1 [REV2]'))
2143 2143 def debugsetparents(ui, repo, rev1, rev2=None):
2144 2144 """manually set the parents of the current working directory
2145 2145
2146 2146 This is useful for writing repository conversion tools, but should
2147 2147 be used with care.
2148 2148
2149 2149 Returns 0 on success.
2150 2150 """
2151 2151
2152 2152 r1 = scmutil.revsingle(repo, rev1).node()
2153 2153 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2154 2154
2155 2155 wlock = repo.wlock()
2156 2156 try:
2157 2157 repo.dirstate.setparents(r1, r2)
2158 2158 finally:
2159 2159 wlock.release()
2160 2160
2161 2161 @command('debugstate',
2162 2162 [('', 'nodates', None, _('do not display the saved mtime')),
2163 2163 ('', 'datesort', None, _('sort by saved mtime'))],
2164 2164 _('[OPTION]...'))
2165 2165 def debugstate(ui, repo, nodates=None, datesort=None):
2166 2166 """show the contents of the current dirstate"""
2167 2167 timestr = ""
2168 2168 showdate = not nodates
2169 2169 if datesort:
2170 2170 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2171 2171 else:
2172 2172 keyfunc = None # sort by filename
2173 2173 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2174 2174 if showdate:
2175 2175 if ent[3] == -1:
2176 2176 # Pad or slice to locale representation
2177 2177 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2178 2178 time.localtime(0)))
2179 2179 timestr = 'unset'
2180 2180 timestr = (timestr[:locale_len] +
2181 2181 ' ' * (locale_len - len(timestr)))
2182 2182 else:
2183 2183 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2184 2184 time.localtime(ent[3]))
2185 2185 if ent[1] & 020000:
2186 2186 mode = 'lnk'
2187 2187 else:
2188 2188 mode = '%3o' % (ent[1] & 0777)
2189 2189 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2190 2190 for f in repo.dirstate.copies():
2191 2191 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2192 2192
2193 2193 @command('debugsub',
2194 2194 [('r', 'rev', '',
2195 2195 _('revision to check'), _('REV'))],
2196 2196 _('[-r REV] [REV]'))
2197 2197 def debugsub(ui, repo, rev=None):
2198 2198 ctx = scmutil.revsingle(repo, rev, None)
2199 2199 for k, v in sorted(ctx.substate.items()):
2200 2200 ui.write('path %s\n' % k)
2201 2201 ui.write(' source %s\n' % v[0])
2202 2202 ui.write(' revision %s\n' % v[1])
2203 2203
2204 2204 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2205 2205 def debugwalk(ui, repo, *pats, **opts):
2206 2206 """show how files match on given patterns"""
2207 2207 m = scmutil.match(repo[None], pats, opts)
2208 2208 items = list(repo.walk(m))
2209 2209 if not items:
2210 2210 return
2211 2211 fmt = 'f %%-%ds %%-%ds %%s' % (
2212 2212 max([len(abs) for abs in items]),
2213 2213 max([len(m.rel(abs)) for abs in items]))
2214 2214 for abs in items:
2215 2215 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2216 2216 ui.write("%s\n" % line.rstrip())
2217 2217
2218 2218 @command('debugwireargs',
2219 2219 [('', 'three', '', 'three'),
2220 2220 ('', 'four', '', 'four'),
2221 2221 ('', 'five', '', 'five'),
2222 2222 ] + remoteopts,
2223 2223 _('REPO [OPTIONS]... [ONE [TWO]]'))
2224 2224 def debugwireargs(ui, repopath, *vals, **opts):
2225 2225 repo = hg.peer(ui, opts, repopath)
2226 2226 for opt in remoteopts:
2227 2227 del opts[opt[1]]
2228 2228 args = {}
2229 2229 for k, v in opts.iteritems():
2230 2230 if v:
2231 2231 args[k] = v
2232 2232 # run twice to check that we don't mess up the stream for the next command
2233 2233 res1 = repo.debugwireargs(*vals, **args)
2234 2234 res2 = repo.debugwireargs(*vals, **args)
2235 2235 ui.write("%s\n" % res1)
2236 2236 if res1 != res2:
2237 2237 ui.warn("%s\n" % res2)
2238 2238
2239 2239 @command('^diff',
2240 2240 [('r', 'rev', [], _('revision'), _('REV')),
2241 2241 ('c', 'change', '', _('change made by revision'), _('REV'))
2242 2242 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2243 2243 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2244 2244 def diff(ui, repo, *pats, **opts):
2245 2245 """diff repository (or selected files)
2246 2246
2247 2247 Show differences between revisions for the specified files.
2248 2248
2249 2249 Differences between files are shown using the unified diff format.
2250 2250
2251 2251 .. note::
2252 2252 diff may generate unexpected results for merges, as it will
2253 2253 default to comparing against the working directory's first
2254 2254 parent changeset if no revisions are specified.
2255 2255
2256 2256 When two revision arguments are given, then changes are shown
2257 2257 between those revisions. If only one revision is specified then
2258 2258 that revision is compared to the working directory, and, when no
2259 2259 revisions are specified, the working directory files are compared
2260 2260 to its parent.
2261 2261
2262 2262 Alternatively you can specify -c/--change with a revision to see
2263 2263 the changes in that changeset relative to its first parent.
2264 2264
2265 2265 Without the -a/--text option, diff will avoid generating diffs of
2266 2266 files it detects as binary. With -a, diff will generate a diff
2267 2267 anyway, probably with undesirable results.
2268 2268
2269 2269 Use the -g/--git option to generate diffs in the git extended diff
2270 2270 format. For more information, read :hg:`help diffs`.
2271 2271
2272 2272 .. container:: verbose
2273 2273
2274 2274 Examples:
2275 2275
2276 2276 - compare a file in the current working directory to its parent::
2277 2277
2278 2278 hg diff foo.c
2279 2279
2280 2280 - compare two historical versions of a directory, with rename info::
2281 2281
2282 2282 hg diff --git -r 1.0:1.2 lib/
2283 2283
2284 2284 - get change stats relative to the last change on some date::
2285 2285
2286 2286 hg diff --stat -r "date('may 2')"
2287 2287
2288 2288 - diff all newly-added files that contain a keyword::
2289 2289
2290 2290 hg diff "set:added() and grep(GNU)"
2291 2291
2292 2292 - compare a revision and its parents::
2293 2293
2294 2294 hg diff -c 9353 # compare against first parent
2295 2295 hg diff -r 9353^:9353 # same using revset syntax
2296 2296 hg diff -r 9353^2:9353 # compare against the second parent
2297 2297
2298 2298 Returns 0 on success.
2299 2299 """
2300 2300
2301 2301 revs = opts.get('rev')
2302 2302 change = opts.get('change')
2303 2303 stat = opts.get('stat')
2304 2304 reverse = opts.get('reverse')
2305 2305
2306 2306 if revs and change:
2307 2307 msg = _('cannot specify --rev and --change at the same time')
2308 2308 raise util.Abort(msg)
2309 2309 elif change:
2310 2310 node2 = scmutil.revsingle(repo, change, None).node()
2311 2311 node1 = repo[node2].p1().node()
2312 2312 else:
2313 2313 node1, node2 = scmutil.revpair(repo, revs)
2314 2314
2315 2315 if reverse:
2316 2316 node1, node2 = node2, node1
2317 2317
2318 2318 diffopts = patch.diffopts(ui, opts)
2319 2319 m = scmutil.match(repo[node2], pats, opts)
2320 2320 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2321 2321 listsubrepos=opts.get('subrepos'))
2322 2322
2323 2323 @command('^export',
2324 2324 [('o', 'output', '',
2325 2325 _('print output to file with formatted name'), _('FORMAT')),
2326 2326 ('', 'switch-parent', None, _('diff against the second parent')),
2327 2327 ('r', 'rev', [], _('revisions to export'), _('REV')),
2328 2328 ] + diffopts,
2329 2329 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2330 2330 def export(ui, repo, *changesets, **opts):
2331 2331 """dump the header and diffs for one or more changesets
2332 2332
2333 2333 Print the changeset header and diffs for one or more revisions.
2334 2334
2335 2335 The information shown in the changeset header is: author, date,
2336 2336 branch name (if non-default), changeset hash, parent(s) and commit
2337 2337 comment.
2338 2338
2339 2339 .. note::
2340 2340 export may generate unexpected diff output for merge
2341 2341 changesets, as it will compare the merge changeset against its
2342 2342 first parent only.
2343 2343
2344 2344 Output may be to a file, in which case the name of the file is
2345 2345 given using a format string. The formatting rules are as follows:
2346 2346
2347 2347 :``%%``: literal "%" character
2348 2348 :``%H``: changeset hash (40 hexadecimal digits)
2349 2349 :``%N``: number of patches being generated
2350 2350 :``%R``: changeset revision number
2351 2351 :``%b``: basename of the exporting repository
2352 2352 :``%h``: short-form changeset hash (12 hexadecimal digits)
2353 2353 :``%m``: first line of the commit message (only alphanumeric characters)
2354 2354 :``%n``: zero-padded sequence number, starting at 1
2355 2355 :``%r``: zero-padded changeset revision number
2356 2356
2357 2357 Without the -a/--text option, export will avoid generating diffs
2358 2358 of files it detects as binary. With -a, export will generate a
2359 2359 diff anyway, probably with undesirable results.
2360 2360
2361 2361 Use the -g/--git option to generate diffs in the git extended diff
2362 2362 format. See :hg:`help diffs` for more information.
2363 2363
2364 2364 With the --switch-parent option, the diff will be against the
2365 2365 second parent. It can be useful to review a merge.
2366 2366
2367 2367 .. container:: verbose
2368 2368
2369 2369 Examples:
2370 2370
2371 2371 - use export and import to transplant a bugfix to the current
2372 2372 branch::
2373 2373
2374 2374 hg export -r 9353 | hg import -
2375 2375
2376 2376 - export all the changesets between two revisions to a file with
2377 2377 rename information::
2378 2378
2379 2379 hg export --git -r 123:150 > changes.txt
2380 2380
2381 2381 - split outgoing changes into a series of patches with
2382 2382 descriptive names::
2383 2383
2384 2384 hg export -r "outgoing()" -o "%n-%m.patch"
2385 2385
2386 2386 Returns 0 on success.
2387 2387 """
2388 2388 changesets += tuple(opts.get('rev', []))
2389 2389 if not changesets:
2390 2390 raise util.Abort(_("export requires at least one changeset"))
2391 2391 revs = scmutil.revrange(repo, changesets)
2392 2392 if len(revs) > 1:
2393 2393 ui.note(_('exporting patches:\n'))
2394 2394 else:
2395 2395 ui.note(_('exporting patch:\n'))
2396 2396 cmdutil.export(repo, revs, template=opts.get('output'),
2397 2397 switch_parent=opts.get('switch_parent'),
2398 2398 opts=patch.diffopts(ui, opts))
2399 2399
2400 2400 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2401 2401 def forget(ui, repo, *pats, **opts):
2402 2402 """forget the specified files on the next commit
2403 2403
2404 2404 Mark the specified files so they will no longer be tracked
2405 2405 after the next commit.
2406 2406
2407 2407 This only removes files from the current branch, not from the
2408 2408 entire project history, and it does not delete them from the
2409 2409 working directory.
2410 2410
2411 2411 To undo a forget before the next commit, see :hg:`add`.
2412 2412
2413 2413 .. container:: verbose
2414 2414
2415 2415 Examples:
2416 2416
2417 2417 - forget newly-added binary files::
2418 2418
2419 2419 hg forget "set:added() and binary()"
2420 2420
2421 2421 - forget files that would be excluded by .hgignore::
2422 2422
2423 2423 hg forget "set:hgignore()"
2424 2424
2425 2425 Returns 0 on success.
2426 2426 """
2427 2427
2428 2428 if not pats:
2429 2429 raise util.Abort(_('no files specified'))
2430 2430
2431 2431 m = scmutil.match(repo[None], pats, opts)
2432 2432 s = repo.status(match=m, clean=True)
2433 2433 forget = sorted(s[0] + s[1] + s[3] + s[6])
2434 2434 errs = 0
2435 2435
2436 2436 for f in m.files():
2437 2437 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2438 2438 if os.path.exists(m.rel(f)):
2439 2439 ui.warn(_('not removing %s: file is already untracked\n')
2440 2440 % m.rel(f))
2441 2441 errs = 1
2442 2442
2443 2443 for f in forget:
2444 2444 if ui.verbose or not m.exact(f):
2445 2445 ui.status(_('removing %s\n') % m.rel(f))
2446 2446
2447 2447 repo[None].forget(forget)
2448 2448 return errs
2449 2449
2450 2450 @command(
2451 2451 'graft',
2452 [('e', 'edit', False, _('invoke editor on commit messages')),
2452 [('c', 'continue', False, _('resume interrupted graft')),
2453 ('e', 'edit', False, _('invoke editor on commit messages')),
2453 2454 ('D', 'currentdate', False,
2454 2455 _('record the current date as commit date')),
2455 2456 ('U', 'currentuser', False,
2456 2457 _('record the current user as committer'), _('DATE'))]
2457 2458 + commitopts2 + mergetoolopts,
2458 2459 _('[OPTION]... REVISION...'))
2459 def graft(ui, repo, rev, *revs, **opts):
2460 def graft(ui, repo, *revs, **opts):
2460 2461 '''copy changes from other branches onto the current branch
2461 2462
2462 2463 This command uses Mercurial's merge logic to copy individual
2463 2464 changes from other branches without merging branches in the
2464 2465 history graph. This is sometimes known as 'backporting' or
2465 2466 'cherry-picking'.
2466 2467
2467 2468 Changesets that are ancestors of the current revision, that have
2468 2469 already been grafted, or that are merges will be skipped.
2469 2470
2471 If a graft merge results in conflicts, the graft process is
2472 aborted so that the current merge can be manually resolved. Once
2473 all conflicts are addressed, the graft process can be continued
2474 with the -c/--continue option.
2475
2476 .. note::
2477 The -c/--continue option does not reapply earlier options.
2478
2470 2479 Returns 0 on successful completion.
2471 2480 '''
2472 2481
2473 cmdutil.bailifchanged(repo)
2474
2475 2482 if not opts.get('user') and opts.get('currentuser'):
2476 2483 opts['user'] = ui.username()
2477 2484 if not opts.get('date') and opts.get('currentdate'):
2478 2485 opts['date'] = "%d %d" % util.makedate()
2479 2486
2480 2487 editor = None
2481 2488 if opts.get('edit'):
2482 2489 editor = cmdutil.commitforceeditor
2483 2490
2484 revs = [rev] + list(revs)
2491 cont = False
2492 if opts['continue']:
2493 cont = True
2494 if revs:
2495 raise util.Abort(_("can't specify --continue and revisions"))
2496 # read in unfinished revisions
2497 try:
2498 nodes = repo.opener.read('graftstate').splitlines()
2499 revs = [repo[node].rev() for node in nodes]
2500 except IOError, inst:
2501 if inst.errno != errno.ENOENT:
2502 raise
2503 raise util.Abort(_("no graft state found, can't continue"))
2504 else:
2505 cmdutil.bailifchanged(repo)
2506 if not revs:
2507 raise util.Abort(_('no revisions specified'))
2485 2508 revs = scmutil.revrange(repo, revs)
2486 2509
2487 2510 # check for merges
2488 2511 for ctx in repo.set('%ld and merge()', revs):
2489 2512 ui.warn(_('skipping ungraftable merge revision %s\n') % ctx.rev())
2490 2513 revs.remove(ctx.rev())
2491 2514 if not revs:
2492 2515 return -1
2493 2516
2494 2517 # check for ancestors of dest branch
2495 2518 for ctx in repo.set('::. and %ld', revs):
2496 2519 ui.warn(_('skipping ancestor revision %s\n') % ctx.rev())
2497 2520 revs.remove(ctx.rev())
2498 2521 if not revs:
2499 2522 return -1
2500 2523
2501 2524 # check ancestors for earlier grafts
2502 2525 ui.debug('scanning for existing transplants')
2503 2526 for ctx in repo.set("::. - ::%ld", revs):
2504 2527 n = ctx.extra().get('source')
2505 2528 if n and n in repo:
2506 2529 r = repo[n].rev()
2507 2530 ui.warn(_('skipping already grafted revision %s\n') % r)
2508 2531 revs.remove(r)
2509 2532 if not revs:
2510 2533 return -1
2511 2534
2512 for ctx in repo.set("%ld", revs):
2535 for pos, ctx in enumerate(repo.set("%ld", revs)):
2513 2536 current = repo['.']
2514 2537 ui.debug('grafting revision %s', ctx.rev())
2538
2539 # we don't merge the first commit when continuing
2540 if not cont:
2515 2541 # perform the graft merge with p1(rev) as 'ancestor'
2516 2542 try:
2517 2543 # ui.forcemerge is an internal variable, do not document
2518 2544 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2519 2545 stats = mergemod.update(repo, ctx.node(), True, True, False,
2520 2546 ctx.p1().node())
2521 2547 finally:
2522 2548 ui.setconfig('ui', 'forcemerge', '')
2523 2549 # drop the second merge parent
2524 2550 repo.dirstate.setparents(current.node(), nullid)
2525 2551 repo.dirstate.write()
2526 2552 # fix up dirstate for copies and renames
2527 2553 cmdutil.duplicatecopies(repo, ctx.rev(), current.node(), nullid)
2528 2554 # report any conflicts
2529 2555 if stats and stats[3] > 0:
2530 raise util.Abort(_("unresolved conflicts, can't continue"),
2556 # write out state for --continue
2557 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2558 repo.opener.write('graftstate', ''.join(nodelines))
2559 raise util.Abort(
2560 _("unresolved conflicts, can't continue"),
2531 2561 hint=_('use hg resolve and hg graft --continue'))
2562 else:
2563 cont = False
2564
2532 2565 # commit
2533 2566 extra = {'source': ctx.hex()}
2534 2567 user = ctx.user()
2535 2568 if opts.get('user'):
2536 2569 user = opts['user']
2537 2570 date = ctx.date()
2538 2571 if opts.get('date'):
2539 2572 date = opts['date']
2540 2573 repo.commit(text=ctx.description(), user=user,
2541 2574 date=date, extra=extra, editor=editor)
2542 2575
2576 # remove state when we complete successfully
2577 if os.path.exists(repo.join('graftstate')):
2578 util.unlinkpath(repo.join('graftstate'))
2579
2543 2580 return 0
2544 2581
2545 2582 @command('grep',
2546 2583 [('0', 'print0', None, _('end fields with NUL')),
2547 2584 ('', 'all', None, _('print all revisions that match')),
2548 2585 ('a', 'text', None, _('treat all files as text')),
2549 2586 ('f', 'follow', None,
2550 2587 _('follow changeset history,'
2551 2588 ' or file history across copies and renames')),
2552 2589 ('i', 'ignore-case', None, _('ignore case when matching')),
2553 2590 ('l', 'files-with-matches', None,
2554 2591 _('print only filenames and revisions that match')),
2555 2592 ('n', 'line-number', None, _('print matching line numbers')),
2556 2593 ('r', 'rev', [],
2557 2594 _('only search files changed within revision range'), _('REV')),
2558 2595 ('u', 'user', None, _('list the author (long with -v)')),
2559 2596 ('d', 'date', None, _('list the date (short with -q)')),
2560 2597 ] + walkopts,
2561 2598 _('[OPTION]... PATTERN [FILE]...'))
2562 2599 def grep(ui, repo, pattern, *pats, **opts):
2563 2600 """search for a pattern in specified files and revisions
2564 2601
2565 2602 Search revisions of files for a regular expression.
2566 2603
2567 2604 This command behaves differently than Unix grep. It only accepts
2568 2605 Python/Perl regexps. It searches repository history, not the
2569 2606 working directory. It always prints the revision number in which a
2570 2607 match appears.
2571 2608
2572 2609 By default, grep only prints output for the first revision of a
2573 2610 file in which it finds a match. To get it to print every revision
2574 2611 that contains a change in match status ("-" for a match that
2575 2612 becomes a non-match, or "+" for a non-match that becomes a match),
2576 2613 use the --all flag.
2577 2614
2578 2615 Returns 0 if a match is found, 1 otherwise.
2579 2616 """
2580 2617 reflags = 0
2581 2618 if opts.get('ignore_case'):
2582 2619 reflags |= re.I
2583 2620 try:
2584 2621 regexp = re.compile(pattern, reflags)
2585 2622 except re.error, inst:
2586 2623 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2587 2624 return 1
2588 2625 sep, eol = ':', '\n'
2589 2626 if opts.get('print0'):
2590 2627 sep = eol = '\0'
2591 2628
2592 2629 getfile = util.lrucachefunc(repo.file)
2593 2630
2594 2631 def matchlines(body):
2595 2632 begin = 0
2596 2633 linenum = 0
2597 2634 while True:
2598 2635 match = regexp.search(body, begin)
2599 2636 if not match:
2600 2637 break
2601 2638 mstart, mend = match.span()
2602 2639 linenum += body.count('\n', begin, mstart) + 1
2603 2640 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2604 2641 begin = body.find('\n', mend) + 1 or len(body)
2605 2642 lend = begin - 1
2606 2643 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2607 2644
2608 2645 class linestate(object):
2609 2646 def __init__(self, line, linenum, colstart, colend):
2610 2647 self.line = line
2611 2648 self.linenum = linenum
2612 2649 self.colstart = colstart
2613 2650 self.colend = colend
2614 2651
2615 2652 def __hash__(self):
2616 2653 return hash((self.linenum, self.line))
2617 2654
2618 2655 def __eq__(self, other):
2619 2656 return self.line == other.line
2620 2657
2621 2658 matches = {}
2622 2659 copies = {}
2623 2660 def grepbody(fn, rev, body):
2624 2661 matches[rev].setdefault(fn, [])
2625 2662 m = matches[rev][fn]
2626 2663 for lnum, cstart, cend, line in matchlines(body):
2627 2664 s = linestate(line, lnum, cstart, cend)
2628 2665 m.append(s)
2629 2666
2630 2667 def difflinestates(a, b):
2631 2668 sm = difflib.SequenceMatcher(None, a, b)
2632 2669 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2633 2670 if tag == 'insert':
2634 2671 for i in xrange(blo, bhi):
2635 2672 yield ('+', b[i])
2636 2673 elif tag == 'delete':
2637 2674 for i in xrange(alo, ahi):
2638 2675 yield ('-', a[i])
2639 2676 elif tag == 'replace':
2640 2677 for i in xrange(alo, ahi):
2641 2678 yield ('-', a[i])
2642 2679 for i in xrange(blo, bhi):
2643 2680 yield ('+', b[i])
2644 2681
2645 2682 def display(fn, ctx, pstates, states):
2646 2683 rev = ctx.rev()
2647 2684 datefunc = ui.quiet and util.shortdate or util.datestr
2648 2685 found = False
2649 2686 filerevmatches = {}
2650 2687 def binary():
2651 2688 flog = getfile(fn)
2652 2689 return util.binary(flog.read(ctx.filenode(fn)))
2653 2690
2654 2691 if opts.get('all'):
2655 2692 iter = difflinestates(pstates, states)
2656 2693 else:
2657 2694 iter = [('', l) for l in states]
2658 2695 for change, l in iter:
2659 2696 cols = [fn, str(rev)]
2660 2697 before, match, after = None, None, None
2661 2698 if opts.get('line_number'):
2662 2699 cols.append(str(l.linenum))
2663 2700 if opts.get('all'):
2664 2701 cols.append(change)
2665 2702 if opts.get('user'):
2666 2703 cols.append(ui.shortuser(ctx.user()))
2667 2704 if opts.get('date'):
2668 2705 cols.append(datefunc(ctx.date()))
2669 2706 if opts.get('files_with_matches'):
2670 2707 c = (fn, rev)
2671 2708 if c in filerevmatches:
2672 2709 continue
2673 2710 filerevmatches[c] = 1
2674 2711 else:
2675 2712 before = l.line[:l.colstart]
2676 2713 match = l.line[l.colstart:l.colend]
2677 2714 after = l.line[l.colend:]
2678 2715 ui.write(sep.join(cols))
2679 2716 if before is not None:
2680 2717 if not opts.get('text') and binary():
2681 2718 ui.write(sep + " Binary file matches")
2682 2719 else:
2683 2720 ui.write(sep + before)
2684 2721 ui.write(match, label='grep.match')
2685 2722 ui.write(after)
2686 2723 ui.write(eol)
2687 2724 found = True
2688 2725 return found
2689 2726
2690 2727 skip = {}
2691 2728 revfiles = {}
2692 2729 matchfn = scmutil.match(repo[None], pats, opts)
2693 2730 found = False
2694 2731 follow = opts.get('follow')
2695 2732
2696 2733 def prep(ctx, fns):
2697 2734 rev = ctx.rev()
2698 2735 pctx = ctx.p1()
2699 2736 parent = pctx.rev()
2700 2737 matches.setdefault(rev, {})
2701 2738 matches.setdefault(parent, {})
2702 2739 files = revfiles.setdefault(rev, [])
2703 2740 for fn in fns:
2704 2741 flog = getfile(fn)
2705 2742 try:
2706 2743 fnode = ctx.filenode(fn)
2707 2744 except error.LookupError:
2708 2745 continue
2709 2746
2710 2747 copied = flog.renamed(fnode)
2711 2748 copy = follow and copied and copied[0]
2712 2749 if copy:
2713 2750 copies.setdefault(rev, {})[fn] = copy
2714 2751 if fn in skip:
2715 2752 if copy:
2716 2753 skip[copy] = True
2717 2754 continue
2718 2755 files.append(fn)
2719 2756
2720 2757 if fn not in matches[rev]:
2721 2758 grepbody(fn, rev, flog.read(fnode))
2722 2759
2723 2760 pfn = copy or fn
2724 2761 if pfn not in matches[parent]:
2725 2762 try:
2726 2763 fnode = pctx.filenode(pfn)
2727 2764 grepbody(pfn, parent, flog.read(fnode))
2728 2765 except error.LookupError:
2729 2766 pass
2730 2767
2731 2768 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2732 2769 rev = ctx.rev()
2733 2770 parent = ctx.p1().rev()
2734 2771 for fn in sorted(revfiles.get(rev, [])):
2735 2772 states = matches[rev][fn]
2736 2773 copy = copies.get(rev, {}).get(fn)
2737 2774 if fn in skip:
2738 2775 if copy:
2739 2776 skip[copy] = True
2740 2777 continue
2741 2778 pstates = matches.get(parent, {}).get(copy or fn, [])
2742 2779 if pstates or states:
2743 2780 r = display(fn, ctx, pstates, states)
2744 2781 found = found or r
2745 2782 if r and not opts.get('all'):
2746 2783 skip[fn] = True
2747 2784 if copy:
2748 2785 skip[copy] = True
2749 2786 del matches[rev]
2750 2787 del revfiles[rev]
2751 2788
2752 2789 return not found
2753 2790
2754 2791 @command('heads',
2755 2792 [('r', 'rev', '',
2756 2793 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2757 2794 ('t', 'topo', False, _('show topological heads only')),
2758 2795 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2759 2796 ('c', 'closed', False, _('show normal and closed branch heads')),
2760 2797 ] + templateopts,
2761 2798 _('[-ac] [-r STARTREV] [REV]...'))
2762 2799 def heads(ui, repo, *branchrevs, **opts):
2763 2800 """show current repository heads or show branch heads
2764 2801
2765 2802 With no arguments, show all repository branch heads.
2766 2803
2767 2804 Repository "heads" are changesets with no child changesets. They are
2768 2805 where development generally takes place and are the usual targets
2769 2806 for update and merge operations. Branch heads are changesets that have
2770 2807 no child changeset on the same branch.
2771 2808
2772 2809 If one or more REVs are given, only branch heads on the branches
2773 2810 associated with the specified changesets are shown. This means
2774 2811 that you can use :hg:`heads foo` to see the heads on a branch
2775 2812 named ``foo``.
2776 2813
2777 2814 If -c/--closed is specified, also show branch heads marked closed
2778 2815 (see :hg:`commit --close-branch`).
2779 2816
2780 2817 If STARTREV is specified, only those heads that are descendants of
2781 2818 STARTREV will be displayed.
2782 2819
2783 2820 If -t/--topo is specified, named branch mechanics will be ignored and only
2784 2821 changesets without children will be shown.
2785 2822
2786 2823 Returns 0 if matching heads are found, 1 if not.
2787 2824 """
2788 2825
2789 2826 start = None
2790 2827 if 'rev' in opts:
2791 2828 start = scmutil.revsingle(repo, opts['rev'], None).node()
2792 2829
2793 2830 if opts.get('topo'):
2794 2831 heads = [repo[h] for h in repo.heads(start)]
2795 2832 else:
2796 2833 heads = []
2797 2834 for branch in repo.branchmap():
2798 2835 heads += repo.branchheads(branch, start, opts.get('closed'))
2799 2836 heads = [repo[h] for h in heads]
2800 2837
2801 2838 if branchrevs:
2802 2839 branches = set(repo[br].branch() for br in branchrevs)
2803 2840 heads = [h for h in heads if h.branch() in branches]
2804 2841
2805 2842 if opts.get('active') and branchrevs:
2806 2843 dagheads = repo.heads(start)
2807 2844 heads = [h for h in heads if h.node() in dagheads]
2808 2845
2809 2846 if branchrevs:
2810 2847 haveheads = set(h.branch() for h in heads)
2811 2848 if branches - haveheads:
2812 2849 headless = ', '.join(b for b in branches - haveheads)
2813 2850 msg = _('no open branch heads found on branches %s')
2814 2851 if opts.get('rev'):
2815 2852 msg += _(' (started at %s)' % opts['rev'])
2816 2853 ui.warn((msg + '\n') % headless)
2817 2854
2818 2855 if not heads:
2819 2856 return 1
2820 2857
2821 2858 heads = sorted(heads, key=lambda x: -x.rev())
2822 2859 displayer = cmdutil.show_changeset(ui, repo, opts)
2823 2860 for ctx in heads:
2824 2861 displayer.show(ctx)
2825 2862 displayer.close()
2826 2863
2827 2864 @command('help',
2828 2865 [('e', 'extension', None, _('show only help for extensions')),
2829 2866 ('c', 'command', None, _('show only help for commands'))],
2830 2867 _('[-ec] [TOPIC]'))
2831 2868 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2832 2869 """show help for a given topic or a help overview
2833 2870
2834 2871 With no arguments, print a list of commands with short help messages.
2835 2872
2836 2873 Given a topic, extension, or command name, print help for that
2837 2874 topic.
2838 2875
2839 2876 Returns 0 if successful.
2840 2877 """
2841 2878
2842 2879 textwidth = min(ui.termwidth(), 80) - 2
2843 2880
2844 2881 def optrst(options):
2845 2882 data = []
2846 2883 multioccur = False
2847 2884 for option in options:
2848 2885 if len(option) == 5:
2849 2886 shortopt, longopt, default, desc, optlabel = option
2850 2887 else:
2851 2888 shortopt, longopt, default, desc = option
2852 2889 optlabel = _("VALUE") # default label
2853 2890
2854 2891 if _("DEPRECATED") in desc and not ui.verbose:
2855 2892 continue
2856 2893
2857 2894 so = ''
2858 2895 if shortopt:
2859 2896 so = '-' + shortopt
2860 2897 lo = '--' + longopt
2861 2898 if default:
2862 2899 desc += _(" (default: %s)") % default
2863 2900
2864 2901 if isinstance(default, list):
2865 2902 lo += " %s [+]" % optlabel
2866 2903 multioccur = True
2867 2904 elif (default is not None) and not isinstance(default, bool):
2868 2905 lo += " %s" % optlabel
2869 2906
2870 2907 data.append((so, lo, desc))
2871 2908
2872 2909 rst = minirst.maketable(data, 1)
2873 2910
2874 2911 if multioccur:
2875 2912 rst += _("\n[+] marked option can be specified multiple times\n")
2876 2913
2877 2914 return rst
2878 2915
2879 2916 # list all option lists
2880 2917 def opttext(optlist, width):
2881 2918 rst = ''
2882 2919 if not optlist:
2883 2920 return ''
2884 2921
2885 2922 for title, options in optlist:
2886 2923 rst += '\n%s\n' % title
2887 2924 if options:
2888 2925 rst += "\n"
2889 2926 rst += optrst(options)
2890 2927 rst += '\n'
2891 2928
2892 2929 return '\n' + minirst.format(rst, width)
2893 2930
2894 2931 def addglobalopts(optlist, aliases):
2895 2932 if ui.quiet:
2896 2933 return []
2897 2934
2898 2935 if ui.verbose:
2899 2936 optlist.append((_("global options:"), globalopts))
2900 2937 if name == 'shortlist':
2901 2938 optlist.append((_('use "hg help" for the full list '
2902 2939 'of commands'), ()))
2903 2940 else:
2904 2941 if name == 'shortlist':
2905 2942 msg = _('use "hg help" for the full list of commands '
2906 2943 'or "hg -v" for details')
2907 2944 elif name and not full:
2908 2945 msg = _('use "hg help %s" to show the full help text' % name)
2909 2946 elif aliases:
2910 2947 msg = _('use "hg -v help%s" to show builtin aliases and '
2911 2948 'global options') % (name and " " + name or "")
2912 2949 else:
2913 2950 msg = _('use "hg -v help %s" to show more info') % name
2914 2951 optlist.append((msg, ()))
2915 2952
2916 2953 def helpcmd(name):
2917 2954 try:
2918 2955 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2919 2956 except error.AmbiguousCommand, inst:
2920 2957 # py3k fix: except vars can't be used outside the scope of the
2921 2958 # except block, nor can be used inside a lambda. python issue4617
2922 2959 prefix = inst.args[0]
2923 2960 select = lambda c: c.lstrip('^').startswith(prefix)
2924 2961 helplist(select)
2925 2962 return
2926 2963
2927 2964 # check if it's an invalid alias and display its error if it is
2928 2965 if getattr(entry[0], 'badalias', False):
2929 2966 if not unknowncmd:
2930 2967 entry[0](ui)
2931 2968 return
2932 2969
2933 2970 rst = ""
2934 2971
2935 2972 # synopsis
2936 2973 if len(entry) > 2:
2937 2974 if entry[2].startswith('hg'):
2938 2975 rst += "%s\n" % entry[2]
2939 2976 else:
2940 2977 rst += 'hg %s %s\n' % (aliases[0], entry[2])
2941 2978 else:
2942 2979 rst += 'hg %s\n' % aliases[0]
2943 2980
2944 2981 # aliases
2945 2982 if full and not ui.quiet and len(aliases) > 1:
2946 2983 rst += _("\naliases: %s\n") % ', '.join(aliases[1:])
2947 2984
2948 2985 # description
2949 2986 doc = gettext(entry[0].__doc__)
2950 2987 if not doc:
2951 2988 doc = _("(no help text available)")
2952 2989 if util.safehasattr(entry[0], 'definition'): # aliased command
2953 2990 if entry[0].definition.startswith('!'): # shell alias
2954 2991 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2955 2992 else:
2956 2993 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2957 2994 if ui.quiet or not full:
2958 2995 doc = doc.splitlines()[0]
2959 2996 rst += "\n" + doc + "\n"
2960 2997
2961 2998 # check if this command shadows a non-trivial (multi-line)
2962 2999 # extension help text
2963 3000 try:
2964 3001 mod = extensions.find(name)
2965 3002 doc = gettext(mod.__doc__) or ''
2966 3003 if '\n' in doc.strip():
2967 3004 msg = _('use "hg help -e %s" to show help for '
2968 3005 'the %s extension') % (name, name)
2969 3006 rst += '\n%s\n' % msg
2970 3007 except KeyError:
2971 3008 pass
2972 3009
2973 3010 # options
2974 3011 if not ui.quiet and entry[1]:
2975 3012 rst += '\noptions:\n\n'
2976 3013 rst += optrst(entry[1])
2977 3014
2978 3015 if ui.verbose:
2979 3016 rst += '\nglobal options:\n\n'
2980 3017 rst += optrst(globalopts)
2981 3018
2982 3019 keep = ui.verbose and ['verbose'] or []
2983 3020 formatted, pruned = minirst.format(rst, textwidth, keep=keep)
2984 3021 ui.write(formatted)
2985 3022
2986 3023 if not ui.verbose:
2987 3024 if not full:
2988 3025 ui.write(_('\nuse "hg help %s" to show the full help text\n')
2989 3026 % name)
2990 3027 elif not ui.quiet:
2991 3028 ui.write(_('\nuse "hg -v help %s" to show more info\n') % name)
2992 3029
2993 3030
2994 3031 def helplist(select=None):
2995 3032 # list of commands
2996 3033 if name == "shortlist":
2997 3034 header = _('basic commands:\n\n')
2998 3035 else:
2999 3036 header = _('list of commands:\n\n')
3000 3037
3001 3038 h = {}
3002 3039 cmds = {}
3003 3040 for c, e in table.iteritems():
3004 3041 f = c.split("|", 1)[0]
3005 3042 if select and not select(f):
3006 3043 continue
3007 3044 if (not select and name != 'shortlist' and
3008 3045 e[0].__module__ != __name__):
3009 3046 continue
3010 3047 if name == "shortlist" and not f.startswith("^"):
3011 3048 continue
3012 3049 f = f.lstrip("^")
3013 3050 if not ui.debugflag and f.startswith("debug"):
3014 3051 continue
3015 3052 doc = e[0].__doc__
3016 3053 if doc and 'DEPRECATED' in doc and not ui.verbose:
3017 3054 continue
3018 3055 doc = gettext(doc)
3019 3056 if not doc:
3020 3057 doc = _("(no help text available)")
3021 3058 h[f] = doc.splitlines()[0].rstrip()
3022 3059 cmds[f] = c.lstrip("^")
3023 3060
3024 3061 if not h:
3025 3062 ui.status(_('no commands defined\n'))
3026 3063 return
3027 3064
3028 3065 ui.status(header)
3029 3066 fns = sorted(h)
3030 3067 m = max(map(len, fns))
3031 3068 for f in fns:
3032 3069 if ui.verbose:
3033 3070 commands = cmds[f].replace("|",", ")
3034 3071 ui.write(" %s:\n %s\n"%(commands, h[f]))
3035 3072 else:
3036 3073 ui.write('%s\n' % (util.wrap(h[f], textwidth,
3037 3074 initindent=' %-*s ' % (m, f),
3038 3075 hangindent=' ' * (m + 4))))
3039 3076
3040 3077 if not name:
3041 3078 text = help.listexts(_('enabled extensions:'), extensions.enabled())
3042 3079 if text:
3043 3080 ui.write("\n%s" % minirst.format(text, textwidth))
3044 3081
3045 3082 ui.write(_("\nadditional help topics:\n\n"))
3046 3083 topics = []
3047 3084 for names, header, doc in help.helptable:
3048 3085 topics.append((sorted(names, key=len, reverse=True)[0], header))
3049 3086 topics_len = max([len(s[0]) for s in topics])
3050 3087 for t, desc in topics:
3051 3088 ui.write(" %-*s %s\n" % (topics_len, t, desc))
3052 3089
3053 3090 optlist = []
3054 3091 addglobalopts(optlist, True)
3055 3092 ui.write(opttext(optlist, textwidth))
3056 3093
3057 3094 def helptopic(name):
3058 3095 for names, header, doc in help.helptable:
3059 3096 if name in names:
3060 3097 break
3061 3098 else:
3062 3099 raise error.UnknownCommand(name)
3063 3100
3064 3101 # description
3065 3102 if not doc:
3066 3103 doc = _("(no help text available)")
3067 3104 if util.safehasattr(doc, '__call__'):
3068 3105 doc = doc()
3069 3106
3070 3107 ui.write("%s\n\n" % header)
3071 3108 ui.write("%s" % minirst.format(doc, textwidth, indent=4))
3072 3109 try:
3073 3110 cmdutil.findcmd(name, table)
3074 3111 ui.write(_('\nuse "hg help -c %s" to see help for '
3075 3112 'the %s command\n') % (name, name))
3076 3113 except error.UnknownCommand:
3077 3114 pass
3078 3115
3079 3116 def helpext(name):
3080 3117 try:
3081 3118 mod = extensions.find(name)
3082 3119 doc = gettext(mod.__doc__) or _('no help text available')
3083 3120 except KeyError:
3084 3121 mod = None
3085 3122 doc = extensions.disabledext(name)
3086 3123 if not doc:
3087 3124 raise error.UnknownCommand(name)
3088 3125
3089 3126 if '\n' not in doc:
3090 3127 head, tail = doc, ""
3091 3128 else:
3092 3129 head, tail = doc.split('\n', 1)
3093 3130 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
3094 3131 if tail:
3095 3132 ui.write(minirst.format(tail, textwidth))
3096 3133 ui.status('\n')
3097 3134
3098 3135 if mod:
3099 3136 try:
3100 3137 ct = mod.cmdtable
3101 3138 except AttributeError:
3102 3139 ct = {}
3103 3140 modcmds = set([c.split('|', 1)[0] for c in ct])
3104 3141 helplist(modcmds.__contains__)
3105 3142 else:
3106 3143 ui.write(_('use "hg help extensions" for information on enabling '
3107 3144 'extensions\n'))
3108 3145
3109 3146 def helpextcmd(name):
3110 3147 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
3111 3148 doc = gettext(mod.__doc__).splitlines()[0]
3112 3149
3113 3150 msg = help.listexts(_("'%s' is provided by the following "
3114 3151 "extension:") % cmd, {ext: doc}, indent=4)
3115 3152 ui.write(minirst.format(msg, textwidth))
3116 3153 ui.write('\n')
3117 3154 ui.write(_('use "hg help extensions" for information on enabling '
3118 3155 'extensions\n'))
3119 3156
3120 3157 if name and name != 'shortlist':
3121 3158 i = None
3122 3159 if unknowncmd:
3123 3160 queries = (helpextcmd,)
3124 3161 elif opts.get('extension'):
3125 3162 queries = (helpext,)
3126 3163 elif opts.get('command'):
3127 3164 queries = (helpcmd,)
3128 3165 else:
3129 3166 queries = (helptopic, helpcmd, helpext, helpextcmd)
3130 3167 for f in queries:
3131 3168 try:
3132 3169 f(name)
3133 3170 i = None
3134 3171 break
3135 3172 except error.UnknownCommand, inst:
3136 3173 i = inst
3137 3174 if i:
3138 3175 raise i
3139 3176 else:
3140 3177 # program name
3141 3178 ui.status(_("Mercurial Distributed SCM\n"))
3142 3179 ui.status('\n')
3143 3180 helplist()
3144 3181
3145 3182
3146 3183 @command('identify|id',
3147 3184 [('r', 'rev', '',
3148 3185 _('identify the specified revision'), _('REV')),
3149 3186 ('n', 'num', None, _('show local revision number')),
3150 3187 ('i', 'id', None, _('show global revision id')),
3151 3188 ('b', 'branch', None, _('show branch')),
3152 3189 ('t', 'tags', None, _('show tags')),
3153 3190 ('B', 'bookmarks', None, _('show bookmarks'))],
3154 3191 _('[-nibtB] [-r REV] [SOURCE]'))
3155 3192 def identify(ui, repo, source=None, rev=None,
3156 3193 num=None, id=None, branch=None, tags=None, bookmarks=None):
3157 3194 """identify the working copy or specified revision
3158 3195
3159 3196 Print a summary identifying the repository state at REV using one or
3160 3197 two parent hash identifiers, followed by a "+" if the working
3161 3198 directory has uncommitted changes, the branch name (if not default),
3162 3199 a list of tags, and a list of bookmarks.
3163 3200
3164 3201 When REV is not given, print a summary of the current state of the
3165 3202 repository.
3166 3203
3167 3204 Specifying a path to a repository root or Mercurial bundle will
3168 3205 cause lookup to operate on that repository/bundle.
3169 3206
3170 3207 .. container:: verbose
3171 3208
3172 3209 Examples:
3173 3210
3174 3211 - generate a build identifier for the working directory::
3175 3212
3176 3213 hg id --id > build-id.dat
3177 3214
3178 3215 - find the revision corresponding to a tag::
3179 3216
3180 3217 hg id -n -r 1.3
3181 3218
3182 3219 - check the most recent revision of a remote repository::
3183 3220
3184 3221 hg id -r tip http://selenic.com/hg/
3185 3222
3186 3223 Returns 0 if successful.
3187 3224 """
3188 3225
3189 3226 if not repo and not source:
3190 3227 raise util.Abort(_("there is no Mercurial repository here "
3191 3228 "(.hg not found)"))
3192 3229
3193 3230 hexfunc = ui.debugflag and hex or short
3194 3231 default = not (num or id or branch or tags or bookmarks)
3195 3232 output = []
3196 3233 revs = []
3197 3234
3198 3235 if source:
3199 3236 source, branches = hg.parseurl(ui.expandpath(source))
3200 3237 repo = hg.peer(ui, {}, source)
3201 3238 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3202 3239
3203 3240 if not repo.local():
3204 3241 if num or branch or tags:
3205 3242 raise util.Abort(
3206 3243 _("can't query remote revision number, branch, or tags"))
3207 3244 if not rev and revs:
3208 3245 rev = revs[0]
3209 3246 if not rev:
3210 3247 rev = "tip"
3211 3248
3212 3249 remoterev = repo.lookup(rev)
3213 3250 if default or id:
3214 3251 output = [hexfunc(remoterev)]
3215 3252
3216 3253 def getbms():
3217 3254 bms = []
3218 3255
3219 3256 if 'bookmarks' in repo.listkeys('namespaces'):
3220 3257 hexremoterev = hex(remoterev)
3221 3258 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3222 3259 if bmr == hexremoterev]
3223 3260
3224 3261 return bms
3225 3262
3226 3263 if bookmarks:
3227 3264 output.extend(getbms())
3228 3265 elif default and not ui.quiet:
3229 3266 # multiple bookmarks for a single parent separated by '/'
3230 3267 bm = '/'.join(getbms())
3231 3268 if bm:
3232 3269 output.append(bm)
3233 3270 else:
3234 3271 if not rev:
3235 3272 ctx = repo[None]
3236 3273 parents = ctx.parents()
3237 3274 changed = ""
3238 3275 if default or id or num:
3239 3276 changed = util.any(repo.status()) and "+" or ""
3240 3277 if default or id:
3241 3278 output = ["%s%s" %
3242 3279 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3243 3280 if num:
3244 3281 output.append("%s%s" %
3245 3282 ('+'.join([str(p.rev()) for p in parents]), changed))
3246 3283 else:
3247 3284 ctx = scmutil.revsingle(repo, rev)
3248 3285 if default or id:
3249 3286 output = [hexfunc(ctx.node())]
3250 3287 if num:
3251 3288 output.append(str(ctx.rev()))
3252 3289
3253 3290 if default and not ui.quiet:
3254 3291 b = ctx.branch()
3255 3292 if b != 'default':
3256 3293 output.append("(%s)" % b)
3257 3294
3258 3295 # multiple tags for a single parent separated by '/'
3259 3296 t = '/'.join(ctx.tags())
3260 3297 if t:
3261 3298 output.append(t)
3262 3299
3263 3300 # multiple bookmarks for a single parent separated by '/'
3264 3301 bm = '/'.join(ctx.bookmarks())
3265 3302 if bm:
3266 3303 output.append(bm)
3267 3304 else:
3268 3305 if branch:
3269 3306 output.append(ctx.branch())
3270 3307
3271 3308 if tags:
3272 3309 output.extend(ctx.tags())
3273 3310
3274 3311 if bookmarks:
3275 3312 output.extend(ctx.bookmarks())
3276 3313
3277 3314 ui.write("%s\n" % ' '.join(output))
3278 3315
3279 3316 @command('import|patch',
3280 3317 [('p', 'strip', 1,
3281 3318 _('directory strip option for patch. This has the same '
3282 3319 'meaning as the corresponding patch option'), _('NUM')),
3283 3320 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3284 3321 ('e', 'edit', False, _('invoke editor on commit messages')),
3285 3322 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3286 3323 ('', 'no-commit', None,
3287 3324 _("don't commit, just update the working directory")),
3288 3325 ('', 'bypass', None,
3289 3326 _("apply patch without touching the working directory")),
3290 3327 ('', 'exact', None,
3291 3328 _('apply patch to the nodes from which it was generated')),
3292 3329 ('', 'import-branch', None,
3293 3330 _('use any branch information in patch (implied by --exact)'))] +
3294 3331 commitopts + commitopts2 + similarityopts,
3295 3332 _('[OPTION]... PATCH...'))
3296 3333 def import_(ui, repo, patch1, *patches, **opts):
3297 3334 """import an ordered set of patches
3298 3335
3299 3336 Import a list of patches and commit them individually (unless
3300 3337 --no-commit is specified).
3301 3338
3302 3339 If there are outstanding changes in the working directory, import
3303 3340 will abort unless given the -f/--force flag.
3304 3341
3305 3342 You can import a patch straight from a mail message. Even patches
3306 3343 as attachments work (to use the body part, it must have type
3307 3344 text/plain or text/x-patch). From and Subject headers of email
3308 3345 message are used as default committer and commit message. All
3309 3346 text/plain body parts before first diff are added to commit
3310 3347 message.
3311 3348
3312 3349 If the imported patch was generated by :hg:`export`, user and
3313 3350 description from patch override values from message headers and
3314 3351 body. Values given on command line with -m/--message and -u/--user
3315 3352 override these.
3316 3353
3317 3354 If --exact is specified, import will set the working directory to
3318 3355 the parent of each patch before applying it, and will abort if the
3319 3356 resulting changeset has a different ID than the one recorded in
3320 3357 the patch. This may happen due to character set problems or other
3321 3358 deficiencies in the text patch format.
3322 3359
3323 3360 Use --bypass to apply and commit patches directly to the
3324 3361 repository, not touching the working directory. Without --exact,
3325 3362 patches will be applied on top of the working directory parent
3326 3363 revision.
3327 3364
3328 3365 With -s/--similarity, hg will attempt to discover renames and
3329 3366 copies in the patch in the same way as 'addremove'.
3330 3367
3331 3368 To read a patch from standard input, use "-" as the patch name. If
3332 3369 a URL is specified, the patch will be downloaded from it.
3333 3370 See :hg:`help dates` for a list of formats valid for -d/--date.
3334 3371
3335 3372 .. container:: verbose
3336 3373
3337 3374 Examples:
3338 3375
3339 3376 - import a traditional patch from a website and detect renames::
3340 3377
3341 3378 hg import -s 80 http://example.com/bugfix.patch
3342 3379
3343 3380 - import a changeset from an hgweb server::
3344 3381
3345 3382 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3346 3383
3347 3384 - import all the patches in an Unix-style mbox::
3348 3385
3349 3386 hg import incoming-patches.mbox
3350 3387
3351 3388 - attempt to exactly restore an exported changeset (not always
3352 3389 possible)::
3353 3390
3354 3391 hg import --exact proposed-fix.patch
3355 3392
3356 3393 Returns 0 on success.
3357 3394 """
3358 3395 patches = (patch1,) + patches
3359 3396
3360 3397 date = opts.get('date')
3361 3398 if date:
3362 3399 opts['date'] = util.parsedate(date)
3363 3400
3364 3401 editor = cmdutil.commiteditor
3365 3402 if opts.get('edit'):
3366 3403 editor = cmdutil.commitforceeditor
3367 3404
3368 3405 update = not opts.get('bypass')
3369 3406 if not update and opts.get('no_commit'):
3370 3407 raise util.Abort(_('cannot use --no-commit with --bypass'))
3371 3408 try:
3372 3409 sim = float(opts.get('similarity') or 0)
3373 3410 except ValueError:
3374 3411 raise util.Abort(_('similarity must be a number'))
3375 3412 if sim < 0 or sim > 100:
3376 3413 raise util.Abort(_('similarity must be between 0 and 100'))
3377 3414 if sim and not update:
3378 3415 raise util.Abort(_('cannot use --similarity with --bypass'))
3379 3416
3380 3417 if (opts.get('exact') or not opts.get('force')) and update:
3381 3418 cmdutil.bailifchanged(repo)
3382 3419
3383 3420 base = opts["base"]
3384 3421 strip = opts["strip"]
3385 3422 wlock = lock = tr = None
3386 3423 msgs = []
3387 3424
3388 3425 def checkexact(repo, n, nodeid):
3389 3426 if opts.get('exact') and hex(n) != nodeid:
3390 3427 repo.rollback()
3391 3428 raise util.Abort(_('patch is damaged or loses information'))
3392 3429
3393 3430 def tryone(ui, hunk, parents):
3394 3431 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3395 3432 patch.extract(ui, hunk)
3396 3433
3397 3434 if not tmpname:
3398 3435 return (None, None)
3399 3436 msg = _('applied to working directory')
3400 3437
3401 3438 try:
3402 3439 cmdline_message = cmdutil.logmessage(ui, opts)
3403 3440 if cmdline_message:
3404 3441 # pickup the cmdline msg
3405 3442 message = cmdline_message
3406 3443 elif message:
3407 3444 # pickup the patch msg
3408 3445 message = message.strip()
3409 3446 else:
3410 3447 # launch the editor
3411 3448 message = None
3412 3449 ui.debug('message:\n%s\n' % message)
3413 3450
3414 3451 if len(parents) == 1:
3415 3452 parents.append(repo[nullid])
3416 3453 if opts.get('exact'):
3417 3454 if not nodeid or not p1:
3418 3455 raise util.Abort(_('not a Mercurial patch'))
3419 3456 p1 = repo[p1]
3420 3457 p2 = repo[p2 or nullid]
3421 3458 elif p2:
3422 3459 try:
3423 3460 p1 = repo[p1]
3424 3461 p2 = repo[p2]
3425 3462 except error.RepoError:
3426 3463 p1, p2 = parents
3427 3464 else:
3428 3465 p1, p2 = parents
3429 3466
3430 3467 n = None
3431 3468 if update:
3432 3469 if opts.get('exact') and p1 != parents[0]:
3433 3470 hg.clean(repo, p1.node())
3434 3471 if p1 != parents[0] and p2 != parents[1]:
3435 3472 repo.dirstate.setparents(p1.node(), p2.node())
3436 3473
3437 3474 if opts.get('exact') or opts.get('import_branch'):
3438 3475 repo.dirstate.setbranch(branch or 'default')
3439 3476
3440 3477 files = set()
3441 3478 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3442 3479 eolmode=None, similarity=sim / 100.0)
3443 3480 files = list(files)
3444 3481 if opts.get('no_commit'):
3445 3482 if message:
3446 3483 msgs.append(message)
3447 3484 else:
3448 3485 if opts.get('exact'):
3449 3486 m = None
3450 3487 else:
3451 3488 m = scmutil.matchfiles(repo, files or [])
3452 3489 n = repo.commit(message, opts.get('user') or user,
3453 3490 opts.get('date') or date, match=m,
3454 3491 editor=editor)
3455 3492 checkexact(repo, n, nodeid)
3456 3493 else:
3457 3494 if opts.get('exact') or opts.get('import_branch'):
3458 3495 branch = branch or 'default'
3459 3496 else:
3460 3497 branch = p1.branch()
3461 3498 store = patch.filestore()
3462 3499 try:
3463 3500 files = set()
3464 3501 try:
3465 3502 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3466 3503 files, eolmode=None)
3467 3504 except patch.PatchError, e:
3468 3505 raise util.Abort(str(e))
3469 3506 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3470 3507 message,
3471 3508 opts.get('user') or user,
3472 3509 opts.get('date') or date,
3473 3510 branch, files, store,
3474 3511 editor=cmdutil.commiteditor)
3475 3512 repo.savecommitmessage(memctx.description())
3476 3513 n = memctx.commit()
3477 3514 checkexact(repo, n, nodeid)
3478 3515 finally:
3479 3516 store.close()
3480 3517 if n:
3481 3518 msg = _('created %s') % short(n)
3482 3519 return (msg, n)
3483 3520 finally:
3484 3521 os.unlink(tmpname)
3485 3522
3486 3523 try:
3487 3524 wlock = repo.wlock()
3488 3525 lock = repo.lock()
3489 3526 tr = repo.transaction('import')
3490 3527 parents = repo.parents()
3491 3528 for patchurl in patches:
3492 3529 if patchurl == '-':
3493 3530 ui.status(_('applying patch from stdin\n'))
3494 3531 patchfile = ui.fin
3495 3532 patchurl = 'stdin' # for error message
3496 3533 else:
3497 3534 patchurl = os.path.join(base, patchurl)
3498 3535 ui.status(_('applying %s\n') % patchurl)
3499 3536 patchfile = url.open(ui, patchurl)
3500 3537
3501 3538 haspatch = False
3502 3539 for hunk in patch.split(patchfile):
3503 3540 (msg, node) = tryone(ui, hunk, parents)
3504 3541 if msg:
3505 3542 haspatch = True
3506 3543 ui.note(msg + '\n')
3507 3544 if update or opts.get('exact'):
3508 3545 parents = repo.parents()
3509 3546 else:
3510 3547 parents = [repo[node]]
3511 3548
3512 3549 if not haspatch:
3513 3550 raise util.Abort(_('%s: no diffs found') % patchurl)
3514 3551
3515 3552 tr.close()
3516 3553 if msgs:
3517 3554 repo.savecommitmessage('\n* * *\n'.join(msgs))
3518 3555 except:
3519 3556 # wlock.release() indirectly calls dirstate.write(): since
3520 3557 # we're crashing, we do not want to change the working dir
3521 3558 # parent after all, so make sure it writes nothing
3522 3559 repo.dirstate.invalidate()
3523 3560 raise
3524 3561 finally:
3525 3562 if tr:
3526 3563 tr.release()
3527 3564 release(lock, wlock)
3528 3565
3529 3566 @command('incoming|in',
3530 3567 [('f', 'force', None,
3531 3568 _('run even if remote repository is unrelated')),
3532 3569 ('n', 'newest-first', None, _('show newest record first')),
3533 3570 ('', 'bundle', '',
3534 3571 _('file to store the bundles into'), _('FILE')),
3535 3572 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3536 3573 ('B', 'bookmarks', False, _("compare bookmarks")),
3537 3574 ('b', 'branch', [],
3538 3575 _('a specific branch you would like to pull'), _('BRANCH')),
3539 3576 ] + logopts + remoteopts + subrepoopts,
3540 3577 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3541 3578 def incoming(ui, repo, source="default", **opts):
3542 3579 """show new changesets found in source
3543 3580
3544 3581 Show new changesets found in the specified path/URL or the default
3545 3582 pull location. These are the changesets that would have been pulled
3546 3583 if a pull at the time you issued this command.
3547 3584
3548 3585 For remote repository, using --bundle avoids downloading the
3549 3586 changesets twice if the incoming is followed by a pull.
3550 3587
3551 3588 See pull for valid source format details.
3552 3589
3553 3590 Returns 0 if there are incoming changes, 1 otherwise.
3554 3591 """
3555 3592 if opts.get('bundle') and opts.get('subrepos'):
3556 3593 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3557 3594
3558 3595 if opts.get('bookmarks'):
3559 3596 source, branches = hg.parseurl(ui.expandpath(source),
3560 3597 opts.get('branch'))
3561 3598 other = hg.peer(repo, opts, source)
3562 3599 if 'bookmarks' not in other.listkeys('namespaces'):
3563 3600 ui.warn(_("remote doesn't support bookmarks\n"))
3564 3601 return 0
3565 3602 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3566 3603 return bookmarks.diff(ui, repo, other)
3567 3604
3568 3605 repo._subtoppath = ui.expandpath(source)
3569 3606 try:
3570 3607 return hg.incoming(ui, repo, source, opts)
3571 3608 finally:
3572 3609 del repo._subtoppath
3573 3610
3574 3611
3575 3612 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3576 3613 def init(ui, dest=".", **opts):
3577 3614 """create a new repository in the given directory
3578 3615
3579 3616 Initialize a new repository in the given directory. If the given
3580 3617 directory does not exist, it will be created.
3581 3618
3582 3619 If no directory is given, the current directory is used.
3583 3620
3584 3621 It is possible to specify an ``ssh://`` URL as the destination.
3585 3622 See :hg:`help urls` for more information.
3586 3623
3587 3624 Returns 0 on success.
3588 3625 """
3589 3626 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3590 3627
3591 3628 @command('locate',
3592 3629 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3593 3630 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3594 3631 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3595 3632 ] + walkopts,
3596 3633 _('[OPTION]... [PATTERN]...'))
3597 3634 def locate(ui, repo, *pats, **opts):
3598 3635 """locate files matching specific patterns
3599 3636
3600 3637 Print files under Mercurial control in the working directory whose
3601 3638 names match the given patterns.
3602 3639
3603 3640 By default, this command searches all directories in the working
3604 3641 directory. To search just the current directory and its
3605 3642 subdirectories, use "--include .".
3606 3643
3607 3644 If no patterns are given to match, this command prints the names
3608 3645 of all files under Mercurial control in the working directory.
3609 3646
3610 3647 If you want to feed the output of this command into the "xargs"
3611 3648 command, use the -0 option to both this command and "xargs". This
3612 3649 will avoid the problem of "xargs" treating single filenames that
3613 3650 contain whitespace as multiple filenames.
3614 3651
3615 3652 Returns 0 if a match is found, 1 otherwise.
3616 3653 """
3617 3654 end = opts.get('print0') and '\0' or '\n'
3618 3655 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3619 3656
3620 3657 ret = 1
3621 3658 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3622 3659 m.bad = lambda x, y: False
3623 3660 for abs in repo[rev].walk(m):
3624 3661 if not rev and abs not in repo.dirstate:
3625 3662 continue
3626 3663 if opts.get('fullpath'):
3627 3664 ui.write(repo.wjoin(abs), end)
3628 3665 else:
3629 3666 ui.write(((pats and m.rel(abs)) or abs), end)
3630 3667 ret = 0
3631 3668
3632 3669 return ret
3633 3670
3634 3671 @command('^log|history',
3635 3672 [('f', 'follow', None,
3636 3673 _('follow changeset history, or file history across copies and renames')),
3637 3674 ('', 'follow-first', None,
3638 3675 _('only follow the first parent of merge changesets')),
3639 3676 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3640 3677 ('C', 'copies', None, _('show copied files')),
3641 3678 ('k', 'keyword', [],
3642 3679 _('do case-insensitive search for a given text'), _('TEXT')),
3643 3680 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3644 3681 ('', 'removed', None, _('include revisions where files were removed')),
3645 3682 ('m', 'only-merges', None, _('show only merges')),
3646 3683 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3647 3684 ('', 'only-branch', [],
3648 3685 _('show only changesets within the given named branch (DEPRECATED)'),
3649 3686 _('BRANCH')),
3650 3687 ('b', 'branch', [],
3651 3688 _('show changesets within the given named branch'), _('BRANCH')),
3652 3689 ('P', 'prune', [],
3653 3690 _('do not display revision or any of its ancestors'), _('REV')),
3654 3691 ('', 'hidden', False, _('show hidden changesets')),
3655 3692 ] + logopts + walkopts,
3656 3693 _('[OPTION]... [FILE]'))
3657 3694 def log(ui, repo, *pats, **opts):
3658 3695 """show revision history of entire repository or files
3659 3696
3660 3697 Print the revision history of the specified files or the entire
3661 3698 project.
3662 3699
3663 3700 If no revision range is specified, the default is ``tip:0`` unless
3664 3701 --follow is set, in which case the working directory parent is
3665 3702 used as the starting revision.
3666 3703
3667 3704 File history is shown without following rename or copy history of
3668 3705 files. Use -f/--follow with a filename to follow history across
3669 3706 renames and copies. --follow without a filename will only show
3670 3707 ancestors or descendants of the starting revision.
3671 3708
3672 3709 By default this command prints revision number and changeset id,
3673 3710 tags, non-trivial parents, user, date and time, and a summary for
3674 3711 each commit. When the -v/--verbose switch is used, the list of
3675 3712 changed files and full commit message are shown.
3676 3713
3677 3714 .. note::
3678 3715 log -p/--patch may generate unexpected diff output for merge
3679 3716 changesets, as it will only compare the merge changeset against
3680 3717 its first parent. Also, only files different from BOTH parents
3681 3718 will appear in files:.
3682 3719
3683 3720 .. note::
3684 3721 for performance reasons, log FILE may omit duplicate changes
3685 3722 made on branches and will not show deletions. To see all
3686 3723 changes including duplicates and deletions, use the --removed
3687 3724 switch.
3688 3725
3689 3726 .. container:: verbose
3690 3727
3691 3728 Some examples:
3692 3729
3693 3730 - changesets with full descriptions and file lists::
3694 3731
3695 3732 hg log -v
3696 3733
3697 3734 - changesets ancestral to the working directory::
3698 3735
3699 3736 hg log -f
3700 3737
3701 3738 - last 10 commits on the current branch::
3702 3739
3703 3740 hg log -l 10 -b .
3704 3741
3705 3742 - changesets showing all modifications of a file, including removals::
3706 3743
3707 3744 hg log --removed file.c
3708 3745
3709 3746 - all changesets that touch a directory, with diffs, excluding merges::
3710 3747
3711 3748 hg log -Mp lib/
3712 3749
3713 3750 - all revision numbers that match a keyword::
3714 3751
3715 3752 hg log -k bug --template "{rev}\\n"
3716 3753
3717 3754 - check if a given changeset is included is a tagged release::
3718 3755
3719 3756 hg log -r "a21ccf and ancestor(1.9)"
3720 3757
3721 3758 - find all changesets by some user in a date range::
3722 3759
3723 3760 hg log -k alice -d "may 2008 to jul 2008"
3724 3761
3725 3762 - summary of all changesets after the last tag::
3726 3763
3727 3764 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3728 3765
3729 3766 See :hg:`help dates` for a list of formats valid for -d/--date.
3730 3767
3731 3768 See :hg:`help revisions` and :hg:`help revsets` for more about
3732 3769 specifying revisions.
3733 3770
3734 3771 Returns 0 on success.
3735 3772 """
3736 3773
3737 3774 matchfn = scmutil.match(repo[None], pats, opts)
3738 3775 limit = cmdutil.loglimit(opts)
3739 3776 count = 0
3740 3777
3741 3778 endrev = None
3742 3779 if opts.get('copies') and opts.get('rev'):
3743 3780 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3744 3781
3745 3782 df = False
3746 3783 if opts["date"]:
3747 3784 df = util.matchdate(opts["date"])
3748 3785
3749 3786 branches = opts.get('branch', []) + opts.get('only_branch', [])
3750 3787 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3751 3788
3752 3789 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3753 3790 def prep(ctx, fns):
3754 3791 rev = ctx.rev()
3755 3792 parents = [p for p in repo.changelog.parentrevs(rev)
3756 3793 if p != nullrev]
3757 3794 if opts.get('no_merges') and len(parents) == 2:
3758 3795 return
3759 3796 if opts.get('only_merges') and len(parents) != 2:
3760 3797 return
3761 3798 if opts.get('branch') and ctx.branch() not in opts['branch']:
3762 3799 return
3763 3800 if not opts.get('hidden') and ctx.hidden():
3764 3801 return
3765 3802 if df and not df(ctx.date()[0]):
3766 3803 return
3767 3804 if opts['user'] and not [k for k in opts['user']
3768 3805 if k.lower() in ctx.user().lower()]:
3769 3806 return
3770 3807 if opts.get('keyword'):
3771 3808 for k in [kw.lower() for kw in opts['keyword']]:
3772 3809 if (k in ctx.user().lower() or
3773 3810 k in ctx.description().lower() or
3774 3811 k in " ".join(ctx.files()).lower()):
3775 3812 break
3776 3813 else:
3777 3814 return
3778 3815
3779 3816 copies = None
3780 3817 if opts.get('copies') and rev:
3781 3818 copies = []
3782 3819 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3783 3820 for fn in ctx.files():
3784 3821 rename = getrenamed(fn, rev)
3785 3822 if rename:
3786 3823 copies.append((fn, rename[0]))
3787 3824
3788 3825 revmatchfn = None
3789 3826 if opts.get('patch') or opts.get('stat'):
3790 3827 if opts.get('follow') or opts.get('follow_first'):
3791 3828 # note: this might be wrong when following through merges
3792 3829 revmatchfn = scmutil.match(repo[None], fns, default='path')
3793 3830 else:
3794 3831 revmatchfn = matchfn
3795 3832
3796 3833 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3797 3834
3798 3835 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3799 3836 if count == limit:
3800 3837 break
3801 3838 if displayer.flush(ctx.rev()):
3802 3839 count += 1
3803 3840 displayer.close()
3804 3841
3805 3842 @command('manifest',
3806 3843 [('r', 'rev', '', _('revision to display'), _('REV')),
3807 3844 ('', 'all', False, _("list files from all revisions"))],
3808 3845 _('[-r REV]'))
3809 3846 def manifest(ui, repo, node=None, rev=None, **opts):
3810 3847 """output the current or given revision of the project manifest
3811 3848
3812 3849 Print a list of version controlled files for the given revision.
3813 3850 If no revision is given, the first parent of the working directory
3814 3851 is used, or the null revision if no revision is checked out.
3815 3852
3816 3853 With -v, print file permissions, symlink and executable bits.
3817 3854 With --debug, print file revision hashes.
3818 3855
3819 3856 If option --all is specified, the list of all files from all revisions
3820 3857 is printed. This includes deleted and renamed files.
3821 3858
3822 3859 Returns 0 on success.
3823 3860 """
3824 3861 if opts.get('all'):
3825 3862 if rev or node:
3826 3863 raise util.Abort(_("can't specify a revision with --all"))
3827 3864
3828 3865 res = []
3829 3866 prefix = "data/"
3830 3867 suffix = ".i"
3831 3868 plen = len(prefix)
3832 3869 slen = len(suffix)
3833 3870 lock = repo.lock()
3834 3871 try:
3835 3872 for fn, b, size in repo.store.datafiles():
3836 3873 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3837 3874 res.append(fn[plen:-slen])
3838 3875 finally:
3839 3876 lock.release()
3840 3877 for f in sorted(res):
3841 3878 ui.write("%s\n" % f)
3842 3879 return
3843 3880
3844 3881 if rev and node:
3845 3882 raise util.Abort(_("please specify just one revision"))
3846 3883
3847 3884 if not node:
3848 3885 node = rev
3849 3886
3850 3887 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3851 3888 ctx = scmutil.revsingle(repo, node)
3852 3889 for f in ctx:
3853 3890 if ui.debugflag:
3854 3891 ui.write("%40s " % hex(ctx.manifest()[f]))
3855 3892 if ui.verbose:
3856 3893 ui.write(decor[ctx.flags(f)])
3857 3894 ui.write("%s\n" % f)
3858 3895
3859 3896 @command('^merge',
3860 3897 [('f', 'force', None, _('force a merge with outstanding changes')),
3861 3898 ('r', 'rev', '', _('revision to merge'), _('REV')),
3862 3899 ('P', 'preview', None,
3863 3900 _('review revisions to merge (no merge is performed)'))
3864 3901 ] + mergetoolopts,
3865 3902 _('[-P] [-f] [[-r] REV]'))
3866 3903 def merge(ui, repo, node=None, **opts):
3867 3904 """merge working directory with another revision
3868 3905
3869 3906 The current working directory is updated with all changes made in
3870 3907 the requested revision since the last common predecessor revision.
3871 3908
3872 3909 Files that changed between either parent are marked as changed for
3873 3910 the next commit and a commit must be performed before any further
3874 3911 updates to the repository are allowed. The next commit will have
3875 3912 two parents.
3876 3913
3877 3914 ``--tool`` can be used to specify the merge tool used for file
3878 3915 merges. It overrides the HGMERGE environment variable and your
3879 3916 configuration files. See :hg:`help merge-tools` for options.
3880 3917
3881 3918 If no revision is specified, the working directory's parent is a
3882 3919 head revision, and the current branch contains exactly one other
3883 3920 head, the other head is merged with by default. Otherwise, an
3884 3921 explicit revision with which to merge with must be provided.
3885 3922
3886 3923 :hg:`resolve` must be used to resolve unresolved files.
3887 3924
3888 3925 To undo an uncommitted merge, use :hg:`update --clean .` which
3889 3926 will check out a clean copy of the original merge parent, losing
3890 3927 all changes.
3891 3928
3892 3929 Returns 0 on success, 1 if there are unresolved files.
3893 3930 """
3894 3931
3895 3932 if opts.get('rev') and node:
3896 3933 raise util.Abort(_("please specify just one revision"))
3897 3934 if not node:
3898 3935 node = opts.get('rev')
3899 3936
3900 3937 if not node:
3901 3938 branch = repo[None].branch()
3902 3939 bheads = repo.branchheads(branch)
3903 3940 if len(bheads) > 2:
3904 3941 raise util.Abort(_("branch '%s' has %d heads - "
3905 3942 "please merge with an explicit rev")
3906 3943 % (branch, len(bheads)),
3907 3944 hint=_("run 'hg heads .' to see heads"))
3908 3945
3909 3946 parent = repo.dirstate.p1()
3910 3947 if len(bheads) == 1:
3911 3948 if len(repo.heads()) > 1:
3912 3949 raise util.Abort(_("branch '%s' has one head - "
3913 3950 "please merge with an explicit rev")
3914 3951 % branch,
3915 3952 hint=_("run 'hg heads' to see all heads"))
3916 3953 msg = _('there is nothing to merge')
3917 3954 if parent != repo.lookup(repo[None].branch()):
3918 3955 msg = _('%s - use "hg update" instead') % msg
3919 3956 raise util.Abort(msg)
3920 3957
3921 3958 if parent not in bheads:
3922 3959 raise util.Abort(_('working directory not at a head revision'),
3923 3960 hint=_("use 'hg update' or merge with an "
3924 3961 "explicit revision"))
3925 3962 node = parent == bheads[0] and bheads[-1] or bheads[0]
3926 3963 else:
3927 3964 node = scmutil.revsingle(repo, node).node()
3928 3965
3929 3966 if opts.get('preview'):
3930 3967 # find nodes that are ancestors of p2 but not of p1
3931 3968 p1 = repo.lookup('.')
3932 3969 p2 = repo.lookup(node)
3933 3970 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3934 3971
3935 3972 displayer = cmdutil.show_changeset(ui, repo, opts)
3936 3973 for node in nodes:
3937 3974 displayer.show(repo[node])
3938 3975 displayer.close()
3939 3976 return 0
3940 3977
3941 3978 try:
3942 3979 # ui.forcemerge is an internal variable, do not document
3943 3980 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3944 3981 return hg.merge(repo, node, force=opts.get('force'))
3945 3982 finally:
3946 3983 ui.setconfig('ui', 'forcemerge', '')
3947 3984
3948 3985 @command('outgoing|out',
3949 3986 [('f', 'force', None, _('run even when the destination is unrelated')),
3950 3987 ('r', 'rev', [],
3951 3988 _('a changeset intended to be included in the destination'), _('REV')),
3952 3989 ('n', 'newest-first', None, _('show newest record first')),
3953 3990 ('B', 'bookmarks', False, _('compare bookmarks')),
3954 3991 ('b', 'branch', [], _('a specific branch you would like to push'),
3955 3992 _('BRANCH')),
3956 3993 ] + logopts + remoteopts + subrepoopts,
3957 3994 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3958 3995 def outgoing(ui, repo, dest=None, **opts):
3959 3996 """show changesets not found in the destination
3960 3997
3961 3998 Show changesets not found in the specified destination repository
3962 3999 or the default push location. These are the changesets that would
3963 4000 be pushed if a push was requested.
3964 4001
3965 4002 See pull for details of valid destination formats.
3966 4003
3967 4004 Returns 0 if there are outgoing changes, 1 otherwise.
3968 4005 """
3969 4006
3970 4007 if opts.get('bookmarks'):
3971 4008 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3972 4009 dest, branches = hg.parseurl(dest, opts.get('branch'))
3973 4010 other = hg.peer(repo, opts, dest)
3974 4011 if 'bookmarks' not in other.listkeys('namespaces'):
3975 4012 ui.warn(_("remote doesn't support bookmarks\n"))
3976 4013 return 0
3977 4014 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3978 4015 return bookmarks.diff(ui, other, repo)
3979 4016
3980 4017 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3981 4018 try:
3982 4019 return hg.outgoing(ui, repo, dest, opts)
3983 4020 finally:
3984 4021 del repo._subtoppath
3985 4022
3986 4023 @command('parents',
3987 4024 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3988 4025 ] + templateopts,
3989 4026 _('[-r REV] [FILE]'))
3990 4027 def parents(ui, repo, file_=None, **opts):
3991 4028 """show the parents of the working directory or revision
3992 4029
3993 4030 Print the working directory's parent revisions. If a revision is
3994 4031 given via -r/--rev, the parent of that revision will be printed.
3995 4032 If a file argument is given, the revision in which the file was
3996 4033 last changed (before the working directory revision or the
3997 4034 argument to --rev if given) is printed.
3998 4035
3999 4036 Returns 0 on success.
4000 4037 """
4001 4038
4002 4039 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4003 4040
4004 4041 if file_:
4005 4042 m = scmutil.match(ctx, (file_,), opts)
4006 4043 if m.anypats() or len(m.files()) != 1:
4007 4044 raise util.Abort(_('can only specify an explicit filename'))
4008 4045 file_ = m.files()[0]
4009 4046 filenodes = []
4010 4047 for cp in ctx.parents():
4011 4048 if not cp:
4012 4049 continue
4013 4050 try:
4014 4051 filenodes.append(cp.filenode(file_))
4015 4052 except error.LookupError:
4016 4053 pass
4017 4054 if not filenodes:
4018 4055 raise util.Abort(_("'%s' not found in manifest!") % file_)
4019 4056 fl = repo.file(file_)
4020 4057 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4021 4058 else:
4022 4059 p = [cp.node() for cp in ctx.parents()]
4023 4060
4024 4061 displayer = cmdutil.show_changeset(ui, repo, opts)
4025 4062 for n in p:
4026 4063 if n != nullid:
4027 4064 displayer.show(repo[n])
4028 4065 displayer.close()
4029 4066
4030 4067 @command('paths', [], _('[NAME]'))
4031 4068 def paths(ui, repo, search=None):
4032 4069 """show aliases for remote repositories
4033 4070
4034 4071 Show definition of symbolic path name NAME. If no name is given,
4035 4072 show definition of all available names.
4036 4073
4037 4074 Option -q/--quiet suppresses all output when searching for NAME
4038 4075 and shows only the path names when listing all definitions.
4039 4076
4040 4077 Path names are defined in the [paths] section of your
4041 4078 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4042 4079 repository, ``.hg/hgrc`` is used, too.
4043 4080
4044 4081 The path names ``default`` and ``default-push`` have a special
4045 4082 meaning. When performing a push or pull operation, they are used
4046 4083 as fallbacks if no location is specified on the command-line.
4047 4084 When ``default-push`` is set, it will be used for push and
4048 4085 ``default`` will be used for pull; otherwise ``default`` is used
4049 4086 as the fallback for both. When cloning a repository, the clone
4050 4087 source is written as ``default`` in ``.hg/hgrc``. Note that
4051 4088 ``default`` and ``default-push`` apply to all inbound (e.g.
4052 4089 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4053 4090 :hg:`bundle`) operations.
4054 4091
4055 4092 See :hg:`help urls` for more information.
4056 4093
4057 4094 Returns 0 on success.
4058 4095 """
4059 4096 if search:
4060 4097 for name, path in ui.configitems("paths"):
4061 4098 if name == search:
4062 4099 ui.status("%s\n" % util.hidepassword(path))
4063 4100 return
4064 4101 if not ui.quiet:
4065 4102 ui.warn(_("not found!\n"))
4066 4103 return 1
4067 4104 else:
4068 4105 for name, path in ui.configitems("paths"):
4069 4106 if ui.quiet:
4070 4107 ui.write("%s\n" % name)
4071 4108 else:
4072 4109 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4073 4110
4074 4111 def postincoming(ui, repo, modheads, optupdate, checkout):
4075 4112 if modheads == 0:
4076 4113 return
4077 4114 if optupdate:
4078 4115 try:
4079 4116 return hg.update(repo, checkout)
4080 4117 except util.Abort, inst:
4081 4118 ui.warn(_("not updating: %s\n" % str(inst)))
4082 4119 return 0
4083 4120 if modheads > 1:
4084 4121 currentbranchheads = len(repo.branchheads())
4085 4122 if currentbranchheads == modheads:
4086 4123 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4087 4124 elif currentbranchheads > 1:
4088 4125 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
4089 4126 else:
4090 4127 ui.status(_("(run 'hg heads' to see heads)\n"))
4091 4128 else:
4092 4129 ui.status(_("(run 'hg update' to get a working copy)\n"))
4093 4130
4094 4131 @command('^pull',
4095 4132 [('u', 'update', None,
4096 4133 _('update to new branch head if changesets were pulled')),
4097 4134 ('f', 'force', None, _('run even when remote repository is unrelated')),
4098 4135 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4099 4136 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4100 4137 ('b', 'branch', [], _('a specific branch you would like to pull'),
4101 4138 _('BRANCH')),
4102 4139 ] + remoteopts,
4103 4140 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4104 4141 def pull(ui, repo, source="default", **opts):
4105 4142 """pull changes from the specified source
4106 4143
4107 4144 Pull changes from a remote repository to a local one.
4108 4145
4109 4146 This finds all changes from the repository at the specified path
4110 4147 or URL and adds them to a local repository (the current one unless
4111 4148 -R is specified). By default, this does not update the copy of the
4112 4149 project in the working directory.
4113 4150
4114 4151 Use :hg:`incoming` if you want to see what would have been added
4115 4152 by a pull at the time you issued this command. If you then decide
4116 4153 to add those changes to the repository, you should use :hg:`pull
4117 4154 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4118 4155
4119 4156 If SOURCE is omitted, the 'default' path will be used.
4120 4157 See :hg:`help urls` for more information.
4121 4158
4122 4159 Returns 0 on success, 1 if an update had unresolved files.
4123 4160 """
4124 4161 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4125 4162 other = hg.peer(repo, opts, source)
4126 4163 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4127 4164 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4128 4165
4129 4166 if opts.get('bookmark'):
4130 4167 if not revs:
4131 4168 revs = []
4132 4169 rb = other.listkeys('bookmarks')
4133 4170 for b in opts['bookmark']:
4134 4171 if b not in rb:
4135 4172 raise util.Abort(_('remote bookmark %s not found!') % b)
4136 4173 revs.append(rb[b])
4137 4174
4138 4175 if revs:
4139 4176 try:
4140 4177 revs = [other.lookup(rev) for rev in revs]
4141 4178 except error.CapabilityError:
4142 4179 err = _("other repository doesn't support revision lookup, "
4143 4180 "so a rev cannot be specified.")
4144 4181 raise util.Abort(err)
4145 4182
4146 4183 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4147 4184 bookmarks.updatefromremote(ui, repo, other)
4148 4185 if checkout:
4149 4186 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4150 4187 repo._subtoppath = source
4151 4188 try:
4152 4189 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4153 4190
4154 4191 finally:
4155 4192 del repo._subtoppath
4156 4193
4157 4194 # update specified bookmarks
4158 4195 if opts.get('bookmark'):
4159 4196 for b in opts['bookmark']:
4160 4197 # explicit pull overrides local bookmark if any
4161 4198 ui.status(_("importing bookmark %s\n") % b)
4162 4199 repo._bookmarks[b] = repo[rb[b]].node()
4163 4200 bookmarks.write(repo)
4164 4201
4165 4202 return ret
4166 4203
4167 4204 @command('^push',
4168 4205 [('f', 'force', None, _('force push')),
4169 4206 ('r', 'rev', [],
4170 4207 _('a changeset intended to be included in the destination'),
4171 4208 _('REV')),
4172 4209 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4173 4210 ('b', 'branch', [],
4174 4211 _('a specific branch you would like to push'), _('BRANCH')),
4175 4212 ('', 'new-branch', False, _('allow pushing a new branch')),
4176 4213 ] + remoteopts,
4177 4214 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4178 4215 def push(ui, repo, dest=None, **opts):
4179 4216 """push changes to the specified destination
4180 4217
4181 4218 Push changesets from the local repository to the specified
4182 4219 destination.
4183 4220
4184 4221 This operation is symmetrical to pull: it is identical to a pull
4185 4222 in the destination repository from the current one.
4186 4223
4187 4224 By default, push will not allow creation of new heads at the
4188 4225 destination, since multiple heads would make it unclear which head
4189 4226 to use. In this situation, it is recommended to pull and merge
4190 4227 before pushing.
4191 4228
4192 4229 Use --new-branch if you want to allow push to create a new named
4193 4230 branch that is not present at the destination. This allows you to
4194 4231 only create a new branch without forcing other changes.
4195 4232
4196 4233 Use -f/--force to override the default behavior and push all
4197 4234 changesets on all branches.
4198 4235
4199 4236 If -r/--rev is used, the specified revision and all its ancestors
4200 4237 will be pushed to the remote repository.
4201 4238
4202 4239 Please see :hg:`help urls` for important details about ``ssh://``
4203 4240 URLs. If DESTINATION is omitted, a default path will be used.
4204 4241
4205 4242 Returns 0 if push was successful, 1 if nothing to push.
4206 4243 """
4207 4244
4208 4245 if opts.get('bookmark'):
4209 4246 for b in opts['bookmark']:
4210 4247 # translate -B options to -r so changesets get pushed
4211 4248 if b in repo._bookmarks:
4212 4249 opts.setdefault('rev', []).append(b)
4213 4250 else:
4214 4251 # if we try to push a deleted bookmark, translate it to null
4215 4252 # this lets simultaneous -r, -b options continue working
4216 4253 opts.setdefault('rev', []).append("null")
4217 4254
4218 4255 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4219 4256 dest, branches = hg.parseurl(dest, opts.get('branch'))
4220 4257 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4221 4258 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4222 4259 other = hg.peer(repo, opts, dest)
4223 4260 if revs:
4224 4261 revs = [repo.lookup(rev) for rev in revs]
4225 4262
4226 4263 repo._subtoppath = dest
4227 4264 try:
4228 4265 # push subrepos depth-first for coherent ordering
4229 4266 c = repo['']
4230 4267 subs = c.substate # only repos that are committed
4231 4268 for s in sorted(subs):
4232 4269 if not c.sub(s).push(opts.get('force')):
4233 4270 return False
4234 4271 finally:
4235 4272 del repo._subtoppath
4236 4273 result = repo.push(other, opts.get('force'), revs=revs,
4237 4274 newbranch=opts.get('new_branch'))
4238 4275
4239 4276 result = (result == 0)
4240 4277
4241 4278 if opts.get('bookmark'):
4242 4279 rb = other.listkeys('bookmarks')
4243 4280 for b in opts['bookmark']:
4244 4281 # explicit push overrides remote bookmark if any
4245 4282 if b in repo._bookmarks:
4246 4283 ui.status(_("exporting bookmark %s\n") % b)
4247 4284 new = repo[b].hex()
4248 4285 elif b in rb:
4249 4286 ui.status(_("deleting remote bookmark %s\n") % b)
4250 4287 new = '' # delete
4251 4288 else:
4252 4289 ui.warn(_('bookmark %s does not exist on the local '
4253 4290 'or remote repository!\n') % b)
4254 4291 return 2
4255 4292 old = rb.get(b, '')
4256 4293 r = other.pushkey('bookmarks', b, old, new)
4257 4294 if not r:
4258 4295 ui.warn(_('updating bookmark %s failed!\n') % b)
4259 4296 if not result:
4260 4297 result = 2
4261 4298
4262 4299 return result
4263 4300
4264 4301 @command('recover', [])
4265 4302 def recover(ui, repo):
4266 4303 """roll back an interrupted transaction
4267 4304
4268 4305 Recover from an interrupted commit or pull.
4269 4306
4270 4307 This command tries to fix the repository status after an
4271 4308 interrupted operation. It should only be necessary when Mercurial
4272 4309 suggests it.
4273 4310
4274 4311 Returns 0 if successful, 1 if nothing to recover or verify fails.
4275 4312 """
4276 4313 if repo.recover():
4277 4314 return hg.verify(repo)
4278 4315 return 1
4279 4316
4280 4317 @command('^remove|rm',
4281 4318 [('A', 'after', None, _('record delete for missing files')),
4282 4319 ('f', 'force', None,
4283 4320 _('remove (and delete) file even if added or modified')),
4284 4321 ] + walkopts,
4285 4322 _('[OPTION]... FILE...'))
4286 4323 def remove(ui, repo, *pats, **opts):
4287 4324 """remove the specified files on the next commit
4288 4325
4289 4326 Schedule the indicated files for removal from the current branch.
4290 4327
4291 4328 This command schedules the files to be removed at the next commit.
4292 4329 To undo a remove before that, see :hg:`revert`. To undo added
4293 4330 files, see :hg:`forget`.
4294 4331
4295 4332 .. container:: verbose
4296 4333
4297 4334 -A/--after can be used to remove only files that have already
4298 4335 been deleted, -f/--force can be used to force deletion, and -Af
4299 4336 can be used to remove files from the next revision without
4300 4337 deleting them from the working directory.
4301 4338
4302 4339 The following table details the behavior of remove for different
4303 4340 file states (columns) and option combinations (rows). The file
4304 4341 states are Added [A], Clean [C], Modified [M] and Missing [!]
4305 4342 (as reported by :hg:`status`). The actions are Warn, Remove
4306 4343 (from branch) and Delete (from disk):
4307 4344
4308 4345 ======= == == == ==
4309 4346 A C M !
4310 4347 ======= == == == ==
4311 4348 none W RD W R
4312 4349 -f R RD RD R
4313 4350 -A W W W R
4314 4351 -Af R R R R
4315 4352 ======= == == == ==
4316 4353
4317 4354 Note that remove never deletes files in Added [A] state from the
4318 4355 working directory, not even if option --force is specified.
4319 4356
4320 4357 Returns 0 on success, 1 if any warnings encountered.
4321 4358 """
4322 4359
4323 4360 ret = 0
4324 4361 after, force = opts.get('after'), opts.get('force')
4325 4362 if not pats and not after:
4326 4363 raise util.Abort(_('no files specified'))
4327 4364
4328 4365 m = scmutil.match(repo[None], pats, opts)
4329 4366 s = repo.status(match=m, clean=True)
4330 4367 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4331 4368
4332 4369 for f in m.files():
4333 4370 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4334 4371 if os.path.exists(m.rel(f)):
4335 4372 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4336 4373 ret = 1
4337 4374
4338 4375 if force:
4339 4376 list = modified + deleted + clean + added
4340 4377 elif after:
4341 4378 list = deleted
4342 4379 for f in modified + added + clean:
4343 4380 ui.warn(_('not removing %s: file still exists (use -f'
4344 4381 ' to force removal)\n') % m.rel(f))
4345 4382 ret = 1
4346 4383 else:
4347 4384 list = deleted + clean
4348 4385 for f in modified:
4349 4386 ui.warn(_('not removing %s: file is modified (use -f'
4350 4387 ' to force removal)\n') % m.rel(f))
4351 4388 ret = 1
4352 4389 for f in added:
4353 4390 ui.warn(_('not removing %s: file has been marked for add'
4354 4391 ' (use forget to undo)\n') % m.rel(f))
4355 4392 ret = 1
4356 4393
4357 4394 for f in sorted(list):
4358 4395 if ui.verbose or not m.exact(f):
4359 4396 ui.status(_('removing %s\n') % m.rel(f))
4360 4397
4361 4398 wlock = repo.wlock()
4362 4399 try:
4363 4400 if not after:
4364 4401 for f in list:
4365 4402 if f in added:
4366 4403 continue # we never unlink added files on remove
4367 4404 try:
4368 4405 util.unlinkpath(repo.wjoin(f))
4369 4406 except OSError, inst:
4370 4407 if inst.errno != errno.ENOENT:
4371 4408 raise
4372 4409 repo[None].forget(list)
4373 4410 finally:
4374 4411 wlock.release()
4375 4412
4376 4413 return ret
4377 4414
4378 4415 @command('rename|move|mv',
4379 4416 [('A', 'after', None, _('record a rename that has already occurred')),
4380 4417 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4381 4418 ] + walkopts + dryrunopts,
4382 4419 _('[OPTION]... SOURCE... DEST'))
4383 4420 def rename(ui, repo, *pats, **opts):
4384 4421 """rename files; equivalent of copy + remove
4385 4422
4386 4423 Mark dest as copies of sources; mark sources for deletion. If dest
4387 4424 is a directory, copies are put in that directory. If dest is a
4388 4425 file, there can only be one source.
4389 4426
4390 4427 By default, this command copies the contents of files as they
4391 4428 exist in the working directory. If invoked with -A/--after, the
4392 4429 operation is recorded, but no copying is performed.
4393 4430
4394 4431 This command takes effect at the next commit. To undo a rename
4395 4432 before that, see :hg:`revert`.
4396 4433
4397 4434 Returns 0 on success, 1 if errors are encountered.
4398 4435 """
4399 4436 wlock = repo.wlock(False)
4400 4437 try:
4401 4438 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4402 4439 finally:
4403 4440 wlock.release()
4404 4441
4405 4442 @command('resolve',
4406 4443 [('a', 'all', None, _('select all unresolved files')),
4407 4444 ('l', 'list', None, _('list state of files needing merge')),
4408 4445 ('m', 'mark', None, _('mark files as resolved')),
4409 4446 ('u', 'unmark', None, _('mark files as unresolved')),
4410 4447 ('n', 'no-status', None, _('hide status prefix'))]
4411 4448 + mergetoolopts + walkopts,
4412 4449 _('[OPTION]... [FILE]...'))
4413 4450 def resolve(ui, repo, *pats, **opts):
4414 4451 """redo merges or set/view the merge status of files
4415 4452
4416 4453 Merges with unresolved conflicts are often the result of
4417 4454 non-interactive merging using the ``internal:merge`` configuration
4418 4455 setting, or a command-line merge tool like ``diff3``. The resolve
4419 4456 command is used to manage the files involved in a merge, after
4420 4457 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4421 4458 working directory must have two parents).
4422 4459
4423 4460 The resolve command can be used in the following ways:
4424 4461
4425 4462 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4426 4463 files, discarding any previous merge attempts. Re-merging is not
4427 4464 performed for files already marked as resolved. Use ``--all/-a``
4428 4465 to select all unresolved files. ``--tool`` can be used to specify
4429 4466 the merge tool used for the given files. It overrides the HGMERGE
4430 4467 environment variable and your configuration files. Previous file
4431 4468 contents are saved with a ``.orig`` suffix.
4432 4469
4433 4470 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4434 4471 (e.g. after having manually fixed-up the files). The default is
4435 4472 to mark all unresolved files.
4436 4473
4437 4474 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4438 4475 default is to mark all resolved files.
4439 4476
4440 4477 - :hg:`resolve -l`: list files which had or still have conflicts.
4441 4478 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4442 4479
4443 4480 Note that Mercurial will not let you commit files with unresolved
4444 4481 merge conflicts. You must use :hg:`resolve -m ...` before you can
4445 4482 commit after a conflicting merge.
4446 4483
4447 4484 Returns 0 on success, 1 if any files fail a resolve attempt.
4448 4485 """
4449 4486
4450 4487 all, mark, unmark, show, nostatus = \
4451 4488 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4452 4489
4453 4490 if (show and (mark or unmark)) or (mark and unmark):
4454 4491 raise util.Abort(_("too many options specified"))
4455 4492 if pats and all:
4456 4493 raise util.Abort(_("can't specify --all and patterns"))
4457 4494 if not (all or pats or show or mark or unmark):
4458 4495 raise util.Abort(_('no files or directories specified; '
4459 4496 'use --all to remerge all files'))
4460 4497
4461 4498 ms = mergemod.mergestate(repo)
4462 4499 m = scmutil.match(repo[None], pats, opts)
4463 4500 ret = 0
4464 4501
4465 4502 for f in ms:
4466 4503 if m(f):
4467 4504 if show:
4468 4505 if nostatus:
4469 4506 ui.write("%s\n" % f)
4470 4507 else:
4471 4508 ui.write("%s %s\n" % (ms[f].upper(), f),
4472 4509 label='resolve.' +
4473 4510 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4474 4511 elif mark:
4475 4512 ms.mark(f, "r")
4476 4513 elif unmark:
4477 4514 ms.mark(f, "u")
4478 4515 else:
4479 4516 wctx = repo[None]
4480 4517 mctx = wctx.parents()[-1]
4481 4518
4482 4519 # backup pre-resolve (merge uses .orig for its own purposes)
4483 4520 a = repo.wjoin(f)
4484 4521 util.copyfile(a, a + ".resolve")
4485 4522
4486 4523 try:
4487 4524 # resolve file
4488 4525 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4489 4526 if ms.resolve(f, wctx, mctx):
4490 4527 ret = 1
4491 4528 finally:
4492 4529 ui.setconfig('ui', 'forcemerge', '')
4493 4530
4494 4531 # replace filemerge's .orig file with our resolve file
4495 4532 util.rename(a + ".resolve", a + ".orig")
4496 4533
4497 4534 ms.commit()
4498 4535 return ret
4499 4536
4500 4537 @command('revert',
4501 4538 [('a', 'all', None, _('revert all changes when no arguments given')),
4502 4539 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4503 4540 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4504 4541 ('C', 'no-backup', None, _('do not save backup copies of files')),
4505 4542 ] + walkopts + dryrunopts,
4506 4543 _('[OPTION]... [-r REV] [NAME]...'))
4507 4544 def revert(ui, repo, *pats, **opts):
4508 4545 """restore files to their checkout state
4509 4546
4510 4547 .. note::
4511 4548 To check out earlier revisions, you should use :hg:`update REV`.
4512 4549 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4513 4550
4514 4551 With no revision specified, revert the specified files or directories
4515 4552 to the contents they had in the parent of the working directory.
4516 4553 This restores the contents of files to an unmodified
4517 4554 state and unschedules adds, removes, copies, and renames. If the
4518 4555 working directory has two parents, you must explicitly specify a
4519 4556 revision.
4520 4557
4521 4558 Using the -r/--rev or -d/--date options, revert the given files or
4522 4559 directories to their states as of a specific revision. Because
4523 4560 revert does not change the working directory parents, this will
4524 4561 cause these files to appear modified. This can be helpful to "back
4525 4562 out" some or all of an earlier change. See :hg:`backout` for a
4526 4563 related method.
4527 4564
4528 4565 Modified files are saved with a .orig suffix before reverting.
4529 4566 To disable these backups, use --no-backup.
4530 4567
4531 4568 See :hg:`help dates` for a list of formats valid for -d/--date.
4532 4569
4533 4570 Returns 0 on success.
4534 4571 """
4535 4572
4536 4573 if opts.get("date"):
4537 4574 if opts.get("rev"):
4538 4575 raise util.Abort(_("you can't specify a revision and a date"))
4539 4576 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4540 4577
4541 4578 parent, p2 = repo.dirstate.parents()
4542 4579 if not opts.get('rev') and p2 != nullid:
4543 4580 # revert after merge is a trap for new users (issue2915)
4544 4581 raise util.Abort(_('uncommitted merge with no revision specified'),
4545 4582 hint=_('use "hg update" or see "hg help revert"'))
4546 4583
4547 4584 ctx = scmutil.revsingle(repo, opts.get('rev'))
4548 4585 node = ctx.node()
4549 4586
4550 4587 if not pats and not opts.get('all'):
4551 4588 msg = _("no files or directories specified")
4552 4589 if p2 != nullid:
4553 4590 hint = _("uncommitted merge, use --all to discard all changes,"
4554 4591 " or 'hg update -C .' to abort the merge")
4555 4592 raise util.Abort(msg, hint=hint)
4556 4593 dirty = util.any(repo.status())
4557 4594 if node != parent:
4558 4595 if dirty:
4559 4596 hint = _("uncommitted changes, use --all to discard all"
4560 4597 " changes, or 'hg update %s' to update") % ctx.rev()
4561 4598 else:
4562 4599 hint = _("use --all to revert all files,"
4563 4600 " or 'hg update %s' to update") % ctx.rev()
4564 4601 elif dirty:
4565 4602 hint = _("uncommitted changes, use --all to discard all changes")
4566 4603 else:
4567 4604 hint = _("use --all to revert all files")
4568 4605 raise util.Abort(msg, hint=hint)
4569 4606
4570 4607 mf = ctx.manifest()
4571 4608 if node == parent:
4572 4609 pmf = mf
4573 4610 else:
4574 4611 pmf = None
4575 4612
4576 4613 # need all matching names in dirstate and manifest of target rev,
4577 4614 # so have to walk both. do not print errors if files exist in one
4578 4615 # but not other.
4579 4616
4580 4617 names = {}
4581 4618
4582 4619 wlock = repo.wlock()
4583 4620 try:
4584 4621 # walk dirstate.
4585 4622
4586 4623 m = scmutil.match(repo[None], pats, opts)
4587 4624 m.bad = lambda x, y: False
4588 4625 for abs in repo.walk(m):
4589 4626 names[abs] = m.rel(abs), m.exact(abs)
4590 4627
4591 4628 # walk target manifest.
4592 4629
4593 4630 def badfn(path, msg):
4594 4631 if path in names:
4595 4632 return
4596 4633 path_ = path + '/'
4597 4634 for f in names:
4598 4635 if f.startswith(path_):
4599 4636 return
4600 4637 ui.warn("%s: %s\n" % (m.rel(path), msg))
4601 4638
4602 4639 m = scmutil.match(repo[node], pats, opts)
4603 4640 m.bad = badfn
4604 4641 for abs in repo[node].walk(m):
4605 4642 if abs not in names:
4606 4643 names[abs] = m.rel(abs), m.exact(abs)
4607 4644
4608 4645 m = scmutil.matchfiles(repo, names)
4609 4646 changes = repo.status(match=m)[:4]
4610 4647 modified, added, removed, deleted = map(set, changes)
4611 4648
4612 4649 # if f is a rename, also revert the source
4613 4650 cwd = repo.getcwd()
4614 4651 for f in added:
4615 4652 src = repo.dirstate.copied(f)
4616 4653 if src and src not in names and repo.dirstate[src] == 'r':
4617 4654 removed.add(src)
4618 4655 names[src] = (repo.pathto(src, cwd), True)
4619 4656
4620 4657 def removeforget(abs):
4621 4658 if repo.dirstate[abs] == 'a':
4622 4659 return _('forgetting %s\n')
4623 4660 return _('removing %s\n')
4624 4661
4625 4662 revert = ([], _('reverting %s\n'))
4626 4663 add = ([], _('adding %s\n'))
4627 4664 remove = ([], removeforget)
4628 4665 undelete = ([], _('undeleting %s\n'))
4629 4666
4630 4667 disptable = (
4631 4668 # dispatch table:
4632 4669 # file state
4633 4670 # action if in target manifest
4634 4671 # action if not in target manifest
4635 4672 # make backup if in target manifest
4636 4673 # make backup if not in target manifest
4637 4674 (modified, revert, remove, True, True),
4638 4675 (added, revert, remove, True, False),
4639 4676 (removed, undelete, None, False, False),
4640 4677 (deleted, revert, remove, False, False),
4641 4678 )
4642 4679
4643 4680 for abs, (rel, exact) in sorted(names.items()):
4644 4681 mfentry = mf.get(abs)
4645 4682 target = repo.wjoin(abs)
4646 4683 def handle(xlist, dobackup):
4647 4684 xlist[0].append(abs)
4648 4685 if (dobackup and not opts.get('no_backup') and
4649 4686 os.path.lexists(target)):
4650 4687 bakname = "%s.orig" % rel
4651 4688 ui.note(_('saving current version of %s as %s\n') %
4652 4689 (rel, bakname))
4653 4690 if not opts.get('dry_run'):
4654 4691 util.rename(target, bakname)
4655 4692 if ui.verbose or not exact:
4656 4693 msg = xlist[1]
4657 4694 if not isinstance(msg, basestring):
4658 4695 msg = msg(abs)
4659 4696 ui.status(msg % rel)
4660 4697 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4661 4698 if abs not in table:
4662 4699 continue
4663 4700 # file has changed in dirstate
4664 4701 if mfentry:
4665 4702 handle(hitlist, backuphit)
4666 4703 elif misslist is not None:
4667 4704 handle(misslist, backupmiss)
4668 4705 break
4669 4706 else:
4670 4707 if abs not in repo.dirstate:
4671 4708 if mfentry:
4672 4709 handle(add, True)
4673 4710 elif exact:
4674 4711 ui.warn(_('file not managed: %s\n') % rel)
4675 4712 continue
4676 4713 # file has not changed in dirstate
4677 4714 if node == parent:
4678 4715 if exact:
4679 4716 ui.warn(_('no changes needed to %s\n') % rel)
4680 4717 continue
4681 4718 if pmf is None:
4682 4719 # only need parent manifest in this unlikely case,
4683 4720 # so do not read by default
4684 4721 pmf = repo[parent].manifest()
4685 4722 if abs in pmf:
4686 4723 if mfentry:
4687 4724 # if version of file is same in parent and target
4688 4725 # manifests, do nothing
4689 4726 if (pmf[abs] != mfentry or
4690 4727 pmf.flags(abs) != mf.flags(abs)):
4691 4728 handle(revert, False)
4692 4729 else:
4693 4730 handle(remove, False)
4694 4731
4695 4732 if not opts.get('dry_run'):
4696 4733 def checkout(f):
4697 4734 fc = ctx[f]
4698 4735 repo.wwrite(f, fc.data(), fc.flags())
4699 4736
4700 4737 audit_path = scmutil.pathauditor(repo.root)
4701 4738 for f in remove[0]:
4702 4739 if repo.dirstate[f] == 'a':
4703 4740 repo.dirstate.drop(f)
4704 4741 continue
4705 4742 audit_path(f)
4706 4743 try:
4707 4744 util.unlinkpath(repo.wjoin(f))
4708 4745 except OSError:
4709 4746 pass
4710 4747 repo.dirstate.remove(f)
4711 4748
4712 4749 normal = None
4713 4750 if node == parent:
4714 4751 # We're reverting to our parent. If possible, we'd like status
4715 4752 # to report the file as clean. We have to use normallookup for
4716 4753 # merges to avoid losing information about merged/dirty files.
4717 4754 if p2 != nullid:
4718 4755 normal = repo.dirstate.normallookup
4719 4756 else:
4720 4757 normal = repo.dirstate.normal
4721 4758 for f in revert[0]:
4722 4759 checkout(f)
4723 4760 if normal:
4724 4761 normal(f)
4725 4762
4726 4763 for f in add[0]:
4727 4764 checkout(f)
4728 4765 repo.dirstate.add(f)
4729 4766
4730 4767 normal = repo.dirstate.normallookup
4731 4768 if node == parent and p2 == nullid:
4732 4769 normal = repo.dirstate.normal
4733 4770 for f in undelete[0]:
4734 4771 checkout(f)
4735 4772 normal(f)
4736 4773
4737 4774 finally:
4738 4775 wlock.release()
4739 4776
4740 4777 @command('rollback', dryrunopts +
4741 4778 [('f', 'force', False, _('ignore safety measures'))])
4742 4779 def rollback(ui, repo, **opts):
4743 4780 """roll back the last transaction (dangerous)
4744 4781
4745 4782 This command should be used with care. There is only one level of
4746 4783 rollback, and there is no way to undo a rollback. It will also
4747 4784 restore the dirstate at the time of the last transaction, losing
4748 4785 any dirstate changes since that time. This command does not alter
4749 4786 the working directory.
4750 4787
4751 4788 Transactions are used to encapsulate the effects of all commands
4752 4789 that create new changesets or propagate existing changesets into a
4753 4790 repository. For example, the following commands are transactional,
4754 4791 and their effects can be rolled back:
4755 4792
4756 4793 - commit
4757 4794 - import
4758 4795 - pull
4759 4796 - push (with this repository as the destination)
4760 4797 - unbundle
4761 4798
4762 4799 It's possible to lose data with rollback: commit, update back to
4763 4800 an older changeset, and then rollback. The update removes the
4764 4801 changes you committed from the working directory, and rollback
4765 4802 removes them from history. To avoid data loss, you must pass
4766 4803 --force in this case.
4767 4804
4768 4805 This command is not intended for use on public repositories. Once
4769 4806 changes are visible for pull by other users, rolling a transaction
4770 4807 back locally is ineffective (someone else may already have pulled
4771 4808 the changes). Furthermore, a race is possible with readers of the
4772 4809 repository; for example an in-progress pull from the repository
4773 4810 may fail if a rollback is performed.
4774 4811
4775 4812 Returns 0 on success, 1 if no rollback data is available.
4776 4813 """
4777 4814 return repo.rollback(dryrun=opts.get('dry_run'),
4778 4815 force=opts.get('force'))
4779 4816
4780 4817 @command('root', [])
4781 4818 def root(ui, repo):
4782 4819 """print the root (top) of the current working directory
4783 4820
4784 4821 Print the root directory of the current repository.
4785 4822
4786 4823 Returns 0 on success.
4787 4824 """
4788 4825 ui.write(repo.root + "\n")
4789 4826
4790 4827 @command('^serve',
4791 4828 [('A', 'accesslog', '', _('name of access log file to write to'),
4792 4829 _('FILE')),
4793 4830 ('d', 'daemon', None, _('run server in background')),
4794 4831 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4795 4832 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4796 4833 # use string type, then we can check if something was passed
4797 4834 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4798 4835 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4799 4836 _('ADDR')),
4800 4837 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4801 4838 _('PREFIX')),
4802 4839 ('n', 'name', '',
4803 4840 _('name to show in web pages (default: working directory)'), _('NAME')),
4804 4841 ('', 'web-conf', '',
4805 4842 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4806 4843 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4807 4844 _('FILE')),
4808 4845 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4809 4846 ('', 'stdio', None, _('for remote clients')),
4810 4847 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4811 4848 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4812 4849 ('', 'style', '', _('template style to use'), _('STYLE')),
4813 4850 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4814 4851 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4815 4852 _('[OPTION]...'))
4816 4853 def serve(ui, repo, **opts):
4817 4854 """start stand-alone webserver
4818 4855
4819 4856 Start a local HTTP repository browser and pull server. You can use
4820 4857 this for ad-hoc sharing and browsing of repositories. It is
4821 4858 recommended to use a real web server to serve a repository for
4822 4859 longer periods of time.
4823 4860
4824 4861 Please note that the server does not implement access control.
4825 4862 This means that, by default, anybody can read from the server and
4826 4863 nobody can write to it by default. Set the ``web.allow_push``
4827 4864 option to ``*`` to allow everybody to push to the server. You
4828 4865 should use a real web server if you need to authenticate users.
4829 4866
4830 4867 By default, the server logs accesses to stdout and errors to
4831 4868 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4832 4869 files.
4833 4870
4834 4871 To have the server choose a free port number to listen on, specify
4835 4872 a port number of 0; in this case, the server will print the port
4836 4873 number it uses.
4837 4874
4838 4875 Returns 0 on success.
4839 4876 """
4840 4877
4841 4878 if opts["stdio"] and opts["cmdserver"]:
4842 4879 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4843 4880
4844 4881 def checkrepo():
4845 4882 if repo is None:
4846 4883 raise error.RepoError(_("There is no Mercurial repository here"
4847 4884 " (.hg not found)"))
4848 4885
4849 4886 if opts["stdio"]:
4850 4887 checkrepo()
4851 4888 s = sshserver.sshserver(ui, repo)
4852 4889 s.serve_forever()
4853 4890
4854 4891 if opts["cmdserver"]:
4855 4892 checkrepo()
4856 4893 s = commandserver.server(ui, repo, opts["cmdserver"])
4857 4894 return s.serve()
4858 4895
4859 4896 # this way we can check if something was given in the command-line
4860 4897 if opts.get('port'):
4861 4898 opts['port'] = util.getport(opts.get('port'))
4862 4899
4863 4900 baseui = repo and repo.baseui or ui
4864 4901 optlist = ("name templates style address port prefix ipv6"
4865 4902 " accesslog errorlog certificate encoding")
4866 4903 for o in optlist.split():
4867 4904 val = opts.get(o, '')
4868 4905 if val in (None, ''): # should check against default options instead
4869 4906 continue
4870 4907 baseui.setconfig("web", o, val)
4871 4908 if repo and repo.ui != baseui:
4872 4909 repo.ui.setconfig("web", o, val)
4873 4910
4874 4911 o = opts.get('web_conf') or opts.get('webdir_conf')
4875 4912 if not o:
4876 4913 if not repo:
4877 4914 raise error.RepoError(_("There is no Mercurial repository"
4878 4915 " here (.hg not found)"))
4879 4916 o = repo.root
4880 4917
4881 4918 app = hgweb.hgweb(o, baseui=ui)
4882 4919
4883 4920 class service(object):
4884 4921 def init(self):
4885 4922 util.setsignalhandler()
4886 4923 self.httpd = hgweb.server.create_server(ui, app)
4887 4924
4888 4925 if opts['port'] and not ui.verbose:
4889 4926 return
4890 4927
4891 4928 if self.httpd.prefix:
4892 4929 prefix = self.httpd.prefix.strip('/') + '/'
4893 4930 else:
4894 4931 prefix = ''
4895 4932
4896 4933 port = ':%d' % self.httpd.port
4897 4934 if port == ':80':
4898 4935 port = ''
4899 4936
4900 4937 bindaddr = self.httpd.addr
4901 4938 if bindaddr == '0.0.0.0':
4902 4939 bindaddr = '*'
4903 4940 elif ':' in bindaddr: # IPv6
4904 4941 bindaddr = '[%s]' % bindaddr
4905 4942
4906 4943 fqaddr = self.httpd.fqaddr
4907 4944 if ':' in fqaddr:
4908 4945 fqaddr = '[%s]' % fqaddr
4909 4946 if opts['port']:
4910 4947 write = ui.status
4911 4948 else:
4912 4949 write = ui.write
4913 4950 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4914 4951 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4915 4952
4916 4953 def run(self):
4917 4954 self.httpd.serve_forever()
4918 4955
4919 4956 service = service()
4920 4957
4921 4958 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4922 4959
4923 4960 @command('showconfig|debugconfig',
4924 4961 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4925 4962 _('[-u] [NAME]...'))
4926 4963 def showconfig(ui, repo, *values, **opts):
4927 4964 """show combined config settings from all hgrc files
4928 4965
4929 4966 With no arguments, print names and values of all config items.
4930 4967
4931 4968 With one argument of the form section.name, print just the value
4932 4969 of that config item.
4933 4970
4934 4971 With multiple arguments, print names and values of all config
4935 4972 items with matching section names.
4936 4973
4937 4974 With --debug, the source (filename and line number) is printed
4938 4975 for each config item.
4939 4976
4940 4977 Returns 0 on success.
4941 4978 """
4942 4979
4943 4980 for f in scmutil.rcpath():
4944 4981 ui.debug('read config from: %s\n' % f)
4945 4982 untrusted = bool(opts.get('untrusted'))
4946 4983 if values:
4947 4984 sections = [v for v in values if '.' not in v]
4948 4985 items = [v for v in values if '.' in v]
4949 4986 if len(items) > 1 or items and sections:
4950 4987 raise util.Abort(_('only one config item permitted'))
4951 4988 for section, name, value in ui.walkconfig(untrusted=untrusted):
4952 4989 value = str(value).replace('\n', '\\n')
4953 4990 sectname = section + '.' + name
4954 4991 if values:
4955 4992 for v in values:
4956 4993 if v == section:
4957 4994 ui.debug('%s: ' %
4958 4995 ui.configsource(section, name, untrusted))
4959 4996 ui.write('%s=%s\n' % (sectname, value))
4960 4997 elif v == sectname:
4961 4998 ui.debug('%s: ' %
4962 4999 ui.configsource(section, name, untrusted))
4963 5000 ui.write(value, '\n')
4964 5001 else:
4965 5002 ui.debug('%s: ' %
4966 5003 ui.configsource(section, name, untrusted))
4967 5004 ui.write('%s=%s\n' % (sectname, value))
4968 5005
4969 5006 @command('^status|st',
4970 5007 [('A', 'all', None, _('show status of all files')),
4971 5008 ('m', 'modified', None, _('show only modified files')),
4972 5009 ('a', 'added', None, _('show only added files')),
4973 5010 ('r', 'removed', None, _('show only removed files')),
4974 5011 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4975 5012 ('c', 'clean', None, _('show only files without changes')),
4976 5013 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4977 5014 ('i', 'ignored', None, _('show only ignored files')),
4978 5015 ('n', 'no-status', None, _('hide status prefix')),
4979 5016 ('C', 'copies', None, _('show source of copied files')),
4980 5017 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4981 5018 ('', 'rev', [], _('show difference from revision'), _('REV')),
4982 5019 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4983 5020 ] + walkopts + subrepoopts,
4984 5021 _('[OPTION]... [FILE]...'))
4985 5022 def status(ui, repo, *pats, **opts):
4986 5023 """show changed files in the working directory
4987 5024
4988 5025 Show status of files in the repository. If names are given, only
4989 5026 files that match are shown. Files that are clean or ignored or
4990 5027 the source of a copy/move operation, are not listed unless
4991 5028 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4992 5029 Unless options described with "show only ..." are given, the
4993 5030 options -mardu are used.
4994 5031
4995 5032 Option -q/--quiet hides untracked (unknown and ignored) files
4996 5033 unless explicitly requested with -u/--unknown or -i/--ignored.
4997 5034
4998 5035 .. note::
4999 5036 status may appear to disagree with diff if permissions have
5000 5037 changed or a merge has occurred. The standard diff format does
5001 5038 not report permission changes and diff only reports changes
5002 5039 relative to one merge parent.
5003 5040
5004 5041 If one revision is given, it is used as the base revision.
5005 5042 If two revisions are given, the differences between them are
5006 5043 shown. The --change option can also be used as a shortcut to list
5007 5044 the changed files of a revision from its first parent.
5008 5045
5009 5046 The codes used to show the status of files are::
5010 5047
5011 5048 M = modified
5012 5049 A = added
5013 5050 R = removed
5014 5051 C = clean
5015 5052 ! = missing (deleted by non-hg command, but still tracked)
5016 5053 ? = not tracked
5017 5054 I = ignored
5018 5055 = origin of the previous file listed as A (added)
5019 5056
5020 5057 .. container:: verbose
5021 5058
5022 5059 Examples:
5023 5060
5024 5061 - show changes in the working directory relative to a changeset:
5025 5062
5026 5063 hg status --rev 9353
5027 5064
5028 5065 - show all changes including copies in an existing changeset::
5029 5066
5030 5067 hg status --copies --change 9353
5031 5068
5032 5069 - get a NUL separated list of added files, suitable for xargs::
5033 5070
5034 5071 hg status -an0
5035 5072
5036 5073 Returns 0 on success.
5037 5074 """
5038 5075
5039 5076 revs = opts.get('rev')
5040 5077 change = opts.get('change')
5041 5078
5042 5079 if revs and change:
5043 5080 msg = _('cannot specify --rev and --change at the same time')
5044 5081 raise util.Abort(msg)
5045 5082 elif change:
5046 5083 node2 = repo.lookup(change)
5047 5084 node1 = repo[node2].p1().node()
5048 5085 else:
5049 5086 node1, node2 = scmutil.revpair(repo, revs)
5050 5087
5051 5088 cwd = (pats and repo.getcwd()) or ''
5052 5089 end = opts.get('print0') and '\0' or '\n'
5053 5090 copy = {}
5054 5091 states = 'modified added removed deleted unknown ignored clean'.split()
5055 5092 show = [k for k in states if opts.get(k)]
5056 5093 if opts.get('all'):
5057 5094 show += ui.quiet and (states[:4] + ['clean']) or states
5058 5095 if not show:
5059 5096 show = ui.quiet and states[:4] or states[:5]
5060 5097
5061 5098 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5062 5099 'ignored' in show, 'clean' in show, 'unknown' in show,
5063 5100 opts.get('subrepos'))
5064 5101 changestates = zip(states, 'MAR!?IC', stat)
5065 5102
5066 5103 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5067 5104 ctxn = repo[nullid]
5068 5105 ctx1 = repo[node1]
5069 5106 ctx2 = repo[node2]
5070 5107 added = stat[1]
5071 5108 if node2 is None:
5072 5109 added = stat[0] + stat[1] # merged?
5073 5110
5074 5111 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
5075 5112 if k in added:
5076 5113 copy[k] = v
5077 5114 elif v in added:
5078 5115 copy[v] = k
5079 5116
5080 5117 for state, char, files in changestates:
5081 5118 if state in show:
5082 5119 format = "%s %%s%s" % (char, end)
5083 5120 if opts.get('no_status'):
5084 5121 format = "%%s%s" % end
5085 5122
5086 5123 for f in files:
5087 5124 ui.write(format % repo.pathto(f, cwd),
5088 5125 label='status.' + state)
5089 5126 if f in copy:
5090 5127 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
5091 5128 label='status.copied')
5092 5129
5093 5130 @command('^summary|sum',
5094 5131 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5095 5132 def summary(ui, repo, **opts):
5096 5133 """summarize working directory state
5097 5134
5098 5135 This generates a brief summary of the working directory state,
5099 5136 including parents, branch, commit status, and available updates.
5100 5137
5101 5138 With the --remote option, this will check the default paths for
5102 5139 incoming and outgoing changes. This can be time-consuming.
5103 5140
5104 5141 Returns 0 on success.
5105 5142 """
5106 5143
5107 5144 ctx = repo[None]
5108 5145 parents = ctx.parents()
5109 5146 pnode = parents[0].node()
5110 5147 marks = []
5111 5148
5112 5149 for p in parents:
5113 5150 # label with log.changeset (instead of log.parent) since this
5114 5151 # shows a working directory parent *changeset*:
5115 5152 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5116 5153 label='log.changeset')
5117 5154 ui.write(' '.join(p.tags()), label='log.tag')
5118 5155 if p.bookmarks():
5119 5156 marks.extend(p.bookmarks())
5120 5157 if p.rev() == -1:
5121 5158 if not len(repo):
5122 5159 ui.write(_(' (empty repository)'))
5123 5160 else:
5124 5161 ui.write(_(' (no revision checked out)'))
5125 5162 ui.write('\n')
5126 5163 if p.description():
5127 5164 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5128 5165 label='log.summary')
5129 5166
5130 5167 branch = ctx.branch()
5131 5168 bheads = repo.branchheads(branch)
5132 5169 m = _('branch: %s\n') % branch
5133 5170 if branch != 'default':
5134 5171 ui.write(m, label='log.branch')
5135 5172 else:
5136 5173 ui.status(m, label='log.branch')
5137 5174
5138 5175 if marks:
5139 5176 current = repo._bookmarkcurrent
5140 5177 ui.write(_('bookmarks:'), label='log.bookmark')
5141 5178 if current is not None:
5142 5179 try:
5143 5180 marks.remove(current)
5144 5181 ui.write(' *' + current, label='bookmarks.current')
5145 5182 except ValueError:
5146 5183 # current bookmark not in parent ctx marks
5147 5184 pass
5148 5185 for m in marks:
5149 5186 ui.write(' ' + m, label='log.bookmark')
5150 5187 ui.write('\n', label='log.bookmark')
5151 5188
5152 5189 st = list(repo.status(unknown=True))[:6]
5153 5190
5154 5191 c = repo.dirstate.copies()
5155 5192 copied, renamed = [], []
5156 5193 for d, s in c.iteritems():
5157 5194 if s in st[2]:
5158 5195 st[2].remove(s)
5159 5196 renamed.append(d)
5160 5197 else:
5161 5198 copied.append(d)
5162 5199 if d in st[1]:
5163 5200 st[1].remove(d)
5164 5201 st.insert(3, renamed)
5165 5202 st.insert(4, copied)
5166 5203
5167 5204 ms = mergemod.mergestate(repo)
5168 5205 st.append([f for f in ms if ms[f] == 'u'])
5169 5206
5170 5207 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5171 5208 st.append(subs)
5172 5209
5173 5210 labels = [ui.label(_('%d modified'), 'status.modified'),
5174 5211 ui.label(_('%d added'), 'status.added'),
5175 5212 ui.label(_('%d removed'), 'status.removed'),
5176 5213 ui.label(_('%d renamed'), 'status.copied'),
5177 5214 ui.label(_('%d copied'), 'status.copied'),
5178 5215 ui.label(_('%d deleted'), 'status.deleted'),
5179 5216 ui.label(_('%d unknown'), 'status.unknown'),
5180 5217 ui.label(_('%d ignored'), 'status.ignored'),
5181 5218 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5182 5219 ui.label(_('%d subrepos'), 'status.modified')]
5183 5220 t = []
5184 5221 for s, l in zip(st, labels):
5185 5222 if s:
5186 5223 t.append(l % len(s))
5187 5224
5188 5225 t = ', '.join(t)
5189 5226 cleanworkdir = False
5190 5227
5191 5228 if len(parents) > 1:
5192 5229 t += _(' (merge)')
5193 5230 elif branch != parents[0].branch():
5194 5231 t += _(' (new branch)')
5195 5232 elif (parents[0].extra().get('close') and
5196 5233 pnode in repo.branchheads(branch, closed=True)):
5197 5234 t += _(' (head closed)')
5198 5235 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5199 5236 t += _(' (clean)')
5200 5237 cleanworkdir = True
5201 5238 elif pnode not in bheads:
5202 5239 t += _(' (new branch head)')
5203 5240
5204 5241 if cleanworkdir:
5205 5242 ui.status(_('commit: %s\n') % t.strip())
5206 5243 else:
5207 5244 ui.write(_('commit: %s\n') % t.strip())
5208 5245
5209 5246 # all ancestors of branch heads - all ancestors of parent = new csets
5210 5247 new = [0] * len(repo)
5211 5248 cl = repo.changelog
5212 5249 for a in [cl.rev(n) for n in bheads]:
5213 5250 new[a] = 1
5214 5251 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
5215 5252 new[a] = 1
5216 5253 for a in [p.rev() for p in parents]:
5217 5254 if a >= 0:
5218 5255 new[a] = 0
5219 5256 for a in cl.ancestors(*[p.rev() for p in parents]):
5220 5257 new[a] = 0
5221 5258 new = sum(new)
5222 5259
5223 5260 if new == 0:
5224 5261 ui.status(_('update: (current)\n'))
5225 5262 elif pnode not in bheads:
5226 5263 ui.write(_('update: %d new changesets (update)\n') % new)
5227 5264 else:
5228 5265 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5229 5266 (new, len(bheads)))
5230 5267
5231 5268 if opts.get('remote'):
5232 5269 t = []
5233 5270 source, branches = hg.parseurl(ui.expandpath('default'))
5234 5271 other = hg.peer(repo, {}, source)
5235 5272 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5236 5273 ui.debug('comparing with %s\n' % util.hidepassword(source))
5237 5274 repo.ui.pushbuffer()
5238 5275 commoninc = discovery.findcommonincoming(repo, other)
5239 5276 _common, incoming, _rheads = commoninc
5240 5277 repo.ui.popbuffer()
5241 5278 if incoming:
5242 5279 t.append(_('1 or more incoming'))
5243 5280
5244 5281 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5245 5282 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5246 5283 if source != dest:
5247 5284 other = hg.peer(repo, {}, dest)
5248 5285 commoninc = None
5249 5286 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5250 5287 repo.ui.pushbuffer()
5251 5288 common, outheads = discovery.findcommonoutgoing(repo, other,
5252 5289 commoninc=commoninc)
5253 5290 repo.ui.popbuffer()
5254 5291 o = repo.changelog.findmissing(common=common, heads=outheads)
5255 5292 if o:
5256 5293 t.append(_('%d outgoing') % len(o))
5257 5294 if 'bookmarks' in other.listkeys('namespaces'):
5258 5295 lmarks = repo.listkeys('bookmarks')
5259 5296 rmarks = other.listkeys('bookmarks')
5260 5297 diff = set(rmarks) - set(lmarks)
5261 5298 if len(diff) > 0:
5262 5299 t.append(_('%d incoming bookmarks') % len(diff))
5263 5300 diff = set(lmarks) - set(rmarks)
5264 5301 if len(diff) > 0:
5265 5302 t.append(_('%d outgoing bookmarks') % len(diff))
5266 5303
5267 5304 if t:
5268 5305 ui.write(_('remote: %s\n') % (', '.join(t)))
5269 5306 else:
5270 5307 ui.status(_('remote: (synced)\n'))
5271 5308
5272 5309 @command('tag',
5273 5310 [('f', 'force', None, _('force tag')),
5274 5311 ('l', 'local', None, _('make the tag local')),
5275 5312 ('r', 'rev', '', _('revision to tag'), _('REV')),
5276 5313 ('', 'remove', None, _('remove a tag')),
5277 5314 # -l/--local is already there, commitopts cannot be used
5278 5315 ('e', 'edit', None, _('edit commit message')),
5279 5316 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5280 5317 ] + commitopts2,
5281 5318 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5282 5319 def tag(ui, repo, name1, *names, **opts):
5283 5320 """add one or more tags for the current or given revision
5284 5321
5285 5322 Name a particular revision using <name>.
5286 5323
5287 5324 Tags are used to name particular revisions of the repository and are
5288 5325 very useful to compare different revisions, to go back to significant
5289 5326 earlier versions or to mark branch points as releases, etc. Changing
5290 5327 an existing tag is normally disallowed; use -f/--force to override.
5291 5328
5292 5329 If no revision is given, the parent of the working directory is
5293 5330 used, or tip if no revision is checked out.
5294 5331
5295 5332 To facilitate version control, distribution, and merging of tags,
5296 5333 they are stored as a file named ".hgtags" which is managed similarly
5297 5334 to other project files and can be hand-edited if necessary. This
5298 5335 also means that tagging creates a new commit. The file
5299 5336 ".hg/localtags" is used for local tags (not shared among
5300 5337 repositories).
5301 5338
5302 5339 Tag commits are usually made at the head of a branch. If the parent
5303 5340 of the working directory is not a branch head, :hg:`tag` aborts; use
5304 5341 -f/--force to force the tag commit to be based on a non-head
5305 5342 changeset.
5306 5343
5307 5344 See :hg:`help dates` for a list of formats valid for -d/--date.
5308 5345
5309 5346 Since tag names have priority over branch names during revision
5310 5347 lookup, using an existing branch name as a tag name is discouraged.
5311 5348
5312 5349 Returns 0 on success.
5313 5350 """
5314 5351
5315 5352 rev_ = "."
5316 5353 names = [t.strip() for t in (name1,) + names]
5317 5354 if len(names) != len(set(names)):
5318 5355 raise util.Abort(_('tag names must be unique'))
5319 5356 for n in names:
5320 5357 if n in ['tip', '.', 'null']:
5321 5358 raise util.Abort(_("the name '%s' is reserved") % n)
5322 5359 if not n:
5323 5360 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
5324 5361 if opts.get('rev') and opts.get('remove'):
5325 5362 raise util.Abort(_("--rev and --remove are incompatible"))
5326 5363 if opts.get('rev'):
5327 5364 rev_ = opts['rev']
5328 5365 message = opts.get('message')
5329 5366 if opts.get('remove'):
5330 5367 expectedtype = opts.get('local') and 'local' or 'global'
5331 5368 for n in names:
5332 5369 if not repo.tagtype(n):
5333 5370 raise util.Abort(_("tag '%s' does not exist") % n)
5334 5371 if repo.tagtype(n) != expectedtype:
5335 5372 if expectedtype == 'global':
5336 5373 raise util.Abort(_("tag '%s' is not a global tag") % n)
5337 5374 else:
5338 5375 raise util.Abort(_("tag '%s' is not a local tag") % n)
5339 5376 rev_ = nullid
5340 5377 if not message:
5341 5378 # we don't translate commit messages
5342 5379 message = 'Removed tag %s' % ', '.join(names)
5343 5380 elif not opts.get('force'):
5344 5381 for n in names:
5345 5382 if n in repo.tags():
5346 5383 raise util.Abort(_("tag '%s' already exists "
5347 5384 "(use -f to force)") % n)
5348 5385 if not opts.get('local'):
5349 5386 p1, p2 = repo.dirstate.parents()
5350 5387 if p2 != nullid:
5351 5388 raise util.Abort(_('uncommitted merge'))
5352 5389 bheads = repo.branchheads()
5353 5390 if not opts.get('force') and bheads and p1 not in bheads:
5354 5391 raise util.Abort(_('not at a branch head (use -f to force)'))
5355 5392 r = scmutil.revsingle(repo, rev_).node()
5356 5393
5357 5394 if not message:
5358 5395 # we don't translate commit messages
5359 5396 message = ('Added tag %s for changeset %s' %
5360 5397 (', '.join(names), short(r)))
5361 5398
5362 5399 date = opts.get('date')
5363 5400 if date:
5364 5401 date = util.parsedate(date)
5365 5402
5366 5403 if opts.get('edit'):
5367 5404 message = ui.edit(message, ui.username())
5368 5405
5369 5406 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5370 5407
5371 5408 @command('tags', [], '')
5372 5409 def tags(ui, repo):
5373 5410 """list repository tags
5374 5411
5375 5412 This lists both regular and local tags. When the -v/--verbose
5376 5413 switch is used, a third column "local" is printed for local tags.
5377 5414
5378 5415 Returns 0 on success.
5379 5416 """
5380 5417
5381 5418 hexfunc = ui.debugflag and hex or short
5382 5419 tagtype = ""
5383 5420
5384 5421 for t, n in reversed(repo.tagslist()):
5385 5422 if ui.quiet:
5386 5423 ui.write("%s\n" % t, label='tags.normal')
5387 5424 continue
5388 5425
5389 5426 hn = hexfunc(n)
5390 5427 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5391 5428 rev = ui.label(r, 'log.changeset')
5392 5429 spaces = " " * (30 - encoding.colwidth(t))
5393 5430
5394 5431 tag = ui.label(t, 'tags.normal')
5395 5432 if ui.verbose:
5396 5433 if repo.tagtype(t) == 'local':
5397 5434 tagtype = " local"
5398 5435 tag = ui.label(t, 'tags.local')
5399 5436 else:
5400 5437 tagtype = ""
5401 5438 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5402 5439
5403 5440 @command('tip',
5404 5441 [('p', 'patch', None, _('show patch')),
5405 5442 ('g', 'git', None, _('use git extended diff format')),
5406 5443 ] + templateopts,
5407 5444 _('[-p] [-g]'))
5408 5445 def tip(ui, repo, **opts):
5409 5446 """show the tip revision
5410 5447
5411 5448 The tip revision (usually just called the tip) is the changeset
5412 5449 most recently added to the repository (and therefore the most
5413 5450 recently changed head).
5414 5451
5415 5452 If you have just made a commit, that commit will be the tip. If
5416 5453 you have just pulled changes from another repository, the tip of
5417 5454 that repository becomes the current tip. The "tip" tag is special
5418 5455 and cannot be renamed or assigned to a different changeset.
5419 5456
5420 5457 Returns 0 on success.
5421 5458 """
5422 5459 displayer = cmdutil.show_changeset(ui, repo, opts)
5423 5460 displayer.show(repo[len(repo) - 1])
5424 5461 displayer.close()
5425 5462
5426 5463 @command('unbundle',
5427 5464 [('u', 'update', None,
5428 5465 _('update to new branch head if changesets were unbundled'))],
5429 5466 _('[-u] FILE...'))
5430 5467 def unbundle(ui, repo, fname1, *fnames, **opts):
5431 5468 """apply one or more changegroup files
5432 5469
5433 5470 Apply one or more compressed changegroup files generated by the
5434 5471 bundle command.
5435 5472
5436 5473 Returns 0 on success, 1 if an update has unresolved files.
5437 5474 """
5438 5475 fnames = (fname1,) + fnames
5439 5476
5440 5477 lock = repo.lock()
5441 5478 wc = repo['.']
5442 5479 try:
5443 5480 for fname in fnames:
5444 5481 f = url.open(ui, fname)
5445 5482 gen = changegroup.readbundle(f, fname)
5446 5483 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5447 5484 lock=lock)
5448 5485 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5449 5486 finally:
5450 5487 lock.release()
5451 5488 return postincoming(ui, repo, modheads, opts.get('update'), None)
5452 5489
5453 5490 @command('^update|up|checkout|co',
5454 5491 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5455 5492 ('c', 'check', None,
5456 5493 _('update across branches if no uncommitted changes')),
5457 5494 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5458 5495 ('r', 'rev', '', _('revision'), _('REV'))],
5459 5496 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5460 5497 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5461 5498 """update working directory (or switch revisions)
5462 5499
5463 5500 Update the repository's working directory to the specified
5464 5501 changeset. If no changeset is specified, update to the tip of the
5465 5502 current named branch.
5466 5503
5467 5504 If the changeset is not a descendant of the working directory's
5468 5505 parent, the update is aborted. With the -c/--check option, the
5469 5506 working directory is checked for uncommitted changes; if none are
5470 5507 found, the working directory is updated to the specified
5471 5508 changeset.
5472 5509
5473 5510 Update sets the working directory's parent revison to the specified
5474 5511 changeset (see :hg:`help parents`).
5475 5512
5476 5513 The following rules apply when the working directory contains
5477 5514 uncommitted changes:
5478 5515
5479 5516 1. If neither -c/--check nor -C/--clean is specified, and if
5480 5517 the requested changeset is an ancestor or descendant of
5481 5518 the working directory's parent, the uncommitted changes
5482 5519 are merged into the requested changeset and the merged
5483 5520 result is left uncommitted. If the requested changeset is
5484 5521 not an ancestor or descendant (that is, it is on another
5485 5522 branch), the update is aborted and the uncommitted changes
5486 5523 are preserved.
5487 5524
5488 5525 2. With the -c/--check option, the update is aborted and the
5489 5526 uncommitted changes are preserved.
5490 5527
5491 5528 3. With the -C/--clean option, uncommitted changes are discarded and
5492 5529 the working directory is updated to the requested changeset.
5493 5530
5494 5531 Use null as the changeset to remove the working directory (like
5495 5532 :hg:`clone -U`).
5496 5533
5497 5534 If you want to revert just one file to an older revision, use
5498 5535 :hg:`revert [-r REV] NAME`.
5499 5536
5500 5537 See :hg:`help dates` for a list of formats valid for -d/--date.
5501 5538
5502 5539 Returns 0 on success, 1 if there are unresolved files.
5503 5540 """
5504 5541 if rev and node:
5505 5542 raise util.Abort(_("please specify just one revision"))
5506 5543
5507 5544 if rev is None or rev == '':
5508 5545 rev = node
5509 5546
5510 5547 # if we defined a bookmark, we have to remember the original bookmark name
5511 5548 brev = rev
5512 5549 rev = scmutil.revsingle(repo, rev, rev).rev()
5513 5550
5514 5551 if check and clean:
5515 5552 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5516 5553
5517 5554 if check:
5518 5555 # we could use dirty() but we can ignore merge and branch trivia
5519 5556 c = repo[None]
5520 5557 if c.modified() or c.added() or c.removed():
5521 5558 raise util.Abort(_("uncommitted local changes"))
5522 5559
5523 5560 if date:
5524 5561 if rev is not None:
5525 5562 raise util.Abort(_("you can't specify a revision and a date"))
5526 5563 rev = cmdutil.finddate(ui, repo, date)
5527 5564
5528 5565 if clean or check:
5529 5566 ret = hg.clean(repo, rev)
5530 5567 else:
5531 5568 ret = hg.update(repo, rev)
5532 5569
5533 5570 if brev in repo._bookmarks:
5534 5571 bookmarks.setcurrent(repo, brev)
5535 5572
5536 5573 return ret
5537 5574
5538 5575 @command('verify', [])
5539 5576 def verify(ui, repo):
5540 5577 """verify the integrity of the repository
5541 5578
5542 5579 Verify the integrity of the current repository.
5543 5580
5544 5581 This will perform an extensive check of the repository's
5545 5582 integrity, validating the hashes and checksums of each entry in
5546 5583 the changelog, manifest, and tracked files, as well as the
5547 5584 integrity of their crosslinks and indices.
5548 5585
5549 5586 Returns 0 on success, 1 if errors are encountered.
5550 5587 """
5551 5588 return hg.verify(repo)
5552 5589
5553 5590 @command('version', [])
5554 5591 def version_(ui):
5555 5592 """output version and copyright information"""
5556 5593 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5557 5594 % util.version())
5558 5595 ui.status(_(
5559 5596 "(see http://mercurial.selenic.com for more information)\n"
5560 5597 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5561 5598 "This is free software; see the source for copying conditions. "
5562 5599 "There is NO\nwarranty; "
5563 5600 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5564 5601 ))
5565 5602
5566 5603 norepo = ("clone init version help debugcommands debugcomplete"
5567 5604 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5568 5605 " debugknown debuggetbundle debugbundle")
5569 5606 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5570 5607 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,270 +1,270 b''
1 1 Show all commands except debug commands
2 2 $ hg debugcomplete
3 3 add
4 4 addremove
5 5 annotate
6 6 archive
7 7 backout
8 8 bisect
9 9 bookmarks
10 10 branch
11 11 branches
12 12 bundle
13 13 cat
14 14 clone
15 15 commit
16 16 copy
17 17 diff
18 18 export
19 19 forget
20 20 graft
21 21 grep
22 22 heads
23 23 help
24 24 identify
25 25 import
26 26 incoming
27 27 init
28 28 locate
29 29 log
30 30 manifest
31 31 merge
32 32 outgoing
33 33 parents
34 34 paths
35 35 pull
36 36 push
37 37 recover
38 38 remove
39 39 rename
40 40 resolve
41 41 revert
42 42 rollback
43 43 root
44 44 serve
45 45 showconfig
46 46 status
47 47 summary
48 48 tag
49 49 tags
50 50 tip
51 51 unbundle
52 52 update
53 53 verify
54 54 version
55 55
56 56 Show all commands that start with "a"
57 57 $ hg debugcomplete a
58 58 add
59 59 addremove
60 60 annotate
61 61 archive
62 62
63 63 Do not show debug commands if there are other candidates
64 64 $ hg debugcomplete d
65 65 diff
66 66
67 67 Show debug commands if there are no other candidates
68 68 $ hg debugcomplete debug
69 69 debugancestor
70 70 debugbuilddag
71 71 debugbundle
72 72 debugcheckstate
73 73 debugcommands
74 74 debugcomplete
75 75 debugconfig
76 76 debugdag
77 77 debugdata
78 78 debugdate
79 79 debugdiscovery
80 80 debugfileset
81 81 debugfsinfo
82 82 debuggetbundle
83 83 debugignore
84 84 debugindex
85 85 debugindexdot
86 86 debuginstall
87 87 debugknown
88 88 debugpushkey
89 89 debugrebuildstate
90 90 debugrename
91 91 debugrevlog
92 92 debugrevspec
93 93 debugsetparents
94 94 debugstate
95 95 debugsub
96 96 debugwalk
97 97 debugwireargs
98 98
99 99 Do not show the alias of a debug command if there are other candidates
100 100 (this should hide rawcommit)
101 101 $ hg debugcomplete r
102 102 recover
103 103 remove
104 104 rename
105 105 resolve
106 106 revert
107 107 rollback
108 108 root
109 109 Show the alias of a debug command if there are no other candidates
110 110 $ hg debugcomplete rawc
111 111
112 112
113 113 Show the global options
114 114 $ hg debugcomplete --options | sort
115 115 --config
116 116 --cwd
117 117 --debug
118 118 --debugger
119 119 --encoding
120 120 --encodingmode
121 121 --help
122 122 --noninteractive
123 123 --profile
124 124 --quiet
125 125 --repository
126 126 --time
127 127 --traceback
128 128 --verbose
129 129 --version
130 130 -R
131 131 -h
132 132 -q
133 133 -v
134 134 -y
135 135
136 136 Show the options for the "serve" command
137 137 $ hg debugcomplete --options serve | sort
138 138 --accesslog
139 139 --address
140 140 --certificate
141 141 --cmdserver
142 142 --config
143 143 --cwd
144 144 --daemon
145 145 --daemon-pipefds
146 146 --debug
147 147 --debugger
148 148 --encoding
149 149 --encodingmode
150 150 --errorlog
151 151 --help
152 152 --ipv6
153 153 --name
154 154 --noninteractive
155 155 --pid-file
156 156 --port
157 157 --prefix
158 158 --profile
159 159 --quiet
160 160 --repository
161 161 --stdio
162 162 --style
163 163 --templates
164 164 --time
165 165 --traceback
166 166 --verbose
167 167 --version
168 168 --web-conf
169 169 -6
170 170 -A
171 171 -E
172 172 -R
173 173 -a
174 174 -d
175 175 -h
176 176 -n
177 177 -p
178 178 -q
179 179 -t
180 180 -v
181 181 -y
182 182
183 183 Show an error if we use --options with an ambiguous abbreviation
184 184 $ hg debugcomplete --options s
185 185 hg: command 's' is ambiguous:
186 186 serve showconfig status summary
187 187 [255]
188 188
189 189 Show all commands + options
190 190 $ hg debugcommands
191 191 add: include, exclude, subrepos, dry-run
192 192 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, include, exclude
193 193 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
194 194 commit: addremove, close-branch, include, exclude, message, logfile, date, user
195 195 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
196 196 export: output, switch-parent, rev, text, git, nodates
197 197 forget: include, exclude
198 198 init: ssh, remotecmd, insecure
199 199 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, hidden, patch, git, limit, no-merges, stat, style, template, include, exclude
200 200 merge: force, rev, preview, tool
201 201 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
202 202 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
203 203 remove: after, force, include, exclude
204 204 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
205 205 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
206 206 summary: remote
207 207 update: clean, check, date, rev
208 208 addremove: similarity, include, exclude, dry-run
209 209 archive: no-decode, prefix, rev, type, subrepos, include, exclude
210 210 backout: merge, parent, rev, tool, include, exclude, message, logfile, date, user
211 211 bisect: reset, good, bad, skip, extend, command, noupdate
212 212 bookmarks: force, rev, delete, rename, inactive
213 213 branch: force, clean
214 214 branches: active, closed
215 215 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
216 216 cat: output, rev, decode, include, exclude
217 217 copy: after, force, include, exclude, dry-run
218 218 debugancestor:
219 219 debugbuilddag: mergeable-file, overwritten-file, new-file
220 220 debugbundle: all
221 221 debugcheckstate:
222 222 debugcommands:
223 223 debugcomplete: options
224 224 debugdag: tags, branches, dots, spaces
225 225 debugdata: changelog, manifest
226 226 debugdate: extended
227 227 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
228 228 debugfileset:
229 229 debugfsinfo:
230 230 debuggetbundle: head, common, type
231 231 debugignore:
232 232 debugindex: changelog, manifest, format
233 233 debugindexdot:
234 234 debuginstall:
235 235 debugknown:
236 236 debugpushkey:
237 237 debugrebuildstate: rev
238 238 debugrename: rev
239 239 debugrevlog: changelog, manifest, dump
240 240 debugrevspec:
241 241 debugsetparents:
242 242 debugstate: nodates, datesort
243 243 debugsub: rev
244 244 debugwalk: include, exclude
245 245 debugwireargs: three, four, five, ssh, remotecmd, insecure
246 graft: edit, currentdate, currentuser, date, user, tool
246 graft: continue, edit, currentdate, currentuser, date, user, tool
247 247 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
248 248 heads: rev, topo, active, closed, style, template
249 249 help: extension, command
250 250 identify: rev, num, id, branch, tags, bookmarks
251 251 import: strip, base, edit, force, no-commit, bypass, exact, import-branch, message, logfile, date, user, similarity
252 252 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
253 253 locate: rev, print0, fullpath, include, exclude
254 254 manifest: rev, all
255 255 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
256 256 parents: rev, style, template
257 257 paths:
258 258 recover:
259 259 rename: after, force, include, exclude, dry-run
260 260 resolve: all, list, mark, unmark, no-status, tool, include, exclude
261 261 revert: all, date, rev, no-backup, include, exclude, dry-run
262 262 rollback: dry-run, force
263 263 root:
264 264 showconfig: untrusted
265 265 tag: force, local, rev, remove, edit, message, date, user
266 266 tags:
267 267 tip: patch, git, style, template
268 268 unbundle: update
269 269 verify:
270 270 version:
General Comments 0
You need to be logged in to leave comments. Login now