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