##// END OF EJS Templates
bundle: introduce a --exact option...
marmoute -
r50305:2bbd7bc7 default
parent child Browse files
Show More
@@ -1,7955 +1,7975 b''
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005-2007 Olivia Mackall <olivia@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
9 9 import os
10 10 import re
11 11 import sys
12 12
13 13 from .i18n import _
14 14 from .node import (
15 15 hex,
16 16 nullrev,
17 17 short,
18 18 wdirrev,
19 19 )
20 20 from .pycompat import open
21 21 from . import (
22 22 archival,
23 23 bookmarks,
24 24 bundle2,
25 25 bundlecaches,
26 26 changegroup,
27 27 cmdutil,
28 28 copies,
29 29 debugcommands as debugcommandsmod,
30 30 destutil,
31 31 dirstateguard,
32 32 discovery,
33 33 encoding,
34 34 error,
35 35 exchange,
36 36 extensions,
37 37 filemerge,
38 38 formatter,
39 39 graphmod,
40 40 grep as grepmod,
41 41 hbisect,
42 42 help,
43 43 hg,
44 44 logcmdutil,
45 45 merge as mergemod,
46 46 mergestate as mergestatemod,
47 47 narrowspec,
48 48 obsolete,
49 49 obsutil,
50 50 patch,
51 51 phases,
52 52 pycompat,
53 53 rcutil,
54 54 registrar,
55 55 requirements,
56 56 revsetlang,
57 57 rewriteutil,
58 58 scmutil,
59 59 server,
60 60 shelve as shelvemod,
61 61 state as statemod,
62 62 streamclone,
63 63 tags as tagsmod,
64 64 ui as uimod,
65 65 util,
66 66 verify as verifymod,
67 67 vfs as vfsmod,
68 68 wireprotoserver,
69 69 )
70 70 from .utils import (
71 71 dateutil,
72 72 stringutil,
73 73 urlutil,
74 74 )
75 75
76 76 table = {}
77 77 table.update(debugcommandsmod.command._table)
78 78
79 79 command = registrar.command(table)
80 80 INTENT_READONLY = registrar.INTENT_READONLY
81 81
82 82 # common command options
83 83
84 84 globalopts = [
85 85 (
86 86 b'R',
87 87 b'repository',
88 88 b'',
89 89 _(b'repository root directory or name of overlay bundle file'),
90 90 _(b'REPO'),
91 91 ),
92 92 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
93 93 (
94 94 b'y',
95 95 b'noninteractive',
96 96 None,
97 97 _(
98 98 b'do not prompt, automatically pick the first choice for all prompts'
99 99 ),
100 100 ),
101 101 (b'q', b'quiet', None, _(b'suppress output')),
102 102 (b'v', b'verbose', None, _(b'enable additional output')),
103 103 (
104 104 b'',
105 105 b'color',
106 106 b'',
107 107 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
108 108 # and should not be translated
109 109 _(b"when to colorize (boolean, always, auto, never, or debug)"),
110 110 _(b'TYPE'),
111 111 ),
112 112 (
113 113 b'',
114 114 b'config',
115 115 [],
116 116 _(b'set/override config option (use \'section.name=value\')'),
117 117 _(b'CONFIG'),
118 118 ),
119 119 (b'', b'debug', None, _(b'enable debugging output')),
120 120 (b'', b'debugger', None, _(b'start debugger')),
121 121 (
122 122 b'',
123 123 b'encoding',
124 124 encoding.encoding,
125 125 _(b'set the charset encoding'),
126 126 _(b'ENCODE'),
127 127 ),
128 128 (
129 129 b'',
130 130 b'encodingmode',
131 131 encoding.encodingmode,
132 132 _(b'set the charset encoding mode'),
133 133 _(b'MODE'),
134 134 ),
135 135 (b'', b'traceback', None, _(b'always print a traceback on exception')),
136 136 (b'', b'time', None, _(b'time how long the command takes')),
137 137 (b'', b'profile', None, _(b'print command execution profile')),
138 138 (b'', b'version', None, _(b'output version information and exit')),
139 139 (b'h', b'help', None, _(b'display help and exit')),
140 140 (b'', b'hidden', False, _(b'consider hidden changesets')),
141 141 (
142 142 b'',
143 143 b'pager',
144 144 b'auto',
145 145 _(b"when to paginate (boolean, always, auto, or never)"),
146 146 _(b'TYPE'),
147 147 ),
148 148 ]
149 149
150 150 dryrunopts = cmdutil.dryrunopts
151 151 remoteopts = cmdutil.remoteopts
152 152 walkopts = cmdutil.walkopts
153 153 commitopts = cmdutil.commitopts
154 154 commitopts2 = cmdutil.commitopts2
155 155 commitopts3 = cmdutil.commitopts3
156 156 formatteropts = cmdutil.formatteropts
157 157 templateopts = cmdutil.templateopts
158 158 logopts = cmdutil.logopts
159 159 diffopts = cmdutil.diffopts
160 160 diffwsopts = cmdutil.diffwsopts
161 161 diffopts2 = cmdutil.diffopts2
162 162 mergetoolopts = cmdutil.mergetoolopts
163 163 similarityopts = cmdutil.similarityopts
164 164 subrepoopts = cmdutil.subrepoopts
165 165 debugrevlogopts = cmdutil.debugrevlogopts
166 166
167 167 # Commands start here, listed alphabetically
168 168
169 169
170 170 @command(
171 171 b'abort',
172 172 dryrunopts,
173 173 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
174 174 helpbasic=True,
175 175 )
176 176 def abort(ui, repo, **opts):
177 177 """abort an unfinished operation (EXPERIMENTAL)
178 178
179 179 Aborts a multistep operation like graft, histedit, rebase, merge,
180 180 and unshelve if they are in an unfinished state.
181 181
182 182 use --dry-run/-n to dry run the command.
183 183 """
184 184 dryrun = opts.get('dry_run')
185 185 abortstate = cmdutil.getunfinishedstate(repo)
186 186 if not abortstate:
187 187 raise error.StateError(_(b'no operation in progress'))
188 188 if not abortstate.abortfunc:
189 189 raise error.InputError(
190 190 (
191 191 _(b"%s in progress but does not support 'hg abort'")
192 192 % (abortstate._opname)
193 193 ),
194 194 hint=abortstate.hint(),
195 195 )
196 196 if dryrun:
197 197 ui.status(
198 198 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
199 199 )
200 200 return
201 201 return abortstate.abortfunc(ui, repo)
202 202
203 203
204 204 @command(
205 205 b'add',
206 206 walkopts + subrepoopts + dryrunopts,
207 207 _(b'[OPTION]... [FILE]...'),
208 208 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
209 209 helpbasic=True,
210 210 inferrepo=True,
211 211 )
212 212 def add(ui, repo, *pats, **opts):
213 213 """add the specified files on the next commit
214 214
215 215 Schedule files to be version controlled and added to the
216 216 repository.
217 217
218 218 The files will be added to the repository at the next commit. To
219 219 undo an add before that, see :hg:`forget`.
220 220
221 221 If no names are given, add all files to the repository (except
222 222 files matching ``.hgignore``).
223 223
224 224 .. container:: verbose
225 225
226 226 Examples:
227 227
228 228 - New (unknown) files are added
229 229 automatically by :hg:`add`::
230 230
231 231 $ ls
232 232 foo.c
233 233 $ hg status
234 234 ? foo.c
235 235 $ hg add
236 236 adding foo.c
237 237 $ hg status
238 238 A foo.c
239 239
240 240 - Specific files to be added can be specified::
241 241
242 242 $ ls
243 243 bar.c foo.c
244 244 $ hg status
245 245 ? bar.c
246 246 ? foo.c
247 247 $ hg add bar.c
248 248 $ hg status
249 249 A bar.c
250 250 ? foo.c
251 251
252 252 Returns 0 if all files are successfully added.
253 253 """
254 254
255 255 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
256 256 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
257 257 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
258 258 return rejected and 1 or 0
259 259
260 260
261 261 @command(
262 262 b'addremove',
263 263 similarityopts + subrepoopts + walkopts + dryrunopts,
264 264 _(b'[OPTION]... [FILE]...'),
265 265 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
266 266 inferrepo=True,
267 267 )
268 268 def addremove(ui, repo, *pats, **opts):
269 269 """add all new files, delete all missing files
270 270
271 271 Add all new files and remove all missing files from the
272 272 repository.
273 273
274 274 Unless names are given, new files are ignored if they match any of
275 275 the patterns in ``.hgignore``. As with add, these changes take
276 276 effect at the next commit.
277 277
278 278 Use the -s/--similarity option to detect renamed files. This
279 279 option takes a percentage between 0 (disabled) and 100 (files must
280 280 be identical) as its parameter. With a parameter greater than 0,
281 281 this compares every removed file with every added file and records
282 282 those similar enough as renames. Detecting renamed files this way
283 283 can be expensive. After using this option, :hg:`status -C` can be
284 284 used to check which files were identified as moved or renamed. If
285 285 not specified, -s/--similarity defaults to 100 and only renames of
286 286 identical files are detected.
287 287
288 288 .. container:: verbose
289 289
290 290 Examples:
291 291
292 292 - A number of files (bar.c and foo.c) are new,
293 293 while foobar.c has been removed (without using :hg:`remove`)
294 294 from the repository::
295 295
296 296 $ ls
297 297 bar.c foo.c
298 298 $ hg status
299 299 ! foobar.c
300 300 ? bar.c
301 301 ? foo.c
302 302 $ hg addremove
303 303 adding bar.c
304 304 adding foo.c
305 305 removing foobar.c
306 306 $ hg status
307 307 A bar.c
308 308 A foo.c
309 309 R foobar.c
310 310
311 311 - A file foobar.c was moved to foo.c without using :hg:`rename`.
312 312 Afterwards, it was edited slightly::
313 313
314 314 $ ls
315 315 foo.c
316 316 $ hg status
317 317 ! foobar.c
318 318 ? foo.c
319 319 $ hg addremove --similarity 90
320 320 removing foobar.c
321 321 adding foo.c
322 322 recording removal of foobar.c as rename to foo.c (94% similar)
323 323 $ hg status -C
324 324 A foo.c
325 325 foobar.c
326 326 R foobar.c
327 327
328 328 Returns 0 if all files are successfully added.
329 329 """
330 330 opts = pycompat.byteskwargs(opts)
331 331 if not opts.get(b'similarity'):
332 332 opts[b'similarity'] = b'100'
333 333 matcher = scmutil.match(repo[None], pats, opts)
334 334 relative = scmutil.anypats(pats, opts)
335 335 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
336 336 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
337 337
338 338
339 339 @command(
340 340 b'annotate|blame',
341 341 [
342 342 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
343 343 (
344 344 b'',
345 345 b'follow',
346 346 None,
347 347 _(b'follow copies/renames and list the filename (DEPRECATED)'),
348 348 ),
349 349 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
350 350 (b'a', b'text', None, _(b'treat all files as text')),
351 351 (b'u', b'user', None, _(b'list the author (long with -v)')),
352 352 (b'f', b'file', None, _(b'list the filename')),
353 353 (b'd', b'date', None, _(b'list the date (short with -q)')),
354 354 (b'n', b'number', None, _(b'list the revision number (default)')),
355 355 (b'c', b'changeset', None, _(b'list the changeset')),
356 356 (
357 357 b'l',
358 358 b'line-number',
359 359 None,
360 360 _(b'show line number at the first appearance'),
361 361 ),
362 362 (
363 363 b'',
364 364 b'skip',
365 365 [],
366 366 _(b'revset to not display (EXPERIMENTAL)'),
367 367 _(b'REV'),
368 368 ),
369 369 ]
370 370 + diffwsopts
371 371 + walkopts
372 372 + formatteropts,
373 373 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
374 374 helpcategory=command.CATEGORY_FILE_CONTENTS,
375 375 helpbasic=True,
376 376 inferrepo=True,
377 377 )
378 378 def annotate(ui, repo, *pats, **opts):
379 379 """show changeset information by line for each file
380 380
381 381 List changes in files, showing the revision id responsible for
382 382 each line.
383 383
384 384 This command is useful for discovering when a change was made and
385 385 by whom.
386 386
387 387 If you include --file, --user, or --date, the revision number is
388 388 suppressed unless you also include --number.
389 389
390 390 Without the -a/--text option, annotate will avoid processing files
391 391 it detects as binary. With -a, annotate will annotate the file
392 392 anyway, although the results will probably be neither useful
393 393 nor desirable.
394 394
395 395 .. container:: verbose
396 396
397 397 Template:
398 398
399 399 The following keywords are supported in addition to the common template
400 400 keywords and functions. See also :hg:`help templates`.
401 401
402 402 :lines: List of lines with annotation data.
403 403 :path: String. Repository-absolute path of the specified file.
404 404
405 405 And each entry of ``{lines}`` provides the following sub-keywords in
406 406 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
407 407
408 408 :line: String. Line content.
409 409 :lineno: Integer. Line number at that revision.
410 410 :path: String. Repository-absolute path of the file at that revision.
411 411
412 412 See :hg:`help templates.operators` for the list expansion syntax.
413 413
414 414 Returns 0 on success.
415 415 """
416 416 opts = pycompat.byteskwargs(opts)
417 417 if not pats:
418 418 raise error.InputError(
419 419 _(b'at least one filename or pattern is required')
420 420 )
421 421
422 422 if opts.get(b'follow'):
423 423 # --follow is deprecated and now just an alias for -f/--file
424 424 # to mimic the behavior of Mercurial before version 1.5
425 425 opts[b'file'] = True
426 426
427 427 if (
428 428 not opts.get(b'user')
429 429 and not opts.get(b'changeset')
430 430 and not opts.get(b'date')
431 431 and not opts.get(b'file')
432 432 ):
433 433 opts[b'number'] = True
434 434
435 435 linenumber = opts.get(b'line_number') is not None
436 436 if (
437 437 linenumber
438 438 and (not opts.get(b'changeset'))
439 439 and (not opts.get(b'number'))
440 440 ):
441 441 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
442 442
443 443 rev = opts.get(b'rev')
444 444 if rev:
445 445 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
446 446 ctx = logcmdutil.revsingle(repo, rev)
447 447
448 448 ui.pager(b'annotate')
449 449 rootfm = ui.formatter(b'annotate', opts)
450 450 if ui.debugflag:
451 451 shorthex = pycompat.identity
452 452 else:
453 453
454 454 def shorthex(h):
455 455 return h[:12]
456 456
457 457 if ui.quiet:
458 458 datefunc = dateutil.shortdate
459 459 else:
460 460 datefunc = dateutil.datestr
461 461 if ctx.rev() is None:
462 462 if opts.get(b'changeset'):
463 463 # omit "+" suffix which is appended to node hex
464 464 def formatrev(rev):
465 465 if rev == wdirrev:
466 466 return b'%d' % ctx.p1().rev()
467 467 else:
468 468 return b'%d' % rev
469 469
470 470 else:
471 471
472 472 def formatrev(rev):
473 473 if rev == wdirrev:
474 474 return b'%d+' % ctx.p1().rev()
475 475 else:
476 476 return b'%d ' % rev
477 477
478 478 def formathex(h):
479 479 if h == repo.nodeconstants.wdirhex:
480 480 return b'%s+' % shorthex(hex(ctx.p1().node()))
481 481 else:
482 482 return b'%s ' % shorthex(h)
483 483
484 484 else:
485 485 formatrev = b'%d'.__mod__
486 486 formathex = shorthex
487 487
488 488 opmap = [
489 489 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
490 490 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
491 491 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
492 492 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
493 493 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
494 494 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
495 495 ]
496 496 opnamemap = {
497 497 b'rev': b'number',
498 498 b'node': b'changeset',
499 499 b'path': b'file',
500 500 b'lineno': b'line_number',
501 501 }
502 502
503 503 if rootfm.isplain():
504 504
505 505 def makefunc(get, fmt):
506 506 return lambda x: fmt(get(x))
507 507
508 508 else:
509 509
510 510 def makefunc(get, fmt):
511 511 return get
512 512
513 513 datahint = rootfm.datahint()
514 514 funcmap = [
515 515 (makefunc(get, fmt), sep)
516 516 for fn, sep, get, fmt in opmap
517 517 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
518 518 ]
519 519 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
520 520 fields = b' '.join(
521 521 fn
522 522 for fn, sep, get, fmt in opmap
523 523 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
524 524 )
525 525
526 526 def bad(x, y):
527 527 raise error.InputError(b"%s: %s" % (x, y))
528 528
529 529 m = scmutil.match(ctx, pats, opts, badfn=bad)
530 530
531 531 follow = not opts.get(b'no_follow')
532 532 diffopts = patch.difffeatureopts(
533 533 ui, opts, section=b'annotate', whitespace=True
534 534 )
535 535 skiprevs = opts.get(b'skip')
536 536 if skiprevs:
537 537 skiprevs = logcmdutil.revrange(repo, skiprevs)
538 538
539 539 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
540 540 for abs in ctx.walk(m):
541 541 fctx = ctx[abs]
542 542 rootfm.startitem()
543 543 rootfm.data(path=abs)
544 544 if not opts.get(b'text') and fctx.isbinary():
545 545 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
546 546 continue
547 547
548 548 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
549 549 lines = fctx.annotate(
550 550 follow=follow, skiprevs=skiprevs, diffopts=diffopts
551 551 )
552 552 if not lines:
553 553 fm.end()
554 554 continue
555 555 formats = []
556 556 pieces = []
557 557
558 558 for f, sep in funcmap:
559 559 l = [f(n) for n in lines]
560 560 if fm.isplain():
561 561 sizes = [encoding.colwidth(x) for x in l]
562 562 ml = max(sizes)
563 563 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
564 564 else:
565 565 formats.append([b'%s'] * len(l))
566 566 pieces.append(l)
567 567
568 568 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
569 569 fm.startitem()
570 570 fm.context(fctx=n.fctx)
571 571 fm.write(fields, b"".join(f), *p)
572 572 if n.skip:
573 573 fmt = b"* %s"
574 574 else:
575 575 fmt = b": %s"
576 576 fm.write(b'line', fmt, n.text)
577 577
578 578 if not lines[-1].text.endswith(b'\n'):
579 579 fm.plain(b'\n')
580 580 fm.end()
581 581
582 582 rootfm.end()
583 583
584 584
585 585 @command(
586 586 b'archive',
587 587 [
588 588 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
589 589 (
590 590 b'p',
591 591 b'prefix',
592 592 b'',
593 593 _(b'directory prefix for files in archive'),
594 594 _(b'PREFIX'),
595 595 ),
596 596 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
597 597 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
598 598 ]
599 599 + subrepoopts
600 600 + walkopts,
601 601 _(b'[OPTION]... DEST'),
602 602 helpcategory=command.CATEGORY_IMPORT_EXPORT,
603 603 )
604 604 def archive(ui, repo, dest, **opts):
605 605 """create an unversioned archive of a repository revision
606 606
607 607 By default, the revision used is the parent of the working
608 608 directory; use -r/--rev to specify a different revision.
609 609
610 610 The archive type is automatically detected based on file
611 611 extension (to override, use -t/--type).
612 612
613 613 .. container:: verbose
614 614
615 615 Examples:
616 616
617 617 - create a zip file containing the 1.0 release::
618 618
619 619 hg archive -r 1.0 project-1.0.zip
620 620
621 621 - create a tarball excluding .hg files::
622 622
623 623 hg archive project.tar.gz -X ".hg*"
624 624
625 625 Valid types are:
626 626
627 627 :``files``: a directory full of files (default)
628 628 :``tar``: tar archive, uncompressed
629 629 :``tbz2``: tar archive, compressed using bzip2
630 630 :``tgz``: tar archive, compressed using gzip
631 631 :``txz``: tar archive, compressed using lzma (only in Python 3)
632 632 :``uzip``: zip archive, uncompressed
633 633 :``zip``: zip archive, compressed using deflate
634 634
635 635 The exact name of the destination archive or directory is given
636 636 using a format string; see :hg:`help export` for details.
637 637
638 638 Each member added to an archive file has a directory prefix
639 639 prepended. Use -p/--prefix to specify a format string for the
640 640 prefix. The default is the basename of the archive, with suffixes
641 641 removed.
642 642
643 643 Returns 0 on success.
644 644 """
645 645
646 646 opts = pycompat.byteskwargs(opts)
647 647 rev = opts.get(b'rev')
648 648 if rev:
649 649 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
650 650 ctx = logcmdutil.revsingle(repo, rev)
651 651 if not ctx:
652 652 raise error.InputError(
653 653 _(b'no working directory: please specify a revision')
654 654 )
655 655 node = ctx.node()
656 656 dest = cmdutil.makefilename(ctx, dest)
657 657 if os.path.realpath(dest) == repo.root:
658 658 raise error.InputError(_(b'repository root cannot be destination'))
659 659
660 660 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
661 661 prefix = opts.get(b'prefix')
662 662
663 663 if dest == b'-':
664 664 if kind == b'files':
665 665 raise error.InputError(_(b'cannot archive plain files to stdout'))
666 666 dest = cmdutil.makefileobj(ctx, dest)
667 667 if not prefix:
668 668 prefix = os.path.basename(repo.root) + b'-%h'
669 669
670 670 prefix = cmdutil.makefilename(ctx, prefix)
671 671 match = scmutil.match(ctx, [], opts)
672 672 archival.archive(
673 673 repo,
674 674 dest,
675 675 node,
676 676 kind,
677 677 not opts.get(b'no_decode'),
678 678 match,
679 679 prefix,
680 680 subrepos=opts.get(b'subrepos'),
681 681 )
682 682
683 683
684 684 @command(
685 685 b'backout',
686 686 [
687 687 (
688 688 b'',
689 689 b'merge',
690 690 None,
691 691 _(b'merge with old dirstate parent after backout'),
692 692 ),
693 693 (
694 694 b'',
695 695 b'commit',
696 696 None,
697 697 _(b'commit if no conflicts were encountered (DEPRECATED)'),
698 698 ),
699 699 (b'', b'no-commit', None, _(b'do not commit')),
700 700 (
701 701 b'',
702 702 b'parent',
703 703 b'',
704 704 _(b'parent to choose when backing out merge (DEPRECATED)'),
705 705 _(b'REV'),
706 706 ),
707 707 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
708 708 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
709 709 ]
710 710 + mergetoolopts
711 711 + walkopts
712 712 + commitopts
713 713 + commitopts2,
714 714 _(b'[OPTION]... [-r] REV'),
715 715 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
716 716 )
717 717 def backout(ui, repo, node=None, rev=None, **opts):
718 718 """reverse effect of earlier changeset
719 719
720 720 Prepare a new changeset with the effect of REV undone in the
721 721 current working directory. If no conflicts were encountered,
722 722 it will be committed immediately.
723 723
724 724 If REV is the parent of the working directory, then this new changeset
725 725 is committed automatically (unless --no-commit is specified).
726 726
727 727 .. note::
728 728
729 729 :hg:`backout` cannot be used to fix either an unwanted or
730 730 incorrect merge.
731 731
732 732 .. container:: verbose
733 733
734 734 Examples:
735 735
736 736 - Reverse the effect of the parent of the working directory.
737 737 This backout will be committed immediately::
738 738
739 739 hg backout -r .
740 740
741 741 - Reverse the effect of previous bad revision 23::
742 742
743 743 hg backout -r 23
744 744
745 745 - Reverse the effect of previous bad revision 23 and
746 746 leave changes uncommitted::
747 747
748 748 hg backout -r 23 --no-commit
749 749 hg commit -m "Backout revision 23"
750 750
751 751 By default, the pending changeset will have one parent,
752 752 maintaining a linear history. With --merge, the pending
753 753 changeset will instead have two parents: the old parent of the
754 754 working directory and a new child of REV that simply undoes REV.
755 755
756 756 Before version 1.7, the behavior without --merge was equivalent
757 757 to specifying --merge followed by :hg:`update --clean .` to
758 758 cancel the merge and leave the child of REV as a head to be
759 759 merged separately.
760 760
761 761 See :hg:`help dates` for a list of formats valid for -d/--date.
762 762
763 763 See :hg:`help revert` for a way to restore files to the state
764 764 of another revision.
765 765
766 766 Returns 0 on success, 1 if nothing to backout or there are unresolved
767 767 files.
768 768 """
769 769 with repo.wlock(), repo.lock():
770 770 return _dobackout(ui, repo, node, rev, **opts)
771 771
772 772
773 773 def _dobackout(ui, repo, node=None, rev=None, **opts):
774 774 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
775 775 opts = pycompat.byteskwargs(opts)
776 776
777 777 if rev and node:
778 778 raise error.InputError(_(b"please specify just one revision"))
779 779
780 780 if not rev:
781 781 rev = node
782 782
783 783 if not rev:
784 784 raise error.InputError(_(b"please specify a revision to backout"))
785 785
786 786 date = opts.get(b'date')
787 787 if date:
788 788 opts[b'date'] = dateutil.parsedate(date)
789 789
790 790 cmdutil.checkunfinished(repo)
791 791 cmdutil.bailifchanged(repo)
792 792 ctx = logcmdutil.revsingle(repo, rev)
793 793 node = ctx.node()
794 794
795 795 op1, op2 = repo.dirstate.parents()
796 796 if not repo.changelog.isancestor(node, op1):
797 797 raise error.InputError(
798 798 _(b'cannot backout change that is not an ancestor')
799 799 )
800 800
801 801 p1, p2 = repo.changelog.parents(node)
802 802 if p1 == repo.nullid:
803 803 raise error.InputError(_(b'cannot backout a change with no parents'))
804 804 if p2 != repo.nullid:
805 805 if not opts.get(b'parent'):
806 806 raise error.InputError(_(b'cannot backout a merge changeset'))
807 807 p = repo.lookup(opts[b'parent'])
808 808 if p not in (p1, p2):
809 809 raise error.InputError(
810 810 _(b'%s is not a parent of %s') % (short(p), short(node))
811 811 )
812 812 parent = p
813 813 else:
814 814 if opts.get(b'parent'):
815 815 raise error.InputError(
816 816 _(b'cannot use --parent on non-merge changeset')
817 817 )
818 818 parent = p1
819 819
820 820 # the backout should appear on the same branch
821 821 branch = repo.dirstate.branch()
822 822 bheads = repo.branchheads(branch)
823 823 rctx = scmutil.revsingle(repo, hex(parent))
824 824 if not opts.get(b'merge') and op1 != node:
825 825 with dirstateguard.dirstateguard(repo, b'backout'):
826 826 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
827 827 with ui.configoverride(overrides, b'backout'):
828 828 stats = mergemod.back_out(ctx, parent=repo[parent])
829 829 repo.setparents(op1, op2)
830 830 hg._showstats(repo, stats)
831 831 if stats.unresolvedcount:
832 832 repo.ui.status(
833 833 _(b"use 'hg resolve' to retry unresolved file merges\n")
834 834 )
835 835 return 1
836 836 else:
837 837 hg.clean(repo, node, show_stats=False)
838 838 repo.dirstate.setbranch(branch)
839 839 cmdutil.revert(ui, repo, rctx)
840 840
841 841 if opts.get(b'no_commit'):
842 842 msg = _(b"changeset %s backed out, don't forget to commit.\n")
843 843 ui.status(msg % short(node))
844 844 return 0
845 845
846 846 def commitfunc(ui, repo, message, match, opts):
847 847 editform = b'backout'
848 848 e = cmdutil.getcommiteditor(
849 849 editform=editform, **pycompat.strkwargs(opts)
850 850 )
851 851 if not message:
852 852 # we don't translate commit messages
853 853 message = b"Backed out changeset %s" % short(node)
854 854 e = cmdutil.getcommiteditor(edit=True, editform=editform)
855 855 return repo.commit(
856 856 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
857 857 )
858 858
859 859 # save to detect changes
860 860 tip = repo.changelog.tip()
861 861
862 862 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
863 863 if not newnode:
864 864 ui.status(_(b"nothing changed\n"))
865 865 return 1
866 866 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
867 867
868 868 def nice(node):
869 869 return b'%d:%s' % (repo.changelog.rev(node), short(node))
870 870
871 871 ui.status(
872 872 _(b'changeset %s backs out changeset %s\n')
873 873 % (nice(newnode), nice(node))
874 874 )
875 875 if opts.get(b'merge') and op1 != node:
876 876 hg.clean(repo, op1, show_stats=False)
877 877 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
878 878 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
879 879 with ui.configoverride(overrides, b'backout'):
880 880 return hg.merge(repo[b'tip'])
881 881 return 0
882 882
883 883
884 884 @command(
885 885 b'bisect',
886 886 [
887 887 (b'r', b'reset', False, _(b'reset bisect state')),
888 888 (b'g', b'good', False, _(b'mark changeset good')),
889 889 (b'b', b'bad', False, _(b'mark changeset bad')),
890 890 (b's', b'skip', False, _(b'skip testing changeset')),
891 891 (b'e', b'extend', False, _(b'extend the bisect range')),
892 892 (
893 893 b'c',
894 894 b'command',
895 895 b'',
896 896 _(b'use command to check changeset state'),
897 897 _(b'CMD'),
898 898 ),
899 899 (b'U', b'noupdate', False, _(b'do not update to target')),
900 900 ],
901 901 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
902 902 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
903 903 )
904 904 def bisect(
905 905 ui,
906 906 repo,
907 907 positional_1=None,
908 908 positional_2=None,
909 909 command=None,
910 910 reset=None,
911 911 good=None,
912 912 bad=None,
913 913 skip=None,
914 914 extend=None,
915 915 noupdate=None,
916 916 ):
917 917 """subdivision search of changesets
918 918
919 919 This command helps to find changesets which introduce problems. To
920 920 use, mark the earliest changeset you know exhibits the problem as
921 921 bad, then mark the latest changeset which is free from the problem
922 922 as good. Bisect will update your working directory to a revision
923 923 for testing (unless the -U/--noupdate option is specified). Once
924 924 you have performed tests, mark the working directory as good or
925 925 bad, and bisect will either update to another candidate changeset
926 926 or announce that it has found the bad revision.
927 927
928 928 As a shortcut, you can also use the revision argument to mark a
929 929 revision as good or bad without checking it out first.
930 930
931 931 If you supply a command, it will be used for automatic bisection.
932 932 The environment variable HG_NODE will contain the ID of the
933 933 changeset being tested. The exit status of the command will be
934 934 used to mark revisions as good or bad: status 0 means good, 125
935 935 means to skip the revision, 127 (command not found) will abort the
936 936 bisection, and any other non-zero exit status means the revision
937 937 is bad.
938 938
939 939 .. container:: verbose
940 940
941 941 Some examples:
942 942
943 943 - start a bisection with known bad revision 34, and good revision 12::
944 944
945 945 hg bisect --bad 34
946 946 hg bisect --good 12
947 947
948 948 - advance the current bisection by marking current revision as good or
949 949 bad::
950 950
951 951 hg bisect --good
952 952 hg bisect --bad
953 953
954 954 - mark the current revision, or a known revision, to be skipped (e.g. if
955 955 that revision is not usable because of another issue)::
956 956
957 957 hg bisect --skip
958 958 hg bisect --skip 23
959 959
960 960 - skip all revisions that do not touch directories ``foo`` or ``bar``::
961 961
962 962 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
963 963
964 964 - forget the current bisection::
965 965
966 966 hg bisect --reset
967 967
968 968 - use 'make && make tests' to automatically find the first broken
969 969 revision::
970 970
971 971 hg bisect --reset
972 972 hg bisect --bad 34
973 973 hg bisect --good 12
974 974 hg bisect --command "make && make tests"
975 975
976 976 - see all changesets whose states are already known in the current
977 977 bisection::
978 978
979 979 hg log -r "bisect(pruned)"
980 980
981 981 - see the changeset currently being bisected (especially useful
982 982 if running with -U/--noupdate)::
983 983
984 984 hg log -r "bisect(current)"
985 985
986 986 - see all changesets that took part in the current bisection::
987 987
988 988 hg log -r "bisect(range)"
989 989
990 990 - you can even get a nice graph::
991 991
992 992 hg log --graph -r "bisect(range)"
993 993
994 994 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
995 995
996 996 Returns 0 on success.
997 997 """
998 998 rev = []
999 999 # backward compatibility
1000 1000 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1001 1001 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1002 1002 cmd = positional_1
1003 1003 rev.append(positional_2)
1004 1004 if cmd == b"good":
1005 1005 good = True
1006 1006 elif cmd == b"bad":
1007 1007 bad = True
1008 1008 else:
1009 1009 reset = True
1010 1010 elif positional_2:
1011 1011 raise error.InputError(_(b'incompatible arguments'))
1012 1012 elif positional_1 is not None:
1013 1013 rev.append(positional_1)
1014 1014
1015 1015 incompatibles = {
1016 1016 b'--bad': bad,
1017 1017 b'--command': bool(command),
1018 1018 b'--extend': extend,
1019 1019 b'--good': good,
1020 1020 b'--reset': reset,
1021 1021 b'--skip': skip,
1022 1022 }
1023 1023
1024 1024 enabled = [x for x in incompatibles if incompatibles[x]]
1025 1025
1026 1026 if len(enabled) > 1:
1027 1027 raise error.InputError(
1028 1028 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1029 1029 )
1030 1030
1031 1031 if reset:
1032 1032 hbisect.resetstate(repo)
1033 1033 return
1034 1034
1035 1035 state = hbisect.load_state(repo)
1036 1036
1037 1037 if rev:
1038 1038 nodes = [repo[i].node() for i in logcmdutil.revrange(repo, rev)]
1039 1039 else:
1040 1040 nodes = [repo.lookup(b'.')]
1041 1041
1042 1042 # update state
1043 1043 if good or bad or skip:
1044 1044 if good:
1045 1045 state[b'good'] += nodes
1046 1046 elif bad:
1047 1047 state[b'bad'] += nodes
1048 1048 elif skip:
1049 1049 state[b'skip'] += nodes
1050 1050 hbisect.save_state(repo, state)
1051 1051 if not (state[b'good'] and state[b'bad']):
1052 1052 return
1053 1053
1054 1054 def mayupdate(repo, node, show_stats=True):
1055 1055 """common used update sequence"""
1056 1056 if noupdate:
1057 1057 return
1058 1058 cmdutil.checkunfinished(repo)
1059 1059 cmdutil.bailifchanged(repo)
1060 1060 return hg.clean(repo, node, show_stats=show_stats)
1061 1061
1062 1062 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1063 1063
1064 1064 if command:
1065 1065 changesets = 1
1066 1066 if noupdate:
1067 1067 try:
1068 1068 node = state[b'current'][0]
1069 1069 except LookupError:
1070 1070 raise error.StateError(
1071 1071 _(
1072 1072 b'current bisect revision is unknown - '
1073 1073 b'start a new bisect to fix'
1074 1074 )
1075 1075 )
1076 1076 else:
1077 1077 node, p2 = repo.dirstate.parents()
1078 1078 if p2 != repo.nullid:
1079 1079 raise error.StateError(_(b'current bisect revision is a merge'))
1080 1080 if rev:
1081 1081 if not nodes:
1082 1082 raise error.InputError(_(b'empty revision set'))
1083 1083 node = repo[nodes[-1]].node()
1084 1084 with hbisect.restore_state(repo, state, node):
1085 1085 while changesets:
1086 1086 # update state
1087 1087 state[b'current'] = [node]
1088 1088 hbisect.save_state(repo, state)
1089 1089 status = ui.system(
1090 1090 command,
1091 1091 environ={b'HG_NODE': hex(node)},
1092 1092 blockedtag=b'bisect_check',
1093 1093 )
1094 1094 if status == 125:
1095 1095 transition = b"skip"
1096 1096 elif status == 0:
1097 1097 transition = b"good"
1098 1098 # status < 0 means process was killed
1099 1099 elif status == 127:
1100 1100 raise error.Abort(_(b"failed to execute %s") % command)
1101 1101 elif status < 0:
1102 1102 raise error.Abort(_(b"%s killed") % command)
1103 1103 else:
1104 1104 transition = b"bad"
1105 1105 state[transition].append(node)
1106 1106 ctx = repo[node]
1107 1107 summary = cmdutil.format_changeset_summary(ui, ctx, b'bisect')
1108 1108 ui.status(_(b'changeset %s: %s\n') % (summary, transition))
1109 1109 hbisect.checkstate(state)
1110 1110 # bisect
1111 1111 nodes, changesets, bgood = hbisect.bisect(repo, state)
1112 1112 # update to next check
1113 1113 node = nodes[0]
1114 1114 mayupdate(repo, node, show_stats=False)
1115 1115 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1116 1116 return
1117 1117
1118 1118 hbisect.checkstate(state)
1119 1119
1120 1120 # actually bisect
1121 1121 nodes, changesets, good = hbisect.bisect(repo, state)
1122 1122 if extend:
1123 1123 if not changesets:
1124 1124 extendctx = hbisect.extendrange(repo, state, nodes, good)
1125 1125 if extendctx is not None:
1126 1126 ui.write(
1127 1127 _(b"Extending search to changeset %s\n")
1128 1128 % cmdutil.format_changeset_summary(ui, extendctx, b'bisect')
1129 1129 )
1130 1130 state[b'current'] = [extendctx.node()]
1131 1131 hbisect.save_state(repo, state)
1132 1132 return mayupdate(repo, extendctx.node())
1133 1133 raise error.StateError(_(b"nothing to extend"))
1134 1134
1135 1135 if changesets == 0:
1136 1136 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1137 1137 else:
1138 1138 assert len(nodes) == 1 # only a single node can be tested next
1139 1139 node = nodes[0]
1140 1140 # compute the approximate number of remaining tests
1141 1141 tests, size = 0, 2
1142 1142 while size <= changesets:
1143 1143 tests, size = tests + 1, size * 2
1144 1144 rev = repo.changelog.rev(node)
1145 1145 summary = cmdutil.format_changeset_summary(ui, repo[rev], b'bisect')
1146 1146 ui.write(
1147 1147 _(
1148 1148 b"Testing changeset %s "
1149 1149 b"(%d changesets remaining, ~%d tests)\n"
1150 1150 )
1151 1151 % (summary, changesets, tests)
1152 1152 )
1153 1153 state[b'current'] = [node]
1154 1154 hbisect.save_state(repo, state)
1155 1155 return mayupdate(repo, node)
1156 1156
1157 1157
1158 1158 @command(
1159 1159 b'bookmarks|bookmark',
1160 1160 [
1161 1161 (b'f', b'force', False, _(b'force')),
1162 1162 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1163 1163 (b'd', b'delete', False, _(b'delete a given bookmark')),
1164 1164 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1165 1165 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1166 1166 (b'l', b'list', False, _(b'list existing bookmarks')),
1167 1167 ]
1168 1168 + formatteropts,
1169 1169 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1170 1170 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1171 1171 )
1172 1172 def bookmark(ui, repo, *names, **opts):
1173 1173 """create a new bookmark or list existing bookmarks
1174 1174
1175 1175 Bookmarks are labels on changesets to help track lines of development.
1176 1176 Bookmarks are unversioned and can be moved, renamed and deleted.
1177 1177 Deleting or moving a bookmark has no effect on the associated changesets.
1178 1178
1179 1179 Creating or updating to a bookmark causes it to be marked as 'active'.
1180 1180 The active bookmark is indicated with a '*'.
1181 1181 When a commit is made, the active bookmark will advance to the new commit.
1182 1182 A plain :hg:`update` will also advance an active bookmark, if possible.
1183 1183 Updating away from a bookmark will cause it to be deactivated.
1184 1184
1185 1185 Bookmarks can be pushed and pulled between repositories (see
1186 1186 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1187 1187 diverged, a new 'divergent bookmark' of the form 'name@path' will
1188 1188 be created. Using :hg:`merge` will resolve the divergence.
1189 1189
1190 1190 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1191 1191 the active bookmark's name.
1192 1192
1193 1193 A bookmark named '@' has the special property that :hg:`clone` will
1194 1194 check it out by default if it exists.
1195 1195
1196 1196 .. container:: verbose
1197 1197
1198 1198 Template:
1199 1199
1200 1200 The following keywords are supported in addition to the common template
1201 1201 keywords and functions such as ``{bookmark}``. See also
1202 1202 :hg:`help templates`.
1203 1203
1204 1204 :active: Boolean. True if the bookmark is active.
1205 1205
1206 1206 Examples:
1207 1207
1208 1208 - create an active bookmark for a new line of development::
1209 1209
1210 1210 hg book new-feature
1211 1211
1212 1212 - create an inactive bookmark as a place marker::
1213 1213
1214 1214 hg book -i reviewed
1215 1215
1216 1216 - create an inactive bookmark on another changeset::
1217 1217
1218 1218 hg book -r .^ tested
1219 1219
1220 1220 - rename bookmark turkey to dinner::
1221 1221
1222 1222 hg book -m turkey dinner
1223 1223
1224 1224 - move the '@' bookmark from another branch::
1225 1225
1226 1226 hg book -f @
1227 1227
1228 1228 - print only the active bookmark name::
1229 1229
1230 1230 hg book -ql .
1231 1231 """
1232 1232 opts = pycompat.byteskwargs(opts)
1233 1233 force = opts.get(b'force')
1234 1234 rev = opts.get(b'rev')
1235 1235 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1236 1236
1237 1237 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1238 1238 if action:
1239 1239 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1240 1240 elif names or rev:
1241 1241 action = b'add'
1242 1242 elif inactive:
1243 1243 action = b'inactive' # meaning deactivate
1244 1244 else:
1245 1245 action = b'list'
1246 1246
1247 1247 cmdutil.check_incompatible_arguments(
1248 1248 opts, b'inactive', [b'delete', b'list']
1249 1249 )
1250 1250 if not names and action in {b'add', b'delete'}:
1251 1251 raise error.InputError(_(b"bookmark name required"))
1252 1252
1253 1253 if action in {b'add', b'delete', b'rename', b'inactive'}:
1254 1254 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1255 1255 if action == b'delete':
1256 1256 names = pycompat.maplist(repo._bookmarks.expandname, names)
1257 1257 bookmarks.delete(repo, tr, names)
1258 1258 elif action == b'rename':
1259 1259 if not names:
1260 1260 raise error.InputError(_(b"new bookmark name required"))
1261 1261 elif len(names) > 1:
1262 1262 raise error.InputError(
1263 1263 _(b"only one new bookmark name allowed")
1264 1264 )
1265 1265 oldname = repo._bookmarks.expandname(opts[b'rename'])
1266 1266 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1267 1267 elif action == b'add':
1268 1268 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1269 1269 elif action == b'inactive':
1270 1270 if len(repo._bookmarks) == 0:
1271 1271 ui.status(_(b"no bookmarks set\n"))
1272 1272 elif not repo._activebookmark:
1273 1273 ui.status(_(b"no active bookmark\n"))
1274 1274 else:
1275 1275 bookmarks.deactivate(repo)
1276 1276 elif action == b'list':
1277 1277 names = pycompat.maplist(repo._bookmarks.expandname, names)
1278 1278 with ui.formatter(b'bookmarks', opts) as fm:
1279 1279 bookmarks.printbookmarks(ui, repo, fm, names)
1280 1280 else:
1281 1281 raise error.ProgrammingError(b'invalid action: %s' % action)
1282 1282
1283 1283
1284 1284 @command(
1285 1285 b'branch',
1286 1286 [
1287 1287 (
1288 1288 b'f',
1289 1289 b'force',
1290 1290 None,
1291 1291 _(b'set branch name even if it shadows an existing branch'),
1292 1292 ),
1293 1293 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1294 1294 (
1295 1295 b'r',
1296 1296 b'rev',
1297 1297 [],
1298 1298 _(b'change branches of the given revs (EXPERIMENTAL)'),
1299 1299 ),
1300 1300 ],
1301 1301 _(b'[-fC] [NAME]'),
1302 1302 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1303 1303 )
1304 1304 def branch(ui, repo, label=None, **opts):
1305 1305 """set or show the current branch name
1306 1306
1307 1307 .. note::
1308 1308
1309 1309 Branch names are permanent and global. Use :hg:`bookmark` to create a
1310 1310 light-weight bookmark instead. See :hg:`help glossary` for more
1311 1311 information about named branches and bookmarks.
1312 1312
1313 1313 With no argument, show the current branch name. With one argument,
1314 1314 set the working directory branch name (the branch will not exist
1315 1315 in the repository until the next commit). Standard practice
1316 1316 recommends that primary development take place on the 'default'
1317 1317 branch.
1318 1318
1319 1319 Unless -f/--force is specified, branch will not let you set a
1320 1320 branch name that already exists.
1321 1321
1322 1322 Use -C/--clean to reset the working directory branch to that of
1323 1323 the parent of the working directory, negating a previous branch
1324 1324 change.
1325 1325
1326 1326 Use the command :hg:`update` to switch to an existing branch. Use
1327 1327 :hg:`commit --close-branch` to mark this branch head as closed.
1328 1328 When all heads of a branch are closed, the branch will be
1329 1329 considered closed.
1330 1330
1331 1331 Returns 0 on success.
1332 1332 """
1333 1333 opts = pycompat.byteskwargs(opts)
1334 1334 revs = opts.get(b'rev')
1335 1335 if label:
1336 1336 label = label.strip()
1337 1337
1338 1338 if not opts.get(b'clean') and not label:
1339 1339 if revs:
1340 1340 raise error.InputError(
1341 1341 _(b"no branch name specified for the revisions")
1342 1342 )
1343 1343 ui.write(b"%s\n" % repo.dirstate.branch())
1344 1344 return
1345 1345
1346 1346 with repo.wlock():
1347 1347 if opts.get(b'clean'):
1348 1348 label = repo[b'.'].branch()
1349 1349 repo.dirstate.setbranch(label)
1350 1350 ui.status(_(b'reset working directory to branch %s\n') % label)
1351 1351 elif label:
1352 1352
1353 1353 scmutil.checknewlabel(repo, label, b'branch')
1354 1354 if revs:
1355 1355 return cmdutil.changebranch(ui, repo, revs, label, opts)
1356 1356
1357 1357 if not opts.get(b'force') and label in repo.branchmap():
1358 1358 if label not in [p.branch() for p in repo[None].parents()]:
1359 1359 raise error.InputError(
1360 1360 _(b'a branch of the same name already exists'),
1361 1361 # i18n: "it" refers to an existing branch
1362 1362 hint=_(b"use 'hg update' to switch to it"),
1363 1363 )
1364 1364
1365 1365 repo.dirstate.setbranch(label)
1366 1366 ui.status(_(b'marked working directory as branch %s\n') % label)
1367 1367
1368 1368 # find any open named branches aside from default
1369 1369 for n, h, t, c in repo.branchmap().iterbranches():
1370 1370 if n != b"default" and not c:
1371 1371 return 0
1372 1372 ui.status(
1373 1373 _(
1374 1374 b'(branches are permanent and global, '
1375 1375 b'did you want a bookmark?)\n'
1376 1376 )
1377 1377 )
1378 1378
1379 1379
1380 1380 @command(
1381 1381 b'branches',
1382 1382 [
1383 1383 (
1384 1384 b'a',
1385 1385 b'active',
1386 1386 False,
1387 1387 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1388 1388 ),
1389 1389 (b'c', b'closed', False, _(b'show normal and closed branches')),
1390 1390 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1391 1391 ]
1392 1392 + formatteropts,
1393 1393 _(b'[-c]'),
1394 1394 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1395 1395 intents={INTENT_READONLY},
1396 1396 )
1397 1397 def branches(ui, repo, active=False, closed=False, **opts):
1398 1398 """list repository named branches
1399 1399
1400 1400 List the repository's named branches, indicating which ones are
1401 1401 inactive. If -c/--closed is specified, also list branches which have
1402 1402 been marked closed (see :hg:`commit --close-branch`).
1403 1403
1404 1404 Use the command :hg:`update` to switch to an existing branch.
1405 1405
1406 1406 .. container:: verbose
1407 1407
1408 1408 Template:
1409 1409
1410 1410 The following keywords are supported in addition to the common template
1411 1411 keywords and functions such as ``{branch}``. See also
1412 1412 :hg:`help templates`.
1413 1413
1414 1414 :active: Boolean. True if the branch is active.
1415 1415 :closed: Boolean. True if the branch is closed.
1416 1416 :current: Boolean. True if it is the current branch.
1417 1417
1418 1418 Returns 0.
1419 1419 """
1420 1420
1421 1421 opts = pycompat.byteskwargs(opts)
1422 1422 revs = opts.get(b'rev')
1423 1423 selectedbranches = None
1424 1424 if revs:
1425 1425 revs = logcmdutil.revrange(repo, revs)
1426 1426 getbi = repo.revbranchcache().branchinfo
1427 1427 selectedbranches = {getbi(r)[0] for r in revs}
1428 1428
1429 1429 ui.pager(b'branches')
1430 1430 fm = ui.formatter(b'branches', opts)
1431 1431 hexfunc = fm.hexfunc
1432 1432
1433 1433 allheads = set(repo.heads())
1434 1434 branches = []
1435 1435 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1436 1436 if selectedbranches is not None and tag not in selectedbranches:
1437 1437 continue
1438 1438 isactive = False
1439 1439 if not isclosed:
1440 1440 openheads = set(repo.branchmap().iteropen(heads))
1441 1441 isactive = bool(openheads & allheads)
1442 1442 branches.append((tag, repo[tip], isactive, not isclosed))
1443 1443 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1444 1444
1445 1445 for tag, ctx, isactive, isopen in branches:
1446 1446 if active and not isactive:
1447 1447 continue
1448 1448 if isactive:
1449 1449 label = b'branches.active'
1450 1450 notice = b''
1451 1451 elif not isopen:
1452 1452 if not closed:
1453 1453 continue
1454 1454 label = b'branches.closed'
1455 1455 notice = _(b' (closed)')
1456 1456 else:
1457 1457 label = b'branches.inactive'
1458 1458 notice = _(b' (inactive)')
1459 1459 current = tag == repo.dirstate.branch()
1460 1460 if current:
1461 1461 label = b'branches.current'
1462 1462
1463 1463 fm.startitem()
1464 1464 fm.write(b'branch', b'%s', tag, label=label)
1465 1465 rev = ctx.rev()
1466 1466 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1467 1467 fmt = b' ' * padsize + b' %d:%s'
1468 1468 fm.condwrite(
1469 1469 not ui.quiet,
1470 1470 b'rev node',
1471 1471 fmt,
1472 1472 rev,
1473 1473 hexfunc(ctx.node()),
1474 1474 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1475 1475 )
1476 1476 fm.context(ctx=ctx)
1477 1477 fm.data(active=isactive, closed=not isopen, current=current)
1478 1478 if not ui.quiet:
1479 1479 fm.plain(notice)
1480 1480 fm.plain(b'\n')
1481 1481 fm.end()
1482 1482
1483 1483
1484 1484 @command(
1485 1485 b'bundle',
1486 1486 [
1487
1488 (
1489 b'',
1490 b'exact',
1491 None,
1492 _(b'compute the base from the revision specified'),
1493 ),
1487 1494 (
1488 1495 b'f',
1489 1496 b'force',
1490 1497 None,
1491 1498 _(b'run even when the destination is unrelated'),
1492 1499 ),
1493 1500 (
1494 1501 b'r',
1495 1502 b'rev',
1496 1503 [],
1497 1504 _(b'a changeset intended to be added to the destination'),
1498 1505 _(b'REV'),
1499 1506 ),
1500 1507 (
1501 1508 b'b',
1502 1509 b'branch',
1503 1510 [],
1504 1511 _(b'a specific branch you would like to bundle'),
1505 1512 _(b'BRANCH'),
1506 1513 ),
1507 1514 (
1508 1515 b'',
1509 1516 b'base',
1510 1517 [],
1511 1518 _(b'a base changeset assumed to be available at the destination'),
1512 1519 _(b'REV'),
1513 1520 ),
1514 1521 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1515 1522 (
1516 1523 b't',
1517 1524 b'type',
1518 1525 b'bzip2',
1519 1526 _(b'bundle compression type to use'),
1520 1527 _(b'TYPE'),
1521 1528 ),
1522 1529 ]
1523 1530 + remoteopts,
1524 1531 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]...'),
1525 1532 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1526 1533 )
1527 1534 def bundle(ui, repo, fname, *dests, **opts):
1528 1535 """create a bundle file
1529 1536
1530 1537 Generate a bundle file containing data to be transferred to another
1531 1538 repository.
1532 1539
1533 1540 To create a bundle containing all changesets, use -a/--all
1534 1541 (or --base null). Otherwise, hg assumes the destination will have
1535 1542 all the nodes you specify with --base parameters. Otherwise, hg
1536 1543 will assume the repository has all the nodes in destination, or
1537 1544 default-push/default if no destination is specified, where destination
1538 1545 is the repositories you provide through DEST option.
1539 1546
1540 1547 You can change bundle format with the -t/--type option. See
1541 1548 :hg:`help bundlespec` for documentation on this format. By default,
1542 1549 the most appropriate format is used and compression defaults to
1543 1550 bzip2.
1544 1551
1545 1552 The bundle file can then be transferred using conventional means
1546 1553 and applied to another repository with the unbundle or pull
1547 1554 command. This is useful when direct push and pull are not
1548 1555 available or when exporting an entire repository is undesirable.
1549 1556
1550 1557 Applying bundles preserves all changeset contents including
1551 1558 permissions, copy/rename information, and revision history.
1552 1559
1553 1560 Returns 0 on success, 1 if no changes found.
1554 1561 """
1555 1562 opts = pycompat.byteskwargs(opts)
1563
1556 1564 revs = None
1557 1565 if b'rev' in opts:
1558 1566 revstrings = opts[b'rev']
1559 1567 revs = logcmdutil.revrange(repo, revstrings)
1560 1568 if revstrings and not revs:
1561 1569 raise error.InputError(_(b'no commits to bundle'))
1562 1570
1563 1571 bundletype = opts.get(b'type', b'bzip2').lower()
1564 1572 try:
1565 1573 bundlespec = bundlecaches.parsebundlespec(
1566 1574 repo, bundletype, strict=False
1567 1575 )
1568 1576 except error.UnsupportedBundleSpecification as e:
1569 1577 raise error.InputError(
1570 1578 pycompat.bytestr(e),
1571 1579 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1572 1580 )
1573 1581 cgversion = bundlespec.params[b"cg.version"]
1574 1582
1575 1583 # Packed bundles are a pseudo bundle format for now.
1576 1584 if cgversion == b's1':
1577 1585 raise error.InputError(
1578 1586 _(b'packed bundles cannot be produced by "hg bundle"'),
1579 1587 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1580 1588 )
1581 1589
1582 1590 if opts.get(b'all'):
1583 1591 if dests:
1584 1592 raise error.InputError(
1585 1593 _(b"--all is incompatible with specifying destinations")
1586 1594 )
1587 1595 if opts.get(b'base'):
1588 1596 ui.warn(_(b"ignoring --base because --all was specified\n"))
1597 if opts.get(b'exact'):
1598 ui.warn(_(b"ignoring --exact because --all was specified\n"))
1589 1599 base = [nullrev]
1600 elif opts.get(b'exact'):
1601 if dests:
1602 raise error.InputError(
1603 _(b"--exact is incompatible with specifying destinations")
1604 )
1605 if opts.get(b'base'):
1606 ui.warn(_(b"ignoring --base because --exact was specified\n"))
1607 base = repo.revs(b'parents(%ld) - %ld', revs, revs)
1608 if not base:
1609 base = [nullrev]
1590 1610 else:
1591 1611 base = logcmdutil.revrange(repo, opts.get(b'base'))
1592 1612 if cgversion not in changegroup.supportedoutgoingversions(repo):
1593 1613 raise error.Abort(
1594 1614 _(b"repository does not support bundle version %s") % cgversion
1595 1615 )
1596 1616
1597 1617 if base:
1598 1618 if dests:
1599 1619 raise error.InputError(
1600 1620 _(b"--base is incompatible with specifying destinations")
1601 1621 )
1602 1622 cl = repo.changelog
1603 1623 common = [cl.node(rev) for rev in base]
1604 1624 heads = [cl.node(r) for r in revs] if revs else None
1605 1625 outgoing = discovery.outgoing(repo, common, heads)
1606 1626 missing = outgoing.missing
1607 1627 excluded = outgoing.excluded
1608 1628 else:
1609 1629 missing = set()
1610 1630 excluded = set()
1611 1631 for path in urlutil.get_push_paths(repo, ui, dests):
1612 1632 other = hg.peer(repo, opts, path.rawloc)
1613 1633 if revs is not None:
1614 1634 hex_revs = [repo[r].hex() for r in revs]
1615 1635 else:
1616 1636 hex_revs = None
1617 1637 branches = (path.branch, [])
1618 1638 head_revs, checkout = hg.addbranchrevs(
1619 1639 repo, repo, branches, hex_revs
1620 1640 )
1621 1641 heads = (
1622 1642 head_revs
1623 1643 and pycompat.maplist(repo.lookup, head_revs)
1624 1644 or head_revs
1625 1645 )
1626 1646 outgoing = discovery.findcommonoutgoing(
1627 1647 repo,
1628 1648 other,
1629 1649 onlyheads=heads,
1630 1650 force=opts.get(b'force'),
1631 1651 portable=True,
1632 1652 )
1633 1653 missing.update(outgoing.missing)
1634 1654 excluded.update(outgoing.excluded)
1635 1655
1636 1656 if not missing:
1637 1657 scmutil.nochangesfound(ui, repo, not base and excluded)
1638 1658 return 1
1639 1659
1640 1660 if heads:
1641 1661 outgoing = discovery.outgoing(
1642 1662 repo, missingroots=missing, ancestorsof=heads
1643 1663 )
1644 1664 else:
1645 1665 outgoing = discovery.outgoing(repo, missingroots=missing)
1646 1666 outgoing.excluded = sorted(excluded)
1647 1667
1648 1668 if cgversion == b'01': # bundle1
1649 1669 bversion = b'HG10' + bundlespec.wirecompression
1650 1670 bcompression = None
1651 1671 elif cgversion in (b'02', b'03'):
1652 1672 bversion = b'HG20'
1653 1673 bcompression = bundlespec.wirecompression
1654 1674 else:
1655 1675 raise error.ProgrammingError(
1656 1676 b'bundle: unexpected changegroup version %s' % cgversion
1657 1677 )
1658 1678
1659 1679 # TODO compression options should be derived from bundlespec parsing.
1660 1680 # This is a temporary hack to allow adjusting bundle compression
1661 1681 # level without a) formalizing the bundlespec changes to declare it
1662 1682 # b) introducing a command flag.
1663 1683 compopts = {}
1664 1684 complevel = ui.configint(
1665 1685 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1666 1686 )
1667 1687 if complevel is None:
1668 1688 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1669 1689 if complevel is not None:
1670 1690 compopts[b'level'] = complevel
1671 1691
1672 1692 compthreads = ui.configint(
1673 1693 b'experimental', b'bundlecompthreads.' + bundlespec.compression
1674 1694 )
1675 1695 if compthreads is None:
1676 1696 compthreads = ui.configint(b'experimental', b'bundlecompthreads')
1677 1697 if compthreads is not None:
1678 1698 compopts[b'threads'] = compthreads
1679 1699
1680 1700 # Bundling of obsmarker and phases is optional as not all clients
1681 1701 # support the necessary features.
1682 1702 cfg = ui.configbool
1683 1703 obsolescence_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker')
1684 1704 bundlespec.set_param(b'obsolescence', obsolescence_cfg, overwrite=False)
1685 1705 obs_mand_cfg = cfg(b'experimental', b'evolution.bundle-obsmarker:mandatory')
1686 1706 bundlespec.set_param(
1687 1707 b'obsolescence-mandatory', obs_mand_cfg, overwrite=False
1688 1708 )
1689 1709 phases_cfg = cfg(b'experimental', b'bundle-phases')
1690 1710 bundlespec.set_param(b'phases', phases_cfg, overwrite=False)
1691 1711
1692 1712 bundle2.writenewbundle(
1693 1713 ui,
1694 1714 repo,
1695 1715 b'bundle',
1696 1716 fname,
1697 1717 bversion,
1698 1718 outgoing,
1699 1719 bundlespec.params,
1700 1720 compression=bcompression,
1701 1721 compopts=compopts,
1702 1722 )
1703 1723
1704 1724
1705 1725 @command(
1706 1726 b'cat',
1707 1727 [
1708 1728 (
1709 1729 b'o',
1710 1730 b'output',
1711 1731 b'',
1712 1732 _(b'print output to file with formatted name'),
1713 1733 _(b'FORMAT'),
1714 1734 ),
1715 1735 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1716 1736 (b'', b'decode', None, _(b'apply any matching decode filter')),
1717 1737 ]
1718 1738 + walkopts
1719 1739 + formatteropts,
1720 1740 _(b'[OPTION]... FILE...'),
1721 1741 helpcategory=command.CATEGORY_FILE_CONTENTS,
1722 1742 inferrepo=True,
1723 1743 intents={INTENT_READONLY},
1724 1744 )
1725 1745 def cat(ui, repo, file1, *pats, **opts):
1726 1746 """output the current or given revision of files
1727 1747
1728 1748 Print the specified files as they were at the given revision. If
1729 1749 no revision is given, the parent of the working directory is used.
1730 1750
1731 1751 Output may be to a file, in which case the name of the file is
1732 1752 given using a template string. See :hg:`help templates`. In addition
1733 1753 to the common template keywords, the following formatting rules are
1734 1754 supported:
1735 1755
1736 1756 :``%%``: literal "%" character
1737 1757 :``%s``: basename of file being printed
1738 1758 :``%d``: dirname of file being printed, or '.' if in repository root
1739 1759 :``%p``: root-relative path name of file being printed
1740 1760 :``%H``: changeset hash (40 hexadecimal digits)
1741 1761 :``%R``: changeset revision number
1742 1762 :``%h``: short-form changeset hash (12 hexadecimal digits)
1743 1763 :``%r``: zero-padded changeset revision number
1744 1764 :``%b``: basename of the exporting repository
1745 1765 :``\\``: literal "\\" character
1746 1766
1747 1767 .. container:: verbose
1748 1768
1749 1769 Template:
1750 1770
1751 1771 The following keywords are supported in addition to the common template
1752 1772 keywords and functions. See also :hg:`help templates`.
1753 1773
1754 1774 :data: String. File content.
1755 1775 :path: String. Repository-absolute path of the file.
1756 1776
1757 1777 Returns 0 on success.
1758 1778 """
1759 1779 opts = pycompat.byteskwargs(opts)
1760 1780 rev = opts.get(b'rev')
1761 1781 if rev:
1762 1782 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1763 1783 ctx = logcmdutil.revsingle(repo, rev)
1764 1784 m = scmutil.match(ctx, (file1,) + pats, opts)
1765 1785 fntemplate = opts.pop(b'output', b'')
1766 1786 if cmdutil.isstdiofilename(fntemplate):
1767 1787 fntemplate = b''
1768 1788
1769 1789 if fntemplate:
1770 1790 fm = formatter.nullformatter(ui, b'cat', opts)
1771 1791 else:
1772 1792 ui.pager(b'cat')
1773 1793 fm = ui.formatter(b'cat', opts)
1774 1794 with fm:
1775 1795 return cmdutil.cat(
1776 1796 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1777 1797 )
1778 1798
1779 1799
1780 1800 @command(
1781 1801 b'clone',
1782 1802 [
1783 1803 (
1784 1804 b'U',
1785 1805 b'noupdate',
1786 1806 None,
1787 1807 _(
1788 1808 b'the clone will include an empty working '
1789 1809 b'directory (only a repository)'
1790 1810 ),
1791 1811 ),
1792 1812 (
1793 1813 b'u',
1794 1814 b'updaterev',
1795 1815 b'',
1796 1816 _(b'revision, tag, or branch to check out'),
1797 1817 _(b'REV'),
1798 1818 ),
1799 1819 (
1800 1820 b'r',
1801 1821 b'rev',
1802 1822 [],
1803 1823 _(
1804 1824 b'do not clone everything, but include this changeset'
1805 1825 b' and its ancestors'
1806 1826 ),
1807 1827 _(b'REV'),
1808 1828 ),
1809 1829 (
1810 1830 b'b',
1811 1831 b'branch',
1812 1832 [],
1813 1833 _(
1814 1834 b'do not clone everything, but include this branch\'s'
1815 1835 b' changesets and their ancestors'
1816 1836 ),
1817 1837 _(b'BRANCH'),
1818 1838 ),
1819 1839 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1820 1840 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1821 1841 (b'', b'stream', None, _(b'clone with minimal data processing')),
1822 1842 ]
1823 1843 + remoteopts,
1824 1844 _(b'[OPTION]... SOURCE [DEST]'),
1825 1845 helpcategory=command.CATEGORY_REPO_CREATION,
1826 1846 helpbasic=True,
1827 1847 norepo=True,
1828 1848 )
1829 1849 def clone(ui, source, dest=None, **opts):
1830 1850 """make a copy of an existing repository
1831 1851
1832 1852 Create a copy of an existing repository in a new directory.
1833 1853
1834 1854 If no destination directory name is specified, it defaults to the
1835 1855 basename of the source.
1836 1856
1837 1857 The location of the source is added to the new repository's
1838 1858 ``.hg/hgrc`` file, as the default to be used for future pulls.
1839 1859
1840 1860 Only local paths and ``ssh://`` URLs are supported as
1841 1861 destinations. For ``ssh://`` destinations, no working directory or
1842 1862 ``.hg/hgrc`` will be created on the remote side.
1843 1863
1844 1864 If the source repository has a bookmark called '@' set, that
1845 1865 revision will be checked out in the new repository by default.
1846 1866
1847 1867 To check out a particular version, use -u/--update, or
1848 1868 -U/--noupdate to create a clone with no working directory.
1849 1869
1850 1870 To pull only a subset of changesets, specify one or more revisions
1851 1871 identifiers with -r/--rev or branches with -b/--branch. The
1852 1872 resulting clone will contain only the specified changesets and
1853 1873 their ancestors. These options (or 'clone src#rev dest') imply
1854 1874 --pull, even for local source repositories.
1855 1875
1856 1876 In normal clone mode, the remote normalizes repository data into a common
1857 1877 exchange format and the receiving end translates this data into its local
1858 1878 storage format. --stream activates a different clone mode that essentially
1859 1879 copies repository files from the remote with minimal data processing. This
1860 1880 significantly reduces the CPU cost of a clone both remotely and locally.
1861 1881 However, it often increases the transferred data size by 30-40%. This can
1862 1882 result in substantially faster clones where I/O throughput is plentiful,
1863 1883 especially for larger repositories. A side-effect of --stream clones is
1864 1884 that storage settings and requirements on the remote are applied locally:
1865 1885 a modern client may inherit legacy or inefficient storage used by the
1866 1886 remote or a legacy Mercurial client may not be able to clone from a
1867 1887 modern Mercurial remote.
1868 1888
1869 1889 .. note::
1870 1890
1871 1891 Specifying a tag will include the tagged changeset but not the
1872 1892 changeset containing the tag.
1873 1893
1874 1894 .. container:: verbose
1875 1895
1876 1896 For efficiency, hardlinks are used for cloning whenever the
1877 1897 source and destination are on the same filesystem (note this
1878 1898 applies only to the repository data, not to the working
1879 1899 directory). Some filesystems, such as AFS, implement hardlinking
1880 1900 incorrectly, but do not report errors. In these cases, use the
1881 1901 --pull option to avoid hardlinking.
1882 1902
1883 1903 Mercurial will update the working directory to the first applicable
1884 1904 revision from this list:
1885 1905
1886 1906 a) null if -U or the source repository has no changesets
1887 1907 b) if -u . and the source repository is local, the first parent of
1888 1908 the source repository's working directory
1889 1909 c) the changeset specified with -u (if a branch name, this means the
1890 1910 latest head of that branch)
1891 1911 d) the changeset specified with -r
1892 1912 e) the tipmost head specified with -b
1893 1913 f) the tipmost head specified with the url#branch source syntax
1894 1914 g) the revision marked with the '@' bookmark, if present
1895 1915 h) the tipmost head of the default branch
1896 1916 i) tip
1897 1917
1898 1918 When cloning from servers that support it, Mercurial may fetch
1899 1919 pre-generated data from a server-advertised URL or inline from the
1900 1920 same stream. When this is done, hooks operating on incoming changesets
1901 1921 and changegroups may fire more than once, once for each pre-generated
1902 1922 bundle and as well as for any additional remaining data. In addition,
1903 1923 if an error occurs, the repository may be rolled back to a partial
1904 1924 clone. This behavior may change in future releases.
1905 1925 See :hg:`help -e clonebundles` for more.
1906 1926
1907 1927 Examples:
1908 1928
1909 1929 - clone a remote repository to a new directory named hg/::
1910 1930
1911 1931 hg clone https://www.mercurial-scm.org/repo/hg/
1912 1932
1913 1933 - create a lightweight local clone::
1914 1934
1915 1935 hg clone project/ project-feature/
1916 1936
1917 1937 - clone from an absolute path on an ssh server (note double-slash)::
1918 1938
1919 1939 hg clone ssh://user@server//home/projects/alpha/
1920 1940
1921 1941 - do a streaming clone while checking out a specified version::
1922 1942
1923 1943 hg clone --stream http://server/repo -u 1.5
1924 1944
1925 1945 - create a repository without changesets after a particular revision::
1926 1946
1927 1947 hg clone -r 04e544 experimental/ good/
1928 1948
1929 1949 - clone (and track) a particular named branch::
1930 1950
1931 1951 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1932 1952
1933 1953 See :hg:`help urls` for details on specifying URLs.
1934 1954
1935 1955 Returns 0 on success.
1936 1956 """
1937 1957 opts = pycompat.byteskwargs(opts)
1938 1958 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1939 1959
1940 1960 # --include/--exclude can come from narrow or sparse.
1941 1961 includepats, excludepats = None, None
1942 1962
1943 1963 # hg.clone() differentiates between None and an empty set. So make sure
1944 1964 # patterns are sets if narrow is requested without patterns.
1945 1965 if opts.get(b'narrow'):
1946 1966 includepats = set()
1947 1967 excludepats = set()
1948 1968
1949 1969 if opts.get(b'include'):
1950 1970 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1951 1971 if opts.get(b'exclude'):
1952 1972 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1953 1973
1954 1974 r = hg.clone(
1955 1975 ui,
1956 1976 opts,
1957 1977 source,
1958 1978 dest,
1959 1979 pull=opts.get(b'pull'),
1960 1980 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1961 1981 revs=opts.get(b'rev'),
1962 1982 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1963 1983 branch=opts.get(b'branch'),
1964 1984 shareopts=opts.get(b'shareopts'),
1965 1985 storeincludepats=includepats,
1966 1986 storeexcludepats=excludepats,
1967 1987 depth=opts.get(b'depth') or None,
1968 1988 )
1969 1989
1970 1990 return r is None
1971 1991
1972 1992
1973 1993 @command(
1974 1994 b'commit|ci',
1975 1995 [
1976 1996 (
1977 1997 b'A',
1978 1998 b'addremove',
1979 1999 None,
1980 2000 _(b'mark new/missing files as added/removed before committing'),
1981 2001 ),
1982 2002 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1983 2003 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1984 2004 (b's', b'secret', None, _(b'use the secret phase for committing')),
1985 2005 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1986 2006 (
1987 2007 b'',
1988 2008 b'force-close-branch',
1989 2009 None,
1990 2010 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1991 2011 ),
1992 2012 (b'i', b'interactive', None, _(b'use interactive mode')),
1993 2013 ]
1994 2014 + walkopts
1995 2015 + commitopts
1996 2016 + commitopts2
1997 2017 + subrepoopts,
1998 2018 _(b'[OPTION]... [FILE]...'),
1999 2019 helpcategory=command.CATEGORY_COMMITTING,
2000 2020 helpbasic=True,
2001 2021 inferrepo=True,
2002 2022 )
2003 2023 def commit(ui, repo, *pats, **opts):
2004 2024 """commit the specified files or all outstanding changes
2005 2025
2006 2026 Commit changes to the given files into the repository. Unlike a
2007 2027 centralized SCM, this operation is a local operation. See
2008 2028 :hg:`push` for a way to actively distribute your changes.
2009 2029
2010 2030 If a list of files is omitted, all changes reported by :hg:`status`
2011 2031 will be committed.
2012 2032
2013 2033 If you are committing the result of a merge, do not provide any
2014 2034 filenames or -I/-X filters.
2015 2035
2016 2036 If no commit message is specified, Mercurial starts your
2017 2037 configured editor where you can enter a message. In case your
2018 2038 commit fails, you will find a backup of your message in
2019 2039 ``.hg/last-message.txt``.
2020 2040
2021 2041 The --close-branch flag can be used to mark the current branch
2022 2042 head closed. When all heads of a branch are closed, the branch
2023 2043 will be considered closed and no longer listed.
2024 2044
2025 2045 The --amend flag can be used to amend the parent of the
2026 2046 working directory with a new commit that contains the changes
2027 2047 in the parent in addition to those currently reported by :hg:`status`,
2028 2048 if there are any. The old commit is stored in a backup bundle in
2029 2049 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2030 2050 on how to restore it).
2031 2051
2032 2052 Message, user and date are taken from the amended commit unless
2033 2053 specified. When a message isn't specified on the command line,
2034 2054 the editor will open with the message of the amended commit.
2035 2055
2036 2056 It is not possible to amend public changesets (see :hg:`help phases`)
2037 2057 or changesets that have children.
2038 2058
2039 2059 See :hg:`help dates` for a list of formats valid for -d/--date.
2040 2060
2041 2061 Returns 0 on success, 1 if nothing changed.
2042 2062
2043 2063 .. container:: verbose
2044 2064
2045 2065 Examples:
2046 2066
2047 2067 - commit all files ending in .py::
2048 2068
2049 2069 hg commit --include "set:**.py"
2050 2070
2051 2071 - commit all non-binary files::
2052 2072
2053 2073 hg commit --exclude "set:binary()"
2054 2074
2055 2075 - amend the current commit and set the date to now::
2056 2076
2057 2077 hg commit --amend --date now
2058 2078 """
2059 2079 with repo.wlock(), repo.lock():
2060 2080 return _docommit(ui, repo, *pats, **opts)
2061 2081
2062 2082
2063 2083 def _docommit(ui, repo, *pats, **opts):
2064 2084 if opts.get('interactive'):
2065 2085 opts.pop('interactive')
2066 2086 ret = cmdutil.dorecord(
2067 2087 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2068 2088 )
2069 2089 # ret can be 0 (no changes to record) or the value returned by
2070 2090 # commit(), 1 if nothing changed or None on success.
2071 2091 return 1 if ret == 0 else ret
2072 2092
2073 2093 if opts.get('subrepos'):
2074 2094 cmdutil.check_incompatible_arguments(opts, 'subrepos', ['amend'])
2075 2095 # Let --subrepos on the command line override config setting.
2076 2096 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2077 2097
2078 2098 cmdutil.checkunfinished(repo, commit=True)
2079 2099
2080 2100 branch = repo[None].branch()
2081 2101 bheads = repo.branchheads(branch)
2082 2102 tip = repo.changelog.tip()
2083 2103
2084 2104 extra = {}
2085 2105 if opts.get('close_branch') or opts.get('force_close_branch'):
2086 2106 extra[b'close'] = b'1'
2087 2107
2088 2108 if repo[b'.'].closesbranch():
2089 2109 # Not ideal, but let us do an extra status early to prevent early
2090 2110 # bail out.
2091 2111 matcher = scmutil.match(repo[None], pats, opts)
2092 2112 s = repo.status(match=matcher)
2093 2113 if s.modified or s.added or s.removed:
2094 2114 bheads = repo.branchheads(branch, closed=True)
2095 2115 else:
2096 2116 msg = _(b'current revision is already a branch closing head')
2097 2117 raise error.InputError(msg)
2098 2118
2099 2119 if not bheads:
2100 2120 raise error.InputError(
2101 2121 _(b'branch "%s" has no heads to close') % branch
2102 2122 )
2103 2123 elif (
2104 2124 branch == repo[b'.'].branch()
2105 2125 and repo[b'.'].node() not in bheads
2106 2126 and not opts.get('force_close_branch')
2107 2127 ):
2108 2128 hint = _(
2109 2129 b'use --force-close-branch to close branch from a non-head'
2110 2130 b' changeset'
2111 2131 )
2112 2132 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2113 2133 elif opts.get('amend'):
2114 2134 if (
2115 2135 repo[b'.'].p1().branch() != branch
2116 2136 and repo[b'.'].p2().branch() != branch
2117 2137 ):
2118 2138 raise error.InputError(_(b'can only close branch heads'))
2119 2139
2120 2140 if opts.get('amend'):
2121 2141 if ui.configbool(b'ui', b'commitsubrepos'):
2122 2142 raise error.InputError(
2123 2143 _(b'cannot amend with ui.commitsubrepos enabled')
2124 2144 )
2125 2145
2126 2146 old = repo[b'.']
2127 2147 rewriteutil.precheck(repo, [old.rev()], b'amend')
2128 2148
2129 2149 # Currently histedit gets confused if an amend happens while histedit
2130 2150 # is in progress. Since we have a checkunfinished command, we are
2131 2151 # temporarily honoring it.
2132 2152 #
2133 2153 # Note: eventually this guard will be removed. Please do not expect
2134 2154 # this behavior to remain.
2135 2155 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2136 2156 cmdutil.checkunfinished(repo)
2137 2157
2138 2158 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2139 2159 opts = pycompat.byteskwargs(opts)
2140 2160 if node == old.node():
2141 2161 ui.status(_(b"nothing changed\n"))
2142 2162 return 1
2143 2163 else:
2144 2164
2145 2165 def commitfunc(ui, repo, message, match, opts):
2146 2166 overrides = {}
2147 2167 if opts.get(b'secret'):
2148 2168 overrides[(b'phases', b'new-commit')] = b'secret'
2149 2169
2150 2170 baseui = repo.baseui
2151 2171 with baseui.configoverride(overrides, b'commit'):
2152 2172 with ui.configoverride(overrides, b'commit'):
2153 2173 editform = cmdutil.mergeeditform(
2154 2174 repo[None], b'commit.normal'
2155 2175 )
2156 2176 editor = cmdutil.getcommiteditor(
2157 2177 editform=editform, **pycompat.strkwargs(opts)
2158 2178 )
2159 2179 return repo.commit(
2160 2180 message,
2161 2181 opts.get(b'user'),
2162 2182 opts.get(b'date'),
2163 2183 match,
2164 2184 editor=editor,
2165 2185 extra=extra,
2166 2186 )
2167 2187
2168 2188 opts = pycompat.byteskwargs(opts)
2169 2189 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2170 2190
2171 2191 if not node:
2172 2192 stat = cmdutil.postcommitstatus(repo, pats, opts)
2173 2193 if stat.deleted:
2174 2194 ui.status(
2175 2195 _(
2176 2196 b"nothing changed (%d missing files, see "
2177 2197 b"'hg status')\n"
2178 2198 )
2179 2199 % len(stat.deleted)
2180 2200 )
2181 2201 else:
2182 2202 ui.status(_(b"nothing changed\n"))
2183 2203 return 1
2184 2204
2185 2205 cmdutil.commitstatus(repo, node, branch, bheads, tip, opts)
2186 2206
2187 2207 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2188 2208 status(
2189 2209 ui,
2190 2210 repo,
2191 2211 modified=True,
2192 2212 added=True,
2193 2213 removed=True,
2194 2214 deleted=True,
2195 2215 unknown=True,
2196 2216 subrepos=opts.get(b'subrepos'),
2197 2217 )
2198 2218
2199 2219
2200 2220 @command(
2201 2221 b'config|showconfig|debugconfig',
2202 2222 [
2203 2223 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2204 2224 # This is experimental because we need
2205 2225 # * reasonable behavior around aliases,
2206 2226 # * decide if we display [debug] [experimental] and [devel] section par
2207 2227 # default
2208 2228 # * some way to display "generic" config entry (the one matching
2209 2229 # regexp,
2210 2230 # * proper display of the different value type
2211 2231 # * a better way to handle <DYNAMIC> values (and variable types),
2212 2232 # * maybe some type information ?
2213 2233 (
2214 2234 b'',
2215 2235 b'exp-all-known',
2216 2236 None,
2217 2237 _(b'show all known config option (EXPERIMENTAL)'),
2218 2238 ),
2219 2239 (b'e', b'edit', None, _(b'edit user config')),
2220 2240 (b'l', b'local', None, _(b'edit repository config')),
2221 2241 (b'', b'source', None, _(b'show source of configuration value')),
2222 2242 (
2223 2243 b'',
2224 2244 b'shared',
2225 2245 None,
2226 2246 _(b'edit shared source repository config (EXPERIMENTAL)'),
2227 2247 ),
2228 2248 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2229 2249 (b'g', b'global', None, _(b'edit global config')),
2230 2250 ]
2231 2251 + formatteropts,
2232 2252 _(b'[-u] [NAME]...'),
2233 2253 helpcategory=command.CATEGORY_HELP,
2234 2254 optionalrepo=True,
2235 2255 intents={INTENT_READONLY},
2236 2256 )
2237 2257 def config(ui, repo, *values, **opts):
2238 2258 """show combined config settings from all hgrc files
2239 2259
2240 2260 With no arguments, print names and values of all config items.
2241 2261
2242 2262 With one argument of the form section.name, print just the value
2243 2263 of that config item.
2244 2264
2245 2265 With multiple arguments, print names and values of all config
2246 2266 items with matching section names or section.names.
2247 2267
2248 2268 With --edit, start an editor on the user-level config file. With
2249 2269 --global, edit the system-wide config file. With --local, edit the
2250 2270 repository-level config file.
2251 2271
2252 2272 With --source, the source (filename and line number) is printed
2253 2273 for each config item.
2254 2274
2255 2275 See :hg:`help config` for more information about config files.
2256 2276
2257 2277 .. container:: verbose
2258 2278
2259 2279 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2260 2280 This file is not shared across shares when in share-safe mode.
2261 2281
2262 2282 Template:
2263 2283
2264 2284 The following keywords are supported. See also :hg:`help templates`.
2265 2285
2266 2286 :name: String. Config name.
2267 2287 :source: String. Filename and line number where the item is defined.
2268 2288 :value: String. Config value.
2269 2289
2270 2290 The --shared flag can be used to edit the config file of shared source
2271 2291 repository. It only works when you have shared using the experimental
2272 2292 share safe feature.
2273 2293
2274 2294 Returns 0 on success, 1 if NAME does not exist.
2275 2295
2276 2296 """
2277 2297
2278 2298 opts = pycompat.byteskwargs(opts)
2279 2299 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2280 2300 if any(opts.get(o) for o in editopts):
2281 2301 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2282 2302 if opts.get(b'local'):
2283 2303 if not repo:
2284 2304 raise error.InputError(
2285 2305 _(b"can't use --local outside a repository")
2286 2306 )
2287 2307 paths = [repo.vfs.join(b'hgrc')]
2288 2308 elif opts.get(b'global'):
2289 2309 paths = rcutil.systemrcpath()
2290 2310 elif opts.get(b'shared'):
2291 2311 if not repo.shared():
2292 2312 raise error.InputError(
2293 2313 _(b"repository is not shared; can't use --shared")
2294 2314 )
2295 2315 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2296 2316 raise error.InputError(
2297 2317 _(
2298 2318 b"share safe feature not enabled; "
2299 2319 b"unable to edit shared source repository config"
2300 2320 )
2301 2321 )
2302 2322 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2303 2323 elif opts.get(b'non_shared'):
2304 2324 paths = [repo.vfs.join(b'hgrc-not-shared')]
2305 2325 else:
2306 2326 paths = rcutil.userrcpath()
2307 2327
2308 2328 for f in paths:
2309 2329 if os.path.exists(f):
2310 2330 break
2311 2331 else:
2312 2332 if opts.get(b'global'):
2313 2333 samplehgrc = uimod.samplehgrcs[b'global']
2314 2334 elif opts.get(b'local'):
2315 2335 samplehgrc = uimod.samplehgrcs[b'local']
2316 2336 else:
2317 2337 samplehgrc = uimod.samplehgrcs[b'user']
2318 2338
2319 2339 f = paths[0]
2320 2340 fp = open(f, b"wb")
2321 2341 fp.write(util.tonativeeol(samplehgrc))
2322 2342 fp.close()
2323 2343
2324 2344 editor = ui.geteditor()
2325 2345 ui.system(
2326 2346 b"%s \"%s\"" % (editor, f),
2327 2347 onerr=error.InputError,
2328 2348 errprefix=_(b"edit failed"),
2329 2349 blockedtag=b'config_edit',
2330 2350 )
2331 2351 return
2332 2352 ui.pager(b'config')
2333 2353 fm = ui.formatter(b'config', opts)
2334 2354 for t, f in rcutil.rccomponents():
2335 2355 if t == b'path':
2336 2356 ui.debug(b'read config from: %s\n' % f)
2337 2357 elif t == b'resource':
2338 2358 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2339 2359 elif t == b'items':
2340 2360 # Don't print anything for 'items'.
2341 2361 pass
2342 2362 else:
2343 2363 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2344 2364 untrusted = bool(opts.get(b'untrusted'))
2345 2365
2346 2366 selsections = selentries = []
2347 2367 if values:
2348 2368 selsections = [v for v in values if b'.' not in v]
2349 2369 selentries = [v for v in values if b'.' in v]
2350 2370 uniquesel = len(selentries) == 1 and not selsections
2351 2371 selsections = set(selsections)
2352 2372 selentries = set(selentries)
2353 2373
2354 2374 matched = False
2355 2375 all_known = opts[b'exp_all_known']
2356 2376 show_source = ui.debugflag or opts.get(b'source')
2357 2377 entries = ui.walkconfig(untrusted=untrusted, all_known=all_known)
2358 2378 for section, name, value in entries:
2359 2379 source = ui.configsource(section, name, untrusted)
2360 2380 value = pycompat.bytestr(value)
2361 2381 defaultvalue = ui.configdefault(section, name)
2362 2382 if fm.isplain():
2363 2383 source = source or b'none'
2364 2384 value = value.replace(b'\n', b'\\n')
2365 2385 entryname = section + b'.' + name
2366 2386 if values and not (section in selsections or entryname in selentries):
2367 2387 continue
2368 2388 fm.startitem()
2369 2389 fm.condwrite(show_source, b'source', b'%s: ', source)
2370 2390 if uniquesel:
2371 2391 fm.data(name=entryname)
2372 2392 fm.write(b'value', b'%s\n', value)
2373 2393 else:
2374 2394 fm.write(b'name value', b'%s=%s\n', entryname, value)
2375 2395 if formatter.isprintable(defaultvalue):
2376 2396 fm.data(defaultvalue=defaultvalue)
2377 2397 elif isinstance(defaultvalue, list) and all(
2378 2398 formatter.isprintable(e) for e in defaultvalue
2379 2399 ):
2380 2400 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2381 2401 # TODO: no idea how to process unsupported defaultvalue types
2382 2402 matched = True
2383 2403 fm.end()
2384 2404 if matched:
2385 2405 return 0
2386 2406 return 1
2387 2407
2388 2408
2389 2409 @command(
2390 2410 b'continue',
2391 2411 dryrunopts,
2392 2412 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2393 2413 helpbasic=True,
2394 2414 )
2395 2415 def continuecmd(ui, repo, **opts):
2396 2416 """resumes an interrupted operation (EXPERIMENTAL)
2397 2417
2398 2418 Finishes a multistep operation like graft, histedit, rebase, merge,
2399 2419 and unshelve if they are in an interrupted state.
2400 2420
2401 2421 use --dry-run/-n to dry run the command.
2402 2422 """
2403 2423 dryrun = opts.get('dry_run')
2404 2424 contstate = cmdutil.getunfinishedstate(repo)
2405 2425 if not contstate:
2406 2426 raise error.StateError(_(b'no operation in progress'))
2407 2427 if not contstate.continuefunc:
2408 2428 raise error.StateError(
2409 2429 (
2410 2430 _(b"%s in progress but does not support 'hg continue'")
2411 2431 % (contstate._opname)
2412 2432 ),
2413 2433 hint=contstate.continuemsg(),
2414 2434 )
2415 2435 if dryrun:
2416 2436 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2417 2437 return
2418 2438 return contstate.continuefunc(ui, repo)
2419 2439
2420 2440
2421 2441 @command(
2422 2442 b'copy|cp',
2423 2443 [
2424 2444 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2425 2445 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2426 2446 (
2427 2447 b'',
2428 2448 b'at-rev',
2429 2449 b'',
2430 2450 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2431 2451 _(b'REV'),
2432 2452 ),
2433 2453 (
2434 2454 b'f',
2435 2455 b'force',
2436 2456 None,
2437 2457 _(b'forcibly copy over an existing managed file'),
2438 2458 ),
2439 2459 ]
2440 2460 + walkopts
2441 2461 + dryrunopts,
2442 2462 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2443 2463 helpcategory=command.CATEGORY_FILE_CONTENTS,
2444 2464 )
2445 2465 def copy(ui, repo, *pats, **opts):
2446 2466 """mark files as copied for the next commit
2447 2467
2448 2468 Mark dest as having copies of source files. If dest is a
2449 2469 directory, copies are put in that directory. If dest is a file,
2450 2470 the source must be a single file.
2451 2471
2452 2472 By default, this command copies the contents of files as they
2453 2473 exist in the working directory. If invoked with -A/--after, the
2454 2474 operation is recorded, but no copying is performed.
2455 2475
2456 2476 To undo marking a destination file as copied, use --forget. With that
2457 2477 option, all given (positional) arguments are unmarked as copies. The
2458 2478 destination file(s) will be left in place (still tracked). Note that
2459 2479 :hg:`copy --forget` behaves the same way as :hg:`rename --forget`.
2460 2480
2461 2481 This command takes effect with the next commit by default.
2462 2482
2463 2483 Returns 0 on success, 1 if errors are encountered.
2464 2484 """
2465 2485 opts = pycompat.byteskwargs(opts)
2466 2486 with repo.wlock():
2467 2487 return cmdutil.copy(ui, repo, pats, opts)
2468 2488
2469 2489
2470 2490 @command(
2471 2491 b'debugcommands',
2472 2492 [],
2473 2493 _(b'[COMMAND]'),
2474 2494 helpcategory=command.CATEGORY_HELP,
2475 2495 norepo=True,
2476 2496 )
2477 2497 def debugcommands(ui, cmd=b'', *args):
2478 2498 """list all available commands and options"""
2479 2499 for cmd, vals in sorted(table.items()):
2480 2500 cmd = cmd.split(b'|')[0]
2481 2501 opts = b', '.join([i[1] for i in vals[1]])
2482 2502 ui.write(b'%s: %s\n' % (cmd, opts))
2483 2503
2484 2504
2485 2505 @command(
2486 2506 b'debugcomplete',
2487 2507 [(b'o', b'options', None, _(b'show the command options'))],
2488 2508 _(b'[-o] CMD'),
2489 2509 helpcategory=command.CATEGORY_HELP,
2490 2510 norepo=True,
2491 2511 )
2492 2512 def debugcomplete(ui, cmd=b'', **opts):
2493 2513 """returns the completion list associated with the given command"""
2494 2514
2495 2515 if opts.get('options'):
2496 2516 options = []
2497 2517 otables = [globalopts]
2498 2518 if cmd:
2499 2519 aliases, entry = cmdutil.findcmd(cmd, table, False)
2500 2520 otables.append(entry[1])
2501 2521 for t in otables:
2502 2522 for o in t:
2503 2523 if b"(DEPRECATED)" in o[3]:
2504 2524 continue
2505 2525 if o[0]:
2506 2526 options.append(b'-%s' % o[0])
2507 2527 options.append(b'--%s' % o[1])
2508 2528 ui.write(b"%s\n" % b"\n".join(options))
2509 2529 return
2510 2530
2511 2531 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2512 2532 if ui.verbose:
2513 2533 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2514 2534 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2515 2535
2516 2536
2517 2537 @command(
2518 2538 b'diff',
2519 2539 [
2520 2540 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2521 2541 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2522 2542 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2523 2543 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2524 2544 ]
2525 2545 + diffopts
2526 2546 + diffopts2
2527 2547 + walkopts
2528 2548 + subrepoopts,
2529 2549 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2530 2550 helpcategory=command.CATEGORY_FILE_CONTENTS,
2531 2551 helpbasic=True,
2532 2552 inferrepo=True,
2533 2553 intents={INTENT_READONLY},
2534 2554 )
2535 2555 def diff(ui, repo, *pats, **opts):
2536 2556 """diff repository (or selected files)
2537 2557
2538 2558 Show differences between revisions for the specified files.
2539 2559
2540 2560 Differences between files are shown using the unified diff format.
2541 2561
2542 2562 .. note::
2543 2563
2544 2564 :hg:`diff` may generate unexpected results for merges, as it will
2545 2565 default to comparing against the working directory's first
2546 2566 parent changeset if no revisions are specified. To diff against the
2547 2567 conflict regions, you can use `--config diff.merge=yes`.
2548 2568
2549 2569 By default, the working directory files are compared to its first parent. To
2550 2570 see the differences from another revision, use --from. To see the difference
2551 2571 to another revision, use --to. For example, :hg:`diff --from .^` will show
2552 2572 the differences from the working copy's grandparent to the working copy,
2553 2573 :hg:`diff --to .` will show the diff from the working copy to its parent
2554 2574 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2555 2575 show the diff between those two revisions.
2556 2576
2557 2577 Alternatively you can specify -c/--change with a revision to see the changes
2558 2578 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2559 2579 equivalent to :hg:`diff --from 42^ --to 42`)
2560 2580
2561 2581 Without the -a/--text option, diff will avoid generating diffs of
2562 2582 files it detects as binary. With -a, diff will generate a diff
2563 2583 anyway, probably with undesirable results.
2564 2584
2565 2585 Use the -g/--git option to generate diffs in the git extended diff
2566 2586 format. For more information, read :hg:`help diffs`.
2567 2587
2568 2588 .. container:: verbose
2569 2589
2570 2590 Examples:
2571 2591
2572 2592 - compare a file in the current working directory to its parent::
2573 2593
2574 2594 hg diff foo.c
2575 2595
2576 2596 - compare two historical versions of a directory, with rename info::
2577 2597
2578 2598 hg diff --git --from 1.0 --to 1.2 lib/
2579 2599
2580 2600 - get change stats relative to the last change on some date::
2581 2601
2582 2602 hg diff --stat --from "date('may 2')"
2583 2603
2584 2604 - diff all newly-added files that contain a keyword::
2585 2605
2586 2606 hg diff "set:added() and grep(GNU)"
2587 2607
2588 2608 - compare a revision and its parents::
2589 2609
2590 2610 hg diff -c 9353 # compare against first parent
2591 2611 hg diff --from 9353^ --to 9353 # same using revset syntax
2592 2612 hg diff --from 9353^2 --to 9353 # compare against the second parent
2593 2613
2594 2614 Returns 0 on success.
2595 2615 """
2596 2616
2597 2617 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2598 2618 opts = pycompat.byteskwargs(opts)
2599 2619 revs = opts.get(b'rev')
2600 2620 change = opts.get(b'change')
2601 2621 from_rev = opts.get(b'from')
2602 2622 to_rev = opts.get(b'to')
2603 2623 stat = opts.get(b'stat')
2604 2624 reverse = opts.get(b'reverse')
2605 2625
2606 2626 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2607 2627 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2608 2628 if change:
2609 2629 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2610 2630 ctx2 = logcmdutil.revsingle(repo, change, None)
2611 2631 ctx1 = logcmdutil.diff_parent(ctx2)
2612 2632 elif from_rev or to_rev:
2613 2633 repo = scmutil.unhidehashlikerevs(
2614 2634 repo, [from_rev] + [to_rev], b'nowarn'
2615 2635 )
2616 2636 ctx1 = logcmdutil.revsingle(repo, from_rev, None)
2617 2637 ctx2 = logcmdutil.revsingle(repo, to_rev, None)
2618 2638 else:
2619 2639 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2620 2640 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
2621 2641
2622 2642 if reverse:
2623 2643 ctxleft = ctx2
2624 2644 ctxright = ctx1
2625 2645 else:
2626 2646 ctxleft = ctx1
2627 2647 ctxright = ctx2
2628 2648
2629 2649 diffopts = patch.diffallopts(ui, opts)
2630 2650 m = scmutil.match(ctx2, pats, opts)
2631 2651 m = repo.narrowmatch(m)
2632 2652 ui.pager(b'diff')
2633 2653 logcmdutil.diffordiffstat(
2634 2654 ui,
2635 2655 repo,
2636 2656 diffopts,
2637 2657 ctxleft,
2638 2658 ctxright,
2639 2659 m,
2640 2660 stat=stat,
2641 2661 listsubrepos=opts.get(b'subrepos'),
2642 2662 root=opts.get(b'root'),
2643 2663 )
2644 2664
2645 2665
2646 2666 @command(
2647 2667 b'export',
2648 2668 [
2649 2669 (
2650 2670 b'B',
2651 2671 b'bookmark',
2652 2672 b'',
2653 2673 _(b'export changes only reachable by given bookmark'),
2654 2674 _(b'BOOKMARK'),
2655 2675 ),
2656 2676 (
2657 2677 b'o',
2658 2678 b'output',
2659 2679 b'',
2660 2680 _(b'print output to file with formatted name'),
2661 2681 _(b'FORMAT'),
2662 2682 ),
2663 2683 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2664 2684 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2665 2685 ]
2666 2686 + diffopts
2667 2687 + formatteropts,
2668 2688 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2669 2689 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2670 2690 helpbasic=True,
2671 2691 intents={INTENT_READONLY},
2672 2692 )
2673 2693 def export(ui, repo, *changesets, **opts):
2674 2694 """dump the header and diffs for one or more changesets
2675 2695
2676 2696 Print the changeset header and diffs for one or more revisions.
2677 2697 If no revision is given, the parent of the working directory is used.
2678 2698
2679 2699 The information shown in the changeset header is: author, date,
2680 2700 branch name (if non-default), changeset hash, parent(s) and commit
2681 2701 comment.
2682 2702
2683 2703 .. note::
2684 2704
2685 2705 :hg:`export` may generate unexpected diff output for merge
2686 2706 changesets, as it will compare the merge changeset against its
2687 2707 first parent only.
2688 2708
2689 2709 Output may be to a file, in which case the name of the file is
2690 2710 given using a template string. See :hg:`help templates`. In addition
2691 2711 to the common template keywords, the following formatting rules are
2692 2712 supported:
2693 2713
2694 2714 :``%%``: literal "%" character
2695 2715 :``%H``: changeset hash (40 hexadecimal digits)
2696 2716 :``%N``: number of patches being generated
2697 2717 :``%R``: changeset revision number
2698 2718 :``%b``: basename of the exporting repository
2699 2719 :``%h``: short-form changeset hash (12 hexadecimal digits)
2700 2720 :``%m``: first line of the commit message (only alphanumeric characters)
2701 2721 :``%n``: zero-padded sequence number, starting at 1
2702 2722 :``%r``: zero-padded changeset revision number
2703 2723 :``\\``: literal "\\" character
2704 2724
2705 2725 Without the -a/--text option, export will avoid generating diffs
2706 2726 of files it detects as binary. With -a, export will generate a
2707 2727 diff anyway, probably with undesirable results.
2708 2728
2709 2729 With -B/--bookmark changesets reachable by the given bookmark are
2710 2730 selected.
2711 2731
2712 2732 Use the -g/--git option to generate diffs in the git extended diff
2713 2733 format. See :hg:`help diffs` for more information.
2714 2734
2715 2735 With the --switch-parent option, the diff will be against the
2716 2736 second parent. It can be useful to review a merge.
2717 2737
2718 2738 .. container:: verbose
2719 2739
2720 2740 Template:
2721 2741
2722 2742 The following keywords are supported in addition to the common template
2723 2743 keywords and functions. See also :hg:`help templates`.
2724 2744
2725 2745 :diff: String. Diff content.
2726 2746 :parents: List of strings. Parent nodes of the changeset.
2727 2747
2728 2748 Examples:
2729 2749
2730 2750 - use export and import to transplant a bugfix to the current
2731 2751 branch::
2732 2752
2733 2753 hg export -r 9353 | hg import -
2734 2754
2735 2755 - export all the changesets between two revisions to a file with
2736 2756 rename information::
2737 2757
2738 2758 hg export --git -r 123:150 > changes.txt
2739 2759
2740 2760 - split outgoing changes into a series of patches with
2741 2761 descriptive names::
2742 2762
2743 2763 hg export -r "outgoing()" -o "%n-%m.patch"
2744 2764
2745 2765 Returns 0 on success.
2746 2766 """
2747 2767 opts = pycompat.byteskwargs(opts)
2748 2768 bookmark = opts.get(b'bookmark')
2749 2769 changesets += tuple(opts.get(b'rev', []))
2750 2770
2751 2771 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2752 2772
2753 2773 if bookmark:
2754 2774 if bookmark not in repo._bookmarks:
2755 2775 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2756 2776
2757 2777 revs = scmutil.bookmarkrevs(repo, bookmark)
2758 2778 else:
2759 2779 if not changesets:
2760 2780 changesets = [b'.']
2761 2781
2762 2782 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2763 2783 revs = logcmdutil.revrange(repo, changesets)
2764 2784
2765 2785 if not revs:
2766 2786 raise error.InputError(_(b"export requires at least one changeset"))
2767 2787 if len(revs) > 1:
2768 2788 ui.note(_(b'exporting patches:\n'))
2769 2789 else:
2770 2790 ui.note(_(b'exporting patch:\n'))
2771 2791
2772 2792 fntemplate = opts.get(b'output')
2773 2793 if cmdutil.isstdiofilename(fntemplate):
2774 2794 fntemplate = b''
2775 2795
2776 2796 if fntemplate:
2777 2797 fm = formatter.nullformatter(ui, b'export', opts)
2778 2798 else:
2779 2799 ui.pager(b'export')
2780 2800 fm = ui.formatter(b'export', opts)
2781 2801 with fm:
2782 2802 cmdutil.export(
2783 2803 repo,
2784 2804 revs,
2785 2805 fm,
2786 2806 fntemplate=fntemplate,
2787 2807 switch_parent=opts.get(b'switch_parent'),
2788 2808 opts=patch.diffallopts(ui, opts),
2789 2809 )
2790 2810
2791 2811
2792 2812 @command(
2793 2813 b'files',
2794 2814 [
2795 2815 (
2796 2816 b'r',
2797 2817 b'rev',
2798 2818 b'',
2799 2819 _(b'search the repository as it is in REV'),
2800 2820 _(b'REV'),
2801 2821 ),
2802 2822 (
2803 2823 b'0',
2804 2824 b'print0',
2805 2825 None,
2806 2826 _(b'end filenames with NUL, for use with xargs'),
2807 2827 ),
2808 2828 ]
2809 2829 + walkopts
2810 2830 + formatteropts
2811 2831 + subrepoopts,
2812 2832 _(b'[OPTION]... [FILE]...'),
2813 2833 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2814 2834 intents={INTENT_READONLY},
2815 2835 )
2816 2836 def files(ui, repo, *pats, **opts):
2817 2837 """list tracked files
2818 2838
2819 2839 Print files under Mercurial control in the working directory or
2820 2840 specified revision for given files (excluding removed files).
2821 2841 Files can be specified as filenames or filesets.
2822 2842
2823 2843 If no files are given to match, this command prints the names
2824 2844 of all files under Mercurial control.
2825 2845
2826 2846 .. container:: verbose
2827 2847
2828 2848 Template:
2829 2849
2830 2850 The following keywords are supported in addition to the common template
2831 2851 keywords and functions. See also :hg:`help templates`.
2832 2852
2833 2853 :flags: String. Character denoting file's symlink and executable bits.
2834 2854 :path: String. Repository-absolute path of the file.
2835 2855 :size: Integer. Size of the file in bytes.
2836 2856
2837 2857 Examples:
2838 2858
2839 2859 - list all files under the current directory::
2840 2860
2841 2861 hg files .
2842 2862
2843 2863 - shows sizes and flags for current revision::
2844 2864
2845 2865 hg files -vr .
2846 2866
2847 2867 - list all files named README::
2848 2868
2849 2869 hg files -I "**/README"
2850 2870
2851 2871 - list all binary files::
2852 2872
2853 2873 hg files "set:binary()"
2854 2874
2855 2875 - find files containing a regular expression::
2856 2876
2857 2877 hg files "set:grep('bob')"
2858 2878
2859 2879 - search tracked file contents with xargs and grep::
2860 2880
2861 2881 hg files -0 | xargs -0 grep foo
2862 2882
2863 2883 See :hg:`help patterns` and :hg:`help filesets` for more information
2864 2884 on specifying file patterns.
2865 2885
2866 2886 Returns 0 if a match is found, 1 otherwise.
2867 2887
2868 2888 """
2869 2889
2870 2890 opts = pycompat.byteskwargs(opts)
2871 2891 rev = opts.get(b'rev')
2872 2892 if rev:
2873 2893 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2874 2894 ctx = logcmdutil.revsingle(repo, rev, None)
2875 2895
2876 2896 end = b'\n'
2877 2897 if opts.get(b'print0'):
2878 2898 end = b'\0'
2879 2899 fmt = b'%s' + end
2880 2900
2881 2901 m = scmutil.match(ctx, pats, opts)
2882 2902 ui.pager(b'files')
2883 2903 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2884 2904 with ui.formatter(b'files', opts) as fm:
2885 2905 return cmdutil.files(
2886 2906 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2887 2907 )
2888 2908
2889 2909
2890 2910 @command(
2891 2911 b'forget',
2892 2912 [
2893 2913 (b'i', b'interactive', None, _(b'use interactive mode')),
2894 2914 ]
2895 2915 + walkopts
2896 2916 + dryrunopts,
2897 2917 _(b'[OPTION]... FILE...'),
2898 2918 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2899 2919 helpbasic=True,
2900 2920 inferrepo=True,
2901 2921 )
2902 2922 def forget(ui, repo, *pats, **opts):
2903 2923 """forget the specified files on the next commit
2904 2924
2905 2925 Mark the specified files so they will no longer be tracked
2906 2926 after the next commit.
2907 2927
2908 2928 This only removes files from the current branch, not from the
2909 2929 entire project history, and it does not delete them from the
2910 2930 working directory.
2911 2931
2912 2932 To delete the file from the working directory, see :hg:`remove`.
2913 2933
2914 2934 To undo a forget before the next commit, see :hg:`add`.
2915 2935
2916 2936 .. container:: verbose
2917 2937
2918 2938 Examples:
2919 2939
2920 2940 - forget newly-added binary files::
2921 2941
2922 2942 hg forget "set:added() and binary()"
2923 2943
2924 2944 - forget files that would be excluded by .hgignore::
2925 2945
2926 2946 hg forget "set:hgignore()"
2927 2947
2928 2948 Returns 0 on success.
2929 2949 """
2930 2950
2931 2951 opts = pycompat.byteskwargs(opts)
2932 2952 if not pats:
2933 2953 raise error.InputError(_(b'no files specified'))
2934 2954
2935 2955 m = scmutil.match(repo[None], pats, opts)
2936 2956 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2937 2957 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2938 2958 rejected = cmdutil.forget(
2939 2959 ui,
2940 2960 repo,
2941 2961 m,
2942 2962 prefix=b"",
2943 2963 uipathfn=uipathfn,
2944 2964 explicitonly=False,
2945 2965 dryrun=dryrun,
2946 2966 interactive=interactive,
2947 2967 )[0]
2948 2968 return rejected and 1 or 0
2949 2969
2950 2970
2951 2971 @command(
2952 2972 b'graft',
2953 2973 [
2954 2974 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2955 2975 (
2956 2976 b'',
2957 2977 b'base',
2958 2978 b'',
2959 2979 _(b'base revision when doing the graft merge (ADVANCED)'),
2960 2980 _(b'REV'),
2961 2981 ),
2962 2982 (b'c', b'continue', False, _(b'resume interrupted graft')),
2963 2983 (b'', b'stop', False, _(b'stop interrupted graft')),
2964 2984 (b'', b'abort', False, _(b'abort interrupted graft')),
2965 2985 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2966 2986 (b'', b'log', None, _(b'append graft info to log message')),
2967 2987 (
2968 2988 b'',
2969 2989 b'no-commit',
2970 2990 None,
2971 2991 _(b"don't commit, just apply the changes in working directory"),
2972 2992 ),
2973 2993 (b'f', b'force', False, _(b'force graft')),
2974 2994 (
2975 2995 b'D',
2976 2996 b'currentdate',
2977 2997 False,
2978 2998 _(b'record the current date as commit date'),
2979 2999 ),
2980 3000 (
2981 3001 b'U',
2982 3002 b'currentuser',
2983 3003 False,
2984 3004 _(b'record the current user as committer'),
2985 3005 ),
2986 3006 ]
2987 3007 + commitopts2
2988 3008 + mergetoolopts
2989 3009 + dryrunopts,
2990 3010 _(b'[OPTION]... [-r REV]... REV...'),
2991 3011 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2992 3012 )
2993 3013 def graft(ui, repo, *revs, **opts):
2994 3014 """copy changes from other branches onto the current branch
2995 3015
2996 3016 This command uses Mercurial's merge logic to copy individual
2997 3017 changes from other branches without merging branches in the
2998 3018 history graph. This is sometimes known as 'backporting' or
2999 3019 'cherry-picking'. By default, graft will copy user, date, and
3000 3020 description from the source changesets.
3001 3021
3002 3022 Changesets that are ancestors of the current revision, that have
3003 3023 already been grafted, or that are merges will be skipped.
3004 3024
3005 3025 If --log is specified, log messages will have a comment appended
3006 3026 of the form::
3007 3027
3008 3028 (grafted from CHANGESETHASH)
3009 3029
3010 3030 If --force is specified, revisions will be grafted even if they
3011 3031 are already ancestors of, or have been grafted to, the destination.
3012 3032 This is useful when the revisions have since been backed out.
3013 3033
3014 3034 If a graft merge results in conflicts, the graft process is
3015 3035 interrupted so that the current merge can be manually resolved.
3016 3036 Once all conflicts are addressed, the graft process can be
3017 3037 continued with the -c/--continue option.
3018 3038
3019 3039 The -c/--continue option reapplies all the earlier options.
3020 3040
3021 3041 .. container:: verbose
3022 3042
3023 3043 The --base option exposes more of how graft internally uses merge with a
3024 3044 custom base revision. --base can be used to specify another ancestor than
3025 3045 the first and only parent.
3026 3046
3027 3047 The command::
3028 3048
3029 3049 hg graft -r 345 --base 234
3030 3050
3031 3051 is thus pretty much the same as::
3032 3052
3033 3053 hg diff --from 234 --to 345 | hg import
3034 3054
3035 3055 but using merge to resolve conflicts and track moved files.
3036 3056
3037 3057 The result of a merge can thus be backported as a single commit by
3038 3058 specifying one of the merge parents as base, and thus effectively
3039 3059 grafting the changes from the other side.
3040 3060
3041 3061 It is also possible to collapse multiple changesets and clean up history
3042 3062 by specifying another ancestor as base, much like rebase --collapse
3043 3063 --keep.
3044 3064
3045 3065 The commit message can be tweaked after the fact using commit --amend .
3046 3066
3047 3067 For using non-ancestors as the base to backout changes, see the backout
3048 3068 command and the hidden --parent option.
3049 3069
3050 3070 .. container:: verbose
3051 3071
3052 3072 Examples:
3053 3073
3054 3074 - copy a single change to the stable branch and edit its description::
3055 3075
3056 3076 hg update stable
3057 3077 hg graft --edit 9393
3058 3078
3059 3079 - graft a range of changesets with one exception, updating dates::
3060 3080
3061 3081 hg graft -D "2085::2093 and not 2091"
3062 3082
3063 3083 - continue a graft after resolving conflicts::
3064 3084
3065 3085 hg graft -c
3066 3086
3067 3087 - show the source of a grafted changeset::
3068 3088
3069 3089 hg log --debug -r .
3070 3090
3071 3091 - show revisions sorted by date::
3072 3092
3073 3093 hg log -r "sort(all(), date)"
3074 3094
3075 3095 - backport the result of a merge as a single commit::
3076 3096
3077 3097 hg graft -r 123 --base 123^
3078 3098
3079 3099 - land a feature branch as one changeset::
3080 3100
3081 3101 hg up -cr default
3082 3102 hg graft -r featureX --base "ancestor('featureX', 'default')"
3083 3103
3084 3104 See :hg:`help revisions` for more about specifying revisions.
3085 3105
3086 3106 Returns 0 on successful completion, 1 if there are unresolved files.
3087 3107 """
3088 3108 with repo.wlock():
3089 3109 return _dograft(ui, repo, *revs, **opts)
3090 3110
3091 3111
3092 3112 def _dograft(ui, repo, *revs, **opts):
3093 3113 if revs and opts.get('rev'):
3094 3114 ui.warn(
3095 3115 _(
3096 3116 b'warning: inconsistent use of --rev might give unexpected '
3097 3117 b'revision ordering!\n'
3098 3118 )
3099 3119 )
3100 3120
3101 3121 revs = list(revs)
3102 3122 revs.extend(opts.get('rev'))
3103 3123 # a dict of data to be stored in state file
3104 3124 statedata = {}
3105 3125 # list of new nodes created by ongoing graft
3106 3126 statedata[b'newnodes'] = []
3107 3127
3108 3128 cmdutil.resolve_commit_options(ui, opts)
3109 3129
3110 3130 editor = cmdutil.getcommiteditor(editform=b'graft', **opts)
3111 3131
3112 3132 cmdutil.check_at_most_one_arg(opts, 'abort', 'stop', 'continue')
3113 3133
3114 3134 cont = False
3115 3135 if opts.get('no_commit'):
3116 3136 cmdutil.check_incompatible_arguments(
3117 3137 opts,
3118 3138 'no_commit',
3119 3139 ['edit', 'currentuser', 'currentdate', 'log'],
3120 3140 )
3121 3141
3122 3142 graftstate = statemod.cmdstate(repo, b'graftstate')
3123 3143
3124 3144 if opts.get('stop'):
3125 3145 cmdutil.check_incompatible_arguments(
3126 3146 opts,
3127 3147 'stop',
3128 3148 [
3129 3149 'edit',
3130 3150 'log',
3131 3151 'user',
3132 3152 'date',
3133 3153 'currentdate',
3134 3154 'currentuser',
3135 3155 'rev',
3136 3156 ],
3137 3157 )
3138 3158 return _stopgraft(ui, repo, graftstate)
3139 3159 elif opts.get('abort'):
3140 3160 cmdutil.check_incompatible_arguments(
3141 3161 opts,
3142 3162 'abort',
3143 3163 [
3144 3164 'edit',
3145 3165 'log',
3146 3166 'user',
3147 3167 'date',
3148 3168 'currentdate',
3149 3169 'currentuser',
3150 3170 'rev',
3151 3171 ],
3152 3172 )
3153 3173 return cmdutil.abortgraft(ui, repo, graftstate)
3154 3174 elif opts.get('continue'):
3155 3175 cont = True
3156 3176 if revs:
3157 3177 raise error.InputError(_(b"can't specify --continue and revisions"))
3158 3178 # read in unfinished revisions
3159 3179 if graftstate.exists():
3160 3180 statedata = cmdutil.readgraftstate(repo, graftstate)
3161 3181 if statedata.get(b'date'):
3162 3182 opts['date'] = statedata[b'date']
3163 3183 if statedata.get(b'user'):
3164 3184 opts['user'] = statedata[b'user']
3165 3185 if statedata.get(b'log'):
3166 3186 opts['log'] = True
3167 3187 if statedata.get(b'no_commit'):
3168 3188 opts['no_commit'] = statedata.get(b'no_commit')
3169 3189 if statedata.get(b'base'):
3170 3190 opts['base'] = statedata.get(b'base')
3171 3191 nodes = statedata[b'nodes']
3172 3192 revs = [repo[node].rev() for node in nodes]
3173 3193 else:
3174 3194 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3175 3195 else:
3176 3196 if not revs:
3177 3197 raise error.InputError(_(b'no revisions specified'))
3178 3198 cmdutil.checkunfinished(repo)
3179 3199 cmdutil.bailifchanged(repo)
3180 3200 revs = logcmdutil.revrange(repo, revs)
3181 3201
3182 3202 skipped = set()
3183 3203 basectx = None
3184 3204 if opts.get('base'):
3185 3205 basectx = logcmdutil.revsingle(repo, opts['base'], None)
3186 3206 if basectx is None:
3187 3207 # check for merges
3188 3208 for rev in repo.revs(b'%ld and merge()', revs):
3189 3209 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3190 3210 skipped.add(rev)
3191 3211 revs = [r for r in revs if r not in skipped]
3192 3212 if not revs:
3193 3213 return -1
3194 3214 if basectx is not None and len(revs) != 1:
3195 3215 raise error.InputError(_(b'only one revision allowed with --base '))
3196 3216
3197 3217 # Don't check in the --continue case, in effect retaining --force across
3198 3218 # --continues. That's because without --force, any revisions we decided to
3199 3219 # skip would have been filtered out here, so they wouldn't have made their
3200 3220 # way to the graftstate. With --force, any revisions we would have otherwise
3201 3221 # skipped would not have been filtered out, and if they hadn't been applied
3202 3222 # already, they'd have been in the graftstate.
3203 3223 if not (cont or opts.get('force')) and basectx is None:
3204 3224 # check for ancestors of dest branch
3205 3225 ancestors = repo.revs(b'%ld & (::.)', revs)
3206 3226 for rev in ancestors:
3207 3227 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3208 3228
3209 3229 revs = [r for r in revs if r not in ancestors]
3210 3230
3211 3231 if not revs:
3212 3232 return -1
3213 3233
3214 3234 # analyze revs for earlier grafts
3215 3235 ids = {}
3216 3236 for ctx in repo.set(b"%ld", revs):
3217 3237 ids[ctx.hex()] = ctx.rev()
3218 3238 n = ctx.extra().get(b'source')
3219 3239 if n:
3220 3240 ids[n] = ctx.rev()
3221 3241
3222 3242 # check ancestors for earlier grafts
3223 3243 ui.debug(b'scanning for duplicate grafts\n')
3224 3244
3225 3245 # The only changesets we can be sure doesn't contain grafts of any
3226 3246 # revs, are the ones that are common ancestors of *all* revs:
3227 3247 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3228 3248 ctx = repo[rev]
3229 3249 n = ctx.extra().get(b'source')
3230 3250 if n in ids:
3231 3251 try:
3232 3252 r = repo[n].rev()
3233 3253 except error.RepoLookupError:
3234 3254 r = None
3235 3255 if r in revs:
3236 3256 ui.warn(
3237 3257 _(
3238 3258 b'skipping revision %d:%s '
3239 3259 b'(already grafted to %d:%s)\n'
3240 3260 )
3241 3261 % (r, repo[r], rev, ctx)
3242 3262 )
3243 3263 revs.remove(r)
3244 3264 elif ids[n] in revs:
3245 3265 if r is None:
3246 3266 ui.warn(
3247 3267 _(
3248 3268 b'skipping already grafted revision %d:%s '
3249 3269 b'(%d:%s also has unknown origin %s)\n'
3250 3270 )
3251 3271 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3252 3272 )
3253 3273 else:
3254 3274 ui.warn(
3255 3275 _(
3256 3276 b'skipping already grafted revision %d:%s '
3257 3277 b'(%d:%s also has origin %d:%s)\n'
3258 3278 )
3259 3279 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3260 3280 )
3261 3281 revs.remove(ids[n])
3262 3282 elif ctx.hex() in ids:
3263 3283 r = ids[ctx.hex()]
3264 3284 if r in revs:
3265 3285 ui.warn(
3266 3286 _(
3267 3287 b'skipping already grafted revision %d:%s '
3268 3288 b'(was grafted from %d:%s)\n'
3269 3289 )
3270 3290 % (r, repo[r], rev, ctx)
3271 3291 )
3272 3292 revs.remove(r)
3273 3293 if not revs:
3274 3294 return -1
3275 3295
3276 3296 if opts.get('no_commit'):
3277 3297 statedata[b'no_commit'] = True
3278 3298 if opts.get('base'):
3279 3299 statedata[b'base'] = opts['base']
3280 3300 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3281 3301 desc = b'%d:%s "%s"' % (
3282 3302 ctx.rev(),
3283 3303 ctx,
3284 3304 ctx.description().split(b'\n', 1)[0],
3285 3305 )
3286 3306 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3287 3307 if names:
3288 3308 desc += b' (%s)' % b' '.join(names)
3289 3309 ui.status(_(b'grafting %s\n') % desc)
3290 3310 if opts.get('dry_run'):
3291 3311 continue
3292 3312
3293 3313 source = ctx.extra().get(b'source')
3294 3314 extra = {}
3295 3315 if source:
3296 3316 extra[b'source'] = source
3297 3317 extra[b'intermediate-source'] = ctx.hex()
3298 3318 else:
3299 3319 extra[b'source'] = ctx.hex()
3300 3320 user = ctx.user()
3301 3321 if opts.get('user'):
3302 3322 user = opts['user']
3303 3323 statedata[b'user'] = user
3304 3324 date = ctx.date()
3305 3325 if opts.get('date'):
3306 3326 date = opts['date']
3307 3327 statedata[b'date'] = date
3308 3328 message = ctx.description()
3309 3329 if opts.get('log'):
3310 3330 message += b'\n(grafted from %s)' % ctx.hex()
3311 3331 statedata[b'log'] = True
3312 3332
3313 3333 # we don't merge the first commit when continuing
3314 3334 if not cont:
3315 3335 # perform the graft merge with p1(rev) as 'ancestor'
3316 3336 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
3317 3337 base = ctx.p1() if basectx is None else basectx
3318 3338 with ui.configoverride(overrides, b'graft'):
3319 3339 stats = mergemod.graft(
3320 3340 repo, ctx, base, [b'local', b'graft', b'parent of graft']
3321 3341 )
3322 3342 # report any conflicts
3323 3343 if stats.unresolvedcount > 0:
3324 3344 # write out state for --continue
3325 3345 nodes = [repo[rev].hex() for rev in revs[pos:]]
3326 3346 statedata[b'nodes'] = nodes
3327 3347 stateversion = 1
3328 3348 graftstate.save(stateversion, statedata)
3329 3349 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3330 3350 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3331 3351 return 1
3332 3352 else:
3333 3353 cont = False
3334 3354
3335 3355 # commit if --no-commit is false
3336 3356 if not opts.get('no_commit'):
3337 3357 node = repo.commit(
3338 3358 text=message, user=user, date=date, extra=extra, editor=editor
3339 3359 )
3340 3360 if node is None:
3341 3361 ui.warn(
3342 3362 _(b'note: graft of %d:%s created no changes to commit\n')
3343 3363 % (ctx.rev(), ctx)
3344 3364 )
3345 3365 # checking that newnodes exist because old state files won't have it
3346 3366 elif statedata.get(b'newnodes') is not None:
3347 3367 nn = statedata[b'newnodes']
3348 3368 assert isinstance(nn, list) # list of bytes
3349 3369 nn.append(node)
3350 3370
3351 3371 # remove state when we complete successfully
3352 3372 if not opts.get('dry_run'):
3353 3373 graftstate.delete()
3354 3374
3355 3375 return 0
3356 3376
3357 3377
3358 3378 def _stopgraft(ui, repo, graftstate):
3359 3379 """stop the interrupted graft"""
3360 3380 if not graftstate.exists():
3361 3381 raise error.StateError(_(b"no interrupted graft found"))
3362 3382 pctx = repo[b'.']
3363 3383 mergemod.clean_update(pctx)
3364 3384 graftstate.delete()
3365 3385 ui.status(_(b"stopped the interrupted graft\n"))
3366 3386 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3367 3387 return 0
3368 3388
3369 3389
3370 3390 statemod.addunfinished(
3371 3391 b'graft',
3372 3392 fname=b'graftstate',
3373 3393 clearable=True,
3374 3394 stopflag=True,
3375 3395 continueflag=True,
3376 3396 abortfunc=cmdutil.hgabortgraft,
3377 3397 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3378 3398 )
3379 3399
3380 3400
3381 3401 @command(
3382 3402 b'grep',
3383 3403 [
3384 3404 (b'0', b'print0', None, _(b'end fields with NUL')),
3385 3405 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3386 3406 (
3387 3407 b'',
3388 3408 b'diff',
3389 3409 None,
3390 3410 _(
3391 3411 b'search revision differences for when the pattern was added '
3392 3412 b'or removed'
3393 3413 ),
3394 3414 ),
3395 3415 (b'a', b'text', None, _(b'treat all files as text')),
3396 3416 (
3397 3417 b'f',
3398 3418 b'follow',
3399 3419 None,
3400 3420 _(
3401 3421 b'follow changeset history,'
3402 3422 b' or file history across copies and renames'
3403 3423 ),
3404 3424 ),
3405 3425 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3406 3426 (
3407 3427 b'l',
3408 3428 b'files-with-matches',
3409 3429 None,
3410 3430 _(b'print only filenames and revisions that match'),
3411 3431 ),
3412 3432 (b'n', b'line-number', None, _(b'print matching line numbers')),
3413 3433 (
3414 3434 b'r',
3415 3435 b'rev',
3416 3436 [],
3417 3437 _(b'search files changed within revision range'),
3418 3438 _(b'REV'),
3419 3439 ),
3420 3440 (
3421 3441 b'',
3422 3442 b'all-files',
3423 3443 None,
3424 3444 _(
3425 3445 b'include all files in the changeset while grepping (DEPRECATED)'
3426 3446 ),
3427 3447 ),
3428 3448 (b'u', b'user', None, _(b'list the author (long with -v)')),
3429 3449 (b'd', b'date', None, _(b'list the date (short with -q)')),
3430 3450 ]
3431 3451 + formatteropts
3432 3452 + walkopts,
3433 3453 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3434 3454 helpcategory=command.CATEGORY_FILE_CONTENTS,
3435 3455 inferrepo=True,
3436 3456 intents={INTENT_READONLY},
3437 3457 )
3438 3458 def grep(ui, repo, pattern, *pats, **opts):
3439 3459 """search for a pattern in specified files
3440 3460
3441 3461 Search the working directory or revision history for a regular
3442 3462 expression in the specified files for the entire repository.
3443 3463
3444 3464 By default, grep searches the repository files in the working
3445 3465 directory and prints the files where it finds a match. To specify
3446 3466 historical revisions instead of the working directory, use the
3447 3467 --rev flag.
3448 3468
3449 3469 To search instead historical revision differences that contains a
3450 3470 change in match status ("-" for a match that becomes a non-match,
3451 3471 or "+" for a non-match that becomes a match), use the --diff flag.
3452 3472
3453 3473 PATTERN can be any Python (roughly Perl-compatible) regular
3454 3474 expression.
3455 3475
3456 3476 If no FILEs are specified and the --rev flag isn't supplied, all
3457 3477 files in the working directory are searched. When using the --rev
3458 3478 flag and specifying FILEs, use the --follow argument to also
3459 3479 follow the specified FILEs across renames and copies.
3460 3480
3461 3481 .. container:: verbose
3462 3482
3463 3483 Template:
3464 3484
3465 3485 The following keywords are supported in addition to the common template
3466 3486 keywords and functions. See also :hg:`help templates`.
3467 3487
3468 3488 :change: String. Character denoting insertion ``+`` or removal ``-``.
3469 3489 Available if ``--diff`` is specified.
3470 3490 :lineno: Integer. Line number of the match.
3471 3491 :path: String. Repository-absolute path of the file.
3472 3492 :texts: List of text chunks.
3473 3493
3474 3494 And each entry of ``{texts}`` provides the following sub-keywords.
3475 3495
3476 3496 :matched: Boolean. True if the chunk matches the specified pattern.
3477 3497 :text: String. Chunk content.
3478 3498
3479 3499 See :hg:`help templates.operators` for the list expansion syntax.
3480 3500
3481 3501 Returns 0 if a match is found, 1 otherwise.
3482 3502
3483 3503 """
3484 3504 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3485 3505 opts = pycompat.byteskwargs(opts)
3486 3506 diff = opts.get(b'all') or opts.get(b'diff')
3487 3507 follow = opts.get(b'follow')
3488 3508 if opts.get(b'all_files') is None and not diff:
3489 3509 opts[b'all_files'] = True
3490 3510 plaingrep = (
3491 3511 opts.get(b'all_files')
3492 3512 and not opts.get(b'rev')
3493 3513 and not opts.get(b'follow')
3494 3514 )
3495 3515 all_files = opts.get(b'all_files')
3496 3516 if plaingrep:
3497 3517 opts[b'rev'] = [b'wdir()']
3498 3518
3499 3519 reflags = re.M
3500 3520 if opts.get(b'ignore_case'):
3501 3521 reflags |= re.I
3502 3522 try:
3503 3523 regexp = util.re.compile(pattern, reflags)
3504 3524 except re.error as inst:
3505 3525 ui.warn(
3506 3526 _(b"grep: invalid match pattern: %s\n")
3507 3527 % stringutil.forcebytestr(inst)
3508 3528 )
3509 3529 return 1
3510 3530 sep, eol = b':', b'\n'
3511 3531 if opts.get(b'print0'):
3512 3532 sep = eol = b'\0'
3513 3533
3514 3534 searcher = grepmod.grepsearcher(
3515 3535 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3516 3536 )
3517 3537
3518 3538 getfile = searcher._getfile
3519 3539
3520 3540 uipathfn = scmutil.getuipathfn(repo)
3521 3541
3522 3542 def display(fm, fn, ctx, pstates, states):
3523 3543 rev = scmutil.intrev(ctx)
3524 3544 if fm.isplain():
3525 3545 formatuser = ui.shortuser
3526 3546 else:
3527 3547 formatuser = pycompat.bytestr
3528 3548 if ui.quiet:
3529 3549 datefmt = b'%Y-%m-%d'
3530 3550 else:
3531 3551 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3532 3552 found = False
3533 3553
3534 3554 @util.cachefunc
3535 3555 def binary():
3536 3556 flog = getfile(fn)
3537 3557 try:
3538 3558 return stringutil.binary(flog.read(ctx.filenode(fn)))
3539 3559 except error.WdirUnsupported:
3540 3560 return ctx[fn].isbinary()
3541 3561
3542 3562 fieldnamemap = {b'linenumber': b'lineno'}
3543 3563 if diff:
3544 3564 iter = grepmod.difflinestates(pstates, states)
3545 3565 else:
3546 3566 iter = [(b'', l) for l in states]
3547 3567 for change, l in iter:
3548 3568 fm.startitem()
3549 3569 fm.context(ctx=ctx)
3550 3570 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3551 3571 fm.plain(uipathfn(fn), label=b'grep.filename')
3552 3572
3553 3573 cols = [
3554 3574 (b'rev', b'%d', rev, not plaingrep, b''),
3555 3575 (
3556 3576 b'linenumber',
3557 3577 b'%d',
3558 3578 l.linenum,
3559 3579 opts.get(b'line_number'),
3560 3580 b'',
3561 3581 ),
3562 3582 ]
3563 3583 if diff:
3564 3584 cols.append(
3565 3585 (
3566 3586 b'change',
3567 3587 b'%s',
3568 3588 change,
3569 3589 True,
3570 3590 b'grep.inserted '
3571 3591 if change == b'+'
3572 3592 else b'grep.deleted ',
3573 3593 )
3574 3594 )
3575 3595 cols.extend(
3576 3596 [
3577 3597 (
3578 3598 b'user',
3579 3599 b'%s',
3580 3600 formatuser(ctx.user()),
3581 3601 opts.get(b'user'),
3582 3602 b'',
3583 3603 ),
3584 3604 (
3585 3605 b'date',
3586 3606 b'%s',
3587 3607 fm.formatdate(ctx.date(), datefmt),
3588 3608 opts.get(b'date'),
3589 3609 b'',
3590 3610 ),
3591 3611 ]
3592 3612 )
3593 3613 for name, fmt, data, cond, extra_label in cols:
3594 3614 if cond:
3595 3615 fm.plain(sep, label=b'grep.sep')
3596 3616 field = fieldnamemap.get(name, name)
3597 3617 label = extra_label + (b'grep.%s' % name)
3598 3618 fm.condwrite(cond, field, fmt, data, label=label)
3599 3619 if not opts.get(b'files_with_matches'):
3600 3620 fm.plain(sep, label=b'grep.sep')
3601 3621 if not opts.get(b'text') and binary():
3602 3622 fm.plain(_(b" Binary file matches"))
3603 3623 else:
3604 3624 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3605 3625 fm.plain(eol)
3606 3626 found = True
3607 3627 if opts.get(b'files_with_matches'):
3608 3628 break
3609 3629 return found
3610 3630
3611 3631 def displaymatches(fm, l):
3612 3632 p = 0
3613 3633 for s, e in l.findpos(regexp):
3614 3634 if p < s:
3615 3635 fm.startitem()
3616 3636 fm.write(b'text', b'%s', l.line[p:s])
3617 3637 fm.data(matched=False)
3618 3638 fm.startitem()
3619 3639 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3620 3640 fm.data(matched=True)
3621 3641 p = e
3622 3642 if p < len(l.line):
3623 3643 fm.startitem()
3624 3644 fm.write(b'text', b'%s', l.line[p:])
3625 3645 fm.data(matched=False)
3626 3646 fm.end()
3627 3647
3628 3648 found = False
3629 3649
3630 3650 wopts = logcmdutil.walkopts(
3631 3651 pats=pats,
3632 3652 opts=opts,
3633 3653 revspec=opts[b'rev'],
3634 3654 include_pats=opts[b'include'],
3635 3655 exclude_pats=opts[b'exclude'],
3636 3656 follow=follow,
3637 3657 force_changelog_traversal=all_files,
3638 3658 filter_revisions_by_pats=not all_files,
3639 3659 )
3640 3660 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3641 3661
3642 3662 ui.pager(b'grep')
3643 3663 fm = ui.formatter(b'grep', opts)
3644 3664 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3645 3665 r = display(fm, fn, ctx, pstates, states)
3646 3666 found = found or r
3647 3667 if r and not diff and not all_files:
3648 3668 searcher.skipfile(fn, ctx.rev())
3649 3669 fm.end()
3650 3670
3651 3671 return not found
3652 3672
3653 3673
3654 3674 @command(
3655 3675 b'heads',
3656 3676 [
3657 3677 (
3658 3678 b'r',
3659 3679 b'rev',
3660 3680 b'',
3661 3681 _(b'show only heads which are descendants of STARTREV'),
3662 3682 _(b'STARTREV'),
3663 3683 ),
3664 3684 (b't', b'topo', False, _(b'show topological heads only')),
3665 3685 (
3666 3686 b'a',
3667 3687 b'active',
3668 3688 False,
3669 3689 _(b'show active branchheads only (DEPRECATED)'),
3670 3690 ),
3671 3691 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3672 3692 ]
3673 3693 + templateopts,
3674 3694 _(b'[-ct] [-r STARTREV] [REV]...'),
3675 3695 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3676 3696 intents={INTENT_READONLY},
3677 3697 )
3678 3698 def heads(ui, repo, *branchrevs, **opts):
3679 3699 """show branch heads
3680 3700
3681 3701 With no arguments, show all open branch heads in the repository.
3682 3702 Branch heads are changesets that have no descendants on the
3683 3703 same branch. They are where development generally takes place and
3684 3704 are the usual targets for update and merge operations.
3685 3705
3686 3706 If one or more REVs are given, only open branch heads on the
3687 3707 branches associated with the specified changesets are shown. This
3688 3708 means that you can use :hg:`heads .` to see the heads on the
3689 3709 currently checked-out branch.
3690 3710
3691 3711 If -c/--closed is specified, also show branch heads marked closed
3692 3712 (see :hg:`commit --close-branch`).
3693 3713
3694 3714 If STARTREV is specified, only those heads that are descendants of
3695 3715 STARTREV will be displayed.
3696 3716
3697 3717 If -t/--topo is specified, named branch mechanics will be ignored and only
3698 3718 topological heads (changesets with no children) will be shown.
3699 3719
3700 3720 Returns 0 if matching heads are found, 1 if not.
3701 3721 """
3702 3722
3703 3723 opts = pycompat.byteskwargs(opts)
3704 3724 start = None
3705 3725 rev = opts.get(b'rev')
3706 3726 if rev:
3707 3727 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3708 3728 start = logcmdutil.revsingle(repo, rev, None).node()
3709 3729
3710 3730 if opts.get(b'topo'):
3711 3731 heads = [repo[h] for h in repo.heads(start)]
3712 3732 else:
3713 3733 heads = []
3714 3734 for branch in repo.branchmap():
3715 3735 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3716 3736 heads = [repo[h] for h in heads]
3717 3737
3718 3738 if branchrevs:
3719 3739 branches = {
3720 3740 repo[r].branch() for r in logcmdutil.revrange(repo, branchrevs)
3721 3741 }
3722 3742 heads = [h for h in heads if h.branch() in branches]
3723 3743
3724 3744 if opts.get(b'active') and branchrevs:
3725 3745 dagheads = repo.heads(start)
3726 3746 heads = [h for h in heads if h.node() in dagheads]
3727 3747
3728 3748 if branchrevs:
3729 3749 haveheads = {h.branch() for h in heads}
3730 3750 if branches - haveheads:
3731 3751 headless = b', '.join(b for b in branches - haveheads)
3732 3752 msg = _(b'no open branch heads found on branches %s')
3733 3753 if opts.get(b'rev'):
3734 3754 msg += _(b' (started at %s)') % opts[b'rev']
3735 3755 ui.warn((msg + b'\n') % headless)
3736 3756
3737 3757 if not heads:
3738 3758 return 1
3739 3759
3740 3760 ui.pager(b'heads')
3741 3761 heads = sorted(heads, key=lambda x: -(x.rev()))
3742 3762 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3743 3763 for ctx in heads:
3744 3764 displayer.show(ctx)
3745 3765 displayer.close()
3746 3766
3747 3767
3748 3768 @command(
3749 3769 b'help',
3750 3770 [
3751 3771 (b'e', b'extension', None, _(b'show only help for extensions')),
3752 3772 (b'c', b'command', None, _(b'show only help for commands')),
3753 3773 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3754 3774 (
3755 3775 b's',
3756 3776 b'system',
3757 3777 [],
3758 3778 _(b'show help for specific platform(s)'),
3759 3779 _(b'PLATFORM'),
3760 3780 ),
3761 3781 ],
3762 3782 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3763 3783 helpcategory=command.CATEGORY_HELP,
3764 3784 norepo=True,
3765 3785 intents={INTENT_READONLY},
3766 3786 )
3767 3787 def help_(ui, name=None, **opts):
3768 3788 """show help for a given topic or a help overview
3769 3789
3770 3790 With no arguments, print a list of commands with short help messages.
3771 3791
3772 3792 Given a topic, extension, or command name, print help for that
3773 3793 topic.
3774 3794
3775 3795 Returns 0 if successful.
3776 3796 """
3777 3797
3778 3798 keep = opts.get('system') or []
3779 3799 if len(keep) == 0:
3780 3800 if pycompat.sysplatform.startswith(b'win'):
3781 3801 keep.append(b'windows')
3782 3802 elif pycompat.sysplatform == b'OpenVMS':
3783 3803 keep.append(b'vms')
3784 3804 elif pycompat.sysplatform == b'plan9':
3785 3805 keep.append(b'plan9')
3786 3806 else:
3787 3807 keep.append(b'unix')
3788 3808 keep.append(pycompat.sysplatform.lower())
3789 3809 if ui.verbose:
3790 3810 keep.append(b'verbose')
3791 3811
3792 3812 commands = sys.modules[__name__]
3793 3813 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3794 3814 ui.pager(b'help')
3795 3815 ui.write(formatted)
3796 3816
3797 3817
3798 3818 @command(
3799 3819 b'identify|id',
3800 3820 [
3801 3821 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3802 3822 (b'n', b'num', None, _(b'show local revision number')),
3803 3823 (b'i', b'id', None, _(b'show global revision id')),
3804 3824 (b'b', b'branch', None, _(b'show branch')),
3805 3825 (b't', b'tags', None, _(b'show tags')),
3806 3826 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3807 3827 ]
3808 3828 + remoteopts
3809 3829 + formatteropts,
3810 3830 _(b'[-nibtB] [-r REV] [SOURCE]'),
3811 3831 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3812 3832 optionalrepo=True,
3813 3833 intents={INTENT_READONLY},
3814 3834 )
3815 3835 def identify(
3816 3836 ui,
3817 3837 repo,
3818 3838 source=None,
3819 3839 rev=None,
3820 3840 num=None,
3821 3841 id=None,
3822 3842 branch=None,
3823 3843 tags=None,
3824 3844 bookmarks=None,
3825 3845 **opts
3826 3846 ):
3827 3847 """identify the working directory or specified revision
3828 3848
3829 3849 Print a summary identifying the repository state at REV using one or
3830 3850 two parent hash identifiers, followed by a "+" if the working
3831 3851 directory has uncommitted changes, the branch name (if not default),
3832 3852 a list of tags, and a list of bookmarks.
3833 3853
3834 3854 When REV is not given, print a summary of the current state of the
3835 3855 repository including the working directory. Specify -r. to get information
3836 3856 of the working directory parent without scanning uncommitted changes.
3837 3857
3838 3858 Specifying a path to a repository root or Mercurial bundle will
3839 3859 cause lookup to operate on that repository/bundle.
3840 3860
3841 3861 .. container:: verbose
3842 3862
3843 3863 Template:
3844 3864
3845 3865 The following keywords are supported in addition to the common template
3846 3866 keywords and functions. See also :hg:`help templates`.
3847 3867
3848 3868 :dirty: String. Character ``+`` denoting if the working directory has
3849 3869 uncommitted changes.
3850 3870 :id: String. One or two nodes, optionally followed by ``+``.
3851 3871 :parents: List of strings. Parent nodes of the changeset.
3852 3872
3853 3873 Examples:
3854 3874
3855 3875 - generate a build identifier for the working directory::
3856 3876
3857 3877 hg id --id > build-id.dat
3858 3878
3859 3879 - find the revision corresponding to a tag::
3860 3880
3861 3881 hg id -n -r 1.3
3862 3882
3863 3883 - check the most recent revision of a remote repository::
3864 3884
3865 3885 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3866 3886
3867 3887 See :hg:`log` for generating more information about specific revisions,
3868 3888 including full hash identifiers.
3869 3889
3870 3890 Returns 0 if successful.
3871 3891 """
3872 3892
3873 3893 opts = pycompat.byteskwargs(opts)
3874 3894 if not repo and not source:
3875 3895 raise error.InputError(
3876 3896 _(b"there is no Mercurial repository here (.hg not found)")
3877 3897 )
3878 3898
3879 3899 default = not (num or id or branch or tags or bookmarks)
3880 3900 output = []
3881 3901 revs = []
3882 3902
3883 3903 peer = None
3884 3904 try:
3885 3905 if source:
3886 3906 source, branches = urlutil.get_unique_pull_path(
3887 3907 b'identify', repo, ui, source
3888 3908 )
3889 3909 # only pass ui when no repo
3890 3910 peer = hg.peer(repo or ui, opts, source)
3891 3911 repo = peer.local()
3892 3912 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3893 3913
3894 3914 fm = ui.formatter(b'identify', opts)
3895 3915 fm.startitem()
3896 3916
3897 3917 if not repo:
3898 3918 if num or branch or tags:
3899 3919 raise error.InputError(
3900 3920 _(b"can't query remote revision number, branch, or tags")
3901 3921 )
3902 3922 if not rev and revs:
3903 3923 rev = revs[0]
3904 3924 if not rev:
3905 3925 rev = b"tip"
3906 3926
3907 3927 remoterev = peer.lookup(rev)
3908 3928 hexrev = fm.hexfunc(remoterev)
3909 3929 if default or id:
3910 3930 output = [hexrev]
3911 3931 fm.data(id=hexrev)
3912 3932
3913 3933 @util.cachefunc
3914 3934 def getbms():
3915 3935 bms = []
3916 3936
3917 3937 if b'bookmarks' in peer.listkeys(b'namespaces'):
3918 3938 hexremoterev = hex(remoterev)
3919 3939 bms = [
3920 3940 bm
3921 3941 for bm, bmr in peer.listkeys(b'bookmarks').items()
3922 3942 if bmr == hexremoterev
3923 3943 ]
3924 3944
3925 3945 return sorted(bms)
3926 3946
3927 3947 if fm.isplain():
3928 3948 if bookmarks:
3929 3949 output.extend(getbms())
3930 3950 elif default and not ui.quiet:
3931 3951 # multiple bookmarks for a single parent separated by '/'
3932 3952 bm = b'/'.join(getbms())
3933 3953 if bm:
3934 3954 output.append(bm)
3935 3955 else:
3936 3956 fm.data(node=hex(remoterev))
3937 3957 if bookmarks or b'bookmarks' in fm.datahint():
3938 3958 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3939 3959 else:
3940 3960 if rev:
3941 3961 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3942 3962 ctx = logcmdutil.revsingle(repo, rev, None)
3943 3963
3944 3964 if ctx.rev() is None:
3945 3965 ctx = repo[None]
3946 3966 parents = ctx.parents()
3947 3967 taglist = []
3948 3968 for p in parents:
3949 3969 taglist.extend(p.tags())
3950 3970
3951 3971 dirty = b""
3952 3972 if ctx.dirty(missing=True, merge=False, branch=False):
3953 3973 dirty = b'+'
3954 3974 fm.data(dirty=dirty)
3955 3975
3956 3976 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3957 3977 if default or id:
3958 3978 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3959 3979 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3960 3980
3961 3981 if num:
3962 3982 numoutput = [b"%d" % p.rev() for p in parents]
3963 3983 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3964 3984
3965 3985 fm.data(
3966 3986 parents=fm.formatlist(
3967 3987 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3968 3988 )
3969 3989 )
3970 3990 else:
3971 3991 hexoutput = fm.hexfunc(ctx.node())
3972 3992 if default or id:
3973 3993 output = [hexoutput]
3974 3994 fm.data(id=hexoutput)
3975 3995
3976 3996 if num:
3977 3997 output.append(pycompat.bytestr(ctx.rev()))
3978 3998 taglist = ctx.tags()
3979 3999
3980 4000 if default and not ui.quiet:
3981 4001 b = ctx.branch()
3982 4002 if b != b'default':
3983 4003 output.append(b"(%s)" % b)
3984 4004
3985 4005 # multiple tags for a single parent separated by '/'
3986 4006 t = b'/'.join(taglist)
3987 4007 if t:
3988 4008 output.append(t)
3989 4009
3990 4010 # multiple bookmarks for a single parent separated by '/'
3991 4011 bm = b'/'.join(ctx.bookmarks())
3992 4012 if bm:
3993 4013 output.append(bm)
3994 4014 else:
3995 4015 if branch:
3996 4016 output.append(ctx.branch())
3997 4017
3998 4018 if tags:
3999 4019 output.extend(taglist)
4000 4020
4001 4021 if bookmarks:
4002 4022 output.extend(ctx.bookmarks())
4003 4023
4004 4024 fm.data(node=ctx.hex())
4005 4025 fm.data(branch=ctx.branch())
4006 4026 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4007 4027 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4008 4028 fm.context(ctx=ctx)
4009 4029
4010 4030 fm.plain(b"%s\n" % b' '.join(output))
4011 4031 fm.end()
4012 4032 finally:
4013 4033 if peer:
4014 4034 peer.close()
4015 4035
4016 4036
4017 4037 @command(
4018 4038 b'import|patch',
4019 4039 [
4020 4040 (
4021 4041 b'p',
4022 4042 b'strip',
4023 4043 1,
4024 4044 _(
4025 4045 b'directory strip option for patch. This has the same '
4026 4046 b'meaning as the corresponding patch option'
4027 4047 ),
4028 4048 _(b'NUM'),
4029 4049 ),
4030 4050 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4031 4051 (b'', b'secret', None, _(b'use the secret phase for committing')),
4032 4052 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4033 4053 (
4034 4054 b'f',
4035 4055 b'force',
4036 4056 None,
4037 4057 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4038 4058 ),
4039 4059 (
4040 4060 b'',
4041 4061 b'no-commit',
4042 4062 None,
4043 4063 _(b"don't commit, just update the working directory"),
4044 4064 ),
4045 4065 (
4046 4066 b'',
4047 4067 b'bypass',
4048 4068 None,
4049 4069 _(b"apply patch without touching the working directory"),
4050 4070 ),
4051 4071 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4052 4072 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4053 4073 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4054 4074 (
4055 4075 b'',
4056 4076 b'import-branch',
4057 4077 None,
4058 4078 _(b'use any branch information in patch (implied by --exact)'),
4059 4079 ),
4060 4080 ]
4061 4081 + commitopts
4062 4082 + commitopts2
4063 4083 + similarityopts,
4064 4084 _(b'[OPTION]... PATCH...'),
4065 4085 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4066 4086 )
4067 4087 def import_(ui, repo, patch1=None, *patches, **opts):
4068 4088 """import an ordered set of patches
4069 4089
4070 4090 Import a list of patches and commit them individually (unless
4071 4091 --no-commit is specified).
4072 4092
4073 4093 To read a patch from standard input (stdin), use "-" as the patch
4074 4094 name. If a URL is specified, the patch will be downloaded from
4075 4095 there.
4076 4096
4077 4097 Import first applies changes to the working directory (unless
4078 4098 --bypass is specified), import will abort if there are outstanding
4079 4099 changes.
4080 4100
4081 4101 Use --bypass to apply and commit patches directly to the
4082 4102 repository, without affecting the working directory. Without
4083 4103 --exact, patches will be applied on top of the working directory
4084 4104 parent revision.
4085 4105
4086 4106 You can import a patch straight from a mail message. Even patches
4087 4107 as attachments work (to use the body part, it must have type
4088 4108 text/plain or text/x-patch). From and Subject headers of email
4089 4109 message are used as default committer and commit message. All
4090 4110 text/plain body parts before first diff are added to the commit
4091 4111 message.
4092 4112
4093 4113 If the imported patch was generated by :hg:`export`, user and
4094 4114 description from patch override values from message headers and
4095 4115 body. Values given on command line with -m/--message and -u/--user
4096 4116 override these.
4097 4117
4098 4118 If --exact is specified, import will set the working directory to
4099 4119 the parent of each patch before applying it, and will abort if the
4100 4120 resulting changeset has a different ID than the one recorded in
4101 4121 the patch. This will guard against various ways that portable
4102 4122 patch formats and mail systems might fail to transfer Mercurial
4103 4123 data or metadata. See :hg:`bundle` for lossless transmission.
4104 4124
4105 4125 Use --partial to ensure a changeset will be created from the patch
4106 4126 even if some hunks fail to apply. Hunks that fail to apply will be
4107 4127 written to a <target-file>.rej file. Conflicts can then be resolved
4108 4128 by hand before :hg:`commit --amend` is run to update the created
4109 4129 changeset. This flag exists to let people import patches that
4110 4130 partially apply without losing the associated metadata (author,
4111 4131 date, description, ...).
4112 4132
4113 4133 .. note::
4114 4134
4115 4135 When no hunks apply cleanly, :hg:`import --partial` will create
4116 4136 an empty changeset, importing only the patch metadata.
4117 4137
4118 4138 With -s/--similarity, hg will attempt to discover renames and
4119 4139 copies in the patch in the same way as :hg:`addremove`.
4120 4140
4121 4141 It is possible to use external patch programs to perform the patch
4122 4142 by setting the ``ui.patch`` configuration option. For the default
4123 4143 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4124 4144 See :hg:`help config` for more information about configuration
4125 4145 files and how to use these options.
4126 4146
4127 4147 See :hg:`help dates` for a list of formats valid for -d/--date.
4128 4148
4129 4149 .. container:: verbose
4130 4150
4131 4151 Examples:
4132 4152
4133 4153 - import a traditional patch from a website and detect renames::
4134 4154
4135 4155 hg import -s 80 http://example.com/bugfix.patch
4136 4156
4137 4157 - import a changeset from an hgweb server::
4138 4158
4139 4159 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4140 4160
4141 4161 - import all the patches in an Unix-style mbox::
4142 4162
4143 4163 hg import incoming-patches.mbox
4144 4164
4145 4165 - import patches from stdin::
4146 4166
4147 4167 hg import -
4148 4168
4149 4169 - attempt to exactly restore an exported changeset (not always
4150 4170 possible)::
4151 4171
4152 4172 hg import --exact proposed-fix.patch
4153 4173
4154 4174 - use an external tool to apply a patch which is too fuzzy for
4155 4175 the default internal tool.
4156 4176
4157 4177 hg import --config ui.patch="patch --merge" fuzzy.patch
4158 4178
4159 4179 - change the default fuzzing from 2 to a less strict 7
4160 4180
4161 4181 hg import --config ui.fuzz=7 fuzz.patch
4162 4182
4163 4183 Returns 0 on success, 1 on partial success (see --partial).
4164 4184 """
4165 4185
4166 4186 cmdutil.check_incompatible_arguments(
4167 4187 opts, 'no_commit', ['bypass', 'secret']
4168 4188 )
4169 4189 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4170 4190 opts = pycompat.byteskwargs(opts)
4171 4191 if not patch1:
4172 4192 raise error.InputError(_(b'need at least one patch to import'))
4173 4193
4174 4194 patches = (patch1,) + patches
4175 4195
4176 4196 date = opts.get(b'date')
4177 4197 if date:
4178 4198 opts[b'date'] = dateutil.parsedate(date)
4179 4199
4180 4200 exact = opts.get(b'exact')
4181 4201 update = not opts.get(b'bypass')
4182 4202 try:
4183 4203 sim = float(opts.get(b'similarity') or 0)
4184 4204 except ValueError:
4185 4205 raise error.InputError(_(b'similarity must be a number'))
4186 4206 if sim < 0 or sim > 100:
4187 4207 raise error.InputError(_(b'similarity must be between 0 and 100'))
4188 4208 if sim and not update:
4189 4209 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4190 4210
4191 4211 base = opts[b"base"]
4192 4212 msgs = []
4193 4213 ret = 0
4194 4214
4195 4215 with repo.wlock():
4196 4216 if update:
4197 4217 cmdutil.checkunfinished(repo)
4198 4218 if exact or not opts.get(b'force'):
4199 4219 cmdutil.bailifchanged(repo)
4200 4220
4201 4221 if not opts.get(b'no_commit'):
4202 4222 lock = repo.lock
4203 4223 tr = lambda: repo.transaction(b'import')
4204 4224 dsguard = util.nullcontextmanager
4205 4225 else:
4206 4226 lock = util.nullcontextmanager
4207 4227 tr = util.nullcontextmanager
4208 4228 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4209 4229 with lock(), tr(), dsguard():
4210 4230 parents = repo[None].parents()
4211 4231 for patchurl in patches:
4212 4232 if patchurl == b'-':
4213 4233 ui.status(_(b'applying patch from stdin\n'))
4214 4234 patchfile = ui.fin
4215 4235 patchurl = b'stdin' # for error message
4216 4236 else:
4217 4237 patchurl = os.path.join(base, patchurl)
4218 4238 ui.status(_(b'applying %s\n') % patchurl)
4219 4239 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4220 4240
4221 4241 haspatch = False
4222 4242 for hunk in patch.split(patchfile):
4223 4243 with patch.extract(ui, hunk) as patchdata:
4224 4244 msg, node, rej = cmdutil.tryimportone(
4225 4245 ui, repo, patchdata, parents, opts, msgs, hg.clean
4226 4246 )
4227 4247 if msg:
4228 4248 haspatch = True
4229 4249 ui.note(msg + b'\n')
4230 4250 if update or exact:
4231 4251 parents = repo[None].parents()
4232 4252 else:
4233 4253 parents = [repo[node]]
4234 4254 if rej:
4235 4255 ui.write_err(_(b"patch applied partially\n"))
4236 4256 ui.write_err(
4237 4257 _(
4238 4258 b"(fix the .rej files and run "
4239 4259 b"`hg commit --amend`)\n"
4240 4260 )
4241 4261 )
4242 4262 ret = 1
4243 4263 break
4244 4264
4245 4265 if not haspatch:
4246 4266 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4247 4267
4248 4268 if msgs:
4249 4269 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4250 4270 return ret
4251 4271
4252 4272
4253 4273 @command(
4254 4274 b'incoming|in',
4255 4275 [
4256 4276 (
4257 4277 b'f',
4258 4278 b'force',
4259 4279 None,
4260 4280 _(b'run even if remote repository is unrelated'),
4261 4281 ),
4262 4282 (b'n', b'newest-first', None, _(b'show newest record first')),
4263 4283 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4264 4284 (
4265 4285 b'r',
4266 4286 b'rev',
4267 4287 [],
4268 4288 _(b'a remote changeset intended to be added'),
4269 4289 _(b'REV'),
4270 4290 ),
4271 4291 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4272 4292 (
4273 4293 b'b',
4274 4294 b'branch',
4275 4295 [],
4276 4296 _(b'a specific branch you would like to pull'),
4277 4297 _(b'BRANCH'),
4278 4298 ),
4279 4299 ]
4280 4300 + logopts
4281 4301 + remoteopts
4282 4302 + subrepoopts,
4283 4303 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4284 4304 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4285 4305 )
4286 4306 def incoming(ui, repo, source=b"default", **opts):
4287 4307 """show new changesets found in source
4288 4308
4289 4309 Show new changesets found in the specified path/URL or the default
4290 4310 pull location. These are the changesets that would have been pulled
4291 4311 by :hg:`pull` at the time you issued this command.
4292 4312
4293 4313 See pull for valid source format details.
4294 4314
4295 4315 .. container:: verbose
4296 4316
4297 4317 With -B/--bookmarks, the result of bookmark comparison between
4298 4318 local and remote repositories is displayed. With -v/--verbose,
4299 4319 status is also displayed for each bookmark like below::
4300 4320
4301 4321 BM1 01234567890a added
4302 4322 BM2 1234567890ab advanced
4303 4323 BM3 234567890abc diverged
4304 4324 BM4 34567890abcd changed
4305 4325
4306 4326 The action taken locally when pulling depends on the
4307 4327 status of each bookmark:
4308 4328
4309 4329 :``added``: pull will create it
4310 4330 :``advanced``: pull will update it
4311 4331 :``diverged``: pull will create a divergent bookmark
4312 4332 :``changed``: result depends on remote changesets
4313 4333
4314 4334 From the point of view of pulling behavior, bookmark
4315 4335 existing only in the remote repository are treated as ``added``,
4316 4336 even if it is in fact locally deleted.
4317 4337
4318 4338 .. container:: verbose
4319 4339
4320 4340 For remote repository, using --bundle avoids downloading the
4321 4341 changesets twice if the incoming is followed by a pull.
4322 4342
4323 4343 Examples:
4324 4344
4325 4345 - show incoming changes with patches and full description::
4326 4346
4327 4347 hg incoming -vp
4328 4348
4329 4349 - show incoming changes excluding merges, store a bundle::
4330 4350
4331 4351 hg in -vpM --bundle incoming.hg
4332 4352 hg pull incoming.hg
4333 4353
4334 4354 - briefly list changes inside a bundle::
4335 4355
4336 4356 hg in changes.hg -T "{desc|firstline}\\n"
4337 4357
4338 4358 Returns 0 if there are incoming changes, 1 otherwise.
4339 4359 """
4340 4360 opts = pycompat.byteskwargs(opts)
4341 4361 if opts.get(b'graph'):
4342 4362 logcmdutil.checkunsupportedgraphflags([], opts)
4343 4363
4344 4364 def display(other, chlist, displayer):
4345 4365 revdag = logcmdutil.graphrevs(other, chlist, opts)
4346 4366 logcmdutil.displaygraph(
4347 4367 ui, repo, revdag, displayer, graphmod.asciiedges
4348 4368 )
4349 4369
4350 4370 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4351 4371 return 0
4352 4372
4353 4373 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4354 4374
4355 4375 if opts.get(b'bookmarks'):
4356 4376 srcs = urlutil.get_pull_paths(repo, ui, [source])
4357 4377 for path in srcs:
4358 4378 source, branches = urlutil.parseurl(
4359 4379 path.rawloc, opts.get(b'branch')
4360 4380 )
4361 4381 other = hg.peer(repo, opts, source)
4362 4382 try:
4363 4383 if b'bookmarks' not in other.listkeys(b'namespaces'):
4364 4384 ui.warn(_(b"remote doesn't support bookmarks\n"))
4365 4385 return 0
4366 4386 ui.pager(b'incoming')
4367 4387 ui.status(
4368 4388 _(b'comparing with %s\n') % urlutil.hidepassword(source)
4369 4389 )
4370 4390 return bookmarks.incoming(
4371 4391 ui, repo, other, mode=path.bookmarks_mode
4372 4392 )
4373 4393 finally:
4374 4394 other.close()
4375 4395
4376 4396 return hg.incoming(ui, repo, source, opts)
4377 4397
4378 4398
4379 4399 @command(
4380 4400 b'init',
4381 4401 remoteopts,
4382 4402 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4383 4403 helpcategory=command.CATEGORY_REPO_CREATION,
4384 4404 helpbasic=True,
4385 4405 norepo=True,
4386 4406 )
4387 4407 def init(ui, dest=b".", **opts):
4388 4408 """create a new repository in the given directory
4389 4409
4390 4410 Initialize a new repository in the given directory. If the given
4391 4411 directory does not exist, it will be created.
4392 4412
4393 4413 If no directory is given, the current directory is used.
4394 4414
4395 4415 It is possible to specify an ``ssh://`` URL as the destination.
4396 4416 See :hg:`help urls` for more information.
4397 4417
4398 4418 Returns 0 on success.
4399 4419 """
4400 4420 opts = pycompat.byteskwargs(opts)
4401 4421 path = urlutil.get_clone_path(ui, dest)[1]
4402 4422 peer = hg.peer(ui, opts, path, create=True)
4403 4423 peer.close()
4404 4424
4405 4425
4406 4426 @command(
4407 4427 b'locate',
4408 4428 [
4409 4429 (
4410 4430 b'r',
4411 4431 b'rev',
4412 4432 b'',
4413 4433 _(b'search the repository as it is in REV'),
4414 4434 _(b'REV'),
4415 4435 ),
4416 4436 (
4417 4437 b'0',
4418 4438 b'print0',
4419 4439 None,
4420 4440 _(b'end filenames with NUL, for use with xargs'),
4421 4441 ),
4422 4442 (
4423 4443 b'f',
4424 4444 b'fullpath',
4425 4445 None,
4426 4446 _(b'print complete paths from the filesystem root'),
4427 4447 ),
4428 4448 ]
4429 4449 + walkopts,
4430 4450 _(b'[OPTION]... [PATTERN]...'),
4431 4451 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4432 4452 )
4433 4453 def locate(ui, repo, *pats, **opts):
4434 4454 """locate files matching specific patterns (DEPRECATED)
4435 4455
4436 4456 Print files under Mercurial control in the working directory whose
4437 4457 names match the given patterns.
4438 4458
4439 4459 By default, this command searches all directories in the working
4440 4460 directory. To search just the current directory and its
4441 4461 subdirectories, use "--include .".
4442 4462
4443 4463 If no patterns are given to match, this command prints the names
4444 4464 of all files under Mercurial control in the working directory.
4445 4465
4446 4466 If you want to feed the output of this command into the "xargs"
4447 4467 command, use the -0 option to both this command and "xargs". This
4448 4468 will avoid the problem of "xargs" treating single filenames that
4449 4469 contain whitespace as multiple filenames.
4450 4470
4451 4471 See :hg:`help files` for a more versatile command.
4452 4472
4453 4473 Returns 0 if a match is found, 1 otherwise.
4454 4474 """
4455 4475 opts = pycompat.byteskwargs(opts)
4456 4476 if opts.get(b'print0'):
4457 4477 end = b'\0'
4458 4478 else:
4459 4479 end = b'\n'
4460 4480 ctx = logcmdutil.revsingle(repo, opts.get(b'rev'), None)
4461 4481
4462 4482 ret = 1
4463 4483 m = scmutil.match(
4464 4484 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4465 4485 )
4466 4486
4467 4487 ui.pager(b'locate')
4468 4488 if ctx.rev() is None:
4469 4489 # When run on the working copy, "locate" includes removed files, so
4470 4490 # we get the list of files from the dirstate.
4471 4491 filesgen = sorted(repo.dirstate.matches(m))
4472 4492 else:
4473 4493 filesgen = ctx.matches(m)
4474 4494 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4475 4495 for abs in filesgen:
4476 4496 if opts.get(b'fullpath'):
4477 4497 ui.write(repo.wjoin(abs), end)
4478 4498 else:
4479 4499 ui.write(uipathfn(abs), end)
4480 4500 ret = 0
4481 4501
4482 4502 return ret
4483 4503
4484 4504
4485 4505 @command(
4486 4506 b'log|history',
4487 4507 [
4488 4508 (
4489 4509 b'f',
4490 4510 b'follow',
4491 4511 None,
4492 4512 _(
4493 4513 b'follow changeset history, or file history across copies and renames'
4494 4514 ),
4495 4515 ),
4496 4516 (
4497 4517 b'',
4498 4518 b'follow-first',
4499 4519 None,
4500 4520 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4501 4521 ),
4502 4522 (
4503 4523 b'd',
4504 4524 b'date',
4505 4525 b'',
4506 4526 _(b'show revisions matching date spec'),
4507 4527 _(b'DATE'),
4508 4528 ),
4509 4529 (b'C', b'copies', None, _(b'show copied files')),
4510 4530 (
4511 4531 b'k',
4512 4532 b'keyword',
4513 4533 [],
4514 4534 _(b'do case-insensitive search for a given text'),
4515 4535 _(b'TEXT'),
4516 4536 ),
4517 4537 (
4518 4538 b'r',
4519 4539 b'rev',
4520 4540 [],
4521 4541 _(b'revisions to select or follow from'),
4522 4542 _(b'REV'),
4523 4543 ),
4524 4544 (
4525 4545 b'L',
4526 4546 b'line-range',
4527 4547 [],
4528 4548 _(b'follow line range of specified file (EXPERIMENTAL)'),
4529 4549 _(b'FILE,RANGE'),
4530 4550 ),
4531 4551 (
4532 4552 b'',
4533 4553 b'removed',
4534 4554 None,
4535 4555 _(b'include revisions where files were removed'),
4536 4556 ),
4537 4557 (
4538 4558 b'm',
4539 4559 b'only-merges',
4540 4560 None,
4541 4561 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4542 4562 ),
4543 4563 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4544 4564 (
4545 4565 b'',
4546 4566 b'only-branch',
4547 4567 [],
4548 4568 _(
4549 4569 b'show only changesets within the given named branch (DEPRECATED)'
4550 4570 ),
4551 4571 _(b'BRANCH'),
4552 4572 ),
4553 4573 (
4554 4574 b'b',
4555 4575 b'branch',
4556 4576 [],
4557 4577 _(b'show changesets within the given named branch'),
4558 4578 _(b'BRANCH'),
4559 4579 ),
4560 4580 (
4561 4581 b'B',
4562 4582 b'bookmark',
4563 4583 [],
4564 4584 _(b"show changesets within the given bookmark"),
4565 4585 _(b'BOOKMARK'),
4566 4586 ),
4567 4587 (
4568 4588 b'P',
4569 4589 b'prune',
4570 4590 [],
4571 4591 _(b'do not display revision or any of its ancestors'),
4572 4592 _(b'REV'),
4573 4593 ),
4574 4594 ]
4575 4595 + logopts
4576 4596 + walkopts,
4577 4597 _(b'[OPTION]... [FILE]'),
4578 4598 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4579 4599 helpbasic=True,
4580 4600 inferrepo=True,
4581 4601 intents={INTENT_READONLY},
4582 4602 )
4583 4603 def log(ui, repo, *pats, **opts):
4584 4604 """show revision history of entire repository or files
4585 4605
4586 4606 Print the revision history of the specified files or the entire
4587 4607 project.
4588 4608
4589 4609 If no revision range is specified, the default is ``tip:0`` unless
4590 4610 --follow is set.
4591 4611
4592 4612 File history is shown without following rename or copy history of
4593 4613 files. Use -f/--follow with a filename to follow history across
4594 4614 renames and copies. --follow without a filename will only show
4595 4615 ancestors of the starting revisions. The starting revisions can be
4596 4616 specified by -r/--rev, which default to the working directory parent.
4597 4617
4598 4618 By default this command prints revision number and changeset id,
4599 4619 tags, non-trivial parents, user, date and time, and a summary for
4600 4620 each commit. When the -v/--verbose switch is used, the list of
4601 4621 changed files and full commit message are shown.
4602 4622
4603 4623 With --graph the revisions are shown as an ASCII art DAG with the most
4604 4624 recent changeset at the top.
4605 4625 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4606 4626 involved in an unresolved merge conflict, '_' closes a branch,
4607 4627 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4608 4628 changeset from the lines below is a parent of the 'o' merge on the same
4609 4629 line.
4610 4630 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4611 4631 of a '|' indicates one or more revisions in a path are omitted.
4612 4632
4613 4633 .. container:: verbose
4614 4634
4615 4635 Use -L/--line-range FILE,M:N options to follow the history of lines
4616 4636 from M to N in FILE. With -p/--patch only diff hunks affecting
4617 4637 specified line range will be shown. This option requires --follow;
4618 4638 it can be specified multiple times. Currently, this option is not
4619 4639 compatible with --graph. This option is experimental.
4620 4640
4621 4641 .. note::
4622 4642
4623 4643 :hg:`log --patch` may generate unexpected diff output for merge
4624 4644 changesets, as it will only compare the merge changeset against
4625 4645 its first parent. Also, only files different from BOTH parents
4626 4646 will appear in files:.
4627 4647
4628 4648 .. note::
4629 4649
4630 4650 For performance reasons, :hg:`log FILE` may omit duplicate changes
4631 4651 made on branches and will not show removals or mode changes. To
4632 4652 see all such changes, use the --removed switch.
4633 4653
4634 4654 .. container:: verbose
4635 4655
4636 4656 .. note::
4637 4657
4638 4658 The history resulting from -L/--line-range options depends on diff
4639 4659 options; for instance if white-spaces are ignored, respective changes
4640 4660 with only white-spaces in specified line range will not be listed.
4641 4661
4642 4662 .. container:: verbose
4643 4663
4644 4664 Some examples:
4645 4665
4646 4666 - changesets with full descriptions and file lists::
4647 4667
4648 4668 hg log -v
4649 4669
4650 4670 - changesets ancestral to the working directory::
4651 4671
4652 4672 hg log -f
4653 4673
4654 4674 - last 10 commits on the current branch::
4655 4675
4656 4676 hg log -l 10 -b .
4657 4677
4658 4678 - changesets showing all modifications of a file, including removals::
4659 4679
4660 4680 hg log --removed file.c
4661 4681
4662 4682 - all changesets that touch a directory, with diffs, excluding merges::
4663 4683
4664 4684 hg log -Mp lib/
4665 4685
4666 4686 - all revision numbers that match a keyword::
4667 4687
4668 4688 hg log -k bug --template "{rev}\\n"
4669 4689
4670 4690 - the full hash identifier of the working directory parent::
4671 4691
4672 4692 hg log -r . --template "{node}\\n"
4673 4693
4674 4694 - list available log templates::
4675 4695
4676 4696 hg log -T list
4677 4697
4678 4698 - check if a given changeset is included in a tagged release::
4679 4699
4680 4700 hg log -r "a21ccf and ancestor(1.9)"
4681 4701
4682 4702 - find all changesets by some user in a date range::
4683 4703
4684 4704 hg log -k alice -d "may 2008 to jul 2008"
4685 4705
4686 4706 - summary of all changesets after the last tag::
4687 4707
4688 4708 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4689 4709
4690 4710 - changesets touching lines 13 to 23 for file.c::
4691 4711
4692 4712 hg log -L file.c,13:23
4693 4713
4694 4714 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4695 4715 main.c with patch::
4696 4716
4697 4717 hg log -L file.c,13:23 -L main.c,2:6 -p
4698 4718
4699 4719 See :hg:`help dates` for a list of formats valid for -d/--date.
4700 4720
4701 4721 See :hg:`help revisions` for more about specifying and ordering
4702 4722 revisions.
4703 4723
4704 4724 See :hg:`help templates` for more about pre-packaged styles and
4705 4725 specifying custom templates. The default template used by the log
4706 4726 command can be customized via the ``command-templates.log`` configuration
4707 4727 setting.
4708 4728
4709 4729 Returns 0 on success.
4710 4730
4711 4731 """
4712 4732 opts = pycompat.byteskwargs(opts)
4713 4733 linerange = opts.get(b'line_range')
4714 4734
4715 4735 if linerange and not opts.get(b'follow'):
4716 4736 raise error.InputError(_(b'--line-range requires --follow'))
4717 4737
4718 4738 if linerange and pats:
4719 4739 # TODO: take pats as patterns with no line-range filter
4720 4740 raise error.InputError(
4721 4741 _(b'FILE arguments are not compatible with --line-range option')
4722 4742 )
4723 4743
4724 4744 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4725 4745 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4726 4746 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4727 4747 if linerange:
4728 4748 # TODO: should follow file history from logcmdutil._initialrevs(),
4729 4749 # then filter the result by logcmdutil._makerevset() and --limit
4730 4750 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4731 4751
4732 4752 getcopies = None
4733 4753 if opts.get(b'copies'):
4734 4754 endrev = None
4735 4755 if revs:
4736 4756 endrev = revs.max() + 1
4737 4757 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4738 4758
4739 4759 ui.pager(b'log')
4740 4760 displayer = logcmdutil.changesetdisplayer(
4741 4761 ui, repo, opts, differ, buffered=True
4742 4762 )
4743 4763 if opts.get(b'graph'):
4744 4764 displayfn = logcmdutil.displaygraphrevs
4745 4765 else:
4746 4766 displayfn = logcmdutil.displayrevs
4747 4767 displayfn(ui, repo, revs, displayer, getcopies)
4748 4768
4749 4769
4750 4770 @command(
4751 4771 b'manifest',
4752 4772 [
4753 4773 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4754 4774 (b'', b'all', False, _(b"list files from all revisions")),
4755 4775 ]
4756 4776 + formatteropts,
4757 4777 _(b'[-r REV]'),
4758 4778 helpcategory=command.CATEGORY_MAINTENANCE,
4759 4779 intents={INTENT_READONLY},
4760 4780 )
4761 4781 def manifest(ui, repo, node=None, rev=None, **opts):
4762 4782 """output the current or given revision of the project manifest
4763 4783
4764 4784 Print a list of version controlled files for the given revision.
4765 4785 If no revision is given, the first parent of the working directory
4766 4786 is used, or the null revision if no revision is checked out.
4767 4787
4768 4788 With -v, print file permissions, symlink and executable bits.
4769 4789 With --debug, print file revision hashes.
4770 4790
4771 4791 If option --all is specified, the list of all files from all revisions
4772 4792 is printed. This includes deleted and renamed files.
4773 4793
4774 4794 Returns 0 on success.
4775 4795 """
4776 4796 opts = pycompat.byteskwargs(opts)
4777 4797 fm = ui.formatter(b'manifest', opts)
4778 4798
4779 4799 if opts.get(b'all'):
4780 4800 if rev or node:
4781 4801 raise error.InputError(_(b"can't specify a revision with --all"))
4782 4802
4783 4803 res = set()
4784 4804 for rev in repo:
4785 4805 ctx = repo[rev]
4786 4806 res |= set(ctx.files())
4787 4807
4788 4808 ui.pager(b'manifest')
4789 4809 for f in sorted(res):
4790 4810 fm.startitem()
4791 4811 fm.write(b"path", b'%s\n', f)
4792 4812 fm.end()
4793 4813 return
4794 4814
4795 4815 if rev and node:
4796 4816 raise error.InputError(_(b"please specify just one revision"))
4797 4817
4798 4818 if not node:
4799 4819 node = rev
4800 4820
4801 4821 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4802 4822 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4803 4823 if node:
4804 4824 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4805 4825 ctx = logcmdutil.revsingle(repo, node)
4806 4826 mf = ctx.manifest()
4807 4827 ui.pager(b'manifest')
4808 4828 for f in ctx:
4809 4829 fm.startitem()
4810 4830 fm.context(ctx=ctx)
4811 4831 fl = ctx[f].flags()
4812 4832 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4813 4833 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4814 4834 fm.write(b'path', b'%s\n', f)
4815 4835 fm.end()
4816 4836
4817 4837
4818 4838 @command(
4819 4839 b'merge',
4820 4840 [
4821 4841 (
4822 4842 b'f',
4823 4843 b'force',
4824 4844 None,
4825 4845 _(b'force a merge including outstanding changes (DEPRECATED)'),
4826 4846 ),
4827 4847 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4828 4848 (
4829 4849 b'P',
4830 4850 b'preview',
4831 4851 None,
4832 4852 _(b'review revisions to merge (no merge is performed)'),
4833 4853 ),
4834 4854 (b'', b'abort', None, _(b'abort the ongoing merge')),
4835 4855 ]
4836 4856 + mergetoolopts,
4837 4857 _(b'[-P] [[-r] REV]'),
4838 4858 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4839 4859 helpbasic=True,
4840 4860 )
4841 4861 def merge(ui, repo, node=None, **opts):
4842 4862 """merge another revision into working directory
4843 4863
4844 4864 The current working directory is updated with all changes made in
4845 4865 the requested revision since the last common predecessor revision.
4846 4866
4847 4867 Files that changed between either parent are marked as changed for
4848 4868 the next commit and a commit must be performed before any further
4849 4869 updates to the repository are allowed. The next commit will have
4850 4870 two parents.
4851 4871
4852 4872 ``--tool`` can be used to specify the merge tool used for file
4853 4873 merges. It overrides the HGMERGE environment variable and your
4854 4874 configuration files. See :hg:`help merge-tools` for options.
4855 4875
4856 4876 If no revision is specified, the working directory's parent is a
4857 4877 head revision, and the current branch contains exactly one other
4858 4878 head, the other head is merged with by default. Otherwise, an
4859 4879 explicit revision with which to merge must be provided.
4860 4880
4861 4881 See :hg:`help resolve` for information on handling file conflicts.
4862 4882
4863 4883 To undo an uncommitted merge, use :hg:`merge --abort` which
4864 4884 will check out a clean copy of the original merge parent, losing
4865 4885 all changes.
4866 4886
4867 4887 Returns 0 on success, 1 if there are unresolved files.
4868 4888 """
4869 4889
4870 4890 opts = pycompat.byteskwargs(opts)
4871 4891 abort = opts.get(b'abort')
4872 4892 if abort and repo.dirstate.p2() == repo.nullid:
4873 4893 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4874 4894 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4875 4895 if abort:
4876 4896 state = cmdutil.getunfinishedstate(repo)
4877 4897 if state and state._opname != b'merge':
4878 4898 raise error.StateError(
4879 4899 _(b'cannot abort merge with %s in progress') % (state._opname),
4880 4900 hint=state.hint(),
4881 4901 )
4882 4902 if node:
4883 4903 raise error.InputError(_(b"cannot specify a node with --abort"))
4884 4904 return hg.abortmerge(repo.ui, repo)
4885 4905
4886 4906 if opts.get(b'rev') and node:
4887 4907 raise error.InputError(_(b"please specify just one revision"))
4888 4908 if not node:
4889 4909 node = opts.get(b'rev')
4890 4910
4891 4911 if node:
4892 4912 ctx = logcmdutil.revsingle(repo, node)
4893 4913 else:
4894 4914 if ui.configbool(b'commands', b'merge.require-rev'):
4895 4915 raise error.InputError(
4896 4916 _(
4897 4917 b'configuration requires specifying revision to merge '
4898 4918 b'with'
4899 4919 )
4900 4920 )
4901 4921 ctx = repo[destutil.destmerge(repo)]
4902 4922
4903 4923 if ctx.node() is None:
4904 4924 raise error.InputError(
4905 4925 _(b'merging with the working copy has no effect')
4906 4926 )
4907 4927
4908 4928 if opts.get(b'preview'):
4909 4929 # find nodes that are ancestors of p2 but not of p1
4910 4930 p1 = repo[b'.'].node()
4911 4931 p2 = ctx.node()
4912 4932 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4913 4933
4914 4934 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4915 4935 for node in nodes:
4916 4936 displayer.show(repo[node])
4917 4937 displayer.close()
4918 4938 return 0
4919 4939
4920 4940 # ui.forcemerge is an internal variable, do not document
4921 4941 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4922 4942 with ui.configoverride(overrides, b'merge'):
4923 4943 force = opts.get(b'force')
4924 4944 labels = [b'working copy', b'merge rev', b'common ancestor']
4925 4945 return hg.merge(ctx, force=force, labels=labels)
4926 4946
4927 4947
4928 4948 statemod.addunfinished(
4929 4949 b'merge',
4930 4950 fname=None,
4931 4951 clearable=True,
4932 4952 allowcommit=True,
4933 4953 cmdmsg=_(b'outstanding uncommitted merge'),
4934 4954 abortfunc=hg.abortmerge,
4935 4955 statushint=_(
4936 4956 b'To continue: hg commit\nTo abort: hg merge --abort'
4937 4957 ),
4938 4958 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4939 4959 )
4940 4960
4941 4961
4942 4962 @command(
4943 4963 b'outgoing|out',
4944 4964 [
4945 4965 (
4946 4966 b'f',
4947 4967 b'force',
4948 4968 None,
4949 4969 _(b'run even when the destination is unrelated'),
4950 4970 ),
4951 4971 (
4952 4972 b'r',
4953 4973 b'rev',
4954 4974 [],
4955 4975 _(b'a changeset intended to be included in the destination'),
4956 4976 _(b'REV'),
4957 4977 ),
4958 4978 (b'n', b'newest-first', None, _(b'show newest record first')),
4959 4979 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4960 4980 (
4961 4981 b'b',
4962 4982 b'branch',
4963 4983 [],
4964 4984 _(b'a specific branch you would like to push'),
4965 4985 _(b'BRANCH'),
4966 4986 ),
4967 4987 ]
4968 4988 + logopts
4969 4989 + remoteopts
4970 4990 + subrepoopts,
4971 4991 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]...'),
4972 4992 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4973 4993 )
4974 4994 def outgoing(ui, repo, *dests, **opts):
4975 4995 """show changesets not found in the destination
4976 4996
4977 4997 Show changesets not found in the specified destination repository
4978 4998 or the default push location. These are the changesets that would
4979 4999 be pushed if a push was requested.
4980 5000
4981 5001 See pull for details of valid destination formats.
4982 5002
4983 5003 .. container:: verbose
4984 5004
4985 5005 With -B/--bookmarks, the result of bookmark comparison between
4986 5006 local and remote repositories is displayed. With -v/--verbose,
4987 5007 status is also displayed for each bookmark like below::
4988 5008
4989 5009 BM1 01234567890a added
4990 5010 BM2 deleted
4991 5011 BM3 234567890abc advanced
4992 5012 BM4 34567890abcd diverged
4993 5013 BM5 4567890abcde changed
4994 5014
4995 5015 The action taken when pushing depends on the
4996 5016 status of each bookmark:
4997 5017
4998 5018 :``added``: push with ``-B`` will create it
4999 5019 :``deleted``: push with ``-B`` will delete it
5000 5020 :``advanced``: push will update it
5001 5021 :``diverged``: push with ``-B`` will update it
5002 5022 :``changed``: push with ``-B`` will update it
5003 5023
5004 5024 From the point of view of pushing behavior, bookmarks
5005 5025 existing only in the remote repository are treated as
5006 5026 ``deleted``, even if it is in fact added remotely.
5007 5027
5008 5028 Returns 0 if there are outgoing changes, 1 otherwise.
5009 5029 """
5010 5030 opts = pycompat.byteskwargs(opts)
5011 5031 if opts.get(b'bookmarks'):
5012 5032 for path in urlutil.get_push_paths(repo, ui, dests):
5013 5033 dest = path.pushloc or path.loc
5014 5034 other = hg.peer(repo, opts, dest)
5015 5035 try:
5016 5036 if b'bookmarks' not in other.listkeys(b'namespaces'):
5017 5037 ui.warn(_(b"remote doesn't support bookmarks\n"))
5018 5038 return 0
5019 5039 ui.status(
5020 5040 _(b'comparing with %s\n') % urlutil.hidepassword(dest)
5021 5041 )
5022 5042 ui.pager(b'outgoing')
5023 5043 return bookmarks.outgoing(ui, repo, other)
5024 5044 finally:
5025 5045 other.close()
5026 5046
5027 5047 return hg.outgoing(ui, repo, dests, opts)
5028 5048
5029 5049
5030 5050 @command(
5031 5051 b'parents',
5032 5052 [
5033 5053 (
5034 5054 b'r',
5035 5055 b'rev',
5036 5056 b'',
5037 5057 _(b'show parents of the specified revision'),
5038 5058 _(b'REV'),
5039 5059 ),
5040 5060 ]
5041 5061 + templateopts,
5042 5062 _(b'[-r REV] [FILE]'),
5043 5063 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5044 5064 inferrepo=True,
5045 5065 )
5046 5066 def parents(ui, repo, file_=None, **opts):
5047 5067 """show the parents of the working directory or revision (DEPRECATED)
5048 5068
5049 5069 Print the working directory's parent revisions. If a revision is
5050 5070 given via -r/--rev, the parent of that revision will be printed.
5051 5071 If a file argument is given, the revision in which the file was
5052 5072 last changed (before the working directory revision or the
5053 5073 argument to --rev if given) is printed.
5054 5074
5055 5075 This command is equivalent to::
5056 5076
5057 5077 hg log -r "p1()+p2()" or
5058 5078 hg log -r "p1(REV)+p2(REV)" or
5059 5079 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5060 5080 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5061 5081
5062 5082 See :hg:`summary` and :hg:`help revsets` for related information.
5063 5083
5064 5084 Returns 0 on success.
5065 5085 """
5066 5086
5067 5087 opts = pycompat.byteskwargs(opts)
5068 5088 rev = opts.get(b'rev')
5069 5089 if rev:
5070 5090 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5071 5091 ctx = logcmdutil.revsingle(repo, rev, None)
5072 5092
5073 5093 if file_:
5074 5094 m = scmutil.match(ctx, (file_,), opts)
5075 5095 if m.anypats() or len(m.files()) != 1:
5076 5096 raise error.InputError(_(b'can only specify an explicit filename'))
5077 5097 file_ = m.files()[0]
5078 5098 filenodes = []
5079 5099 for cp in ctx.parents():
5080 5100 if not cp:
5081 5101 continue
5082 5102 try:
5083 5103 filenodes.append(cp.filenode(file_))
5084 5104 except error.LookupError:
5085 5105 pass
5086 5106 if not filenodes:
5087 5107 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5088 5108 p = []
5089 5109 for fn in filenodes:
5090 5110 fctx = repo.filectx(file_, fileid=fn)
5091 5111 p.append(fctx.node())
5092 5112 else:
5093 5113 p = [cp.node() for cp in ctx.parents()]
5094 5114
5095 5115 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5096 5116 for n in p:
5097 5117 if n != repo.nullid:
5098 5118 displayer.show(repo[n])
5099 5119 displayer.close()
5100 5120
5101 5121
5102 5122 @command(
5103 5123 b'paths',
5104 5124 formatteropts,
5105 5125 _(b'[NAME]'),
5106 5126 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5107 5127 optionalrepo=True,
5108 5128 intents={INTENT_READONLY},
5109 5129 )
5110 5130 def paths(ui, repo, search=None, **opts):
5111 5131 """show aliases for remote repositories
5112 5132
5113 5133 Show definition of symbolic path name NAME. If no name is given,
5114 5134 show definition of all available names.
5115 5135
5116 5136 Option -q/--quiet suppresses all output when searching for NAME
5117 5137 and shows only the path names when listing all definitions.
5118 5138
5119 5139 Path names are defined in the [paths] section of your
5120 5140 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5121 5141 repository, ``.hg/hgrc`` is used, too.
5122 5142
5123 5143 The path names ``default`` and ``default-push`` have a special
5124 5144 meaning. When performing a push or pull operation, they are used
5125 5145 as fallbacks if no location is specified on the command-line.
5126 5146 When ``default-push`` is set, it will be used for push and
5127 5147 ``default`` will be used for pull; otherwise ``default`` is used
5128 5148 as the fallback for both. When cloning a repository, the clone
5129 5149 source is written as ``default`` in ``.hg/hgrc``.
5130 5150
5131 5151 .. note::
5132 5152
5133 5153 ``default`` and ``default-push`` apply to all inbound (e.g.
5134 5154 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5135 5155 and :hg:`bundle`) operations.
5136 5156
5137 5157 See :hg:`help urls` for more information.
5138 5158
5139 5159 .. container:: verbose
5140 5160
5141 5161 Template:
5142 5162
5143 5163 The following keywords are supported. See also :hg:`help templates`.
5144 5164
5145 5165 :name: String. Symbolic name of the path alias.
5146 5166 :pushurl: String. URL for push operations.
5147 5167 :url: String. URL or directory path for the other operations.
5148 5168
5149 5169 Returns 0 on success.
5150 5170 """
5151 5171
5152 5172 opts = pycompat.byteskwargs(opts)
5153 5173
5154 5174 pathitems = urlutil.list_paths(ui, search)
5155 5175 ui.pager(b'paths')
5156 5176
5157 5177 fm = ui.formatter(b'paths', opts)
5158 5178 if fm.isplain():
5159 5179 hidepassword = urlutil.hidepassword
5160 5180 else:
5161 5181 hidepassword = bytes
5162 5182 if ui.quiet:
5163 5183 namefmt = b'%s\n'
5164 5184 else:
5165 5185 namefmt = b'%s = '
5166 5186 showsubopts = not search and not ui.quiet
5167 5187
5168 5188 for name, path in pathitems:
5169 5189 fm.startitem()
5170 5190 fm.condwrite(not search, b'name', namefmt, name)
5171 5191 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5172 5192 for subopt, value in sorted(path.suboptions.items()):
5173 5193 assert subopt not in (b'name', b'url')
5174 5194 if showsubopts:
5175 5195 fm.plain(b'%s:%s = ' % (name, subopt))
5176 5196 if isinstance(value, bool):
5177 5197 if value:
5178 5198 value = b'yes'
5179 5199 else:
5180 5200 value = b'no'
5181 5201 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5182 5202
5183 5203 fm.end()
5184 5204
5185 5205 if search and not pathitems:
5186 5206 if not ui.quiet:
5187 5207 ui.warn(_(b"not found!\n"))
5188 5208 return 1
5189 5209 else:
5190 5210 return 0
5191 5211
5192 5212
5193 5213 @command(
5194 5214 b'phase',
5195 5215 [
5196 5216 (b'p', b'public', False, _(b'set changeset phase to public')),
5197 5217 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5198 5218 (b's', b'secret', False, _(b'set changeset phase to secret')),
5199 5219 (b'f', b'force', False, _(b'allow to move boundary backward')),
5200 5220 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5201 5221 ],
5202 5222 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5203 5223 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5204 5224 )
5205 5225 def phase(ui, repo, *revs, **opts):
5206 5226 """set or show the current phase name
5207 5227
5208 5228 With no argument, show the phase name of the current revision(s).
5209 5229
5210 5230 With one of -p/--public, -d/--draft or -s/--secret, change the
5211 5231 phase value of the specified revisions.
5212 5232
5213 5233 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5214 5234 lower phase to a higher phase. Phases are ordered as follows::
5215 5235
5216 5236 public < draft < secret
5217 5237
5218 5238 Returns 0 on success, 1 if some phases could not be changed.
5219 5239
5220 5240 (For more information about the phases concept, see :hg:`help phases`.)
5221 5241 """
5222 5242 opts = pycompat.byteskwargs(opts)
5223 5243 # search for a unique phase argument
5224 5244 targetphase = None
5225 5245 for idx, name in enumerate(phases.cmdphasenames):
5226 5246 if opts[name]:
5227 5247 if targetphase is not None:
5228 5248 raise error.InputError(_(b'only one phase can be specified'))
5229 5249 targetphase = idx
5230 5250
5231 5251 # look for specified revision
5232 5252 revs = list(revs)
5233 5253 revs.extend(opts[b'rev'])
5234 5254 if revs:
5235 5255 revs = logcmdutil.revrange(repo, revs)
5236 5256 else:
5237 5257 # display both parents as the second parent phase can influence
5238 5258 # the phase of a merge commit
5239 5259 revs = [c.rev() for c in repo[None].parents()]
5240 5260
5241 5261 ret = 0
5242 5262 if targetphase is None:
5243 5263 # display
5244 5264 for r in revs:
5245 5265 ctx = repo[r]
5246 5266 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5247 5267 else:
5248 5268 with repo.lock(), repo.transaction(b"phase") as tr:
5249 5269 # set phase
5250 5270 if not revs:
5251 5271 raise error.InputError(_(b'empty revision set'))
5252 5272 nodes = [repo[r].node() for r in revs]
5253 5273 # moving revision from public to draft may hide them
5254 5274 # We have to check result on an unfiltered repository
5255 5275 unfi = repo.unfiltered()
5256 5276 getphase = unfi._phasecache.phase
5257 5277 olddata = [getphase(unfi, r) for r in unfi]
5258 5278 phases.advanceboundary(repo, tr, targetphase, nodes)
5259 5279 if opts[b'force']:
5260 5280 phases.retractboundary(repo, tr, targetphase, nodes)
5261 5281 getphase = unfi._phasecache.phase
5262 5282 newdata = [getphase(unfi, r) for r in unfi]
5263 5283 changes = sum(newdata[r] != olddata[r] for r in unfi)
5264 5284 cl = unfi.changelog
5265 5285 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5266 5286 if rejected:
5267 5287 ui.warn(
5268 5288 _(
5269 5289 b'cannot move %i changesets to a higher '
5270 5290 b'phase, use --force\n'
5271 5291 )
5272 5292 % len(rejected)
5273 5293 )
5274 5294 ret = 1
5275 5295 if changes:
5276 5296 msg = _(b'phase changed for %i changesets\n') % changes
5277 5297 if ret:
5278 5298 ui.status(msg)
5279 5299 else:
5280 5300 ui.note(msg)
5281 5301 else:
5282 5302 ui.warn(_(b'no phases changed\n'))
5283 5303 return ret
5284 5304
5285 5305
5286 5306 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5287 5307 """Run after a changegroup has been added via pull/unbundle
5288 5308
5289 5309 This takes arguments below:
5290 5310
5291 5311 :modheads: change of heads by pull/unbundle
5292 5312 :optupdate: updating working directory is needed or not
5293 5313 :checkout: update destination revision (or None to default destination)
5294 5314 :brev: a name, which might be a bookmark to be activated after updating
5295 5315
5296 5316 return True if update raise any conflict, False otherwise.
5297 5317 """
5298 5318 if modheads == 0:
5299 5319 return False
5300 5320 if optupdate:
5301 5321 try:
5302 5322 return hg.updatetotally(ui, repo, checkout, brev)
5303 5323 except error.UpdateAbort as inst:
5304 5324 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5305 5325 hint = inst.hint
5306 5326 raise error.UpdateAbort(msg, hint=hint)
5307 5327 if modheads is not None and modheads > 1:
5308 5328 currentbranchheads = len(repo.branchheads())
5309 5329 if currentbranchheads == modheads:
5310 5330 ui.status(
5311 5331 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5312 5332 )
5313 5333 elif currentbranchheads > 1:
5314 5334 ui.status(
5315 5335 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5316 5336 )
5317 5337 else:
5318 5338 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5319 5339 elif not ui.configbool(b'commands', b'update.requiredest'):
5320 5340 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5321 5341 return False
5322 5342
5323 5343
5324 5344 @command(
5325 5345 b'pull',
5326 5346 [
5327 5347 (
5328 5348 b'u',
5329 5349 b'update',
5330 5350 None,
5331 5351 _(b'update to new branch head if new descendants were pulled'),
5332 5352 ),
5333 5353 (
5334 5354 b'f',
5335 5355 b'force',
5336 5356 None,
5337 5357 _(b'run even when remote repository is unrelated'),
5338 5358 ),
5339 5359 (
5340 5360 b'',
5341 5361 b'confirm',
5342 5362 None,
5343 5363 _(b'confirm pull before applying changes'),
5344 5364 ),
5345 5365 (
5346 5366 b'r',
5347 5367 b'rev',
5348 5368 [],
5349 5369 _(b'a remote changeset intended to be added'),
5350 5370 _(b'REV'),
5351 5371 ),
5352 5372 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5353 5373 (
5354 5374 b'b',
5355 5375 b'branch',
5356 5376 [],
5357 5377 _(b'a specific branch you would like to pull'),
5358 5378 _(b'BRANCH'),
5359 5379 ),
5360 5380 ]
5361 5381 + remoteopts,
5362 5382 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5363 5383 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5364 5384 helpbasic=True,
5365 5385 )
5366 5386 def pull(ui, repo, *sources, **opts):
5367 5387 """pull changes from the specified source
5368 5388
5369 5389 Pull changes from a remote repository to a local one.
5370 5390
5371 5391 This finds all changes from the repository at the specified path
5372 5392 or URL and adds them to a local repository (the current one unless
5373 5393 -R is specified). By default, this does not update the copy of the
5374 5394 project in the working directory.
5375 5395
5376 5396 When cloning from servers that support it, Mercurial may fetch
5377 5397 pre-generated data. When this is done, hooks operating on incoming
5378 5398 changesets and changegroups may fire more than once, once for each
5379 5399 pre-generated bundle and as well as for any additional remaining
5380 5400 data. See :hg:`help -e clonebundles` for more.
5381 5401
5382 5402 Use :hg:`incoming` if you want to see what would have been added
5383 5403 by a pull at the time you issued this command. If you then decide
5384 5404 to add those changes to the repository, you should use :hg:`pull
5385 5405 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5386 5406
5387 5407 If SOURCE is omitted, the 'default' path will be used.
5388 5408 See :hg:`help urls` for more information.
5389 5409
5390 5410 If multiple sources are specified, they will be pulled sequentially as if
5391 5411 the command was run multiple time. If --update is specify and the command
5392 5412 will stop at the first failed --update.
5393 5413
5394 5414 Specifying bookmark as ``.`` is equivalent to specifying the active
5395 5415 bookmark's name.
5396 5416
5397 5417 Returns 0 on success, 1 if an update had unresolved files.
5398 5418 """
5399 5419
5400 5420 opts = pycompat.byteskwargs(opts)
5401 5421 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5402 5422 b'update'
5403 5423 ):
5404 5424 msg = _(b'update destination required by configuration')
5405 5425 hint = _(b'use hg pull followed by hg update DEST')
5406 5426 raise error.InputError(msg, hint=hint)
5407 5427
5408 5428 for path in urlutil.get_pull_paths(repo, ui, sources):
5409 5429 source, branches = urlutil.parseurl(path.rawloc, opts.get(b'branch'))
5410 5430 ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(source))
5411 5431 ui.flush()
5412 5432 other = hg.peer(repo, opts, source)
5413 5433 update_conflict = None
5414 5434 try:
5415 5435 revs, checkout = hg.addbranchrevs(
5416 5436 repo, other, branches, opts.get(b'rev')
5417 5437 )
5418 5438
5419 5439 pullopargs = {}
5420 5440
5421 5441 nodes = None
5422 5442 if opts.get(b'bookmark') or revs:
5423 5443 # The list of bookmark used here is the same used to actually update
5424 5444 # the bookmark names, to avoid the race from issue 4689 and we do
5425 5445 # all lookup and bookmark queries in one go so they see the same
5426 5446 # version of the server state (issue 4700).
5427 5447 nodes = []
5428 5448 fnodes = []
5429 5449 revs = revs or []
5430 5450 if revs and not other.capable(b'lookup'):
5431 5451 err = _(
5432 5452 b"other repository doesn't support revision lookup, "
5433 5453 b"so a rev cannot be specified."
5434 5454 )
5435 5455 raise error.Abort(err)
5436 5456 with other.commandexecutor() as e:
5437 5457 fremotebookmarks = e.callcommand(
5438 5458 b'listkeys', {b'namespace': b'bookmarks'}
5439 5459 )
5440 5460 for r in revs:
5441 5461 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5442 5462 remotebookmarks = fremotebookmarks.result()
5443 5463 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5444 5464 pullopargs[b'remotebookmarks'] = remotebookmarks
5445 5465 for b in opts.get(b'bookmark', []):
5446 5466 b = repo._bookmarks.expandname(b)
5447 5467 if b not in remotebookmarks:
5448 5468 raise error.InputError(
5449 5469 _(b'remote bookmark %s not found!') % b
5450 5470 )
5451 5471 nodes.append(remotebookmarks[b])
5452 5472 for i, rev in enumerate(revs):
5453 5473 node = fnodes[i].result()
5454 5474 nodes.append(node)
5455 5475 if rev == checkout:
5456 5476 checkout = node
5457 5477
5458 5478 wlock = util.nullcontextmanager()
5459 5479 if opts.get(b'update'):
5460 5480 wlock = repo.wlock()
5461 5481 with wlock:
5462 5482 pullopargs.update(opts.get(b'opargs', {}))
5463 5483 modheads = exchange.pull(
5464 5484 repo,
5465 5485 other,
5466 5486 path=path,
5467 5487 heads=nodes,
5468 5488 force=opts.get(b'force'),
5469 5489 bookmarks=opts.get(b'bookmark', ()),
5470 5490 opargs=pullopargs,
5471 5491 confirm=opts.get(b'confirm'),
5472 5492 ).cgresult
5473 5493
5474 5494 # brev is a name, which might be a bookmark to be activated at
5475 5495 # the end of the update. In other words, it is an explicit
5476 5496 # destination of the update
5477 5497 brev = None
5478 5498
5479 5499 if checkout:
5480 5500 checkout = repo.unfiltered().changelog.rev(checkout)
5481 5501
5482 5502 # order below depends on implementation of
5483 5503 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5484 5504 # because 'checkout' is determined without it.
5485 5505 if opts.get(b'rev'):
5486 5506 brev = opts[b'rev'][0]
5487 5507 elif opts.get(b'branch'):
5488 5508 brev = opts[b'branch'][0]
5489 5509 else:
5490 5510 brev = branches[0]
5491 5511 repo._subtoppath = source
5492 5512 try:
5493 5513 update_conflict = postincoming(
5494 5514 ui, repo, modheads, opts.get(b'update'), checkout, brev
5495 5515 )
5496 5516 except error.FilteredRepoLookupError as exc:
5497 5517 msg = _(b'cannot update to target: %s') % exc.args[0]
5498 5518 exc.args = (msg,) + exc.args[1:]
5499 5519 raise
5500 5520 finally:
5501 5521 del repo._subtoppath
5502 5522
5503 5523 finally:
5504 5524 other.close()
5505 5525 # skip the remaining pull source if they are some conflict.
5506 5526 if update_conflict:
5507 5527 break
5508 5528 if update_conflict:
5509 5529 return 1
5510 5530 else:
5511 5531 return 0
5512 5532
5513 5533
5514 5534 @command(
5515 5535 b'purge|clean',
5516 5536 [
5517 5537 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5518 5538 (b'', b'all', None, _(b'purge ignored files too')),
5519 5539 (b'i', b'ignored', None, _(b'purge only ignored files')),
5520 5540 (b'', b'dirs', None, _(b'purge empty directories')),
5521 5541 (b'', b'files', None, _(b'purge files')),
5522 5542 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5523 5543 (
5524 5544 b'0',
5525 5545 b'print0',
5526 5546 None,
5527 5547 _(
5528 5548 b'end filenames with NUL, for use with xargs'
5529 5549 b' (implies -p/--print)'
5530 5550 ),
5531 5551 ),
5532 5552 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5533 5553 ]
5534 5554 + cmdutil.walkopts,
5535 5555 _(b'hg purge [OPTION]... [DIR]...'),
5536 5556 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5537 5557 )
5538 5558 def purge(ui, repo, *dirs, **opts):
5539 5559 """removes files not tracked by Mercurial
5540 5560
5541 5561 Delete files not known to Mercurial. This is useful to test local
5542 5562 and uncommitted changes in an otherwise-clean source tree.
5543 5563
5544 5564 This means that purge will delete the following by default:
5545 5565
5546 5566 - Unknown files: files marked with "?" by :hg:`status`
5547 5567 - Empty directories: in fact Mercurial ignores directories unless
5548 5568 they contain files under source control management
5549 5569
5550 5570 But it will leave untouched:
5551 5571
5552 5572 - Modified and unmodified tracked files
5553 5573 - Ignored files (unless -i or --all is specified)
5554 5574 - New files added to the repository (with :hg:`add`)
5555 5575
5556 5576 The --files and --dirs options can be used to direct purge to delete
5557 5577 only files, only directories, or both. If neither option is given,
5558 5578 both will be deleted.
5559 5579
5560 5580 If directories are given on the command line, only files in these
5561 5581 directories are considered.
5562 5582
5563 5583 Be careful with purge, as you could irreversibly delete some files
5564 5584 you forgot to add to the repository. If you only want to print the
5565 5585 list of files that this program would delete, use the --print
5566 5586 option.
5567 5587 """
5568 5588 opts = pycompat.byteskwargs(opts)
5569 5589 cmdutil.check_at_most_one_arg(opts, b'all', b'ignored')
5570 5590
5571 5591 act = not opts.get(b'print')
5572 5592 eol = b'\n'
5573 5593 if opts.get(b'print0'):
5574 5594 eol = b'\0'
5575 5595 act = False # --print0 implies --print
5576 5596 if opts.get(b'all', False):
5577 5597 ignored = True
5578 5598 unknown = True
5579 5599 else:
5580 5600 ignored = opts.get(b'ignored', False)
5581 5601 unknown = not ignored
5582 5602
5583 5603 removefiles = opts.get(b'files')
5584 5604 removedirs = opts.get(b'dirs')
5585 5605 confirm = opts.get(b'confirm')
5586 5606 if confirm is None:
5587 5607 try:
5588 5608 extensions.find(b'purge')
5589 5609 confirm = False
5590 5610 except KeyError:
5591 5611 confirm = True
5592 5612
5593 5613 if not removefiles and not removedirs:
5594 5614 removefiles = True
5595 5615 removedirs = True
5596 5616
5597 5617 match = scmutil.match(repo[None], dirs, opts)
5598 5618
5599 5619 paths = mergemod.purge(
5600 5620 repo,
5601 5621 match,
5602 5622 unknown=unknown,
5603 5623 ignored=ignored,
5604 5624 removeemptydirs=removedirs,
5605 5625 removefiles=removefiles,
5606 5626 abortonerror=opts.get(b'abort_on_err'),
5607 5627 noop=not act,
5608 5628 confirm=confirm,
5609 5629 )
5610 5630
5611 5631 for path in paths:
5612 5632 if not act:
5613 5633 ui.write(b'%s%s' % (path, eol))
5614 5634
5615 5635
5616 5636 @command(
5617 5637 b'push',
5618 5638 [
5619 5639 (b'f', b'force', None, _(b'force push')),
5620 5640 (
5621 5641 b'r',
5622 5642 b'rev',
5623 5643 [],
5624 5644 _(b'a changeset intended to be included in the destination'),
5625 5645 _(b'REV'),
5626 5646 ),
5627 5647 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5628 5648 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5629 5649 (
5630 5650 b'b',
5631 5651 b'branch',
5632 5652 [],
5633 5653 _(b'a specific branch you would like to push'),
5634 5654 _(b'BRANCH'),
5635 5655 ),
5636 5656 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5637 5657 (
5638 5658 b'',
5639 5659 b'pushvars',
5640 5660 [],
5641 5661 _(b'variables that can be sent to server (ADVANCED)'),
5642 5662 ),
5643 5663 (
5644 5664 b'',
5645 5665 b'publish',
5646 5666 False,
5647 5667 _(b'push the changeset as public (EXPERIMENTAL)'),
5648 5668 ),
5649 5669 ]
5650 5670 + remoteopts,
5651 5671 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]...'),
5652 5672 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5653 5673 helpbasic=True,
5654 5674 )
5655 5675 def push(ui, repo, *dests, **opts):
5656 5676 """push changes to the specified destination
5657 5677
5658 5678 Push changesets from the local repository to the specified
5659 5679 destination.
5660 5680
5661 5681 This operation is symmetrical to pull: it is identical to a pull
5662 5682 in the destination repository from the current one.
5663 5683
5664 5684 By default, push will not allow creation of new heads at the
5665 5685 destination, since multiple heads would make it unclear which head
5666 5686 to use. In this situation, it is recommended to pull and merge
5667 5687 before pushing.
5668 5688
5669 5689 Use --new-branch if you want to allow push to create a new named
5670 5690 branch that is not present at the destination. This allows you to
5671 5691 only create a new branch without forcing other changes.
5672 5692
5673 5693 .. note::
5674 5694
5675 5695 Extra care should be taken with the -f/--force option,
5676 5696 which will push all new heads on all branches, an action which will
5677 5697 almost always cause confusion for collaborators.
5678 5698
5679 5699 If -r/--rev is used, the specified revision and all its ancestors
5680 5700 will be pushed to the remote repository.
5681 5701
5682 5702 If -B/--bookmark is used, the specified bookmarked revision, its
5683 5703 ancestors, and the bookmark will be pushed to the remote
5684 5704 repository. Specifying ``.`` is equivalent to specifying the active
5685 5705 bookmark's name. Use the --all-bookmarks option for pushing all
5686 5706 current bookmarks.
5687 5707
5688 5708 Please see :hg:`help urls` for important details about ``ssh://``
5689 5709 URLs. If DESTINATION is omitted, a default path will be used.
5690 5710
5691 5711 When passed multiple destinations, push will process them one after the
5692 5712 other, but stop should an error occur.
5693 5713
5694 5714 .. container:: verbose
5695 5715
5696 5716 The --pushvars option sends strings to the server that become
5697 5717 environment variables prepended with ``HG_USERVAR_``. For example,
5698 5718 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5699 5719 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5700 5720
5701 5721 pushvars can provide for user-overridable hooks as well as set debug
5702 5722 levels. One example is having a hook that blocks commits containing
5703 5723 conflict markers, but enables the user to override the hook if the file
5704 5724 is using conflict markers for testing purposes or the file format has
5705 5725 strings that look like conflict markers.
5706 5726
5707 5727 By default, servers will ignore `--pushvars`. To enable it add the
5708 5728 following to your configuration file::
5709 5729
5710 5730 [push]
5711 5731 pushvars.server = true
5712 5732
5713 5733 Returns 0 if push was successful, 1 if nothing to push.
5714 5734 """
5715 5735
5716 5736 opts = pycompat.byteskwargs(opts)
5717 5737
5718 5738 if opts.get(b'all_bookmarks'):
5719 5739 cmdutil.check_incompatible_arguments(
5720 5740 opts,
5721 5741 b'all_bookmarks',
5722 5742 [b'bookmark', b'rev'],
5723 5743 )
5724 5744 opts[b'bookmark'] = list(repo._bookmarks)
5725 5745
5726 5746 if opts.get(b'bookmark'):
5727 5747 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5728 5748 for b in opts[b'bookmark']:
5729 5749 # translate -B options to -r so changesets get pushed
5730 5750 b = repo._bookmarks.expandname(b)
5731 5751 if b in repo._bookmarks:
5732 5752 opts.setdefault(b'rev', []).append(b)
5733 5753 else:
5734 5754 # if we try to push a deleted bookmark, translate it to null
5735 5755 # this lets simultaneous -r, -b options continue working
5736 5756 opts.setdefault(b'rev', []).append(b"null")
5737 5757
5738 5758 some_pushed = False
5739 5759 result = 0
5740 5760 for path in urlutil.get_push_paths(repo, ui, dests):
5741 5761 dest = path.pushloc or path.loc
5742 5762 branches = (path.branch, opts.get(b'branch') or [])
5743 5763 ui.status(_(b'pushing to %s\n') % urlutil.hidepassword(dest))
5744 5764 revs, checkout = hg.addbranchrevs(
5745 5765 repo, repo, branches, opts.get(b'rev')
5746 5766 )
5747 5767 other = hg.peer(repo, opts, dest)
5748 5768
5749 5769 try:
5750 5770 if revs:
5751 5771 revs = [repo[r].node() for r in logcmdutil.revrange(repo, revs)]
5752 5772 if not revs:
5753 5773 raise error.InputError(
5754 5774 _(b"specified revisions evaluate to an empty set"),
5755 5775 hint=_(b"use different revision arguments"),
5756 5776 )
5757 5777 elif path.pushrev:
5758 5778 # It doesn't make any sense to specify ancestor revisions. So limit
5759 5779 # to DAG heads to make discovery simpler.
5760 5780 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5761 5781 revs = scmutil.revrange(repo, [expr])
5762 5782 revs = [repo[rev].node() for rev in revs]
5763 5783 if not revs:
5764 5784 raise error.InputError(
5765 5785 _(
5766 5786 b'default push revset for path evaluates to an empty set'
5767 5787 )
5768 5788 )
5769 5789 elif ui.configbool(b'commands', b'push.require-revs'):
5770 5790 raise error.InputError(
5771 5791 _(b'no revisions specified to push'),
5772 5792 hint=_(b'did you mean "hg push -r ."?'),
5773 5793 )
5774 5794
5775 5795 repo._subtoppath = dest
5776 5796 try:
5777 5797 # push subrepos depth-first for coherent ordering
5778 5798 c = repo[b'.']
5779 5799 subs = c.substate # only repos that are committed
5780 5800 for s in sorted(subs):
5781 5801 sub_result = c.sub(s).push(opts)
5782 5802 if sub_result == 0:
5783 5803 return 1
5784 5804 finally:
5785 5805 del repo._subtoppath
5786 5806
5787 5807 opargs = dict(
5788 5808 opts.get(b'opargs', {})
5789 5809 ) # copy opargs since we may mutate it
5790 5810 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5791 5811
5792 5812 pushop = exchange.push(
5793 5813 repo,
5794 5814 other,
5795 5815 opts.get(b'force'),
5796 5816 revs=revs,
5797 5817 newbranch=opts.get(b'new_branch'),
5798 5818 bookmarks=opts.get(b'bookmark', ()),
5799 5819 publish=opts.get(b'publish'),
5800 5820 opargs=opargs,
5801 5821 )
5802 5822
5803 5823 if pushop.cgresult == 0:
5804 5824 result = 1
5805 5825 elif pushop.cgresult is not None:
5806 5826 some_pushed = True
5807 5827
5808 5828 if pushop.bkresult is not None:
5809 5829 if pushop.bkresult == 2:
5810 5830 result = 2
5811 5831 elif not result and pushop.bkresult:
5812 5832 result = 2
5813 5833
5814 5834 if result:
5815 5835 break
5816 5836
5817 5837 finally:
5818 5838 other.close()
5819 5839 if result == 0 and not some_pushed:
5820 5840 result = 1
5821 5841 return result
5822 5842
5823 5843
5824 5844 @command(
5825 5845 b'recover',
5826 5846 [
5827 5847 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5828 5848 ],
5829 5849 helpcategory=command.CATEGORY_MAINTENANCE,
5830 5850 )
5831 5851 def recover(ui, repo, **opts):
5832 5852 """roll back an interrupted transaction
5833 5853
5834 5854 Recover from an interrupted commit or pull.
5835 5855
5836 5856 This command tries to fix the repository status after an
5837 5857 interrupted operation. It should only be necessary when Mercurial
5838 5858 suggests it.
5839 5859
5840 5860 Returns 0 if successful, 1 if nothing to recover or verify fails.
5841 5861 """
5842 5862 ret = repo.recover()
5843 5863 if ret:
5844 5864 if opts['verify']:
5845 5865 return hg.verify(repo)
5846 5866 else:
5847 5867 msg = _(
5848 5868 b"(verify step skipped, run `hg verify` to check your "
5849 5869 b"repository content)\n"
5850 5870 )
5851 5871 ui.warn(msg)
5852 5872 return 0
5853 5873 return 1
5854 5874
5855 5875
5856 5876 @command(
5857 5877 b'remove|rm',
5858 5878 [
5859 5879 (b'A', b'after', None, _(b'record delete for missing files')),
5860 5880 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5861 5881 ]
5862 5882 + subrepoopts
5863 5883 + walkopts
5864 5884 + dryrunopts,
5865 5885 _(b'[OPTION]... FILE...'),
5866 5886 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5867 5887 helpbasic=True,
5868 5888 inferrepo=True,
5869 5889 )
5870 5890 def remove(ui, repo, *pats, **opts):
5871 5891 """remove the specified files on the next commit
5872 5892
5873 5893 Schedule the indicated files for removal from the current branch.
5874 5894
5875 5895 This command schedules the files to be removed at the next commit.
5876 5896 To undo a remove before that, see :hg:`revert`. To undo added
5877 5897 files, see :hg:`forget`.
5878 5898
5879 5899 .. container:: verbose
5880 5900
5881 5901 -A/--after can be used to remove only files that have already
5882 5902 been deleted, -f/--force can be used to force deletion, and -Af
5883 5903 can be used to remove files from the next revision without
5884 5904 deleting them from the working directory.
5885 5905
5886 5906 The following table details the behavior of remove for different
5887 5907 file states (columns) and option combinations (rows). The file
5888 5908 states are Added [A], Clean [C], Modified [M] and Missing [!]
5889 5909 (as reported by :hg:`status`). The actions are Warn, Remove
5890 5910 (from branch) and Delete (from disk):
5891 5911
5892 5912 ========= == == == ==
5893 5913 opt/state A C M !
5894 5914 ========= == == == ==
5895 5915 none W RD W R
5896 5916 -f R RD RD R
5897 5917 -A W W W R
5898 5918 -Af R R R R
5899 5919 ========= == == == ==
5900 5920
5901 5921 .. note::
5902 5922
5903 5923 :hg:`remove` never deletes files in Added [A] state from the
5904 5924 working directory, not even if ``--force`` is specified.
5905 5925
5906 5926 Returns 0 on success, 1 if any warnings encountered.
5907 5927 """
5908 5928
5909 5929 opts = pycompat.byteskwargs(opts)
5910 5930 after, force = opts.get(b'after'), opts.get(b'force')
5911 5931 dryrun = opts.get(b'dry_run')
5912 5932 if not pats and not after:
5913 5933 raise error.InputError(_(b'no files specified'))
5914 5934
5915 5935 m = scmutil.match(repo[None], pats, opts)
5916 5936 subrepos = opts.get(b'subrepos')
5917 5937 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5918 5938 return cmdutil.remove(
5919 5939 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5920 5940 )
5921 5941
5922 5942
5923 5943 @command(
5924 5944 b'rename|move|mv',
5925 5945 [
5926 5946 (b'', b'forget', None, _(b'unmark a destination file as renamed')),
5927 5947 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5928 5948 (
5929 5949 b'',
5930 5950 b'at-rev',
5931 5951 b'',
5932 5952 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5933 5953 _(b'REV'),
5934 5954 ),
5935 5955 (
5936 5956 b'f',
5937 5957 b'force',
5938 5958 None,
5939 5959 _(b'forcibly move over an existing managed file'),
5940 5960 ),
5941 5961 ]
5942 5962 + walkopts
5943 5963 + dryrunopts,
5944 5964 _(b'[OPTION]... SOURCE... DEST'),
5945 5965 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5946 5966 )
5947 5967 def rename(ui, repo, *pats, **opts):
5948 5968 """rename files; equivalent of copy + remove
5949 5969
5950 5970 Mark dest as copies of sources; mark sources for deletion. If dest
5951 5971 is a directory, copies are put in that directory. If dest is a
5952 5972 file, there can only be one source.
5953 5973
5954 5974 By default, this command copies the contents of files as they
5955 5975 exist in the working directory. If invoked with -A/--after, the
5956 5976 operation is recorded, but no copying is performed.
5957 5977
5958 5978 To undo marking a destination file as renamed, use --forget. With that
5959 5979 option, all given (positional) arguments are unmarked as renames. The
5960 5980 destination file(s) will be left in place (still tracked). The source
5961 5981 file(s) will not be restored. Note that :hg:`rename --forget` behaves
5962 5982 the same way as :hg:`copy --forget`.
5963 5983
5964 5984 This command takes effect with the next commit by default.
5965 5985
5966 5986 Returns 0 on success, 1 if errors are encountered.
5967 5987 """
5968 5988 opts = pycompat.byteskwargs(opts)
5969 5989 with repo.wlock():
5970 5990 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5971 5991
5972 5992
5973 5993 @command(
5974 5994 b'resolve',
5975 5995 [
5976 5996 (b'a', b'all', None, _(b'select all unresolved files')),
5977 5997 (b'l', b'list', None, _(b'list state of files needing merge')),
5978 5998 (b'm', b'mark', None, _(b'mark files as resolved')),
5979 5999 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5980 6000 (b'n', b'no-status', None, _(b'hide status prefix')),
5981 6001 (b'', b're-merge', None, _(b're-merge files')),
5982 6002 ]
5983 6003 + mergetoolopts
5984 6004 + walkopts
5985 6005 + formatteropts,
5986 6006 _(b'[OPTION]... [FILE]...'),
5987 6007 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5988 6008 inferrepo=True,
5989 6009 )
5990 6010 def resolve(ui, repo, *pats, **opts):
5991 6011 """redo merges or set/view the merge status of files
5992 6012
5993 6013 Merges with unresolved conflicts are often the result of
5994 6014 non-interactive merging using the ``internal:merge`` configuration
5995 6015 setting, or a command-line merge tool like ``diff3``. The resolve
5996 6016 command is used to manage the files involved in a merge, after
5997 6017 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5998 6018 working directory must have two parents). See :hg:`help
5999 6019 merge-tools` for information on configuring merge tools.
6000 6020
6001 6021 The resolve command can be used in the following ways:
6002 6022
6003 6023 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
6004 6024 the specified files, discarding any previous merge attempts. Re-merging
6005 6025 is not performed for files already marked as resolved. Use ``--all/-a``
6006 6026 to select all unresolved files. ``--tool`` can be used to specify
6007 6027 the merge tool used for the given files. It overrides the HGMERGE
6008 6028 environment variable and your configuration files. Previous file
6009 6029 contents are saved with a ``.orig`` suffix.
6010 6030
6011 6031 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6012 6032 (e.g. after having manually fixed-up the files). The default is
6013 6033 to mark all unresolved files.
6014 6034
6015 6035 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6016 6036 default is to mark all resolved files.
6017 6037
6018 6038 - :hg:`resolve -l`: list files which had or still have conflicts.
6019 6039 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6020 6040 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
6021 6041 the list. See :hg:`help filesets` for details.
6022 6042
6023 6043 .. note::
6024 6044
6025 6045 Mercurial will not let you commit files with unresolved merge
6026 6046 conflicts. You must use :hg:`resolve -m ...` before you can
6027 6047 commit after a conflicting merge.
6028 6048
6029 6049 .. container:: verbose
6030 6050
6031 6051 Template:
6032 6052
6033 6053 The following keywords are supported in addition to the common template
6034 6054 keywords and functions. See also :hg:`help templates`.
6035 6055
6036 6056 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
6037 6057 :path: String. Repository-absolute path of the file.
6038 6058
6039 6059 Returns 0 on success, 1 if any files fail a resolve attempt.
6040 6060 """
6041 6061
6042 6062 opts = pycompat.byteskwargs(opts)
6043 6063 confirm = ui.configbool(b'commands', b'resolve.confirm')
6044 6064 flaglist = b'all mark unmark list no_status re_merge'.split()
6045 6065 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
6046 6066
6047 6067 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
6048 6068 if actioncount > 1:
6049 6069 raise error.InputError(_(b"too many actions specified"))
6050 6070 elif actioncount == 0 and ui.configbool(
6051 6071 b'commands', b'resolve.explicit-re-merge'
6052 6072 ):
6053 6073 hint = _(b'use --mark, --unmark, --list or --re-merge')
6054 6074 raise error.InputError(_(b'no action specified'), hint=hint)
6055 6075 if pats and all:
6056 6076 raise error.InputError(_(b"can't specify --all and patterns"))
6057 6077 if not (all or pats or show or mark or unmark):
6058 6078 raise error.InputError(
6059 6079 _(b'no files or directories specified'),
6060 6080 hint=b'use --all to re-merge all unresolved files',
6061 6081 )
6062 6082
6063 6083 if confirm:
6064 6084 if all:
6065 6085 if ui.promptchoice(
6066 6086 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6067 6087 ):
6068 6088 raise error.CanceledError(_(b'user quit'))
6069 6089 if mark and not pats:
6070 6090 if ui.promptchoice(
6071 6091 _(
6072 6092 b'mark all unresolved files as resolved (yn)?'
6073 6093 b'$$ &Yes $$ &No'
6074 6094 )
6075 6095 ):
6076 6096 raise error.CanceledError(_(b'user quit'))
6077 6097 if unmark and not pats:
6078 6098 if ui.promptchoice(
6079 6099 _(
6080 6100 b'mark all resolved files as unresolved (yn)?'
6081 6101 b'$$ &Yes $$ &No'
6082 6102 )
6083 6103 ):
6084 6104 raise error.CanceledError(_(b'user quit'))
6085 6105
6086 6106 uipathfn = scmutil.getuipathfn(repo)
6087 6107
6088 6108 if show:
6089 6109 ui.pager(b'resolve')
6090 6110 fm = ui.formatter(b'resolve', opts)
6091 6111 ms = mergestatemod.mergestate.read(repo)
6092 6112 wctx = repo[None]
6093 6113 m = scmutil.match(wctx, pats, opts)
6094 6114
6095 6115 # Labels and keys based on merge state. Unresolved path conflicts show
6096 6116 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6097 6117 # resolved conflicts.
6098 6118 mergestateinfo = {
6099 6119 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6100 6120 b'resolve.unresolved',
6101 6121 b'U',
6102 6122 ),
6103 6123 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6104 6124 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6105 6125 b'resolve.unresolved',
6106 6126 b'P',
6107 6127 ),
6108 6128 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6109 6129 b'resolve.resolved',
6110 6130 b'R',
6111 6131 ),
6112 6132 }
6113 6133
6114 6134 for f in ms:
6115 6135 if not m(f):
6116 6136 continue
6117 6137
6118 6138 label, key = mergestateinfo[ms[f]]
6119 6139 fm.startitem()
6120 6140 fm.context(ctx=wctx)
6121 6141 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6122 6142 fm.data(path=f)
6123 6143 fm.plain(b'%s\n' % uipathfn(f), label=label)
6124 6144 fm.end()
6125 6145 return 0
6126 6146
6127 6147 with repo.wlock():
6128 6148 ms = mergestatemod.mergestate.read(repo)
6129 6149
6130 6150 if not (ms.active() or repo.dirstate.p2() != repo.nullid):
6131 6151 raise error.StateError(
6132 6152 _(b'resolve command not applicable when not merging')
6133 6153 )
6134 6154
6135 6155 wctx = repo[None]
6136 6156 m = scmutil.match(wctx, pats, opts)
6137 6157 ret = 0
6138 6158 didwork = False
6139 6159
6140 6160 hasconflictmarkers = []
6141 6161 if mark:
6142 6162 markcheck = ui.config(b'commands', b'resolve.mark-check')
6143 6163 if markcheck not in [b'warn', b'abort']:
6144 6164 # Treat all invalid / unrecognized values as 'none'.
6145 6165 markcheck = False
6146 6166 for f in ms:
6147 6167 if not m(f):
6148 6168 continue
6149 6169
6150 6170 didwork = True
6151 6171
6152 6172 # path conflicts must be resolved manually
6153 6173 if ms[f] in (
6154 6174 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6155 6175 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6156 6176 ):
6157 6177 if mark:
6158 6178 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6159 6179 elif unmark:
6160 6180 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6161 6181 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6162 6182 ui.warn(
6163 6183 _(b'%s: path conflict must be resolved manually\n')
6164 6184 % uipathfn(f)
6165 6185 )
6166 6186 continue
6167 6187
6168 6188 if mark:
6169 6189 if markcheck:
6170 6190 fdata = repo.wvfs.tryread(f)
6171 6191 if (
6172 6192 filemerge.hasconflictmarkers(fdata)
6173 6193 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6174 6194 ):
6175 6195 hasconflictmarkers.append(f)
6176 6196 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6177 6197 elif unmark:
6178 6198 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6179 6199 else:
6180 6200 # backup pre-resolve (merge uses .orig for its own purposes)
6181 6201 a = repo.wjoin(f)
6182 6202 try:
6183 6203 util.copyfile(a, a + b".resolve")
6184 6204 except FileNotFoundError:
6185 6205 pass
6186 6206
6187 6207 try:
6188 6208 # preresolve file
6189 6209 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6190 6210 with ui.configoverride(overrides, b'resolve'):
6191 6211 r = ms.resolve(f, wctx)
6192 6212 if r:
6193 6213 ret = 1
6194 6214 finally:
6195 6215 ms.commit()
6196 6216
6197 6217 # replace filemerge's .orig file with our resolve file
6198 6218 try:
6199 6219 util.rename(
6200 6220 a + b".resolve", scmutil.backuppath(ui, repo, f)
6201 6221 )
6202 6222 except FileNotFoundError:
6203 6223 pass
6204 6224
6205 6225 if hasconflictmarkers:
6206 6226 ui.warn(
6207 6227 _(
6208 6228 b'warning: the following files still have conflict '
6209 6229 b'markers:\n'
6210 6230 )
6211 6231 + b''.join(
6212 6232 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6213 6233 )
6214 6234 )
6215 6235 if markcheck == b'abort' and not all and not pats:
6216 6236 raise error.StateError(
6217 6237 _(b'conflict markers detected'),
6218 6238 hint=_(b'use --all to mark anyway'),
6219 6239 )
6220 6240
6221 6241 ms.commit()
6222 6242 branchmerge = repo.dirstate.p2() != repo.nullid
6223 6243 # resolve is not doing a parent change here, however, `record updates`
6224 6244 # will call some dirstate API that at intended for parent changes call.
6225 6245 # Ideally we would not need this and could implement a lighter version
6226 6246 # of the recordupdateslogic that will not have to deal with the part
6227 6247 # related to parent changes. However this would requires that:
6228 6248 # - we are sure we passed around enough information at update/merge
6229 6249 # time to no longer needs it at `hg resolve time`
6230 6250 # - we are sure we store that information well enough to be able to reuse it
6231 6251 # - we are the necessary logic to reuse it right.
6232 6252 #
6233 6253 # All this should eventually happens, but in the mean time, we use this
6234 6254 # context manager slightly out of the context it should be.
6235 6255 with repo.dirstate.parentchange():
6236 6256 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6237 6257
6238 6258 if not didwork and pats:
6239 6259 hint = None
6240 6260 if not any([p for p in pats if p.find(b':') >= 0]):
6241 6261 pats = [b'path:%s' % p for p in pats]
6242 6262 m = scmutil.match(wctx, pats, opts)
6243 6263 for f in ms:
6244 6264 if not m(f):
6245 6265 continue
6246 6266
6247 6267 def flag(o):
6248 6268 if o == b're_merge':
6249 6269 return b'--re-merge '
6250 6270 return b'-%s ' % o[0:1]
6251 6271
6252 6272 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6253 6273 hint = _(b"(try: hg resolve %s%s)\n") % (
6254 6274 flags,
6255 6275 b' '.join(pats),
6256 6276 )
6257 6277 break
6258 6278 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6259 6279 if hint:
6260 6280 ui.warn(hint)
6261 6281
6262 6282 unresolvedf = ms.unresolvedcount()
6263 6283 if not unresolvedf:
6264 6284 ui.status(_(b'(no more unresolved files)\n'))
6265 6285 cmdutil.checkafterresolved(repo)
6266 6286
6267 6287 return ret
6268 6288
6269 6289
6270 6290 @command(
6271 6291 b'revert',
6272 6292 [
6273 6293 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6274 6294 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6275 6295 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6276 6296 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6277 6297 (b'i', b'interactive', None, _(b'interactively select the changes')),
6278 6298 ]
6279 6299 + walkopts
6280 6300 + dryrunopts,
6281 6301 _(b'[OPTION]... [-r REV] [NAME]...'),
6282 6302 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6283 6303 )
6284 6304 def revert(ui, repo, *pats, **opts):
6285 6305 """restore files to their checkout state
6286 6306
6287 6307 .. note::
6288 6308
6289 6309 To check out earlier revisions, you should use :hg:`update REV`.
6290 6310 To cancel an uncommitted merge (and lose your changes),
6291 6311 use :hg:`merge --abort`.
6292 6312
6293 6313 With no revision specified, revert the specified files or directories
6294 6314 to the contents they had in the parent of the working directory.
6295 6315 This restores the contents of files to an unmodified
6296 6316 state and unschedules adds, removes, copies, and renames. If the
6297 6317 working directory has two parents, you must explicitly specify a
6298 6318 revision.
6299 6319
6300 6320 Using the -r/--rev or -d/--date options, revert the given files or
6301 6321 directories to their states as of a specific revision. Because
6302 6322 revert does not change the working directory parents, this will
6303 6323 cause these files to appear modified. This can be helpful to "back
6304 6324 out" some or all of an earlier change. See :hg:`backout` for a
6305 6325 related method.
6306 6326
6307 6327 Modified files are saved with a .orig suffix before reverting.
6308 6328 To disable these backups, use --no-backup. It is possible to store
6309 6329 the backup files in a custom directory relative to the root of the
6310 6330 repository by setting the ``ui.origbackuppath`` configuration
6311 6331 option.
6312 6332
6313 6333 See :hg:`help dates` for a list of formats valid for -d/--date.
6314 6334
6315 6335 See :hg:`help backout` for a way to reverse the effect of an
6316 6336 earlier changeset.
6317 6337
6318 6338 Returns 0 on success.
6319 6339 """
6320 6340
6321 6341 opts = pycompat.byteskwargs(opts)
6322 6342 if opts.get(b"date"):
6323 6343 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6324 6344 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6325 6345
6326 6346 parent, p2 = repo.dirstate.parents()
6327 6347 if not opts.get(b'rev') and p2 != repo.nullid:
6328 6348 # revert after merge is a trap for new users (issue2915)
6329 6349 raise error.InputError(
6330 6350 _(b'uncommitted merge with no revision specified'),
6331 6351 hint=_(b"use 'hg update' or see 'hg help revert'"),
6332 6352 )
6333 6353
6334 6354 rev = opts.get(b'rev')
6335 6355 if rev:
6336 6356 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6337 6357 ctx = logcmdutil.revsingle(repo, rev)
6338 6358
6339 6359 if not (
6340 6360 pats
6341 6361 or opts.get(b'include')
6342 6362 or opts.get(b'exclude')
6343 6363 or opts.get(b'all')
6344 6364 or opts.get(b'interactive')
6345 6365 ):
6346 6366 msg = _(b"no files or directories specified")
6347 6367 if p2 != repo.nullid:
6348 6368 hint = _(
6349 6369 b"uncommitted merge, use --all to discard all changes,"
6350 6370 b" or 'hg update -C .' to abort the merge"
6351 6371 )
6352 6372 raise error.InputError(msg, hint=hint)
6353 6373 dirty = any(repo.status())
6354 6374 node = ctx.node()
6355 6375 if node != parent:
6356 6376 if dirty:
6357 6377 hint = (
6358 6378 _(
6359 6379 b"uncommitted changes, use --all to discard all"
6360 6380 b" changes, or 'hg update %d' to update"
6361 6381 )
6362 6382 % ctx.rev()
6363 6383 )
6364 6384 else:
6365 6385 hint = (
6366 6386 _(
6367 6387 b"use --all to revert all files,"
6368 6388 b" or 'hg update %d' to update"
6369 6389 )
6370 6390 % ctx.rev()
6371 6391 )
6372 6392 elif dirty:
6373 6393 hint = _(b"uncommitted changes, use --all to discard all changes")
6374 6394 else:
6375 6395 hint = _(b"use --all to revert all files")
6376 6396 raise error.InputError(msg, hint=hint)
6377 6397
6378 6398 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6379 6399
6380 6400
6381 6401 @command(
6382 6402 b'rollback',
6383 6403 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6384 6404 helpcategory=command.CATEGORY_MAINTENANCE,
6385 6405 )
6386 6406 def rollback(ui, repo, **opts):
6387 6407 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6388 6408
6389 6409 Please use :hg:`commit --amend` instead of rollback to correct
6390 6410 mistakes in the last commit.
6391 6411
6392 6412 This command should be used with care. There is only one level of
6393 6413 rollback, and there is no way to undo a rollback. It will also
6394 6414 restore the dirstate at the time of the last transaction, losing
6395 6415 any dirstate changes since that time. This command does not alter
6396 6416 the working directory.
6397 6417
6398 6418 Transactions are used to encapsulate the effects of all commands
6399 6419 that create new changesets or propagate existing changesets into a
6400 6420 repository.
6401 6421
6402 6422 .. container:: verbose
6403 6423
6404 6424 For example, the following commands are transactional, and their
6405 6425 effects can be rolled back:
6406 6426
6407 6427 - commit
6408 6428 - import
6409 6429 - pull
6410 6430 - push (with this repository as the destination)
6411 6431 - unbundle
6412 6432
6413 6433 To avoid permanent data loss, rollback will refuse to rollback a
6414 6434 commit transaction if it isn't checked out. Use --force to
6415 6435 override this protection.
6416 6436
6417 6437 The rollback command can be entirely disabled by setting the
6418 6438 ``ui.rollback`` configuration setting to false. If you're here
6419 6439 because you want to use rollback and it's disabled, you can
6420 6440 re-enable the command by setting ``ui.rollback`` to true.
6421 6441
6422 6442 This command is not intended for use on public repositories. Once
6423 6443 changes are visible for pull by other users, rolling a transaction
6424 6444 back locally is ineffective (someone else may already have pulled
6425 6445 the changes). Furthermore, a race is possible with readers of the
6426 6446 repository; for example an in-progress pull from the repository
6427 6447 may fail if a rollback is performed.
6428 6448
6429 6449 Returns 0 on success, 1 if no rollback data is available.
6430 6450 """
6431 6451 if not ui.configbool(b'ui', b'rollback'):
6432 6452 raise error.Abort(
6433 6453 _(b'rollback is disabled because it is unsafe'),
6434 6454 hint=b'see `hg help -v rollback` for information',
6435 6455 )
6436 6456 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6437 6457
6438 6458
6439 6459 @command(
6440 6460 b'root',
6441 6461 [] + formatteropts,
6442 6462 intents={INTENT_READONLY},
6443 6463 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6444 6464 )
6445 6465 def root(ui, repo, **opts):
6446 6466 """print the root (top) of the current working directory
6447 6467
6448 6468 Print the root directory of the current repository.
6449 6469
6450 6470 .. container:: verbose
6451 6471
6452 6472 Template:
6453 6473
6454 6474 The following keywords are supported in addition to the common template
6455 6475 keywords and functions. See also :hg:`help templates`.
6456 6476
6457 6477 :hgpath: String. Path to the .hg directory.
6458 6478 :storepath: String. Path to the directory holding versioned data.
6459 6479
6460 6480 Returns 0 on success.
6461 6481 """
6462 6482 opts = pycompat.byteskwargs(opts)
6463 6483 with ui.formatter(b'root', opts) as fm:
6464 6484 fm.startitem()
6465 6485 fm.write(b'reporoot', b'%s\n', repo.root)
6466 6486 fm.data(hgpath=repo.path, storepath=repo.spath)
6467 6487
6468 6488
6469 6489 @command(
6470 6490 b'serve',
6471 6491 [
6472 6492 (
6473 6493 b'A',
6474 6494 b'accesslog',
6475 6495 b'',
6476 6496 _(b'name of access log file to write to'),
6477 6497 _(b'FILE'),
6478 6498 ),
6479 6499 (b'd', b'daemon', None, _(b'run server in background')),
6480 6500 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6481 6501 (
6482 6502 b'E',
6483 6503 b'errorlog',
6484 6504 b'',
6485 6505 _(b'name of error log file to write to'),
6486 6506 _(b'FILE'),
6487 6507 ),
6488 6508 # use string type, then we can check if something was passed
6489 6509 (
6490 6510 b'p',
6491 6511 b'port',
6492 6512 b'',
6493 6513 _(b'port to listen on (default: 8000)'),
6494 6514 _(b'PORT'),
6495 6515 ),
6496 6516 (
6497 6517 b'a',
6498 6518 b'address',
6499 6519 b'',
6500 6520 _(b'address to listen on (default: all interfaces)'),
6501 6521 _(b'ADDR'),
6502 6522 ),
6503 6523 (
6504 6524 b'',
6505 6525 b'prefix',
6506 6526 b'',
6507 6527 _(b'prefix path to serve from (default: server root)'),
6508 6528 _(b'PREFIX'),
6509 6529 ),
6510 6530 (
6511 6531 b'n',
6512 6532 b'name',
6513 6533 b'',
6514 6534 _(b'name to show in web pages (default: working directory)'),
6515 6535 _(b'NAME'),
6516 6536 ),
6517 6537 (
6518 6538 b'',
6519 6539 b'web-conf',
6520 6540 b'',
6521 6541 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6522 6542 _(b'FILE'),
6523 6543 ),
6524 6544 (
6525 6545 b'',
6526 6546 b'webdir-conf',
6527 6547 b'',
6528 6548 _(b'name of the hgweb config file (DEPRECATED)'),
6529 6549 _(b'FILE'),
6530 6550 ),
6531 6551 (
6532 6552 b'',
6533 6553 b'pid-file',
6534 6554 b'',
6535 6555 _(b'name of file to write process ID to'),
6536 6556 _(b'FILE'),
6537 6557 ),
6538 6558 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6539 6559 (
6540 6560 b'',
6541 6561 b'cmdserver',
6542 6562 b'',
6543 6563 _(b'for remote clients (ADVANCED)'),
6544 6564 _(b'MODE'),
6545 6565 ),
6546 6566 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6547 6567 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6548 6568 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6549 6569 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6550 6570 (b'', b'print-url', None, _(b'start and print only the URL')),
6551 6571 ]
6552 6572 + subrepoopts,
6553 6573 _(b'[OPTION]...'),
6554 6574 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6555 6575 helpbasic=True,
6556 6576 optionalrepo=True,
6557 6577 )
6558 6578 def serve(ui, repo, **opts):
6559 6579 """start stand-alone webserver
6560 6580
6561 6581 Start a local HTTP repository browser and pull server. You can use
6562 6582 this for ad-hoc sharing and browsing of repositories. It is
6563 6583 recommended to use a real web server to serve a repository for
6564 6584 longer periods of time.
6565 6585
6566 6586 Please note that the server does not implement access control.
6567 6587 This means that, by default, anybody can read from the server and
6568 6588 nobody can write to it by default. Set the ``web.allow-push``
6569 6589 option to ``*`` to allow everybody to push to the server. You
6570 6590 should use a real web server if you need to authenticate users.
6571 6591
6572 6592 By default, the server logs accesses to stdout and errors to
6573 6593 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6574 6594 files.
6575 6595
6576 6596 To have the server choose a free port number to listen on, specify
6577 6597 a port number of 0; in this case, the server will print the port
6578 6598 number it uses.
6579 6599
6580 6600 Returns 0 on success.
6581 6601 """
6582 6602
6583 6603 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6584 6604 opts = pycompat.byteskwargs(opts)
6585 6605 if opts[b"print_url"] and ui.verbose:
6586 6606 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6587 6607
6588 6608 if opts[b"stdio"]:
6589 6609 if repo is None:
6590 6610 raise error.RepoError(
6591 6611 _(b"there is no Mercurial repository here (.hg not found)")
6592 6612 )
6593 6613 s = wireprotoserver.sshserver(ui, repo)
6594 6614 s.serve_forever()
6595 6615 return
6596 6616
6597 6617 service = server.createservice(ui, repo, opts)
6598 6618 return server.runservice(opts, initfn=service.init, runfn=service.run)
6599 6619
6600 6620
6601 6621 @command(
6602 6622 b'shelve',
6603 6623 [
6604 6624 (
6605 6625 b'A',
6606 6626 b'addremove',
6607 6627 None,
6608 6628 _(b'mark new/missing files as added/removed before shelving'),
6609 6629 ),
6610 6630 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6611 6631 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6612 6632 (
6613 6633 b'',
6614 6634 b'date',
6615 6635 b'',
6616 6636 _(b'shelve with the specified commit date'),
6617 6637 _(b'DATE'),
6618 6638 ),
6619 6639 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6620 6640 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6621 6641 (
6622 6642 b'k',
6623 6643 b'keep',
6624 6644 False,
6625 6645 _(b'shelve, but keep changes in the working directory'),
6626 6646 ),
6627 6647 (b'l', b'list', None, _(b'list current shelves')),
6628 6648 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6629 6649 (
6630 6650 b'n',
6631 6651 b'name',
6632 6652 b'',
6633 6653 _(b'use the given name for the shelved commit'),
6634 6654 _(b'NAME'),
6635 6655 ),
6636 6656 (
6637 6657 b'p',
6638 6658 b'patch',
6639 6659 None,
6640 6660 _(
6641 6661 b'output patches for changes (provide the names of the shelved '
6642 6662 b'changes as positional arguments)'
6643 6663 ),
6644 6664 ),
6645 6665 (b'i', b'interactive', None, _(b'interactive mode')),
6646 6666 (
6647 6667 b'',
6648 6668 b'stat',
6649 6669 None,
6650 6670 _(
6651 6671 b'output diffstat-style summary of changes (provide the names of '
6652 6672 b'the shelved changes as positional arguments)'
6653 6673 ),
6654 6674 ),
6655 6675 ]
6656 6676 + cmdutil.walkopts,
6657 6677 _(b'hg shelve [OPTION]... [FILE]...'),
6658 6678 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6659 6679 )
6660 6680 def shelve(ui, repo, *pats, **opts):
6661 6681 """save and set aside changes from the working directory
6662 6682
6663 6683 Shelving takes files that "hg status" reports as not clean, saves
6664 6684 the modifications to a bundle (a shelved change), and reverts the
6665 6685 files so that their state in the working directory becomes clean.
6666 6686
6667 6687 To restore these changes to the working directory, using "hg
6668 6688 unshelve"; this will work even if you switch to a different
6669 6689 commit.
6670 6690
6671 6691 When no files are specified, "hg shelve" saves all not-clean
6672 6692 files. If specific files or directories are named, only changes to
6673 6693 those files are shelved.
6674 6694
6675 6695 In bare shelve (when no files are specified, without interactive,
6676 6696 include and exclude option), shelving remembers information if the
6677 6697 working directory was on newly created branch, in other words working
6678 6698 directory was on different branch than its first parent. In this
6679 6699 situation unshelving restores branch information to the working directory.
6680 6700
6681 6701 Each shelved change has a name that makes it easier to find later.
6682 6702 The name of a shelved change defaults to being based on the active
6683 6703 bookmark, or if there is no active bookmark, the current named
6684 6704 branch. To specify a different name, use ``--name``.
6685 6705
6686 6706 To see a list of existing shelved changes, use the ``--list``
6687 6707 option. For each shelved change, this will print its name, age,
6688 6708 and description; use ``--patch`` or ``--stat`` for more details.
6689 6709
6690 6710 To delete specific shelved changes, use ``--delete``. To delete
6691 6711 all shelved changes, use ``--cleanup``.
6692 6712 """
6693 6713 opts = pycompat.byteskwargs(opts)
6694 6714 allowables = [
6695 6715 (b'addremove', {b'create'}), # 'create' is pseudo action
6696 6716 (b'unknown', {b'create'}),
6697 6717 (b'cleanup', {b'cleanup'}),
6698 6718 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6699 6719 (b'delete', {b'delete'}),
6700 6720 (b'edit', {b'create'}),
6701 6721 (b'keep', {b'create'}),
6702 6722 (b'list', {b'list'}),
6703 6723 (b'message', {b'create'}),
6704 6724 (b'name', {b'create'}),
6705 6725 (b'patch', {b'patch', b'list'}),
6706 6726 (b'stat', {b'stat', b'list'}),
6707 6727 ]
6708 6728
6709 6729 def checkopt(opt):
6710 6730 if opts.get(opt):
6711 6731 for i, allowable in allowables:
6712 6732 if opts[i] and opt not in allowable:
6713 6733 raise error.InputError(
6714 6734 _(
6715 6735 b"options '--%s' and '--%s' may not be "
6716 6736 b"used together"
6717 6737 )
6718 6738 % (opt, i)
6719 6739 )
6720 6740 return True
6721 6741
6722 6742 if checkopt(b'cleanup'):
6723 6743 if pats:
6724 6744 raise error.InputError(
6725 6745 _(b"cannot specify names when using '--cleanup'")
6726 6746 )
6727 6747 return shelvemod.cleanupcmd(ui, repo)
6728 6748 elif checkopt(b'delete'):
6729 6749 return shelvemod.deletecmd(ui, repo, pats)
6730 6750 elif checkopt(b'list'):
6731 6751 return shelvemod.listcmd(ui, repo, pats, opts)
6732 6752 elif checkopt(b'patch') or checkopt(b'stat'):
6733 6753 return shelvemod.patchcmds(ui, repo, pats, opts)
6734 6754 else:
6735 6755 return shelvemod.createcmd(ui, repo, pats, opts)
6736 6756
6737 6757
6738 6758 _NOTTERSE = b'nothing'
6739 6759
6740 6760
6741 6761 @command(
6742 6762 b'status|st',
6743 6763 [
6744 6764 (b'A', b'all', None, _(b'show status of all files')),
6745 6765 (b'm', b'modified', None, _(b'show only modified files')),
6746 6766 (b'a', b'added', None, _(b'show only added files')),
6747 6767 (b'r', b'removed', None, _(b'show only removed files')),
6748 6768 (b'd', b'deleted', None, _(b'show only missing files')),
6749 6769 (b'c', b'clean', None, _(b'show only files without changes')),
6750 6770 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6751 6771 (b'i', b'ignored', None, _(b'show only ignored files')),
6752 6772 (b'n', b'no-status', None, _(b'hide status prefix')),
6753 6773 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6754 6774 (
6755 6775 b'C',
6756 6776 b'copies',
6757 6777 None,
6758 6778 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6759 6779 ),
6760 6780 (
6761 6781 b'0',
6762 6782 b'print0',
6763 6783 None,
6764 6784 _(b'end filenames with NUL, for use with xargs'),
6765 6785 ),
6766 6786 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6767 6787 (
6768 6788 b'',
6769 6789 b'change',
6770 6790 b'',
6771 6791 _(b'list the changed files of a revision'),
6772 6792 _(b'REV'),
6773 6793 ),
6774 6794 ]
6775 6795 + walkopts
6776 6796 + subrepoopts
6777 6797 + formatteropts,
6778 6798 _(b'[OPTION]... [FILE]...'),
6779 6799 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6780 6800 helpbasic=True,
6781 6801 inferrepo=True,
6782 6802 intents={INTENT_READONLY},
6783 6803 )
6784 6804 def status(ui, repo, *pats, **opts):
6785 6805 """show changed files in the working directory
6786 6806
6787 6807 Show status of files in the repository. If names are given, only
6788 6808 files that match are shown. Files that are clean or ignored or
6789 6809 the source of a copy/move operation, are not listed unless
6790 6810 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6791 6811 Unless options described with "show only ..." are given, the
6792 6812 options -mardu are used.
6793 6813
6794 6814 Option -q/--quiet hides untracked (unknown and ignored) files
6795 6815 unless explicitly requested with -u/--unknown or -i/--ignored.
6796 6816
6797 6817 .. note::
6798 6818
6799 6819 :hg:`status` may appear to disagree with diff if permissions have
6800 6820 changed or a merge has occurred. The standard diff format does
6801 6821 not report permission changes and diff only reports changes
6802 6822 relative to one merge parent.
6803 6823
6804 6824 If one revision is given, it is used as the base revision.
6805 6825 If two revisions are given, the differences between them are
6806 6826 shown. The --change option can also be used as a shortcut to list
6807 6827 the changed files of a revision from its first parent.
6808 6828
6809 6829 The codes used to show the status of files are::
6810 6830
6811 6831 M = modified
6812 6832 A = added
6813 6833 R = removed
6814 6834 C = clean
6815 6835 ! = missing (deleted by non-hg command, but still tracked)
6816 6836 ? = not tracked
6817 6837 I = ignored
6818 6838 = origin of the previous file (with --copies)
6819 6839
6820 6840 .. container:: verbose
6821 6841
6822 6842 The -t/--terse option abbreviates the output by showing only the directory
6823 6843 name if all the files in it share the same status. The option takes an
6824 6844 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6825 6845 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6826 6846 for 'ignored' and 'c' for clean.
6827 6847
6828 6848 It abbreviates only those statuses which are passed. Note that clean and
6829 6849 ignored files are not displayed with '--terse ic' unless the -c/--clean
6830 6850 and -i/--ignored options are also used.
6831 6851
6832 6852 The -v/--verbose option shows information when the repository is in an
6833 6853 unfinished merge, shelve, rebase state etc. You can have this behavior
6834 6854 turned on by default by enabling the ``commands.status.verbose`` option.
6835 6855
6836 6856 You can skip displaying some of these states by setting
6837 6857 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6838 6858 'histedit', 'merge', 'rebase', or 'unshelve'.
6839 6859
6840 6860 Template:
6841 6861
6842 6862 The following keywords are supported in addition to the common template
6843 6863 keywords and functions. See also :hg:`help templates`.
6844 6864
6845 6865 :path: String. Repository-absolute path of the file.
6846 6866 :source: String. Repository-absolute path of the file originated from.
6847 6867 Available if ``--copies`` is specified.
6848 6868 :status: String. Character denoting file's status.
6849 6869
6850 6870 Examples:
6851 6871
6852 6872 - show changes in the working directory relative to a
6853 6873 changeset::
6854 6874
6855 6875 hg status --rev 9353
6856 6876
6857 6877 - show changes in the working directory relative to the
6858 6878 current directory (see :hg:`help patterns` for more information)::
6859 6879
6860 6880 hg status re:
6861 6881
6862 6882 - show all changes including copies in an existing changeset::
6863 6883
6864 6884 hg status --copies --change 9353
6865 6885
6866 6886 - get a NUL separated list of added files, suitable for xargs::
6867 6887
6868 6888 hg status -an0
6869 6889
6870 6890 - show more information about the repository status, abbreviating
6871 6891 added, removed, modified, deleted, and untracked paths::
6872 6892
6873 6893 hg status -v -t mardu
6874 6894
6875 6895 Returns 0 on success.
6876 6896
6877 6897 """
6878 6898
6879 6899 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6880 6900 opts = pycompat.byteskwargs(opts)
6881 6901 revs = opts.get(b'rev', [])
6882 6902 change = opts.get(b'change', b'')
6883 6903 terse = opts.get(b'terse', _NOTTERSE)
6884 6904 if terse is _NOTTERSE:
6885 6905 if revs:
6886 6906 terse = b''
6887 6907 else:
6888 6908 terse = ui.config(b'commands', b'status.terse')
6889 6909
6890 6910 if revs and terse:
6891 6911 msg = _(b'cannot use --terse with --rev')
6892 6912 raise error.InputError(msg)
6893 6913 elif change:
6894 6914 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6895 6915 ctx2 = logcmdutil.revsingle(repo, change, None)
6896 6916 ctx1 = ctx2.p1()
6897 6917 else:
6898 6918 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6899 6919 ctx1, ctx2 = logcmdutil.revpair(repo, revs)
6900 6920
6901 6921 forcerelativevalue = None
6902 6922 if ui.hasconfig(b'commands', b'status.relative'):
6903 6923 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6904 6924 uipathfn = scmutil.getuipathfn(
6905 6925 repo,
6906 6926 legacyrelativevalue=bool(pats),
6907 6927 forcerelativevalue=forcerelativevalue,
6908 6928 )
6909 6929
6910 6930 if opts.get(b'print0'):
6911 6931 end = b'\0'
6912 6932 else:
6913 6933 end = b'\n'
6914 6934 states = b'modified added removed deleted unknown ignored clean'.split()
6915 6935 show = [k for k in states if opts.get(k)]
6916 6936 if opts.get(b'all'):
6917 6937 show += ui.quiet and (states[:4] + [b'clean']) or states
6918 6938
6919 6939 if not show:
6920 6940 if ui.quiet:
6921 6941 show = states[:4]
6922 6942 else:
6923 6943 show = states[:5]
6924 6944
6925 6945 m = scmutil.match(ctx2, pats, opts)
6926 6946 if terse:
6927 6947 # we need to compute clean and unknown to terse
6928 6948 stat = repo.status(
6929 6949 ctx1.node(),
6930 6950 ctx2.node(),
6931 6951 m,
6932 6952 b'ignored' in show or b'i' in terse,
6933 6953 clean=True,
6934 6954 unknown=True,
6935 6955 listsubrepos=opts.get(b'subrepos'),
6936 6956 )
6937 6957
6938 6958 stat = cmdutil.tersedir(stat, terse)
6939 6959 else:
6940 6960 stat = repo.status(
6941 6961 ctx1.node(),
6942 6962 ctx2.node(),
6943 6963 m,
6944 6964 b'ignored' in show,
6945 6965 b'clean' in show,
6946 6966 b'unknown' in show,
6947 6967 opts.get(b'subrepos'),
6948 6968 )
6949 6969
6950 6970 changestates = zip(
6951 6971 states,
6952 6972 pycompat.iterbytestr(b'MAR!?IC'),
6953 6973 [getattr(stat, s.decode('utf8')) for s in states],
6954 6974 )
6955 6975
6956 6976 copy = {}
6957 6977 if (
6958 6978 opts.get(b'all')
6959 6979 or opts.get(b'copies')
6960 6980 or ui.configbool(b'ui', b'statuscopies')
6961 6981 ) and not opts.get(b'no_status'):
6962 6982 copy = copies.pathcopies(ctx1, ctx2, m)
6963 6983
6964 6984 morestatus = None
6965 6985 if (
6966 6986 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6967 6987 and not ui.plain()
6968 6988 and not opts.get(b'print0')
6969 6989 ):
6970 6990 morestatus = cmdutil.readmorestatus(repo)
6971 6991
6972 6992 ui.pager(b'status')
6973 6993 fm = ui.formatter(b'status', opts)
6974 6994 fmt = b'%s' + end
6975 6995 showchar = not opts.get(b'no_status')
6976 6996
6977 6997 for state, char, files in changestates:
6978 6998 if state in show:
6979 6999 label = b'status.' + state
6980 7000 for f in files:
6981 7001 fm.startitem()
6982 7002 fm.context(ctx=ctx2)
6983 7003 fm.data(itemtype=b'file', path=f)
6984 7004 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6985 7005 fm.plain(fmt % uipathfn(f), label=label)
6986 7006 if f in copy:
6987 7007 fm.data(source=copy[f])
6988 7008 fm.plain(
6989 7009 (b' %s' + end) % uipathfn(copy[f]),
6990 7010 label=b'status.copied',
6991 7011 )
6992 7012 if morestatus:
6993 7013 morestatus.formatfile(f, fm)
6994 7014
6995 7015 if morestatus:
6996 7016 morestatus.formatfooter(fm)
6997 7017 fm.end()
6998 7018
6999 7019
7000 7020 @command(
7001 7021 b'summary|sum',
7002 7022 [(b'', b'remote', None, _(b'check for push and pull'))],
7003 7023 b'[--remote]',
7004 7024 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7005 7025 helpbasic=True,
7006 7026 intents={INTENT_READONLY},
7007 7027 )
7008 7028 def summary(ui, repo, **opts):
7009 7029 """summarize working directory state
7010 7030
7011 7031 This generates a brief summary of the working directory state,
7012 7032 including parents, branch, commit status, phase and available updates.
7013 7033
7014 7034 With the --remote option, this will check the default paths for
7015 7035 incoming and outgoing changes. This can be time-consuming.
7016 7036
7017 7037 Returns 0 on success.
7018 7038 """
7019 7039
7020 7040 opts = pycompat.byteskwargs(opts)
7021 7041 ui.pager(b'summary')
7022 7042 ctx = repo[None]
7023 7043 parents = ctx.parents()
7024 7044 pnode = parents[0].node()
7025 7045 marks = []
7026 7046
7027 7047 try:
7028 7048 ms = mergestatemod.mergestate.read(repo)
7029 7049 except error.UnsupportedMergeRecords as e:
7030 7050 s = b' '.join(e.recordtypes)
7031 7051 ui.warn(
7032 7052 _(b'warning: merge state has unsupported record types: %s\n') % s
7033 7053 )
7034 7054 unresolved = []
7035 7055 else:
7036 7056 unresolved = list(ms.unresolved())
7037 7057
7038 7058 for p in parents:
7039 7059 # label with log.changeset (instead of log.parent) since this
7040 7060 # shows a working directory parent *changeset*:
7041 7061 # i18n: column positioning for "hg summary"
7042 7062 ui.write(
7043 7063 _(b'parent: %d:%s ') % (p.rev(), p),
7044 7064 label=logcmdutil.changesetlabels(p),
7045 7065 )
7046 7066 ui.write(b' '.join(p.tags()), label=b'log.tag')
7047 7067 if p.bookmarks():
7048 7068 marks.extend(p.bookmarks())
7049 7069 if p.rev() == -1:
7050 7070 if not len(repo):
7051 7071 ui.write(_(b' (empty repository)'))
7052 7072 else:
7053 7073 ui.write(_(b' (no revision checked out)'))
7054 7074 if p.obsolete():
7055 7075 ui.write(_(b' (obsolete)'))
7056 7076 if p.isunstable():
7057 7077 instabilities = (
7058 7078 ui.label(instability, b'trouble.%s' % instability)
7059 7079 for instability in p.instabilities()
7060 7080 )
7061 7081 ui.write(b' (' + b', '.join(instabilities) + b')')
7062 7082 ui.write(b'\n')
7063 7083 if p.description():
7064 7084 ui.status(
7065 7085 b' ' + p.description().splitlines()[0].strip() + b'\n',
7066 7086 label=b'log.summary',
7067 7087 )
7068 7088
7069 7089 branch = ctx.branch()
7070 7090 bheads = repo.branchheads(branch)
7071 7091 # i18n: column positioning for "hg summary"
7072 7092 m = _(b'branch: %s\n') % branch
7073 7093 if branch != b'default':
7074 7094 ui.write(m, label=b'log.branch')
7075 7095 else:
7076 7096 ui.status(m, label=b'log.branch')
7077 7097
7078 7098 if marks:
7079 7099 active = repo._activebookmark
7080 7100 # i18n: column positioning for "hg summary"
7081 7101 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7082 7102 if active is not None:
7083 7103 if active in marks:
7084 7104 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7085 7105 marks.remove(active)
7086 7106 else:
7087 7107 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7088 7108 for m in marks:
7089 7109 ui.write(b' ' + m, label=b'log.bookmark')
7090 7110 ui.write(b'\n', label=b'log.bookmark')
7091 7111
7092 7112 status = repo.status(unknown=True)
7093 7113
7094 7114 c = repo.dirstate.copies()
7095 7115 copied, renamed = [], []
7096 7116 for d, s in c.items():
7097 7117 if s in status.removed:
7098 7118 status.removed.remove(s)
7099 7119 renamed.append(d)
7100 7120 else:
7101 7121 copied.append(d)
7102 7122 if d in status.added:
7103 7123 status.added.remove(d)
7104 7124
7105 7125 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7106 7126
7107 7127 labels = [
7108 7128 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7109 7129 (ui.label(_(b'%d added'), b'status.added'), status.added),
7110 7130 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7111 7131 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7112 7132 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7113 7133 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7114 7134 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7115 7135 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7116 7136 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7117 7137 ]
7118 7138 t = []
7119 7139 for l, s in labels:
7120 7140 if s:
7121 7141 t.append(l % len(s))
7122 7142
7123 7143 t = b', '.join(t)
7124 7144 cleanworkdir = False
7125 7145
7126 7146 if repo.vfs.exists(b'graftstate'):
7127 7147 t += _(b' (graft in progress)')
7128 7148 if repo.vfs.exists(b'updatestate'):
7129 7149 t += _(b' (interrupted update)')
7130 7150 elif len(parents) > 1:
7131 7151 t += _(b' (merge)')
7132 7152 elif branch != parents[0].branch():
7133 7153 t += _(b' (new branch)')
7134 7154 elif parents[0].closesbranch() and pnode in repo.branchheads(
7135 7155 branch, closed=True
7136 7156 ):
7137 7157 t += _(b' (head closed)')
7138 7158 elif not (
7139 7159 status.modified
7140 7160 or status.added
7141 7161 or status.removed
7142 7162 or renamed
7143 7163 or copied
7144 7164 or subs
7145 7165 ):
7146 7166 t += _(b' (clean)')
7147 7167 cleanworkdir = True
7148 7168 elif pnode not in bheads:
7149 7169 t += _(b' (new branch head)')
7150 7170
7151 7171 if parents:
7152 7172 pendingphase = max(p.phase() for p in parents)
7153 7173 else:
7154 7174 pendingphase = phases.public
7155 7175
7156 7176 if pendingphase > phases.newcommitphase(ui):
7157 7177 t += b' (%s)' % phases.phasenames[pendingphase]
7158 7178
7159 7179 if cleanworkdir:
7160 7180 # i18n: column positioning for "hg summary"
7161 7181 ui.status(_(b'commit: %s\n') % t.strip())
7162 7182 else:
7163 7183 # i18n: column positioning for "hg summary"
7164 7184 ui.write(_(b'commit: %s\n') % t.strip())
7165 7185
7166 7186 # all ancestors of branch heads - all ancestors of parent = new csets
7167 7187 new = len(
7168 7188 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7169 7189 )
7170 7190
7171 7191 if new == 0:
7172 7192 # i18n: column positioning for "hg summary"
7173 7193 ui.status(_(b'update: (current)\n'))
7174 7194 elif pnode not in bheads:
7175 7195 # i18n: column positioning for "hg summary"
7176 7196 ui.write(_(b'update: %d new changesets (update)\n') % new)
7177 7197 else:
7178 7198 # i18n: column positioning for "hg summary"
7179 7199 ui.write(
7180 7200 _(b'update: %d new changesets, %d branch heads (merge)\n')
7181 7201 % (new, len(bheads))
7182 7202 )
7183 7203
7184 7204 t = []
7185 7205 draft = len(repo.revs(b'draft()'))
7186 7206 if draft:
7187 7207 t.append(_(b'%d draft') % draft)
7188 7208 secret = len(repo.revs(b'secret()'))
7189 7209 if secret:
7190 7210 t.append(_(b'%d secret') % secret)
7191 7211
7192 7212 if draft or secret:
7193 7213 ui.status(_(b'phases: %s\n') % b', '.join(t))
7194 7214
7195 7215 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7196 7216 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7197 7217 numtrouble = len(repo.revs(trouble + b"()"))
7198 7218 # We write all the possibilities to ease translation
7199 7219 troublemsg = {
7200 7220 b"orphan": _(b"orphan: %d changesets"),
7201 7221 b"contentdivergent": _(b"content-divergent: %d changesets"),
7202 7222 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7203 7223 }
7204 7224 if numtrouble > 0:
7205 7225 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7206 7226
7207 7227 cmdutil.summaryhooks(ui, repo)
7208 7228
7209 7229 if opts.get(b'remote'):
7210 7230 needsincoming, needsoutgoing = True, True
7211 7231 else:
7212 7232 needsincoming, needsoutgoing = False, False
7213 7233 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7214 7234 if i:
7215 7235 needsincoming = True
7216 7236 if o:
7217 7237 needsoutgoing = True
7218 7238 if not needsincoming and not needsoutgoing:
7219 7239 return
7220 7240
7221 7241 def getincoming():
7222 7242 # XXX We should actually skip this if no default is specified, instead
7223 7243 # of passing "default" which will resolve as "./default/" if no default
7224 7244 # path is defined.
7225 7245 source, branches = urlutil.get_unique_pull_path(
7226 7246 b'summary', repo, ui, b'default'
7227 7247 )
7228 7248 sbranch = branches[0]
7229 7249 try:
7230 7250 other = hg.peer(repo, {}, source)
7231 7251 except error.RepoError:
7232 7252 if opts.get(b'remote'):
7233 7253 raise
7234 7254 return source, sbranch, None, None, None
7235 7255 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7236 7256 if revs:
7237 7257 revs = [other.lookup(rev) for rev in revs]
7238 7258 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(source))
7239 7259 with repo.ui.silent():
7240 7260 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7241 7261 return source, sbranch, other, commoninc, commoninc[1]
7242 7262
7243 7263 if needsincoming:
7244 7264 source, sbranch, sother, commoninc, incoming = getincoming()
7245 7265 else:
7246 7266 source = sbranch = sother = commoninc = incoming = None
7247 7267
7248 7268 def getoutgoing():
7249 7269 # XXX We should actually skip this if no default is specified, instead
7250 7270 # of passing "default" which will resolve as "./default/" if no default
7251 7271 # path is defined.
7252 7272 d = None
7253 7273 if b'default-push' in ui.paths:
7254 7274 d = b'default-push'
7255 7275 elif b'default' in ui.paths:
7256 7276 d = b'default'
7257 7277 if d is not None:
7258 7278 path = urlutil.get_unique_push_path(b'summary', repo, ui, d)
7259 7279 dest = path.pushloc or path.loc
7260 7280 dbranch = path.branch
7261 7281 else:
7262 7282 dest = b'default'
7263 7283 dbranch = None
7264 7284 revs, checkout = hg.addbranchrevs(repo, repo, (dbranch, []), None)
7265 7285 if source != dest:
7266 7286 try:
7267 7287 dother = hg.peer(repo, {}, dest)
7268 7288 except error.RepoError:
7269 7289 if opts.get(b'remote'):
7270 7290 raise
7271 7291 return dest, dbranch, None, None
7272 7292 ui.debug(b'comparing with %s\n' % urlutil.hidepassword(dest))
7273 7293 elif sother is None:
7274 7294 # there is no explicit destination peer, but source one is invalid
7275 7295 return dest, dbranch, None, None
7276 7296 else:
7277 7297 dother = sother
7278 7298 if source != dest or (sbranch is not None and sbranch != dbranch):
7279 7299 common = None
7280 7300 else:
7281 7301 common = commoninc
7282 7302 if revs:
7283 7303 revs = [repo.lookup(rev) for rev in revs]
7284 7304 with repo.ui.silent():
7285 7305 outgoing = discovery.findcommonoutgoing(
7286 7306 repo, dother, onlyheads=revs, commoninc=common
7287 7307 )
7288 7308 return dest, dbranch, dother, outgoing
7289 7309
7290 7310 if needsoutgoing:
7291 7311 dest, dbranch, dother, outgoing = getoutgoing()
7292 7312 else:
7293 7313 dest = dbranch = dother = outgoing = None
7294 7314
7295 7315 if opts.get(b'remote'):
7296 7316 # Help pytype. --remote sets both `needsincoming` and `needsoutgoing`.
7297 7317 # The former always sets `sother` (or raises an exception if it can't);
7298 7318 # the latter always sets `outgoing`.
7299 7319 assert sother is not None
7300 7320 assert outgoing is not None
7301 7321
7302 7322 t = []
7303 7323 if incoming:
7304 7324 t.append(_(b'1 or more incoming'))
7305 7325 o = outgoing.missing
7306 7326 if o:
7307 7327 t.append(_(b'%d outgoing') % len(o))
7308 7328 other = dother or sother
7309 7329 if b'bookmarks' in other.listkeys(b'namespaces'):
7310 7330 counts = bookmarks.summary(repo, other)
7311 7331 if counts[0] > 0:
7312 7332 t.append(_(b'%d incoming bookmarks') % counts[0])
7313 7333 if counts[1] > 0:
7314 7334 t.append(_(b'%d outgoing bookmarks') % counts[1])
7315 7335
7316 7336 if t:
7317 7337 # i18n: column positioning for "hg summary"
7318 7338 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7319 7339 else:
7320 7340 # i18n: column positioning for "hg summary"
7321 7341 ui.status(_(b'remote: (synced)\n'))
7322 7342
7323 7343 cmdutil.summaryremotehooks(
7324 7344 ui,
7325 7345 repo,
7326 7346 opts,
7327 7347 (
7328 7348 (source, sbranch, sother, commoninc),
7329 7349 (dest, dbranch, dother, outgoing),
7330 7350 ),
7331 7351 )
7332 7352
7333 7353
7334 7354 @command(
7335 7355 b'tag',
7336 7356 [
7337 7357 (b'f', b'force', None, _(b'force tag')),
7338 7358 (b'l', b'local', None, _(b'make the tag local')),
7339 7359 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7340 7360 (b'', b'remove', None, _(b'remove a tag')),
7341 7361 # -l/--local is already there, commitopts cannot be used
7342 7362 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7343 7363 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7344 7364 ]
7345 7365 + commitopts2,
7346 7366 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7347 7367 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7348 7368 )
7349 7369 def tag(ui, repo, name1, *names, **opts):
7350 7370 """add one or more tags for the current or given revision
7351 7371
7352 7372 Name a particular revision using <name>.
7353 7373
7354 7374 Tags are used to name particular revisions of the repository and are
7355 7375 very useful to compare different revisions, to go back to significant
7356 7376 earlier versions or to mark branch points as releases, etc. Changing
7357 7377 an existing tag is normally disallowed; use -f/--force to override.
7358 7378
7359 7379 If no revision is given, the parent of the working directory is
7360 7380 used.
7361 7381
7362 7382 To facilitate version control, distribution, and merging of tags,
7363 7383 they are stored as a file named ".hgtags" which is managed similarly
7364 7384 to other project files and can be hand-edited if necessary. This
7365 7385 also means that tagging creates a new commit. The file
7366 7386 ".hg/localtags" is used for local tags (not shared among
7367 7387 repositories).
7368 7388
7369 7389 Tag commits are usually made at the head of a branch. If the parent
7370 7390 of the working directory is not a branch head, :hg:`tag` aborts; use
7371 7391 -f/--force to force the tag commit to be based on a non-head
7372 7392 changeset.
7373 7393
7374 7394 See :hg:`help dates` for a list of formats valid for -d/--date.
7375 7395
7376 7396 Since tag names have priority over branch names during revision
7377 7397 lookup, using an existing branch name as a tag name is discouraged.
7378 7398
7379 7399 Returns 0 on success.
7380 7400 """
7381 7401 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7382 7402 opts = pycompat.byteskwargs(opts)
7383 7403 with repo.wlock(), repo.lock():
7384 7404 rev_ = b"."
7385 7405 names = [t.strip() for t in (name1,) + names]
7386 7406 if len(names) != len(set(names)):
7387 7407 raise error.InputError(_(b'tag names must be unique'))
7388 7408 for n in names:
7389 7409 scmutil.checknewlabel(repo, n, b'tag')
7390 7410 if not n:
7391 7411 raise error.InputError(
7392 7412 _(b'tag names cannot consist entirely of whitespace')
7393 7413 )
7394 7414 if opts.get(b'rev'):
7395 7415 rev_ = opts[b'rev']
7396 7416 message = opts.get(b'message')
7397 7417 if opts.get(b'remove'):
7398 7418 if opts.get(b'local'):
7399 7419 expectedtype = b'local'
7400 7420 else:
7401 7421 expectedtype = b'global'
7402 7422
7403 7423 for n in names:
7404 7424 if repo.tagtype(n) == b'global':
7405 7425 alltags = tagsmod.findglobaltags(ui, repo)
7406 7426 if alltags[n][0] == repo.nullid:
7407 7427 raise error.InputError(
7408 7428 _(b"tag '%s' is already removed") % n
7409 7429 )
7410 7430 if not repo.tagtype(n):
7411 7431 raise error.InputError(_(b"tag '%s' does not exist") % n)
7412 7432 if repo.tagtype(n) != expectedtype:
7413 7433 if expectedtype == b'global':
7414 7434 raise error.InputError(
7415 7435 _(b"tag '%s' is not a global tag") % n
7416 7436 )
7417 7437 else:
7418 7438 raise error.InputError(
7419 7439 _(b"tag '%s' is not a local tag") % n
7420 7440 )
7421 7441 rev_ = b'null'
7422 7442 if not message:
7423 7443 # we don't translate commit messages
7424 7444 message = b'Removed tag %s' % b', '.join(names)
7425 7445 elif not opts.get(b'force'):
7426 7446 for n in names:
7427 7447 if n in repo.tags():
7428 7448 raise error.InputError(
7429 7449 _(b"tag '%s' already exists (use -f to force)") % n
7430 7450 )
7431 7451 if not opts.get(b'local'):
7432 7452 p1, p2 = repo.dirstate.parents()
7433 7453 if p2 != repo.nullid:
7434 7454 raise error.StateError(_(b'uncommitted merge'))
7435 7455 bheads = repo.branchheads()
7436 7456 if not opts.get(b'force') and bheads and p1 not in bheads:
7437 7457 raise error.InputError(
7438 7458 _(
7439 7459 b'working directory is not at a branch head '
7440 7460 b'(use -f to force)'
7441 7461 )
7442 7462 )
7443 7463 node = logcmdutil.revsingle(repo, rev_).node()
7444 7464
7445 7465 if not message:
7446 7466 # we don't translate commit messages
7447 7467 message = b'Added tag %s for changeset %s' % (
7448 7468 b', '.join(names),
7449 7469 short(node),
7450 7470 )
7451 7471
7452 7472 date = opts.get(b'date')
7453 7473 if date:
7454 7474 date = dateutil.parsedate(date)
7455 7475
7456 7476 if opts.get(b'remove'):
7457 7477 editform = b'tag.remove'
7458 7478 else:
7459 7479 editform = b'tag.add'
7460 7480 editor = cmdutil.getcommiteditor(
7461 7481 editform=editform, **pycompat.strkwargs(opts)
7462 7482 )
7463 7483
7464 7484 # don't allow tagging the null rev
7465 7485 if (
7466 7486 not opts.get(b'remove')
7467 7487 and logcmdutil.revsingle(repo, rev_).rev() == nullrev
7468 7488 ):
7469 7489 raise error.InputError(_(b"cannot tag null revision"))
7470 7490
7471 7491 tagsmod.tag(
7472 7492 repo,
7473 7493 names,
7474 7494 node,
7475 7495 message,
7476 7496 opts.get(b'local'),
7477 7497 opts.get(b'user'),
7478 7498 date,
7479 7499 editor=editor,
7480 7500 )
7481 7501
7482 7502
7483 7503 @command(
7484 7504 b'tags',
7485 7505 formatteropts,
7486 7506 b'',
7487 7507 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7488 7508 intents={INTENT_READONLY},
7489 7509 )
7490 7510 def tags(ui, repo, **opts):
7491 7511 """list repository tags
7492 7512
7493 7513 This lists both regular and local tags. When the -v/--verbose
7494 7514 switch is used, a third column "local" is printed for local tags.
7495 7515 When the -q/--quiet switch is used, only the tag name is printed.
7496 7516
7497 7517 .. container:: verbose
7498 7518
7499 7519 Template:
7500 7520
7501 7521 The following keywords are supported in addition to the common template
7502 7522 keywords and functions such as ``{tag}``. See also
7503 7523 :hg:`help templates`.
7504 7524
7505 7525 :type: String. ``local`` for local tags.
7506 7526
7507 7527 Returns 0 on success.
7508 7528 """
7509 7529
7510 7530 opts = pycompat.byteskwargs(opts)
7511 7531 ui.pager(b'tags')
7512 7532 fm = ui.formatter(b'tags', opts)
7513 7533 hexfunc = fm.hexfunc
7514 7534
7515 7535 for t, n in reversed(repo.tagslist()):
7516 7536 hn = hexfunc(n)
7517 7537 label = b'tags.normal'
7518 7538 tagtype = repo.tagtype(t)
7519 7539 if not tagtype or tagtype == b'global':
7520 7540 tagtype = b''
7521 7541 else:
7522 7542 label = b'tags.' + tagtype
7523 7543
7524 7544 fm.startitem()
7525 7545 fm.context(repo=repo)
7526 7546 fm.write(b'tag', b'%s', t, label=label)
7527 7547 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7528 7548 fm.condwrite(
7529 7549 not ui.quiet,
7530 7550 b'rev node',
7531 7551 fmt,
7532 7552 repo.changelog.rev(n),
7533 7553 hn,
7534 7554 label=label,
7535 7555 )
7536 7556 fm.condwrite(
7537 7557 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7538 7558 )
7539 7559 fm.plain(b'\n')
7540 7560 fm.end()
7541 7561
7542 7562
7543 7563 @command(
7544 7564 b'tip',
7545 7565 [
7546 7566 (b'p', b'patch', None, _(b'show patch')),
7547 7567 (b'g', b'git', None, _(b'use git extended diff format')),
7548 7568 ]
7549 7569 + templateopts,
7550 7570 _(b'[-p] [-g]'),
7551 7571 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7552 7572 )
7553 7573 def tip(ui, repo, **opts):
7554 7574 """show the tip revision (DEPRECATED)
7555 7575
7556 7576 The tip revision (usually just called the tip) is the changeset
7557 7577 most recently added to the repository (and therefore the most
7558 7578 recently changed head).
7559 7579
7560 7580 If you have just made a commit, that commit will be the tip. If
7561 7581 you have just pulled changes from another repository, the tip of
7562 7582 that repository becomes the current tip. The "tip" tag is special
7563 7583 and cannot be renamed or assigned to a different changeset.
7564 7584
7565 7585 This command is deprecated, please use :hg:`heads` instead.
7566 7586
7567 7587 Returns 0 on success.
7568 7588 """
7569 7589 opts = pycompat.byteskwargs(opts)
7570 7590 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7571 7591 displayer.show(repo[b'tip'])
7572 7592 displayer.close()
7573 7593
7574 7594
7575 7595 @command(
7576 7596 b'unbundle',
7577 7597 [
7578 7598 (
7579 7599 b'u',
7580 7600 b'update',
7581 7601 None,
7582 7602 _(b'update to new branch head if changesets were unbundled'),
7583 7603 )
7584 7604 ],
7585 7605 _(b'[-u] FILE...'),
7586 7606 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7587 7607 )
7588 7608 def unbundle(ui, repo, fname1, *fnames, **opts):
7589 7609 """apply one or more bundle files
7590 7610
7591 7611 Apply one or more bundle files generated by :hg:`bundle`.
7592 7612
7593 7613 Returns 0 on success, 1 if an update has unresolved files.
7594 7614 """
7595 7615 fnames = (fname1,) + fnames
7596 7616
7597 7617 with repo.lock():
7598 7618 for fname in fnames:
7599 7619 f = hg.openpath(ui, fname)
7600 7620 gen = exchange.readbundle(ui, f, fname)
7601 7621 if isinstance(gen, streamclone.streamcloneapplier):
7602 7622 raise error.InputError(
7603 7623 _(
7604 7624 b'packed bundles cannot be applied with '
7605 7625 b'"hg unbundle"'
7606 7626 ),
7607 7627 hint=_(b'use "hg debugapplystreamclonebundle"'),
7608 7628 )
7609 7629 url = b'bundle:' + fname
7610 7630 try:
7611 7631 txnname = b'unbundle'
7612 7632 if not isinstance(gen, bundle2.unbundle20):
7613 7633 txnname = b'unbundle\n%s' % urlutil.hidepassword(url)
7614 7634 with repo.transaction(txnname) as tr:
7615 7635 op = bundle2.applybundle(
7616 7636 repo, gen, tr, source=b'unbundle', url=url
7617 7637 )
7618 7638 except error.BundleUnknownFeatureError as exc:
7619 7639 raise error.Abort(
7620 7640 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7621 7641 hint=_(
7622 7642 b"see https://mercurial-scm.org/"
7623 7643 b"wiki/BundleFeature for more "
7624 7644 b"information"
7625 7645 ),
7626 7646 )
7627 7647 modheads = bundle2.combinechangegroupresults(op)
7628 7648
7629 7649 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7630 7650 return 1
7631 7651 else:
7632 7652 return 0
7633 7653
7634 7654
7635 7655 @command(
7636 7656 b'unshelve',
7637 7657 [
7638 7658 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7639 7659 (
7640 7660 b'c',
7641 7661 b'continue',
7642 7662 None,
7643 7663 _(b'continue an incomplete unshelve operation'),
7644 7664 ),
7645 7665 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7646 7666 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7647 7667 (
7648 7668 b'n',
7649 7669 b'name',
7650 7670 b'',
7651 7671 _(b'restore shelved change with given name'),
7652 7672 _(b'NAME'),
7653 7673 ),
7654 7674 (b't', b'tool', b'', _(b'specify merge tool')),
7655 7675 (
7656 7676 b'',
7657 7677 b'date',
7658 7678 b'',
7659 7679 _(b'set date for temporary commits (DEPRECATED)'),
7660 7680 _(b'DATE'),
7661 7681 ),
7662 7682 ],
7663 7683 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7664 7684 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7665 7685 )
7666 7686 def unshelve(ui, repo, *shelved, **opts):
7667 7687 """restore a shelved change to the working directory
7668 7688
7669 7689 This command accepts an optional name of a shelved change to
7670 7690 restore. If none is given, the most recent shelved change is used.
7671 7691
7672 7692 If a shelved change is applied successfully, the bundle that
7673 7693 contains the shelved changes is moved to a backup location
7674 7694 (.hg/shelve-backup).
7675 7695
7676 7696 Since you can restore a shelved change on top of an arbitrary
7677 7697 commit, it is possible that unshelving will result in a conflict
7678 7698 between your changes and the commits you are unshelving onto. If
7679 7699 this occurs, you must resolve the conflict, then use
7680 7700 ``--continue`` to complete the unshelve operation. (The bundle
7681 7701 will not be moved until you successfully complete the unshelve.)
7682 7702
7683 7703 (Alternatively, you can use ``--abort`` to abandon an unshelve
7684 7704 that causes a conflict. This reverts the unshelved changes, and
7685 7705 leaves the bundle in place.)
7686 7706
7687 7707 If bare shelved change (without interactive, include and exclude
7688 7708 option) was done on newly created branch it would restore branch
7689 7709 information to the working directory.
7690 7710
7691 7711 After a successful unshelve, the shelved changes are stored in a
7692 7712 backup directory. Only the N most recent backups are kept. N
7693 7713 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7694 7714 configuration option.
7695 7715
7696 7716 .. container:: verbose
7697 7717
7698 7718 Timestamp in seconds is used to decide order of backups. More
7699 7719 than ``maxbackups`` backups are kept, if same timestamp
7700 7720 prevents from deciding exact order of them, for safety.
7701 7721
7702 7722 Selected changes can be unshelved with ``--interactive`` flag.
7703 7723 The working directory is updated with the selected changes, and
7704 7724 only the unselected changes remain shelved.
7705 7725 Note: The whole shelve is applied to working directory first before
7706 7726 running interactively. So, this will bring up all the conflicts between
7707 7727 working directory and the shelve, irrespective of which changes will be
7708 7728 unshelved.
7709 7729 """
7710 7730 with repo.wlock():
7711 7731 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7712 7732
7713 7733
7714 7734 statemod.addunfinished(
7715 7735 b'unshelve',
7716 7736 fname=b'shelvedstate',
7717 7737 continueflag=True,
7718 7738 abortfunc=shelvemod.hgabortunshelve,
7719 7739 continuefunc=shelvemod.hgcontinueunshelve,
7720 7740 cmdmsg=_(b'unshelve already in progress'),
7721 7741 )
7722 7742
7723 7743
7724 7744 @command(
7725 7745 b'update|up|checkout|co',
7726 7746 [
7727 7747 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7728 7748 (b'c', b'check', None, _(b'require clean working directory')),
7729 7749 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7730 7750 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7731 7751 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7732 7752 ]
7733 7753 + mergetoolopts,
7734 7754 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7735 7755 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7736 7756 helpbasic=True,
7737 7757 )
7738 7758 def update(ui, repo, node=None, **opts):
7739 7759 """update working directory (or switch revisions)
7740 7760
7741 7761 Update the repository's working directory to the specified
7742 7762 changeset. If no changeset is specified, update to the tip of the
7743 7763 current named branch and move the active bookmark (see :hg:`help
7744 7764 bookmarks`).
7745 7765
7746 7766 Update sets the working directory's parent revision to the specified
7747 7767 changeset (see :hg:`help parents`).
7748 7768
7749 7769 If the changeset is not a descendant or ancestor of the working
7750 7770 directory's parent and there are uncommitted changes, the update is
7751 7771 aborted. With the -c/--check option, the working directory is checked
7752 7772 for uncommitted changes; if none are found, the working directory is
7753 7773 updated to the specified changeset.
7754 7774
7755 7775 .. container:: verbose
7756 7776
7757 7777 The -C/--clean, -c/--check, and -m/--merge options control what
7758 7778 happens if the working directory contains uncommitted changes.
7759 7779 At most of one of them can be specified.
7760 7780
7761 7781 1. If no option is specified, and if
7762 7782 the requested changeset is an ancestor or descendant of
7763 7783 the working directory's parent, the uncommitted changes
7764 7784 are merged into the requested changeset and the merged
7765 7785 result is left uncommitted. If the requested changeset is
7766 7786 not an ancestor or descendant (that is, it is on another
7767 7787 branch), the update is aborted and the uncommitted changes
7768 7788 are preserved.
7769 7789
7770 7790 2. With the -m/--merge option, the update is allowed even if the
7771 7791 requested changeset is not an ancestor or descendant of
7772 7792 the working directory's parent.
7773 7793
7774 7794 3. With the -c/--check option, the update is aborted and the
7775 7795 uncommitted changes are preserved.
7776 7796
7777 7797 4. With the -C/--clean option, uncommitted changes are discarded and
7778 7798 the working directory is updated to the requested changeset.
7779 7799
7780 7800 To cancel an uncommitted merge (and lose your changes), use
7781 7801 :hg:`merge --abort`.
7782 7802
7783 7803 Use null as the changeset to remove the working directory (like
7784 7804 :hg:`clone -U`).
7785 7805
7786 7806 If you want to revert just one file to an older revision, use
7787 7807 :hg:`revert [-r REV] NAME`.
7788 7808
7789 7809 See :hg:`help dates` for a list of formats valid for -d/--date.
7790 7810
7791 7811 Returns 0 on success, 1 if there are unresolved files.
7792 7812 """
7793 7813 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7794 7814 rev = opts.get('rev')
7795 7815 date = opts.get('date')
7796 7816 clean = opts.get('clean')
7797 7817 check = opts.get('check')
7798 7818 merge = opts.get('merge')
7799 7819 if rev and node:
7800 7820 raise error.InputError(_(b"please specify just one revision"))
7801 7821
7802 7822 if ui.configbool(b'commands', b'update.requiredest'):
7803 7823 if not node and not rev and not date:
7804 7824 raise error.InputError(
7805 7825 _(b'you must specify a destination'),
7806 7826 hint=_(b'for example: hg update ".::"'),
7807 7827 )
7808 7828
7809 7829 if rev is None or rev == b'':
7810 7830 rev = node
7811 7831
7812 7832 if date and rev is not None:
7813 7833 raise error.InputError(_(b"you can't specify a revision and a date"))
7814 7834
7815 7835 updatecheck = None
7816 7836 if check or merge is not None and not merge:
7817 7837 updatecheck = b'abort'
7818 7838 elif merge or check is not None and not check:
7819 7839 updatecheck = b'none'
7820 7840
7821 7841 with repo.wlock():
7822 7842 cmdutil.clearunfinished(repo)
7823 7843 if date:
7824 7844 rev = cmdutil.finddate(ui, repo, date)
7825 7845
7826 7846 # if we defined a bookmark, we have to remember the original name
7827 7847 brev = rev
7828 7848 if rev:
7829 7849 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7830 7850 ctx = logcmdutil.revsingle(repo, rev, default=None)
7831 7851 rev = ctx.rev()
7832 7852 hidden = ctx.hidden()
7833 7853 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7834 7854 with ui.configoverride(overrides, b'update'):
7835 7855 ret = hg.updatetotally(
7836 7856 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7837 7857 )
7838 7858 if hidden:
7839 7859 ctxstr = ctx.hex()[:12]
7840 7860 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7841 7861
7842 7862 if ctx.obsolete():
7843 7863 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7844 7864 ui.warn(b"(%s)\n" % obsfatemsg)
7845 7865 return ret
7846 7866
7847 7867
7848 7868 @command(
7849 7869 b'verify',
7850 7870 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7851 7871 helpcategory=command.CATEGORY_MAINTENANCE,
7852 7872 )
7853 7873 def verify(ui, repo, **opts):
7854 7874 """verify the integrity of the repository
7855 7875
7856 7876 Verify the integrity of the current repository.
7857 7877
7858 7878 This will perform an extensive check of the repository's
7859 7879 integrity, validating the hashes and checksums of each entry in
7860 7880 the changelog, manifest, and tracked files, as well as the
7861 7881 integrity of their crosslinks and indices.
7862 7882
7863 7883 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7864 7884 for more information about recovery from corruption of the
7865 7885 repository.
7866 7886
7867 7887 Returns 0 on success, 1 if errors are encountered.
7868 7888 """
7869 7889 opts = pycompat.byteskwargs(opts)
7870 7890
7871 7891 level = None
7872 7892 if opts[b'full']:
7873 7893 level = verifymod.VERIFY_FULL
7874 7894 return hg.verify(repo, level)
7875 7895
7876 7896
7877 7897 @command(
7878 7898 b'version',
7879 7899 [] + formatteropts,
7880 7900 helpcategory=command.CATEGORY_HELP,
7881 7901 norepo=True,
7882 7902 intents={INTENT_READONLY},
7883 7903 )
7884 7904 def version_(ui, **opts):
7885 7905 """output version and copyright information
7886 7906
7887 7907 .. container:: verbose
7888 7908
7889 7909 Template:
7890 7910
7891 7911 The following keywords are supported. See also :hg:`help templates`.
7892 7912
7893 7913 :extensions: List of extensions.
7894 7914 :ver: String. Version number.
7895 7915
7896 7916 And each entry of ``{extensions}`` provides the following sub-keywords
7897 7917 in addition to ``{ver}``.
7898 7918
7899 7919 :bundled: Boolean. True if included in the release.
7900 7920 :name: String. Extension name.
7901 7921 """
7902 7922 opts = pycompat.byteskwargs(opts)
7903 7923 if ui.verbose:
7904 7924 ui.pager(b'version')
7905 7925 fm = ui.formatter(b"version", opts)
7906 7926 fm.startitem()
7907 7927 fm.write(
7908 7928 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7909 7929 )
7910 7930 license = _(
7911 7931 b"(see https://mercurial-scm.org for more information)\n"
7912 7932 b"\nCopyright (C) 2005-2022 Olivia Mackall and others\n"
7913 7933 b"This is free software; see the source for copying conditions. "
7914 7934 b"There is NO\nwarranty; "
7915 7935 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7916 7936 )
7917 7937 if not ui.quiet:
7918 7938 fm.plain(license)
7919 7939
7920 7940 if ui.verbose:
7921 7941 fm.plain(_(b"\nEnabled extensions:\n\n"))
7922 7942 # format names and versions into columns
7923 7943 names = []
7924 7944 vers = []
7925 7945 isinternals = []
7926 7946 for name, module in sorted(extensions.extensions()):
7927 7947 names.append(name)
7928 7948 vers.append(extensions.moduleversion(module) or None)
7929 7949 isinternals.append(extensions.ismoduleinternal(module))
7930 7950 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7931 7951 if names:
7932 7952 namefmt = b" %%-%ds " % max(len(n) for n in names)
7933 7953 places = [_(b"external"), _(b"internal")]
7934 7954 for n, v, p in zip(names, vers, isinternals):
7935 7955 fn.startitem()
7936 7956 fn.condwrite(ui.verbose, b"name", namefmt, n)
7937 7957 if ui.verbose:
7938 7958 fn.plain(b"%s " % places[p])
7939 7959 fn.data(bundled=p)
7940 7960 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7941 7961 if ui.verbose:
7942 7962 fn.plain(b"\n")
7943 7963 fn.end()
7944 7964 fm.end()
7945 7965
7946 7966
7947 7967 def loadcmdtable(ui, name, cmdtable):
7948 7968 """Load command functions from specified cmdtable"""
7949 7969 overrides = [cmd for cmd in cmdtable if cmd in table]
7950 7970 if overrides:
7951 7971 ui.warn(
7952 7972 _(b"extension '%s' overrides commands: %s\n")
7953 7973 % (name, b" ".join(overrides))
7954 7974 )
7955 7975 table.update(cmdtable)
@@ -1,1065 +1,1065 b''
1 1 Setting up test
2 2
3 3 $ hg init test
4 4 $ cd test
5 5 $ echo 0 > afile
6 6 $ hg add afile
7 7 $ hg commit -m "0.0"
8 8 $ echo 1 >> afile
9 9 $ hg commit -m "0.1"
10 10 $ echo 2 >> afile
11 11 $ hg commit -m "0.2"
12 12 $ echo 3 >> afile
13 13 $ hg commit -m "0.3"
14 14 $ hg update -C 0
15 15 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
16 16 $ echo 1 >> afile
17 17 $ hg commit -m "1.1"
18 18 created new head
19 19 $ echo 2 >> afile
20 20 $ hg commit -m "1.2"
21 21 $ echo "a line" > fred
22 22 $ echo 3 >> afile
23 23 $ hg add fred
24 24 $ hg commit -m "1.3"
25 25 $ hg mv afile adifferentfile
26 26 $ hg commit -m "1.3m"
27 27 $ hg update -C 3
28 28 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
29 29 $ hg mv afile anotherfile
30 30 $ hg commit -m "0.3m"
31 31 $ hg verify
32 32 checking changesets
33 33 checking manifests
34 34 crosschecking files in changesets and manifests
35 35 checking files
36 36 checked 9 changesets with 7 changes to 4 files
37 37 $ cd ..
38 38 $ hg init empty
39 39
40 40 Bundle and phase
41 41
42 42 $ hg -R test phase --force --secret 0
43 43 $ hg -R test bundle phase.hg empty
44 44 searching for changes
45 45 no changes found (ignored 9 secret changesets)
46 46 [1]
47 47 $ hg -R test phase --draft -r 'head()'
48 48
49 49 Bundle --all
50 50
51 51 $ hg -R test bundle --all all.hg
52 52 9 changesets found
53 53
54 54 Bundle test to full.hg
55 55
56 56 $ hg -R test bundle full.hg empty
57 57 searching for changes
58 58 9 changesets found
59 59
60 60 Unbundle full.hg in test
61 61
62 62 $ hg -R test unbundle full.hg
63 63 adding changesets
64 64 adding manifests
65 65 adding file changes
66 66 added 0 changesets with 0 changes to 4 files
67 67 (run 'hg update' to get a working copy)
68 68
69 69 Verify empty
70 70
71 71 $ hg -R empty heads
72 72 [1]
73 73 $ hg -R empty verify
74 74 checking changesets
75 75 checking manifests
76 76 crosschecking files in changesets and manifests
77 77 checking files
78 78 checked 0 changesets with 0 changes to 0 files
79 79
80 80 #if repobundlerepo
81 81
82 82 Pull full.hg into test (using --cwd)
83 83
84 84 $ hg --cwd test pull ../full.hg
85 85 pulling from ../full.hg
86 86 searching for changes
87 87 no changes found
88 88
89 89 Verify that there are no leaked temporary files after pull (issue2797)
90 90
91 91 $ ls test/.hg | grep .hg10un
92 92 [1]
93 93
94 94 Pull full.hg into empty (using --cwd)
95 95
96 96 $ hg --cwd empty pull ../full.hg
97 97 pulling from ../full.hg
98 98 requesting all changes
99 99 adding changesets
100 100 adding manifests
101 101 adding file changes
102 102 added 9 changesets with 7 changes to 4 files (+1 heads)
103 103 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
104 104 (run 'hg heads' to see heads, 'hg merge' to merge)
105 105
106 106 Rollback empty
107 107
108 108 $ hg -R empty rollback
109 109 repository tip rolled back to revision -1 (undo pull)
110 110
111 111 Pull full.hg into empty again (using --cwd)
112 112
113 113 $ hg --cwd empty pull ../full.hg
114 114 pulling from ../full.hg
115 115 requesting all changes
116 116 adding changesets
117 117 adding manifests
118 118 adding file changes
119 119 added 9 changesets with 7 changes to 4 files (+1 heads)
120 120 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
121 121 (run 'hg heads' to see heads, 'hg merge' to merge)
122 122
123 123 Pull full.hg into test (using -R)
124 124
125 125 $ hg -R test pull full.hg
126 126 pulling from full.hg
127 127 searching for changes
128 128 no changes found
129 129
130 130 Pull full.hg into empty (using -R)
131 131
132 132 $ hg -R empty pull full.hg
133 133 pulling from full.hg
134 134 searching for changes
135 135 no changes found
136 136
137 137 Rollback empty
138 138
139 139 $ hg -R empty rollback
140 140 repository tip rolled back to revision -1 (undo pull)
141 141
142 142 Pull full.hg into empty again (using -R)
143 143
144 144 $ hg -R empty pull full.hg
145 145 pulling from full.hg
146 146 requesting all changes
147 147 adding changesets
148 148 adding manifests
149 149 adding file changes
150 150 added 9 changesets with 7 changes to 4 files (+1 heads)
151 151 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
152 152 (run 'hg heads' to see heads, 'hg merge' to merge)
153 153
154 154 Log -R full.hg in fresh empty
155 155
156 156 $ rm -r empty
157 157 $ hg init empty
158 158 $ cd empty
159 159 $ hg -R bundle://../full.hg log
160 160 changeset: 8:aa35859c02ea
161 161 tag: tip
162 162 parent: 3:eebf5a27f8ca
163 163 user: test
164 164 date: Thu Jan 01 00:00:00 1970 +0000
165 165 summary: 0.3m
166 166
167 167 changeset: 7:a6a34bfa0076
168 168 user: test
169 169 date: Thu Jan 01 00:00:00 1970 +0000
170 170 summary: 1.3m
171 171
172 172 changeset: 6:7373c1169842
173 173 user: test
174 174 date: Thu Jan 01 00:00:00 1970 +0000
175 175 summary: 1.3
176 176
177 177 changeset: 5:1bb50a9436a7
178 178 user: test
179 179 date: Thu Jan 01 00:00:00 1970 +0000
180 180 summary: 1.2
181 181
182 182 changeset: 4:095197eb4973
183 183 parent: 0:f9ee2f85a263
184 184 user: test
185 185 date: Thu Jan 01 00:00:00 1970 +0000
186 186 summary: 1.1
187 187
188 188 changeset: 3:eebf5a27f8ca
189 189 user: test
190 190 date: Thu Jan 01 00:00:00 1970 +0000
191 191 summary: 0.3
192 192
193 193 changeset: 2:e38ba6f5b7e0
194 194 user: test
195 195 date: Thu Jan 01 00:00:00 1970 +0000
196 196 summary: 0.2
197 197
198 198 changeset: 1:34c2bf6b0626
199 199 user: test
200 200 date: Thu Jan 01 00:00:00 1970 +0000
201 201 summary: 0.1
202 202
203 203 changeset: 0:f9ee2f85a263
204 204 user: test
205 205 date: Thu Jan 01 00:00:00 1970 +0000
206 206 summary: 0.0
207 207
208 208 Make sure bundlerepo doesn't leak tempfiles (issue2491)
209 209
210 210 $ ls .hg
211 211 00changelog.i
212 212 cache
213 213 requires
214 214 store
215 215 wcache
216 216
217 217 Pull ../full.hg into empty (with hook)
218 218
219 219 $ cat >> .hg/hgrc <<EOF
220 220 > [hooks]
221 221 > changegroup = sh -c "printenv.py --line changegroup"
222 222 > EOF
223 223
224 224 doesn't work (yet ?)
225 225 NOTE: msys is mangling the URL below
226 226
227 227 hg -R bundle://../full.hg verify
228 228
229 229 $ hg pull bundle://../full.hg
230 230 pulling from bundle:../full.hg
231 231 requesting all changes
232 232 adding changesets
233 233 adding manifests
234 234 adding file changes
235 235 added 9 changesets with 7 changes to 4 files (+1 heads)
236 236 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
237 237 changegroup hook: HG_HOOKNAME=changegroup
238 238 HG_HOOKTYPE=changegroup
239 239 HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735
240 240 HG_NODE_LAST=aa35859c02ea8bd48da5da68cd2740ac71afcbaf
241 241 HG_SOURCE=pull
242 242 HG_TXNID=TXN:$ID$
243 243 HG_TXNNAME=pull
244 244 bundle:../full.hg (no-msys !)
245 245 bundle;../full.hg (msys !)
246 246 HG_URL=bundle:../full.hg (no-msys !)
247 247 HG_URL=bundle;../full.hg (msys !)
248 248
249 249 (run 'hg heads' to see heads, 'hg merge' to merge)
250 250
251 251 Rollback empty
252 252
253 253 $ hg rollback
254 254 repository tip rolled back to revision -1 (undo pull)
255 255 $ cd ..
256 256
257 257 Log -R bundle:empty+full.hg
258 258
259 259 $ hg -R bundle:empty+full.hg log --template="{rev} "; echo ""
260 260 8 7 6 5 4 3 2 1 0
261 261
262 262 Pull full.hg into empty again (using -R; with hook)
263 263
264 264 $ hg -R empty pull full.hg
265 265 pulling from full.hg
266 266 requesting all changes
267 267 adding changesets
268 268 adding manifests
269 269 adding file changes
270 270 added 9 changesets with 7 changes to 4 files (+1 heads)
271 271 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
272 272 changegroup hook: HG_HOOKNAME=changegroup
273 273 HG_HOOKTYPE=changegroup
274 274 HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735
275 275 HG_NODE_LAST=aa35859c02ea8bd48da5da68cd2740ac71afcbaf
276 276 HG_SOURCE=pull
277 277 HG_TXNID=TXN:$ID$
278 278 HG_TXNNAME=pull
279 279 bundle:empty+full.hg
280 280 HG_URL=bundle:empty+full.hg
281 281
282 282 (run 'hg heads' to see heads, 'hg merge' to merge)
283 283
284 284 #endif
285 285
286 286 Cannot produce streaming clone bundles with "hg bundle"
287 287
288 288 $ hg -R test bundle -t packed1 packed.hg
289 289 abort: packed bundles cannot be produced by "hg bundle"
290 290 (use 'hg debugcreatestreamclonebundle')
291 291 [10]
292 292
293 293 packed1 is produced properly
294 294
295 295
296 296 #if reporevlogstore rust
297 297
298 298 $ hg -R test debugcreatestreamclonebundle packed.hg
299 299 writing 2665 bytes for 6 files
300 300 bundle requirements: generaldelta, revlog-compression-zstd, revlogv1, sparserevlog
301 301
302 302 $ f -B 64 --size --sha1 --hexdump packed.hg
303 303 packed.hg: size=2865, sha1=353d10311f4befa195d9a1ca4b8e26518115c702
304 304 0000: 48 47 53 31 55 4e 00 00 00 00 00 00 00 06 00 00 |HGS1UN..........|
305 305 0010: 00 00 00 00 0a 69 00 3b 67 65 6e 65 72 61 6c 64 |.....i.;generald|
306 306 0020: 65 6c 74 61 2c 72 65 76 6c 6f 67 2d 63 6f 6d 70 |elta,revlog-comp|
307 307 0030: 72 65 73 73 69 6f 6e 2d 7a 73 74 64 2c 72 65 76 |ression-zstd,rev|
308 308 $ hg debugbundle --spec packed.hg
309 309 none-packed1;requirements%3Dgeneraldelta%2Crevlog-compression-zstd%2Crevlogv1%2Csparserevlog
310 310 #endif
311 311
312 312 #if reporevlogstore no-rust zstd
313 313
314 314 $ hg -R test debugcreatestreamclonebundle packed.hg
315 315 writing 2665 bytes for 6 files
316 316 bundle requirements: generaldelta, revlog-compression-zstd, revlogv1, sparserevlog
317 317
318 318 $ f -B 64 --size --sha1 --hexdump packed.hg
319 319 packed.hg: size=2865, sha1=353d10311f4befa195d9a1ca4b8e26518115c702
320 320 0000: 48 47 53 31 55 4e 00 00 00 00 00 00 00 06 00 00 |HGS1UN..........|
321 321 0010: 00 00 00 00 0a 69 00 3b 67 65 6e 65 72 61 6c 64 |.....i.;generald|
322 322 0020: 65 6c 74 61 2c 72 65 76 6c 6f 67 2d 63 6f 6d 70 |elta,revlog-comp|
323 323 0030: 72 65 73 73 69 6f 6e 2d 7a 73 74 64 2c 72 65 76 |ression-zstd,rev|
324 324 $ hg debugbundle --spec packed.hg
325 325 none-packed1;requirements%3Dgeneraldelta%2Crevlog-compression-zstd%2Crevlogv1%2Csparserevlog
326 326 #endif
327 327
328 328 #if reporevlogstore no-rust no-zstd
329 329
330 330 $ hg -R test debugcreatestreamclonebundle packed.hg
331 331 writing 2664 bytes for 6 files
332 332 bundle requirements: generaldelta, revlogv1, sparserevlog
333 333
334 334 $ f -B 64 --size --sha1 --hexdump packed.hg
335 335 packed.hg: size=2840, sha1=12bf3eee3eb8a04c503ce2d29b48f0135c7edff5
336 336 0000: 48 47 53 31 55 4e 00 00 00 00 00 00 00 06 00 00 |HGS1UN..........|
337 337 0010: 00 00 00 00 0a 68 00 23 67 65 6e 65 72 61 6c 64 |.....h.#generald|
338 338 0020: 65 6c 74 61 2c 72 65 76 6c 6f 67 76 31 2c 73 70 |elta,revlogv1,sp|
339 339 0030: 61 72 73 65 72 65 76 6c 6f 67 00 64 61 74 61 2f |arserevlog.data/|
340 340 $ hg debugbundle --spec packed.hg
341 341 none-packed1;requirements%3Dgeneraldelta%2Crevlogv1%2Csparserevlog
342 342 #endif
343 343
344 344 #if reporevlogstore
345 345
346 346 generaldelta requirement is not listed in stream clone bundles unless used
347 347
348 348 $ hg --config format.usegeneraldelta=false init testnongd
349 349 $ cd testnongd
350 350 $ touch foo
351 351 $ hg -q commit -A -m initial
352 352 $ cd ..
353 353
354 354 #endif
355 355
356 356 #if reporevlogstore rust
357 357
358 358 $ hg -R testnongd debugcreatestreamclonebundle packednongd.hg
359 359 writing 301 bytes for 3 files
360 360 bundle requirements: revlog-compression-zstd, revlogv1
361 361
362 362 $ f -B 64 --size --sha1 --hexdump packednongd.hg
363 363 packednongd.hg: size=407, sha1=0b8714422b785ba8eb98c916b41ffd5fb994c9b5
364 364 0000: 48 47 53 31 55 4e 00 00 00 00 00 00 00 03 00 00 |HGS1UN..........|
365 365 0010: 00 00 00 00 01 2d 00 21 72 65 76 6c 6f 67 2d 63 |.....-.!revlog-c|
366 366 0020: 6f 6d 70 72 65 73 73 69 6f 6e 2d 7a 73 74 64 2c |ompression-zstd,|
367 367 0030: 72 65 76 6c 6f 67 76 31 00 64 61 74 61 2f 66 6f |revlogv1.data/fo|
368 368
369 369 $ hg debugbundle --spec packednongd.hg
370 370 none-packed1;requirements%3Drevlog-compression-zstd%2Crevlogv1
371 371
372 372 #endif
373 373
374 374 #if reporevlogstore no-rust zstd
375 375
376 376 $ hg -R testnongd debugcreatestreamclonebundle packednongd.hg
377 377 writing 301 bytes for 3 files
378 378 bundle requirements: revlog-compression-zstd, revlogv1
379 379
380 380 $ f -B 64 --size --sha1 --hexdump packednongd.hg
381 381 packednongd.hg: size=407, sha1=0b8714422b785ba8eb98c916b41ffd5fb994c9b5
382 382 0000: 48 47 53 31 55 4e 00 00 00 00 00 00 00 03 00 00 |HGS1UN..........|
383 383 0010: 00 00 00 00 01 2d 00 21 72 65 76 6c 6f 67 2d 63 |.....-.!revlog-c|
384 384 0020: 6f 6d 70 72 65 73 73 69 6f 6e 2d 7a 73 74 64 2c |ompression-zstd,|
385 385 0030: 72 65 76 6c 6f 67 76 31 00 64 61 74 61 2f 66 6f |revlogv1.data/fo|
386 386
387 387 $ hg debugbundle --spec packednongd.hg
388 388 none-packed1;requirements%3Drevlog-compression-zstd%2Crevlogv1
389 389
390 390
391 391 #endif
392 392
393 393 #if reporevlogstore no-rust no-zstd
394 394
395 395 $ hg -R testnongd debugcreatestreamclonebundle packednongd.hg
396 396 writing 301 bytes for 3 files
397 397 bundle requirements: revlogv1
398 398
399 399 $ f -B 64 --size --sha1 --hexdump packednongd.hg
400 400 packednongd.hg: size=383, sha1=1d9c230238edd5d38907100b729ba72b1831fe6f
401 401 0000: 48 47 53 31 55 4e 00 00 00 00 00 00 00 03 00 00 |HGS1UN..........|
402 402 0010: 00 00 00 00 01 2d 00 09 72 65 76 6c 6f 67 76 31 |.....-..revlogv1|
403 403 0020: 00 64 61 74 61 2f 66 6f 6f 2e 69 00 36 34 0a 00 |.data/foo.i.64..|
404 404 0030: 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
405 405
406 406 $ hg debugbundle --spec packednongd.hg
407 407 none-packed1;requirements%3Drevlogv1
408 408
409 409
410 410 #endif
411 411
412 412 #if reporevlogstore
413 413
414 414 Warning emitted when packed bundles contain secret changesets
415 415
416 416 $ hg init testsecret
417 417 $ cd testsecret
418 418 $ touch foo
419 419 $ hg -q commit -A -m initial
420 420 $ hg phase --force --secret -r .
421 421 $ cd ..
422 422
423 423 #endif
424 424
425 425 #if reporevlogstore rust
426 426
427 427 $ hg -R testsecret debugcreatestreamclonebundle packedsecret.hg
428 428 (warning: stream clone bundle will contain secret revisions)
429 429 writing 301 bytes for 3 files
430 430 bundle requirements: generaldelta, revlog-compression-zstd, revlogv1, sparserevlog
431 431
432 432 #endif
433 433
434 434 #if reporevlogstore no-rust zstd
435 435
436 436 $ hg -R testsecret debugcreatestreamclonebundle packedsecret.hg
437 437 (warning: stream clone bundle will contain secret revisions)
438 438 writing 301 bytes for 3 files
439 439 bundle requirements: generaldelta, revlog-compression-zstd, revlogv1, sparserevlog
440 440
441 441 #endif
442 442
443 443 #if reporevlogstore no-rust no-zstd
444 444
445 445 $ hg -R testsecret debugcreatestreamclonebundle packedsecret.hg
446 446 (warning: stream clone bundle will contain secret revisions)
447 447 writing 301 bytes for 3 files
448 448 bundle requirements: generaldelta, revlogv1, sparserevlog
449 449
450 450 #endif
451 451
452 452 #if reporevlogstore
453 453
454 454 Unpacking packed1 bundles with "hg unbundle" isn't allowed
455 455
456 456 $ hg init packed
457 457 $ hg -R packed unbundle packed.hg
458 458 abort: packed bundles cannot be applied with "hg unbundle"
459 459 (use "hg debugapplystreamclonebundle")
460 460 [10]
461 461
462 462 packed1 can be consumed from debug command
463 463
464 464 (this also confirms that streamclone-ed changes are visible via
465 465 @filecache properties to in-process procedures before closing
466 466 transaction)
467 467
468 468 $ cat > $TESTTMP/showtip.py <<EOF
469 469 >
470 470 > def showtip(ui, repo, hooktype, **kwargs):
471 471 > ui.warn(b'%s: %s\n' % (hooktype, repo[b'tip'].hex()[:12]))
472 472 >
473 473 > def reposetup(ui, repo):
474 474 > # this confirms (and ensures) that (empty) 00changelog.i
475 475 > # before streamclone is already cached as repo.changelog
476 476 > ui.setconfig(b'hooks', b'pretxnopen.showtip', showtip)
477 477 >
478 478 > # this confirms that streamclone-ed changes are visible to
479 479 > # in-process procedures before closing transaction
480 480 > ui.setconfig(b'hooks', b'pretxnclose.showtip', showtip)
481 481 >
482 482 > # this confirms that streamclone-ed changes are still visible
483 483 > # after closing transaction
484 484 > ui.setconfig(b'hooks', b'txnclose.showtip', showtip)
485 485 > EOF
486 486 $ cat >> $HGRCPATH <<EOF
487 487 > [extensions]
488 488 > showtip = $TESTTMP/showtip.py
489 489 > EOF
490 490
491 491 $ hg -R packed debugapplystreamclonebundle packed.hg
492 492 6 files to transfer, 2.60 KB of data
493 493 pretxnopen: 000000000000
494 494 pretxnclose: aa35859c02ea
495 495 transferred 2.60 KB in * seconds (* */sec) (glob)
496 496 txnclose: aa35859c02ea
497 497
498 498 (for safety, confirm visibility of streamclone-ed changes by another
499 499 process, too)
500 500
501 501 $ hg -R packed tip -T "{node|short}\n"
502 502 aa35859c02ea
503 503
504 504 $ cat >> $HGRCPATH <<EOF
505 505 > [extensions]
506 506 > showtip = !
507 507 > EOF
508 508
509 509 Does not work on non-empty repo
510 510
511 511 $ hg -R packed debugapplystreamclonebundle packed.hg
512 512 abort: cannot apply stream clone bundle on non-empty repo
513 513 [255]
514 514
515 515 #endif
516 516
517 517 Create partial clones
518 518
519 519 $ rm -r empty
520 520 $ hg init empty
521 521 $ hg clone -r 3 test partial
522 522 adding changesets
523 523 adding manifests
524 524 adding file changes
525 525 added 4 changesets with 4 changes to 1 files
526 526 new changesets f9ee2f85a263:eebf5a27f8ca
527 527 updating to branch default
528 528 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
529 529 $ hg clone partial partial2
530 530 updating to branch default
531 531 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
532 532 $ cd partial
533 533
534 534 #if repobundlerepo
535 535
536 536 Log -R full.hg in partial
537 537
538 538 $ hg -R bundle://../full.hg log -T phases
539 539 changeset: 8:aa35859c02ea
540 540 tag: tip
541 541 phase: draft
542 542 parent: 3:eebf5a27f8ca
543 543 user: test
544 544 date: Thu Jan 01 00:00:00 1970 +0000
545 545 summary: 0.3m
546 546
547 547 changeset: 7:a6a34bfa0076
548 548 phase: draft
549 549 user: test
550 550 date: Thu Jan 01 00:00:00 1970 +0000
551 551 summary: 1.3m
552 552
553 553 changeset: 6:7373c1169842
554 554 phase: draft
555 555 user: test
556 556 date: Thu Jan 01 00:00:00 1970 +0000
557 557 summary: 1.3
558 558
559 559 changeset: 5:1bb50a9436a7
560 560 phase: draft
561 561 user: test
562 562 date: Thu Jan 01 00:00:00 1970 +0000
563 563 summary: 1.2
564 564
565 565 changeset: 4:095197eb4973
566 566 phase: draft
567 567 parent: 0:f9ee2f85a263
568 568 user: test
569 569 date: Thu Jan 01 00:00:00 1970 +0000
570 570 summary: 1.1
571 571
572 572 changeset: 3:eebf5a27f8ca
573 573 phase: public
574 574 user: test
575 575 date: Thu Jan 01 00:00:00 1970 +0000
576 576 summary: 0.3
577 577
578 578 changeset: 2:e38ba6f5b7e0
579 579 phase: public
580 580 user: test
581 581 date: Thu Jan 01 00:00:00 1970 +0000
582 582 summary: 0.2
583 583
584 584 changeset: 1:34c2bf6b0626
585 585 phase: public
586 586 user: test
587 587 date: Thu Jan 01 00:00:00 1970 +0000
588 588 summary: 0.1
589 589
590 590 changeset: 0:f9ee2f85a263
591 591 phase: public
592 592 user: test
593 593 date: Thu Jan 01 00:00:00 1970 +0000
594 594 summary: 0.0
595 595
596 596
597 597 Incoming full.hg in partial
598 598
599 599 $ hg incoming bundle://../full.hg
600 600 comparing with bundle:../full.hg
601 601 searching for changes
602 602 changeset: 4:095197eb4973
603 603 parent: 0:f9ee2f85a263
604 604 user: test
605 605 date: Thu Jan 01 00:00:00 1970 +0000
606 606 summary: 1.1
607 607
608 608 changeset: 5:1bb50a9436a7
609 609 user: test
610 610 date: Thu Jan 01 00:00:00 1970 +0000
611 611 summary: 1.2
612 612
613 613 changeset: 6:7373c1169842
614 614 user: test
615 615 date: Thu Jan 01 00:00:00 1970 +0000
616 616 summary: 1.3
617 617
618 618 changeset: 7:a6a34bfa0076
619 619 user: test
620 620 date: Thu Jan 01 00:00:00 1970 +0000
621 621 summary: 1.3m
622 622
623 623 changeset: 8:aa35859c02ea
624 624 tag: tip
625 625 parent: 3:eebf5a27f8ca
626 626 user: test
627 627 date: Thu Jan 01 00:00:00 1970 +0000
628 628 summary: 0.3m
629 629
630 630
631 631 Outgoing -R full.hg vs partial2 in partial
632 632
633 633 $ hg -R bundle://../full.hg outgoing ../partial2
634 634 comparing with ../partial2
635 635 searching for changes
636 636 changeset: 4:095197eb4973
637 637 parent: 0:f9ee2f85a263
638 638 user: test
639 639 date: Thu Jan 01 00:00:00 1970 +0000
640 640 summary: 1.1
641 641
642 642 changeset: 5:1bb50a9436a7
643 643 user: test
644 644 date: Thu Jan 01 00:00:00 1970 +0000
645 645 summary: 1.2
646 646
647 647 changeset: 6:7373c1169842
648 648 user: test
649 649 date: Thu Jan 01 00:00:00 1970 +0000
650 650 summary: 1.3
651 651
652 652 changeset: 7:a6a34bfa0076
653 653 user: test
654 654 date: Thu Jan 01 00:00:00 1970 +0000
655 655 summary: 1.3m
656 656
657 657 changeset: 8:aa35859c02ea
658 658 tag: tip
659 659 parent: 3:eebf5a27f8ca
660 660 user: test
661 661 date: Thu Jan 01 00:00:00 1970 +0000
662 662 summary: 0.3m
663 663
664 664
665 665 Outgoing -R does-not-exist.hg vs partial2 in partial
666 666
667 667 $ hg -R bundle://../does-not-exist.hg outgoing ../partial2
668 668 abort: *../does-not-exist.hg* (glob)
669 669 [255]
670 670
671 671 #endif
672 672
673 673 $ cd ..
674 674
675 675 hide outer repo
676 676 $ hg init
677 677
678 678 Direct clone from bundle (all-history)
679 679
680 680 #if repobundlerepo
681 681
682 682 $ hg clone full.hg full-clone
683 683 requesting all changes
684 684 adding changesets
685 685 adding manifests
686 686 adding file changes
687 687 added 9 changesets with 7 changes to 4 files (+1 heads)
688 688 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
689 689 updating to branch default
690 690 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
691 691 $ hg -R full-clone heads
692 692 changeset: 8:aa35859c02ea
693 693 tag: tip
694 694 parent: 3:eebf5a27f8ca
695 695 user: test
696 696 date: Thu Jan 01 00:00:00 1970 +0000
697 697 summary: 0.3m
698 698
699 699 changeset: 7:a6a34bfa0076
700 700 user: test
701 701 date: Thu Jan 01 00:00:00 1970 +0000
702 702 summary: 1.3m
703 703
704 704 $ rm -r full-clone
705 705
706 706 When cloning from a non-copiable repository into '', do not
707 707 recurse infinitely (issue2528)
708 708
709 709 $ hg clone full.hg ''
710 710 abort: empty destination path is not valid
711 711 [10]
712 712
713 713 test for https://bz.mercurial-scm.org/216
714 714
715 715 Unbundle incremental bundles into fresh empty in one go
716 716
717 717 $ rm -r empty
718 718 $ hg init empty
719 719 $ hg -R test bundle --base null -r 0 ../0.hg
720 720 1 changesets found
721 $ hg -R test bundle --base 0 -r 1 ../1.hg
721 $ hg -R test bundle --exact -r 1 ../1.hg
722 722 1 changesets found
723 723 $ hg -R empty unbundle -u ../0.hg ../1.hg
724 724 adding changesets
725 725 adding manifests
726 726 adding file changes
727 727 added 1 changesets with 1 changes to 1 files
728 728 new changesets f9ee2f85a263 (1 drafts)
729 729 adding changesets
730 730 adding manifests
731 731 adding file changes
732 732 added 1 changesets with 1 changes to 1 files
733 733 new changesets 34c2bf6b0626 (1 drafts)
734 734 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
735 735
736 736 View full contents of the bundle
737 737 $ hg -R test bundle --base null -r 3 ../partial.hg
738 738 4 changesets found
739 739 $ cd test
740 740 $ hg -R ../../partial.hg log -r "bundle()"
741 741 changeset: 0:f9ee2f85a263
742 742 user: test
743 743 date: Thu Jan 01 00:00:00 1970 +0000
744 744 summary: 0.0
745 745
746 746 changeset: 1:34c2bf6b0626
747 747 user: test
748 748 date: Thu Jan 01 00:00:00 1970 +0000
749 749 summary: 0.1
750 750
751 751 changeset: 2:e38ba6f5b7e0
752 752 user: test
753 753 date: Thu Jan 01 00:00:00 1970 +0000
754 754 summary: 0.2
755 755
756 756 changeset: 3:eebf5a27f8ca
757 757 user: test
758 758 date: Thu Jan 01 00:00:00 1970 +0000
759 759 summary: 0.3
760 760
761 761 $ cd ..
762 762
763 763 #endif
764 764
765 765 test for 540d1059c802
766 766
767 767 $ hg init orig
768 768 $ cd orig
769 769 $ echo foo > foo
770 770 $ hg add foo
771 771 $ hg ci -m 'add foo'
772 772
773 773 $ hg clone . ../copy
774 774 updating to branch default
775 775 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
776 776 $ hg tag foo
777 777
778 778 $ cd ../copy
779 779 $ echo >> foo
780 780 $ hg ci -m 'change foo'
781 781 $ hg bundle ../bundle.hg ../orig
782 782 searching for changes
783 783 1 changesets found
784 784
785 785 $ cd ..
786 786
787 787 #if repobundlerepo
788 788 $ cd orig
789 789 $ hg incoming ../bundle.hg
790 790 comparing with ../bundle.hg
791 791 searching for changes
792 792 changeset: 2:ed1b79f46b9a
793 793 tag: tip
794 794 parent: 0:bbd179dfa0a7
795 795 user: test
796 796 date: Thu Jan 01 00:00:00 1970 +0000
797 797 summary: change foo
798 798
799 799 $ cd ..
800 800
801 801 test bundle with # in the filename (issue2154):
802 802
803 803 $ cp bundle.hg 'test#bundle.hg'
804 804 $ cd orig
805 805 $ hg incoming '../test#bundle.hg'
806 806 comparing with ../test
807 807 abort: unknown revision 'bundle.hg'
808 808 [10]
809 809
810 810 note that percent encoding is not handled:
811 811
812 812 $ hg incoming ../test%23bundle.hg
813 813 abort: repository ../test%23bundle.hg not found
814 814 [255]
815 815 $ cd ..
816 816
817 817 #endif
818 818
819 819 test to bundle revisions on the newly created branch (issue3828):
820 820
821 821 $ hg -q clone -U test test-clone
822 822 $ cd test
823 823
824 824 $ hg -q branch foo
825 825 $ hg commit -m "create foo branch"
826 826 $ hg -q outgoing ../test-clone
827 827 9:b4f5acb1ee27
828 828 $ hg -q bundle --branch foo foo.hg ../test-clone
829 829 #if repobundlerepo
830 830 $ hg -R foo.hg -q log -r "bundle()"
831 831 9:b4f5acb1ee27
832 832 #endif
833 833
834 834 $ cd ..
835 835
836 836 test for https://bz.mercurial-scm.org/1144
837 837
838 838 test that verify bundle does not traceback
839 839
840 840 partial history bundle, fails w/ unknown parent
841 841
842 842 $ hg -R bundle.hg verify
843 843 abort: 00changelog@bbd179dfa0a71671c253b3ae0aa1513b60d199fa: unknown parent
844 844 [50]
845 845
846 846 full history bundle, refuses to verify non-local repo
847 847
848 848 #if repobundlerepo
849 849 $ hg -R all.hg verify
850 850 abort: cannot verify bundle or remote repos
851 851 [255]
852 852 #endif
853 853
854 854 but, regular verify must continue to work
855 855
856 856 $ hg -R orig verify
857 857 checking changesets
858 858 checking manifests
859 859 crosschecking files in changesets and manifests
860 860 checking files
861 861 checked 2 changesets with 2 changes to 2 files
862 862
863 863 #if repobundlerepo
864 864 diff against bundle
865 865
866 866 $ hg init b
867 867 $ cd b
868 868 $ hg -R ../all.hg diff -r tip
869 869 diff -r aa35859c02ea anotherfile
870 870 --- a/anotherfile Thu Jan 01 00:00:00 1970 +0000
871 871 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
872 872 @@ -1,4 +0,0 @@
873 873 -0
874 874 -1
875 875 -2
876 876 -3
877 877 $ cd ..
878 878 #endif
879 879
880 880 bundle single branch
881 881
882 882 $ hg init branchy
883 883 $ cd branchy
884 884 $ echo a >a
885 885 $ echo x >x
886 886 $ hg ci -Ama
887 887 adding a
888 888 adding x
889 889 $ echo c >c
890 890 $ echo xx >x
891 891 $ hg ci -Amc
892 892 adding c
893 893 $ echo c1 >c1
894 894 $ hg ci -Amc1
895 895 adding c1
896 896 $ hg up 0
897 897 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
898 898 $ echo b >b
899 899 $ hg ci -Amb
900 900 adding b
901 901 created new head
902 902 $ echo b1 >b1
903 903 $ echo xx >x
904 904 $ hg ci -Amb1
905 905 adding b1
906 906 $ hg clone -q -r2 . part
907 907
908 908 == bundling via incoming
909 909
910 910 $ hg in -R part --bundle incoming.hg --template "{node}\n" .
911 911 comparing with .
912 912 searching for changes
913 913 1a38c1b849e8b70c756d2d80b0b9a3ac0b7ea11a
914 914 057f4db07f61970e1c11e83be79e9d08adc4dc31
915 915
916 916 == bundling
917 917
918 918 $ hg bundle bundle.hg part --debug --config progress.debug=true
919 919 query 1; heads
920 920 searching for changes
921 921 all remote heads known locally
922 922 2 changesets found
923 923 list of changesets:
924 924 1a38c1b849e8b70c756d2d80b0b9a3ac0b7ea11a
925 925 057f4db07f61970e1c11e83be79e9d08adc4dc31
926 926 bundle2-output-bundle: "HG20", (1 params) 2 parts total
927 927 bundle2-output-part: "changegroup" (params: 1 mandatory 1 advisory) streamed payload
928 928 changesets: 1/2 chunks (50.00%)
929 929 changesets: 2/2 chunks (100.00%)
930 930 manifests: 1/2 chunks (50.00%)
931 931 manifests: 2/2 chunks (100.00%)
932 932 files: b 1/3 files (33.33%)
933 933 files: b1 2/3 files (66.67%)
934 934 files: x 3/3 files (100.00%)
935 935 bundle2-output-part: "cache:rev-branch-cache" (advisory) streamed payload
936 936
937 937 #if repobundlerepo
938 938 == Test for issue3441
939 939
940 940 $ hg clone -q -r0 . part2
941 941 $ hg -q -R part2 pull bundle.hg
942 942 $ hg -R part2 verify
943 943 checking changesets
944 944 checking manifests
945 945 crosschecking files in changesets and manifests
946 946 checking files
947 947 checked 3 changesets with 5 changes to 4 files
948 948 #endif
949 949
950 950 == Test bundling no commits
951 951
952 952 $ hg bundle -r 'public()' no-output.hg
953 953 abort: no commits to bundle
954 954 [10]
955 955
956 956 $ cd ..
957 957
958 958 When user merges to the revision existing only in the bundle,
959 959 it should show warning that second parent of the working
960 960 directory does not exist
961 961
962 962 $ hg init update2bundled
963 963 $ cd update2bundled
964 964 $ cat <<EOF >> .hg/hgrc
965 965 > [extensions]
966 966 > strip =
967 967 > EOF
968 968 $ echo "aaa" >> a
969 969 $ hg commit -A -m 0
970 970 adding a
971 971 $ echo "bbb" >> b
972 972 $ hg commit -A -m 1
973 973 adding b
974 974 $ echo "ccc" >> c
975 975 $ hg commit -A -m 2
976 976 adding c
977 977 $ hg update -r 1
978 978 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
979 979 $ echo "ddd" >> d
980 980 $ hg commit -A -m 3
981 981 adding d
982 982 created new head
983 983 $ hg update -r 2
984 984 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
985 985 $ hg log -G
986 986 o changeset: 3:8bd3e1f196af
987 987 | tag: tip
988 988 | parent: 1:a01eca7af26d
989 989 | user: test
990 990 | date: Thu Jan 01 00:00:00 1970 +0000
991 991 | summary: 3
992 992 |
993 993 | @ changeset: 2:4652c276ac4f
994 994 |/ user: test
995 995 | date: Thu Jan 01 00:00:00 1970 +0000
996 996 | summary: 2
997 997 |
998 998 o changeset: 1:a01eca7af26d
999 999 | user: test
1000 1000 | date: Thu Jan 01 00:00:00 1970 +0000
1001 1001 | summary: 1
1002 1002 |
1003 1003 o changeset: 0:4fe08cd4693e
1004 1004 user: test
1005 1005 date: Thu Jan 01 00:00:00 1970 +0000
1006 1006 summary: 0
1007 1007
1008 1008
1009 1009 #if repobundlerepo
1010 1010 $ hg bundle --base 1 -r 3 ../update2bundled.hg
1011 1011 1 changesets found
1012 1012 $ hg strip -r 3
1013 1013 saved backup bundle to $TESTTMP/update2bundled/.hg/strip-backup/8bd3e1f196af-017e56d8-backup.hg
1014 1014 $ hg merge -R ../update2bundled.hg -r 3
1015 1015 setting parent to node 8bd3e1f196af289b2b121be08031e76d7ae92098 that only exists in the bundle
1016 1016 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1017 1017 (branch merge, don't forget to commit)
1018 1018
1019 1019 When user updates to the revision existing only in the bundle,
1020 1020 it should show warning
1021 1021
1022 1022 $ hg update -R ../update2bundled.hg --clean -r 3
1023 1023 setting parent to node 8bd3e1f196af289b2b121be08031e76d7ae92098 that only exists in the bundle
1024 1024 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1025 1025
1026 1026 When user updates to the revision existing in the local repository
1027 1027 the warning shouldn't be emitted
1028 1028
1029 1029 $ hg update -R ../update2bundled.hg -r 0
1030 1030 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1031 1031 #endif
1032 1032
1033 1033 Test the option that create slim bundle
1034 1034
1035 1035 $ hg bundle -a --config devel.bundle.delta=p1 ./slim.hg
1036 1036 3 changesets found
1037 1037
1038 1038 Test the option that create and no-delta's bundle
1039 1039 $ hg bundle -a --config devel.bundle.delta=full ./full.hg
1040 1040 3 changesets found
1041 1041
1042 1042 Test the debug output when applying delta
1043 1043 -----------------------------------------
1044 1044
1045 1045 $ hg init foo
1046 1046 $ hg -R foo unbundle ./slim.hg \
1047 1047 > --config debug.revlog.debug-delta=yes \
1048 1048 > --config storage.revlog.reuse-external-delta=no \
1049 1049 > --config storage.revlog.reuse-external-delta-parent=no
1050 1050 adding changesets
1051 1051 DBG-DELTAS: CHANGELOG: rev=0: search-rounds=0 try-count=0 - delta-type=full snap-depth=0 - p1-chain-length=-1 p2-chain-length=-1 - duration=* (glob)
1052 1052 DBG-DELTAS: CHANGELOG: rev=1: search-rounds=0 try-count=0 - delta-type=full snap-depth=0 - p1-chain-length=0 p2-chain-length=-1 - duration=* (glob)
1053 1053 DBG-DELTAS: CHANGELOG: rev=2: search-rounds=0 try-count=0 - delta-type=full snap-depth=0 - p1-chain-length=0 p2-chain-length=-1 - duration=* (glob)
1054 1054 adding manifests
1055 1055 DBG-DELTAS: MANIFESTLOG: rev=0: search-rounds=0 try-count=0 - delta-type=full snap-depth=0 - p1-chain-length=-1 p2-chain-length=-1 - duration=* (glob)
1056 1056 DBG-DELTAS: MANIFESTLOG: rev=1: search-rounds=1 try-count=1 - delta-type=delta snap-depth=0 - p1-chain-length=0 p2-chain-length=-1 - duration=* (glob)
1057 1057 DBG-DELTAS: MANIFESTLOG: rev=2: search-rounds=1 try-count=1 - delta-type=delta snap-depth=0 - p1-chain-length=1 p2-chain-length=-1 - duration=* (glob)
1058 1058 adding file changes
1059 1059 DBG-DELTAS: FILELOG:a: rev=0: search-rounds=0 try-count=0 - delta-type=full snap-depth=0 - p1-chain-length=-1 p2-chain-length=-1 - duration=* (glob)
1060 1060 DBG-DELTAS: FILELOG:b: rev=0: search-rounds=0 try-count=0 - delta-type=full snap-depth=0 - p1-chain-length=-1 p2-chain-length=-1 - duration=* (glob)
1061 1061 DBG-DELTAS: FILELOG:c: rev=0: search-rounds=0 try-count=0 - delta-type=full snap-depth=0 - p1-chain-length=-1 p2-chain-length=-1 - duration=* (glob)
1062 1062 added 3 changesets with 3 changes to 3 files
1063 1063 new changesets 4fe08cd4693e:4652c276ac4f (3 drafts)
1064 1064 (run 'hg update' to get a working copy)
1065 1065
@@ -1,449 +1,449 b''
1 1 Show all commands except debug commands
2 2 $ hg debugcomplete
3 3 abort
4 4 add
5 5 addremove
6 6 annotate
7 7 archive
8 8 backout
9 9 bisect
10 10 bookmarks
11 11 branch
12 12 branches
13 13 bundle
14 14 cat
15 15 clone
16 16 commit
17 17 config
18 18 continue
19 19 copy
20 20 diff
21 21 export
22 22 files
23 23 forget
24 24 graft
25 25 grep
26 26 heads
27 27 help
28 28 identify
29 29 import
30 30 incoming
31 31 init
32 32 locate
33 33 log
34 34 manifest
35 35 merge
36 36 outgoing
37 37 parents
38 38 paths
39 39 phase
40 40 pull
41 41 purge
42 42 push
43 43 recover
44 44 remove
45 45 rename
46 46 resolve
47 47 revert
48 48 rollback
49 49 root
50 50 serve
51 51 shelve
52 52 status
53 53 summary
54 54 tag
55 55 tags
56 56 tip
57 57 unbundle
58 58 unshelve
59 59 update
60 60 verify
61 61 version
62 62
63 63 Show all commands that start with "a"
64 64 $ hg debugcomplete a
65 65 abort
66 66 add
67 67 addremove
68 68 annotate
69 69 archive
70 70
71 71 Do not show debug commands if there are other candidates
72 72 $ hg debugcomplete d
73 73 diff
74 74
75 75 Show debug commands if there are no other candidates
76 76 $ hg debugcomplete debug
77 77 debug-delta-find
78 78 debug-repair-issue6528
79 79 debug-revlog-index
80 80 debugancestor
81 81 debugantivirusrunning
82 82 debugapplystreamclonebundle
83 83 debugbackupbundle
84 84 debugbuilddag
85 85 debugbundle
86 86 debugcapabilities
87 87 debugchangedfiles
88 88 debugcheckstate
89 89 debugcolor
90 90 debugcommands
91 91 debugcomplete
92 92 debugconfig
93 93 debugcreatestreamclonebundle
94 94 debugdag
95 95 debugdata
96 96 debugdate
97 97 debugdeltachain
98 98 debugdirstate
99 99 debugdirstateignorepatternshash
100 100 debugdiscovery
101 101 debugdownload
102 102 debugextensions
103 103 debugfileset
104 104 debugformat
105 105 debugfsinfo
106 106 debuggetbundle
107 107 debugignore
108 108 debugindexdot
109 109 debugindexstats
110 110 debuginstall
111 111 debugknown
112 112 debuglabelcomplete
113 113 debuglocks
114 114 debugmanifestfulltextcache
115 115 debugmergestate
116 116 debugnamecomplete
117 117 debugnodemap
118 118 debugobsolete
119 119 debugp1copies
120 120 debugp2copies
121 121 debugpathcomplete
122 122 debugpathcopies
123 123 debugpeer
124 124 debugpickmergetool
125 125 debugpushkey
126 126 debugpvec
127 127 debugrebuilddirstate
128 128 debugrebuildfncache
129 129 debugrename
130 130 debugrequires
131 131 debugrevlog
132 132 debugrevlogindex
133 133 debugrevspec
134 134 debugserve
135 135 debugsetparents
136 136 debugshell
137 137 debugsidedata
138 138 debugssl
139 139 debugstrip
140 140 debugsub
141 141 debugsuccessorssets
142 142 debugtagscache
143 143 debugtemplate
144 144 debuguigetpass
145 145 debuguiprompt
146 146 debugupdatecaches
147 147 debugupgraderepo
148 148 debugwalk
149 149 debugwhyunstable
150 150 debugwireargs
151 151 debugwireproto
152 152
153 153 Do not show the alias of a debug command if there are other candidates
154 154 (this should hide rawcommit)
155 155 $ hg debugcomplete r
156 156 recover
157 157 remove
158 158 rename
159 159 resolve
160 160 revert
161 161 rollback
162 162 root
163 163 Show the alias of a debug command if there are no other candidates
164 164 $ hg debugcomplete rawc
165 165
166 166
167 167 Show the global options
168 168 $ hg debugcomplete --options | sort
169 169 --color
170 170 --config
171 171 --cwd
172 172 --debug
173 173 --debugger
174 174 --encoding
175 175 --encodingmode
176 176 --help
177 177 --hidden
178 178 --noninteractive
179 179 --pager
180 180 --profile
181 181 --quiet
182 182 --repository
183 183 --time
184 184 --traceback
185 185 --verbose
186 186 --version
187 187 -R
188 188 -h
189 189 -q
190 190 -v
191 191 -y
192 192
193 193 Show the options for the "serve" command
194 194 $ hg debugcomplete --options serve | sort
195 195 --accesslog
196 196 --address
197 197 --certificate
198 198 --cmdserver
199 199 --color
200 200 --config
201 201 --cwd
202 202 --daemon
203 203 --daemon-postexec
204 204 --debug
205 205 --debugger
206 206 --encoding
207 207 --encodingmode
208 208 --errorlog
209 209 --help
210 210 --hidden
211 211 --ipv6
212 212 --name
213 213 --noninteractive
214 214 --pager
215 215 --pid-file
216 216 --port
217 217 --prefix
218 218 --print-url
219 219 --profile
220 220 --quiet
221 221 --repository
222 222 --stdio
223 223 --style
224 224 --subrepos
225 225 --templates
226 226 --time
227 227 --traceback
228 228 --verbose
229 229 --version
230 230 --web-conf
231 231 -6
232 232 -A
233 233 -E
234 234 -R
235 235 -S
236 236 -a
237 237 -d
238 238 -h
239 239 -n
240 240 -p
241 241 -q
242 242 -t
243 243 -v
244 244 -y
245 245
246 246 Show an error if we use --options with an ambiguous abbreviation
247 247 $ hg debugcomplete --options s
248 248 hg: command 's' is ambiguous:
249 249 serve shelve showconfig status summary
250 250 [10]
251 251
252 252 Show all commands + options
253 253 $ hg debugcommands
254 254 abort: dry-run
255 255 add: include, exclude, subrepos, dry-run
256 256 addremove: similarity, subrepos, include, exclude, dry-run
257 257 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
258 258 archive: no-decode, prefix, rev, type, subrepos, include, exclude
259 259 backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
260 260 bisect: reset, good, bad, skip, extend, command, noupdate
261 261 bookmarks: force, rev, delete, rename, inactive, list, template
262 262 branch: force, clean, rev
263 263 branches: active, closed, rev, template
264 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
264 bundle: exact, force, rev, branch, base, all, type, ssh, remotecmd, insecure
265 265 cat: output, rev, decode, include, exclude, template
266 266 clone: noupdate, updaterev, rev, branch, pull, uncompressed, stream, ssh, remotecmd, insecure
267 267 commit: addremove, close-branch, amend, secret, edit, force-close-branch, interactive, include, exclude, message, logfile, date, user, subrepos
268 268 config: untrusted, exp-all-known, edit, local, source, shared, non-shared, global, template
269 269 continue: dry-run
270 270 copy: forget, after, at-rev, force, include, exclude, dry-run
271 271 debug-delta-find: changelog, manifest, dir, template
272 272 debug-repair-issue6528: to-report, from-report, paranoid, dry-run
273 273 debug-revlog-index: changelog, manifest, dir, template
274 274 debugancestor:
275 275 debugantivirusrunning:
276 276 debugapplystreamclonebundle:
277 277 debugbackupbundle: recover, patch, git, limit, no-merges, stat, graph, style, template
278 278 debugbuilddag: mergeable-file, overwritten-file, new-file, from-existing
279 279 debugbundle: all, part-type, spec
280 280 debugcapabilities:
281 281 debugchangedfiles: compute
282 282 debugcheckstate:
283 283 debugcolor: style
284 284 debugcommands:
285 285 debugcomplete: options
286 286 debugcreatestreamclonebundle:
287 287 debugdag: tags, branches, dots, spaces
288 288 debugdata: changelog, manifest, dir
289 289 debugdate: extended
290 290 debugdeltachain: changelog, manifest, dir, template
291 291 debugdirstateignorepatternshash:
292 292 debugdirstate: nodates, dates, datesort, docket, all
293 293 debugdiscovery: old, nonheads, rev, seed, local-as-revs, remote-as-revs, ssh, remotecmd, insecure, template
294 294 debugdownload: output
295 295 debugextensions: template
296 296 debugfileset: rev, all-files, show-matcher, show-stage
297 297 debugformat: template
298 298 debugfsinfo:
299 299 debuggetbundle: head, common, type
300 300 debugignore:
301 301 debugindexdot: changelog, manifest, dir
302 302 debugindexstats:
303 303 debuginstall: template
304 304 debugknown:
305 305 debuglabelcomplete:
306 306 debuglocks: force-free-lock, force-free-wlock, set-lock, set-wlock
307 307 debugmanifestfulltextcache: clear, add
308 308 debugmergestate: style, template
309 309 debugnamecomplete:
310 310 debugnodemap: dump-new, dump-disk, check, metadata
311 311 debugobsolete: flags, record-parents, rev, exclusive, index, delete, date, user, template
312 312 debugp1copies: rev
313 313 debugp2copies: rev
314 314 debugpathcomplete: full, normal, added, removed
315 315 debugpathcopies: include, exclude
316 316 debugpeer:
317 317 debugpickmergetool: rev, changedelete, include, exclude, tool
318 318 debugpushkey:
319 319 debugpvec:
320 320 debugrebuilddirstate: rev, minimal
321 321 debugrebuildfncache: only-data
322 322 debugrename: rev
323 323 debugrequires:
324 324 debugrevlog: changelog, manifest, dir, dump
325 325 debugrevlogindex: changelog, manifest, dir, format
326 326 debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized
327 327 debugserve: sshstdio, logiofd, logiofile
328 328 debugsetparents:
329 329 debugshell:
330 330 debugsidedata: changelog, manifest, dir
331 331 debugssl:
332 332 debugstrip: rev, force, no-backup, nobackup, , keep, bookmark, soft
333 333 debugsub: rev
334 334 debugsuccessorssets: closest
335 335 debugtagscache:
336 336 debugtemplate: rev, define
337 337 debuguigetpass: prompt
338 338 debuguiprompt: prompt
339 339 debugupdatecaches:
340 340 debugupgraderepo: optimize, run, backup, changelog, manifest, filelogs
341 341 debugwalk: include, exclude
342 342 debugwhyunstable:
343 343 debugwireargs: three, four, five, ssh, remotecmd, insecure
344 344 debugwireproto: localssh, peer, noreadstderr, nologhandshake, ssh, remotecmd, insecure
345 345 diff: rev, from, to, 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
346 346 export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
347 347 files: rev, print0, include, exclude, template, subrepos
348 348 forget: interactive, include, exclude, dry-run
349 349 graft: rev, base, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
350 350 grep: print0, all, diff, text, follow, ignore-case, files-with-matches, line-number, rev, all-files, user, date, template, include, exclude
351 351 heads: rev, topo, active, closed, style, template
352 352 help: extension, command, keyword, system
353 353 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure, template
354 354 import: strip, base, secret, edit, force, no-commit, bypass, partial, exact, prefix, import-branch, message, logfile, date, user, similarity
355 355 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
356 356 init: ssh, remotecmd, insecure
357 357 locate: rev, print0, fullpath, include, exclude
358 358 log: follow, follow-first, date, copies, keyword, rev, line-range, removed, only-merges, user, only-branch, branch, bookmark, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
359 359 manifest: rev, all, template
360 360 merge: force, rev, preview, abort, tool
361 361 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
362 362 parents: rev, style, template
363 363 paths: template
364 364 phase: public, draft, secret, force, rev
365 365 pull: update, force, confirm, rev, bookmark, branch, ssh, remotecmd, insecure
366 366 purge: abort-on-err, all, ignored, dirs, files, print, print0, confirm, include, exclude
367 367 push: force, rev, bookmark, all-bookmarks, branch, new-branch, pushvars, publish, ssh, remotecmd, insecure
368 368 recover: verify
369 369 remove: after, force, subrepos, include, exclude, dry-run
370 370 rename: forget, after, at-rev, force, include, exclude, dry-run
371 371 resolve: all, list, mark, unmark, no-status, re-merge, tool, include, exclude, template
372 372 revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
373 373 rollback: dry-run, force
374 374 root: template
375 375 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
376 376 shelve: addremove, unknown, cleanup, date, delete, edit, keep, list, message, name, patch, interactive, stat, include, exclude
377 377 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, terse, copies, print0, rev, change, include, exclude, subrepos, template
378 378 summary: remote
379 379 tag: force, local, rev, remove, edit, message, date, user
380 380 tags: template
381 381 tip: patch, git, style, template
382 382 unbundle: update
383 383 unshelve: abort, continue, interactive, keep, name, tool, date
384 384 update: clean, check, merge, date, rev, tool
385 385 verify: full
386 386 version: template
387 387
388 388 $ hg init a
389 389 $ cd a
390 390 $ echo fee > fee
391 391 $ hg ci -q -Amfee
392 392 $ hg tag fee
393 393 $ mkdir fie
394 394 $ echo dead > fie/dead
395 395 $ echo live > fie/live
396 396 $ hg bookmark fo
397 397 $ hg branch -q fie
398 398 $ hg ci -q -Amfie
399 399 $ echo fo > fo
400 400 $ hg branch -qf default
401 401 $ hg ci -q -Amfo
402 402 $ echo Fum > Fum
403 403 $ hg ci -q -AmFum
404 404 $ hg bookmark Fum
405 405
406 406 Test debugpathcomplete
407 407
408 408 $ hg debugpathcomplete f
409 409 fee
410 410 fie
411 411 fo
412 412 $ hg debugpathcomplete -f f
413 413 fee
414 414 fie/dead
415 415 fie/live
416 416 fo
417 417
418 418 $ hg rm Fum
419 419 $ hg debugpathcomplete -r F
420 420 Fum
421 421
422 422 Test debugnamecomplete
423 423
424 424 $ hg debugnamecomplete
425 425 Fum
426 426 default
427 427 fee
428 428 fie
429 429 fo
430 430 tip
431 431 $ hg debugnamecomplete f
432 432 fee
433 433 fie
434 434 fo
435 435
436 436 Test debuglabelcomplete, a deprecated name for debugnamecomplete that is still
437 437 used for completions in some shells.
438 438
439 439 $ hg debuglabelcomplete
440 440 Fum
441 441 default
442 442 fee
443 443 fie
444 444 fo
445 445 tip
446 446 $ hg debuglabelcomplete f
447 447 fee
448 448 fie
449 449 fo
General Comments 0
You need to be logged in to leave comments. Login now