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