##// END OF EJS Templates
commit: return 1 for interactive commit with no changes (issue5397)...
Philippe Pepiot -
r30157:df224038 default
parent child Browse files
Show More
@@ -1,7346 +1,7348 b''
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import difflib
11 11 import errno
12 12 import operator
13 13 import os
14 14 import random
15 15 import re
16 16 import shlex
17 17 import socket
18 18 import sys
19 19 import tempfile
20 20 import time
21 21
22 22 from .i18n import _
23 23 from .node import (
24 24 bin,
25 25 hex,
26 26 nullhex,
27 27 nullid,
28 28 nullrev,
29 29 short,
30 30 )
31 31 from . import (
32 32 archival,
33 33 bookmarks,
34 34 bundle2,
35 35 changegroup,
36 36 cmdutil,
37 37 commandserver,
38 38 context,
39 39 copies,
40 40 dagparser,
41 41 dagutil,
42 42 destutil,
43 43 discovery,
44 44 encoding,
45 45 error,
46 46 exchange,
47 47 extensions,
48 48 fileset,
49 49 formatter,
50 50 graphmod,
51 51 hbisect,
52 52 help,
53 53 hg,
54 54 hgweb,
55 55 localrepo,
56 56 lock as lockmod,
57 57 merge as mergemod,
58 58 minirst,
59 59 obsolete,
60 60 patch,
61 61 phases,
62 62 policy,
63 63 pvec,
64 64 repair,
65 65 revlog,
66 66 revset,
67 67 scmutil,
68 68 setdiscovery,
69 69 simplemerge,
70 70 sshserver,
71 71 streamclone,
72 72 templatekw,
73 73 templater,
74 74 treediscovery,
75 75 ui as uimod,
76 76 util,
77 77 )
78 78
79 79 release = lockmod.release
80 80
81 81 table = {}
82 82
83 83 command = cmdutil.command(table)
84 84
85 85 # label constants
86 86 # until 3.5, bookmarks.current was the advertised name, not
87 87 # bookmarks.active, so we must use both to avoid breaking old
88 88 # custom styles
89 89 activebookmarklabel = 'bookmarks.active bookmarks.current'
90 90
91 91 # common command options
92 92
93 93 globalopts = [
94 94 ('R', 'repository', '',
95 95 _('repository root directory or name of overlay bundle file'),
96 96 _('REPO')),
97 97 ('', 'cwd', '',
98 98 _('change working directory'), _('DIR')),
99 99 ('y', 'noninteractive', None,
100 100 _('do not prompt, automatically pick the first choice for all prompts')),
101 101 ('q', 'quiet', None, _('suppress output')),
102 102 ('v', 'verbose', None, _('enable additional output')),
103 103 ('', 'config', [],
104 104 _('set/override config option (use \'section.name=value\')'),
105 105 _('CONFIG')),
106 106 ('', 'debug', None, _('enable debugging output')),
107 107 ('', 'debugger', None, _('start debugger')),
108 108 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
109 109 _('ENCODE')),
110 110 ('', 'encodingmode', encoding.encodingmode,
111 111 _('set the charset encoding mode'), _('MODE')),
112 112 ('', 'traceback', None, _('always print a traceback on exception')),
113 113 ('', 'time', None, _('time how long the command takes')),
114 114 ('', 'profile', None, _('print command execution profile')),
115 115 ('', 'version', None, _('output version information and exit')),
116 116 ('h', 'help', None, _('display help and exit')),
117 117 ('', 'hidden', False, _('consider hidden changesets')),
118 118 ]
119 119
120 120 dryrunopts = [('n', 'dry-run', None,
121 121 _('do not perform actions, just print output'))]
122 122
123 123 remoteopts = [
124 124 ('e', 'ssh', '',
125 125 _('specify ssh command to use'), _('CMD')),
126 126 ('', 'remotecmd', '',
127 127 _('specify hg command to run on the remote side'), _('CMD')),
128 128 ('', 'insecure', None,
129 129 _('do not verify server certificate (ignoring web.cacerts config)')),
130 130 ]
131 131
132 132 walkopts = [
133 133 ('I', 'include', [],
134 134 _('include names matching the given patterns'), _('PATTERN')),
135 135 ('X', 'exclude', [],
136 136 _('exclude names matching the given patterns'), _('PATTERN')),
137 137 ]
138 138
139 139 commitopts = [
140 140 ('m', 'message', '',
141 141 _('use text as commit message'), _('TEXT')),
142 142 ('l', 'logfile', '',
143 143 _('read commit message from file'), _('FILE')),
144 144 ]
145 145
146 146 commitopts2 = [
147 147 ('d', 'date', '',
148 148 _('record the specified date as commit date'), _('DATE')),
149 149 ('u', 'user', '',
150 150 _('record the specified user as committer'), _('USER')),
151 151 ]
152 152
153 153 # hidden for now
154 154 formatteropts = [
155 155 ('T', 'template', '',
156 156 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
157 157 ]
158 158
159 159 templateopts = [
160 160 ('', 'style', '',
161 161 _('display using template map file (DEPRECATED)'), _('STYLE')),
162 162 ('T', 'template', '',
163 163 _('display with template'), _('TEMPLATE')),
164 164 ]
165 165
166 166 logopts = [
167 167 ('p', 'patch', None, _('show patch')),
168 168 ('g', 'git', None, _('use git extended diff format')),
169 169 ('l', 'limit', '',
170 170 _('limit number of changes displayed'), _('NUM')),
171 171 ('M', 'no-merges', None, _('do not show merges')),
172 172 ('', 'stat', None, _('output diffstat-style summary of changes')),
173 173 ('G', 'graph', None, _("show the revision DAG")),
174 174 ] + templateopts
175 175
176 176 diffopts = [
177 177 ('a', 'text', None, _('treat all files as text')),
178 178 ('g', 'git', None, _('use git extended diff format')),
179 179 ('', 'nodates', None, _('omit dates from diff headers'))
180 180 ]
181 181
182 182 diffwsopts = [
183 183 ('w', 'ignore-all-space', None,
184 184 _('ignore white space when comparing lines')),
185 185 ('b', 'ignore-space-change', None,
186 186 _('ignore changes in the amount of white space')),
187 187 ('B', 'ignore-blank-lines', None,
188 188 _('ignore changes whose lines are all blank')),
189 189 ]
190 190
191 191 diffopts2 = [
192 192 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
193 193 ('p', 'show-function', None, _('show which function each change is in')),
194 194 ('', 'reverse', None, _('produce a diff that undoes the changes')),
195 195 ] + diffwsopts + [
196 196 ('U', 'unified', '',
197 197 _('number of lines of context to show'), _('NUM')),
198 198 ('', 'stat', None, _('output diffstat-style summary of changes')),
199 199 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
200 200 ]
201 201
202 202 mergetoolopts = [
203 203 ('t', 'tool', '', _('specify merge tool')),
204 204 ]
205 205
206 206 similarityopts = [
207 207 ('s', 'similarity', '',
208 208 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
209 209 ]
210 210
211 211 subrepoopts = [
212 212 ('S', 'subrepos', None,
213 213 _('recurse into subrepositories'))
214 214 ]
215 215
216 216 debugrevlogopts = [
217 217 ('c', 'changelog', False, _('open changelog')),
218 218 ('m', 'manifest', False, _('open manifest')),
219 219 ('', 'dir', '', _('open directory manifest')),
220 220 ]
221 221
222 222 # Commands start here, listed alphabetically
223 223
224 224 @command('^add',
225 225 walkopts + subrepoopts + dryrunopts,
226 226 _('[OPTION]... [FILE]...'),
227 227 inferrepo=True)
228 228 def add(ui, repo, *pats, **opts):
229 229 """add the specified files on the next commit
230 230
231 231 Schedule files to be version controlled and added to the
232 232 repository.
233 233
234 234 The files will be added to the repository at the next commit. To
235 235 undo an add before that, see :hg:`forget`.
236 236
237 237 If no names are given, add all files to the repository (except
238 238 files matching ``.hgignore``).
239 239
240 240 .. container:: verbose
241 241
242 242 Examples:
243 243
244 244 - New (unknown) files are added
245 245 automatically by :hg:`add`::
246 246
247 247 $ ls
248 248 foo.c
249 249 $ hg status
250 250 ? foo.c
251 251 $ hg add
252 252 adding foo.c
253 253 $ hg status
254 254 A foo.c
255 255
256 256 - Specific files to be added can be specified::
257 257
258 258 $ ls
259 259 bar.c foo.c
260 260 $ hg status
261 261 ? bar.c
262 262 ? foo.c
263 263 $ hg add bar.c
264 264 $ hg status
265 265 A bar.c
266 266 ? foo.c
267 267
268 268 Returns 0 if all files are successfully added.
269 269 """
270 270
271 271 m = scmutil.match(repo[None], pats, opts)
272 272 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
273 273 return rejected and 1 or 0
274 274
275 275 @command('addremove',
276 276 similarityopts + subrepoopts + walkopts + dryrunopts,
277 277 _('[OPTION]... [FILE]...'),
278 278 inferrepo=True)
279 279 def addremove(ui, repo, *pats, **opts):
280 280 """add all new files, delete all missing files
281 281
282 282 Add all new files and remove all missing files from the
283 283 repository.
284 284
285 285 Unless names are given, new files are ignored if they match any of
286 286 the patterns in ``.hgignore``. As with add, these changes take
287 287 effect at the next commit.
288 288
289 289 Use the -s/--similarity option to detect renamed files. This
290 290 option takes a percentage between 0 (disabled) and 100 (files must
291 291 be identical) as its parameter. With a parameter greater than 0,
292 292 this compares every removed file with every added file and records
293 293 those similar enough as renames. Detecting renamed files this way
294 294 can be expensive. After using this option, :hg:`status -C` can be
295 295 used to check which files were identified as moved or renamed. If
296 296 not specified, -s/--similarity defaults to 100 and only renames of
297 297 identical files are detected.
298 298
299 299 .. container:: verbose
300 300
301 301 Examples:
302 302
303 303 - A number of files (bar.c and foo.c) are new,
304 304 while foobar.c has been removed (without using :hg:`remove`)
305 305 from the repository::
306 306
307 307 $ ls
308 308 bar.c foo.c
309 309 $ hg status
310 310 ! foobar.c
311 311 ? bar.c
312 312 ? foo.c
313 313 $ hg addremove
314 314 adding bar.c
315 315 adding foo.c
316 316 removing foobar.c
317 317 $ hg status
318 318 A bar.c
319 319 A foo.c
320 320 R foobar.c
321 321
322 322 - A file foobar.c was moved to foo.c without using :hg:`rename`.
323 323 Afterwards, it was edited slightly::
324 324
325 325 $ ls
326 326 foo.c
327 327 $ hg status
328 328 ! foobar.c
329 329 ? foo.c
330 330 $ hg addremove --similarity 90
331 331 removing foobar.c
332 332 adding foo.c
333 333 recording removal of foobar.c as rename to foo.c (94% similar)
334 334 $ hg status -C
335 335 A foo.c
336 336 foobar.c
337 337 R foobar.c
338 338
339 339 Returns 0 if all files are successfully added.
340 340 """
341 341 try:
342 342 sim = float(opts.get('similarity') or 100)
343 343 except ValueError:
344 344 raise error.Abort(_('similarity must be a number'))
345 345 if sim < 0 or sim > 100:
346 346 raise error.Abort(_('similarity must be between 0 and 100'))
347 347 matcher = scmutil.match(repo[None], pats, opts)
348 348 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
349 349
350 350 @command('^annotate|blame',
351 351 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
352 352 ('', 'follow', None,
353 353 _('follow copies/renames and list the filename (DEPRECATED)')),
354 354 ('', 'no-follow', None, _("don't follow copies and renames")),
355 355 ('a', 'text', None, _('treat all files as text')),
356 356 ('u', 'user', None, _('list the author (long with -v)')),
357 357 ('f', 'file', None, _('list the filename')),
358 358 ('d', 'date', None, _('list the date (short with -q)')),
359 359 ('n', 'number', None, _('list the revision number (default)')),
360 360 ('c', 'changeset', None, _('list the changeset')),
361 361 ('l', 'line-number', None, _('show line number at the first appearance'))
362 362 ] + diffwsopts + walkopts + formatteropts,
363 363 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
364 364 inferrepo=True)
365 365 def annotate(ui, repo, *pats, **opts):
366 366 """show changeset information by line for each file
367 367
368 368 List changes in files, showing the revision id responsible for
369 369 each line.
370 370
371 371 This command is useful for discovering when a change was made and
372 372 by whom.
373 373
374 374 If you include --file, --user, or --date, the revision number is
375 375 suppressed unless you also include --number.
376 376
377 377 Without the -a/--text option, annotate will avoid processing files
378 378 it detects as binary. With -a, annotate will annotate the file
379 379 anyway, although the results will probably be neither useful
380 380 nor desirable.
381 381
382 382 Returns 0 on success.
383 383 """
384 384 if not pats:
385 385 raise error.Abort(_('at least one filename or pattern is required'))
386 386
387 387 if opts.get('follow'):
388 388 # --follow is deprecated and now just an alias for -f/--file
389 389 # to mimic the behavior of Mercurial before version 1.5
390 390 opts['file'] = True
391 391
392 392 ctx = scmutil.revsingle(repo, opts.get('rev'))
393 393
394 394 fm = ui.formatter('annotate', opts)
395 395 if ui.quiet:
396 396 datefunc = util.shortdate
397 397 else:
398 398 datefunc = util.datestr
399 399 if ctx.rev() is None:
400 400 def hexfn(node):
401 401 if node is None:
402 402 return None
403 403 else:
404 404 return fm.hexfunc(node)
405 405 if opts.get('changeset'):
406 406 # omit "+" suffix which is appended to node hex
407 407 def formatrev(rev):
408 408 if rev is None:
409 409 return '%d' % ctx.p1().rev()
410 410 else:
411 411 return '%d' % rev
412 412 else:
413 413 def formatrev(rev):
414 414 if rev is None:
415 415 return '%d+' % ctx.p1().rev()
416 416 else:
417 417 return '%d ' % rev
418 418 def formathex(hex):
419 419 if hex is None:
420 420 return '%s+' % fm.hexfunc(ctx.p1().node())
421 421 else:
422 422 return '%s ' % hex
423 423 else:
424 424 hexfn = fm.hexfunc
425 425 formatrev = formathex = str
426 426
427 427 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
428 428 ('number', ' ', lambda x: x[0].rev(), formatrev),
429 429 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
430 430 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
431 431 ('file', ' ', lambda x: x[0].path(), str),
432 432 ('line_number', ':', lambda x: x[1], str),
433 433 ]
434 434 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
435 435
436 436 if (not opts.get('user') and not opts.get('changeset')
437 437 and not opts.get('date') and not opts.get('file')):
438 438 opts['number'] = True
439 439
440 440 linenumber = opts.get('line_number') is not None
441 441 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
442 442 raise error.Abort(_('at least one of -n/-c is required for -l'))
443 443
444 444 if fm.isplain():
445 445 def makefunc(get, fmt):
446 446 return lambda x: fmt(get(x))
447 447 else:
448 448 def makefunc(get, fmt):
449 449 return get
450 450 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
451 451 if opts.get(op)]
452 452 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
453 453 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
454 454 if opts.get(op))
455 455
456 456 def bad(x, y):
457 457 raise error.Abort("%s: %s" % (x, y))
458 458
459 459 m = scmutil.match(ctx, pats, opts, badfn=bad)
460 460
461 461 follow = not opts.get('no_follow')
462 462 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
463 463 whitespace=True)
464 464 for abs in ctx.walk(m):
465 465 fctx = ctx[abs]
466 466 if not opts.get('text') and util.binary(fctx.data()):
467 467 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
468 468 continue
469 469
470 470 lines = fctx.annotate(follow=follow, linenumber=linenumber,
471 471 diffopts=diffopts)
472 472 if not lines:
473 473 continue
474 474 formats = []
475 475 pieces = []
476 476
477 477 for f, sep in funcmap:
478 478 l = [f(n) for n, dummy in lines]
479 479 if fm.isplain():
480 480 sizes = [encoding.colwidth(x) for x in l]
481 481 ml = max(sizes)
482 482 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
483 483 else:
484 484 formats.append(['%s' for x in l])
485 485 pieces.append(l)
486 486
487 487 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
488 488 fm.startitem()
489 489 fm.write(fields, "".join(f), *p)
490 490 fm.write('line', ": %s", l[1])
491 491
492 492 if not lines[-1][1].endswith('\n'):
493 493 fm.plain('\n')
494 494
495 495 fm.end()
496 496
497 497 @command('archive',
498 498 [('', 'no-decode', None, _('do not pass files through decoders')),
499 499 ('p', 'prefix', '', _('directory prefix for files in archive'),
500 500 _('PREFIX')),
501 501 ('r', 'rev', '', _('revision to distribute'), _('REV')),
502 502 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
503 503 ] + subrepoopts + walkopts,
504 504 _('[OPTION]... DEST'))
505 505 def archive(ui, repo, dest, **opts):
506 506 '''create an unversioned archive of a repository revision
507 507
508 508 By default, the revision used is the parent of the working
509 509 directory; use -r/--rev to specify a different revision.
510 510
511 511 The archive type is automatically detected based on file
512 512 extension (to override, use -t/--type).
513 513
514 514 .. container:: verbose
515 515
516 516 Examples:
517 517
518 518 - create a zip file containing the 1.0 release::
519 519
520 520 hg archive -r 1.0 project-1.0.zip
521 521
522 522 - create a tarball excluding .hg files::
523 523
524 524 hg archive project.tar.gz -X ".hg*"
525 525
526 526 Valid types are:
527 527
528 528 :``files``: a directory full of files (default)
529 529 :``tar``: tar archive, uncompressed
530 530 :``tbz2``: tar archive, compressed using bzip2
531 531 :``tgz``: tar archive, compressed using gzip
532 532 :``uzip``: zip archive, uncompressed
533 533 :``zip``: zip archive, compressed using deflate
534 534
535 535 The exact name of the destination archive or directory is given
536 536 using a format string; see :hg:`help export` for details.
537 537
538 538 Each member added to an archive file has a directory prefix
539 539 prepended. Use -p/--prefix to specify a format string for the
540 540 prefix. The default is the basename of the archive, with suffixes
541 541 removed.
542 542
543 543 Returns 0 on success.
544 544 '''
545 545
546 546 ctx = scmutil.revsingle(repo, opts.get('rev'))
547 547 if not ctx:
548 548 raise error.Abort(_('no working directory: please specify a revision'))
549 549 node = ctx.node()
550 550 dest = cmdutil.makefilename(repo, dest, node)
551 551 if os.path.realpath(dest) == repo.root:
552 552 raise error.Abort(_('repository root cannot be destination'))
553 553
554 554 kind = opts.get('type') or archival.guesskind(dest) or 'files'
555 555 prefix = opts.get('prefix')
556 556
557 557 if dest == '-':
558 558 if kind == 'files':
559 559 raise error.Abort(_('cannot archive plain files to stdout'))
560 560 dest = cmdutil.makefileobj(repo, dest)
561 561 if not prefix:
562 562 prefix = os.path.basename(repo.root) + '-%h'
563 563
564 564 prefix = cmdutil.makefilename(repo, prefix, node)
565 565 matchfn = scmutil.match(ctx, [], opts)
566 566 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
567 567 matchfn, prefix, subrepos=opts.get('subrepos'))
568 568
569 569 @command('backout',
570 570 [('', 'merge', None, _('merge with old dirstate parent after backout')),
571 571 ('', 'commit', None,
572 572 _('commit if no conflicts were encountered (DEPRECATED)')),
573 573 ('', 'no-commit', None, _('do not commit')),
574 574 ('', 'parent', '',
575 575 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
576 576 ('r', 'rev', '', _('revision to backout'), _('REV')),
577 577 ('e', 'edit', False, _('invoke editor on commit messages')),
578 578 ] + mergetoolopts + walkopts + commitopts + commitopts2,
579 579 _('[OPTION]... [-r] REV'))
580 580 def backout(ui, repo, node=None, rev=None, **opts):
581 581 '''reverse effect of earlier changeset
582 582
583 583 Prepare a new changeset with the effect of REV undone in the
584 584 current working directory. If no conflicts were encountered,
585 585 it will be committed immediately.
586 586
587 587 If REV is the parent of the working directory, then this new changeset
588 588 is committed automatically (unless --no-commit is specified).
589 589
590 590 .. note::
591 591
592 592 :hg:`backout` cannot be used to fix either an unwanted or
593 593 incorrect merge.
594 594
595 595 .. container:: verbose
596 596
597 597 Examples:
598 598
599 599 - Reverse the effect of the parent of the working directory.
600 600 This backout will be committed immediately::
601 601
602 602 hg backout -r .
603 603
604 604 - Reverse the effect of previous bad revision 23::
605 605
606 606 hg backout -r 23
607 607
608 608 - Reverse the effect of previous bad revision 23 and
609 609 leave changes uncommitted::
610 610
611 611 hg backout -r 23 --no-commit
612 612 hg commit -m "Backout revision 23"
613 613
614 614 By default, the pending changeset will have one parent,
615 615 maintaining a linear history. With --merge, the pending
616 616 changeset will instead have two parents: the old parent of the
617 617 working directory and a new child of REV that simply undoes REV.
618 618
619 619 Before version 1.7, the behavior without --merge was equivalent
620 620 to specifying --merge followed by :hg:`update --clean .` to
621 621 cancel the merge and leave the child of REV as a head to be
622 622 merged separately.
623 623
624 624 See :hg:`help dates` for a list of formats valid for -d/--date.
625 625
626 626 See :hg:`help revert` for a way to restore files to the state
627 627 of another revision.
628 628
629 629 Returns 0 on success, 1 if nothing to backout or there are unresolved
630 630 files.
631 631 '''
632 632 wlock = lock = None
633 633 try:
634 634 wlock = repo.wlock()
635 635 lock = repo.lock()
636 636 return _dobackout(ui, repo, node, rev, **opts)
637 637 finally:
638 638 release(lock, wlock)
639 639
640 640 def _dobackout(ui, repo, node=None, rev=None, **opts):
641 641 if opts.get('commit') and opts.get('no_commit'):
642 642 raise error.Abort(_("cannot use --commit with --no-commit"))
643 643 if opts.get('merge') and opts.get('no_commit'):
644 644 raise error.Abort(_("cannot use --merge with --no-commit"))
645 645
646 646 if rev and node:
647 647 raise error.Abort(_("please specify just one revision"))
648 648
649 649 if not rev:
650 650 rev = node
651 651
652 652 if not rev:
653 653 raise error.Abort(_("please specify a revision to backout"))
654 654
655 655 date = opts.get('date')
656 656 if date:
657 657 opts['date'] = util.parsedate(date)
658 658
659 659 cmdutil.checkunfinished(repo)
660 660 cmdutil.bailifchanged(repo)
661 661 node = scmutil.revsingle(repo, rev).node()
662 662
663 663 op1, op2 = repo.dirstate.parents()
664 664 if not repo.changelog.isancestor(node, op1):
665 665 raise error.Abort(_('cannot backout change that is not an ancestor'))
666 666
667 667 p1, p2 = repo.changelog.parents(node)
668 668 if p1 == nullid:
669 669 raise error.Abort(_('cannot backout a change with no parents'))
670 670 if p2 != nullid:
671 671 if not opts.get('parent'):
672 672 raise error.Abort(_('cannot backout a merge changeset'))
673 673 p = repo.lookup(opts['parent'])
674 674 if p not in (p1, p2):
675 675 raise error.Abort(_('%s is not a parent of %s') %
676 676 (short(p), short(node)))
677 677 parent = p
678 678 else:
679 679 if opts.get('parent'):
680 680 raise error.Abort(_('cannot use --parent on non-merge changeset'))
681 681 parent = p1
682 682
683 683 # the backout should appear on the same branch
684 684 branch = repo.dirstate.branch()
685 685 bheads = repo.branchheads(branch)
686 686 rctx = scmutil.revsingle(repo, hex(parent))
687 687 if not opts.get('merge') and op1 != node:
688 688 dsguard = cmdutil.dirstateguard(repo, 'backout')
689 689 try:
690 690 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
691 691 'backout')
692 692 stats = mergemod.update(repo, parent, True, True, node, False)
693 693 repo.setparents(op1, op2)
694 694 dsguard.close()
695 695 hg._showstats(repo, stats)
696 696 if stats[3]:
697 697 repo.ui.status(_("use 'hg resolve' to retry unresolved "
698 698 "file merges\n"))
699 699 return 1
700 700 finally:
701 701 ui.setconfig('ui', 'forcemerge', '', '')
702 702 lockmod.release(dsguard)
703 703 else:
704 704 hg.clean(repo, node, show_stats=False)
705 705 repo.dirstate.setbranch(branch)
706 706 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
707 707
708 708 if opts.get('no_commit'):
709 709 msg = _("changeset %s backed out, "
710 710 "don't forget to commit.\n")
711 711 ui.status(msg % short(node))
712 712 return 0
713 713
714 714 def commitfunc(ui, repo, message, match, opts):
715 715 editform = 'backout'
716 716 e = cmdutil.getcommiteditor(editform=editform, **opts)
717 717 if not message:
718 718 # we don't translate commit messages
719 719 message = "Backed out changeset %s" % short(node)
720 720 e = cmdutil.getcommiteditor(edit=True, editform=editform)
721 721 return repo.commit(message, opts.get('user'), opts.get('date'),
722 722 match, editor=e)
723 723 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
724 724 if not newnode:
725 725 ui.status(_("nothing changed\n"))
726 726 return 1
727 727 cmdutil.commitstatus(repo, newnode, branch, bheads)
728 728
729 729 def nice(node):
730 730 return '%d:%s' % (repo.changelog.rev(node), short(node))
731 731 ui.status(_('changeset %s backs out changeset %s\n') %
732 732 (nice(repo.changelog.tip()), nice(node)))
733 733 if opts.get('merge') and op1 != node:
734 734 hg.clean(repo, op1, show_stats=False)
735 735 ui.status(_('merging with changeset %s\n')
736 736 % nice(repo.changelog.tip()))
737 737 try:
738 738 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
739 739 'backout')
740 740 return hg.merge(repo, hex(repo.changelog.tip()))
741 741 finally:
742 742 ui.setconfig('ui', 'forcemerge', '', '')
743 743 return 0
744 744
745 745 @command('bisect',
746 746 [('r', 'reset', False, _('reset bisect state')),
747 747 ('g', 'good', False, _('mark changeset good')),
748 748 ('b', 'bad', False, _('mark changeset bad')),
749 749 ('s', 'skip', False, _('skip testing changeset')),
750 750 ('e', 'extend', False, _('extend the bisect range')),
751 751 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
752 752 ('U', 'noupdate', False, _('do not update to target'))],
753 753 _("[-gbsr] [-U] [-c CMD] [REV]"))
754 754 def bisect(ui, repo, rev=None, extra=None, command=None,
755 755 reset=None, good=None, bad=None, skip=None, extend=None,
756 756 noupdate=None):
757 757 """subdivision search of changesets
758 758
759 759 This command helps to find changesets which introduce problems. To
760 760 use, mark the earliest changeset you know exhibits the problem as
761 761 bad, then mark the latest changeset which is free from the problem
762 762 as good. Bisect will update your working directory to a revision
763 763 for testing (unless the -U/--noupdate option is specified). Once
764 764 you have performed tests, mark the working directory as good or
765 765 bad, and bisect will either update to another candidate changeset
766 766 or announce that it has found the bad revision.
767 767
768 768 As a shortcut, you can also use the revision argument to mark a
769 769 revision as good or bad without checking it out first.
770 770
771 771 If you supply a command, it will be used for automatic bisection.
772 772 The environment variable HG_NODE will contain the ID of the
773 773 changeset being tested. The exit status of the command will be
774 774 used to mark revisions as good or bad: status 0 means good, 125
775 775 means to skip the revision, 127 (command not found) will abort the
776 776 bisection, and any other non-zero exit status means the revision
777 777 is bad.
778 778
779 779 .. container:: verbose
780 780
781 781 Some examples:
782 782
783 783 - start a bisection with known bad revision 34, and good revision 12::
784 784
785 785 hg bisect --bad 34
786 786 hg bisect --good 12
787 787
788 788 - advance the current bisection by marking current revision as good or
789 789 bad::
790 790
791 791 hg bisect --good
792 792 hg bisect --bad
793 793
794 794 - mark the current revision, or a known revision, to be skipped (e.g. if
795 795 that revision is not usable because of another issue)::
796 796
797 797 hg bisect --skip
798 798 hg bisect --skip 23
799 799
800 800 - skip all revisions that do not touch directories ``foo`` or ``bar``::
801 801
802 802 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
803 803
804 804 - forget the current bisection::
805 805
806 806 hg bisect --reset
807 807
808 808 - use 'make && make tests' to automatically find the first broken
809 809 revision::
810 810
811 811 hg bisect --reset
812 812 hg bisect --bad 34
813 813 hg bisect --good 12
814 814 hg bisect --command "make && make tests"
815 815
816 816 - see all changesets whose states are already known in the current
817 817 bisection::
818 818
819 819 hg log -r "bisect(pruned)"
820 820
821 821 - see the changeset currently being bisected (especially useful
822 822 if running with -U/--noupdate)::
823 823
824 824 hg log -r "bisect(current)"
825 825
826 826 - see all changesets that took part in the current bisection::
827 827
828 828 hg log -r "bisect(range)"
829 829
830 830 - you can even get a nice graph::
831 831
832 832 hg log --graph -r "bisect(range)"
833 833
834 834 See :hg:`help revsets` for more about the `bisect()` keyword.
835 835
836 836 Returns 0 on success.
837 837 """
838 838 # backward compatibility
839 839 if rev in "good bad reset init".split():
840 840 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
841 841 cmd, rev, extra = rev, extra, None
842 842 if cmd == "good":
843 843 good = True
844 844 elif cmd == "bad":
845 845 bad = True
846 846 else:
847 847 reset = True
848 848 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
849 849 raise error.Abort(_('incompatible arguments'))
850 850
851 851 cmdutil.checkunfinished(repo)
852 852
853 853 if reset:
854 854 hbisect.resetstate(repo)
855 855 return
856 856
857 857 state = hbisect.load_state(repo)
858 858
859 859 # update state
860 860 if good or bad or skip:
861 861 if rev:
862 862 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
863 863 else:
864 864 nodes = [repo.lookup('.')]
865 865 if good:
866 866 state['good'] += nodes
867 867 elif bad:
868 868 state['bad'] += nodes
869 869 elif skip:
870 870 state['skip'] += nodes
871 871 hbisect.save_state(repo, state)
872 872 if not (state['good'] and state['bad']):
873 873 return
874 874
875 875 def mayupdate(repo, node, show_stats=True):
876 876 """common used update sequence"""
877 877 if noupdate:
878 878 return
879 879 cmdutil.bailifchanged(repo)
880 880 return hg.clean(repo, node, show_stats=show_stats)
881 881
882 882 displayer = cmdutil.show_changeset(ui, repo, {})
883 883
884 884 if command:
885 885 changesets = 1
886 886 if noupdate:
887 887 try:
888 888 node = state['current'][0]
889 889 except LookupError:
890 890 raise error.Abort(_('current bisect revision is unknown - '
891 891 'start a new bisect to fix'))
892 892 else:
893 893 node, p2 = repo.dirstate.parents()
894 894 if p2 != nullid:
895 895 raise error.Abort(_('current bisect revision is a merge'))
896 896 if rev:
897 897 node = repo[scmutil.revsingle(repo, rev, node)].node()
898 898 try:
899 899 while changesets:
900 900 # update state
901 901 state['current'] = [node]
902 902 hbisect.save_state(repo, state)
903 903 status = ui.system(command, environ={'HG_NODE': hex(node)})
904 904 if status == 125:
905 905 transition = "skip"
906 906 elif status == 0:
907 907 transition = "good"
908 908 # status < 0 means process was killed
909 909 elif status == 127:
910 910 raise error.Abort(_("failed to execute %s") % command)
911 911 elif status < 0:
912 912 raise error.Abort(_("%s killed") % command)
913 913 else:
914 914 transition = "bad"
915 915 state[transition].append(node)
916 916 ctx = repo[node]
917 917 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
918 918 hbisect.checkstate(state)
919 919 # bisect
920 920 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
921 921 # update to next check
922 922 node = nodes[0]
923 923 mayupdate(repo, node, show_stats=False)
924 924 finally:
925 925 state['current'] = [node]
926 926 hbisect.save_state(repo, state)
927 927 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
928 928 return
929 929
930 930 hbisect.checkstate(state)
931 931
932 932 # actually bisect
933 933 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
934 934 if extend:
935 935 if not changesets:
936 936 extendnode = hbisect.extendrange(repo, state, nodes, good)
937 937 if extendnode is not None:
938 938 ui.write(_("Extending search to changeset %d:%s\n")
939 939 % (extendnode.rev(), extendnode))
940 940 state['current'] = [extendnode.node()]
941 941 hbisect.save_state(repo, state)
942 942 return mayupdate(repo, extendnode.node())
943 943 raise error.Abort(_("nothing to extend"))
944 944
945 945 if changesets == 0:
946 946 hbisect.printresult(ui, repo, state, displayer, nodes, good)
947 947 else:
948 948 assert len(nodes) == 1 # only a single node can be tested next
949 949 node = nodes[0]
950 950 # compute the approximate number of remaining tests
951 951 tests, size = 0, 2
952 952 while size <= changesets:
953 953 tests, size = tests + 1, size * 2
954 954 rev = repo.changelog.rev(node)
955 955 ui.write(_("Testing changeset %d:%s "
956 956 "(%d changesets remaining, ~%d tests)\n")
957 957 % (rev, short(node), changesets, tests))
958 958 state['current'] = [node]
959 959 hbisect.save_state(repo, state)
960 960 return mayupdate(repo, node)
961 961
962 962 @command('bookmarks|bookmark',
963 963 [('f', 'force', False, _('force')),
964 964 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
965 965 ('d', 'delete', False, _('delete a given bookmark')),
966 966 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
967 967 ('i', 'inactive', False, _('mark a bookmark inactive')),
968 968 ] + formatteropts,
969 969 _('hg bookmarks [OPTIONS]... [NAME]...'))
970 970 def bookmark(ui, repo, *names, **opts):
971 971 '''create a new bookmark or list existing bookmarks
972 972
973 973 Bookmarks are labels on changesets to help track lines of development.
974 974 Bookmarks are unversioned and can be moved, renamed and deleted.
975 975 Deleting or moving a bookmark has no effect on the associated changesets.
976 976
977 977 Creating or updating to a bookmark causes it to be marked as 'active'.
978 978 The active bookmark is indicated with a '*'.
979 979 When a commit is made, the active bookmark will advance to the new commit.
980 980 A plain :hg:`update` will also advance an active bookmark, if possible.
981 981 Updating away from a bookmark will cause it to be deactivated.
982 982
983 983 Bookmarks can be pushed and pulled between repositories (see
984 984 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
985 985 diverged, a new 'divergent bookmark' of the form 'name@path' will
986 986 be created. Using :hg:`merge` will resolve the divergence.
987 987
988 988 A bookmark named '@' has the special property that :hg:`clone` will
989 989 check it out by default if it exists.
990 990
991 991 .. container:: verbose
992 992
993 993 Examples:
994 994
995 995 - create an active bookmark for a new line of development::
996 996
997 997 hg book new-feature
998 998
999 999 - create an inactive bookmark as a place marker::
1000 1000
1001 1001 hg book -i reviewed
1002 1002
1003 1003 - create an inactive bookmark on another changeset::
1004 1004
1005 1005 hg book -r .^ tested
1006 1006
1007 1007 - rename bookmark turkey to dinner::
1008 1008
1009 1009 hg book -m turkey dinner
1010 1010
1011 1011 - move the '@' bookmark from another branch::
1012 1012
1013 1013 hg book -f @
1014 1014 '''
1015 1015 force = opts.get('force')
1016 1016 rev = opts.get('rev')
1017 1017 delete = opts.get('delete')
1018 1018 rename = opts.get('rename')
1019 1019 inactive = opts.get('inactive')
1020 1020
1021 1021 def checkformat(mark):
1022 1022 mark = mark.strip()
1023 1023 if not mark:
1024 1024 raise error.Abort(_("bookmark names cannot consist entirely of "
1025 1025 "whitespace"))
1026 1026 scmutil.checknewlabel(repo, mark, 'bookmark')
1027 1027 return mark
1028 1028
1029 1029 def checkconflict(repo, mark, cur, force=False, target=None):
1030 1030 if mark in marks and not force:
1031 1031 if target:
1032 1032 if marks[mark] == target and target == cur:
1033 1033 # re-activating a bookmark
1034 1034 return
1035 1035 anc = repo.changelog.ancestors([repo[target].rev()])
1036 1036 bmctx = repo[marks[mark]]
1037 1037 divs = [repo[b].node() for b in marks
1038 1038 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1039 1039
1040 1040 # allow resolving a single divergent bookmark even if moving
1041 1041 # the bookmark across branches when a revision is specified
1042 1042 # that contains a divergent bookmark
1043 1043 if bmctx.rev() not in anc and target in divs:
1044 1044 bookmarks.deletedivergent(repo, [target], mark)
1045 1045 return
1046 1046
1047 1047 deletefrom = [b for b in divs
1048 1048 if repo[b].rev() in anc or b == target]
1049 1049 bookmarks.deletedivergent(repo, deletefrom, mark)
1050 1050 if bookmarks.validdest(repo, bmctx, repo[target]):
1051 1051 ui.status(_("moving bookmark '%s' forward from %s\n") %
1052 1052 (mark, short(bmctx.node())))
1053 1053 return
1054 1054 raise error.Abort(_("bookmark '%s' already exists "
1055 1055 "(use -f to force)") % mark)
1056 1056 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1057 1057 and not force):
1058 1058 raise error.Abort(
1059 1059 _("a bookmark cannot have the name of an existing branch"))
1060 1060
1061 1061 if delete and rename:
1062 1062 raise error.Abort(_("--delete and --rename are incompatible"))
1063 1063 if delete and rev:
1064 1064 raise error.Abort(_("--rev is incompatible with --delete"))
1065 1065 if rename and rev:
1066 1066 raise error.Abort(_("--rev is incompatible with --rename"))
1067 1067 if not names and (delete or rev):
1068 1068 raise error.Abort(_("bookmark name required"))
1069 1069
1070 1070 if delete or rename or names or inactive:
1071 1071 wlock = lock = tr = None
1072 1072 try:
1073 1073 wlock = repo.wlock()
1074 1074 lock = repo.lock()
1075 1075 cur = repo.changectx('.').node()
1076 1076 marks = repo._bookmarks
1077 1077 if delete:
1078 1078 tr = repo.transaction('bookmark')
1079 1079 for mark in names:
1080 1080 if mark not in marks:
1081 1081 raise error.Abort(_("bookmark '%s' does not exist") %
1082 1082 mark)
1083 1083 if mark == repo._activebookmark:
1084 1084 bookmarks.deactivate(repo)
1085 1085 del marks[mark]
1086 1086
1087 1087 elif rename:
1088 1088 tr = repo.transaction('bookmark')
1089 1089 if not names:
1090 1090 raise error.Abort(_("new bookmark name required"))
1091 1091 elif len(names) > 1:
1092 1092 raise error.Abort(_("only one new bookmark name allowed"))
1093 1093 mark = checkformat(names[0])
1094 1094 if rename not in marks:
1095 1095 raise error.Abort(_("bookmark '%s' does not exist")
1096 1096 % rename)
1097 1097 checkconflict(repo, mark, cur, force)
1098 1098 marks[mark] = marks[rename]
1099 1099 if repo._activebookmark == rename and not inactive:
1100 1100 bookmarks.activate(repo, mark)
1101 1101 del marks[rename]
1102 1102 elif names:
1103 1103 tr = repo.transaction('bookmark')
1104 1104 newact = None
1105 1105 for mark in names:
1106 1106 mark = checkformat(mark)
1107 1107 if newact is None:
1108 1108 newact = mark
1109 1109 if inactive and mark == repo._activebookmark:
1110 1110 bookmarks.deactivate(repo)
1111 1111 return
1112 1112 tgt = cur
1113 1113 if rev:
1114 1114 tgt = scmutil.revsingle(repo, rev).node()
1115 1115 checkconflict(repo, mark, cur, force, tgt)
1116 1116 marks[mark] = tgt
1117 1117 if not inactive and cur == marks[newact] and not rev:
1118 1118 bookmarks.activate(repo, newact)
1119 1119 elif cur != tgt and newact == repo._activebookmark:
1120 1120 bookmarks.deactivate(repo)
1121 1121 elif inactive:
1122 1122 if len(marks) == 0:
1123 1123 ui.status(_("no bookmarks set\n"))
1124 1124 elif not repo._activebookmark:
1125 1125 ui.status(_("no active bookmark\n"))
1126 1126 else:
1127 1127 bookmarks.deactivate(repo)
1128 1128 if tr is not None:
1129 1129 marks.recordchange(tr)
1130 1130 tr.close()
1131 1131 finally:
1132 1132 lockmod.release(tr, lock, wlock)
1133 1133 else: # show bookmarks
1134 1134 fm = ui.formatter('bookmarks', opts)
1135 1135 hexfn = fm.hexfunc
1136 1136 marks = repo._bookmarks
1137 1137 if len(marks) == 0 and fm.isplain():
1138 1138 ui.status(_("no bookmarks set\n"))
1139 1139 for bmark, n in sorted(marks.iteritems()):
1140 1140 active = repo._activebookmark
1141 1141 if bmark == active:
1142 1142 prefix, label = '*', activebookmarklabel
1143 1143 else:
1144 1144 prefix, label = ' ', ''
1145 1145
1146 1146 fm.startitem()
1147 1147 if not ui.quiet:
1148 1148 fm.plain(' %s ' % prefix, label=label)
1149 1149 fm.write('bookmark', '%s', bmark, label=label)
1150 1150 pad = " " * (25 - encoding.colwidth(bmark))
1151 1151 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1152 1152 repo.changelog.rev(n), hexfn(n), label=label)
1153 1153 fm.data(active=(bmark == active))
1154 1154 fm.plain('\n')
1155 1155 fm.end()
1156 1156
1157 1157 @command('branch',
1158 1158 [('f', 'force', None,
1159 1159 _('set branch name even if it shadows an existing branch')),
1160 1160 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1161 1161 _('[-fC] [NAME]'))
1162 1162 def branch(ui, repo, label=None, **opts):
1163 1163 """set or show the current branch name
1164 1164
1165 1165 .. note::
1166 1166
1167 1167 Branch names are permanent and global. Use :hg:`bookmark` to create a
1168 1168 light-weight bookmark instead. See :hg:`help glossary` for more
1169 1169 information about named branches and bookmarks.
1170 1170
1171 1171 With no argument, show the current branch name. With one argument,
1172 1172 set the working directory branch name (the branch will not exist
1173 1173 in the repository until the next commit). Standard practice
1174 1174 recommends that primary development take place on the 'default'
1175 1175 branch.
1176 1176
1177 1177 Unless -f/--force is specified, branch will not let you set a
1178 1178 branch name that already exists.
1179 1179
1180 1180 Use -C/--clean to reset the working directory branch to that of
1181 1181 the parent of the working directory, negating a previous branch
1182 1182 change.
1183 1183
1184 1184 Use the command :hg:`update` to switch to an existing branch. Use
1185 1185 :hg:`commit --close-branch` to mark this branch head as closed.
1186 1186 When all heads of a branch are closed, the branch will be
1187 1187 considered closed.
1188 1188
1189 1189 Returns 0 on success.
1190 1190 """
1191 1191 if label:
1192 1192 label = label.strip()
1193 1193
1194 1194 if not opts.get('clean') and not label:
1195 1195 ui.write("%s\n" % repo.dirstate.branch())
1196 1196 return
1197 1197
1198 1198 with repo.wlock():
1199 1199 if opts.get('clean'):
1200 1200 label = repo[None].p1().branch()
1201 1201 repo.dirstate.setbranch(label)
1202 1202 ui.status(_('reset working directory to branch %s\n') % label)
1203 1203 elif label:
1204 1204 if not opts.get('force') and label in repo.branchmap():
1205 1205 if label not in [p.branch() for p in repo[None].parents()]:
1206 1206 raise error.Abort(_('a branch of the same name already'
1207 1207 ' exists'),
1208 1208 # i18n: "it" refers to an existing branch
1209 1209 hint=_("use 'hg update' to switch to it"))
1210 1210 scmutil.checknewlabel(repo, label, 'branch')
1211 1211 repo.dirstate.setbranch(label)
1212 1212 ui.status(_('marked working directory as branch %s\n') % label)
1213 1213
1214 1214 # find any open named branches aside from default
1215 1215 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1216 1216 if n != "default" and not c]
1217 1217 if not others:
1218 1218 ui.status(_('(branches are permanent and global, '
1219 1219 'did you want a bookmark?)\n'))
1220 1220
1221 1221 @command('branches',
1222 1222 [('a', 'active', False,
1223 1223 _('show only branches that have unmerged heads (DEPRECATED)')),
1224 1224 ('c', 'closed', False, _('show normal and closed branches')),
1225 1225 ] + formatteropts,
1226 1226 _('[-c]'))
1227 1227 def branches(ui, repo, active=False, closed=False, **opts):
1228 1228 """list repository named branches
1229 1229
1230 1230 List the repository's named branches, indicating which ones are
1231 1231 inactive. If -c/--closed is specified, also list branches which have
1232 1232 been marked closed (see :hg:`commit --close-branch`).
1233 1233
1234 1234 Use the command :hg:`update` to switch to an existing branch.
1235 1235
1236 1236 Returns 0.
1237 1237 """
1238 1238
1239 1239 fm = ui.formatter('branches', opts)
1240 1240 hexfunc = fm.hexfunc
1241 1241
1242 1242 allheads = set(repo.heads())
1243 1243 branches = []
1244 1244 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1245 1245 isactive = not isclosed and bool(set(heads) & allheads)
1246 1246 branches.append((tag, repo[tip], isactive, not isclosed))
1247 1247 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1248 1248 reverse=True)
1249 1249
1250 1250 for tag, ctx, isactive, isopen in branches:
1251 1251 if active and not isactive:
1252 1252 continue
1253 1253 if isactive:
1254 1254 label = 'branches.active'
1255 1255 notice = ''
1256 1256 elif not isopen:
1257 1257 if not closed:
1258 1258 continue
1259 1259 label = 'branches.closed'
1260 1260 notice = _(' (closed)')
1261 1261 else:
1262 1262 label = 'branches.inactive'
1263 1263 notice = _(' (inactive)')
1264 1264 current = (tag == repo.dirstate.branch())
1265 1265 if current:
1266 1266 label = 'branches.current'
1267 1267
1268 1268 fm.startitem()
1269 1269 fm.write('branch', '%s', tag, label=label)
1270 1270 rev = ctx.rev()
1271 1271 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1272 1272 fmt = ' ' * padsize + ' %d:%s'
1273 1273 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1274 1274 label='log.changeset changeset.%s' % ctx.phasestr())
1275 1275 fm.data(active=isactive, closed=not isopen, current=current)
1276 1276 if not ui.quiet:
1277 1277 fm.plain(notice)
1278 1278 fm.plain('\n')
1279 1279 fm.end()
1280 1280
1281 1281 @command('bundle',
1282 1282 [('f', 'force', None, _('run even when the destination is unrelated')),
1283 1283 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1284 1284 _('REV')),
1285 1285 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1286 1286 _('BRANCH')),
1287 1287 ('', 'base', [],
1288 1288 _('a base changeset assumed to be available at the destination'),
1289 1289 _('REV')),
1290 1290 ('a', 'all', None, _('bundle all changesets in the repository')),
1291 1291 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1292 1292 ] + remoteopts,
1293 1293 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1294 1294 def bundle(ui, repo, fname, dest=None, **opts):
1295 1295 """create a changegroup file
1296 1296
1297 1297 Generate a changegroup file collecting changesets to be added
1298 1298 to a repository.
1299 1299
1300 1300 To create a bundle containing all changesets, use -a/--all
1301 1301 (or --base null). Otherwise, hg assumes the destination will have
1302 1302 all the nodes you specify with --base parameters. Otherwise, hg
1303 1303 will assume the repository has all the nodes in destination, or
1304 1304 default-push/default if no destination is specified.
1305 1305
1306 1306 You can change bundle format with the -t/--type option. You can
1307 1307 specify a compression, a bundle version or both using a dash
1308 1308 (comp-version). The available compression methods are: none, bzip2,
1309 1309 and gzip (by default, bundles are compressed using bzip2). The
1310 1310 available formats are: v1, v2 (default to most suitable).
1311 1311
1312 1312 The bundle file can then be transferred using conventional means
1313 1313 and applied to another repository with the unbundle or pull
1314 1314 command. This is useful when direct push and pull are not
1315 1315 available or when exporting an entire repository is undesirable.
1316 1316
1317 1317 Applying bundles preserves all changeset contents including
1318 1318 permissions, copy/rename information, and revision history.
1319 1319
1320 1320 Returns 0 on success, 1 if no changes found.
1321 1321 """
1322 1322 revs = None
1323 1323 if 'rev' in opts:
1324 1324 revstrings = opts['rev']
1325 1325 revs = scmutil.revrange(repo, revstrings)
1326 1326 if revstrings and not revs:
1327 1327 raise error.Abort(_('no commits to bundle'))
1328 1328
1329 1329 bundletype = opts.get('type', 'bzip2').lower()
1330 1330 try:
1331 1331 bcompression, cgversion, params = exchange.parsebundlespec(
1332 1332 repo, bundletype, strict=False)
1333 1333 except error.UnsupportedBundleSpecification as e:
1334 1334 raise error.Abort(str(e),
1335 1335 hint=_("see 'hg help bundle' for supported "
1336 1336 "values for --type"))
1337 1337
1338 1338 # Packed bundles are a pseudo bundle format for now.
1339 1339 if cgversion == 's1':
1340 1340 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1341 1341 hint=_("use 'hg debugcreatestreamclonebundle'"))
1342 1342
1343 1343 if opts.get('all'):
1344 1344 if dest:
1345 1345 raise error.Abort(_("--all is incompatible with specifying "
1346 1346 "a destination"))
1347 1347 if opts.get('base'):
1348 1348 ui.warn(_("ignoring --base because --all was specified\n"))
1349 1349 base = ['null']
1350 1350 else:
1351 1351 base = scmutil.revrange(repo, opts.get('base'))
1352 1352 # TODO: get desired bundlecaps from command line.
1353 1353 bundlecaps = None
1354 1354 if cgversion not in changegroup.supportedoutgoingversions(repo):
1355 1355 raise error.Abort(_("repository does not support bundle version %s") %
1356 1356 cgversion)
1357 1357
1358 1358 if base:
1359 1359 if dest:
1360 1360 raise error.Abort(_("--base is incompatible with specifying "
1361 1361 "a destination"))
1362 1362 common = [repo.lookup(rev) for rev in base]
1363 1363 heads = revs and map(repo.lookup, revs) or None
1364 1364 outgoing = discovery.outgoing(repo, common, heads)
1365 1365 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1366 1366 bundlecaps=bundlecaps,
1367 1367 version=cgversion)
1368 1368 outgoing = None
1369 1369 else:
1370 1370 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1371 1371 dest, branches = hg.parseurl(dest, opts.get('branch'))
1372 1372 other = hg.peer(repo, opts, dest)
1373 1373 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1374 1374 heads = revs and map(repo.lookup, revs) or revs
1375 1375 outgoing = discovery.findcommonoutgoing(repo, other,
1376 1376 onlyheads=heads,
1377 1377 force=opts.get('force'),
1378 1378 portable=True)
1379 1379 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1380 1380 bundlecaps, version=cgversion)
1381 1381 if not cg:
1382 1382 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1383 1383 return 1
1384 1384
1385 1385 if cgversion == '01': #bundle1
1386 1386 if bcompression is None:
1387 1387 bcompression = 'UN'
1388 1388 bversion = 'HG10' + bcompression
1389 1389 bcompression = None
1390 1390 else:
1391 1391 assert cgversion == '02'
1392 1392 bversion = 'HG20'
1393 1393
1394 1394 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1395 1395
1396 1396 @command('cat',
1397 1397 [('o', 'output', '',
1398 1398 _('print output to file with formatted name'), _('FORMAT')),
1399 1399 ('r', 'rev', '', _('print the given revision'), _('REV')),
1400 1400 ('', 'decode', None, _('apply any matching decode filter')),
1401 1401 ] + walkopts,
1402 1402 _('[OPTION]... FILE...'),
1403 1403 inferrepo=True)
1404 1404 def cat(ui, repo, file1, *pats, **opts):
1405 1405 """output the current or given revision of files
1406 1406
1407 1407 Print the specified files as they were at the given revision. If
1408 1408 no revision is given, the parent of the working directory is used.
1409 1409
1410 1410 Output may be to a file, in which case the name of the file is
1411 1411 given using a format string. The formatting rules as follows:
1412 1412
1413 1413 :``%%``: literal "%" character
1414 1414 :``%s``: basename of file being printed
1415 1415 :``%d``: dirname of file being printed, or '.' if in repository root
1416 1416 :``%p``: root-relative path name of file being printed
1417 1417 :``%H``: changeset hash (40 hexadecimal digits)
1418 1418 :``%R``: changeset revision number
1419 1419 :``%h``: short-form changeset hash (12 hexadecimal digits)
1420 1420 :``%r``: zero-padded changeset revision number
1421 1421 :``%b``: basename of the exporting repository
1422 1422
1423 1423 Returns 0 on success.
1424 1424 """
1425 1425 ctx = scmutil.revsingle(repo, opts.get('rev'))
1426 1426 m = scmutil.match(ctx, (file1,) + pats, opts)
1427 1427
1428 1428 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1429 1429
1430 1430 @command('^clone',
1431 1431 [('U', 'noupdate', None, _('the clone will include an empty working '
1432 1432 'directory (only a repository)')),
1433 1433 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1434 1434 _('REV')),
1435 1435 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1436 1436 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1437 1437 ('', 'pull', None, _('use pull protocol to copy metadata')),
1438 1438 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1439 1439 ] + remoteopts,
1440 1440 _('[OPTION]... SOURCE [DEST]'),
1441 1441 norepo=True)
1442 1442 def clone(ui, source, dest=None, **opts):
1443 1443 """make a copy of an existing repository
1444 1444
1445 1445 Create a copy of an existing repository in a new directory.
1446 1446
1447 1447 If no destination directory name is specified, it defaults to the
1448 1448 basename of the source.
1449 1449
1450 1450 The location of the source is added to the new repository's
1451 1451 ``.hg/hgrc`` file, as the default to be used for future pulls.
1452 1452
1453 1453 Only local paths and ``ssh://`` URLs are supported as
1454 1454 destinations. For ``ssh://`` destinations, no working directory or
1455 1455 ``.hg/hgrc`` will be created on the remote side.
1456 1456
1457 1457 If the source repository has a bookmark called '@' set, that
1458 1458 revision will be checked out in the new repository by default.
1459 1459
1460 1460 To check out a particular version, use -u/--update, or
1461 1461 -U/--noupdate to create a clone with no working directory.
1462 1462
1463 1463 To pull only a subset of changesets, specify one or more revisions
1464 1464 identifiers with -r/--rev or branches with -b/--branch. The
1465 1465 resulting clone will contain only the specified changesets and
1466 1466 their ancestors. These options (or 'clone src#rev dest') imply
1467 1467 --pull, even for local source repositories.
1468 1468
1469 1469 .. note::
1470 1470
1471 1471 Specifying a tag will include the tagged changeset but not the
1472 1472 changeset containing the tag.
1473 1473
1474 1474 .. container:: verbose
1475 1475
1476 1476 For efficiency, hardlinks are used for cloning whenever the
1477 1477 source and destination are on the same filesystem (note this
1478 1478 applies only to the repository data, not to the working
1479 1479 directory). Some filesystems, such as AFS, implement hardlinking
1480 1480 incorrectly, but do not report errors. In these cases, use the
1481 1481 --pull option to avoid hardlinking.
1482 1482
1483 1483 In some cases, you can clone repositories and the working
1484 1484 directory using full hardlinks with ::
1485 1485
1486 1486 $ cp -al REPO REPOCLONE
1487 1487
1488 1488 This is the fastest way to clone, but it is not always safe. The
1489 1489 operation is not atomic (making sure REPO is not modified during
1490 1490 the operation is up to you) and you have to make sure your
1491 1491 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1492 1492 so). Also, this is not compatible with certain extensions that
1493 1493 place their metadata under the .hg directory, such as mq.
1494 1494
1495 1495 Mercurial will update the working directory to the first applicable
1496 1496 revision from this list:
1497 1497
1498 1498 a) null if -U or the source repository has no changesets
1499 1499 b) if -u . and the source repository is local, the first parent of
1500 1500 the source repository's working directory
1501 1501 c) the changeset specified with -u (if a branch name, this means the
1502 1502 latest head of that branch)
1503 1503 d) the changeset specified with -r
1504 1504 e) the tipmost head specified with -b
1505 1505 f) the tipmost head specified with the url#branch source syntax
1506 1506 g) the revision marked with the '@' bookmark, if present
1507 1507 h) the tipmost head of the default branch
1508 1508 i) tip
1509 1509
1510 1510 When cloning from servers that support it, Mercurial may fetch
1511 1511 pre-generated data from a server-advertised URL. When this is done,
1512 1512 hooks operating on incoming changesets and changegroups may fire twice,
1513 1513 once for the bundle fetched from the URL and another for any additional
1514 1514 data not fetched from this URL. In addition, if an error occurs, the
1515 1515 repository may be rolled back to a partial clone. This behavior may
1516 1516 change in future releases. See :hg:`help -e clonebundles` for more.
1517 1517
1518 1518 Examples:
1519 1519
1520 1520 - clone a remote repository to a new directory named hg/::
1521 1521
1522 1522 hg clone http://selenic.com/hg
1523 1523
1524 1524 - create a lightweight local clone::
1525 1525
1526 1526 hg clone project/ project-feature/
1527 1527
1528 1528 - clone from an absolute path on an ssh server (note double-slash)::
1529 1529
1530 1530 hg clone ssh://user@server//home/projects/alpha/
1531 1531
1532 1532 - do a high-speed clone over a LAN while checking out a
1533 1533 specified version::
1534 1534
1535 1535 hg clone --uncompressed http://server/repo -u 1.5
1536 1536
1537 1537 - create a repository without changesets after a particular revision::
1538 1538
1539 1539 hg clone -r 04e544 experimental/ good/
1540 1540
1541 1541 - clone (and track) a particular named branch::
1542 1542
1543 1543 hg clone http://selenic.com/hg#stable
1544 1544
1545 1545 See :hg:`help urls` for details on specifying URLs.
1546 1546
1547 1547 Returns 0 on success.
1548 1548 """
1549 1549 if opts.get('noupdate') and opts.get('updaterev'):
1550 1550 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1551 1551
1552 1552 r = hg.clone(ui, opts, source, dest,
1553 1553 pull=opts.get('pull'),
1554 1554 stream=opts.get('uncompressed'),
1555 1555 rev=opts.get('rev'),
1556 1556 update=opts.get('updaterev') or not opts.get('noupdate'),
1557 1557 branch=opts.get('branch'),
1558 1558 shareopts=opts.get('shareopts'))
1559 1559
1560 1560 return r is None
1561 1561
1562 1562 @command('^commit|ci',
1563 1563 [('A', 'addremove', None,
1564 1564 _('mark new/missing files as added/removed before committing')),
1565 1565 ('', 'close-branch', None,
1566 1566 _('mark a branch head as closed')),
1567 1567 ('', 'amend', None, _('amend the parent of the working directory')),
1568 1568 ('s', 'secret', None, _('use the secret phase for committing')),
1569 1569 ('e', 'edit', None, _('invoke editor on commit messages')),
1570 1570 ('i', 'interactive', None, _('use interactive mode')),
1571 1571 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1572 1572 _('[OPTION]... [FILE]...'),
1573 1573 inferrepo=True)
1574 1574 def commit(ui, repo, *pats, **opts):
1575 1575 """commit the specified files or all outstanding changes
1576 1576
1577 1577 Commit changes to the given files into the repository. Unlike a
1578 1578 centralized SCM, this operation is a local operation. See
1579 1579 :hg:`push` for a way to actively distribute your changes.
1580 1580
1581 1581 If a list of files is omitted, all changes reported by :hg:`status`
1582 1582 will be committed.
1583 1583
1584 1584 If you are committing the result of a merge, do not provide any
1585 1585 filenames or -I/-X filters.
1586 1586
1587 1587 If no commit message is specified, Mercurial starts your
1588 1588 configured editor where you can enter a message. In case your
1589 1589 commit fails, you will find a backup of your message in
1590 1590 ``.hg/last-message.txt``.
1591 1591
1592 1592 The --close-branch flag can be used to mark the current branch
1593 1593 head closed. When all heads of a branch are closed, the branch
1594 1594 will be considered closed and no longer listed.
1595 1595
1596 1596 The --amend flag can be used to amend the parent of the
1597 1597 working directory with a new commit that contains the changes
1598 1598 in the parent in addition to those currently reported by :hg:`status`,
1599 1599 if there are any. The old commit is stored in a backup bundle in
1600 1600 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1601 1601 on how to restore it).
1602 1602
1603 1603 Message, user and date are taken from the amended commit unless
1604 1604 specified. When a message isn't specified on the command line,
1605 1605 the editor will open with the message of the amended commit.
1606 1606
1607 1607 It is not possible to amend public changesets (see :hg:`help phases`)
1608 1608 or changesets that have children.
1609 1609
1610 1610 See :hg:`help dates` for a list of formats valid for -d/--date.
1611 1611
1612 1612 Returns 0 on success, 1 if nothing changed.
1613 1613
1614 1614 .. container:: verbose
1615 1615
1616 1616 Examples:
1617 1617
1618 1618 - commit all files ending in .py::
1619 1619
1620 1620 hg commit --include "set:**.py"
1621 1621
1622 1622 - commit all non-binary files::
1623 1623
1624 1624 hg commit --exclude "set:binary()"
1625 1625
1626 1626 - amend the current commit and set the date to now::
1627 1627
1628 1628 hg commit --amend --date now
1629 1629 """
1630 1630 wlock = lock = None
1631 1631 try:
1632 1632 wlock = repo.wlock()
1633 1633 lock = repo.lock()
1634 1634 return _docommit(ui, repo, *pats, **opts)
1635 1635 finally:
1636 1636 release(lock, wlock)
1637 1637
1638 1638 def _docommit(ui, repo, *pats, **opts):
1639 1639 if opts.get('interactive'):
1640 1640 opts.pop('interactive')
1641 cmdutil.dorecord(ui, repo, commit, None, False,
1642 cmdutil.recordfilter, *pats, **opts)
1643 return
1641 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1642 cmdutil.recordfilter, *pats, **opts)
1643 # ret can be 0 (no changes to record) or the value returned by
1644 # commit(), 1 if nothing changed or None on success.
1645 return 1 if ret == 0 else ret
1644 1646
1645 1647 if opts.get('subrepos'):
1646 1648 if opts.get('amend'):
1647 1649 raise error.Abort(_('cannot amend with --subrepos'))
1648 1650 # Let --subrepos on the command line override config setting.
1649 1651 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1650 1652
1651 1653 cmdutil.checkunfinished(repo, commit=True)
1652 1654
1653 1655 branch = repo[None].branch()
1654 1656 bheads = repo.branchheads(branch)
1655 1657
1656 1658 extra = {}
1657 1659 if opts.get('close_branch'):
1658 1660 extra['close'] = 1
1659 1661
1660 1662 if not bheads:
1661 1663 raise error.Abort(_('can only close branch heads'))
1662 1664 elif opts.get('amend'):
1663 1665 if repo[None].parents()[0].p1().branch() != branch and \
1664 1666 repo[None].parents()[0].p2().branch() != branch:
1665 1667 raise error.Abort(_('can only close branch heads'))
1666 1668
1667 1669 if opts.get('amend'):
1668 1670 if ui.configbool('ui', 'commitsubrepos'):
1669 1671 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1670 1672
1671 1673 old = repo['.']
1672 1674 if not old.mutable():
1673 1675 raise error.Abort(_('cannot amend public changesets'))
1674 1676 if len(repo[None].parents()) > 1:
1675 1677 raise error.Abort(_('cannot amend while merging'))
1676 1678 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1677 1679 if not allowunstable and old.children():
1678 1680 raise error.Abort(_('cannot amend changeset with children'))
1679 1681
1680 1682 # Currently histedit gets confused if an amend happens while histedit
1681 1683 # is in progress. Since we have a checkunfinished command, we are
1682 1684 # temporarily honoring it.
1683 1685 #
1684 1686 # Note: eventually this guard will be removed. Please do not expect
1685 1687 # this behavior to remain.
1686 1688 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1687 1689 cmdutil.checkunfinished(repo)
1688 1690
1689 1691 # commitfunc is used only for temporary amend commit by cmdutil.amend
1690 1692 def commitfunc(ui, repo, message, match, opts):
1691 1693 return repo.commit(message,
1692 1694 opts.get('user') or old.user(),
1693 1695 opts.get('date') or old.date(),
1694 1696 match,
1695 1697 extra=extra)
1696 1698
1697 1699 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1698 1700 if node == old.node():
1699 1701 ui.status(_("nothing changed\n"))
1700 1702 return 1
1701 1703 else:
1702 1704 def commitfunc(ui, repo, message, match, opts):
1703 1705 backup = ui.backupconfig('phases', 'new-commit')
1704 1706 baseui = repo.baseui
1705 1707 basebackup = baseui.backupconfig('phases', 'new-commit')
1706 1708 try:
1707 1709 if opts.get('secret'):
1708 1710 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1709 1711 # Propagate to subrepos
1710 1712 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1711 1713
1712 1714 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1713 1715 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1714 1716 return repo.commit(message, opts.get('user'), opts.get('date'),
1715 1717 match,
1716 1718 editor=editor,
1717 1719 extra=extra)
1718 1720 finally:
1719 1721 ui.restoreconfig(backup)
1720 1722 repo.baseui.restoreconfig(basebackup)
1721 1723
1722 1724
1723 1725 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1724 1726
1725 1727 if not node:
1726 1728 stat = cmdutil.postcommitstatus(repo, pats, opts)
1727 1729 if stat[3]:
1728 1730 ui.status(_("nothing changed (%d missing files, see "
1729 1731 "'hg status')\n") % len(stat[3]))
1730 1732 else:
1731 1733 ui.status(_("nothing changed\n"))
1732 1734 return 1
1733 1735
1734 1736 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1735 1737
1736 1738 @command('config|showconfig|debugconfig',
1737 1739 [('u', 'untrusted', None, _('show untrusted configuration options')),
1738 1740 ('e', 'edit', None, _('edit user config')),
1739 1741 ('l', 'local', None, _('edit repository config')),
1740 1742 ('g', 'global', None, _('edit global config'))] + formatteropts,
1741 1743 _('[-u] [NAME]...'),
1742 1744 optionalrepo=True)
1743 1745 def config(ui, repo, *values, **opts):
1744 1746 """show combined config settings from all hgrc files
1745 1747
1746 1748 With no arguments, print names and values of all config items.
1747 1749
1748 1750 With one argument of the form section.name, print just the value
1749 1751 of that config item.
1750 1752
1751 1753 With multiple arguments, print names and values of all config
1752 1754 items with matching section names.
1753 1755
1754 1756 With --edit, start an editor on the user-level config file. With
1755 1757 --global, edit the system-wide config file. With --local, edit the
1756 1758 repository-level config file.
1757 1759
1758 1760 With --debug, the source (filename and line number) is printed
1759 1761 for each config item.
1760 1762
1761 1763 See :hg:`help config` for more information about config files.
1762 1764
1763 1765 Returns 0 on success, 1 if NAME does not exist.
1764 1766
1765 1767 """
1766 1768
1767 1769 if opts.get('edit') or opts.get('local') or opts.get('global'):
1768 1770 if opts.get('local') and opts.get('global'):
1769 1771 raise error.Abort(_("can't use --local and --global together"))
1770 1772
1771 1773 if opts.get('local'):
1772 1774 if not repo:
1773 1775 raise error.Abort(_("can't use --local outside a repository"))
1774 1776 paths = [repo.join('hgrc')]
1775 1777 elif opts.get('global'):
1776 1778 paths = scmutil.systemrcpath()
1777 1779 else:
1778 1780 paths = scmutil.userrcpath()
1779 1781
1780 1782 for f in paths:
1781 1783 if os.path.exists(f):
1782 1784 break
1783 1785 else:
1784 1786 if opts.get('global'):
1785 1787 samplehgrc = uimod.samplehgrcs['global']
1786 1788 elif opts.get('local'):
1787 1789 samplehgrc = uimod.samplehgrcs['local']
1788 1790 else:
1789 1791 samplehgrc = uimod.samplehgrcs['user']
1790 1792
1791 1793 f = paths[0]
1792 1794 fp = open(f, "w")
1793 1795 fp.write(samplehgrc)
1794 1796 fp.close()
1795 1797
1796 1798 editor = ui.geteditor()
1797 1799 ui.system("%s \"%s\"" % (editor, f),
1798 1800 onerr=error.Abort, errprefix=_("edit failed"))
1799 1801 return
1800 1802
1801 1803 fm = ui.formatter('config', opts)
1802 1804 for f in scmutil.rcpath():
1803 1805 ui.debug('read config from: %s\n' % f)
1804 1806 untrusted = bool(opts.get('untrusted'))
1805 1807 if values:
1806 1808 sections = [v for v in values if '.' not in v]
1807 1809 items = [v for v in values if '.' in v]
1808 1810 if len(items) > 1 or items and sections:
1809 1811 raise error.Abort(_('only one config item permitted'))
1810 1812 matched = False
1811 1813 for section, name, value in ui.walkconfig(untrusted=untrusted):
1812 1814 value = str(value)
1813 1815 if fm.isplain():
1814 1816 value = value.replace('\n', '\\n')
1815 1817 entryname = section + '.' + name
1816 1818 if values:
1817 1819 for v in values:
1818 1820 if v == section:
1819 1821 fm.startitem()
1820 1822 fm.condwrite(ui.debugflag, 'source', '%s: ',
1821 1823 ui.configsource(section, name, untrusted))
1822 1824 fm.write('name value', '%s=%s\n', entryname, value)
1823 1825 matched = True
1824 1826 elif v == entryname:
1825 1827 fm.startitem()
1826 1828 fm.condwrite(ui.debugflag, 'source', '%s: ',
1827 1829 ui.configsource(section, name, untrusted))
1828 1830 fm.write('value', '%s\n', value)
1829 1831 fm.data(name=entryname)
1830 1832 matched = True
1831 1833 else:
1832 1834 fm.startitem()
1833 1835 fm.condwrite(ui.debugflag, 'source', '%s: ',
1834 1836 ui.configsource(section, name, untrusted))
1835 1837 fm.write('name value', '%s=%s\n', entryname, value)
1836 1838 matched = True
1837 1839 fm.end()
1838 1840 if matched:
1839 1841 return 0
1840 1842 return 1
1841 1843
1842 1844 @command('copy|cp',
1843 1845 [('A', 'after', None, _('record a copy that has already occurred')),
1844 1846 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1845 1847 ] + walkopts + dryrunopts,
1846 1848 _('[OPTION]... [SOURCE]... DEST'))
1847 1849 def copy(ui, repo, *pats, **opts):
1848 1850 """mark files as copied for the next commit
1849 1851
1850 1852 Mark dest as having copies of source files. If dest is a
1851 1853 directory, copies are put in that directory. If dest is a file,
1852 1854 the source must be a single file.
1853 1855
1854 1856 By default, this command copies the contents of files as they
1855 1857 exist in the working directory. If invoked with -A/--after, the
1856 1858 operation is recorded, but no copying is performed.
1857 1859
1858 1860 This command takes effect with the next commit. To undo a copy
1859 1861 before that, see :hg:`revert`.
1860 1862
1861 1863 Returns 0 on success, 1 if errors are encountered.
1862 1864 """
1863 1865 with repo.wlock(False):
1864 1866 return cmdutil.copy(ui, repo, pats, opts)
1865 1867
1866 1868 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1867 1869 def debugancestor(ui, repo, *args):
1868 1870 """find the ancestor revision of two revisions in a given index"""
1869 1871 if len(args) == 3:
1870 1872 index, rev1, rev2 = args
1871 1873 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1872 1874 lookup = r.lookup
1873 1875 elif len(args) == 2:
1874 1876 if not repo:
1875 1877 raise error.Abort(_("there is no Mercurial repository here "
1876 1878 "(.hg not found)"))
1877 1879 rev1, rev2 = args
1878 1880 r = repo.changelog
1879 1881 lookup = repo.lookup
1880 1882 else:
1881 1883 raise error.Abort(_('either two or three arguments required'))
1882 1884 a = r.ancestor(lookup(rev1), lookup(rev2))
1883 1885 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1884 1886
1885 1887 @command('debugbuilddag',
1886 1888 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1887 1889 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1888 1890 ('n', 'new-file', None, _('add new file at each rev'))],
1889 1891 _('[OPTION]... [TEXT]'))
1890 1892 def debugbuilddag(ui, repo, text=None,
1891 1893 mergeable_file=False,
1892 1894 overwritten_file=False,
1893 1895 new_file=False):
1894 1896 """builds a repo with a given DAG from scratch in the current empty repo
1895 1897
1896 1898 The description of the DAG is read from stdin if not given on the
1897 1899 command line.
1898 1900
1899 1901 Elements:
1900 1902
1901 1903 - "+n" is a linear run of n nodes based on the current default parent
1902 1904 - "." is a single node based on the current default parent
1903 1905 - "$" resets the default parent to null (implied at the start);
1904 1906 otherwise the default parent is always the last node created
1905 1907 - "<p" sets the default parent to the backref p
1906 1908 - "*p" is a fork at parent p, which is a backref
1907 1909 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1908 1910 - "/p2" is a merge of the preceding node and p2
1909 1911 - ":tag" defines a local tag for the preceding node
1910 1912 - "@branch" sets the named branch for subsequent nodes
1911 1913 - "#...\\n" is a comment up to the end of the line
1912 1914
1913 1915 Whitespace between the above elements is ignored.
1914 1916
1915 1917 A backref is either
1916 1918
1917 1919 - a number n, which references the node curr-n, where curr is the current
1918 1920 node, or
1919 1921 - the name of a local tag you placed earlier using ":tag", or
1920 1922 - empty to denote the default parent.
1921 1923
1922 1924 All string valued-elements are either strictly alphanumeric, or must
1923 1925 be enclosed in double quotes ("..."), with "\\" as escape character.
1924 1926 """
1925 1927
1926 1928 if text is None:
1927 1929 ui.status(_("reading DAG from stdin\n"))
1928 1930 text = ui.fin.read()
1929 1931
1930 1932 cl = repo.changelog
1931 1933 if len(cl) > 0:
1932 1934 raise error.Abort(_('repository is not empty'))
1933 1935
1934 1936 # determine number of revs in DAG
1935 1937 total = 0
1936 1938 for type, data in dagparser.parsedag(text):
1937 1939 if type == 'n':
1938 1940 total += 1
1939 1941
1940 1942 if mergeable_file:
1941 1943 linesperrev = 2
1942 1944 # make a file with k lines per rev
1943 1945 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1944 1946 initialmergedlines.append("")
1945 1947
1946 1948 tags = []
1947 1949
1948 1950 wlock = lock = tr = None
1949 1951 try:
1950 1952 wlock = repo.wlock()
1951 1953 lock = repo.lock()
1952 1954 tr = repo.transaction("builddag")
1953 1955
1954 1956 at = -1
1955 1957 atbranch = 'default'
1956 1958 nodeids = []
1957 1959 id = 0
1958 1960 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1959 1961 for type, data in dagparser.parsedag(text):
1960 1962 if type == 'n':
1961 1963 ui.note(('node %s\n' % str(data)))
1962 1964 id, ps = data
1963 1965
1964 1966 files = []
1965 1967 fctxs = {}
1966 1968
1967 1969 p2 = None
1968 1970 if mergeable_file:
1969 1971 fn = "mf"
1970 1972 p1 = repo[ps[0]]
1971 1973 if len(ps) > 1:
1972 1974 p2 = repo[ps[1]]
1973 1975 pa = p1.ancestor(p2)
1974 1976 base, local, other = [x[fn].data() for x in (pa, p1,
1975 1977 p2)]
1976 1978 m3 = simplemerge.Merge3Text(base, local, other)
1977 1979 ml = [l.strip() for l in m3.merge_lines()]
1978 1980 ml.append("")
1979 1981 elif at > 0:
1980 1982 ml = p1[fn].data().split("\n")
1981 1983 else:
1982 1984 ml = initialmergedlines
1983 1985 ml[id * linesperrev] += " r%i" % id
1984 1986 mergedtext = "\n".join(ml)
1985 1987 files.append(fn)
1986 1988 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1987 1989
1988 1990 if overwritten_file:
1989 1991 fn = "of"
1990 1992 files.append(fn)
1991 1993 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1992 1994
1993 1995 if new_file:
1994 1996 fn = "nf%i" % id
1995 1997 files.append(fn)
1996 1998 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1997 1999 if len(ps) > 1:
1998 2000 if not p2:
1999 2001 p2 = repo[ps[1]]
2000 2002 for fn in p2:
2001 2003 if fn.startswith("nf"):
2002 2004 files.append(fn)
2003 2005 fctxs[fn] = p2[fn]
2004 2006
2005 2007 def fctxfn(repo, cx, path):
2006 2008 return fctxs.get(path)
2007 2009
2008 2010 if len(ps) == 0 or ps[0] < 0:
2009 2011 pars = [None, None]
2010 2012 elif len(ps) == 1:
2011 2013 pars = [nodeids[ps[0]], None]
2012 2014 else:
2013 2015 pars = [nodeids[p] for p in ps]
2014 2016 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2015 2017 date=(id, 0),
2016 2018 user="debugbuilddag",
2017 2019 extra={'branch': atbranch})
2018 2020 nodeid = repo.commitctx(cx)
2019 2021 nodeids.append(nodeid)
2020 2022 at = id
2021 2023 elif type == 'l':
2022 2024 id, name = data
2023 2025 ui.note(('tag %s\n' % name))
2024 2026 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2025 2027 elif type == 'a':
2026 2028 ui.note(('branch %s\n' % data))
2027 2029 atbranch = data
2028 2030 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2029 2031 tr.close()
2030 2032
2031 2033 if tags:
2032 2034 repo.vfs.write("localtags", "".join(tags))
2033 2035 finally:
2034 2036 ui.progress(_('building'), None)
2035 2037 release(tr, lock, wlock)
2036 2038
2037 2039 @command('debugbundle',
2038 2040 [('a', 'all', None, _('show all details')),
2039 2041 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2040 2042 _('FILE'),
2041 2043 norepo=True)
2042 2044 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2043 2045 """lists the contents of a bundle"""
2044 2046 with hg.openpath(ui, bundlepath) as f:
2045 2047 if spec:
2046 2048 spec = exchange.getbundlespec(ui, f)
2047 2049 ui.write('%s\n' % spec)
2048 2050 return
2049 2051
2050 2052 gen = exchange.readbundle(ui, f, bundlepath)
2051 2053 if isinstance(gen, bundle2.unbundle20):
2052 2054 return _debugbundle2(ui, gen, all=all, **opts)
2053 2055 _debugchangegroup(ui, gen, all=all, **opts)
2054 2056
2055 2057 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
2056 2058 indent_string = ' ' * indent
2057 2059 if all:
2058 2060 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
2059 2061 % indent_string)
2060 2062
2061 2063 def showchunks(named):
2062 2064 ui.write("\n%s%s\n" % (indent_string, named))
2063 2065 chain = None
2064 2066 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
2065 2067 node = chunkdata['node']
2066 2068 p1 = chunkdata['p1']
2067 2069 p2 = chunkdata['p2']
2068 2070 cs = chunkdata['cs']
2069 2071 deltabase = chunkdata['deltabase']
2070 2072 delta = chunkdata['delta']
2071 2073 ui.write("%s%s %s %s %s %s %s\n" %
2072 2074 (indent_string, hex(node), hex(p1), hex(p2),
2073 2075 hex(cs), hex(deltabase), len(delta)))
2074 2076 chain = node
2075 2077
2076 2078 chunkdata = gen.changelogheader()
2077 2079 showchunks("changelog")
2078 2080 chunkdata = gen.manifestheader()
2079 2081 showchunks("manifest")
2080 2082 for chunkdata in iter(gen.filelogheader, {}):
2081 2083 fname = chunkdata['filename']
2082 2084 showchunks(fname)
2083 2085 else:
2084 2086 if isinstance(gen, bundle2.unbundle20):
2085 2087 raise error.Abort(_('use debugbundle2 for this file'))
2086 2088 chunkdata = gen.changelogheader()
2087 2089 chain = None
2088 2090 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
2089 2091 node = chunkdata['node']
2090 2092 ui.write("%s%s\n" % (indent_string, hex(node)))
2091 2093 chain = node
2092 2094
2093 2095 def _debugbundle2(ui, gen, all=None, **opts):
2094 2096 """lists the contents of a bundle2"""
2095 2097 if not isinstance(gen, bundle2.unbundle20):
2096 2098 raise error.Abort(_('not a bundle2 file'))
2097 2099 ui.write(('Stream params: %s\n' % repr(gen.params)))
2098 2100 for part in gen.iterparts():
2099 2101 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2100 2102 if part.type == 'changegroup':
2101 2103 version = part.params.get('version', '01')
2102 2104 cg = changegroup.getunbundler(version, part, 'UN')
2103 2105 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
2104 2106
2105 2107 @command('debugcreatestreamclonebundle', [], 'FILE')
2106 2108 def debugcreatestreamclonebundle(ui, repo, fname):
2107 2109 """create a stream clone bundle file
2108 2110
2109 2111 Stream bundles are special bundles that are essentially archives of
2110 2112 revlog files. They are commonly used for cloning very quickly.
2111 2113 """
2112 2114 requirements, gen = streamclone.generatebundlev1(repo)
2113 2115 changegroup.writechunks(ui, gen, fname)
2114 2116
2115 2117 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2116 2118
2117 2119 @command('debugapplystreamclonebundle', [], 'FILE')
2118 2120 def debugapplystreamclonebundle(ui, repo, fname):
2119 2121 """apply a stream clone bundle file"""
2120 2122 f = hg.openpath(ui, fname)
2121 2123 gen = exchange.readbundle(ui, f, fname)
2122 2124 gen.apply(repo)
2123 2125
2124 2126 @command('debugcheckstate', [], '')
2125 2127 def debugcheckstate(ui, repo):
2126 2128 """validate the correctness of the current dirstate"""
2127 2129 parent1, parent2 = repo.dirstate.parents()
2128 2130 m1 = repo[parent1].manifest()
2129 2131 m2 = repo[parent2].manifest()
2130 2132 errors = 0
2131 2133 for f in repo.dirstate:
2132 2134 state = repo.dirstate[f]
2133 2135 if state in "nr" and f not in m1:
2134 2136 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2135 2137 errors += 1
2136 2138 if state in "a" and f in m1:
2137 2139 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2138 2140 errors += 1
2139 2141 if state in "m" and f not in m1 and f not in m2:
2140 2142 ui.warn(_("%s in state %s, but not in either manifest\n") %
2141 2143 (f, state))
2142 2144 errors += 1
2143 2145 for f in m1:
2144 2146 state = repo.dirstate[f]
2145 2147 if state not in "nrm":
2146 2148 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2147 2149 errors += 1
2148 2150 if errors:
2149 2151 error = _(".hg/dirstate inconsistent with current parent's manifest")
2150 2152 raise error.Abort(error)
2151 2153
2152 2154 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2153 2155 def debugcommands(ui, cmd='', *args):
2154 2156 """list all available commands and options"""
2155 2157 for cmd, vals in sorted(table.iteritems()):
2156 2158 cmd = cmd.split('|')[0].strip('^')
2157 2159 opts = ', '.join([i[1] for i in vals[1]])
2158 2160 ui.write('%s: %s\n' % (cmd, opts))
2159 2161
2160 2162 @command('debugcomplete',
2161 2163 [('o', 'options', None, _('show the command options'))],
2162 2164 _('[-o] CMD'),
2163 2165 norepo=True)
2164 2166 def debugcomplete(ui, cmd='', **opts):
2165 2167 """returns the completion list associated with the given command"""
2166 2168
2167 2169 if opts.get('options'):
2168 2170 options = []
2169 2171 otables = [globalopts]
2170 2172 if cmd:
2171 2173 aliases, entry = cmdutil.findcmd(cmd, table, False)
2172 2174 otables.append(entry[1])
2173 2175 for t in otables:
2174 2176 for o in t:
2175 2177 if "(DEPRECATED)" in o[3]:
2176 2178 continue
2177 2179 if o[0]:
2178 2180 options.append('-%s' % o[0])
2179 2181 options.append('--%s' % o[1])
2180 2182 ui.write("%s\n" % "\n".join(options))
2181 2183 return
2182 2184
2183 2185 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2184 2186 if ui.verbose:
2185 2187 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2186 2188 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2187 2189
2188 2190 @command('debugdag',
2189 2191 [('t', 'tags', None, _('use tags as labels')),
2190 2192 ('b', 'branches', None, _('annotate with branch names')),
2191 2193 ('', 'dots', None, _('use dots for runs')),
2192 2194 ('s', 'spaces', None, _('separate elements by spaces'))],
2193 2195 _('[OPTION]... [FILE [REV]...]'),
2194 2196 optionalrepo=True)
2195 2197 def debugdag(ui, repo, file_=None, *revs, **opts):
2196 2198 """format the changelog or an index DAG as a concise textual description
2197 2199
2198 2200 If you pass a revlog index, the revlog's DAG is emitted. If you list
2199 2201 revision numbers, they get labeled in the output as rN.
2200 2202
2201 2203 Otherwise, the changelog DAG of the current repo is emitted.
2202 2204 """
2203 2205 spaces = opts.get('spaces')
2204 2206 dots = opts.get('dots')
2205 2207 if file_:
2206 2208 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2207 2209 revs = set((int(r) for r in revs))
2208 2210 def events():
2209 2211 for r in rlog:
2210 2212 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2211 2213 if p != -1))
2212 2214 if r in revs:
2213 2215 yield 'l', (r, "r%i" % r)
2214 2216 elif repo:
2215 2217 cl = repo.changelog
2216 2218 tags = opts.get('tags')
2217 2219 branches = opts.get('branches')
2218 2220 if tags:
2219 2221 labels = {}
2220 2222 for l, n in repo.tags().items():
2221 2223 labels.setdefault(cl.rev(n), []).append(l)
2222 2224 def events():
2223 2225 b = "default"
2224 2226 for r in cl:
2225 2227 if branches:
2226 2228 newb = cl.read(cl.node(r))[5]['branch']
2227 2229 if newb != b:
2228 2230 yield 'a', newb
2229 2231 b = newb
2230 2232 yield 'n', (r, list(p for p in cl.parentrevs(r)
2231 2233 if p != -1))
2232 2234 if tags:
2233 2235 ls = labels.get(r)
2234 2236 if ls:
2235 2237 for l in ls:
2236 2238 yield 'l', (r, l)
2237 2239 else:
2238 2240 raise error.Abort(_('need repo for changelog dag'))
2239 2241
2240 2242 for line in dagparser.dagtextlines(events(),
2241 2243 addspaces=spaces,
2242 2244 wraplabels=True,
2243 2245 wrapannotations=True,
2244 2246 wrapnonlinear=dots,
2245 2247 usedots=dots,
2246 2248 maxlinewidth=70):
2247 2249 ui.write(line)
2248 2250 ui.write("\n")
2249 2251
2250 2252 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2251 2253 def debugdata(ui, repo, file_, rev=None, **opts):
2252 2254 """dump the contents of a data file revision"""
2253 2255 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
2254 2256 if rev is not None:
2255 2257 raise error.CommandError('debugdata', _('invalid arguments'))
2256 2258 file_, rev = None, file_
2257 2259 elif rev is None:
2258 2260 raise error.CommandError('debugdata', _('invalid arguments'))
2259 2261 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2260 2262 try:
2261 2263 ui.write(r.revision(r.lookup(rev)))
2262 2264 except KeyError:
2263 2265 raise error.Abort(_('invalid revision identifier %s') % rev)
2264 2266
2265 2267 @command('debugdate',
2266 2268 [('e', 'extended', None, _('try extended date formats'))],
2267 2269 _('[-e] DATE [RANGE]'),
2268 2270 norepo=True, optionalrepo=True)
2269 2271 def debugdate(ui, date, range=None, **opts):
2270 2272 """parse and display a date"""
2271 2273 if opts["extended"]:
2272 2274 d = util.parsedate(date, util.extendeddateformats)
2273 2275 else:
2274 2276 d = util.parsedate(date)
2275 2277 ui.write(("internal: %s %s\n") % d)
2276 2278 ui.write(("standard: %s\n") % util.datestr(d))
2277 2279 if range:
2278 2280 m = util.matchdate(range)
2279 2281 ui.write(("match: %s\n") % m(d[0]))
2280 2282
2281 2283 @command('debugdiscovery',
2282 2284 [('', 'old', None, _('use old-style discovery')),
2283 2285 ('', 'nonheads', None,
2284 2286 _('use old-style discovery with non-heads included')),
2285 2287 ] + remoteopts,
2286 2288 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2287 2289 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2288 2290 """runs the changeset discovery protocol in isolation"""
2289 2291 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2290 2292 opts.get('branch'))
2291 2293 remote = hg.peer(repo, opts, remoteurl)
2292 2294 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2293 2295
2294 2296 # make sure tests are repeatable
2295 2297 random.seed(12323)
2296 2298
2297 2299 def doit(localheads, remoteheads, remote=remote):
2298 2300 if opts.get('old'):
2299 2301 if localheads:
2300 2302 raise error.Abort('cannot use localheads with old style '
2301 2303 'discovery')
2302 2304 if not util.safehasattr(remote, 'branches'):
2303 2305 # enable in-client legacy support
2304 2306 remote = localrepo.locallegacypeer(remote.local())
2305 2307 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2306 2308 force=True)
2307 2309 common = set(common)
2308 2310 if not opts.get('nonheads'):
2309 2311 ui.write(("unpruned common: %s\n") %
2310 2312 " ".join(sorted(short(n) for n in common)))
2311 2313 dag = dagutil.revlogdag(repo.changelog)
2312 2314 all = dag.ancestorset(dag.internalizeall(common))
2313 2315 common = dag.externalizeall(dag.headsetofconnecteds(all))
2314 2316 else:
2315 2317 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2316 2318 common = set(common)
2317 2319 rheads = set(hds)
2318 2320 lheads = set(repo.heads())
2319 2321 ui.write(("common heads: %s\n") %
2320 2322 " ".join(sorted(short(n) for n in common)))
2321 2323 if lheads <= common:
2322 2324 ui.write(("local is subset\n"))
2323 2325 elif rheads <= common:
2324 2326 ui.write(("remote is subset\n"))
2325 2327
2326 2328 serverlogs = opts.get('serverlog')
2327 2329 if serverlogs:
2328 2330 for filename in serverlogs:
2329 2331 with open(filename, 'r') as logfile:
2330 2332 line = logfile.readline()
2331 2333 while line:
2332 2334 parts = line.strip().split(';')
2333 2335 op = parts[1]
2334 2336 if op == 'cg':
2335 2337 pass
2336 2338 elif op == 'cgss':
2337 2339 doit(parts[2].split(' '), parts[3].split(' '))
2338 2340 elif op == 'unb':
2339 2341 doit(parts[3].split(' '), parts[2].split(' '))
2340 2342 line = logfile.readline()
2341 2343 else:
2342 2344 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2343 2345 opts.get('remote_head'))
2344 2346 localrevs = opts.get('local_head')
2345 2347 doit(localrevs, remoterevs)
2346 2348
2347 2349 @command('debugextensions', formatteropts, [], norepo=True)
2348 2350 def debugextensions(ui, **opts):
2349 2351 '''show information about active extensions'''
2350 2352 exts = extensions.extensions(ui)
2351 2353 hgver = util.version()
2352 2354 fm = ui.formatter('debugextensions', opts)
2353 2355 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2354 2356 isinternal = extensions.ismoduleinternal(extmod)
2355 2357 extsource = extmod.__file__
2356 2358 if isinternal:
2357 2359 exttestedwith = [] # never expose magic string to users
2358 2360 else:
2359 2361 exttestedwith = getattr(extmod, 'testedwith', '').split()
2360 2362 extbuglink = getattr(extmod, 'buglink', None)
2361 2363
2362 2364 fm.startitem()
2363 2365
2364 2366 if ui.quiet or ui.verbose:
2365 2367 fm.write('name', '%s\n', extname)
2366 2368 else:
2367 2369 fm.write('name', '%s', extname)
2368 2370 if isinternal or hgver in exttestedwith:
2369 2371 fm.plain('\n')
2370 2372 elif not exttestedwith:
2371 2373 fm.plain(_(' (untested!)\n'))
2372 2374 else:
2373 2375 lasttestedversion = exttestedwith[-1]
2374 2376 fm.plain(' (%s!)\n' % lasttestedversion)
2375 2377
2376 2378 fm.condwrite(ui.verbose and extsource, 'source',
2377 2379 _(' location: %s\n'), extsource or "")
2378 2380
2379 2381 if ui.verbose:
2380 2382 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
2381 2383 fm.data(bundled=isinternal)
2382 2384
2383 2385 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2384 2386 _(' tested with: %s\n'),
2385 2387 fm.formatlist(exttestedwith, name='ver'))
2386 2388
2387 2389 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2388 2390 _(' bug reporting: %s\n'), extbuglink or "")
2389 2391
2390 2392 fm.end()
2391 2393
2392 2394 @command('debugfileset',
2393 2395 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2394 2396 _('[-r REV] FILESPEC'))
2395 2397 def debugfileset(ui, repo, expr, **opts):
2396 2398 '''parse and apply a fileset specification'''
2397 2399 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2398 2400 if ui.verbose:
2399 2401 tree = fileset.parse(expr)
2400 2402 ui.note(fileset.prettyformat(tree), "\n")
2401 2403
2402 2404 for f in ctx.getfileset(expr):
2403 2405 ui.write("%s\n" % f)
2404 2406
2405 2407 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2406 2408 def debugfsinfo(ui, path="."):
2407 2409 """show information detected about current filesystem"""
2408 2410 util.writefile('.debugfsinfo', '')
2409 2411 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2410 2412 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2411 2413 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2412 2414 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
2413 2415 and 'yes' or 'no'))
2414 2416 os.unlink('.debugfsinfo')
2415 2417
2416 2418 @command('debuggetbundle',
2417 2419 [('H', 'head', [], _('id of head node'), _('ID')),
2418 2420 ('C', 'common', [], _('id of common node'), _('ID')),
2419 2421 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2420 2422 _('REPO FILE [-H|-C ID]...'),
2421 2423 norepo=True)
2422 2424 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2423 2425 """retrieves a bundle from a repo
2424 2426
2425 2427 Every ID must be a full-length hex node id string. Saves the bundle to the
2426 2428 given file.
2427 2429 """
2428 2430 repo = hg.peer(ui, opts, repopath)
2429 2431 if not repo.capable('getbundle'):
2430 2432 raise error.Abort("getbundle() not supported by target repository")
2431 2433 args = {}
2432 2434 if common:
2433 2435 args['common'] = [bin(s) for s in common]
2434 2436 if head:
2435 2437 args['heads'] = [bin(s) for s in head]
2436 2438 # TODO: get desired bundlecaps from command line.
2437 2439 args['bundlecaps'] = None
2438 2440 bundle = repo.getbundle('debug', **args)
2439 2441
2440 2442 bundletype = opts.get('type', 'bzip2').lower()
2441 2443 btypes = {'none': 'HG10UN',
2442 2444 'bzip2': 'HG10BZ',
2443 2445 'gzip': 'HG10GZ',
2444 2446 'bundle2': 'HG20'}
2445 2447 bundletype = btypes.get(bundletype)
2446 2448 if bundletype not in bundle2.bundletypes:
2447 2449 raise error.Abort(_('unknown bundle type specified with --type'))
2448 2450 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2449 2451
2450 2452 @command('debugignore', [], '[FILE]')
2451 2453 def debugignore(ui, repo, *files, **opts):
2452 2454 """display the combined ignore pattern and information about ignored files
2453 2455
2454 2456 With no argument display the combined ignore pattern.
2455 2457
2456 2458 Given space separated file names, shows if the given file is ignored and
2457 2459 if so, show the ignore rule (file and line number) that matched it.
2458 2460 """
2459 2461 ignore = repo.dirstate._ignore
2460 2462 if not files:
2461 2463 # Show all the patterns
2462 2464 includepat = getattr(ignore, 'includepat', None)
2463 2465 if includepat is not None:
2464 2466 ui.write("%s\n" % includepat)
2465 2467 else:
2466 2468 raise error.Abort(_("no ignore patterns found"))
2467 2469 else:
2468 2470 for f in files:
2469 2471 nf = util.normpath(f)
2470 2472 ignored = None
2471 2473 ignoredata = None
2472 2474 if nf != '.':
2473 2475 if ignore(nf):
2474 2476 ignored = nf
2475 2477 ignoredata = repo.dirstate._ignorefileandline(nf)
2476 2478 else:
2477 2479 for p in util.finddirs(nf):
2478 2480 if ignore(p):
2479 2481 ignored = p
2480 2482 ignoredata = repo.dirstate._ignorefileandline(p)
2481 2483 break
2482 2484 if ignored:
2483 2485 if ignored == nf:
2484 2486 ui.write(_("%s is ignored\n") % f)
2485 2487 else:
2486 2488 ui.write(_("%s is ignored because of "
2487 2489 "containing folder %s\n")
2488 2490 % (f, ignored))
2489 2491 ignorefile, lineno, line = ignoredata
2490 2492 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2491 2493 % (ignorefile, lineno, line))
2492 2494 else:
2493 2495 ui.write(_("%s is not ignored\n") % f)
2494 2496
2495 2497 @command('debugindex', debugrevlogopts +
2496 2498 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2497 2499 _('[-f FORMAT] -c|-m|FILE'),
2498 2500 optionalrepo=True)
2499 2501 def debugindex(ui, repo, file_=None, **opts):
2500 2502 """dump the contents of an index file"""
2501 2503 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2502 2504 format = opts.get('format', 0)
2503 2505 if format not in (0, 1):
2504 2506 raise error.Abort(_("unknown format %d") % format)
2505 2507
2506 2508 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2507 2509 if generaldelta:
2508 2510 basehdr = ' delta'
2509 2511 else:
2510 2512 basehdr = ' base'
2511 2513
2512 2514 if ui.debugflag:
2513 2515 shortfn = hex
2514 2516 else:
2515 2517 shortfn = short
2516 2518
2517 2519 # There might not be anything in r, so have a sane default
2518 2520 idlen = 12
2519 2521 for i in r:
2520 2522 idlen = len(shortfn(r.node(i)))
2521 2523 break
2522 2524
2523 2525 if format == 0:
2524 2526 ui.write((" rev offset length " + basehdr + " linkrev"
2525 2527 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2526 2528 elif format == 1:
2527 2529 ui.write((" rev flag offset length"
2528 2530 " size " + basehdr + " link p1 p2"
2529 2531 " %s\n") % "nodeid".rjust(idlen))
2530 2532
2531 2533 for i in r:
2532 2534 node = r.node(i)
2533 2535 if generaldelta:
2534 2536 base = r.deltaparent(i)
2535 2537 else:
2536 2538 base = r.chainbase(i)
2537 2539 if format == 0:
2538 2540 try:
2539 2541 pp = r.parents(node)
2540 2542 except Exception:
2541 2543 pp = [nullid, nullid]
2542 2544 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2543 2545 i, r.start(i), r.length(i), base, r.linkrev(i),
2544 2546 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2545 2547 elif format == 1:
2546 2548 pr = r.parentrevs(i)
2547 2549 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2548 2550 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2549 2551 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2550 2552
2551 2553 @command('debugindexdot', debugrevlogopts,
2552 2554 _('-c|-m|FILE'), optionalrepo=True)
2553 2555 def debugindexdot(ui, repo, file_=None, **opts):
2554 2556 """dump an index DAG as a graphviz dot file"""
2555 2557 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2556 2558 ui.write(("digraph G {\n"))
2557 2559 for i in r:
2558 2560 node = r.node(i)
2559 2561 pp = r.parents(node)
2560 2562 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2561 2563 if pp[1] != nullid:
2562 2564 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2563 2565 ui.write("}\n")
2564 2566
2565 2567 @command('debugdeltachain',
2566 2568 debugrevlogopts + formatteropts,
2567 2569 _('-c|-m|FILE'),
2568 2570 optionalrepo=True)
2569 2571 def debugdeltachain(ui, repo, file_=None, **opts):
2570 2572 """dump information about delta chains in a revlog
2571 2573
2572 2574 Output can be templatized. Available template keywords are:
2573 2575
2574 2576 :``rev``: revision number
2575 2577 :``chainid``: delta chain identifier (numbered by unique base)
2576 2578 :``chainlen``: delta chain length to this revision
2577 2579 :``prevrev``: previous revision in delta chain
2578 2580 :``deltatype``: role of delta / how it was computed
2579 2581 :``compsize``: compressed size of revision
2580 2582 :``uncompsize``: uncompressed size of revision
2581 2583 :``chainsize``: total size of compressed revisions in chain
2582 2584 :``chainratio``: total chain size divided by uncompressed revision size
2583 2585 (new delta chains typically start at ratio 2.00)
2584 2586 :``lindist``: linear distance from base revision in delta chain to end
2585 2587 of this revision
2586 2588 :``extradist``: total size of revisions not part of this delta chain from
2587 2589 base of delta chain to end of this revision; a measurement
2588 2590 of how much extra data we need to read/seek across to read
2589 2591 the delta chain for this revision
2590 2592 :``extraratio``: extradist divided by chainsize; another representation of
2591 2593 how much unrelated data is needed to load this delta chain
2592 2594 """
2593 2595 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2594 2596 index = r.index
2595 2597 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2596 2598
2597 2599 def revinfo(rev):
2598 2600 e = index[rev]
2599 2601 compsize = e[1]
2600 2602 uncompsize = e[2]
2601 2603 chainsize = 0
2602 2604
2603 2605 if generaldelta:
2604 2606 if e[3] == e[5]:
2605 2607 deltatype = 'p1'
2606 2608 elif e[3] == e[6]:
2607 2609 deltatype = 'p2'
2608 2610 elif e[3] == rev - 1:
2609 2611 deltatype = 'prev'
2610 2612 elif e[3] == rev:
2611 2613 deltatype = 'base'
2612 2614 else:
2613 2615 deltatype = 'other'
2614 2616 else:
2615 2617 if e[3] == rev:
2616 2618 deltatype = 'base'
2617 2619 else:
2618 2620 deltatype = 'prev'
2619 2621
2620 2622 chain = r._deltachain(rev)[0]
2621 2623 for iterrev in chain:
2622 2624 e = index[iterrev]
2623 2625 chainsize += e[1]
2624 2626
2625 2627 return compsize, uncompsize, deltatype, chain, chainsize
2626 2628
2627 2629 fm = ui.formatter('debugdeltachain', opts)
2628 2630
2629 2631 fm.plain(' rev chain# chainlen prev delta '
2630 2632 'size rawsize chainsize ratio lindist extradist '
2631 2633 'extraratio\n')
2632 2634
2633 2635 chainbases = {}
2634 2636 for rev in r:
2635 2637 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2636 2638 chainbase = chain[0]
2637 2639 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2638 2640 basestart = r.start(chainbase)
2639 2641 revstart = r.start(rev)
2640 2642 lineardist = revstart + comp - basestart
2641 2643 extradist = lineardist - chainsize
2642 2644 try:
2643 2645 prevrev = chain[-2]
2644 2646 except IndexError:
2645 2647 prevrev = -1
2646 2648
2647 2649 chainratio = float(chainsize) / float(uncomp)
2648 2650 extraratio = float(extradist) / float(chainsize)
2649 2651
2650 2652 fm.startitem()
2651 2653 fm.write('rev chainid chainlen prevrev deltatype compsize '
2652 2654 'uncompsize chainsize chainratio lindist extradist '
2653 2655 'extraratio',
2654 2656 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2655 2657 rev, chainid, len(chain), prevrev, deltatype, comp,
2656 2658 uncomp, chainsize, chainratio, lineardist, extradist,
2657 2659 extraratio,
2658 2660 rev=rev, chainid=chainid, chainlen=len(chain),
2659 2661 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2660 2662 uncompsize=uncomp, chainsize=chainsize,
2661 2663 chainratio=chainratio, lindist=lineardist,
2662 2664 extradist=extradist, extraratio=extraratio)
2663 2665
2664 2666 fm.end()
2665 2667
2666 2668 @command('debuginstall', [] + formatteropts, '', norepo=True)
2667 2669 def debuginstall(ui, **opts):
2668 2670 '''test Mercurial installation
2669 2671
2670 2672 Returns 0 on success.
2671 2673 '''
2672 2674
2673 2675 def writetemp(contents):
2674 2676 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2675 2677 f = os.fdopen(fd, "wb")
2676 2678 f.write(contents)
2677 2679 f.close()
2678 2680 return name
2679 2681
2680 2682 problems = 0
2681 2683
2682 2684 fm = ui.formatter('debuginstall', opts)
2683 2685 fm.startitem()
2684 2686
2685 2687 # encoding
2686 2688 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2687 2689 err = None
2688 2690 try:
2689 2691 encoding.fromlocal("test")
2690 2692 except error.Abort as inst:
2691 2693 err = inst
2692 2694 problems += 1
2693 2695 fm.condwrite(err, 'encodingerror', _(" %s\n"
2694 2696 " (check that your locale is properly set)\n"), err)
2695 2697
2696 2698 # Python
2697 2699 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2698 2700 sys.executable)
2699 2701 fm.write('pythonver', _("checking Python version (%s)\n"),
2700 2702 ("%s.%s.%s" % sys.version_info[:3]))
2701 2703 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2702 2704 os.path.dirname(os.__file__))
2703 2705
2704 2706 # hg version
2705 2707 hgver = util.version()
2706 2708 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2707 2709 hgver.split('+')[0])
2708 2710 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2709 2711 '+'.join(hgver.split('+')[1:]))
2710 2712
2711 2713 # compiled modules
2712 2714 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2713 2715 policy.policy)
2714 2716 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2715 2717 os.path.dirname(__file__))
2716 2718
2717 2719 err = None
2718 2720 try:
2719 2721 from . import (
2720 2722 base85,
2721 2723 bdiff,
2722 2724 mpatch,
2723 2725 osutil,
2724 2726 )
2725 2727 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2726 2728 except Exception as inst:
2727 2729 err = inst
2728 2730 problems += 1
2729 2731 fm.condwrite(err, 'extensionserror', " %s\n", err)
2730 2732
2731 2733 # templates
2732 2734 p = templater.templatepaths()
2733 2735 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2734 2736 fm.condwrite(not p, '', _(" no template directories found\n"))
2735 2737 if p:
2736 2738 m = templater.templatepath("map-cmdline.default")
2737 2739 if m:
2738 2740 # template found, check if it is working
2739 2741 err = None
2740 2742 try:
2741 2743 templater.templater.frommapfile(m)
2742 2744 except Exception as inst:
2743 2745 err = inst
2744 2746 p = None
2745 2747 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2746 2748 else:
2747 2749 p = None
2748 2750 fm.condwrite(p, 'defaulttemplate',
2749 2751 _("checking default template (%s)\n"), m)
2750 2752 fm.condwrite(not m, 'defaulttemplatenotfound',
2751 2753 _(" template '%s' not found\n"), "default")
2752 2754 if not p:
2753 2755 problems += 1
2754 2756 fm.condwrite(not p, '',
2755 2757 _(" (templates seem to have been installed incorrectly)\n"))
2756 2758
2757 2759 # editor
2758 2760 editor = ui.geteditor()
2759 2761 editor = util.expandpath(editor)
2760 2762 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2761 2763 cmdpath = util.findexe(shlex.split(editor)[0])
2762 2764 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2763 2765 _(" No commit editor set and can't find %s in PATH\n"
2764 2766 " (specify a commit editor in your configuration"
2765 2767 " file)\n"), not cmdpath and editor == 'vi' and editor)
2766 2768 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2767 2769 _(" Can't find editor '%s' in PATH\n"
2768 2770 " (specify a commit editor in your configuration"
2769 2771 " file)\n"), not cmdpath and editor)
2770 2772 if not cmdpath and editor != 'vi':
2771 2773 problems += 1
2772 2774
2773 2775 # check username
2774 2776 username = None
2775 2777 err = None
2776 2778 try:
2777 2779 username = ui.username()
2778 2780 except error.Abort as e:
2779 2781 err = e
2780 2782 problems += 1
2781 2783
2782 2784 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2783 2785 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2784 2786 " (specify a username in your configuration file)\n"), err)
2785 2787
2786 2788 fm.condwrite(not problems, '',
2787 2789 _("no problems detected\n"))
2788 2790 if not problems:
2789 2791 fm.data(problems=problems)
2790 2792 fm.condwrite(problems, 'problems',
2791 2793 _("%d problems detected,"
2792 2794 " please check your install!\n"), problems)
2793 2795 fm.end()
2794 2796
2795 2797 return problems
2796 2798
2797 2799 @command('debugknown', [], _('REPO ID...'), norepo=True)
2798 2800 def debugknown(ui, repopath, *ids, **opts):
2799 2801 """test whether node ids are known to a repo
2800 2802
2801 2803 Every ID must be a full-length hex node id string. Returns a list of 0s
2802 2804 and 1s indicating unknown/known.
2803 2805 """
2804 2806 repo = hg.peer(ui, opts, repopath)
2805 2807 if not repo.capable('known'):
2806 2808 raise error.Abort("known() not supported by target repository")
2807 2809 flags = repo.known([bin(s) for s in ids])
2808 2810 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2809 2811
2810 2812 @command('debuglabelcomplete', [], _('LABEL...'))
2811 2813 def debuglabelcomplete(ui, repo, *args):
2812 2814 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2813 2815 debugnamecomplete(ui, repo, *args)
2814 2816
2815 2817 @command('debugmergestate', [], '')
2816 2818 def debugmergestate(ui, repo, *args):
2817 2819 """print merge state
2818 2820
2819 2821 Use --verbose to print out information about whether v1 or v2 merge state
2820 2822 was chosen."""
2821 2823 def _hashornull(h):
2822 2824 if h == nullhex:
2823 2825 return 'null'
2824 2826 else:
2825 2827 return h
2826 2828
2827 2829 def printrecords(version):
2828 2830 ui.write(('* version %s records\n') % version)
2829 2831 if version == 1:
2830 2832 records = v1records
2831 2833 else:
2832 2834 records = v2records
2833 2835
2834 2836 for rtype, record in records:
2835 2837 # pretty print some record types
2836 2838 if rtype == 'L':
2837 2839 ui.write(('local: %s\n') % record)
2838 2840 elif rtype == 'O':
2839 2841 ui.write(('other: %s\n') % record)
2840 2842 elif rtype == 'm':
2841 2843 driver, mdstate = record.split('\0', 1)
2842 2844 ui.write(('merge driver: %s (state "%s")\n')
2843 2845 % (driver, mdstate))
2844 2846 elif rtype in 'FDC':
2845 2847 r = record.split('\0')
2846 2848 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2847 2849 if version == 1:
2848 2850 onode = 'not stored in v1 format'
2849 2851 flags = r[7]
2850 2852 else:
2851 2853 onode, flags = r[7:9]
2852 2854 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2853 2855 % (f, rtype, state, _hashornull(hash)))
2854 2856 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2855 2857 ui.write((' ancestor path: %s (node %s)\n')
2856 2858 % (afile, _hashornull(anode)))
2857 2859 ui.write((' other path: %s (node %s)\n')
2858 2860 % (ofile, _hashornull(onode)))
2859 2861 elif rtype == 'f':
2860 2862 filename, rawextras = record.split('\0', 1)
2861 2863 extras = rawextras.split('\0')
2862 2864 i = 0
2863 2865 extrastrings = []
2864 2866 while i < len(extras):
2865 2867 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2866 2868 i += 2
2867 2869
2868 2870 ui.write(('file extras: %s (%s)\n')
2869 2871 % (filename, ', '.join(extrastrings)))
2870 2872 elif rtype == 'l':
2871 2873 labels = record.split('\0', 2)
2872 2874 labels = [l for l in labels if len(l) > 0]
2873 2875 ui.write(('labels:\n'))
2874 2876 ui.write((' local: %s\n' % labels[0]))
2875 2877 ui.write((' other: %s\n' % labels[1]))
2876 2878 if len(labels) > 2:
2877 2879 ui.write((' base: %s\n' % labels[2]))
2878 2880 else:
2879 2881 ui.write(('unrecognized entry: %s\t%s\n')
2880 2882 % (rtype, record.replace('\0', '\t')))
2881 2883
2882 2884 # Avoid mergestate.read() since it may raise an exception for unsupported
2883 2885 # merge state records. We shouldn't be doing this, but this is OK since this
2884 2886 # command is pretty low-level.
2885 2887 ms = mergemod.mergestate(repo)
2886 2888
2887 2889 # sort so that reasonable information is on top
2888 2890 v1records = ms._readrecordsv1()
2889 2891 v2records = ms._readrecordsv2()
2890 2892 order = 'LOml'
2891 2893 def key(r):
2892 2894 idx = order.find(r[0])
2893 2895 if idx == -1:
2894 2896 return (1, r[1])
2895 2897 else:
2896 2898 return (0, idx)
2897 2899 v1records.sort(key=key)
2898 2900 v2records.sort(key=key)
2899 2901
2900 2902 if not v1records and not v2records:
2901 2903 ui.write(('no merge state found\n'))
2902 2904 elif not v2records:
2903 2905 ui.note(('no version 2 merge state\n'))
2904 2906 printrecords(1)
2905 2907 elif ms._v1v2match(v1records, v2records):
2906 2908 ui.note(('v1 and v2 states match: using v2\n'))
2907 2909 printrecords(2)
2908 2910 else:
2909 2911 ui.note(('v1 and v2 states mismatch: using v1\n'))
2910 2912 printrecords(1)
2911 2913 if ui.verbose:
2912 2914 printrecords(2)
2913 2915
2914 2916 @command('debugnamecomplete', [], _('NAME...'))
2915 2917 def debugnamecomplete(ui, repo, *args):
2916 2918 '''complete "names" - tags, open branch names, bookmark names'''
2917 2919
2918 2920 names = set()
2919 2921 # since we previously only listed open branches, we will handle that
2920 2922 # specially (after this for loop)
2921 2923 for name, ns in repo.names.iteritems():
2922 2924 if name != 'branches':
2923 2925 names.update(ns.listnames(repo))
2924 2926 names.update(tag for (tag, heads, tip, closed)
2925 2927 in repo.branchmap().iterbranches() if not closed)
2926 2928 completions = set()
2927 2929 if not args:
2928 2930 args = ['']
2929 2931 for a in args:
2930 2932 completions.update(n for n in names if n.startswith(a))
2931 2933 ui.write('\n'.join(sorted(completions)))
2932 2934 ui.write('\n')
2933 2935
2934 2936 @command('debuglocks',
2935 2937 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2936 2938 ('W', 'force-wlock', None,
2937 2939 _('free the working state lock (DANGEROUS)'))],
2938 2940 _('[OPTION]...'))
2939 2941 def debuglocks(ui, repo, **opts):
2940 2942 """show or modify state of locks
2941 2943
2942 2944 By default, this command will show which locks are held. This
2943 2945 includes the user and process holding the lock, the amount of time
2944 2946 the lock has been held, and the machine name where the process is
2945 2947 running if it's not local.
2946 2948
2947 2949 Locks protect the integrity of Mercurial's data, so should be
2948 2950 treated with care. System crashes or other interruptions may cause
2949 2951 locks to not be properly released, though Mercurial will usually
2950 2952 detect and remove such stale locks automatically.
2951 2953
2952 2954 However, detecting stale locks may not always be possible (for
2953 2955 instance, on a shared filesystem). Removing locks may also be
2954 2956 blocked by filesystem permissions.
2955 2957
2956 2958 Returns 0 if no locks are held.
2957 2959
2958 2960 """
2959 2961
2960 2962 if opts.get('force_lock'):
2961 2963 repo.svfs.unlink('lock')
2962 2964 if opts.get('force_wlock'):
2963 2965 repo.vfs.unlink('wlock')
2964 2966 if opts.get('force_lock') or opts.get('force_lock'):
2965 2967 return 0
2966 2968
2967 2969 now = time.time()
2968 2970 held = 0
2969 2971
2970 2972 def report(vfs, name, method):
2971 2973 # this causes stale locks to get reaped for more accurate reporting
2972 2974 try:
2973 2975 l = method(False)
2974 2976 except error.LockHeld:
2975 2977 l = None
2976 2978
2977 2979 if l:
2978 2980 l.release()
2979 2981 else:
2980 2982 try:
2981 2983 stat = vfs.lstat(name)
2982 2984 age = now - stat.st_mtime
2983 2985 user = util.username(stat.st_uid)
2984 2986 locker = vfs.readlock(name)
2985 2987 if ":" in locker:
2986 2988 host, pid = locker.split(':')
2987 2989 if host == socket.gethostname():
2988 2990 locker = 'user %s, process %s' % (user, pid)
2989 2991 else:
2990 2992 locker = 'user %s, process %s, host %s' \
2991 2993 % (user, pid, host)
2992 2994 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
2993 2995 return 1
2994 2996 except OSError as e:
2995 2997 if e.errno != errno.ENOENT:
2996 2998 raise
2997 2999
2998 3000 ui.write(("%-6s free\n") % (name + ":"))
2999 3001 return 0
3000 3002
3001 3003 held += report(repo.svfs, "lock", repo.lock)
3002 3004 held += report(repo.vfs, "wlock", repo.wlock)
3003 3005
3004 3006 return held
3005 3007
3006 3008 @command('debugobsolete',
3007 3009 [('', 'flags', 0, _('markers flag')),
3008 3010 ('', 'record-parents', False,
3009 3011 _('record parent information for the precursor')),
3010 3012 ('r', 'rev', [], _('display markers relevant to REV')),
3011 3013 ('', 'index', False, _('display index of the marker')),
3012 3014 ('', 'delete', [], _('delete markers specified by indices')),
3013 3015 ] + commitopts2 + formatteropts,
3014 3016 _('[OBSOLETED [REPLACEMENT ...]]'))
3015 3017 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3016 3018 """create arbitrary obsolete marker
3017 3019
3018 3020 With no arguments, displays the list of obsolescence markers."""
3019 3021
3020 3022 def parsenodeid(s):
3021 3023 try:
3022 3024 # We do not use revsingle/revrange functions here to accept
3023 3025 # arbitrary node identifiers, possibly not present in the
3024 3026 # local repository.
3025 3027 n = bin(s)
3026 3028 if len(n) != len(nullid):
3027 3029 raise TypeError()
3028 3030 return n
3029 3031 except TypeError:
3030 3032 raise error.Abort('changeset references must be full hexadecimal '
3031 3033 'node identifiers')
3032 3034
3033 3035 if opts.get('delete'):
3034 3036 indices = []
3035 3037 for v in opts.get('delete'):
3036 3038 try:
3037 3039 indices.append(int(v))
3038 3040 except ValueError:
3039 3041 raise error.Abort(_('invalid index value: %r') % v,
3040 3042 hint=_('use integers for indices'))
3041 3043
3042 3044 if repo.currenttransaction():
3043 3045 raise error.Abort(_('cannot delete obsmarkers in the middle '
3044 3046 'of transaction.'))
3045 3047
3046 3048 with repo.lock():
3047 3049 n = repair.deleteobsmarkers(repo.obsstore, indices)
3048 3050 ui.write(_('deleted %i obsolescense markers\n') % n)
3049 3051
3050 3052 return
3051 3053
3052 3054 if precursor is not None:
3053 3055 if opts['rev']:
3054 3056 raise error.Abort('cannot select revision when creating marker')
3055 3057 metadata = {}
3056 3058 metadata['user'] = opts['user'] or ui.username()
3057 3059 succs = tuple(parsenodeid(succ) for succ in successors)
3058 3060 l = repo.lock()
3059 3061 try:
3060 3062 tr = repo.transaction('debugobsolete')
3061 3063 try:
3062 3064 date = opts.get('date')
3063 3065 if date:
3064 3066 date = util.parsedate(date)
3065 3067 else:
3066 3068 date = None
3067 3069 prec = parsenodeid(precursor)
3068 3070 parents = None
3069 3071 if opts['record_parents']:
3070 3072 if prec not in repo.unfiltered():
3071 3073 raise error.Abort('cannot used --record-parents on '
3072 3074 'unknown changesets')
3073 3075 parents = repo.unfiltered()[prec].parents()
3074 3076 parents = tuple(p.node() for p in parents)
3075 3077 repo.obsstore.create(tr, prec, succs, opts['flags'],
3076 3078 parents=parents, date=date,
3077 3079 metadata=metadata)
3078 3080 tr.close()
3079 3081 except ValueError as exc:
3080 3082 raise error.Abort(_('bad obsmarker input: %s') % exc)
3081 3083 finally:
3082 3084 tr.release()
3083 3085 finally:
3084 3086 l.release()
3085 3087 else:
3086 3088 if opts['rev']:
3087 3089 revs = scmutil.revrange(repo, opts['rev'])
3088 3090 nodes = [repo[r].node() for r in revs]
3089 3091 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3090 3092 markers.sort(key=lambda x: x._data)
3091 3093 else:
3092 3094 markers = obsolete.getmarkers(repo)
3093 3095
3094 3096 markerstoiter = markers
3095 3097 isrelevant = lambda m: True
3096 3098 if opts.get('rev') and opts.get('index'):
3097 3099 markerstoiter = obsolete.getmarkers(repo)
3098 3100 markerset = set(markers)
3099 3101 isrelevant = lambda m: m in markerset
3100 3102
3101 3103 fm = ui.formatter('debugobsolete', opts)
3102 3104 for i, m in enumerate(markerstoiter):
3103 3105 if not isrelevant(m):
3104 3106 # marker can be irrelevant when we're iterating over a set
3105 3107 # of markers (markerstoiter) which is bigger than the set
3106 3108 # of markers we want to display (markers)
3107 3109 # this can happen if both --index and --rev options are
3108 3110 # provided and thus we need to iterate over all of the markers
3109 3111 # to get the correct indices, but only display the ones that
3110 3112 # are relevant to --rev value
3111 3113 continue
3112 3114 fm.startitem()
3113 3115 ind = i if opts.get('index') else None
3114 3116 cmdutil.showmarker(fm, m, index=ind)
3115 3117 fm.end()
3116 3118
3117 3119 @command('debugpathcomplete',
3118 3120 [('f', 'full', None, _('complete an entire path')),
3119 3121 ('n', 'normal', None, _('show only normal files')),
3120 3122 ('a', 'added', None, _('show only added files')),
3121 3123 ('r', 'removed', None, _('show only removed files'))],
3122 3124 _('FILESPEC...'))
3123 3125 def debugpathcomplete(ui, repo, *specs, **opts):
3124 3126 '''complete part or all of a tracked path
3125 3127
3126 3128 This command supports shells that offer path name completion. It
3127 3129 currently completes only files already known to the dirstate.
3128 3130
3129 3131 Completion extends only to the next path segment unless
3130 3132 --full is specified, in which case entire paths are used.'''
3131 3133
3132 3134 def complete(path, acceptable):
3133 3135 dirstate = repo.dirstate
3134 3136 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3135 3137 rootdir = repo.root + os.sep
3136 3138 if spec != repo.root and not spec.startswith(rootdir):
3137 3139 return [], []
3138 3140 if os.path.isdir(spec):
3139 3141 spec += '/'
3140 3142 spec = spec[len(rootdir):]
3141 3143 fixpaths = os.sep != '/'
3142 3144 if fixpaths:
3143 3145 spec = spec.replace(os.sep, '/')
3144 3146 speclen = len(spec)
3145 3147 fullpaths = opts['full']
3146 3148 files, dirs = set(), set()
3147 3149 adddir, addfile = dirs.add, files.add
3148 3150 for f, st in dirstate.iteritems():
3149 3151 if f.startswith(spec) and st[0] in acceptable:
3150 3152 if fixpaths:
3151 3153 f = f.replace('/', os.sep)
3152 3154 if fullpaths:
3153 3155 addfile(f)
3154 3156 continue
3155 3157 s = f.find(os.sep, speclen)
3156 3158 if s >= 0:
3157 3159 adddir(f[:s])
3158 3160 else:
3159 3161 addfile(f)
3160 3162 return files, dirs
3161 3163
3162 3164 acceptable = ''
3163 3165 if opts['normal']:
3164 3166 acceptable += 'nm'
3165 3167 if opts['added']:
3166 3168 acceptable += 'a'
3167 3169 if opts['removed']:
3168 3170 acceptable += 'r'
3169 3171 cwd = repo.getcwd()
3170 3172 if not specs:
3171 3173 specs = ['.']
3172 3174
3173 3175 files, dirs = set(), set()
3174 3176 for spec in specs:
3175 3177 f, d = complete(spec, acceptable or 'nmar')
3176 3178 files.update(f)
3177 3179 dirs.update(d)
3178 3180 files.update(dirs)
3179 3181 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3180 3182 ui.write('\n')
3181 3183
3182 3184 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3183 3185 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3184 3186 '''access the pushkey key/value protocol
3185 3187
3186 3188 With two args, list the keys in the given namespace.
3187 3189
3188 3190 With five args, set a key to new if it currently is set to old.
3189 3191 Reports success or failure.
3190 3192 '''
3191 3193
3192 3194 target = hg.peer(ui, {}, repopath)
3193 3195 if keyinfo:
3194 3196 key, old, new = keyinfo
3195 3197 r = target.pushkey(namespace, key, old, new)
3196 3198 ui.status(str(r) + '\n')
3197 3199 return not r
3198 3200 else:
3199 3201 for k, v in sorted(target.listkeys(namespace).iteritems()):
3200 3202 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3201 3203 v.encode('string-escape')))
3202 3204
3203 3205 @command('debugpvec', [], _('A B'))
3204 3206 def debugpvec(ui, repo, a, b=None):
3205 3207 ca = scmutil.revsingle(repo, a)
3206 3208 cb = scmutil.revsingle(repo, b)
3207 3209 pa = pvec.ctxpvec(ca)
3208 3210 pb = pvec.ctxpvec(cb)
3209 3211 if pa == pb:
3210 3212 rel = "="
3211 3213 elif pa > pb:
3212 3214 rel = ">"
3213 3215 elif pa < pb:
3214 3216 rel = "<"
3215 3217 elif pa | pb:
3216 3218 rel = "|"
3217 3219 ui.write(_("a: %s\n") % pa)
3218 3220 ui.write(_("b: %s\n") % pb)
3219 3221 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3220 3222 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3221 3223 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3222 3224 pa.distance(pb), rel))
3223 3225
3224 3226 @command('debugrebuilddirstate|debugrebuildstate',
3225 3227 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3226 3228 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3227 3229 'the working copy parent')),
3228 3230 ],
3229 3231 _('[-r REV]'))
3230 3232 def debugrebuilddirstate(ui, repo, rev, **opts):
3231 3233 """rebuild the dirstate as it would look like for the given revision
3232 3234
3233 3235 If no revision is specified the first current parent will be used.
3234 3236
3235 3237 The dirstate will be set to the files of the given revision.
3236 3238 The actual working directory content or existing dirstate
3237 3239 information such as adds or removes is not considered.
3238 3240
3239 3241 ``minimal`` will only rebuild the dirstate status for files that claim to be
3240 3242 tracked but are not in the parent manifest, or that exist in the parent
3241 3243 manifest but are not in the dirstate. It will not change adds, removes, or
3242 3244 modified files that are in the working copy parent.
3243 3245
3244 3246 One use of this command is to make the next :hg:`status` invocation
3245 3247 check the actual file content.
3246 3248 """
3247 3249 ctx = scmutil.revsingle(repo, rev)
3248 3250 with repo.wlock():
3249 3251 dirstate = repo.dirstate
3250 3252 changedfiles = None
3251 3253 # See command doc for what minimal does.
3252 3254 if opts.get('minimal'):
3253 3255 manifestfiles = set(ctx.manifest().keys())
3254 3256 dirstatefiles = set(dirstate)
3255 3257 manifestonly = manifestfiles - dirstatefiles
3256 3258 dsonly = dirstatefiles - manifestfiles
3257 3259 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3258 3260 changedfiles = manifestonly | dsnotadded
3259 3261
3260 3262 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3261 3263
3262 3264 @command('debugrebuildfncache', [], '')
3263 3265 def debugrebuildfncache(ui, repo):
3264 3266 """rebuild the fncache file"""
3265 3267 repair.rebuildfncache(ui, repo)
3266 3268
3267 3269 @command('debugrename',
3268 3270 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3269 3271 _('[-r REV] FILE'))
3270 3272 def debugrename(ui, repo, file1, *pats, **opts):
3271 3273 """dump rename information"""
3272 3274
3273 3275 ctx = scmutil.revsingle(repo, opts.get('rev'))
3274 3276 m = scmutil.match(ctx, (file1,) + pats, opts)
3275 3277 for abs in ctx.walk(m):
3276 3278 fctx = ctx[abs]
3277 3279 o = fctx.filelog().renamed(fctx.filenode())
3278 3280 rel = m.rel(abs)
3279 3281 if o:
3280 3282 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3281 3283 else:
3282 3284 ui.write(_("%s not renamed\n") % rel)
3283 3285
3284 3286 @command('debugrevlog', debugrevlogopts +
3285 3287 [('d', 'dump', False, _('dump index data'))],
3286 3288 _('-c|-m|FILE'),
3287 3289 optionalrepo=True)
3288 3290 def debugrevlog(ui, repo, file_=None, **opts):
3289 3291 """show data and statistics about a revlog"""
3290 3292 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3291 3293
3292 3294 if opts.get("dump"):
3293 3295 numrevs = len(r)
3294 3296 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
3295 3297 " rawsize totalsize compression heads chainlen\n"))
3296 3298 ts = 0
3297 3299 heads = set()
3298 3300
3299 3301 for rev in xrange(numrevs):
3300 3302 dbase = r.deltaparent(rev)
3301 3303 if dbase == -1:
3302 3304 dbase = rev
3303 3305 cbase = r.chainbase(rev)
3304 3306 clen = r.chainlen(rev)
3305 3307 p1, p2 = r.parentrevs(rev)
3306 3308 rs = r.rawsize(rev)
3307 3309 ts = ts + rs
3308 3310 heads -= set(r.parentrevs(rev))
3309 3311 heads.add(rev)
3310 3312 try:
3311 3313 compression = ts / r.end(rev)
3312 3314 except ZeroDivisionError:
3313 3315 compression = 0
3314 3316 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3315 3317 "%11d %5d %8d\n" %
3316 3318 (rev, p1, p2, r.start(rev), r.end(rev),
3317 3319 r.start(dbase), r.start(cbase),
3318 3320 r.start(p1), r.start(p2),
3319 3321 rs, ts, compression, len(heads), clen))
3320 3322 return 0
3321 3323
3322 3324 v = r.version
3323 3325 format = v & 0xFFFF
3324 3326 flags = []
3325 3327 gdelta = False
3326 3328 if v & revlog.REVLOGNGINLINEDATA:
3327 3329 flags.append('inline')
3328 3330 if v & revlog.REVLOGGENERALDELTA:
3329 3331 gdelta = True
3330 3332 flags.append('generaldelta')
3331 3333 if not flags:
3332 3334 flags = ['(none)']
3333 3335
3334 3336 nummerges = 0
3335 3337 numfull = 0
3336 3338 numprev = 0
3337 3339 nump1 = 0
3338 3340 nump2 = 0
3339 3341 numother = 0
3340 3342 nump1prev = 0
3341 3343 nump2prev = 0
3342 3344 chainlengths = []
3343 3345
3344 3346 datasize = [None, 0, 0]
3345 3347 fullsize = [None, 0, 0]
3346 3348 deltasize = [None, 0, 0]
3347 3349
3348 3350 def addsize(size, l):
3349 3351 if l[0] is None or size < l[0]:
3350 3352 l[0] = size
3351 3353 if size > l[1]:
3352 3354 l[1] = size
3353 3355 l[2] += size
3354 3356
3355 3357 numrevs = len(r)
3356 3358 for rev in xrange(numrevs):
3357 3359 p1, p2 = r.parentrevs(rev)
3358 3360 delta = r.deltaparent(rev)
3359 3361 if format > 0:
3360 3362 addsize(r.rawsize(rev), datasize)
3361 3363 if p2 != nullrev:
3362 3364 nummerges += 1
3363 3365 size = r.length(rev)
3364 3366 if delta == nullrev:
3365 3367 chainlengths.append(0)
3366 3368 numfull += 1
3367 3369 addsize(size, fullsize)
3368 3370 else:
3369 3371 chainlengths.append(chainlengths[delta] + 1)
3370 3372 addsize(size, deltasize)
3371 3373 if delta == rev - 1:
3372 3374 numprev += 1
3373 3375 if delta == p1:
3374 3376 nump1prev += 1
3375 3377 elif delta == p2:
3376 3378 nump2prev += 1
3377 3379 elif delta == p1:
3378 3380 nump1 += 1
3379 3381 elif delta == p2:
3380 3382 nump2 += 1
3381 3383 elif delta != nullrev:
3382 3384 numother += 1
3383 3385
3384 3386 # Adjust size min value for empty cases
3385 3387 for size in (datasize, fullsize, deltasize):
3386 3388 if size[0] is None:
3387 3389 size[0] = 0
3388 3390
3389 3391 numdeltas = numrevs - numfull
3390 3392 numoprev = numprev - nump1prev - nump2prev
3391 3393 totalrawsize = datasize[2]
3392 3394 datasize[2] /= numrevs
3393 3395 fulltotal = fullsize[2]
3394 3396 fullsize[2] /= numfull
3395 3397 deltatotal = deltasize[2]
3396 3398 if numrevs - numfull > 0:
3397 3399 deltasize[2] /= numrevs - numfull
3398 3400 totalsize = fulltotal + deltatotal
3399 3401 avgchainlen = sum(chainlengths) / numrevs
3400 3402 maxchainlen = max(chainlengths)
3401 3403 compratio = 1
3402 3404 if totalsize:
3403 3405 compratio = totalrawsize / totalsize
3404 3406
3405 3407 basedfmtstr = '%%%dd\n'
3406 3408 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3407 3409
3408 3410 def dfmtstr(max):
3409 3411 return basedfmtstr % len(str(max))
3410 3412 def pcfmtstr(max, padding=0):
3411 3413 return basepcfmtstr % (len(str(max)), ' ' * padding)
3412 3414
3413 3415 def pcfmt(value, total):
3414 3416 if total:
3415 3417 return (value, 100 * float(value) / total)
3416 3418 else:
3417 3419 return value, 100.0
3418 3420
3419 3421 ui.write(('format : %d\n') % format)
3420 3422 ui.write(('flags : %s\n') % ', '.join(flags))
3421 3423
3422 3424 ui.write('\n')
3423 3425 fmt = pcfmtstr(totalsize)
3424 3426 fmt2 = dfmtstr(totalsize)
3425 3427 ui.write(('revisions : ') + fmt2 % numrevs)
3426 3428 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3427 3429 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3428 3430 ui.write(('revisions : ') + fmt2 % numrevs)
3429 3431 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3430 3432 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3431 3433 ui.write(('revision size : ') + fmt2 % totalsize)
3432 3434 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3433 3435 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3434 3436
3435 3437 ui.write('\n')
3436 3438 fmt = dfmtstr(max(avgchainlen, compratio))
3437 3439 ui.write(('avg chain length : ') + fmt % avgchainlen)
3438 3440 ui.write(('max chain length : ') + fmt % maxchainlen)
3439 3441 ui.write(('compression ratio : ') + fmt % compratio)
3440 3442
3441 3443 if format > 0:
3442 3444 ui.write('\n')
3443 3445 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3444 3446 % tuple(datasize))
3445 3447 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3446 3448 % tuple(fullsize))
3447 3449 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3448 3450 % tuple(deltasize))
3449 3451
3450 3452 if numdeltas > 0:
3451 3453 ui.write('\n')
3452 3454 fmt = pcfmtstr(numdeltas)
3453 3455 fmt2 = pcfmtstr(numdeltas, 4)
3454 3456 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3455 3457 if numprev > 0:
3456 3458 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3457 3459 numprev))
3458 3460 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3459 3461 numprev))
3460 3462 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3461 3463 numprev))
3462 3464 if gdelta:
3463 3465 ui.write(('deltas against p1 : ')
3464 3466 + fmt % pcfmt(nump1, numdeltas))
3465 3467 ui.write(('deltas against p2 : ')
3466 3468 + fmt % pcfmt(nump2, numdeltas))
3467 3469 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3468 3470 numdeltas))
3469 3471
3470 3472 @command('debugrevspec',
3471 3473 [('', 'optimize', None,
3472 3474 _('print parsed tree after optimizing (DEPRECATED)')),
3473 3475 ('p', 'show-stage', [],
3474 3476 _('print parsed tree at the given stage'), _('NAME')),
3475 3477 ('', 'no-optimized', False, _('evaluate tree without optimization')),
3476 3478 ('', 'verify-optimized', False, _('verify optimized result')),
3477 3479 ],
3478 3480 ('REVSPEC'))
3479 3481 def debugrevspec(ui, repo, expr, **opts):
3480 3482 """parse and apply a revision specification
3481 3483
3482 3484 Use -p/--show-stage option to print the parsed tree at the given stages.
3483 3485 Use -p all to print tree at every stage.
3484 3486
3485 3487 Use --verify-optimized to compare the optimized result with the unoptimized
3486 3488 one. Returns 1 if the optimized result differs.
3487 3489 """
3488 3490 stages = [
3489 3491 ('parsed', lambda tree: tree),
3490 3492 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
3491 3493 ('concatenated', revset.foldconcat),
3492 3494 ('analyzed', revset.analyze),
3493 3495 ('optimized', revset.optimize),
3494 3496 ]
3495 3497 if opts['no_optimized']:
3496 3498 stages = stages[:-1]
3497 3499 if opts['verify_optimized'] and opts['no_optimized']:
3498 3500 raise error.Abort(_('cannot use --verify-optimized with '
3499 3501 '--no-optimized'))
3500 3502 stagenames = set(n for n, f in stages)
3501 3503
3502 3504 showalways = set()
3503 3505 showchanged = set()
3504 3506 if ui.verbose and not opts['show_stage']:
3505 3507 # show parsed tree by --verbose (deprecated)
3506 3508 showalways.add('parsed')
3507 3509 showchanged.update(['expanded', 'concatenated'])
3508 3510 if opts['optimize']:
3509 3511 showalways.add('optimized')
3510 3512 if opts['show_stage'] and opts['optimize']:
3511 3513 raise error.Abort(_('cannot use --optimize with --show-stage'))
3512 3514 if opts['show_stage'] == ['all']:
3513 3515 showalways.update(stagenames)
3514 3516 else:
3515 3517 for n in opts['show_stage']:
3516 3518 if n not in stagenames:
3517 3519 raise error.Abort(_('invalid stage name: %s') % n)
3518 3520 showalways.update(opts['show_stage'])
3519 3521
3520 3522 treebystage = {}
3521 3523 printedtree = None
3522 3524 tree = revset.parse(expr, lookup=repo.__contains__)
3523 3525 for n, f in stages:
3524 3526 treebystage[n] = tree = f(tree)
3525 3527 if n in showalways or (n in showchanged and tree != printedtree):
3526 3528 if opts['show_stage'] or n != 'parsed':
3527 3529 ui.write(("* %s:\n") % n)
3528 3530 ui.write(revset.prettyformat(tree), "\n")
3529 3531 printedtree = tree
3530 3532
3531 3533 if opts['verify_optimized']:
3532 3534 arevs = revset.makematcher(treebystage['analyzed'])(repo)
3533 3535 brevs = revset.makematcher(treebystage['optimized'])(repo)
3534 3536 if ui.verbose:
3535 3537 ui.note(("* analyzed set:\n"), revset.prettyformatset(arevs), "\n")
3536 3538 ui.note(("* optimized set:\n"), revset.prettyformatset(brevs), "\n")
3537 3539 arevs = list(arevs)
3538 3540 brevs = list(brevs)
3539 3541 if arevs == brevs:
3540 3542 return 0
3541 3543 ui.write(('--- analyzed\n'), label='diff.file_a')
3542 3544 ui.write(('+++ optimized\n'), label='diff.file_b')
3543 3545 sm = difflib.SequenceMatcher(None, arevs, brevs)
3544 3546 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3545 3547 if tag in ('delete', 'replace'):
3546 3548 for c in arevs[alo:ahi]:
3547 3549 ui.write('-%s\n' % c, label='diff.deleted')
3548 3550 if tag in ('insert', 'replace'):
3549 3551 for c in brevs[blo:bhi]:
3550 3552 ui.write('+%s\n' % c, label='diff.inserted')
3551 3553 if tag == 'equal':
3552 3554 for c in arevs[alo:ahi]:
3553 3555 ui.write(' %s\n' % c)
3554 3556 return 1
3555 3557
3556 3558 func = revset.makematcher(tree)
3557 3559 revs = func(repo)
3558 3560 if ui.verbose:
3559 3561 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3560 3562 for c in revs:
3561 3563 ui.write("%s\n" % c)
3562 3564
3563 3565 @command('debugsetparents', [], _('REV1 [REV2]'))
3564 3566 def debugsetparents(ui, repo, rev1, rev2=None):
3565 3567 """manually set the parents of the current working directory
3566 3568
3567 3569 This is useful for writing repository conversion tools, but should
3568 3570 be used with care. For example, neither the working directory nor the
3569 3571 dirstate is updated, so file status may be incorrect after running this
3570 3572 command.
3571 3573
3572 3574 Returns 0 on success.
3573 3575 """
3574 3576
3575 3577 r1 = scmutil.revsingle(repo, rev1).node()
3576 3578 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3577 3579
3578 3580 with repo.wlock():
3579 3581 repo.setparents(r1, r2)
3580 3582
3581 3583 @command('debugdirstate|debugstate',
3582 3584 [('', 'nodates', None, _('do not display the saved mtime')),
3583 3585 ('', 'datesort', None, _('sort by saved mtime'))],
3584 3586 _('[OPTION]...'))
3585 3587 def debugstate(ui, repo, **opts):
3586 3588 """show the contents of the current dirstate"""
3587 3589
3588 3590 nodates = opts.get('nodates')
3589 3591 datesort = opts.get('datesort')
3590 3592
3591 3593 timestr = ""
3592 3594 if datesort:
3593 3595 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3594 3596 else:
3595 3597 keyfunc = None # sort by filename
3596 3598 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3597 3599 if ent[3] == -1:
3598 3600 timestr = 'unset '
3599 3601 elif nodates:
3600 3602 timestr = 'set '
3601 3603 else:
3602 3604 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3603 3605 time.localtime(ent[3]))
3604 3606 if ent[1] & 0o20000:
3605 3607 mode = 'lnk'
3606 3608 else:
3607 3609 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3608 3610 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3609 3611 for f in repo.dirstate.copies():
3610 3612 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3611 3613
3612 3614 @command('debugsub',
3613 3615 [('r', 'rev', '',
3614 3616 _('revision to check'), _('REV'))],
3615 3617 _('[-r REV] [REV]'))
3616 3618 def debugsub(ui, repo, rev=None):
3617 3619 ctx = scmutil.revsingle(repo, rev, None)
3618 3620 for k, v in sorted(ctx.substate.items()):
3619 3621 ui.write(('path %s\n') % k)
3620 3622 ui.write((' source %s\n') % v[0])
3621 3623 ui.write((' revision %s\n') % v[1])
3622 3624
3623 3625 @command('debugsuccessorssets',
3624 3626 [],
3625 3627 _('[REV]'))
3626 3628 def debugsuccessorssets(ui, repo, *revs):
3627 3629 """show set of successors for revision
3628 3630
3629 3631 A successors set of changeset A is a consistent group of revisions that
3630 3632 succeed A. It contains non-obsolete changesets only.
3631 3633
3632 3634 In most cases a changeset A has a single successors set containing a single
3633 3635 successor (changeset A replaced by A').
3634 3636
3635 3637 A changeset that is made obsolete with no successors are called "pruned".
3636 3638 Such changesets have no successors sets at all.
3637 3639
3638 3640 A changeset that has been "split" will have a successors set containing
3639 3641 more than one successor.
3640 3642
3641 3643 A changeset that has been rewritten in multiple different ways is called
3642 3644 "divergent". Such changesets have multiple successor sets (each of which
3643 3645 may also be split, i.e. have multiple successors).
3644 3646
3645 3647 Results are displayed as follows::
3646 3648
3647 3649 <rev1>
3648 3650 <successors-1A>
3649 3651 <rev2>
3650 3652 <successors-2A>
3651 3653 <successors-2B1> <successors-2B2> <successors-2B3>
3652 3654
3653 3655 Here rev2 has two possible (i.e. divergent) successors sets. The first
3654 3656 holds one element, whereas the second holds three (i.e. the changeset has
3655 3657 been split).
3656 3658 """
3657 3659 # passed to successorssets caching computation from one call to another
3658 3660 cache = {}
3659 3661 ctx2str = str
3660 3662 node2str = short
3661 3663 if ui.debug():
3662 3664 def ctx2str(ctx):
3663 3665 return ctx.hex()
3664 3666 node2str = hex
3665 3667 for rev in scmutil.revrange(repo, revs):
3666 3668 ctx = repo[rev]
3667 3669 ui.write('%s\n'% ctx2str(ctx))
3668 3670 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3669 3671 if succsset:
3670 3672 ui.write(' ')
3671 3673 ui.write(node2str(succsset[0]))
3672 3674 for node in succsset[1:]:
3673 3675 ui.write(' ')
3674 3676 ui.write(node2str(node))
3675 3677 ui.write('\n')
3676 3678
3677 3679 @command('debugtemplate',
3678 3680 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3679 3681 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3680 3682 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3681 3683 optionalrepo=True)
3682 3684 def debugtemplate(ui, repo, tmpl, **opts):
3683 3685 """parse and apply a template
3684 3686
3685 3687 If -r/--rev is given, the template is processed as a log template and
3686 3688 applied to the given changesets. Otherwise, it is processed as a generic
3687 3689 template.
3688 3690
3689 3691 Use --verbose to print the parsed tree.
3690 3692 """
3691 3693 revs = None
3692 3694 if opts['rev']:
3693 3695 if repo is None:
3694 3696 raise error.RepoError(_('there is no Mercurial repository here '
3695 3697 '(.hg not found)'))
3696 3698 revs = scmutil.revrange(repo, opts['rev'])
3697 3699
3698 3700 props = {}
3699 3701 for d in opts['define']:
3700 3702 try:
3701 3703 k, v = (e.strip() for e in d.split('=', 1))
3702 3704 if not k:
3703 3705 raise ValueError
3704 3706 props[k] = v
3705 3707 except ValueError:
3706 3708 raise error.Abort(_('malformed keyword definition: %s') % d)
3707 3709
3708 3710 if ui.verbose:
3709 3711 aliases = ui.configitems('templatealias')
3710 3712 tree = templater.parse(tmpl)
3711 3713 ui.note(templater.prettyformat(tree), '\n')
3712 3714 newtree = templater.expandaliases(tree, aliases)
3713 3715 if newtree != tree:
3714 3716 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3715 3717
3716 3718 mapfile = None
3717 3719 if revs is None:
3718 3720 k = 'debugtemplate'
3719 3721 t = formatter.maketemplater(ui, k, tmpl)
3720 3722 ui.write(templater.stringify(t(k, **props)))
3721 3723 else:
3722 3724 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3723 3725 mapfile, buffered=False)
3724 3726 for r in revs:
3725 3727 displayer.show(repo[r], **props)
3726 3728 displayer.close()
3727 3729
3728 3730 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3729 3731 def debugwalk(ui, repo, *pats, **opts):
3730 3732 """show how files match on given patterns"""
3731 3733 m = scmutil.match(repo[None], pats, opts)
3732 3734 items = list(repo.walk(m))
3733 3735 if not items:
3734 3736 return
3735 3737 f = lambda fn: fn
3736 3738 if ui.configbool('ui', 'slash') and os.sep != '/':
3737 3739 f = lambda fn: util.normpath(fn)
3738 3740 fmt = 'f %%-%ds %%-%ds %%s' % (
3739 3741 max([len(abs) for abs in items]),
3740 3742 max([len(m.rel(abs)) for abs in items]))
3741 3743 for abs in items:
3742 3744 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3743 3745 ui.write("%s\n" % line.rstrip())
3744 3746
3745 3747 @command('debugwireargs',
3746 3748 [('', 'three', '', 'three'),
3747 3749 ('', 'four', '', 'four'),
3748 3750 ('', 'five', '', 'five'),
3749 3751 ] + remoteopts,
3750 3752 _('REPO [OPTIONS]... [ONE [TWO]]'),
3751 3753 norepo=True)
3752 3754 def debugwireargs(ui, repopath, *vals, **opts):
3753 3755 repo = hg.peer(ui, opts, repopath)
3754 3756 for opt in remoteopts:
3755 3757 del opts[opt[1]]
3756 3758 args = {}
3757 3759 for k, v in opts.iteritems():
3758 3760 if v:
3759 3761 args[k] = v
3760 3762 # run twice to check that we don't mess up the stream for the next command
3761 3763 res1 = repo.debugwireargs(*vals, **args)
3762 3764 res2 = repo.debugwireargs(*vals, **args)
3763 3765 ui.write("%s\n" % res1)
3764 3766 if res1 != res2:
3765 3767 ui.warn("%s\n" % res2)
3766 3768
3767 3769 @command('^diff',
3768 3770 [('r', 'rev', [], _('revision'), _('REV')),
3769 3771 ('c', 'change', '', _('change made by revision'), _('REV'))
3770 3772 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3771 3773 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3772 3774 inferrepo=True)
3773 3775 def diff(ui, repo, *pats, **opts):
3774 3776 """diff repository (or selected files)
3775 3777
3776 3778 Show differences between revisions for the specified files.
3777 3779
3778 3780 Differences between files are shown using the unified diff format.
3779 3781
3780 3782 .. note::
3781 3783
3782 3784 :hg:`diff` may generate unexpected results for merges, as it will
3783 3785 default to comparing against the working directory's first
3784 3786 parent changeset if no revisions are specified.
3785 3787
3786 3788 When two revision arguments are given, then changes are shown
3787 3789 between those revisions. If only one revision is specified then
3788 3790 that revision is compared to the working directory, and, when no
3789 3791 revisions are specified, the working directory files are compared
3790 3792 to its first parent.
3791 3793
3792 3794 Alternatively you can specify -c/--change with a revision to see
3793 3795 the changes in that changeset relative to its first parent.
3794 3796
3795 3797 Without the -a/--text option, diff will avoid generating diffs of
3796 3798 files it detects as binary. With -a, diff will generate a diff
3797 3799 anyway, probably with undesirable results.
3798 3800
3799 3801 Use the -g/--git option to generate diffs in the git extended diff
3800 3802 format. For more information, read :hg:`help diffs`.
3801 3803
3802 3804 .. container:: verbose
3803 3805
3804 3806 Examples:
3805 3807
3806 3808 - compare a file in the current working directory to its parent::
3807 3809
3808 3810 hg diff foo.c
3809 3811
3810 3812 - compare two historical versions of a directory, with rename info::
3811 3813
3812 3814 hg diff --git -r 1.0:1.2 lib/
3813 3815
3814 3816 - get change stats relative to the last change on some date::
3815 3817
3816 3818 hg diff --stat -r "date('may 2')"
3817 3819
3818 3820 - diff all newly-added files that contain a keyword::
3819 3821
3820 3822 hg diff "set:added() and grep(GNU)"
3821 3823
3822 3824 - compare a revision and its parents::
3823 3825
3824 3826 hg diff -c 9353 # compare against first parent
3825 3827 hg diff -r 9353^:9353 # same using revset syntax
3826 3828 hg diff -r 9353^2:9353 # compare against the second parent
3827 3829
3828 3830 Returns 0 on success.
3829 3831 """
3830 3832
3831 3833 revs = opts.get('rev')
3832 3834 change = opts.get('change')
3833 3835 stat = opts.get('stat')
3834 3836 reverse = opts.get('reverse')
3835 3837
3836 3838 if revs and change:
3837 3839 msg = _('cannot specify --rev and --change at the same time')
3838 3840 raise error.Abort(msg)
3839 3841 elif change:
3840 3842 node2 = scmutil.revsingle(repo, change, None).node()
3841 3843 node1 = repo[node2].p1().node()
3842 3844 else:
3843 3845 node1, node2 = scmutil.revpair(repo, revs)
3844 3846
3845 3847 if reverse:
3846 3848 node1, node2 = node2, node1
3847 3849
3848 3850 diffopts = patch.diffallopts(ui, opts)
3849 3851 m = scmutil.match(repo[node2], pats, opts)
3850 3852 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3851 3853 listsubrepos=opts.get('subrepos'),
3852 3854 root=opts.get('root'))
3853 3855
3854 3856 @command('^export',
3855 3857 [('o', 'output', '',
3856 3858 _('print output to file with formatted name'), _('FORMAT')),
3857 3859 ('', 'switch-parent', None, _('diff against the second parent')),
3858 3860 ('r', 'rev', [], _('revisions to export'), _('REV')),
3859 3861 ] + diffopts,
3860 3862 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3861 3863 def export(ui, repo, *changesets, **opts):
3862 3864 """dump the header and diffs for one or more changesets
3863 3865
3864 3866 Print the changeset header and diffs for one or more revisions.
3865 3867 If no revision is given, the parent of the working directory is used.
3866 3868
3867 3869 The information shown in the changeset header is: author, date,
3868 3870 branch name (if non-default), changeset hash, parent(s) and commit
3869 3871 comment.
3870 3872
3871 3873 .. note::
3872 3874
3873 3875 :hg:`export` may generate unexpected diff output for merge
3874 3876 changesets, as it will compare the merge changeset against its
3875 3877 first parent only.
3876 3878
3877 3879 Output may be to a file, in which case the name of the file is
3878 3880 given using a format string. The formatting rules are as follows:
3879 3881
3880 3882 :``%%``: literal "%" character
3881 3883 :``%H``: changeset hash (40 hexadecimal digits)
3882 3884 :``%N``: number of patches being generated
3883 3885 :``%R``: changeset revision number
3884 3886 :``%b``: basename of the exporting repository
3885 3887 :``%h``: short-form changeset hash (12 hexadecimal digits)
3886 3888 :``%m``: first line of the commit message (only alphanumeric characters)
3887 3889 :``%n``: zero-padded sequence number, starting at 1
3888 3890 :``%r``: zero-padded changeset revision number
3889 3891
3890 3892 Without the -a/--text option, export will avoid generating diffs
3891 3893 of files it detects as binary. With -a, export will generate a
3892 3894 diff anyway, probably with undesirable results.
3893 3895
3894 3896 Use the -g/--git option to generate diffs in the git extended diff
3895 3897 format. See :hg:`help diffs` for more information.
3896 3898
3897 3899 With the --switch-parent option, the diff will be against the
3898 3900 second parent. It can be useful to review a merge.
3899 3901
3900 3902 .. container:: verbose
3901 3903
3902 3904 Examples:
3903 3905
3904 3906 - use export and import to transplant a bugfix to the current
3905 3907 branch::
3906 3908
3907 3909 hg export -r 9353 | hg import -
3908 3910
3909 3911 - export all the changesets between two revisions to a file with
3910 3912 rename information::
3911 3913
3912 3914 hg export --git -r 123:150 > changes.txt
3913 3915
3914 3916 - split outgoing changes into a series of patches with
3915 3917 descriptive names::
3916 3918
3917 3919 hg export -r "outgoing()" -o "%n-%m.patch"
3918 3920
3919 3921 Returns 0 on success.
3920 3922 """
3921 3923 changesets += tuple(opts.get('rev', []))
3922 3924 if not changesets:
3923 3925 changesets = ['.']
3924 3926 revs = scmutil.revrange(repo, changesets)
3925 3927 if not revs:
3926 3928 raise error.Abort(_("export requires at least one changeset"))
3927 3929 if len(revs) > 1:
3928 3930 ui.note(_('exporting patches:\n'))
3929 3931 else:
3930 3932 ui.note(_('exporting patch:\n'))
3931 3933 cmdutil.export(repo, revs, template=opts.get('output'),
3932 3934 switch_parent=opts.get('switch_parent'),
3933 3935 opts=patch.diffallopts(ui, opts))
3934 3936
3935 3937 @command('files',
3936 3938 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3937 3939 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3938 3940 ] + walkopts + formatteropts + subrepoopts,
3939 3941 _('[OPTION]... [FILE]...'))
3940 3942 def files(ui, repo, *pats, **opts):
3941 3943 """list tracked files
3942 3944
3943 3945 Print files under Mercurial control in the working directory or
3944 3946 specified revision for given files (excluding removed files).
3945 3947 Files can be specified as filenames or filesets.
3946 3948
3947 3949 If no files are given to match, this command prints the names
3948 3950 of all files under Mercurial control.
3949 3951
3950 3952 .. container:: verbose
3951 3953
3952 3954 Examples:
3953 3955
3954 3956 - list all files under the current directory::
3955 3957
3956 3958 hg files .
3957 3959
3958 3960 - shows sizes and flags for current revision::
3959 3961
3960 3962 hg files -vr .
3961 3963
3962 3964 - list all files named README::
3963 3965
3964 3966 hg files -I "**/README"
3965 3967
3966 3968 - list all binary files::
3967 3969
3968 3970 hg files "set:binary()"
3969 3971
3970 3972 - find files containing a regular expression::
3971 3973
3972 3974 hg files "set:grep('bob')"
3973 3975
3974 3976 - search tracked file contents with xargs and grep::
3975 3977
3976 3978 hg files -0 | xargs -0 grep foo
3977 3979
3978 3980 See :hg:`help patterns` and :hg:`help filesets` for more information
3979 3981 on specifying file patterns.
3980 3982
3981 3983 Returns 0 if a match is found, 1 otherwise.
3982 3984
3983 3985 """
3984 3986 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3985 3987
3986 3988 end = '\n'
3987 3989 if opts.get('print0'):
3988 3990 end = '\0'
3989 3991 fmt = '%s' + end
3990 3992
3991 3993 m = scmutil.match(ctx, pats, opts)
3992 3994 with ui.formatter('files', opts) as fm:
3993 3995 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3994 3996
3995 3997 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3996 3998 def forget(ui, repo, *pats, **opts):
3997 3999 """forget the specified files on the next commit
3998 4000
3999 4001 Mark the specified files so they will no longer be tracked
4000 4002 after the next commit.
4001 4003
4002 4004 This only removes files from the current branch, not from the
4003 4005 entire project history, and it does not delete them from the
4004 4006 working directory.
4005 4007
4006 4008 To delete the file from the working directory, see :hg:`remove`.
4007 4009
4008 4010 To undo a forget before the next commit, see :hg:`add`.
4009 4011
4010 4012 .. container:: verbose
4011 4013
4012 4014 Examples:
4013 4015
4014 4016 - forget newly-added binary files::
4015 4017
4016 4018 hg forget "set:added() and binary()"
4017 4019
4018 4020 - forget files that would be excluded by .hgignore::
4019 4021
4020 4022 hg forget "set:hgignore()"
4021 4023
4022 4024 Returns 0 on success.
4023 4025 """
4024 4026
4025 4027 if not pats:
4026 4028 raise error.Abort(_('no files specified'))
4027 4029
4028 4030 m = scmutil.match(repo[None], pats, opts)
4029 4031 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
4030 4032 return rejected and 1 or 0
4031 4033
4032 4034 @command(
4033 4035 'graft',
4034 4036 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4035 4037 ('c', 'continue', False, _('resume interrupted graft')),
4036 4038 ('e', 'edit', False, _('invoke editor on commit messages')),
4037 4039 ('', 'log', None, _('append graft info to log message')),
4038 4040 ('f', 'force', False, _('force graft')),
4039 4041 ('D', 'currentdate', False,
4040 4042 _('record the current date as commit date')),
4041 4043 ('U', 'currentuser', False,
4042 4044 _('record the current user as committer'), _('DATE'))]
4043 4045 + commitopts2 + mergetoolopts + dryrunopts,
4044 4046 _('[OPTION]... [-r REV]... REV...'))
4045 4047 def graft(ui, repo, *revs, **opts):
4046 4048 '''copy changes from other branches onto the current branch
4047 4049
4048 4050 This command uses Mercurial's merge logic to copy individual
4049 4051 changes from other branches without merging branches in the
4050 4052 history graph. This is sometimes known as 'backporting' or
4051 4053 'cherry-picking'. By default, graft will copy user, date, and
4052 4054 description from the source changesets.
4053 4055
4054 4056 Changesets that are ancestors of the current revision, that have
4055 4057 already been grafted, or that are merges will be skipped.
4056 4058
4057 4059 If --log is specified, log messages will have a comment appended
4058 4060 of the form::
4059 4061
4060 4062 (grafted from CHANGESETHASH)
4061 4063
4062 4064 If --force is specified, revisions will be grafted even if they
4063 4065 are already ancestors of or have been grafted to the destination.
4064 4066 This is useful when the revisions have since been backed out.
4065 4067
4066 4068 If a graft merge results in conflicts, the graft process is
4067 4069 interrupted so that the current merge can be manually resolved.
4068 4070 Once all conflicts are addressed, the graft process can be
4069 4071 continued with the -c/--continue option.
4070 4072
4071 4073 .. note::
4072 4074
4073 4075 The -c/--continue option does not reapply earlier options, except
4074 4076 for --force.
4075 4077
4076 4078 .. container:: verbose
4077 4079
4078 4080 Examples:
4079 4081
4080 4082 - copy a single change to the stable branch and edit its description::
4081 4083
4082 4084 hg update stable
4083 4085 hg graft --edit 9393
4084 4086
4085 4087 - graft a range of changesets with one exception, updating dates::
4086 4088
4087 4089 hg graft -D "2085::2093 and not 2091"
4088 4090
4089 4091 - continue a graft after resolving conflicts::
4090 4092
4091 4093 hg graft -c
4092 4094
4093 4095 - show the source of a grafted changeset::
4094 4096
4095 4097 hg log --debug -r .
4096 4098
4097 4099 - show revisions sorted by date::
4098 4100
4099 4101 hg log -r "sort(all(), date)"
4100 4102
4101 4103 See :hg:`help revisions` and :hg:`help revsets` for more about
4102 4104 specifying revisions.
4103 4105
4104 4106 Returns 0 on successful completion.
4105 4107 '''
4106 4108 with repo.wlock():
4107 4109 return _dograft(ui, repo, *revs, **opts)
4108 4110
4109 4111 def _dograft(ui, repo, *revs, **opts):
4110 4112 if revs and opts.get('rev'):
4111 4113 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4112 4114 'revision ordering!\n'))
4113 4115
4114 4116 revs = list(revs)
4115 4117 revs.extend(opts.get('rev'))
4116 4118
4117 4119 if not opts.get('user') and opts.get('currentuser'):
4118 4120 opts['user'] = ui.username()
4119 4121 if not opts.get('date') and opts.get('currentdate'):
4120 4122 opts['date'] = "%d %d" % util.makedate()
4121 4123
4122 4124 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4123 4125
4124 4126 cont = False
4125 4127 if opts.get('continue'):
4126 4128 cont = True
4127 4129 if revs:
4128 4130 raise error.Abort(_("can't specify --continue and revisions"))
4129 4131 # read in unfinished revisions
4130 4132 try:
4131 4133 nodes = repo.vfs.read('graftstate').splitlines()
4132 4134 revs = [repo[node].rev() for node in nodes]
4133 4135 except IOError as inst:
4134 4136 if inst.errno != errno.ENOENT:
4135 4137 raise
4136 4138 cmdutil.wrongtooltocontinue(repo, _('graft'))
4137 4139 else:
4138 4140 cmdutil.checkunfinished(repo)
4139 4141 cmdutil.bailifchanged(repo)
4140 4142 if not revs:
4141 4143 raise error.Abort(_('no revisions specified'))
4142 4144 revs = scmutil.revrange(repo, revs)
4143 4145
4144 4146 skipped = set()
4145 4147 # check for merges
4146 4148 for rev in repo.revs('%ld and merge()', revs):
4147 4149 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4148 4150 skipped.add(rev)
4149 4151 revs = [r for r in revs if r not in skipped]
4150 4152 if not revs:
4151 4153 return -1
4152 4154
4153 4155 # Don't check in the --continue case, in effect retaining --force across
4154 4156 # --continues. That's because without --force, any revisions we decided to
4155 4157 # skip would have been filtered out here, so they wouldn't have made their
4156 4158 # way to the graftstate. With --force, any revisions we would have otherwise
4157 4159 # skipped would not have been filtered out, and if they hadn't been applied
4158 4160 # already, they'd have been in the graftstate.
4159 4161 if not (cont or opts.get('force')):
4160 4162 # check for ancestors of dest branch
4161 4163 crev = repo['.'].rev()
4162 4164 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4163 4165 # XXX make this lazy in the future
4164 4166 # don't mutate while iterating, create a copy
4165 4167 for rev in list(revs):
4166 4168 if rev in ancestors:
4167 4169 ui.warn(_('skipping ancestor revision %d:%s\n') %
4168 4170 (rev, repo[rev]))
4169 4171 # XXX remove on list is slow
4170 4172 revs.remove(rev)
4171 4173 if not revs:
4172 4174 return -1
4173 4175
4174 4176 # analyze revs for earlier grafts
4175 4177 ids = {}
4176 4178 for ctx in repo.set("%ld", revs):
4177 4179 ids[ctx.hex()] = ctx.rev()
4178 4180 n = ctx.extra().get('source')
4179 4181 if n:
4180 4182 ids[n] = ctx.rev()
4181 4183
4182 4184 # check ancestors for earlier grafts
4183 4185 ui.debug('scanning for duplicate grafts\n')
4184 4186
4185 4187 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4186 4188 ctx = repo[rev]
4187 4189 n = ctx.extra().get('source')
4188 4190 if n in ids:
4189 4191 try:
4190 4192 r = repo[n].rev()
4191 4193 except error.RepoLookupError:
4192 4194 r = None
4193 4195 if r in revs:
4194 4196 ui.warn(_('skipping revision %d:%s '
4195 4197 '(already grafted to %d:%s)\n')
4196 4198 % (r, repo[r], rev, ctx))
4197 4199 revs.remove(r)
4198 4200 elif ids[n] in revs:
4199 4201 if r is None:
4200 4202 ui.warn(_('skipping already grafted revision %d:%s '
4201 4203 '(%d:%s also has unknown origin %s)\n')
4202 4204 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4203 4205 else:
4204 4206 ui.warn(_('skipping already grafted revision %d:%s '
4205 4207 '(%d:%s also has origin %d:%s)\n')
4206 4208 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4207 4209 revs.remove(ids[n])
4208 4210 elif ctx.hex() in ids:
4209 4211 r = ids[ctx.hex()]
4210 4212 ui.warn(_('skipping already grafted revision %d:%s '
4211 4213 '(was grafted from %d:%s)\n') %
4212 4214 (r, repo[r], rev, ctx))
4213 4215 revs.remove(r)
4214 4216 if not revs:
4215 4217 return -1
4216 4218
4217 4219 for pos, ctx in enumerate(repo.set("%ld", revs)):
4218 4220 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4219 4221 ctx.description().split('\n', 1)[0])
4220 4222 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4221 4223 if names:
4222 4224 desc += ' (%s)' % ' '.join(names)
4223 4225 ui.status(_('grafting %s\n') % desc)
4224 4226 if opts.get('dry_run'):
4225 4227 continue
4226 4228
4227 4229 source = ctx.extra().get('source')
4228 4230 extra = {}
4229 4231 if source:
4230 4232 extra['source'] = source
4231 4233 extra['intermediate-source'] = ctx.hex()
4232 4234 else:
4233 4235 extra['source'] = ctx.hex()
4234 4236 user = ctx.user()
4235 4237 if opts.get('user'):
4236 4238 user = opts['user']
4237 4239 date = ctx.date()
4238 4240 if opts.get('date'):
4239 4241 date = opts['date']
4240 4242 message = ctx.description()
4241 4243 if opts.get('log'):
4242 4244 message += '\n(grafted from %s)' % ctx.hex()
4243 4245
4244 4246 # we don't merge the first commit when continuing
4245 4247 if not cont:
4246 4248 # perform the graft merge with p1(rev) as 'ancestor'
4247 4249 try:
4248 4250 # ui.forcemerge is an internal variable, do not document
4249 4251 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4250 4252 'graft')
4251 4253 stats = mergemod.graft(repo, ctx, ctx.p1(),
4252 4254 ['local', 'graft'])
4253 4255 finally:
4254 4256 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4255 4257 # report any conflicts
4256 4258 if stats and stats[3] > 0:
4257 4259 # write out state for --continue
4258 4260 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4259 4261 repo.vfs.write('graftstate', ''.join(nodelines))
4260 4262 extra = ''
4261 4263 if opts.get('user'):
4262 4264 extra += ' --user %s' % util.shellquote(opts['user'])
4263 4265 if opts.get('date'):
4264 4266 extra += ' --date %s' % util.shellquote(opts['date'])
4265 4267 if opts.get('log'):
4266 4268 extra += ' --log'
4267 4269 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4268 4270 raise error.Abort(
4269 4271 _("unresolved conflicts, can't continue"),
4270 4272 hint=hint)
4271 4273 else:
4272 4274 cont = False
4273 4275
4274 4276 # commit
4275 4277 node = repo.commit(text=message, user=user,
4276 4278 date=date, extra=extra, editor=editor)
4277 4279 if node is None:
4278 4280 ui.warn(
4279 4281 _('note: graft of %d:%s created no changes to commit\n') %
4280 4282 (ctx.rev(), ctx))
4281 4283
4282 4284 # remove state when we complete successfully
4283 4285 if not opts.get('dry_run'):
4284 4286 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4285 4287
4286 4288 return 0
4287 4289
4288 4290 @command('grep',
4289 4291 [('0', 'print0', None, _('end fields with NUL')),
4290 4292 ('', 'all', None, _('print all revisions that match')),
4291 4293 ('a', 'text', None, _('treat all files as text')),
4292 4294 ('f', 'follow', None,
4293 4295 _('follow changeset history,'
4294 4296 ' or file history across copies and renames')),
4295 4297 ('i', 'ignore-case', None, _('ignore case when matching')),
4296 4298 ('l', 'files-with-matches', None,
4297 4299 _('print only filenames and revisions that match')),
4298 4300 ('n', 'line-number', None, _('print matching line numbers')),
4299 4301 ('r', 'rev', [],
4300 4302 _('only search files changed within revision range'), _('REV')),
4301 4303 ('u', 'user', None, _('list the author (long with -v)')),
4302 4304 ('d', 'date', None, _('list the date (short with -q)')),
4303 4305 ] + formatteropts + walkopts,
4304 4306 _('[OPTION]... PATTERN [FILE]...'),
4305 4307 inferrepo=True)
4306 4308 def grep(ui, repo, pattern, *pats, **opts):
4307 4309 """search revision history for a pattern in specified files
4308 4310
4309 4311 Search revision history for a regular expression in the specified
4310 4312 files or the entire project.
4311 4313
4312 4314 By default, grep prints the most recent revision number for each
4313 4315 file in which it finds a match. To get it to print every revision
4314 4316 that contains a change in match status ("-" for a match that becomes
4315 4317 a non-match, or "+" for a non-match that becomes a match), use the
4316 4318 --all flag.
4317 4319
4318 4320 PATTERN can be any Python (roughly Perl-compatible) regular
4319 4321 expression.
4320 4322
4321 4323 If no FILEs are specified (and -f/--follow isn't set), all files in
4322 4324 the repository are searched, including those that don't exist in the
4323 4325 current branch or have been deleted in a prior changeset.
4324 4326
4325 4327 Returns 0 if a match is found, 1 otherwise.
4326 4328 """
4327 4329 reflags = re.M
4328 4330 if opts.get('ignore_case'):
4329 4331 reflags |= re.I
4330 4332 try:
4331 4333 regexp = util.re.compile(pattern, reflags)
4332 4334 except re.error as inst:
4333 4335 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4334 4336 return 1
4335 4337 sep, eol = ':', '\n'
4336 4338 if opts.get('print0'):
4337 4339 sep = eol = '\0'
4338 4340
4339 4341 getfile = util.lrucachefunc(repo.file)
4340 4342
4341 4343 def matchlines(body):
4342 4344 begin = 0
4343 4345 linenum = 0
4344 4346 while begin < len(body):
4345 4347 match = regexp.search(body, begin)
4346 4348 if not match:
4347 4349 break
4348 4350 mstart, mend = match.span()
4349 4351 linenum += body.count('\n', begin, mstart) + 1
4350 4352 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4351 4353 begin = body.find('\n', mend) + 1 or len(body) + 1
4352 4354 lend = begin - 1
4353 4355 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4354 4356
4355 4357 class linestate(object):
4356 4358 def __init__(self, line, linenum, colstart, colend):
4357 4359 self.line = line
4358 4360 self.linenum = linenum
4359 4361 self.colstart = colstart
4360 4362 self.colend = colend
4361 4363
4362 4364 def __hash__(self):
4363 4365 return hash((self.linenum, self.line))
4364 4366
4365 4367 def __eq__(self, other):
4366 4368 return self.line == other.line
4367 4369
4368 4370 def findpos(self):
4369 4371 """Iterate all (start, end) indices of matches"""
4370 4372 yield self.colstart, self.colend
4371 4373 p = self.colend
4372 4374 while p < len(self.line):
4373 4375 m = regexp.search(self.line, p)
4374 4376 if not m:
4375 4377 break
4376 4378 yield m.span()
4377 4379 p = m.end()
4378 4380
4379 4381 matches = {}
4380 4382 copies = {}
4381 4383 def grepbody(fn, rev, body):
4382 4384 matches[rev].setdefault(fn, [])
4383 4385 m = matches[rev][fn]
4384 4386 for lnum, cstart, cend, line in matchlines(body):
4385 4387 s = linestate(line, lnum, cstart, cend)
4386 4388 m.append(s)
4387 4389
4388 4390 def difflinestates(a, b):
4389 4391 sm = difflib.SequenceMatcher(None, a, b)
4390 4392 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4391 4393 if tag == 'insert':
4392 4394 for i in xrange(blo, bhi):
4393 4395 yield ('+', b[i])
4394 4396 elif tag == 'delete':
4395 4397 for i in xrange(alo, ahi):
4396 4398 yield ('-', a[i])
4397 4399 elif tag == 'replace':
4398 4400 for i in xrange(alo, ahi):
4399 4401 yield ('-', a[i])
4400 4402 for i in xrange(blo, bhi):
4401 4403 yield ('+', b[i])
4402 4404
4403 4405 def display(fm, fn, ctx, pstates, states):
4404 4406 rev = ctx.rev()
4405 4407 if fm.isplain():
4406 4408 formatuser = ui.shortuser
4407 4409 else:
4408 4410 formatuser = str
4409 4411 if ui.quiet:
4410 4412 datefmt = '%Y-%m-%d'
4411 4413 else:
4412 4414 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
4413 4415 found = False
4414 4416 @util.cachefunc
4415 4417 def binary():
4416 4418 flog = getfile(fn)
4417 4419 return util.binary(flog.read(ctx.filenode(fn)))
4418 4420
4419 4421 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
4420 4422 if opts.get('all'):
4421 4423 iter = difflinestates(pstates, states)
4422 4424 else:
4423 4425 iter = [('', l) for l in states]
4424 4426 for change, l in iter:
4425 4427 fm.startitem()
4426 4428 fm.data(node=fm.hexfunc(ctx.node()))
4427 4429 cols = [
4428 4430 ('filename', fn, True),
4429 4431 ('rev', rev, True),
4430 4432 ('linenumber', l.linenum, opts.get('line_number')),
4431 4433 ]
4432 4434 if opts.get('all'):
4433 4435 cols.append(('change', change, True))
4434 4436 cols.extend([
4435 4437 ('user', formatuser(ctx.user()), opts.get('user')),
4436 4438 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
4437 4439 ])
4438 4440 lastcol = next(name for name, data, cond in reversed(cols) if cond)
4439 4441 for name, data, cond in cols:
4440 4442 field = fieldnamemap.get(name, name)
4441 4443 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
4442 4444 if cond and name != lastcol:
4443 4445 fm.plain(sep, label='grep.sep')
4444 4446 if not opts.get('files_with_matches'):
4445 4447 fm.plain(sep, label='grep.sep')
4446 4448 if not opts.get('text') and binary():
4447 4449 fm.plain(_(" Binary file matches"))
4448 4450 else:
4449 4451 displaymatches(fm.nested('texts'), l)
4450 4452 fm.plain(eol)
4451 4453 found = True
4452 4454 if opts.get('files_with_matches'):
4453 4455 break
4454 4456 return found
4455 4457
4456 4458 def displaymatches(fm, l):
4457 4459 p = 0
4458 4460 for s, e in l.findpos():
4459 4461 if p < s:
4460 4462 fm.startitem()
4461 4463 fm.write('text', '%s', l.line[p:s])
4462 4464 fm.data(matched=False)
4463 4465 fm.startitem()
4464 4466 fm.write('text', '%s', l.line[s:e], label='grep.match')
4465 4467 fm.data(matched=True)
4466 4468 p = e
4467 4469 if p < len(l.line):
4468 4470 fm.startitem()
4469 4471 fm.write('text', '%s', l.line[p:])
4470 4472 fm.data(matched=False)
4471 4473 fm.end()
4472 4474
4473 4475 skip = {}
4474 4476 revfiles = {}
4475 4477 matchfn = scmutil.match(repo[None], pats, opts)
4476 4478 found = False
4477 4479 follow = opts.get('follow')
4478 4480
4479 4481 def prep(ctx, fns):
4480 4482 rev = ctx.rev()
4481 4483 pctx = ctx.p1()
4482 4484 parent = pctx.rev()
4483 4485 matches.setdefault(rev, {})
4484 4486 matches.setdefault(parent, {})
4485 4487 files = revfiles.setdefault(rev, [])
4486 4488 for fn in fns:
4487 4489 flog = getfile(fn)
4488 4490 try:
4489 4491 fnode = ctx.filenode(fn)
4490 4492 except error.LookupError:
4491 4493 continue
4492 4494
4493 4495 copied = flog.renamed(fnode)
4494 4496 copy = follow and copied and copied[0]
4495 4497 if copy:
4496 4498 copies.setdefault(rev, {})[fn] = copy
4497 4499 if fn in skip:
4498 4500 if copy:
4499 4501 skip[copy] = True
4500 4502 continue
4501 4503 files.append(fn)
4502 4504
4503 4505 if fn not in matches[rev]:
4504 4506 grepbody(fn, rev, flog.read(fnode))
4505 4507
4506 4508 pfn = copy or fn
4507 4509 if pfn not in matches[parent]:
4508 4510 try:
4509 4511 fnode = pctx.filenode(pfn)
4510 4512 grepbody(pfn, parent, flog.read(fnode))
4511 4513 except error.LookupError:
4512 4514 pass
4513 4515
4514 4516 fm = ui.formatter('grep', opts)
4515 4517 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4516 4518 rev = ctx.rev()
4517 4519 parent = ctx.p1().rev()
4518 4520 for fn in sorted(revfiles.get(rev, [])):
4519 4521 states = matches[rev][fn]
4520 4522 copy = copies.get(rev, {}).get(fn)
4521 4523 if fn in skip:
4522 4524 if copy:
4523 4525 skip[copy] = True
4524 4526 continue
4525 4527 pstates = matches.get(parent, {}).get(copy or fn, [])
4526 4528 if pstates or states:
4527 4529 r = display(fm, fn, ctx, pstates, states)
4528 4530 found = found or r
4529 4531 if r and not opts.get('all'):
4530 4532 skip[fn] = True
4531 4533 if copy:
4532 4534 skip[copy] = True
4533 4535 del matches[rev]
4534 4536 del revfiles[rev]
4535 4537 fm.end()
4536 4538
4537 4539 return not found
4538 4540
4539 4541 @command('heads',
4540 4542 [('r', 'rev', '',
4541 4543 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4542 4544 ('t', 'topo', False, _('show topological heads only')),
4543 4545 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4544 4546 ('c', 'closed', False, _('show normal and closed branch heads')),
4545 4547 ] + templateopts,
4546 4548 _('[-ct] [-r STARTREV] [REV]...'))
4547 4549 def heads(ui, repo, *branchrevs, **opts):
4548 4550 """show branch heads
4549 4551
4550 4552 With no arguments, show all open branch heads in the repository.
4551 4553 Branch heads are changesets that have no descendants on the
4552 4554 same branch. They are where development generally takes place and
4553 4555 are the usual targets for update and merge operations.
4554 4556
4555 4557 If one or more REVs are given, only open branch heads on the
4556 4558 branches associated with the specified changesets are shown. This
4557 4559 means that you can use :hg:`heads .` to see the heads on the
4558 4560 currently checked-out branch.
4559 4561
4560 4562 If -c/--closed is specified, also show branch heads marked closed
4561 4563 (see :hg:`commit --close-branch`).
4562 4564
4563 4565 If STARTREV is specified, only those heads that are descendants of
4564 4566 STARTREV will be displayed.
4565 4567
4566 4568 If -t/--topo is specified, named branch mechanics will be ignored and only
4567 4569 topological heads (changesets with no children) will be shown.
4568 4570
4569 4571 Returns 0 if matching heads are found, 1 if not.
4570 4572 """
4571 4573
4572 4574 start = None
4573 4575 if 'rev' in opts:
4574 4576 start = scmutil.revsingle(repo, opts['rev'], None).node()
4575 4577
4576 4578 if opts.get('topo'):
4577 4579 heads = [repo[h] for h in repo.heads(start)]
4578 4580 else:
4579 4581 heads = []
4580 4582 for branch in repo.branchmap():
4581 4583 heads += repo.branchheads(branch, start, opts.get('closed'))
4582 4584 heads = [repo[h] for h in heads]
4583 4585
4584 4586 if branchrevs:
4585 4587 branches = set(repo[br].branch() for br in branchrevs)
4586 4588 heads = [h for h in heads if h.branch() in branches]
4587 4589
4588 4590 if opts.get('active') and branchrevs:
4589 4591 dagheads = repo.heads(start)
4590 4592 heads = [h for h in heads if h.node() in dagheads]
4591 4593
4592 4594 if branchrevs:
4593 4595 haveheads = set(h.branch() for h in heads)
4594 4596 if branches - haveheads:
4595 4597 headless = ', '.join(b for b in branches - haveheads)
4596 4598 msg = _('no open branch heads found on branches %s')
4597 4599 if opts.get('rev'):
4598 4600 msg += _(' (started at %s)') % opts['rev']
4599 4601 ui.warn((msg + '\n') % headless)
4600 4602
4601 4603 if not heads:
4602 4604 return 1
4603 4605
4604 4606 heads = sorted(heads, key=lambda x: -x.rev())
4605 4607 displayer = cmdutil.show_changeset(ui, repo, opts)
4606 4608 for ctx in heads:
4607 4609 displayer.show(ctx)
4608 4610 displayer.close()
4609 4611
4610 4612 @command('help',
4611 4613 [('e', 'extension', None, _('show only help for extensions')),
4612 4614 ('c', 'command', None, _('show only help for commands')),
4613 4615 ('k', 'keyword', None, _('show topics matching keyword')),
4614 4616 ('s', 'system', [], _('show help for specific platform(s)')),
4615 4617 ],
4616 4618 _('[-ecks] [TOPIC]'),
4617 4619 norepo=True)
4618 4620 def help_(ui, name=None, **opts):
4619 4621 """show help for a given topic or a help overview
4620 4622
4621 4623 With no arguments, print a list of commands with short help messages.
4622 4624
4623 4625 Given a topic, extension, or command name, print help for that
4624 4626 topic.
4625 4627
4626 4628 Returns 0 if successful.
4627 4629 """
4628 4630
4629 4631 textwidth = ui.configint('ui', 'textwidth', 78)
4630 4632 termwidth = ui.termwidth() - 2
4631 4633 if textwidth <= 0 or termwidth < textwidth:
4632 4634 textwidth = termwidth
4633 4635
4634 4636 keep = opts.get('system') or []
4635 4637 if len(keep) == 0:
4636 4638 if sys.platform.startswith('win'):
4637 4639 keep.append('windows')
4638 4640 elif sys.platform == 'OpenVMS':
4639 4641 keep.append('vms')
4640 4642 elif sys.platform == 'plan9':
4641 4643 keep.append('plan9')
4642 4644 else:
4643 4645 keep.append('unix')
4644 4646 keep.append(sys.platform.lower())
4645 4647 if ui.verbose:
4646 4648 keep.append('verbose')
4647 4649
4648 4650 section = None
4649 4651 subtopic = None
4650 4652 if name and '.' in name:
4651 4653 name, remaining = name.split('.', 1)
4652 4654 remaining = encoding.lower(remaining)
4653 4655 if '.' in remaining:
4654 4656 subtopic, section = remaining.split('.', 1)
4655 4657 else:
4656 4658 if name in help.subtopics:
4657 4659 subtopic = remaining
4658 4660 else:
4659 4661 section = remaining
4660 4662
4661 4663 text = help.help_(ui, name, subtopic=subtopic, **opts)
4662 4664
4663 4665 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4664 4666 section=section)
4665 4667
4666 4668 # We could have been given a weird ".foo" section without a name
4667 4669 # to look for, or we could have simply failed to found "foo.bar"
4668 4670 # because bar isn't a section of foo
4669 4671 if section and not (formatted and name):
4670 4672 raise error.Abort(_("help section not found"))
4671 4673
4672 4674 if 'verbose' in pruned:
4673 4675 keep.append('omitted')
4674 4676 else:
4675 4677 keep.append('notomitted')
4676 4678 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4677 4679 section=section)
4678 4680 ui.write(formatted)
4679 4681
4680 4682
4681 4683 @command('identify|id',
4682 4684 [('r', 'rev', '',
4683 4685 _('identify the specified revision'), _('REV')),
4684 4686 ('n', 'num', None, _('show local revision number')),
4685 4687 ('i', 'id', None, _('show global revision id')),
4686 4688 ('b', 'branch', None, _('show branch')),
4687 4689 ('t', 'tags', None, _('show tags')),
4688 4690 ('B', 'bookmarks', None, _('show bookmarks')),
4689 4691 ] + remoteopts,
4690 4692 _('[-nibtB] [-r REV] [SOURCE]'),
4691 4693 optionalrepo=True)
4692 4694 def identify(ui, repo, source=None, rev=None,
4693 4695 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4694 4696 """identify the working directory or specified revision
4695 4697
4696 4698 Print a summary identifying the repository state at REV using one or
4697 4699 two parent hash identifiers, followed by a "+" if the working
4698 4700 directory has uncommitted changes, the branch name (if not default),
4699 4701 a list of tags, and a list of bookmarks.
4700 4702
4701 4703 When REV is not given, print a summary of the current state of the
4702 4704 repository.
4703 4705
4704 4706 Specifying a path to a repository root or Mercurial bundle will
4705 4707 cause lookup to operate on that repository/bundle.
4706 4708
4707 4709 .. container:: verbose
4708 4710
4709 4711 Examples:
4710 4712
4711 4713 - generate a build identifier for the working directory::
4712 4714
4713 4715 hg id --id > build-id.dat
4714 4716
4715 4717 - find the revision corresponding to a tag::
4716 4718
4717 4719 hg id -n -r 1.3
4718 4720
4719 4721 - check the most recent revision of a remote repository::
4720 4722
4721 4723 hg id -r tip http://selenic.com/hg/
4722 4724
4723 4725 See :hg:`log` for generating more information about specific revisions,
4724 4726 including full hash identifiers.
4725 4727
4726 4728 Returns 0 if successful.
4727 4729 """
4728 4730
4729 4731 if not repo and not source:
4730 4732 raise error.Abort(_("there is no Mercurial repository here "
4731 4733 "(.hg not found)"))
4732 4734
4733 4735 if ui.debugflag:
4734 4736 hexfunc = hex
4735 4737 else:
4736 4738 hexfunc = short
4737 4739 default = not (num or id or branch or tags or bookmarks)
4738 4740 output = []
4739 4741 revs = []
4740 4742
4741 4743 if source:
4742 4744 source, branches = hg.parseurl(ui.expandpath(source))
4743 4745 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4744 4746 repo = peer.local()
4745 4747 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4746 4748
4747 4749 if not repo:
4748 4750 if num or branch or tags:
4749 4751 raise error.Abort(
4750 4752 _("can't query remote revision number, branch, or tags"))
4751 4753 if not rev and revs:
4752 4754 rev = revs[0]
4753 4755 if not rev:
4754 4756 rev = "tip"
4755 4757
4756 4758 remoterev = peer.lookup(rev)
4757 4759 if default or id:
4758 4760 output = [hexfunc(remoterev)]
4759 4761
4760 4762 def getbms():
4761 4763 bms = []
4762 4764
4763 4765 if 'bookmarks' in peer.listkeys('namespaces'):
4764 4766 hexremoterev = hex(remoterev)
4765 4767 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4766 4768 if bmr == hexremoterev]
4767 4769
4768 4770 return sorted(bms)
4769 4771
4770 4772 if bookmarks:
4771 4773 output.extend(getbms())
4772 4774 elif default and not ui.quiet:
4773 4775 # multiple bookmarks for a single parent separated by '/'
4774 4776 bm = '/'.join(getbms())
4775 4777 if bm:
4776 4778 output.append(bm)
4777 4779 else:
4778 4780 ctx = scmutil.revsingle(repo, rev, None)
4779 4781
4780 4782 if ctx.rev() is None:
4781 4783 ctx = repo[None]
4782 4784 parents = ctx.parents()
4783 4785 taglist = []
4784 4786 for p in parents:
4785 4787 taglist.extend(p.tags())
4786 4788
4787 4789 changed = ""
4788 4790 if default or id or num:
4789 4791 if (any(repo.status())
4790 4792 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4791 4793 changed = '+'
4792 4794 if default or id:
4793 4795 output = ["%s%s" %
4794 4796 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4795 4797 if num:
4796 4798 output.append("%s%s" %
4797 4799 ('+'.join([str(p.rev()) for p in parents]), changed))
4798 4800 else:
4799 4801 if default or id:
4800 4802 output = [hexfunc(ctx.node())]
4801 4803 if num:
4802 4804 output.append(str(ctx.rev()))
4803 4805 taglist = ctx.tags()
4804 4806
4805 4807 if default and not ui.quiet:
4806 4808 b = ctx.branch()
4807 4809 if b != 'default':
4808 4810 output.append("(%s)" % b)
4809 4811
4810 4812 # multiple tags for a single parent separated by '/'
4811 4813 t = '/'.join(taglist)
4812 4814 if t:
4813 4815 output.append(t)
4814 4816
4815 4817 # multiple bookmarks for a single parent separated by '/'
4816 4818 bm = '/'.join(ctx.bookmarks())
4817 4819 if bm:
4818 4820 output.append(bm)
4819 4821 else:
4820 4822 if branch:
4821 4823 output.append(ctx.branch())
4822 4824
4823 4825 if tags:
4824 4826 output.extend(taglist)
4825 4827
4826 4828 if bookmarks:
4827 4829 output.extend(ctx.bookmarks())
4828 4830
4829 4831 ui.write("%s\n" % ' '.join(output))
4830 4832
4831 4833 @command('import|patch',
4832 4834 [('p', 'strip', 1,
4833 4835 _('directory strip option for patch. This has the same '
4834 4836 'meaning as the corresponding patch option'), _('NUM')),
4835 4837 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4836 4838 ('e', 'edit', False, _('invoke editor on commit messages')),
4837 4839 ('f', 'force', None,
4838 4840 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4839 4841 ('', 'no-commit', None,
4840 4842 _("don't commit, just update the working directory")),
4841 4843 ('', 'bypass', None,
4842 4844 _("apply patch without touching the working directory")),
4843 4845 ('', 'partial', None,
4844 4846 _('commit even if some hunks fail')),
4845 4847 ('', 'exact', None,
4846 4848 _('abort if patch would apply lossily')),
4847 4849 ('', 'prefix', '',
4848 4850 _('apply patch to subdirectory'), _('DIR')),
4849 4851 ('', 'import-branch', None,
4850 4852 _('use any branch information in patch (implied by --exact)'))] +
4851 4853 commitopts + commitopts2 + similarityopts,
4852 4854 _('[OPTION]... PATCH...'))
4853 4855 def import_(ui, repo, patch1=None, *patches, **opts):
4854 4856 """import an ordered set of patches
4855 4857
4856 4858 Import a list of patches and commit them individually (unless
4857 4859 --no-commit is specified).
4858 4860
4859 4861 To read a patch from standard input, use "-" as the patch name. If
4860 4862 a URL is specified, the patch will be downloaded from there.
4861 4863
4862 4864 Import first applies changes to the working directory (unless
4863 4865 --bypass is specified), import will abort if there are outstanding
4864 4866 changes.
4865 4867
4866 4868 Use --bypass to apply and commit patches directly to the
4867 4869 repository, without affecting the working directory. Without
4868 4870 --exact, patches will be applied on top of the working directory
4869 4871 parent revision.
4870 4872
4871 4873 You can import a patch straight from a mail message. Even patches
4872 4874 as attachments work (to use the body part, it must have type
4873 4875 text/plain or text/x-patch). From and Subject headers of email
4874 4876 message are used as default committer and commit message. All
4875 4877 text/plain body parts before first diff are added to the commit
4876 4878 message.
4877 4879
4878 4880 If the imported patch was generated by :hg:`export`, user and
4879 4881 description from patch override values from message headers and
4880 4882 body. Values given on command line with -m/--message and -u/--user
4881 4883 override these.
4882 4884
4883 4885 If --exact is specified, import will set the working directory to
4884 4886 the parent of each patch before applying it, and will abort if the
4885 4887 resulting changeset has a different ID than the one recorded in
4886 4888 the patch. This will guard against various ways that portable
4887 4889 patch formats and mail systems might fail to transfer Mercurial
4888 4890 data or metadata. See :hg:`bundle` for lossless transmission.
4889 4891
4890 4892 Use --partial to ensure a changeset will be created from the patch
4891 4893 even if some hunks fail to apply. Hunks that fail to apply will be
4892 4894 written to a <target-file>.rej file. Conflicts can then be resolved
4893 4895 by hand before :hg:`commit --amend` is run to update the created
4894 4896 changeset. This flag exists to let people import patches that
4895 4897 partially apply without losing the associated metadata (author,
4896 4898 date, description, ...).
4897 4899
4898 4900 .. note::
4899 4901
4900 4902 When no hunks apply cleanly, :hg:`import --partial` will create
4901 4903 an empty changeset, importing only the patch metadata.
4902 4904
4903 4905 With -s/--similarity, hg will attempt to discover renames and
4904 4906 copies in the patch in the same way as :hg:`addremove`.
4905 4907
4906 4908 It is possible to use external patch programs to perform the patch
4907 4909 by setting the ``ui.patch`` configuration option. For the default
4908 4910 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4909 4911 See :hg:`help config` for more information about configuration
4910 4912 files and how to use these options.
4911 4913
4912 4914 See :hg:`help dates` for a list of formats valid for -d/--date.
4913 4915
4914 4916 .. container:: verbose
4915 4917
4916 4918 Examples:
4917 4919
4918 4920 - import a traditional patch from a website and detect renames::
4919 4921
4920 4922 hg import -s 80 http://example.com/bugfix.patch
4921 4923
4922 4924 - import a changeset from an hgweb server::
4923 4925
4924 4926 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4925 4927
4926 4928 - import all the patches in an Unix-style mbox::
4927 4929
4928 4930 hg import incoming-patches.mbox
4929 4931
4930 4932 - attempt to exactly restore an exported changeset (not always
4931 4933 possible)::
4932 4934
4933 4935 hg import --exact proposed-fix.patch
4934 4936
4935 4937 - use an external tool to apply a patch which is too fuzzy for
4936 4938 the default internal tool.
4937 4939
4938 4940 hg import --config ui.patch="patch --merge" fuzzy.patch
4939 4941
4940 4942 - change the default fuzzing from 2 to a less strict 7
4941 4943
4942 4944 hg import --config ui.fuzz=7 fuzz.patch
4943 4945
4944 4946 Returns 0 on success, 1 on partial success (see --partial).
4945 4947 """
4946 4948
4947 4949 if not patch1:
4948 4950 raise error.Abort(_('need at least one patch to import'))
4949 4951
4950 4952 patches = (patch1,) + patches
4951 4953
4952 4954 date = opts.get('date')
4953 4955 if date:
4954 4956 opts['date'] = util.parsedate(date)
4955 4957
4956 4958 exact = opts.get('exact')
4957 4959 update = not opts.get('bypass')
4958 4960 if not update and opts.get('no_commit'):
4959 4961 raise error.Abort(_('cannot use --no-commit with --bypass'))
4960 4962 try:
4961 4963 sim = float(opts.get('similarity') or 0)
4962 4964 except ValueError:
4963 4965 raise error.Abort(_('similarity must be a number'))
4964 4966 if sim < 0 or sim > 100:
4965 4967 raise error.Abort(_('similarity must be between 0 and 100'))
4966 4968 if sim and not update:
4967 4969 raise error.Abort(_('cannot use --similarity with --bypass'))
4968 4970 if exact:
4969 4971 if opts.get('edit'):
4970 4972 raise error.Abort(_('cannot use --exact with --edit'))
4971 4973 if opts.get('prefix'):
4972 4974 raise error.Abort(_('cannot use --exact with --prefix'))
4973 4975
4974 4976 base = opts["base"]
4975 4977 wlock = dsguard = lock = tr = None
4976 4978 msgs = []
4977 4979 ret = 0
4978 4980
4979 4981
4980 4982 try:
4981 4983 wlock = repo.wlock()
4982 4984
4983 4985 if update:
4984 4986 cmdutil.checkunfinished(repo)
4985 4987 if (exact or not opts.get('force')):
4986 4988 cmdutil.bailifchanged(repo)
4987 4989
4988 4990 if not opts.get('no_commit'):
4989 4991 lock = repo.lock()
4990 4992 tr = repo.transaction('import')
4991 4993 else:
4992 4994 dsguard = cmdutil.dirstateguard(repo, 'import')
4993 4995 parents = repo[None].parents()
4994 4996 for patchurl in patches:
4995 4997 if patchurl == '-':
4996 4998 ui.status(_('applying patch from stdin\n'))
4997 4999 patchfile = ui.fin
4998 5000 patchurl = 'stdin' # for error message
4999 5001 else:
5000 5002 patchurl = os.path.join(base, patchurl)
5001 5003 ui.status(_('applying %s\n') % patchurl)
5002 5004 patchfile = hg.openpath(ui, patchurl)
5003 5005
5004 5006 haspatch = False
5005 5007 for hunk in patch.split(patchfile):
5006 5008 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
5007 5009 parents, opts,
5008 5010 msgs, hg.clean)
5009 5011 if msg:
5010 5012 haspatch = True
5011 5013 ui.note(msg + '\n')
5012 5014 if update or exact:
5013 5015 parents = repo[None].parents()
5014 5016 else:
5015 5017 parents = [repo[node]]
5016 5018 if rej:
5017 5019 ui.write_err(_("patch applied partially\n"))
5018 5020 ui.write_err(_("(fix the .rej files and run "
5019 5021 "`hg commit --amend`)\n"))
5020 5022 ret = 1
5021 5023 break
5022 5024
5023 5025 if not haspatch:
5024 5026 raise error.Abort(_('%s: no diffs found') % patchurl)
5025 5027
5026 5028 if tr:
5027 5029 tr.close()
5028 5030 if msgs:
5029 5031 repo.savecommitmessage('\n* * *\n'.join(msgs))
5030 5032 if dsguard:
5031 5033 dsguard.close()
5032 5034 return ret
5033 5035 finally:
5034 5036 if tr:
5035 5037 tr.release()
5036 5038 release(lock, dsguard, wlock)
5037 5039
5038 5040 @command('incoming|in',
5039 5041 [('f', 'force', None,
5040 5042 _('run even if remote repository is unrelated')),
5041 5043 ('n', 'newest-first', None, _('show newest record first')),
5042 5044 ('', 'bundle', '',
5043 5045 _('file to store the bundles into'), _('FILE')),
5044 5046 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5045 5047 ('B', 'bookmarks', False, _("compare bookmarks")),
5046 5048 ('b', 'branch', [],
5047 5049 _('a specific branch you would like to pull'), _('BRANCH')),
5048 5050 ] + logopts + remoteopts + subrepoopts,
5049 5051 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
5050 5052 def incoming(ui, repo, source="default", **opts):
5051 5053 """show new changesets found in source
5052 5054
5053 5055 Show new changesets found in the specified path/URL or the default
5054 5056 pull location. These are the changesets that would have been pulled
5055 5057 if a pull at the time you issued this command.
5056 5058
5057 5059 See pull for valid source format details.
5058 5060
5059 5061 .. container:: verbose
5060 5062
5061 5063 With -B/--bookmarks, the result of bookmark comparison between
5062 5064 local and remote repositories is displayed. With -v/--verbose,
5063 5065 status is also displayed for each bookmark like below::
5064 5066
5065 5067 BM1 01234567890a added
5066 5068 BM2 1234567890ab advanced
5067 5069 BM3 234567890abc diverged
5068 5070 BM4 34567890abcd changed
5069 5071
5070 5072 The action taken locally when pulling depends on the
5071 5073 status of each bookmark:
5072 5074
5073 5075 :``added``: pull will create it
5074 5076 :``advanced``: pull will update it
5075 5077 :``diverged``: pull will create a divergent bookmark
5076 5078 :``changed``: result depends on remote changesets
5077 5079
5078 5080 From the point of view of pulling behavior, bookmark
5079 5081 existing only in the remote repository are treated as ``added``,
5080 5082 even if it is in fact locally deleted.
5081 5083
5082 5084 .. container:: verbose
5083 5085
5084 5086 For remote repository, using --bundle avoids downloading the
5085 5087 changesets twice if the incoming is followed by a pull.
5086 5088
5087 5089 Examples:
5088 5090
5089 5091 - show incoming changes with patches and full description::
5090 5092
5091 5093 hg incoming -vp
5092 5094
5093 5095 - show incoming changes excluding merges, store a bundle::
5094 5096
5095 5097 hg in -vpM --bundle incoming.hg
5096 5098 hg pull incoming.hg
5097 5099
5098 5100 - briefly list changes inside a bundle::
5099 5101
5100 5102 hg in changes.hg -T "{desc|firstline}\\n"
5101 5103
5102 5104 Returns 0 if there are incoming changes, 1 otherwise.
5103 5105 """
5104 5106 if opts.get('graph'):
5105 5107 cmdutil.checkunsupportedgraphflags([], opts)
5106 5108 def display(other, chlist, displayer):
5107 5109 revdag = cmdutil.graphrevs(other, chlist, opts)
5108 5110 cmdutil.displaygraph(ui, repo, revdag, displayer,
5109 5111 graphmod.asciiedges)
5110 5112
5111 5113 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5112 5114 return 0
5113 5115
5114 5116 if opts.get('bundle') and opts.get('subrepos'):
5115 5117 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5116 5118
5117 5119 if opts.get('bookmarks'):
5118 5120 source, branches = hg.parseurl(ui.expandpath(source),
5119 5121 opts.get('branch'))
5120 5122 other = hg.peer(repo, opts, source)
5121 5123 if 'bookmarks' not in other.listkeys('namespaces'):
5122 5124 ui.warn(_("remote doesn't support bookmarks\n"))
5123 5125 return 0
5124 5126 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5125 5127 return bookmarks.incoming(ui, repo, other)
5126 5128
5127 5129 repo._subtoppath = ui.expandpath(source)
5128 5130 try:
5129 5131 return hg.incoming(ui, repo, source, opts)
5130 5132 finally:
5131 5133 del repo._subtoppath
5132 5134
5133 5135
5134 5136 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5135 5137 norepo=True)
5136 5138 def init(ui, dest=".", **opts):
5137 5139 """create a new repository in the given directory
5138 5140
5139 5141 Initialize a new repository in the given directory. If the given
5140 5142 directory does not exist, it will be created.
5141 5143
5142 5144 If no directory is given, the current directory is used.
5143 5145
5144 5146 It is possible to specify an ``ssh://`` URL as the destination.
5145 5147 See :hg:`help urls` for more information.
5146 5148
5147 5149 Returns 0 on success.
5148 5150 """
5149 5151 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5150 5152
5151 5153 @command('locate',
5152 5154 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5153 5155 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5154 5156 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5155 5157 ] + walkopts,
5156 5158 _('[OPTION]... [PATTERN]...'))
5157 5159 def locate(ui, repo, *pats, **opts):
5158 5160 """locate files matching specific patterns (DEPRECATED)
5159 5161
5160 5162 Print files under Mercurial control in the working directory whose
5161 5163 names match the given patterns.
5162 5164
5163 5165 By default, this command searches all directories in the working
5164 5166 directory. To search just the current directory and its
5165 5167 subdirectories, use "--include .".
5166 5168
5167 5169 If no patterns are given to match, this command prints the names
5168 5170 of all files under Mercurial control in the working directory.
5169 5171
5170 5172 If you want to feed the output of this command into the "xargs"
5171 5173 command, use the -0 option to both this command and "xargs". This
5172 5174 will avoid the problem of "xargs" treating single filenames that
5173 5175 contain whitespace as multiple filenames.
5174 5176
5175 5177 See :hg:`help files` for a more versatile command.
5176 5178
5177 5179 Returns 0 if a match is found, 1 otherwise.
5178 5180 """
5179 5181 if opts.get('print0'):
5180 5182 end = '\0'
5181 5183 else:
5182 5184 end = '\n'
5183 5185 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5184 5186
5185 5187 ret = 1
5186 5188 ctx = repo[rev]
5187 5189 m = scmutil.match(ctx, pats, opts, default='relglob',
5188 5190 badfn=lambda x, y: False)
5189 5191
5190 5192 for abs in ctx.matches(m):
5191 5193 if opts.get('fullpath'):
5192 5194 ui.write(repo.wjoin(abs), end)
5193 5195 else:
5194 5196 ui.write(((pats and m.rel(abs)) or abs), end)
5195 5197 ret = 0
5196 5198
5197 5199 return ret
5198 5200
5199 5201 @command('^log|history',
5200 5202 [('f', 'follow', None,
5201 5203 _('follow changeset history, or file history across copies and renames')),
5202 5204 ('', 'follow-first', None,
5203 5205 _('only follow the first parent of merge changesets (DEPRECATED)')),
5204 5206 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5205 5207 ('C', 'copies', None, _('show copied files')),
5206 5208 ('k', 'keyword', [],
5207 5209 _('do case-insensitive search for a given text'), _('TEXT')),
5208 5210 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5209 5211 ('', 'removed', None, _('include revisions where files were removed')),
5210 5212 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5211 5213 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5212 5214 ('', 'only-branch', [],
5213 5215 _('show only changesets within the given named branch (DEPRECATED)'),
5214 5216 _('BRANCH')),
5215 5217 ('b', 'branch', [],
5216 5218 _('show changesets within the given named branch'), _('BRANCH')),
5217 5219 ('P', 'prune', [],
5218 5220 _('do not display revision or any of its ancestors'), _('REV')),
5219 5221 ] + logopts + walkopts,
5220 5222 _('[OPTION]... [FILE]'),
5221 5223 inferrepo=True)
5222 5224 def log(ui, repo, *pats, **opts):
5223 5225 """show revision history of entire repository or files
5224 5226
5225 5227 Print the revision history of the specified files or the entire
5226 5228 project.
5227 5229
5228 5230 If no revision range is specified, the default is ``tip:0`` unless
5229 5231 --follow is set, in which case the working directory parent is
5230 5232 used as the starting revision.
5231 5233
5232 5234 File history is shown without following rename or copy history of
5233 5235 files. Use -f/--follow with a filename to follow history across
5234 5236 renames and copies. --follow without a filename will only show
5235 5237 ancestors or descendants of the starting revision.
5236 5238
5237 5239 By default this command prints revision number and changeset id,
5238 5240 tags, non-trivial parents, user, date and time, and a summary for
5239 5241 each commit. When the -v/--verbose switch is used, the list of
5240 5242 changed files and full commit message are shown.
5241 5243
5242 5244 With --graph the revisions are shown as an ASCII art DAG with the most
5243 5245 recent changeset at the top.
5244 5246 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5245 5247 and '+' represents a fork where the changeset from the lines below is a
5246 5248 parent of the 'o' merge on the same line.
5247 5249
5248 5250 .. note::
5249 5251
5250 5252 :hg:`log --patch` may generate unexpected diff output for merge
5251 5253 changesets, as it will only compare the merge changeset against
5252 5254 its first parent. Also, only files different from BOTH parents
5253 5255 will appear in files:.
5254 5256
5255 5257 .. note::
5256 5258
5257 5259 For performance reasons, :hg:`log FILE` may omit duplicate changes
5258 5260 made on branches and will not show removals or mode changes. To
5259 5261 see all such changes, use the --removed switch.
5260 5262
5261 5263 .. container:: verbose
5262 5264
5263 5265 Some examples:
5264 5266
5265 5267 - changesets with full descriptions and file lists::
5266 5268
5267 5269 hg log -v
5268 5270
5269 5271 - changesets ancestral to the working directory::
5270 5272
5271 5273 hg log -f
5272 5274
5273 5275 - last 10 commits on the current branch::
5274 5276
5275 5277 hg log -l 10 -b .
5276 5278
5277 5279 - changesets showing all modifications of a file, including removals::
5278 5280
5279 5281 hg log --removed file.c
5280 5282
5281 5283 - all changesets that touch a directory, with diffs, excluding merges::
5282 5284
5283 5285 hg log -Mp lib/
5284 5286
5285 5287 - all revision numbers that match a keyword::
5286 5288
5287 5289 hg log -k bug --template "{rev}\\n"
5288 5290
5289 5291 - the full hash identifier of the working directory parent::
5290 5292
5291 5293 hg log -r . --template "{node}\\n"
5292 5294
5293 5295 - list available log templates::
5294 5296
5295 5297 hg log -T list
5296 5298
5297 5299 - check if a given changeset is included in a tagged release::
5298 5300
5299 5301 hg log -r "a21ccf and ancestor(1.9)"
5300 5302
5301 5303 - find all changesets by some user in a date range::
5302 5304
5303 5305 hg log -k alice -d "may 2008 to jul 2008"
5304 5306
5305 5307 - summary of all changesets after the last tag::
5306 5308
5307 5309 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5308 5310
5309 5311 See :hg:`help dates` for a list of formats valid for -d/--date.
5310 5312
5311 5313 See :hg:`help revisions` and :hg:`help revsets` for more about
5312 5314 specifying and ordering revisions.
5313 5315
5314 5316 See :hg:`help templates` for more about pre-packaged styles and
5315 5317 specifying custom templates.
5316 5318
5317 5319 Returns 0 on success.
5318 5320
5319 5321 """
5320 5322 if opts.get('follow') and opts.get('rev'):
5321 5323 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5322 5324 del opts['follow']
5323 5325
5324 5326 if opts.get('graph'):
5325 5327 return cmdutil.graphlog(ui, repo, *pats, **opts)
5326 5328
5327 5329 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5328 5330 limit = cmdutil.loglimit(opts)
5329 5331 count = 0
5330 5332
5331 5333 getrenamed = None
5332 5334 if opts.get('copies'):
5333 5335 endrev = None
5334 5336 if opts.get('rev'):
5335 5337 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5336 5338 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5337 5339
5338 5340 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5339 5341 for rev in revs:
5340 5342 if count == limit:
5341 5343 break
5342 5344 ctx = repo[rev]
5343 5345 copies = None
5344 5346 if getrenamed is not None and rev:
5345 5347 copies = []
5346 5348 for fn in ctx.files():
5347 5349 rename = getrenamed(fn, rev)
5348 5350 if rename:
5349 5351 copies.append((fn, rename[0]))
5350 5352 if filematcher:
5351 5353 revmatchfn = filematcher(ctx.rev())
5352 5354 else:
5353 5355 revmatchfn = None
5354 5356 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5355 5357 if displayer.flush(ctx):
5356 5358 count += 1
5357 5359
5358 5360 displayer.close()
5359 5361
5360 5362 @command('manifest',
5361 5363 [('r', 'rev', '', _('revision to display'), _('REV')),
5362 5364 ('', 'all', False, _("list files from all revisions"))]
5363 5365 + formatteropts,
5364 5366 _('[-r REV]'))
5365 5367 def manifest(ui, repo, node=None, rev=None, **opts):
5366 5368 """output the current or given revision of the project manifest
5367 5369
5368 5370 Print a list of version controlled files for the given revision.
5369 5371 If no revision is given, the first parent of the working directory
5370 5372 is used, or the null revision if no revision is checked out.
5371 5373
5372 5374 With -v, print file permissions, symlink and executable bits.
5373 5375 With --debug, print file revision hashes.
5374 5376
5375 5377 If option --all is specified, the list of all files from all revisions
5376 5378 is printed. This includes deleted and renamed files.
5377 5379
5378 5380 Returns 0 on success.
5379 5381 """
5380 5382
5381 5383 fm = ui.formatter('manifest', opts)
5382 5384
5383 5385 if opts.get('all'):
5384 5386 if rev or node:
5385 5387 raise error.Abort(_("can't specify a revision with --all"))
5386 5388
5387 5389 res = []
5388 5390 prefix = "data/"
5389 5391 suffix = ".i"
5390 5392 plen = len(prefix)
5391 5393 slen = len(suffix)
5392 5394 with repo.lock():
5393 5395 for fn, b, size in repo.store.datafiles():
5394 5396 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5395 5397 res.append(fn[plen:-slen])
5396 5398 for f in res:
5397 5399 fm.startitem()
5398 5400 fm.write("path", '%s\n', f)
5399 5401 fm.end()
5400 5402 return
5401 5403
5402 5404 if rev and node:
5403 5405 raise error.Abort(_("please specify just one revision"))
5404 5406
5405 5407 if not node:
5406 5408 node = rev
5407 5409
5408 5410 char = {'l': '@', 'x': '*', '': ''}
5409 5411 mode = {'l': '644', 'x': '755', '': '644'}
5410 5412 ctx = scmutil.revsingle(repo, node)
5411 5413 mf = ctx.manifest()
5412 5414 for f in ctx:
5413 5415 fm.startitem()
5414 5416 fl = ctx[f].flags()
5415 5417 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5416 5418 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5417 5419 fm.write('path', '%s\n', f)
5418 5420 fm.end()
5419 5421
5420 5422 @command('^merge',
5421 5423 [('f', 'force', None,
5422 5424 _('force a merge including outstanding changes (DEPRECATED)')),
5423 5425 ('r', 'rev', '', _('revision to merge'), _('REV')),
5424 5426 ('P', 'preview', None,
5425 5427 _('review revisions to merge (no merge is performed)'))
5426 5428 ] + mergetoolopts,
5427 5429 _('[-P] [[-r] REV]'))
5428 5430 def merge(ui, repo, node=None, **opts):
5429 5431 """merge another revision into working directory
5430 5432
5431 5433 The current working directory is updated with all changes made in
5432 5434 the requested revision since the last common predecessor revision.
5433 5435
5434 5436 Files that changed between either parent are marked as changed for
5435 5437 the next commit and a commit must be performed before any further
5436 5438 updates to the repository are allowed. The next commit will have
5437 5439 two parents.
5438 5440
5439 5441 ``--tool`` can be used to specify the merge tool used for file
5440 5442 merges. It overrides the HGMERGE environment variable and your
5441 5443 configuration files. See :hg:`help merge-tools` for options.
5442 5444
5443 5445 If no revision is specified, the working directory's parent is a
5444 5446 head revision, and the current branch contains exactly one other
5445 5447 head, the other head is merged with by default. Otherwise, an
5446 5448 explicit revision with which to merge with must be provided.
5447 5449
5448 5450 See :hg:`help resolve` for information on handling file conflicts.
5449 5451
5450 5452 To undo an uncommitted merge, use :hg:`update --clean .` which
5451 5453 will check out a clean copy of the original merge parent, losing
5452 5454 all changes.
5453 5455
5454 5456 Returns 0 on success, 1 if there are unresolved files.
5455 5457 """
5456 5458
5457 5459 if opts.get('rev') and node:
5458 5460 raise error.Abort(_("please specify just one revision"))
5459 5461 if not node:
5460 5462 node = opts.get('rev')
5461 5463
5462 5464 if node:
5463 5465 node = scmutil.revsingle(repo, node).node()
5464 5466
5465 5467 if not node:
5466 5468 node = repo[destutil.destmerge(repo)].node()
5467 5469
5468 5470 if opts.get('preview'):
5469 5471 # find nodes that are ancestors of p2 but not of p1
5470 5472 p1 = repo.lookup('.')
5471 5473 p2 = repo.lookup(node)
5472 5474 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5473 5475
5474 5476 displayer = cmdutil.show_changeset(ui, repo, opts)
5475 5477 for node in nodes:
5476 5478 displayer.show(repo[node])
5477 5479 displayer.close()
5478 5480 return 0
5479 5481
5480 5482 try:
5481 5483 # ui.forcemerge is an internal variable, do not document
5482 5484 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5483 5485 force = opts.get('force')
5484 5486 labels = ['working copy', 'merge rev']
5485 5487 return hg.merge(repo, node, force=force, mergeforce=force,
5486 5488 labels=labels)
5487 5489 finally:
5488 5490 ui.setconfig('ui', 'forcemerge', '', 'merge')
5489 5491
5490 5492 @command('outgoing|out',
5491 5493 [('f', 'force', None, _('run even when the destination is unrelated')),
5492 5494 ('r', 'rev', [],
5493 5495 _('a changeset intended to be included in the destination'), _('REV')),
5494 5496 ('n', 'newest-first', None, _('show newest record first')),
5495 5497 ('B', 'bookmarks', False, _('compare bookmarks')),
5496 5498 ('b', 'branch', [], _('a specific branch you would like to push'),
5497 5499 _('BRANCH')),
5498 5500 ] + logopts + remoteopts + subrepoopts,
5499 5501 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5500 5502 def outgoing(ui, repo, dest=None, **opts):
5501 5503 """show changesets not found in the destination
5502 5504
5503 5505 Show changesets not found in the specified destination repository
5504 5506 or the default push location. These are the changesets that would
5505 5507 be pushed if a push was requested.
5506 5508
5507 5509 See pull for details of valid destination formats.
5508 5510
5509 5511 .. container:: verbose
5510 5512
5511 5513 With -B/--bookmarks, the result of bookmark comparison between
5512 5514 local and remote repositories is displayed. With -v/--verbose,
5513 5515 status is also displayed for each bookmark like below::
5514 5516
5515 5517 BM1 01234567890a added
5516 5518 BM2 deleted
5517 5519 BM3 234567890abc advanced
5518 5520 BM4 34567890abcd diverged
5519 5521 BM5 4567890abcde changed
5520 5522
5521 5523 The action taken when pushing depends on the
5522 5524 status of each bookmark:
5523 5525
5524 5526 :``added``: push with ``-B`` will create it
5525 5527 :``deleted``: push with ``-B`` will delete it
5526 5528 :``advanced``: push will update it
5527 5529 :``diverged``: push with ``-B`` will update it
5528 5530 :``changed``: push with ``-B`` will update it
5529 5531
5530 5532 From the point of view of pushing behavior, bookmarks
5531 5533 existing only in the remote repository are treated as
5532 5534 ``deleted``, even if it is in fact added remotely.
5533 5535
5534 5536 Returns 0 if there are outgoing changes, 1 otherwise.
5535 5537 """
5536 5538 if opts.get('graph'):
5537 5539 cmdutil.checkunsupportedgraphflags([], opts)
5538 5540 o, other = hg._outgoing(ui, repo, dest, opts)
5539 5541 if not o:
5540 5542 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5541 5543 return
5542 5544
5543 5545 revdag = cmdutil.graphrevs(repo, o, opts)
5544 5546 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5545 5547 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5546 5548 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5547 5549 return 0
5548 5550
5549 5551 if opts.get('bookmarks'):
5550 5552 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5551 5553 dest, branches = hg.parseurl(dest, opts.get('branch'))
5552 5554 other = hg.peer(repo, opts, dest)
5553 5555 if 'bookmarks' not in other.listkeys('namespaces'):
5554 5556 ui.warn(_("remote doesn't support bookmarks\n"))
5555 5557 return 0
5556 5558 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5557 5559 return bookmarks.outgoing(ui, repo, other)
5558 5560
5559 5561 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5560 5562 try:
5561 5563 return hg.outgoing(ui, repo, dest, opts)
5562 5564 finally:
5563 5565 del repo._subtoppath
5564 5566
5565 5567 @command('parents',
5566 5568 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5567 5569 ] + templateopts,
5568 5570 _('[-r REV] [FILE]'),
5569 5571 inferrepo=True)
5570 5572 def parents(ui, repo, file_=None, **opts):
5571 5573 """show the parents of the working directory or revision (DEPRECATED)
5572 5574
5573 5575 Print the working directory's parent revisions. If a revision is
5574 5576 given via -r/--rev, the parent of that revision will be printed.
5575 5577 If a file argument is given, the revision in which the file was
5576 5578 last changed (before the working directory revision or the
5577 5579 argument to --rev if given) is printed.
5578 5580
5579 5581 This command is equivalent to::
5580 5582
5581 5583 hg log -r "p1()+p2()" or
5582 5584 hg log -r "p1(REV)+p2(REV)" or
5583 5585 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5584 5586 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5585 5587
5586 5588 See :hg:`summary` and :hg:`help revsets` for related information.
5587 5589
5588 5590 Returns 0 on success.
5589 5591 """
5590 5592
5591 5593 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5592 5594
5593 5595 if file_:
5594 5596 m = scmutil.match(ctx, (file_,), opts)
5595 5597 if m.anypats() or len(m.files()) != 1:
5596 5598 raise error.Abort(_('can only specify an explicit filename'))
5597 5599 file_ = m.files()[0]
5598 5600 filenodes = []
5599 5601 for cp in ctx.parents():
5600 5602 if not cp:
5601 5603 continue
5602 5604 try:
5603 5605 filenodes.append(cp.filenode(file_))
5604 5606 except error.LookupError:
5605 5607 pass
5606 5608 if not filenodes:
5607 5609 raise error.Abort(_("'%s' not found in manifest!") % file_)
5608 5610 p = []
5609 5611 for fn in filenodes:
5610 5612 fctx = repo.filectx(file_, fileid=fn)
5611 5613 p.append(fctx.node())
5612 5614 else:
5613 5615 p = [cp.node() for cp in ctx.parents()]
5614 5616
5615 5617 displayer = cmdutil.show_changeset(ui, repo, opts)
5616 5618 for n in p:
5617 5619 if n != nullid:
5618 5620 displayer.show(repo[n])
5619 5621 displayer.close()
5620 5622
5621 5623 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5622 5624 def paths(ui, repo, search=None, **opts):
5623 5625 """show aliases for remote repositories
5624 5626
5625 5627 Show definition of symbolic path name NAME. If no name is given,
5626 5628 show definition of all available names.
5627 5629
5628 5630 Option -q/--quiet suppresses all output when searching for NAME
5629 5631 and shows only the path names when listing all definitions.
5630 5632
5631 5633 Path names are defined in the [paths] section of your
5632 5634 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5633 5635 repository, ``.hg/hgrc`` is used, too.
5634 5636
5635 5637 The path names ``default`` and ``default-push`` have a special
5636 5638 meaning. When performing a push or pull operation, they are used
5637 5639 as fallbacks if no location is specified on the command-line.
5638 5640 When ``default-push`` is set, it will be used for push and
5639 5641 ``default`` will be used for pull; otherwise ``default`` is used
5640 5642 as the fallback for both. When cloning a repository, the clone
5641 5643 source is written as ``default`` in ``.hg/hgrc``.
5642 5644
5643 5645 .. note::
5644 5646
5645 5647 ``default`` and ``default-push`` apply to all inbound (e.g.
5646 5648 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5647 5649 and :hg:`bundle`) operations.
5648 5650
5649 5651 See :hg:`help urls` for more information.
5650 5652
5651 5653 Returns 0 on success.
5652 5654 """
5653 5655 if search:
5654 5656 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5655 5657 if name == search]
5656 5658 else:
5657 5659 pathitems = sorted(ui.paths.iteritems())
5658 5660
5659 5661 fm = ui.formatter('paths', opts)
5660 5662 if fm.isplain():
5661 5663 hidepassword = util.hidepassword
5662 5664 else:
5663 5665 hidepassword = str
5664 5666 if ui.quiet:
5665 5667 namefmt = '%s\n'
5666 5668 else:
5667 5669 namefmt = '%s = '
5668 5670 showsubopts = not search and not ui.quiet
5669 5671
5670 5672 for name, path in pathitems:
5671 5673 fm.startitem()
5672 5674 fm.condwrite(not search, 'name', namefmt, name)
5673 5675 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5674 5676 for subopt, value in sorted(path.suboptions.items()):
5675 5677 assert subopt not in ('name', 'url')
5676 5678 if showsubopts:
5677 5679 fm.plain('%s:%s = ' % (name, subopt))
5678 5680 fm.condwrite(showsubopts, subopt, '%s\n', value)
5679 5681
5680 5682 fm.end()
5681 5683
5682 5684 if search and not pathitems:
5683 5685 if not ui.quiet:
5684 5686 ui.warn(_("not found!\n"))
5685 5687 return 1
5686 5688 else:
5687 5689 return 0
5688 5690
5689 5691 @command('phase',
5690 5692 [('p', 'public', False, _('set changeset phase to public')),
5691 5693 ('d', 'draft', False, _('set changeset phase to draft')),
5692 5694 ('s', 'secret', False, _('set changeset phase to secret')),
5693 5695 ('f', 'force', False, _('allow to move boundary backward')),
5694 5696 ('r', 'rev', [], _('target revision'), _('REV')),
5695 5697 ],
5696 5698 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5697 5699 def phase(ui, repo, *revs, **opts):
5698 5700 """set or show the current phase name
5699 5701
5700 5702 With no argument, show the phase name of the current revision(s).
5701 5703
5702 5704 With one of -p/--public, -d/--draft or -s/--secret, change the
5703 5705 phase value of the specified revisions.
5704 5706
5705 5707 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5706 5708 lower phase to an higher phase. Phases are ordered as follows::
5707 5709
5708 5710 public < draft < secret
5709 5711
5710 5712 Returns 0 on success, 1 if some phases could not be changed.
5711 5713
5712 5714 (For more information about the phases concept, see :hg:`help phases`.)
5713 5715 """
5714 5716 # search for a unique phase argument
5715 5717 targetphase = None
5716 5718 for idx, name in enumerate(phases.phasenames):
5717 5719 if opts[name]:
5718 5720 if targetphase is not None:
5719 5721 raise error.Abort(_('only one phase can be specified'))
5720 5722 targetphase = idx
5721 5723
5722 5724 # look for specified revision
5723 5725 revs = list(revs)
5724 5726 revs.extend(opts['rev'])
5725 5727 if not revs:
5726 5728 # display both parents as the second parent phase can influence
5727 5729 # the phase of a merge commit
5728 5730 revs = [c.rev() for c in repo[None].parents()]
5729 5731
5730 5732 revs = scmutil.revrange(repo, revs)
5731 5733
5732 5734 lock = None
5733 5735 ret = 0
5734 5736 if targetphase is None:
5735 5737 # display
5736 5738 for r in revs:
5737 5739 ctx = repo[r]
5738 5740 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5739 5741 else:
5740 5742 tr = None
5741 5743 lock = repo.lock()
5742 5744 try:
5743 5745 tr = repo.transaction("phase")
5744 5746 # set phase
5745 5747 if not revs:
5746 5748 raise error.Abort(_('empty revision set'))
5747 5749 nodes = [repo[r].node() for r in revs]
5748 5750 # moving revision from public to draft may hide them
5749 5751 # We have to check result on an unfiltered repository
5750 5752 unfi = repo.unfiltered()
5751 5753 getphase = unfi._phasecache.phase
5752 5754 olddata = [getphase(unfi, r) for r in unfi]
5753 5755 phases.advanceboundary(repo, tr, targetphase, nodes)
5754 5756 if opts['force']:
5755 5757 phases.retractboundary(repo, tr, targetphase, nodes)
5756 5758 tr.close()
5757 5759 finally:
5758 5760 if tr is not None:
5759 5761 tr.release()
5760 5762 lock.release()
5761 5763 getphase = unfi._phasecache.phase
5762 5764 newdata = [getphase(unfi, r) for r in unfi]
5763 5765 changes = sum(newdata[r] != olddata[r] for r in unfi)
5764 5766 cl = unfi.changelog
5765 5767 rejected = [n for n in nodes
5766 5768 if newdata[cl.rev(n)] < targetphase]
5767 5769 if rejected:
5768 5770 ui.warn(_('cannot move %i changesets to a higher '
5769 5771 'phase, use --force\n') % len(rejected))
5770 5772 ret = 1
5771 5773 if changes:
5772 5774 msg = _('phase changed for %i changesets\n') % changes
5773 5775 if ret:
5774 5776 ui.status(msg)
5775 5777 else:
5776 5778 ui.note(msg)
5777 5779 else:
5778 5780 ui.warn(_('no phases changed\n'))
5779 5781 return ret
5780 5782
5781 5783 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5782 5784 """Run after a changegroup has been added via pull/unbundle
5783 5785
5784 5786 This takes arguments below:
5785 5787
5786 5788 :modheads: change of heads by pull/unbundle
5787 5789 :optupdate: updating working directory is needed or not
5788 5790 :checkout: update destination revision (or None to default destination)
5789 5791 :brev: a name, which might be a bookmark to be activated after updating
5790 5792 """
5791 5793 if modheads == 0:
5792 5794 return
5793 5795 if optupdate:
5794 5796 try:
5795 5797 return hg.updatetotally(ui, repo, checkout, brev)
5796 5798 except error.UpdateAbort as inst:
5797 5799 msg = _("not updating: %s") % str(inst)
5798 5800 hint = inst.hint
5799 5801 raise error.UpdateAbort(msg, hint=hint)
5800 5802 if modheads > 1:
5801 5803 currentbranchheads = len(repo.branchheads())
5802 5804 if currentbranchheads == modheads:
5803 5805 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5804 5806 elif currentbranchheads > 1:
5805 5807 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5806 5808 "merge)\n"))
5807 5809 else:
5808 5810 ui.status(_("(run 'hg heads' to see heads)\n"))
5809 5811 else:
5810 5812 ui.status(_("(run 'hg update' to get a working copy)\n"))
5811 5813
5812 5814 @command('^pull',
5813 5815 [('u', 'update', None,
5814 5816 _('update to new branch head if changesets were pulled')),
5815 5817 ('f', 'force', None, _('run even when remote repository is unrelated')),
5816 5818 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5817 5819 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5818 5820 ('b', 'branch', [], _('a specific branch you would like to pull'),
5819 5821 _('BRANCH')),
5820 5822 ] + remoteopts,
5821 5823 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5822 5824 def pull(ui, repo, source="default", **opts):
5823 5825 """pull changes from the specified source
5824 5826
5825 5827 Pull changes from a remote repository to a local one.
5826 5828
5827 5829 This finds all changes from the repository at the specified path
5828 5830 or URL and adds them to a local repository (the current one unless
5829 5831 -R is specified). By default, this does not update the copy of the
5830 5832 project in the working directory.
5831 5833
5832 5834 Use :hg:`incoming` if you want to see what would have been added
5833 5835 by a pull at the time you issued this command. If you then decide
5834 5836 to add those changes to the repository, you should use :hg:`pull
5835 5837 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5836 5838
5837 5839 If SOURCE is omitted, the 'default' path will be used.
5838 5840 See :hg:`help urls` for more information.
5839 5841
5840 5842 Specifying bookmark as ``.`` is equivalent to specifying the active
5841 5843 bookmark's name.
5842 5844
5843 5845 Returns 0 on success, 1 if an update had unresolved files.
5844 5846 """
5845 5847 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5846 5848 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5847 5849 other = hg.peer(repo, opts, source)
5848 5850 try:
5849 5851 revs, checkout = hg.addbranchrevs(repo, other, branches,
5850 5852 opts.get('rev'))
5851 5853
5852 5854
5853 5855 pullopargs = {}
5854 5856 if opts.get('bookmark'):
5855 5857 if not revs:
5856 5858 revs = []
5857 5859 # The list of bookmark used here is not the one used to actually
5858 5860 # update the bookmark name. This can result in the revision pulled
5859 5861 # not ending up with the name of the bookmark because of a race
5860 5862 # condition on the server. (See issue 4689 for details)
5861 5863 remotebookmarks = other.listkeys('bookmarks')
5862 5864 pullopargs['remotebookmarks'] = remotebookmarks
5863 5865 for b in opts['bookmark']:
5864 5866 b = repo._bookmarks.expandname(b)
5865 5867 if b not in remotebookmarks:
5866 5868 raise error.Abort(_('remote bookmark %s not found!') % b)
5867 5869 revs.append(remotebookmarks[b])
5868 5870
5869 5871 if revs:
5870 5872 try:
5871 5873 # When 'rev' is a bookmark name, we cannot guarantee that it
5872 5874 # will be updated with that name because of a race condition
5873 5875 # server side. (See issue 4689 for details)
5874 5876 oldrevs = revs
5875 5877 revs = [] # actually, nodes
5876 5878 for r in oldrevs:
5877 5879 node = other.lookup(r)
5878 5880 revs.append(node)
5879 5881 if r == checkout:
5880 5882 checkout = node
5881 5883 except error.CapabilityError:
5882 5884 err = _("other repository doesn't support revision lookup, "
5883 5885 "so a rev cannot be specified.")
5884 5886 raise error.Abort(err)
5885 5887
5886 5888 pullopargs.update(opts.get('opargs', {}))
5887 5889 modheads = exchange.pull(repo, other, heads=revs,
5888 5890 force=opts.get('force'),
5889 5891 bookmarks=opts.get('bookmark', ()),
5890 5892 opargs=pullopargs).cgresult
5891 5893
5892 5894 # brev is a name, which might be a bookmark to be activated at
5893 5895 # the end of the update. In other words, it is an explicit
5894 5896 # destination of the update
5895 5897 brev = None
5896 5898
5897 5899 if checkout:
5898 5900 checkout = str(repo.changelog.rev(checkout))
5899 5901
5900 5902 # order below depends on implementation of
5901 5903 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5902 5904 # because 'checkout' is determined without it.
5903 5905 if opts.get('rev'):
5904 5906 brev = opts['rev'][0]
5905 5907 elif opts.get('branch'):
5906 5908 brev = opts['branch'][0]
5907 5909 else:
5908 5910 brev = branches[0]
5909 5911 repo._subtoppath = source
5910 5912 try:
5911 5913 ret = postincoming(ui, repo, modheads, opts.get('update'),
5912 5914 checkout, brev)
5913 5915
5914 5916 finally:
5915 5917 del repo._subtoppath
5916 5918
5917 5919 finally:
5918 5920 other.close()
5919 5921 return ret
5920 5922
5921 5923 @command('^push',
5922 5924 [('f', 'force', None, _('force push')),
5923 5925 ('r', 'rev', [],
5924 5926 _('a changeset intended to be included in the destination'),
5925 5927 _('REV')),
5926 5928 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5927 5929 ('b', 'branch', [],
5928 5930 _('a specific branch you would like to push'), _('BRANCH')),
5929 5931 ('', 'new-branch', False, _('allow pushing a new branch')),
5930 5932 ] + remoteopts,
5931 5933 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5932 5934 def push(ui, repo, dest=None, **opts):
5933 5935 """push changes to the specified destination
5934 5936
5935 5937 Push changesets from the local repository to the specified
5936 5938 destination.
5937 5939
5938 5940 This operation is symmetrical to pull: it is identical to a pull
5939 5941 in the destination repository from the current one.
5940 5942
5941 5943 By default, push will not allow creation of new heads at the
5942 5944 destination, since multiple heads would make it unclear which head
5943 5945 to use. In this situation, it is recommended to pull and merge
5944 5946 before pushing.
5945 5947
5946 5948 Use --new-branch if you want to allow push to create a new named
5947 5949 branch that is not present at the destination. This allows you to
5948 5950 only create a new branch without forcing other changes.
5949 5951
5950 5952 .. note::
5951 5953
5952 5954 Extra care should be taken with the -f/--force option,
5953 5955 which will push all new heads on all branches, an action which will
5954 5956 almost always cause confusion for collaborators.
5955 5957
5956 5958 If -r/--rev is used, the specified revision and all its ancestors
5957 5959 will be pushed to the remote repository.
5958 5960
5959 5961 If -B/--bookmark is used, the specified bookmarked revision, its
5960 5962 ancestors, and the bookmark will be pushed to the remote
5961 5963 repository. Specifying ``.`` is equivalent to specifying the active
5962 5964 bookmark's name.
5963 5965
5964 5966 Please see :hg:`help urls` for important details about ``ssh://``
5965 5967 URLs. If DESTINATION is omitted, a default path will be used.
5966 5968
5967 5969 Returns 0 if push was successful, 1 if nothing to push.
5968 5970 """
5969 5971
5970 5972 if opts.get('bookmark'):
5971 5973 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5972 5974 for b in opts['bookmark']:
5973 5975 # translate -B options to -r so changesets get pushed
5974 5976 b = repo._bookmarks.expandname(b)
5975 5977 if b in repo._bookmarks:
5976 5978 opts.setdefault('rev', []).append(b)
5977 5979 else:
5978 5980 # if we try to push a deleted bookmark, translate it to null
5979 5981 # this lets simultaneous -r, -b options continue working
5980 5982 opts.setdefault('rev', []).append("null")
5981 5983
5982 5984 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5983 5985 if not path:
5984 5986 raise error.Abort(_('default repository not configured!'),
5985 5987 hint=_("see 'hg help config.paths'"))
5986 5988 dest = path.pushloc or path.loc
5987 5989 branches = (path.branch, opts.get('branch') or [])
5988 5990 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5989 5991 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5990 5992 other = hg.peer(repo, opts, dest)
5991 5993
5992 5994 if revs:
5993 5995 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5994 5996 if not revs:
5995 5997 raise error.Abort(_("specified revisions evaluate to an empty set"),
5996 5998 hint=_("use different revision arguments"))
5997 5999 elif path.pushrev:
5998 6000 # It doesn't make any sense to specify ancestor revisions. So limit
5999 6001 # to DAG heads to make discovery simpler.
6000 6002 expr = revset.formatspec('heads(%r)', path.pushrev)
6001 6003 revs = scmutil.revrange(repo, [expr])
6002 6004 revs = [repo[rev].node() for rev in revs]
6003 6005 if not revs:
6004 6006 raise error.Abort(_('default push revset for path evaluates to an '
6005 6007 'empty set'))
6006 6008
6007 6009 repo._subtoppath = dest
6008 6010 try:
6009 6011 # push subrepos depth-first for coherent ordering
6010 6012 c = repo['']
6011 6013 subs = c.substate # only repos that are committed
6012 6014 for s in sorted(subs):
6013 6015 result = c.sub(s).push(opts)
6014 6016 if result == 0:
6015 6017 return not result
6016 6018 finally:
6017 6019 del repo._subtoppath
6018 6020 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
6019 6021 newbranch=opts.get('new_branch'),
6020 6022 bookmarks=opts.get('bookmark', ()),
6021 6023 opargs=opts.get('opargs'))
6022 6024
6023 6025 result = not pushop.cgresult
6024 6026
6025 6027 if pushop.bkresult is not None:
6026 6028 if pushop.bkresult == 2:
6027 6029 result = 2
6028 6030 elif not result and pushop.bkresult:
6029 6031 result = 2
6030 6032
6031 6033 return result
6032 6034
6033 6035 @command('recover', [])
6034 6036 def recover(ui, repo):
6035 6037 """roll back an interrupted transaction
6036 6038
6037 6039 Recover from an interrupted commit or pull.
6038 6040
6039 6041 This command tries to fix the repository status after an
6040 6042 interrupted operation. It should only be necessary when Mercurial
6041 6043 suggests it.
6042 6044
6043 6045 Returns 0 if successful, 1 if nothing to recover or verify fails.
6044 6046 """
6045 6047 if repo.recover():
6046 6048 return hg.verify(repo)
6047 6049 return 1
6048 6050
6049 6051 @command('^remove|rm',
6050 6052 [('A', 'after', None, _('record delete for missing files')),
6051 6053 ('f', 'force', None,
6052 6054 _('forget added files, delete modified files')),
6053 6055 ] + subrepoopts + walkopts,
6054 6056 _('[OPTION]... FILE...'),
6055 6057 inferrepo=True)
6056 6058 def remove(ui, repo, *pats, **opts):
6057 6059 """remove the specified files on the next commit
6058 6060
6059 6061 Schedule the indicated files for removal from the current branch.
6060 6062
6061 6063 This command schedules the files to be removed at the next commit.
6062 6064 To undo a remove before that, see :hg:`revert`. To undo added
6063 6065 files, see :hg:`forget`.
6064 6066
6065 6067 .. container:: verbose
6066 6068
6067 6069 -A/--after can be used to remove only files that have already
6068 6070 been deleted, -f/--force can be used to force deletion, and -Af
6069 6071 can be used to remove files from the next revision without
6070 6072 deleting them from the working directory.
6071 6073
6072 6074 The following table details the behavior of remove for different
6073 6075 file states (columns) and option combinations (rows). The file
6074 6076 states are Added [A], Clean [C], Modified [M] and Missing [!]
6075 6077 (as reported by :hg:`status`). The actions are Warn, Remove
6076 6078 (from branch) and Delete (from disk):
6077 6079
6078 6080 ========= == == == ==
6079 6081 opt/state A C M !
6080 6082 ========= == == == ==
6081 6083 none W RD W R
6082 6084 -f R RD RD R
6083 6085 -A W W W R
6084 6086 -Af R R R R
6085 6087 ========= == == == ==
6086 6088
6087 6089 .. note::
6088 6090
6089 6091 :hg:`remove` never deletes files in Added [A] state from the
6090 6092 working directory, not even if ``--force`` is specified.
6091 6093
6092 6094 Returns 0 on success, 1 if any warnings encountered.
6093 6095 """
6094 6096
6095 6097 after, force = opts.get('after'), opts.get('force')
6096 6098 if not pats and not after:
6097 6099 raise error.Abort(_('no files specified'))
6098 6100
6099 6101 m = scmutil.match(repo[None], pats, opts)
6100 6102 subrepos = opts.get('subrepos')
6101 6103 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6102 6104
6103 6105 @command('rename|move|mv',
6104 6106 [('A', 'after', None, _('record a rename that has already occurred')),
6105 6107 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6106 6108 ] + walkopts + dryrunopts,
6107 6109 _('[OPTION]... SOURCE... DEST'))
6108 6110 def rename(ui, repo, *pats, **opts):
6109 6111 """rename files; equivalent of copy + remove
6110 6112
6111 6113 Mark dest as copies of sources; mark sources for deletion. If dest
6112 6114 is a directory, copies are put in that directory. If dest is a
6113 6115 file, there can only be one source.
6114 6116
6115 6117 By default, this command copies the contents of files as they
6116 6118 exist in the working directory. If invoked with -A/--after, the
6117 6119 operation is recorded, but no copying is performed.
6118 6120
6119 6121 This command takes effect at the next commit. To undo a rename
6120 6122 before that, see :hg:`revert`.
6121 6123
6122 6124 Returns 0 on success, 1 if errors are encountered.
6123 6125 """
6124 6126 with repo.wlock(False):
6125 6127 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6126 6128
6127 6129 @command('resolve',
6128 6130 [('a', 'all', None, _('select all unresolved files')),
6129 6131 ('l', 'list', None, _('list state of files needing merge')),
6130 6132 ('m', 'mark', None, _('mark files as resolved')),
6131 6133 ('u', 'unmark', None, _('mark files as unresolved')),
6132 6134 ('n', 'no-status', None, _('hide status prefix'))]
6133 6135 + mergetoolopts + walkopts + formatteropts,
6134 6136 _('[OPTION]... [FILE]...'),
6135 6137 inferrepo=True)
6136 6138 def resolve(ui, repo, *pats, **opts):
6137 6139 """redo merges or set/view the merge status of files
6138 6140
6139 6141 Merges with unresolved conflicts are often the result of
6140 6142 non-interactive merging using the ``internal:merge`` configuration
6141 6143 setting, or a command-line merge tool like ``diff3``. The resolve
6142 6144 command is used to manage the files involved in a merge, after
6143 6145 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6144 6146 working directory must have two parents). See :hg:`help
6145 6147 merge-tools` for information on configuring merge tools.
6146 6148
6147 6149 The resolve command can be used in the following ways:
6148 6150
6149 6151 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6150 6152 files, discarding any previous merge attempts. Re-merging is not
6151 6153 performed for files already marked as resolved. Use ``--all/-a``
6152 6154 to select all unresolved files. ``--tool`` can be used to specify
6153 6155 the merge tool used for the given files. It overrides the HGMERGE
6154 6156 environment variable and your configuration files. Previous file
6155 6157 contents are saved with a ``.orig`` suffix.
6156 6158
6157 6159 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6158 6160 (e.g. after having manually fixed-up the files). The default is
6159 6161 to mark all unresolved files.
6160 6162
6161 6163 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6162 6164 default is to mark all resolved files.
6163 6165
6164 6166 - :hg:`resolve -l`: list files which had or still have conflicts.
6165 6167 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6166 6168
6167 6169 .. note::
6168 6170
6169 6171 Mercurial will not let you commit files with unresolved merge
6170 6172 conflicts. You must use :hg:`resolve -m ...` before you can
6171 6173 commit after a conflicting merge.
6172 6174
6173 6175 Returns 0 on success, 1 if any files fail a resolve attempt.
6174 6176 """
6175 6177
6176 6178 flaglist = 'all mark unmark list no_status'.split()
6177 6179 all, mark, unmark, show, nostatus = \
6178 6180 [opts.get(o) for o in flaglist]
6179 6181
6180 6182 if (show and (mark or unmark)) or (mark and unmark):
6181 6183 raise error.Abort(_("too many options specified"))
6182 6184 if pats and all:
6183 6185 raise error.Abort(_("can't specify --all and patterns"))
6184 6186 if not (all or pats or show or mark or unmark):
6185 6187 raise error.Abort(_('no files or directories specified'),
6186 6188 hint=('use --all to re-merge all unresolved files'))
6187 6189
6188 6190 if show:
6189 6191 fm = ui.formatter('resolve', opts)
6190 6192 ms = mergemod.mergestate.read(repo)
6191 6193 m = scmutil.match(repo[None], pats, opts)
6192 6194 for f in ms:
6193 6195 if not m(f):
6194 6196 continue
6195 6197 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6196 6198 'd': 'driverresolved'}[ms[f]]
6197 6199 fm.startitem()
6198 6200 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6199 6201 fm.write('path', '%s\n', f, label=l)
6200 6202 fm.end()
6201 6203 return 0
6202 6204
6203 6205 with repo.wlock():
6204 6206 ms = mergemod.mergestate.read(repo)
6205 6207
6206 6208 if not (ms.active() or repo.dirstate.p2() != nullid):
6207 6209 raise error.Abort(
6208 6210 _('resolve command not applicable when not merging'))
6209 6211
6210 6212 wctx = repo[None]
6211 6213
6212 6214 if ms.mergedriver and ms.mdstate() == 'u':
6213 6215 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6214 6216 ms.commit()
6215 6217 # allow mark and unmark to go through
6216 6218 if not mark and not unmark and not proceed:
6217 6219 return 1
6218 6220
6219 6221 m = scmutil.match(wctx, pats, opts)
6220 6222 ret = 0
6221 6223 didwork = False
6222 6224 runconclude = False
6223 6225
6224 6226 tocomplete = []
6225 6227 for f in ms:
6226 6228 if not m(f):
6227 6229 continue
6228 6230
6229 6231 didwork = True
6230 6232
6231 6233 # don't let driver-resolved files be marked, and run the conclude
6232 6234 # step if asked to resolve
6233 6235 if ms[f] == "d":
6234 6236 exact = m.exact(f)
6235 6237 if mark:
6236 6238 if exact:
6237 6239 ui.warn(_('not marking %s as it is driver-resolved\n')
6238 6240 % f)
6239 6241 elif unmark:
6240 6242 if exact:
6241 6243 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6242 6244 % f)
6243 6245 else:
6244 6246 runconclude = True
6245 6247 continue
6246 6248
6247 6249 if mark:
6248 6250 ms.mark(f, "r")
6249 6251 elif unmark:
6250 6252 ms.mark(f, "u")
6251 6253 else:
6252 6254 # backup pre-resolve (merge uses .orig for its own purposes)
6253 6255 a = repo.wjoin(f)
6254 6256 try:
6255 6257 util.copyfile(a, a + ".resolve")
6256 6258 except (IOError, OSError) as inst:
6257 6259 if inst.errno != errno.ENOENT:
6258 6260 raise
6259 6261
6260 6262 try:
6261 6263 # preresolve file
6262 6264 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6263 6265 'resolve')
6264 6266 complete, r = ms.preresolve(f, wctx)
6265 6267 if not complete:
6266 6268 tocomplete.append(f)
6267 6269 elif r:
6268 6270 ret = 1
6269 6271 finally:
6270 6272 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6271 6273 ms.commit()
6272 6274
6273 6275 # replace filemerge's .orig file with our resolve file, but only
6274 6276 # for merges that are complete
6275 6277 if complete:
6276 6278 try:
6277 6279 util.rename(a + ".resolve",
6278 6280 scmutil.origpath(ui, repo, a))
6279 6281 except OSError as inst:
6280 6282 if inst.errno != errno.ENOENT:
6281 6283 raise
6282 6284
6283 6285 for f in tocomplete:
6284 6286 try:
6285 6287 # resolve file
6286 6288 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6287 6289 'resolve')
6288 6290 r = ms.resolve(f, wctx)
6289 6291 if r:
6290 6292 ret = 1
6291 6293 finally:
6292 6294 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6293 6295 ms.commit()
6294 6296
6295 6297 # replace filemerge's .orig file with our resolve file
6296 6298 a = repo.wjoin(f)
6297 6299 try:
6298 6300 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6299 6301 except OSError as inst:
6300 6302 if inst.errno != errno.ENOENT:
6301 6303 raise
6302 6304
6303 6305 ms.commit()
6304 6306 ms.recordactions()
6305 6307
6306 6308 if not didwork and pats:
6307 6309 hint = None
6308 6310 if not any([p for p in pats if p.find(':') >= 0]):
6309 6311 pats = ['path:%s' % p for p in pats]
6310 6312 m = scmutil.match(wctx, pats, opts)
6311 6313 for f in ms:
6312 6314 if not m(f):
6313 6315 continue
6314 6316 flags = ''.join(['-%s ' % o[0] for o in flaglist
6315 6317 if opts.get(o)])
6316 6318 hint = _("(try: hg resolve %s%s)\n") % (
6317 6319 flags,
6318 6320 ' '.join(pats))
6319 6321 break
6320 6322 ui.warn(_("arguments do not match paths that need resolving\n"))
6321 6323 if hint:
6322 6324 ui.warn(hint)
6323 6325 elif ms.mergedriver and ms.mdstate() != 's':
6324 6326 # run conclude step when either a driver-resolved file is requested
6325 6327 # or there are no driver-resolved files
6326 6328 # we can't use 'ret' to determine whether any files are unresolved
6327 6329 # because we might not have tried to resolve some
6328 6330 if ((runconclude or not list(ms.driverresolved()))
6329 6331 and not list(ms.unresolved())):
6330 6332 proceed = mergemod.driverconclude(repo, ms, wctx)
6331 6333 ms.commit()
6332 6334 if not proceed:
6333 6335 return 1
6334 6336
6335 6337 # Nudge users into finishing an unfinished operation
6336 6338 unresolvedf = list(ms.unresolved())
6337 6339 driverresolvedf = list(ms.driverresolved())
6338 6340 if not unresolvedf and not driverresolvedf:
6339 6341 ui.status(_('(no more unresolved files)\n'))
6340 6342 cmdutil.checkafterresolved(repo)
6341 6343 elif not unresolvedf:
6342 6344 ui.status(_('(no more unresolved files -- '
6343 6345 'run "hg resolve --all" to conclude)\n'))
6344 6346
6345 6347 return ret
6346 6348
6347 6349 @command('revert',
6348 6350 [('a', 'all', None, _('revert all changes when no arguments given')),
6349 6351 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6350 6352 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6351 6353 ('C', 'no-backup', None, _('do not save backup copies of files')),
6352 6354 ('i', 'interactive', None,
6353 6355 _('interactively select the changes (EXPERIMENTAL)')),
6354 6356 ] + walkopts + dryrunopts,
6355 6357 _('[OPTION]... [-r REV] [NAME]...'))
6356 6358 def revert(ui, repo, *pats, **opts):
6357 6359 """restore files to their checkout state
6358 6360
6359 6361 .. note::
6360 6362
6361 6363 To check out earlier revisions, you should use :hg:`update REV`.
6362 6364 To cancel an uncommitted merge (and lose your changes),
6363 6365 use :hg:`update --clean .`.
6364 6366
6365 6367 With no revision specified, revert the specified files or directories
6366 6368 to the contents they had in the parent of the working directory.
6367 6369 This restores the contents of files to an unmodified
6368 6370 state and unschedules adds, removes, copies, and renames. If the
6369 6371 working directory has two parents, you must explicitly specify a
6370 6372 revision.
6371 6373
6372 6374 Using the -r/--rev or -d/--date options, revert the given files or
6373 6375 directories to their states as of a specific revision. Because
6374 6376 revert does not change the working directory parents, this will
6375 6377 cause these files to appear modified. This can be helpful to "back
6376 6378 out" some or all of an earlier change. See :hg:`backout` for a
6377 6379 related method.
6378 6380
6379 6381 Modified files are saved with a .orig suffix before reverting.
6380 6382 To disable these backups, use --no-backup. It is possible to store
6381 6383 the backup files in a custom directory relative to the root of the
6382 6384 repository by setting the ``ui.origbackuppath`` configuration
6383 6385 option.
6384 6386
6385 6387 See :hg:`help dates` for a list of formats valid for -d/--date.
6386 6388
6387 6389 See :hg:`help backout` for a way to reverse the effect of an
6388 6390 earlier changeset.
6389 6391
6390 6392 Returns 0 on success.
6391 6393 """
6392 6394
6393 6395 if opts.get("date"):
6394 6396 if opts.get("rev"):
6395 6397 raise error.Abort(_("you can't specify a revision and a date"))
6396 6398 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6397 6399
6398 6400 parent, p2 = repo.dirstate.parents()
6399 6401 if not opts.get('rev') and p2 != nullid:
6400 6402 # revert after merge is a trap for new users (issue2915)
6401 6403 raise error.Abort(_('uncommitted merge with no revision specified'),
6402 6404 hint=_("use 'hg update' or see 'hg help revert'"))
6403 6405
6404 6406 ctx = scmutil.revsingle(repo, opts.get('rev'))
6405 6407
6406 6408 if (not (pats or opts.get('include') or opts.get('exclude') or
6407 6409 opts.get('all') or opts.get('interactive'))):
6408 6410 msg = _("no files or directories specified")
6409 6411 if p2 != nullid:
6410 6412 hint = _("uncommitted merge, use --all to discard all changes,"
6411 6413 " or 'hg update -C .' to abort the merge")
6412 6414 raise error.Abort(msg, hint=hint)
6413 6415 dirty = any(repo.status())
6414 6416 node = ctx.node()
6415 6417 if node != parent:
6416 6418 if dirty:
6417 6419 hint = _("uncommitted changes, use --all to discard all"
6418 6420 " changes, or 'hg update %s' to update") % ctx.rev()
6419 6421 else:
6420 6422 hint = _("use --all to revert all files,"
6421 6423 " or 'hg update %s' to update") % ctx.rev()
6422 6424 elif dirty:
6423 6425 hint = _("uncommitted changes, use --all to discard all changes")
6424 6426 else:
6425 6427 hint = _("use --all to revert all files")
6426 6428 raise error.Abort(msg, hint=hint)
6427 6429
6428 6430 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6429 6431
6430 6432 @command('rollback', dryrunopts +
6431 6433 [('f', 'force', False, _('ignore safety measures'))])
6432 6434 def rollback(ui, repo, **opts):
6433 6435 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6434 6436
6435 6437 Please use :hg:`commit --amend` instead of rollback to correct
6436 6438 mistakes in the last commit.
6437 6439
6438 6440 This command should be used with care. There is only one level of
6439 6441 rollback, and there is no way to undo a rollback. It will also
6440 6442 restore the dirstate at the time of the last transaction, losing
6441 6443 any dirstate changes since that time. This command does not alter
6442 6444 the working directory.
6443 6445
6444 6446 Transactions are used to encapsulate the effects of all commands
6445 6447 that create new changesets or propagate existing changesets into a
6446 6448 repository.
6447 6449
6448 6450 .. container:: verbose
6449 6451
6450 6452 For example, the following commands are transactional, and their
6451 6453 effects can be rolled back:
6452 6454
6453 6455 - commit
6454 6456 - import
6455 6457 - pull
6456 6458 - push (with this repository as the destination)
6457 6459 - unbundle
6458 6460
6459 6461 To avoid permanent data loss, rollback will refuse to rollback a
6460 6462 commit transaction if it isn't checked out. Use --force to
6461 6463 override this protection.
6462 6464
6463 6465 The rollback command can be entirely disabled by setting the
6464 6466 ``ui.rollback`` configuration setting to false. If you're here
6465 6467 because you want to use rollback and it's disabled, you can
6466 6468 re-enable the command by setting ``ui.rollback`` to true.
6467 6469
6468 6470 This command is not intended for use on public repositories. Once
6469 6471 changes are visible for pull by other users, rolling a transaction
6470 6472 back locally is ineffective (someone else may already have pulled
6471 6473 the changes). Furthermore, a race is possible with readers of the
6472 6474 repository; for example an in-progress pull from the repository
6473 6475 may fail if a rollback is performed.
6474 6476
6475 6477 Returns 0 on success, 1 if no rollback data is available.
6476 6478 """
6477 6479 if not ui.configbool('ui', 'rollback', True):
6478 6480 raise error.Abort(_('rollback is disabled because it is unsafe'),
6479 6481 hint=('see `hg help -v rollback` for information'))
6480 6482 return repo.rollback(dryrun=opts.get('dry_run'),
6481 6483 force=opts.get('force'))
6482 6484
6483 6485 @command('root', [])
6484 6486 def root(ui, repo):
6485 6487 """print the root (top) of the current working directory
6486 6488
6487 6489 Print the root directory of the current repository.
6488 6490
6489 6491 Returns 0 on success.
6490 6492 """
6491 6493 ui.write(repo.root + "\n")
6492 6494
6493 6495 @command('^serve',
6494 6496 [('A', 'accesslog', '', _('name of access log file to write to'),
6495 6497 _('FILE')),
6496 6498 ('d', 'daemon', None, _('run server in background')),
6497 6499 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6498 6500 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6499 6501 # use string type, then we can check if something was passed
6500 6502 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6501 6503 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6502 6504 _('ADDR')),
6503 6505 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6504 6506 _('PREFIX')),
6505 6507 ('n', 'name', '',
6506 6508 _('name to show in web pages (default: working directory)'), _('NAME')),
6507 6509 ('', 'web-conf', '',
6508 6510 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
6509 6511 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6510 6512 _('FILE')),
6511 6513 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6512 6514 ('', 'stdio', None, _('for remote clients')),
6513 6515 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6514 6516 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6515 6517 ('', 'style', '', _('template style to use'), _('STYLE')),
6516 6518 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6517 6519 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6518 6520 _('[OPTION]...'),
6519 6521 optionalrepo=True)
6520 6522 def serve(ui, repo, **opts):
6521 6523 """start stand-alone webserver
6522 6524
6523 6525 Start a local HTTP repository browser and pull server. You can use
6524 6526 this for ad-hoc sharing and browsing of repositories. It is
6525 6527 recommended to use a real web server to serve a repository for
6526 6528 longer periods of time.
6527 6529
6528 6530 Please note that the server does not implement access control.
6529 6531 This means that, by default, anybody can read from the server and
6530 6532 nobody can write to it by default. Set the ``web.allow_push``
6531 6533 option to ``*`` to allow everybody to push to the server. You
6532 6534 should use a real web server if you need to authenticate users.
6533 6535
6534 6536 By default, the server logs accesses to stdout and errors to
6535 6537 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6536 6538 files.
6537 6539
6538 6540 To have the server choose a free port number to listen on, specify
6539 6541 a port number of 0; in this case, the server will print the port
6540 6542 number it uses.
6541 6543
6542 6544 Returns 0 on success.
6543 6545 """
6544 6546
6545 6547 if opts["stdio"] and opts["cmdserver"]:
6546 6548 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6547 6549
6548 6550 if opts["stdio"]:
6549 6551 if repo is None:
6550 6552 raise error.RepoError(_("there is no Mercurial repository here"
6551 6553 " (.hg not found)"))
6552 6554 s = sshserver.sshserver(ui, repo)
6553 6555 s.serve_forever()
6554 6556
6555 6557 if opts["cmdserver"]:
6556 6558 service = commandserver.createservice(ui, repo, opts)
6557 6559 else:
6558 6560 service = hgweb.createservice(ui, repo, opts)
6559 6561 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6560 6562
6561 6563 @command('^status|st',
6562 6564 [('A', 'all', None, _('show status of all files')),
6563 6565 ('m', 'modified', None, _('show only modified files')),
6564 6566 ('a', 'added', None, _('show only added files')),
6565 6567 ('r', 'removed', None, _('show only removed files')),
6566 6568 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6567 6569 ('c', 'clean', None, _('show only files without changes')),
6568 6570 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6569 6571 ('i', 'ignored', None, _('show only ignored files')),
6570 6572 ('n', 'no-status', None, _('hide status prefix')),
6571 6573 ('C', 'copies', None, _('show source of copied files')),
6572 6574 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6573 6575 ('', 'rev', [], _('show difference from revision'), _('REV')),
6574 6576 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6575 6577 ] + walkopts + subrepoopts + formatteropts,
6576 6578 _('[OPTION]... [FILE]...'),
6577 6579 inferrepo=True)
6578 6580 def status(ui, repo, *pats, **opts):
6579 6581 """show changed files in the working directory
6580 6582
6581 6583 Show status of files in the repository. If names are given, only
6582 6584 files that match are shown. Files that are clean or ignored or
6583 6585 the source of a copy/move operation, are not listed unless
6584 6586 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6585 6587 Unless options described with "show only ..." are given, the
6586 6588 options -mardu are used.
6587 6589
6588 6590 Option -q/--quiet hides untracked (unknown and ignored) files
6589 6591 unless explicitly requested with -u/--unknown or -i/--ignored.
6590 6592
6591 6593 .. note::
6592 6594
6593 6595 :hg:`status` may appear to disagree with diff if permissions have
6594 6596 changed or a merge has occurred. The standard diff format does
6595 6597 not report permission changes and diff only reports changes
6596 6598 relative to one merge parent.
6597 6599
6598 6600 If one revision is given, it is used as the base revision.
6599 6601 If two revisions are given, the differences between them are
6600 6602 shown. The --change option can also be used as a shortcut to list
6601 6603 the changed files of a revision from its first parent.
6602 6604
6603 6605 The codes used to show the status of files are::
6604 6606
6605 6607 M = modified
6606 6608 A = added
6607 6609 R = removed
6608 6610 C = clean
6609 6611 ! = missing (deleted by non-hg command, but still tracked)
6610 6612 ? = not tracked
6611 6613 I = ignored
6612 6614 = origin of the previous file (with --copies)
6613 6615
6614 6616 .. container:: verbose
6615 6617
6616 6618 Examples:
6617 6619
6618 6620 - show changes in the working directory relative to a
6619 6621 changeset::
6620 6622
6621 6623 hg status --rev 9353
6622 6624
6623 6625 - show changes in the working directory relative to the
6624 6626 current directory (see :hg:`help patterns` for more information)::
6625 6627
6626 6628 hg status re:
6627 6629
6628 6630 - show all changes including copies in an existing changeset::
6629 6631
6630 6632 hg status --copies --change 9353
6631 6633
6632 6634 - get a NUL separated list of added files, suitable for xargs::
6633 6635
6634 6636 hg status -an0
6635 6637
6636 6638 Returns 0 on success.
6637 6639 """
6638 6640
6639 6641 revs = opts.get('rev')
6640 6642 change = opts.get('change')
6641 6643
6642 6644 if revs and change:
6643 6645 msg = _('cannot specify --rev and --change at the same time')
6644 6646 raise error.Abort(msg)
6645 6647 elif change:
6646 6648 node2 = scmutil.revsingle(repo, change, None).node()
6647 6649 node1 = repo[node2].p1().node()
6648 6650 else:
6649 6651 node1, node2 = scmutil.revpair(repo, revs)
6650 6652
6651 6653 if pats:
6652 6654 cwd = repo.getcwd()
6653 6655 else:
6654 6656 cwd = ''
6655 6657
6656 6658 if opts.get('print0'):
6657 6659 end = '\0'
6658 6660 else:
6659 6661 end = '\n'
6660 6662 copy = {}
6661 6663 states = 'modified added removed deleted unknown ignored clean'.split()
6662 6664 show = [k for k in states if opts.get(k)]
6663 6665 if opts.get('all'):
6664 6666 show += ui.quiet and (states[:4] + ['clean']) or states
6665 6667 if not show:
6666 6668 if ui.quiet:
6667 6669 show = states[:4]
6668 6670 else:
6669 6671 show = states[:5]
6670 6672
6671 6673 m = scmutil.match(repo[node2], pats, opts)
6672 6674 stat = repo.status(node1, node2, m,
6673 6675 'ignored' in show, 'clean' in show, 'unknown' in show,
6674 6676 opts.get('subrepos'))
6675 6677 changestates = zip(states, 'MAR!?IC', stat)
6676 6678
6677 6679 if (opts.get('all') or opts.get('copies')
6678 6680 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6679 6681 copy = copies.pathcopies(repo[node1], repo[node2], m)
6680 6682
6681 6683 fm = ui.formatter('status', opts)
6682 6684 fmt = '%s' + end
6683 6685 showchar = not opts.get('no_status')
6684 6686
6685 6687 for state, char, files in changestates:
6686 6688 if state in show:
6687 6689 label = 'status.' + state
6688 6690 for f in files:
6689 6691 fm.startitem()
6690 6692 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6691 6693 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6692 6694 if f in copy:
6693 6695 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6694 6696 label='status.copied')
6695 6697 fm.end()
6696 6698
6697 6699 @command('^summary|sum',
6698 6700 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6699 6701 def summary(ui, repo, **opts):
6700 6702 """summarize working directory state
6701 6703
6702 6704 This generates a brief summary of the working directory state,
6703 6705 including parents, branch, commit status, phase and available updates.
6704 6706
6705 6707 With the --remote option, this will check the default paths for
6706 6708 incoming and outgoing changes. This can be time-consuming.
6707 6709
6708 6710 Returns 0 on success.
6709 6711 """
6710 6712
6711 6713 ctx = repo[None]
6712 6714 parents = ctx.parents()
6713 6715 pnode = parents[0].node()
6714 6716 marks = []
6715 6717
6716 6718 ms = None
6717 6719 try:
6718 6720 ms = mergemod.mergestate.read(repo)
6719 6721 except error.UnsupportedMergeRecords as e:
6720 6722 s = ' '.join(e.recordtypes)
6721 6723 ui.warn(
6722 6724 _('warning: merge state has unsupported record types: %s\n') % s)
6723 6725 unresolved = 0
6724 6726 else:
6725 6727 unresolved = [f for f in ms if ms[f] == 'u']
6726 6728
6727 6729 for p in parents:
6728 6730 # label with log.changeset (instead of log.parent) since this
6729 6731 # shows a working directory parent *changeset*:
6730 6732 # i18n: column positioning for "hg summary"
6731 6733 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6732 6734 label='log.changeset changeset.%s' % p.phasestr())
6733 6735 ui.write(' '.join(p.tags()), label='log.tag')
6734 6736 if p.bookmarks():
6735 6737 marks.extend(p.bookmarks())
6736 6738 if p.rev() == -1:
6737 6739 if not len(repo):
6738 6740 ui.write(_(' (empty repository)'))
6739 6741 else:
6740 6742 ui.write(_(' (no revision checked out)'))
6741 6743 ui.write('\n')
6742 6744 if p.description():
6743 6745 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6744 6746 label='log.summary')
6745 6747
6746 6748 branch = ctx.branch()
6747 6749 bheads = repo.branchheads(branch)
6748 6750 # i18n: column positioning for "hg summary"
6749 6751 m = _('branch: %s\n') % branch
6750 6752 if branch != 'default':
6751 6753 ui.write(m, label='log.branch')
6752 6754 else:
6753 6755 ui.status(m, label='log.branch')
6754 6756
6755 6757 if marks:
6756 6758 active = repo._activebookmark
6757 6759 # i18n: column positioning for "hg summary"
6758 6760 ui.write(_('bookmarks:'), label='log.bookmark')
6759 6761 if active is not None:
6760 6762 if active in marks:
6761 6763 ui.write(' *' + active, label=activebookmarklabel)
6762 6764 marks.remove(active)
6763 6765 else:
6764 6766 ui.write(' [%s]' % active, label=activebookmarklabel)
6765 6767 for m in marks:
6766 6768 ui.write(' ' + m, label='log.bookmark')
6767 6769 ui.write('\n', label='log.bookmark')
6768 6770
6769 6771 status = repo.status(unknown=True)
6770 6772
6771 6773 c = repo.dirstate.copies()
6772 6774 copied, renamed = [], []
6773 6775 for d, s in c.iteritems():
6774 6776 if s in status.removed:
6775 6777 status.removed.remove(s)
6776 6778 renamed.append(d)
6777 6779 else:
6778 6780 copied.append(d)
6779 6781 if d in status.added:
6780 6782 status.added.remove(d)
6781 6783
6782 6784 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6783 6785
6784 6786 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6785 6787 (ui.label(_('%d added'), 'status.added'), status.added),
6786 6788 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6787 6789 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6788 6790 (ui.label(_('%d copied'), 'status.copied'), copied),
6789 6791 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6790 6792 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6791 6793 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6792 6794 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6793 6795 t = []
6794 6796 for l, s in labels:
6795 6797 if s:
6796 6798 t.append(l % len(s))
6797 6799
6798 6800 t = ', '.join(t)
6799 6801 cleanworkdir = False
6800 6802
6801 6803 if repo.vfs.exists('graftstate'):
6802 6804 t += _(' (graft in progress)')
6803 6805 if repo.vfs.exists('updatestate'):
6804 6806 t += _(' (interrupted update)')
6805 6807 elif len(parents) > 1:
6806 6808 t += _(' (merge)')
6807 6809 elif branch != parents[0].branch():
6808 6810 t += _(' (new branch)')
6809 6811 elif (parents[0].closesbranch() and
6810 6812 pnode in repo.branchheads(branch, closed=True)):
6811 6813 t += _(' (head closed)')
6812 6814 elif not (status.modified or status.added or status.removed or renamed or
6813 6815 copied or subs):
6814 6816 t += _(' (clean)')
6815 6817 cleanworkdir = True
6816 6818 elif pnode not in bheads:
6817 6819 t += _(' (new branch head)')
6818 6820
6819 6821 if parents:
6820 6822 pendingphase = max(p.phase() for p in parents)
6821 6823 else:
6822 6824 pendingphase = phases.public
6823 6825
6824 6826 if pendingphase > phases.newcommitphase(ui):
6825 6827 t += ' (%s)' % phases.phasenames[pendingphase]
6826 6828
6827 6829 if cleanworkdir:
6828 6830 # i18n: column positioning for "hg summary"
6829 6831 ui.status(_('commit: %s\n') % t.strip())
6830 6832 else:
6831 6833 # i18n: column positioning for "hg summary"
6832 6834 ui.write(_('commit: %s\n') % t.strip())
6833 6835
6834 6836 # all ancestors of branch heads - all ancestors of parent = new csets
6835 6837 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6836 6838 bheads))
6837 6839
6838 6840 if new == 0:
6839 6841 # i18n: column positioning for "hg summary"
6840 6842 ui.status(_('update: (current)\n'))
6841 6843 elif pnode not in bheads:
6842 6844 # i18n: column positioning for "hg summary"
6843 6845 ui.write(_('update: %d new changesets (update)\n') % new)
6844 6846 else:
6845 6847 # i18n: column positioning for "hg summary"
6846 6848 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6847 6849 (new, len(bheads)))
6848 6850
6849 6851 t = []
6850 6852 draft = len(repo.revs('draft()'))
6851 6853 if draft:
6852 6854 t.append(_('%d draft') % draft)
6853 6855 secret = len(repo.revs('secret()'))
6854 6856 if secret:
6855 6857 t.append(_('%d secret') % secret)
6856 6858
6857 6859 if draft or secret:
6858 6860 ui.status(_('phases: %s\n') % ', '.join(t))
6859 6861
6860 6862 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6861 6863 for trouble in ("unstable", "divergent", "bumped"):
6862 6864 numtrouble = len(repo.revs(trouble + "()"))
6863 6865 # We write all the possibilities to ease translation
6864 6866 troublemsg = {
6865 6867 "unstable": _("unstable: %d changesets"),
6866 6868 "divergent": _("divergent: %d changesets"),
6867 6869 "bumped": _("bumped: %d changesets"),
6868 6870 }
6869 6871 if numtrouble > 0:
6870 6872 ui.status(troublemsg[trouble] % numtrouble + "\n")
6871 6873
6872 6874 cmdutil.summaryhooks(ui, repo)
6873 6875
6874 6876 if opts.get('remote'):
6875 6877 needsincoming, needsoutgoing = True, True
6876 6878 else:
6877 6879 needsincoming, needsoutgoing = False, False
6878 6880 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6879 6881 if i:
6880 6882 needsincoming = True
6881 6883 if o:
6882 6884 needsoutgoing = True
6883 6885 if not needsincoming and not needsoutgoing:
6884 6886 return
6885 6887
6886 6888 def getincoming():
6887 6889 source, branches = hg.parseurl(ui.expandpath('default'))
6888 6890 sbranch = branches[0]
6889 6891 try:
6890 6892 other = hg.peer(repo, {}, source)
6891 6893 except error.RepoError:
6892 6894 if opts.get('remote'):
6893 6895 raise
6894 6896 return source, sbranch, None, None, None
6895 6897 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6896 6898 if revs:
6897 6899 revs = [other.lookup(rev) for rev in revs]
6898 6900 ui.debug('comparing with %s\n' % util.hidepassword(source))
6899 6901 repo.ui.pushbuffer()
6900 6902 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6901 6903 repo.ui.popbuffer()
6902 6904 return source, sbranch, other, commoninc, commoninc[1]
6903 6905
6904 6906 if needsincoming:
6905 6907 source, sbranch, sother, commoninc, incoming = getincoming()
6906 6908 else:
6907 6909 source = sbranch = sother = commoninc = incoming = None
6908 6910
6909 6911 def getoutgoing():
6910 6912 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6911 6913 dbranch = branches[0]
6912 6914 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6913 6915 if source != dest:
6914 6916 try:
6915 6917 dother = hg.peer(repo, {}, dest)
6916 6918 except error.RepoError:
6917 6919 if opts.get('remote'):
6918 6920 raise
6919 6921 return dest, dbranch, None, None
6920 6922 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6921 6923 elif sother is None:
6922 6924 # there is no explicit destination peer, but source one is invalid
6923 6925 return dest, dbranch, None, None
6924 6926 else:
6925 6927 dother = sother
6926 6928 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6927 6929 common = None
6928 6930 else:
6929 6931 common = commoninc
6930 6932 if revs:
6931 6933 revs = [repo.lookup(rev) for rev in revs]
6932 6934 repo.ui.pushbuffer()
6933 6935 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6934 6936 commoninc=common)
6935 6937 repo.ui.popbuffer()
6936 6938 return dest, dbranch, dother, outgoing
6937 6939
6938 6940 if needsoutgoing:
6939 6941 dest, dbranch, dother, outgoing = getoutgoing()
6940 6942 else:
6941 6943 dest = dbranch = dother = outgoing = None
6942 6944
6943 6945 if opts.get('remote'):
6944 6946 t = []
6945 6947 if incoming:
6946 6948 t.append(_('1 or more incoming'))
6947 6949 o = outgoing.missing
6948 6950 if o:
6949 6951 t.append(_('%d outgoing') % len(o))
6950 6952 other = dother or sother
6951 6953 if 'bookmarks' in other.listkeys('namespaces'):
6952 6954 counts = bookmarks.summary(repo, other)
6953 6955 if counts[0] > 0:
6954 6956 t.append(_('%d incoming bookmarks') % counts[0])
6955 6957 if counts[1] > 0:
6956 6958 t.append(_('%d outgoing bookmarks') % counts[1])
6957 6959
6958 6960 if t:
6959 6961 # i18n: column positioning for "hg summary"
6960 6962 ui.write(_('remote: %s\n') % (', '.join(t)))
6961 6963 else:
6962 6964 # i18n: column positioning for "hg summary"
6963 6965 ui.status(_('remote: (synced)\n'))
6964 6966
6965 6967 cmdutil.summaryremotehooks(ui, repo, opts,
6966 6968 ((source, sbranch, sother, commoninc),
6967 6969 (dest, dbranch, dother, outgoing)))
6968 6970
6969 6971 @command('tag',
6970 6972 [('f', 'force', None, _('force tag')),
6971 6973 ('l', 'local', None, _('make the tag local')),
6972 6974 ('r', 'rev', '', _('revision to tag'), _('REV')),
6973 6975 ('', 'remove', None, _('remove a tag')),
6974 6976 # -l/--local is already there, commitopts cannot be used
6975 6977 ('e', 'edit', None, _('invoke editor on commit messages')),
6976 6978 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6977 6979 ] + commitopts2,
6978 6980 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6979 6981 def tag(ui, repo, name1, *names, **opts):
6980 6982 """add one or more tags for the current or given revision
6981 6983
6982 6984 Name a particular revision using <name>.
6983 6985
6984 6986 Tags are used to name particular revisions of the repository and are
6985 6987 very useful to compare different revisions, to go back to significant
6986 6988 earlier versions or to mark branch points as releases, etc. Changing
6987 6989 an existing tag is normally disallowed; use -f/--force to override.
6988 6990
6989 6991 If no revision is given, the parent of the working directory is
6990 6992 used.
6991 6993
6992 6994 To facilitate version control, distribution, and merging of tags,
6993 6995 they are stored as a file named ".hgtags" which is managed similarly
6994 6996 to other project files and can be hand-edited if necessary. This
6995 6997 also means that tagging creates a new commit. The file
6996 6998 ".hg/localtags" is used for local tags (not shared among
6997 6999 repositories).
6998 7000
6999 7001 Tag commits are usually made at the head of a branch. If the parent
7000 7002 of the working directory is not a branch head, :hg:`tag` aborts; use
7001 7003 -f/--force to force the tag commit to be based on a non-head
7002 7004 changeset.
7003 7005
7004 7006 See :hg:`help dates` for a list of formats valid for -d/--date.
7005 7007
7006 7008 Since tag names have priority over branch names during revision
7007 7009 lookup, using an existing branch name as a tag name is discouraged.
7008 7010
7009 7011 Returns 0 on success.
7010 7012 """
7011 7013 wlock = lock = None
7012 7014 try:
7013 7015 wlock = repo.wlock()
7014 7016 lock = repo.lock()
7015 7017 rev_ = "."
7016 7018 names = [t.strip() for t in (name1,) + names]
7017 7019 if len(names) != len(set(names)):
7018 7020 raise error.Abort(_('tag names must be unique'))
7019 7021 for n in names:
7020 7022 scmutil.checknewlabel(repo, n, 'tag')
7021 7023 if not n:
7022 7024 raise error.Abort(_('tag names cannot consist entirely of '
7023 7025 'whitespace'))
7024 7026 if opts.get('rev') and opts.get('remove'):
7025 7027 raise error.Abort(_("--rev and --remove are incompatible"))
7026 7028 if opts.get('rev'):
7027 7029 rev_ = opts['rev']
7028 7030 message = opts.get('message')
7029 7031 if opts.get('remove'):
7030 7032 if opts.get('local'):
7031 7033 expectedtype = 'local'
7032 7034 else:
7033 7035 expectedtype = 'global'
7034 7036
7035 7037 for n in names:
7036 7038 if not repo.tagtype(n):
7037 7039 raise error.Abort(_("tag '%s' does not exist") % n)
7038 7040 if repo.tagtype(n) != expectedtype:
7039 7041 if expectedtype == 'global':
7040 7042 raise error.Abort(_("tag '%s' is not a global tag") % n)
7041 7043 else:
7042 7044 raise error.Abort(_("tag '%s' is not a local tag") % n)
7043 7045 rev_ = 'null'
7044 7046 if not message:
7045 7047 # we don't translate commit messages
7046 7048 message = 'Removed tag %s' % ', '.join(names)
7047 7049 elif not opts.get('force'):
7048 7050 for n in names:
7049 7051 if n in repo.tags():
7050 7052 raise error.Abort(_("tag '%s' already exists "
7051 7053 "(use -f to force)") % n)
7052 7054 if not opts.get('local'):
7053 7055 p1, p2 = repo.dirstate.parents()
7054 7056 if p2 != nullid:
7055 7057 raise error.Abort(_('uncommitted merge'))
7056 7058 bheads = repo.branchheads()
7057 7059 if not opts.get('force') and bheads and p1 not in bheads:
7058 7060 raise error.Abort(_('not at a branch head (use -f to force)'))
7059 7061 r = scmutil.revsingle(repo, rev_).node()
7060 7062
7061 7063 if not message:
7062 7064 # we don't translate commit messages
7063 7065 message = ('Added tag %s for changeset %s' %
7064 7066 (', '.join(names), short(r)))
7065 7067
7066 7068 date = opts.get('date')
7067 7069 if date:
7068 7070 date = util.parsedate(date)
7069 7071
7070 7072 if opts.get('remove'):
7071 7073 editform = 'tag.remove'
7072 7074 else:
7073 7075 editform = 'tag.add'
7074 7076 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7075 7077
7076 7078 # don't allow tagging the null rev
7077 7079 if (not opts.get('remove') and
7078 7080 scmutil.revsingle(repo, rev_).rev() == nullrev):
7079 7081 raise error.Abort(_("cannot tag null revision"))
7080 7082
7081 7083 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
7082 7084 editor=editor)
7083 7085 finally:
7084 7086 release(lock, wlock)
7085 7087
7086 7088 @command('tags', formatteropts, '')
7087 7089 def tags(ui, repo, **opts):
7088 7090 """list repository tags
7089 7091
7090 7092 This lists both regular and local tags. When the -v/--verbose
7091 7093 switch is used, a third column "local" is printed for local tags.
7092 7094 When the -q/--quiet switch is used, only the tag name is printed.
7093 7095
7094 7096 Returns 0 on success.
7095 7097 """
7096 7098
7097 7099 fm = ui.formatter('tags', opts)
7098 7100 hexfunc = fm.hexfunc
7099 7101 tagtype = ""
7100 7102
7101 7103 for t, n in reversed(repo.tagslist()):
7102 7104 hn = hexfunc(n)
7103 7105 label = 'tags.normal'
7104 7106 tagtype = ''
7105 7107 if repo.tagtype(t) == 'local':
7106 7108 label = 'tags.local'
7107 7109 tagtype = 'local'
7108 7110
7109 7111 fm.startitem()
7110 7112 fm.write('tag', '%s', t, label=label)
7111 7113 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7112 7114 fm.condwrite(not ui.quiet, 'rev node', fmt,
7113 7115 repo.changelog.rev(n), hn, label=label)
7114 7116 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7115 7117 tagtype, label=label)
7116 7118 fm.plain('\n')
7117 7119 fm.end()
7118 7120
7119 7121 @command('tip',
7120 7122 [('p', 'patch', None, _('show patch')),
7121 7123 ('g', 'git', None, _('use git extended diff format')),
7122 7124 ] + templateopts,
7123 7125 _('[-p] [-g]'))
7124 7126 def tip(ui, repo, **opts):
7125 7127 """show the tip revision (DEPRECATED)
7126 7128
7127 7129 The tip revision (usually just called the tip) is the changeset
7128 7130 most recently added to the repository (and therefore the most
7129 7131 recently changed head).
7130 7132
7131 7133 If you have just made a commit, that commit will be the tip. If
7132 7134 you have just pulled changes from another repository, the tip of
7133 7135 that repository becomes the current tip. The "tip" tag is special
7134 7136 and cannot be renamed or assigned to a different changeset.
7135 7137
7136 7138 This command is deprecated, please use :hg:`heads` instead.
7137 7139
7138 7140 Returns 0 on success.
7139 7141 """
7140 7142 displayer = cmdutil.show_changeset(ui, repo, opts)
7141 7143 displayer.show(repo['tip'])
7142 7144 displayer.close()
7143 7145
7144 7146 @command('unbundle',
7145 7147 [('u', 'update', None,
7146 7148 _('update to new branch head if changesets were unbundled'))],
7147 7149 _('[-u] FILE...'))
7148 7150 def unbundle(ui, repo, fname1, *fnames, **opts):
7149 7151 """apply one or more changegroup files
7150 7152
7151 7153 Apply one or more compressed changegroup files generated by the
7152 7154 bundle command.
7153 7155
7154 7156 Returns 0 on success, 1 if an update has unresolved files.
7155 7157 """
7156 7158 fnames = (fname1,) + fnames
7157 7159
7158 7160 with repo.lock():
7159 7161 for fname in fnames:
7160 7162 f = hg.openpath(ui, fname)
7161 7163 gen = exchange.readbundle(ui, f, fname)
7162 7164 if isinstance(gen, bundle2.unbundle20):
7163 7165 tr = repo.transaction('unbundle')
7164 7166 try:
7165 7167 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7166 7168 url='bundle:' + fname)
7167 7169 tr.close()
7168 7170 except error.BundleUnknownFeatureError as exc:
7169 7171 raise error.Abort(_('%s: unknown bundle feature, %s')
7170 7172 % (fname, exc),
7171 7173 hint=_("see https://mercurial-scm.org/"
7172 7174 "wiki/BundleFeature for more "
7173 7175 "information"))
7174 7176 finally:
7175 7177 if tr:
7176 7178 tr.release()
7177 7179 changes = [r.get('return', 0)
7178 7180 for r in op.records['changegroup']]
7179 7181 modheads = changegroup.combineresults(changes)
7180 7182 elif isinstance(gen, streamclone.streamcloneapplier):
7181 7183 raise error.Abort(
7182 7184 _('packed bundles cannot be applied with '
7183 7185 '"hg unbundle"'),
7184 7186 hint=_('use "hg debugapplystreamclonebundle"'))
7185 7187 else:
7186 7188 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7187 7189
7188 7190 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7189 7191
7190 7192 @command('^update|up|checkout|co',
7191 7193 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7192 7194 ('c', 'check', None, _('require clean working directory')),
7193 7195 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7194 7196 ('r', 'rev', '', _('revision'), _('REV'))
7195 7197 ] + mergetoolopts,
7196 7198 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7197 7199 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7198 7200 tool=None):
7199 7201 """update working directory (or switch revisions)
7200 7202
7201 7203 Update the repository's working directory to the specified
7202 7204 changeset. If no changeset is specified, update to the tip of the
7203 7205 current named branch and move the active bookmark (see :hg:`help
7204 7206 bookmarks`).
7205 7207
7206 7208 Update sets the working directory's parent revision to the specified
7207 7209 changeset (see :hg:`help parents`).
7208 7210
7209 7211 If the changeset is not a descendant or ancestor of the working
7210 7212 directory's parent, the update is aborted. With the -c/--check
7211 7213 option, the working directory is checked for uncommitted changes; if
7212 7214 none are found, the working directory is updated to the specified
7213 7215 changeset.
7214 7216
7215 7217 .. container:: verbose
7216 7218
7217 7219 The following rules apply when the working directory contains
7218 7220 uncommitted changes:
7219 7221
7220 7222 1. If neither -c/--check nor -C/--clean is specified, and if
7221 7223 the requested changeset is an ancestor or descendant of
7222 7224 the working directory's parent, the uncommitted changes
7223 7225 are merged into the requested changeset and the merged
7224 7226 result is left uncommitted. If the requested changeset is
7225 7227 not an ancestor or descendant (that is, it is on another
7226 7228 branch), the update is aborted and the uncommitted changes
7227 7229 are preserved.
7228 7230
7229 7231 2. With the -c/--check option, the update is aborted and the
7230 7232 uncommitted changes are preserved.
7231 7233
7232 7234 3. With the -C/--clean option, uncommitted changes are discarded and
7233 7235 the working directory is updated to the requested changeset.
7234 7236
7235 7237 To cancel an uncommitted merge (and lose your changes), use
7236 7238 :hg:`update --clean .`.
7237 7239
7238 7240 Use null as the changeset to remove the working directory (like
7239 7241 :hg:`clone -U`).
7240 7242
7241 7243 If you want to revert just one file to an older revision, use
7242 7244 :hg:`revert [-r REV] NAME`.
7243 7245
7244 7246 See :hg:`help dates` for a list of formats valid for -d/--date.
7245 7247
7246 7248 Returns 0 on success, 1 if there are unresolved files.
7247 7249 """
7248 7250 if rev and node:
7249 7251 raise error.Abort(_("please specify just one revision"))
7250 7252
7251 7253 if rev is None or rev == '':
7252 7254 rev = node
7253 7255
7254 7256 if date and rev is not None:
7255 7257 raise error.Abort(_("you can't specify a revision and a date"))
7256 7258
7257 7259 if check and clean:
7258 7260 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7259 7261
7260 7262 with repo.wlock():
7261 7263 cmdutil.clearunfinished(repo)
7262 7264
7263 7265 if date:
7264 7266 rev = cmdutil.finddate(ui, repo, date)
7265 7267
7266 7268 # if we defined a bookmark, we have to remember the original name
7267 7269 brev = rev
7268 7270 rev = scmutil.revsingle(repo, rev, rev).rev()
7269 7271
7270 7272 if check:
7271 7273 cmdutil.bailifchanged(repo, merge=False)
7272 7274
7273 7275 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7274 7276
7275 7277 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7276 7278
7277 7279 @command('verify', [])
7278 7280 def verify(ui, repo):
7279 7281 """verify the integrity of the repository
7280 7282
7281 7283 Verify the integrity of the current repository.
7282 7284
7283 7285 This will perform an extensive check of the repository's
7284 7286 integrity, validating the hashes and checksums of each entry in
7285 7287 the changelog, manifest, and tracked files, as well as the
7286 7288 integrity of their crosslinks and indices.
7287 7289
7288 7290 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7289 7291 for more information about recovery from corruption of the
7290 7292 repository.
7291 7293
7292 7294 Returns 0 on success, 1 if errors are encountered.
7293 7295 """
7294 7296 return hg.verify(repo)
7295 7297
7296 7298 @command('version', [] + formatteropts, norepo=True)
7297 7299 def version_(ui, **opts):
7298 7300 """output version and copyright information"""
7299 7301 fm = ui.formatter("version", opts)
7300 7302 fm.startitem()
7301 7303 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
7302 7304 util.version())
7303 7305 license = _(
7304 7306 "(see https://mercurial-scm.org for more information)\n"
7305 7307 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7306 7308 "This is free software; see the source for copying conditions. "
7307 7309 "There is NO\nwarranty; "
7308 7310 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7309 7311 )
7310 7312 if not ui.quiet:
7311 7313 fm.plain(license)
7312 7314
7313 7315 if ui.verbose:
7314 7316 fm.plain(_("\nEnabled extensions:\n\n"))
7315 7317 # format names and versions into columns
7316 7318 names = []
7317 7319 vers = []
7318 7320 isinternals = []
7319 7321 for name, module in extensions.extensions():
7320 7322 names.append(name)
7321 7323 vers.append(extensions.moduleversion(module) or None)
7322 7324 isinternals.append(extensions.ismoduleinternal(module))
7323 7325 fn = fm.nested("extensions")
7324 7326 if names:
7325 7327 namefmt = " %%-%ds " % max(len(n) for n in names)
7326 7328 places = [_("external"), _("internal")]
7327 7329 for n, v, p in zip(names, vers, isinternals):
7328 7330 fn.startitem()
7329 7331 fn.condwrite(ui.verbose, "name", namefmt, n)
7330 7332 if ui.verbose:
7331 7333 fn.plain("%s " % places[p])
7332 7334 fn.data(bundled=p)
7333 7335 fn.condwrite(ui.verbose and v, "ver", "%s", v)
7334 7336 if ui.verbose:
7335 7337 fn.plain("\n")
7336 7338 fn.end()
7337 7339 fm.end()
7338 7340
7339 7341 def loadcmdtable(ui, name, cmdtable):
7340 7342 """Load command functions from specified cmdtable
7341 7343 """
7342 7344 overrides = [cmd for cmd in cmdtable if cmd in table]
7343 7345 if overrides:
7344 7346 ui.warn(_("extension '%s' overrides commands: %s\n")
7345 7347 % (name, " ".join(overrides)))
7346 7348 table.update(cmdtable)
@@ -1,403 +1,405 b''
1 1 Set up a repo
2 2
3 3 $ cp $HGRCPATH $HGRCPATH.pretest
4 4 $ cat <<EOF >> $HGRCPATH
5 5 > [ui]
6 6 > interactive = true
7 7 > interface = curses
8 8 > [experimental]
9 9 > crecordtest = testModeCommands
10 10 > EOF
11 11
12 12 Record with noeol at eof (issue5268)
13 13 $ hg init noeol
14 14 $ cd noeol
15 15 $ printf '0' > a
16 16 $ printf '0\n' > b
17 17 $ hg ci -Aqm initial
18 18 $ printf '1\n0' > a
19 19 $ printf '1\n0\n' > b
20 20 $ cat <<EOF >testModeCommands
21 21 > c
22 22 > EOF
23 23 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i -m "add hunks" -d "0 0"
24 24 $ cd ..
25 25
26 26 Normal repo
27 27 $ hg init a
28 28 $ cd a
29 29
30 30 Committing some changes but stopping on the way
31 31
32 32 $ echo "a" > a
33 33 $ hg add a
34 34 $ cat <<EOF >testModeCommands
35 35 > TOGGLE
36 36 > X
37 37 > EOF
38 38 $ hg commit -i -m "a" -d "0 0"
39 39 no changes to record
40 [1]
40 41 $ hg tip
41 42 changeset: -1:000000000000
42 43 tag: tip
43 44 user:
44 45 date: Thu Jan 01 00:00:00 1970 +0000
45 46
46 47
47 48 Committing some changes
48 49
49 50 $ cat <<EOF >testModeCommands
50 51 > X
51 52 > EOF
52 53 $ hg commit -i -m "a" -d "0 0"
53 54 $ hg tip
54 55 changeset: 0:cb9a9f314b8b
55 56 tag: tip
56 57 user: test
57 58 date: Thu Jan 01 00:00:00 1970 +0000
58 59 summary: a
59 60
60 61 Check that commit -i works with no changes
61 62 $ hg commit -i
62 63 no changes to record
64 [1]
63 65
64 66 Committing only one file
65 67
66 68 $ echo "a" >> a
67 69 >>> open('b', 'wb').write("1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n")
68 70 $ hg add b
69 71 $ cat <<EOF >testModeCommands
70 72 > TOGGLE
71 73 > KEY_DOWN
72 74 > X
73 75 > EOF
74 76 $ hg commit -i -m "one file" -d "0 0"
75 77 $ hg tip
76 78 changeset: 1:fb2705a663ea
77 79 tag: tip
78 80 user: test
79 81 date: Thu Jan 01 00:00:00 1970 +0000
80 82 summary: one file
81 83
82 84 $ hg cat -r tip a
83 85 a
84 86 $ cat a
85 87 a
86 88 a
87 89
88 90 Committing only one hunk while aborting edition of hunk
89 91
90 92 - Untoggle all the hunks, go down to the second file
91 93 - unfold it
92 94 - go down to second hunk (1 for the first hunk, 1 for the first hunkline, 1 for the second hunk, 1 for the second hunklike)
93 95 - toggle the second hunk
94 96 - toggle on and off the amend mode (to check that it toggles off)
95 97 - edit the hunk and quit the editor immediately with non-zero status
96 98 - commit
97 99
98 100 $ printf "printf 'editor ran\n'; exit 1" > editor.sh
99 101 $ echo "x" > c
100 102 $ cat b >> c
101 103 $ echo "y" >> c
102 104 $ mv c b
103 105 $ cat <<EOF >testModeCommands
104 106 > A
105 107 > KEY_DOWN
106 108 > f
107 109 > KEY_DOWN
108 110 > KEY_DOWN
109 111 > KEY_DOWN
110 112 > KEY_DOWN
111 113 > TOGGLE
112 114 > a
113 115 > a
114 116 > e
115 117 > X
116 118 > EOF
117 119 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i -m "one hunk" -d "0 0"
118 120 editor ran
119 121 $ rm editor.sh
120 122 $ hg tip
121 123 changeset: 2:7d10dfe755a8
122 124 tag: tip
123 125 user: test
124 126 date: Thu Jan 01 00:00:00 1970 +0000
125 127 summary: one hunk
126 128
127 129 $ hg cat -r tip b
128 130 1
129 131 2
130 132 3
131 133 4
132 134 5
133 135 6
134 136 7
135 137 8
136 138 9
137 139 10
138 140 y
139 141 $ cat b
140 142 x
141 143 1
142 144 2
143 145 3
144 146 4
145 147 5
146 148 6
147 149 7
148 150 8
149 151 9
150 152 10
151 153 y
152 154 $ hg commit -m "other hunks"
153 155 $ hg tip
154 156 changeset: 3:a6735021574d
155 157 tag: tip
156 158 user: test
157 159 date: Thu Jan 01 00:00:00 1970 +0000
158 160 summary: other hunks
159 161
160 162 $ hg cat -r tip b
161 163 x
162 164 1
163 165 2
164 166 3
165 167 4
166 168 5
167 169 6
168 170 7
169 171 8
170 172 9
171 173 10
172 174 y
173 175
174 176 Newly added files can be selected with the curses interface
175 177
176 178 $ hg update -C .
177 179 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
178 180 $ echo "hello" > x
179 181 $ hg add x
180 182 $ cat <<EOF >testModeCommands
181 183 > TOGGLE
182 184 > TOGGLE
183 185 > X
184 186 > EOF
185 187 $ hg st
186 188 A x
187 189 ? testModeCommands
188 190 $ hg commit -i -m "newly added file" -d "0 0"
189 191 $ hg st
190 192 ? testModeCommands
191 193
192 194 Amend option works
193 195 $ echo "hello world" > x
194 196 $ hg diff -c .
195 197 diff -r a6735021574d -r 2b0e9be4d336 x
196 198 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
197 199 +++ b/x Thu Jan 01 00:00:00 1970 +0000
198 200 @@ -0,0 +1,1 @@
199 201 +hello
200 202 $ cat <<EOF >testModeCommands
201 203 > a
202 204 > X
203 205 > EOF
204 206 $ hg commit -i -m "newly added file" -d "0 0"
205 207 saved backup bundle to $TESTTMP/a/.hg/strip-backup/2b0e9be4d336-28bbe4e2-amend-backup.hg (glob)
206 208 $ hg diff -c .
207 209 diff -r a6735021574d -r c1d239d165ae x
208 210 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
209 211 +++ b/x Thu Jan 01 00:00:00 1970 +0000
210 212 @@ -0,0 +1,1 @@
211 213 +hello world
212 214
213 215 Editing a hunk puts you back on that hunk when done editing (issue5041)
214 216 To do that, we change two lines in a file, pretend to edit the second line,
215 217 exit, toggle the line selected at the end of the edit and commit.
216 218 The first line should be recorded if we were put on the second line at the end
217 219 of the edit.
218 220
219 221 $ hg update -C .
220 222 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
221 223 $ echo "foo" > x
222 224 $ echo "hello world" >> x
223 225 $ echo "bar" >> x
224 226 $ cat <<EOF >testModeCommands
225 227 > f
226 228 > KEY_DOWN
227 229 > KEY_DOWN
228 230 > KEY_DOWN
229 231 > KEY_DOWN
230 232 > e
231 233 > TOGGLE
232 234 > X
233 235 > EOF
234 236 $ printf "printf 'editor ran\n'; exit 0" > editor.sh
235 237 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i -m "edit hunk" -d "0 0"
236 238 editor ran
237 239 $ hg cat -r . x
238 240 foo
239 241 hello world
240 242
241 243 Testing the review option. The entire final filtered patch should show
242 244 up in the editor and be editable. We will unselect the second file and
243 245 the first hunk of the third file. During review, we will decide that
244 246 "lower" sounds better than "bottom", and the final commit should
245 247 reflect this edition.
246 248
247 249 $ hg update -C .
248 250 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
249 251 $ echo "top" > c
250 252 $ cat x >> c
251 253 $ echo "bottom" >> c
252 254 $ mv c x
253 255 $ echo "third a" >> a
254 256 $ echo "we will unselect this" >> b
255 257
256 258 $ cat > editor.sh <<EOF
257 259 > cat "\$1"
258 260 > cat "\$1" | sed s/bottom/lower/ > tmp
259 261 > mv tmp "\$1"
260 262 > EOF
261 263 $ cat > testModeCommands <<EOF
262 264 > KEY_DOWN
263 265 > TOGGLE
264 266 > KEY_DOWN
265 267 > f
266 268 > KEY_DOWN
267 269 > TOGGLE
268 270 > R
269 271 > EOF
270 272
271 273 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i -m "review hunks" -d "0 0"
272 274 # To remove '-' lines, make them ' ' lines (context).
273 275 # To remove '+' lines, delete them.
274 276 # Lines starting with # will be removed from the patch.
275 277 #
276 278 # If the patch applies cleanly, the edited patch will immediately
277 279 # be finalised. If it does not apply cleanly, rejects files will be
278 280 # generated. You can use those when you try again.
279 281 diff --git a/a b/a
280 282 --- a/a
281 283 +++ b/a
282 284 @@ -1,2 +1,3 @@
283 285 a
284 286 a
285 287 +third a
286 288 diff --git a/x b/x
287 289 --- a/x
288 290 +++ b/x
289 291 @@ -1,2 +1,3 @@
290 292 foo
291 293 hello world
292 294 +bottom
293 295
294 296 $ hg cat -r . a
295 297 a
296 298 a
297 299 third a
298 300
299 301 $ hg cat -r . b
300 302 x
301 303 1
302 304 2
303 305 3
304 306 4
305 307 5
306 308 6
307 309 7
308 310 8
309 311 9
310 312 10
311 313 y
312 314
313 315 $ hg cat -r . x
314 316 foo
315 317 hello world
316 318 lower
317 319 Check ui.interface logic for the chunkselector
318 320
319 321 The default interface is text
320 322 $ cp $HGRCPATH.pretest $HGRCPATH
321 323 $ chunkselectorinterface() {
322 324 > python <<EOF
323 325 > from mercurial import hg, ui, parsers;\
324 326 > repo = hg.repository(ui.ui(), ".");\
325 327 > print repo.ui.interface("chunkselector")
326 328 > EOF
327 329 > }
328 330 $ chunkselectorinterface
329 331 text
330 332
331 333 If only the default is set, we'll use that for the feature, too
332 334 $ cp $HGRCPATH.pretest $HGRCPATH
333 335 $ cat <<EOF >> $HGRCPATH
334 336 > [ui]
335 337 > interface = curses
336 338 > EOF
337 339 $ chunkselectorinterface
338 340 curses
339 341
340 342 It is possible to override the default interface with a feature specific
341 343 interface
342 344 $ cp $HGRCPATH.pretest $HGRCPATH
343 345 $ cat <<EOF >> $HGRCPATH
344 346 > [ui]
345 347 > interface = text
346 348 > interface.chunkselector = curses
347 349 > EOF
348 350
349 351 $ chunkselectorinterface
350 352 curses
351 353
352 354 $ cp $HGRCPATH.pretest $HGRCPATH
353 355 $ cat <<EOF >> $HGRCPATH
354 356 > [ui]
355 357 > interface = curses
356 358 > interface.chunkselector = text
357 359 > EOF
358 360
359 361 $ chunkselectorinterface
360 362 text
361 363
362 364 If a bad interface name is given, we use the default value (with a nice
363 365 error message to suggest that the configuration needs to be fixed)
364 366
365 367 $ cp $HGRCPATH.pretest $HGRCPATH
366 368 $ cat <<EOF >> $HGRCPATH
367 369 > [ui]
368 370 > interface = blah
369 371 > EOF
370 372 $ chunkselectorinterface
371 373 invalid value for ui.interface: blah (using text)
372 374 text
373 375
374 376 $ cp $HGRCPATH.pretest $HGRCPATH
375 377 $ cat <<EOF >> $HGRCPATH
376 378 > [ui]
377 379 > interface = curses
378 380 > interface.chunkselector = blah
379 381 > EOF
380 382 $ chunkselectorinterface
381 383 invalid value for ui.interface.chunkselector: blah (using curses)
382 384 curses
383 385
384 386 $ cp $HGRCPATH.pretest $HGRCPATH
385 387 $ cat <<EOF >> $HGRCPATH
386 388 > [ui]
387 389 > interface = blah
388 390 > interface.chunkselector = curses
389 391 > EOF
390 392 $ chunkselectorinterface
391 393 invalid value for ui.interface: blah
392 394 curses
393 395
394 396 $ cp $HGRCPATH.pretest $HGRCPATH
395 397 $ cat <<EOF >> $HGRCPATH
396 398 > [ui]
397 399 > interface = blah
398 400 > interface.chunkselector = blah
399 401 > EOF
400 402 $ chunkselectorinterface
401 403 invalid value for ui.interface: blah
402 404 invalid value for ui.interface.chunkselector: blah (using text)
403 405 text
@@ -1,1800 +1,1803 b''
1 1 Set up a repo
2 2
3 3 $ cat <<EOF >> $HGRCPATH
4 4 > [ui]
5 5 > interactive = true
6 6 > [extensions]
7 7 > record =
8 8 > EOF
9 9
10 10 $ hg init a
11 11 $ cd a
12 12
13 13 Select no files
14 14
15 15 $ touch empty-rw
16 16 $ hg add empty-rw
17 17
18 18 $ hg record --config ui.interactive=false
19 19 abort: running non-interactively, use commit instead
20 20 [255]
21 21 $ hg commit -i --config ui.interactive=false
22 22 abort: running non-interactively
23 23 [255]
24 24 $ hg commit -i empty-rw<<EOF
25 25 > n
26 26 > EOF
27 27 diff --git a/empty-rw b/empty-rw
28 28 new file mode 100644
29 29 examine changes to 'empty-rw'? [Ynesfdaq?] n
30 30
31 31 no changes to record
32 [1]
32 33
33 34 $ hg tip -p
34 35 changeset: -1:000000000000
35 36 tag: tip
36 37 user:
37 38 date: Thu Jan 01 00:00:00 1970 +0000
38 39
39 40
40 41
41 42 Select files but no hunks
42 43
43 44 $ hg commit -i empty-rw<<EOF
44 45 > y
45 46 > n
46 47 > EOF
47 48 diff --git a/empty-rw b/empty-rw
48 49 new file mode 100644
49 50 examine changes to 'empty-rw'? [Ynesfdaq?] y
50 51
51 52 abort: empty commit message
52 53 [255]
53 54
54 55 $ hg tip -p
55 56 changeset: -1:000000000000
56 57 tag: tip
57 58 user:
58 59 date: Thu Jan 01 00:00:00 1970 +0000
59 60
60 61
61 62
62 63 Abort for untracked
63 64
64 65 $ touch untracked
65 66 $ hg commit -i -m should-fail empty-rw untracked
66 67 abort: untracked: file not tracked!
67 68 [255]
68 69 $ rm untracked
69 70
70 71 Record empty file
71 72
72 73 $ hg commit -i -d '0 0' -m empty empty-rw<<EOF
73 74 > y
74 75 > y
75 76 > EOF
76 77 diff --git a/empty-rw b/empty-rw
77 78 new file mode 100644
78 79 examine changes to 'empty-rw'? [Ynesfdaq?] y
79 80
80 81
81 82 $ hg tip -p
82 83 changeset: 0:c0708cf4e46e
83 84 tag: tip
84 85 user: test
85 86 date: Thu Jan 01 00:00:00 1970 +0000
86 87 summary: empty
87 88
88 89
89 90
90 91 Summary shows we updated to the new cset
91 92
92 93 $ hg summary
93 94 parent: 0:c0708cf4e46e tip
94 95 empty
95 96 branch: default
96 97 commit: (clean)
97 98 update: (current)
98 99 phases: 1 draft
99 100
100 101 Rename empty file
101 102
102 103 $ hg mv empty-rw empty-rename
103 104 $ hg commit -i -d '1 0' -m rename<<EOF
104 105 > y
105 106 > EOF
106 107 diff --git a/empty-rw b/empty-rename
107 108 rename from empty-rw
108 109 rename to empty-rename
109 110 examine changes to 'empty-rw' and 'empty-rename'? [Ynesfdaq?] y
110 111
111 112
112 113 $ hg tip -p
113 114 changeset: 1:d695e8dcb197
114 115 tag: tip
115 116 user: test
116 117 date: Thu Jan 01 00:00:01 1970 +0000
117 118 summary: rename
118 119
119 120
120 121
121 122 Copy empty file
122 123
123 124 $ hg cp empty-rename empty-copy
124 125 $ hg commit -i -d '2 0' -m copy<<EOF
125 126 > y
126 127 > EOF
127 128 diff --git a/empty-rename b/empty-copy
128 129 copy from empty-rename
129 130 copy to empty-copy
130 131 examine changes to 'empty-rename' and 'empty-copy'? [Ynesfdaq?] y
131 132
132 133
133 134 $ hg tip -p
134 135 changeset: 2:1d4b90bea524
135 136 tag: tip
136 137 user: test
137 138 date: Thu Jan 01 00:00:02 1970 +0000
138 139 summary: copy
139 140
140 141
141 142
142 143 Delete empty file
143 144
144 145 $ hg rm empty-copy
145 146 $ hg commit -i -d '3 0' -m delete<<EOF
146 147 > y
147 148 > EOF
148 149 diff --git a/empty-copy b/empty-copy
149 150 deleted file mode 100644
150 151 examine changes to 'empty-copy'? [Ynesfdaq?] y
151 152
152 153
153 154 $ hg tip -p
154 155 changeset: 3:b39a238f01a1
155 156 tag: tip
156 157 user: test
157 158 date: Thu Jan 01 00:00:03 1970 +0000
158 159 summary: delete
159 160
160 161
161 162
162 163 Add binary file
163 164
164 165 $ hg bundle --type v1 --base -2 tip.bundle
165 166 1 changesets found
166 167 $ hg add tip.bundle
167 168 $ hg commit -i -d '4 0' -m binary<<EOF
168 169 > y
169 170 > EOF
170 171 diff --git a/tip.bundle b/tip.bundle
171 172 new file mode 100644
172 173 this is a binary file
173 174 examine changes to 'tip.bundle'? [Ynesfdaq?] y
174 175
175 176
176 177 $ hg tip -p
177 178 changeset: 4:ad816da3711e
178 179 tag: tip
179 180 user: test
180 181 date: Thu Jan 01 00:00:04 1970 +0000
181 182 summary: binary
182 183
183 184 diff -r b39a238f01a1 -r ad816da3711e tip.bundle
184 185 Binary file tip.bundle has changed
185 186
186 187
187 188 Change binary file
188 189
189 190 $ hg bundle --base -2 --type v1 tip.bundle
190 191 1 changesets found
191 192 $ hg commit -i -d '5 0' -m binary-change<<EOF
192 193 > y
193 194 > EOF
194 195 diff --git a/tip.bundle b/tip.bundle
195 196 this modifies a binary file (all or nothing)
196 197 examine changes to 'tip.bundle'? [Ynesfdaq?] y
197 198
198 199
199 200 $ hg tip -p
200 201 changeset: 5:dccd6f3eb485
201 202 tag: tip
202 203 user: test
203 204 date: Thu Jan 01 00:00:05 1970 +0000
204 205 summary: binary-change
205 206
206 207 diff -r ad816da3711e -r dccd6f3eb485 tip.bundle
207 208 Binary file tip.bundle has changed
208 209
209 210
210 211 Rename and change binary file
211 212
212 213 $ hg mv tip.bundle top.bundle
213 214 $ hg bundle --base -2 --type v1 top.bundle
214 215 1 changesets found
215 216 $ hg commit -i -d '6 0' -m binary-change-rename<<EOF
216 217 > y
217 218 > EOF
218 219 diff --git a/tip.bundle b/top.bundle
219 220 rename from tip.bundle
220 221 rename to top.bundle
221 222 this modifies a binary file (all or nothing)
222 223 examine changes to 'tip.bundle' and 'top.bundle'? [Ynesfdaq?] y
223 224
224 225
225 226 $ hg tip -p
226 227 changeset: 6:7fa44105f5b3
227 228 tag: tip
228 229 user: test
229 230 date: Thu Jan 01 00:00:06 1970 +0000
230 231 summary: binary-change-rename
231 232
232 233 diff -r dccd6f3eb485 -r 7fa44105f5b3 tip.bundle
233 234 Binary file tip.bundle has changed
234 235 diff -r dccd6f3eb485 -r 7fa44105f5b3 top.bundle
235 236 Binary file top.bundle has changed
236 237
237 238
238 239 Add plain file
239 240
240 241 $ for i in 1 2 3 4 5 6 7 8 9 10; do
241 242 > echo $i >> plain
242 243 > done
243 244
244 245 $ hg add plain
245 246 $ hg commit -i -d '7 0' -m plain plain<<EOF
246 247 > y
247 248 > y
248 249 > EOF
249 250 diff --git a/plain b/plain
250 251 new file mode 100644
251 252 examine changes to 'plain'? [Ynesfdaq?] y
252 253
253 254 @@ -0,0 +1,10 @@
254 255 +1
255 256 +2
256 257 +3
257 258 +4
258 259 +5
259 260 +6
260 261 +7
261 262 +8
262 263 +9
263 264 +10
264 265 record this change to 'plain'? [Ynesfdaq?] y
265 266
266 267 $ hg tip -p
267 268 changeset: 7:11fb457c1be4
268 269 tag: tip
269 270 user: test
270 271 date: Thu Jan 01 00:00:07 1970 +0000
271 272 summary: plain
272 273
273 274 diff -r 7fa44105f5b3 -r 11fb457c1be4 plain
274 275 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
275 276 +++ b/plain Thu Jan 01 00:00:07 1970 +0000
276 277 @@ -0,0 +1,10 @@
277 278 +1
278 279 +2
279 280 +3
280 281 +4
281 282 +5
282 283 +6
283 284 +7
284 285 +8
285 286 +9
286 287 +10
287 288
288 289 Modify end of plain file with username unset
289 290
290 291 $ echo 11 >> plain
291 292 $ unset HGUSER
292 293 $ hg commit -i --config ui.username= -d '8 0' -m end plain
293 294 abort: no username supplied
294 295 (use 'hg config --edit' to set your username)
295 296 [255]
296 297
297 298
298 299 Modify end of plain file, also test that diffopts are accounted for
299 300
300 301 $ HGUSER="test"
301 302 $ export HGUSER
302 303 $ hg commit -i --config diff.showfunc=true -d '8 0' -m end plain <<EOF
303 304 > y
304 305 > y
305 306 > EOF
306 307 diff --git a/plain b/plain
307 308 1 hunks, 1 lines changed
308 309 examine changes to 'plain'? [Ynesfdaq?] y
309 310
310 311 @@ -8,3 +8,4 @@ 7
311 312 8
312 313 9
313 314 10
314 315 +11
315 316 record this change to 'plain'? [Ynesfdaq?] y
316 317
317 318
318 319 Modify end of plain file, no EOL
319 320
320 321 $ hg tip --template '{node}' >> plain
321 322 $ hg commit -i -d '9 0' -m noeol plain <<EOF
322 323 > y
323 324 > y
324 325 > EOF
325 326 diff --git a/plain b/plain
326 327 1 hunks, 1 lines changed
327 328 examine changes to 'plain'? [Ynesfdaq?] y
328 329
329 330 @@ -9,3 +9,4 @@ 8
330 331 9
331 332 10
332 333 11
333 334 +7264f99c5f5ff3261504828afa4fb4d406c3af54
334 335 \ No newline at end of file
335 336 record this change to 'plain'? [Ynesfdaq?] y
336 337
337 338
338 339 Record showfunc should preserve function across sections
339 340
340 341 $ cat > f1.py <<EOF
341 342 > def annotate(ui, repo, *pats, **opts):
342 343 > """show changeset information by line for each file
343 344 >
344 345 > List changes in files, showing the revision id responsible for
345 346 > each line.
346 347 >
347 348 > This command is useful for discovering when a change was made and
348 349 > by whom.
349 350 >
350 351 > If you include -f/-u/-d, the revision number is suppressed unless
351 352 > you also include -the revision number is suppressed unless
352 353 > you also include -n.
353 354 >
354 355 > Without the -a/--text option, annotate will avoid processing files
355 356 > it detects as binary. With -a, annotate will annotate the file
356 357 > anyway, although the results will probably be neither useful
357 358 > nor desirable.
358 359 >
359 360 > Returns 0 on success.
360 361 > """
361 362 > return 0
362 363 > def archive(ui, repo, dest, **opts):
363 364 > '''create an unversioned archive of a repository revision
364 365 >
365 366 > By default, the revision used is the parent of the working
366 367 > directory; use -r/--rev to specify a different revision.
367 368 >
368 369 > The archive type is automatically detected based on file
369 370 > extension (to override, use -t/--type).
370 371 >
371 372 > .. container:: verbose
372 373 >
373 374 > Valid types are:
374 375 > EOF
375 376 $ hg add f1.py
376 377 $ hg commit -m funcs
377 378 $ cat > f1.py <<EOF
378 379 > def annotate(ui, repo, *pats, **opts):
379 380 > """show changeset information by line for each file
380 381 >
381 382 > List changes in files, showing the revision id responsible for
382 383 > each line
383 384 >
384 385 > This command is useful for discovering when a change was made and
385 386 > by whom.
386 387 >
387 388 > Without the -a/--text option, annotate will avoid processing files
388 389 > it detects as binary. With -a, annotate will annotate the file
389 390 > anyway, although the results will probably be neither useful
390 391 > nor desirable.
391 392 >
392 393 > Returns 0 on success.
393 394 > """
394 395 > return 0
395 396 > def archive(ui, repo, dest, **opts):
396 397 > '''create an unversioned archive of a repository revision
397 398 >
398 399 > By default, the revision used is the parent of the working
399 400 > directory; use -r/--rev to specify a different revision.
400 401 >
401 402 > The archive type is automatically detected based on file
402 403 > extension (or override using -t/--type).
403 404 >
404 405 > .. container:: verbose
405 406 >
406 407 > Valid types are:
407 408 > EOF
408 409 $ hg commit -i -m interactive <<EOF
409 410 > y
410 411 > y
411 412 > y
412 413 > y
413 414 > EOF
414 415 diff --git a/f1.py b/f1.py
415 416 3 hunks, 6 lines changed
416 417 examine changes to 'f1.py'? [Ynesfdaq?] y
417 418
418 419 @@ -2,8 +2,8 @@ def annotate(ui, repo, *pats, **opts):
419 420 """show changeset information by line for each file
420 421
421 422 List changes in files, showing the revision id responsible for
422 423 - each line.
423 424 + each line
424 425
425 426 This command is useful for discovering when a change was made and
426 427 by whom.
427 428
428 429 record change 1/3 to 'f1.py'? [Ynesfdaq?] y
429 430
430 431 @@ -6,11 +6,7 @@ def annotate(ui, repo, *pats, **opts):
431 432
432 433 This command is useful for discovering when a change was made and
433 434 by whom.
434 435
435 436 - If you include -f/-u/-d, the revision number is suppressed unless
436 437 - you also include -the revision number is suppressed unless
437 438 - you also include -n.
438 439 -
439 440 Without the -a/--text option, annotate will avoid processing files
440 441 it detects as binary. With -a, annotate will annotate the file
441 442 anyway, although the results will probably be neither useful
442 443 record change 2/3 to 'f1.py'? [Ynesfdaq?] y
443 444
444 445 @@ -26,7 +22,7 @@ def archive(ui, repo, dest, **opts):
445 446 directory; use -r/--rev to specify a different revision.
446 447
447 448 The archive type is automatically detected based on file
448 449 - extension (to override, use -t/--type).
449 450 + extension (or override using -t/--type).
450 451
451 452 .. container:: verbose
452 453
453 454 record change 3/3 to 'f1.py'? [Ynesfdaq?] y
454 455
455 456
456 457 Modify end of plain file, add EOL
457 458
458 459 $ echo >> plain
459 460 $ echo 1 > plain2
460 461 $ hg add plain2
461 462 $ hg commit -i -d '10 0' -m eol plain plain2 <<EOF
462 463 > y
463 464 > y
464 465 > y
465 466 > y
466 467 > EOF
467 468 diff --git a/plain b/plain
468 469 1 hunks, 1 lines changed
469 470 examine changes to 'plain'? [Ynesfdaq?] y
470 471
471 472 @@ -9,4 +9,4 @@ 8
472 473 9
473 474 10
474 475 11
475 476 -7264f99c5f5ff3261504828afa4fb4d406c3af54
476 477 \ No newline at end of file
477 478 +7264f99c5f5ff3261504828afa4fb4d406c3af54
478 479 record change 1/2 to 'plain'? [Ynesfdaq?] y
479 480
480 481 diff --git a/plain2 b/plain2
481 482 new file mode 100644
482 483 examine changes to 'plain2'? [Ynesfdaq?] y
483 484
484 485 @@ -0,0 +1,1 @@
485 486 +1
486 487 record change 2/2 to 'plain2'? [Ynesfdaq?] y
487 488
488 489 Modify beginning, trim end, record both, add another file to test
489 490 changes numbering
490 491
491 492 $ rm plain
492 493 $ for i in 2 2 3 4 5 6 7 8 9 10; do
493 494 > echo $i >> plain
494 495 > done
495 496 $ echo 2 >> plain2
496 497
497 498 $ hg commit -i -d '10 0' -m begin-and-end plain plain2 <<EOF
498 499 > y
499 500 > y
500 501 > y
501 502 > y
502 503 > y
503 504 > EOF
504 505 diff --git a/plain b/plain
505 506 2 hunks, 3 lines changed
506 507 examine changes to 'plain'? [Ynesfdaq?] y
507 508
508 509 @@ -1,4 +1,4 @@
509 510 -1
510 511 +2
511 512 2
512 513 3
513 514 4
514 515 record change 1/3 to 'plain'? [Ynesfdaq?] y
515 516
516 517 @@ -8,5 +8,3 @@ 7
517 518 8
518 519 9
519 520 10
520 521 -11
521 522 -7264f99c5f5ff3261504828afa4fb4d406c3af54
522 523 record change 2/3 to 'plain'? [Ynesfdaq?] y
523 524
524 525 diff --git a/plain2 b/plain2
525 526 1 hunks, 1 lines changed
526 527 examine changes to 'plain2'? [Ynesfdaq?] y
527 528
528 529 @@ -1,1 +1,2 @@
529 530 1
530 531 +2
531 532 record change 3/3 to 'plain2'? [Ynesfdaq?] y
532 533
533 534
534 535 $ hg tip -p
535 536 changeset: 13:f941910cff62
536 537 tag: tip
537 538 user: test
538 539 date: Thu Jan 01 00:00:10 1970 +0000
539 540 summary: begin-and-end
540 541
541 542 diff -r 33abe24d946c -r f941910cff62 plain
542 543 --- a/plain Thu Jan 01 00:00:10 1970 +0000
543 544 +++ b/plain Thu Jan 01 00:00:10 1970 +0000
544 545 @@ -1,4 +1,4 @@
545 546 -1
546 547 +2
547 548 2
548 549 3
549 550 4
550 551 @@ -8,5 +8,3 @@
551 552 8
552 553 9
553 554 10
554 555 -11
555 556 -7264f99c5f5ff3261504828afa4fb4d406c3af54
556 557 diff -r 33abe24d946c -r f941910cff62 plain2
557 558 --- a/plain2 Thu Jan 01 00:00:10 1970 +0000
558 559 +++ b/plain2 Thu Jan 01 00:00:10 1970 +0000
559 560 @@ -1,1 +1,2 @@
560 561 1
561 562 +2
562 563
563 564
564 565 Trim beginning, modify end
565 566
566 567 $ rm plain
567 568 > for i in 4 5 6 7 8 9 10.new; do
568 569 > echo $i >> plain
569 570 > done
570 571
571 572 Record end
572 573
573 574 $ hg commit -i -d '11 0' -m end-only plain <<EOF
574 575 > y
575 576 > n
576 577 > y
577 578 > EOF
578 579 diff --git a/plain b/plain
579 580 2 hunks, 4 lines changed
580 581 examine changes to 'plain'? [Ynesfdaq?] y
581 582
582 583 @@ -1,9 +1,6 @@
583 584 -2
584 585 -2
585 586 -3
586 587 4
587 588 5
588 589 6
589 590 7
590 591 8
591 592 9
592 593 record change 1/2 to 'plain'? [Ynesfdaq?] n
593 594
594 595 @@ -4,7 +1,7 @@
595 596 4
596 597 5
597 598 6
598 599 7
599 600 8
600 601 9
601 602 -10
602 603 +10.new
603 604 record change 2/2 to 'plain'? [Ynesfdaq?] y
604 605
605 606
606 607 $ hg tip -p
607 608 changeset: 14:4915f538659b
608 609 tag: tip
609 610 user: test
610 611 date: Thu Jan 01 00:00:11 1970 +0000
611 612 summary: end-only
612 613
613 614 diff -r f941910cff62 -r 4915f538659b plain
614 615 --- a/plain Thu Jan 01 00:00:10 1970 +0000
615 616 +++ b/plain Thu Jan 01 00:00:11 1970 +0000
616 617 @@ -7,4 +7,4 @@
617 618 7
618 619 8
619 620 9
620 621 -10
621 622 +10.new
622 623
623 624
624 625 Record beginning
625 626
626 627 $ hg commit -i -d '12 0' -m begin-only plain <<EOF
627 628 > y
628 629 > y
629 630 > EOF
630 631 diff --git a/plain b/plain
631 632 1 hunks, 3 lines changed
632 633 examine changes to 'plain'? [Ynesfdaq?] y
633 634
634 635 @@ -1,6 +1,3 @@
635 636 -2
636 637 -2
637 638 -3
638 639 4
639 640 5
640 641 6
641 642 record this change to 'plain'? [Ynesfdaq?] y
642 643
643 644
644 645 $ hg tip -p
645 646 changeset: 15:1b1f93d4b94b
646 647 tag: tip
647 648 user: test
648 649 date: Thu Jan 01 00:00:12 1970 +0000
649 650 summary: begin-only
650 651
651 652 diff -r 4915f538659b -r 1b1f93d4b94b plain
652 653 --- a/plain Thu Jan 01 00:00:11 1970 +0000
653 654 +++ b/plain Thu Jan 01 00:00:12 1970 +0000
654 655 @@ -1,6 +1,3 @@
655 656 -2
656 657 -2
657 658 -3
658 659 4
659 660 5
660 661 6
661 662
662 663
663 664 Add to beginning, trim from end
664 665
665 666 $ rm plain
666 667 $ for i in 1 2 3 4 5 6 7 8 9; do
667 668 > echo $i >> plain
668 669 > done
669 670
670 671 Record end
671 672
672 673 $ hg commit -i --traceback -d '13 0' -m end-again plain<<EOF
673 674 > y
674 675 > n
675 676 > y
676 677 > EOF
677 678 diff --git a/plain b/plain
678 679 2 hunks, 4 lines changed
679 680 examine changes to 'plain'? [Ynesfdaq?] y
680 681
681 682 @@ -1,6 +1,9 @@
682 683 +1
683 684 +2
684 685 +3
685 686 4
686 687 5
687 688 6
688 689 7
689 690 8
690 691 9
691 692 record change 1/2 to 'plain'? [Ynesfdaq?] n
692 693
693 694 @@ -1,7 +4,6 @@
694 695 4
695 696 5
696 697 6
697 698 7
698 699 8
699 700 9
700 701 -10.new
701 702 record change 2/2 to 'plain'? [Ynesfdaq?] y
702 703
703 704
704 705 Add to beginning, middle, end
705 706
706 707 $ rm plain
707 708 $ for i in 1 2 3 4 5 5.new 5.reallynew 6 7 8 9 10 11; do
708 709 > echo $i >> plain
709 710 > done
710 711
711 712 Record beginning, middle, and test that format-breaking diffopts are ignored
712 713
713 714 $ hg commit -i --config diff.noprefix=True -d '14 0' -m middle-only plain <<EOF
714 715 > y
715 716 > y
716 717 > y
717 718 > n
718 719 > EOF
719 720 diff --git a/plain b/plain
720 721 3 hunks, 7 lines changed
721 722 examine changes to 'plain'? [Ynesfdaq?] y
722 723
723 724 @@ -1,2 +1,5 @@
724 725 +1
725 726 +2
726 727 +3
727 728 4
728 729 5
729 730 record change 1/3 to 'plain'? [Ynesfdaq?] y
730 731
731 732 @@ -1,6 +4,8 @@
732 733 4
733 734 5
734 735 +5.new
735 736 +5.reallynew
736 737 6
737 738 7
738 739 8
739 740 9
740 741 record change 2/3 to 'plain'? [Ynesfdaq?] y
741 742
742 743 @@ -3,4 +8,6 @@
743 744 6
744 745 7
745 746 8
746 747 9
747 748 +10
748 749 +11
749 750 record change 3/3 to 'plain'? [Ynesfdaq?] n
750 751
751 752
752 753 $ hg tip -p
753 754 changeset: 17:41cf3f5c55ae
754 755 tag: tip
755 756 user: test
756 757 date: Thu Jan 01 00:00:14 1970 +0000
757 758 summary: middle-only
758 759
759 760 diff -r a69d252246e1 -r 41cf3f5c55ae plain
760 761 --- a/plain Thu Jan 01 00:00:13 1970 +0000
761 762 +++ b/plain Thu Jan 01 00:00:14 1970 +0000
762 763 @@ -1,5 +1,10 @@
763 764 +1
764 765 +2
765 766 +3
766 767 4
767 768 5
768 769 +5.new
769 770 +5.reallynew
770 771 6
771 772 7
772 773 8
773 774
774 775
775 776 Record end
776 777
777 778 $ hg commit -i -d '15 0' -m end-only plain <<EOF
778 779 > y
779 780 > y
780 781 > EOF
781 782 diff --git a/plain b/plain
782 783 1 hunks, 2 lines changed
783 784 examine changes to 'plain'? [Ynesfdaq?] y
784 785
785 786 @@ -9,3 +9,5 @@ 6
786 787 7
787 788 8
788 789 9
789 790 +10
790 791 +11
791 792 record this change to 'plain'? [Ynesfdaq?] y
792 793
793 794
794 795 $ hg tip -p
795 796 changeset: 18:58a72f46bc24
796 797 tag: tip
797 798 user: test
798 799 date: Thu Jan 01 00:00:15 1970 +0000
799 800 summary: end-only
800 801
801 802 diff -r 41cf3f5c55ae -r 58a72f46bc24 plain
802 803 --- a/plain Thu Jan 01 00:00:14 1970 +0000
803 804 +++ b/plain Thu Jan 01 00:00:15 1970 +0000
804 805 @@ -9,3 +9,5 @@
805 806 7
806 807 8
807 808 9
808 809 +10
809 810 +11
810 811
811 812
812 813 $ mkdir subdir
813 814 $ cd subdir
814 815 $ echo a > a
815 816 $ hg ci -d '16 0' -Amsubdir
816 817 adding subdir/a
817 818
818 819 $ echo a >> a
819 820 $ hg commit -i -d '16 0' -m subdir-change a <<EOF
820 821 > y
821 822 > y
822 823 > EOF
823 824 diff --git a/subdir/a b/subdir/a
824 825 1 hunks, 1 lines changed
825 826 examine changes to 'subdir/a'? [Ynesfdaq?] y
826 827
827 828 @@ -1,1 +1,2 @@
828 829 a
829 830 +a
830 831 record this change to 'subdir/a'? [Ynesfdaq?] y
831 832
832 833
833 834 $ hg tip -p
834 835 changeset: 20:e0f6b99f6c49
835 836 tag: tip
836 837 user: test
837 838 date: Thu Jan 01 00:00:16 1970 +0000
838 839 summary: subdir-change
839 840
840 841 diff -r abd26b51de37 -r e0f6b99f6c49 subdir/a
841 842 --- a/subdir/a Thu Jan 01 00:00:16 1970 +0000
842 843 +++ b/subdir/a Thu Jan 01 00:00:16 1970 +0000
843 844 @@ -1,1 +1,2 @@
844 845 a
845 846 +a
846 847
847 848
848 849 $ echo a > f1
849 850 $ echo b > f2
850 851 $ hg add f1 f2
851 852
852 853 $ hg ci -mz -d '17 0'
853 854
854 855 $ echo a >> f1
855 856 $ echo b >> f2
856 857
857 858 Help, quit
858 859
859 860 $ hg commit -i <<EOF
860 861 > ?
861 862 > q
862 863 > EOF
863 864 diff --git a/subdir/f1 b/subdir/f1
864 865 1 hunks, 1 lines changed
865 866 examine changes to 'subdir/f1'? [Ynesfdaq?] ?
866 867
867 868 y - yes, record this change
868 869 n - no, skip this change
869 870 e - edit this change manually
870 871 s - skip remaining changes to this file
871 872 f - record remaining changes to this file
872 873 d - done, skip remaining changes and files
873 874 a - record all changes to all remaining files
874 875 q - quit, recording no changes
875 876 ? - ? (display help)
876 877 examine changes to 'subdir/f1'? [Ynesfdaq?] q
877 878
878 879 abort: user quit
879 880 [255]
880 881
881 882 #if gettext
882 883
883 884 Test translated help message
884 885
885 886 str.lower() instead of encoding.lower(str) on translated message might
886 887 make message meaningless, because some encoding uses 0x41(A) - 0x5a(Z)
887 888 as the second or later byte of multi-byte character.
888 889
889 890 For example, "\x8bL\x98^" (translation of "record" in ja_JP.cp932)
890 891 contains 0x4c (L). str.lower() replaces 0x4c(L) by 0x6c(l) and this
891 892 replacement makes message meaningless.
892 893
893 894 This tests that translated help message is lower()-ed correctly.
894 895
895 896 $ LANGUAGE=ja
896 897 $ export LANGUAGE
897 898
898 899 $ cat > $TESTTMP/escape.py <<EOF
899 900 > from __future__ import absolute_import
900 901 > import sys
901 902 > def escape(c):
902 903 > o = ord(c)
903 904 > if o < 0x80:
904 905 > return c
905 906 > else:
906 907 > return r'\x%02x' % o # escape char setting MSB
907 908 > for l in sys.stdin:
908 909 > sys.stdout.write(''.join(escape(c) for c in l))
909 910 > EOF
910 911
911 912 $ hg commit -i --encoding cp932 2>&1 <<EOF | python $TESTTMP/escape.py | grep '^y - '
912 913 > ?
913 914 > q
914 915 > EOF
915 916 y - \x82\xb1\x82\xcc\x95\xcf\x8dX\x82\xf0\x8bL\x98^(yes)
916 917
917 918 $ LANGUAGE=
918 919 #endif
919 920
920 921 Skip
921 922
922 923 $ hg commit -i <<EOF
923 924 > s
924 925 > EOF
925 926 diff --git a/subdir/f1 b/subdir/f1
926 927 1 hunks, 1 lines changed
927 928 examine changes to 'subdir/f1'? [Ynesfdaq?] s
928 929
929 930 diff --git a/subdir/f2 b/subdir/f2
930 931 1 hunks, 1 lines changed
931 932 examine changes to 'subdir/f2'? [Ynesfdaq?] abort: response expected
932 933 [255]
933 934
934 935 No
935 936
936 937 $ hg commit -i <<EOF
937 938 > n
938 939 > EOF
939 940 diff --git a/subdir/f1 b/subdir/f1
940 941 1 hunks, 1 lines changed
941 942 examine changes to 'subdir/f1'? [Ynesfdaq?] n
942 943
943 944 diff --git a/subdir/f2 b/subdir/f2
944 945 1 hunks, 1 lines changed
945 946 examine changes to 'subdir/f2'? [Ynesfdaq?] abort: response expected
946 947 [255]
947 948
948 949 f, quit
949 950
950 951 $ hg commit -i <<EOF
951 952 > f
952 953 > q
953 954 > EOF
954 955 diff --git a/subdir/f1 b/subdir/f1
955 956 1 hunks, 1 lines changed
956 957 examine changes to 'subdir/f1'? [Ynesfdaq?] f
957 958
958 959 diff --git a/subdir/f2 b/subdir/f2
959 960 1 hunks, 1 lines changed
960 961 examine changes to 'subdir/f2'? [Ynesfdaq?] q
961 962
962 963 abort: user quit
963 964 [255]
964 965
965 966 s, all
966 967
967 968 $ hg commit -i -d '18 0' -mx <<EOF
968 969 > s
969 970 > a
970 971 > EOF
971 972 diff --git a/subdir/f1 b/subdir/f1
972 973 1 hunks, 1 lines changed
973 974 examine changes to 'subdir/f1'? [Ynesfdaq?] s
974 975
975 976 diff --git a/subdir/f2 b/subdir/f2
976 977 1 hunks, 1 lines changed
977 978 examine changes to 'subdir/f2'? [Ynesfdaq?] a
978 979
979 980
980 981 $ hg tip -p
981 982 changeset: 22:6afbbefacf35
982 983 tag: tip
983 984 user: test
984 985 date: Thu Jan 01 00:00:18 1970 +0000
985 986 summary: x
986 987
987 988 diff -r b73c401c693c -r 6afbbefacf35 subdir/f2
988 989 --- a/subdir/f2 Thu Jan 01 00:00:17 1970 +0000
989 990 +++ b/subdir/f2 Thu Jan 01 00:00:18 1970 +0000
990 991 @@ -1,1 +1,2 @@
991 992 b
992 993 +b
993 994
994 995
995 996 f
996 997
997 998 $ hg commit -i -d '19 0' -my <<EOF
998 999 > f
999 1000 > EOF
1000 1001 diff --git a/subdir/f1 b/subdir/f1
1001 1002 1 hunks, 1 lines changed
1002 1003 examine changes to 'subdir/f1'? [Ynesfdaq?] f
1003 1004
1004 1005
1005 1006 $ hg tip -p
1006 1007 changeset: 23:715028a33949
1007 1008 tag: tip
1008 1009 user: test
1009 1010 date: Thu Jan 01 00:00:19 1970 +0000
1010 1011 summary: y
1011 1012
1012 1013 diff -r 6afbbefacf35 -r 715028a33949 subdir/f1
1013 1014 --- a/subdir/f1 Thu Jan 01 00:00:18 1970 +0000
1014 1015 +++ b/subdir/f1 Thu Jan 01 00:00:19 1970 +0000
1015 1016 @@ -1,1 +1,2 @@
1016 1017 a
1017 1018 +a
1018 1019
1019 1020
1020 1021 #if execbit
1021 1022
1022 1023 Preserve chmod +x
1023 1024
1024 1025 $ chmod +x f1
1025 1026 $ echo a >> f1
1026 1027 $ hg commit -i -d '20 0' -mz <<EOF
1027 1028 > y
1028 1029 > y
1029 1030 > y
1030 1031 > EOF
1031 1032 diff --git a/subdir/f1 b/subdir/f1
1032 1033 old mode 100644
1033 1034 new mode 100755
1034 1035 1 hunks, 1 lines changed
1035 1036 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1036 1037
1037 1038 @@ -1,2 +1,3 @@
1038 1039 a
1039 1040 a
1040 1041 +a
1041 1042 record this change to 'subdir/f1'? [Ynesfdaq?] y
1042 1043
1043 1044
1044 1045 $ hg tip --config diff.git=True -p
1045 1046 changeset: 24:db967c1e5884
1046 1047 tag: tip
1047 1048 user: test
1048 1049 date: Thu Jan 01 00:00:20 1970 +0000
1049 1050 summary: z
1050 1051
1051 1052 diff --git a/subdir/f1 b/subdir/f1
1052 1053 old mode 100644
1053 1054 new mode 100755
1054 1055 --- a/subdir/f1
1055 1056 +++ b/subdir/f1
1056 1057 @@ -1,2 +1,3 @@
1057 1058 a
1058 1059 a
1059 1060 +a
1060 1061
1061 1062
1062 1063 Preserve execute permission on original
1063 1064
1064 1065 $ echo b >> f1
1065 1066 $ hg commit -i -d '21 0' -maa <<EOF
1066 1067 > y
1067 1068 > y
1068 1069 > y
1069 1070 > EOF
1070 1071 diff --git a/subdir/f1 b/subdir/f1
1071 1072 1 hunks, 1 lines changed
1072 1073 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1073 1074
1074 1075 @@ -1,3 +1,4 @@
1075 1076 a
1076 1077 a
1077 1078 a
1078 1079 +b
1079 1080 record this change to 'subdir/f1'? [Ynesfdaq?] y
1080 1081
1081 1082
1082 1083 $ hg tip --config diff.git=True -p
1083 1084 changeset: 25:88903aef81c3
1084 1085 tag: tip
1085 1086 user: test
1086 1087 date: Thu Jan 01 00:00:21 1970 +0000
1087 1088 summary: aa
1088 1089
1089 1090 diff --git a/subdir/f1 b/subdir/f1
1090 1091 --- a/subdir/f1
1091 1092 +++ b/subdir/f1
1092 1093 @@ -1,3 +1,4 @@
1093 1094 a
1094 1095 a
1095 1096 a
1096 1097 +b
1097 1098
1098 1099
1099 1100 Preserve chmod -x
1100 1101
1101 1102 $ chmod -x f1
1102 1103 $ echo c >> f1
1103 1104 $ hg commit -i -d '22 0' -mab <<EOF
1104 1105 > y
1105 1106 > y
1106 1107 > y
1107 1108 > EOF
1108 1109 diff --git a/subdir/f1 b/subdir/f1
1109 1110 old mode 100755
1110 1111 new mode 100644
1111 1112 1 hunks, 1 lines changed
1112 1113 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1113 1114
1114 1115 @@ -2,3 +2,4 @@ a
1115 1116 a
1116 1117 a
1117 1118 b
1118 1119 +c
1119 1120 record this change to 'subdir/f1'? [Ynesfdaq?] y
1120 1121
1121 1122
1122 1123 $ hg tip --config diff.git=True -p
1123 1124 changeset: 26:7af84b6cf560
1124 1125 tag: tip
1125 1126 user: test
1126 1127 date: Thu Jan 01 00:00:22 1970 +0000
1127 1128 summary: ab
1128 1129
1129 1130 diff --git a/subdir/f1 b/subdir/f1
1130 1131 old mode 100755
1131 1132 new mode 100644
1132 1133 --- a/subdir/f1
1133 1134 +++ b/subdir/f1
1134 1135 @@ -2,3 +2,4 @@
1135 1136 a
1136 1137 a
1137 1138 b
1138 1139 +c
1139 1140
1140 1141
1141 1142 #else
1142 1143
1143 1144 Slightly bogus tests to get almost same repo structure as when x bit is used
1144 1145 - but with different hashes.
1145 1146
1146 1147 Mock "Preserve chmod +x"
1147 1148
1148 1149 $ echo a >> f1
1149 1150 $ hg commit -i -d '20 0' -mz <<EOF
1150 1151 > y
1151 1152 > y
1152 1153 > y
1153 1154 > EOF
1154 1155 diff --git a/subdir/f1 b/subdir/f1
1155 1156 1 hunks, 1 lines changed
1156 1157 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1157 1158
1158 1159 @@ -1,2 +1,3 @@
1159 1160 a
1160 1161 a
1161 1162 +a
1162 1163 record this change to 'subdir/f1'? [Ynesfdaq?] y
1163 1164
1164 1165
1165 1166 $ hg tip --config diff.git=True -p
1166 1167 changeset: 24:c26cfe2c4eb0
1167 1168 tag: tip
1168 1169 user: test
1169 1170 date: Thu Jan 01 00:00:20 1970 +0000
1170 1171 summary: z
1171 1172
1172 1173 diff --git a/subdir/f1 b/subdir/f1
1173 1174 --- a/subdir/f1
1174 1175 +++ b/subdir/f1
1175 1176 @@ -1,2 +1,3 @@
1176 1177 a
1177 1178 a
1178 1179 +a
1179 1180
1180 1181
1181 1182 Mock "Preserve execute permission on original"
1182 1183
1183 1184 $ echo b >> f1
1184 1185 $ hg commit -i -d '21 0' -maa <<EOF
1185 1186 > y
1186 1187 > y
1187 1188 > y
1188 1189 > EOF
1189 1190 diff --git a/subdir/f1 b/subdir/f1
1190 1191 1 hunks, 1 lines changed
1191 1192 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1192 1193
1193 1194 @@ -1,3 +1,4 @@
1194 1195 a
1195 1196 a
1196 1197 a
1197 1198 +b
1198 1199 record this change to 'subdir/f1'? [Ynesfdaq?] y
1199 1200
1200 1201
1201 1202 $ hg tip --config diff.git=True -p
1202 1203 changeset: 25:a48d2d60adde
1203 1204 tag: tip
1204 1205 user: test
1205 1206 date: Thu Jan 01 00:00:21 1970 +0000
1206 1207 summary: aa
1207 1208
1208 1209 diff --git a/subdir/f1 b/subdir/f1
1209 1210 --- a/subdir/f1
1210 1211 +++ b/subdir/f1
1211 1212 @@ -1,3 +1,4 @@
1212 1213 a
1213 1214 a
1214 1215 a
1215 1216 +b
1216 1217
1217 1218
1218 1219 Mock "Preserve chmod -x"
1219 1220
1220 1221 $ chmod -x f1
1221 1222 $ echo c >> f1
1222 1223 $ hg commit -i -d '22 0' -mab <<EOF
1223 1224 > y
1224 1225 > y
1225 1226 > y
1226 1227 > EOF
1227 1228 diff --git a/subdir/f1 b/subdir/f1
1228 1229 1 hunks, 1 lines changed
1229 1230 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1230 1231
1231 1232 @@ -2,3 +2,4 @@ a
1232 1233 a
1233 1234 a
1234 1235 b
1235 1236 +c
1236 1237 record this change to 'subdir/f1'? [Ynesfdaq?] y
1237 1238
1238 1239
1239 1240 $ hg tip --config diff.git=True -p
1240 1241 changeset: 26:5cc89ae210fa
1241 1242 tag: tip
1242 1243 user: test
1243 1244 date: Thu Jan 01 00:00:22 1970 +0000
1244 1245 summary: ab
1245 1246
1246 1247 diff --git a/subdir/f1 b/subdir/f1
1247 1248 --- a/subdir/f1
1248 1249 +++ b/subdir/f1
1249 1250 @@ -2,3 +2,4 @@
1250 1251 a
1251 1252 a
1252 1253 b
1253 1254 +c
1254 1255
1255 1256
1256 1257 #endif
1257 1258
1258 1259 $ cd ..
1259 1260
1260 1261
1261 1262 Abort early when a merge is in progress
1262 1263
1263 1264 $ hg up 4
1264 1265 1 files updated, 0 files merged, 7 files removed, 0 files unresolved
1265 1266
1266 1267 $ touch iwillmergethat
1267 1268 $ hg add iwillmergethat
1268 1269
1269 1270 $ hg branch thatbranch
1270 1271 marked working directory as branch thatbranch
1271 1272 (branches are permanent and global, did you want a bookmark?)
1272 1273
1273 1274 $ hg ci -m'new head'
1274 1275
1275 1276 $ hg up default
1276 1277 7 files updated, 0 files merged, 2 files removed, 0 files unresolved
1277 1278
1278 1279 $ hg merge thatbranch
1279 1280 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1280 1281 (branch merge, don't forget to commit)
1281 1282
1282 1283 $ hg commit -i -m'will abort'
1283 1284 abort: cannot partially commit a merge (use "hg commit" instead)
1284 1285 [255]
1285 1286
1286 1287 $ hg up -C
1287 1288 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1288 1289
1289 1290 Editing patch (and ignoring trailing text)
1290 1291
1291 1292 $ cat > editor.sh << '__EOF__'
1292 1293 > sed -e 7d -e '5s/^-/ /' -e '/^# ---/i\
1293 1294 > trailing\nditto' "$1" > tmp
1294 1295 > mv tmp "$1"
1295 1296 > __EOF__
1296 1297 $ cat > editedfile << '__EOF__'
1297 1298 > This is the first line
1298 1299 > This is the second line
1299 1300 > This is the third line
1300 1301 > __EOF__
1301 1302 $ hg add editedfile
1302 1303 $ hg commit -medit-patch-1
1303 1304 $ cat > editedfile << '__EOF__'
1304 1305 > This line has changed
1305 1306 > This change will be committed
1306 1307 > This is the third line
1307 1308 > __EOF__
1308 1309 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i -d '23 0' -medit-patch-2 <<EOF
1309 1310 > y
1310 1311 > e
1311 1312 > EOF
1312 1313 diff --git a/editedfile b/editedfile
1313 1314 1 hunks, 2 lines changed
1314 1315 examine changes to 'editedfile'? [Ynesfdaq?] y
1315 1316
1316 1317 @@ -1,3 +1,3 @@
1317 1318 -This is the first line
1318 1319 -This is the second line
1319 1320 +This line has changed
1320 1321 +This change will be committed
1321 1322 This is the third line
1322 1323 record this change to 'editedfile'? [Ynesfdaq?] e
1323 1324
1324 1325 $ cat editedfile
1325 1326 This line has changed
1326 1327 This change will be committed
1327 1328 This is the third line
1328 1329 $ hg cat -r tip editedfile
1329 1330 This is the first line
1330 1331 This change will be committed
1331 1332 This is the third line
1332 1333 $ hg revert editedfile
1333 1334
1334 1335 Trying to edit patch for whole file
1335 1336
1336 1337 $ echo "This is the fourth line" >> editedfile
1337 1338 $ hg commit -i <<EOF
1338 1339 > e
1339 1340 > q
1340 1341 > EOF
1341 1342 diff --git a/editedfile b/editedfile
1342 1343 1 hunks, 1 lines changed
1343 1344 examine changes to 'editedfile'? [Ynesfdaq?] e
1344 1345
1345 1346 cannot edit patch for whole file
1346 1347 examine changes to 'editedfile'? [Ynesfdaq?] q
1347 1348
1348 1349 abort: user quit
1349 1350 [255]
1350 1351 $ hg revert editedfile
1351 1352
1352 1353 Removing changes from patch
1353 1354
1354 1355 $ sed -e '3s/third/second/' -e '2s/will/will not/' -e 1d editedfile > tmp
1355 1356 $ mv tmp editedfile
1356 1357 $ echo "This line has been added" >> editedfile
1357 1358 $ cat > editor.sh << '__EOF__'
1358 1359 > sed -e 's/^[-+]/ /' "$1" > tmp
1359 1360 > mv tmp "$1"
1360 1361 > __EOF__
1361 1362 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i <<EOF
1362 1363 > y
1363 1364 > e
1364 1365 > EOF
1365 1366 diff --git a/editedfile b/editedfile
1366 1367 1 hunks, 3 lines changed
1367 1368 examine changes to 'editedfile'? [Ynesfdaq?] y
1368 1369
1369 1370 @@ -1,3 +1,3 @@
1370 1371 -This is the first line
1371 1372 -This change will be committed
1372 1373 -This is the third line
1373 1374 +This change will not be committed
1374 1375 +This is the second line
1375 1376 +This line has been added
1376 1377 record this change to 'editedfile'? [Ynesfdaq?] e
1377 1378
1378 1379 no changes to record
1380 [1]
1379 1381 $ cat editedfile
1380 1382 This change will not be committed
1381 1383 This is the second line
1382 1384 This line has been added
1383 1385 $ hg cat -r tip editedfile
1384 1386 This is the first line
1385 1387 This change will be committed
1386 1388 This is the third line
1387 1389 $ hg revert editedfile
1388 1390
1389 1391 Invalid patch
1390 1392
1391 1393 $ sed -e '3s/third/second/' -e '2s/will/will not/' -e 1d editedfile > tmp
1392 1394 $ mv tmp editedfile
1393 1395 $ echo "This line has been added" >> editedfile
1394 1396 $ cat > editor.sh << '__EOF__'
1395 1397 > sed s/This/That/ "$1" > tmp
1396 1398 > mv tmp "$1"
1397 1399 > __EOF__
1398 1400 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i <<EOF
1399 1401 > y
1400 1402 > e
1401 1403 > EOF
1402 1404 diff --git a/editedfile b/editedfile
1403 1405 1 hunks, 3 lines changed
1404 1406 examine changes to 'editedfile'? [Ynesfdaq?] y
1405 1407
1406 1408 @@ -1,3 +1,3 @@
1407 1409 -This is the first line
1408 1410 -This change will be committed
1409 1411 -This is the third line
1410 1412 +This change will not be committed
1411 1413 +This is the second line
1412 1414 +This line has been added
1413 1415 record this change to 'editedfile'? [Ynesfdaq?] e
1414 1416
1415 1417 patching file editedfile
1416 1418 Hunk #1 FAILED at 0
1417 1419 1 out of 1 hunks FAILED -- saving rejects to file editedfile.rej
1418 1420 abort: patch failed to apply
1419 1421 [255]
1420 1422 $ cat editedfile
1421 1423 This change will not be committed
1422 1424 This is the second line
1423 1425 This line has been added
1424 1426 $ hg cat -r tip editedfile
1425 1427 This is the first line
1426 1428 This change will be committed
1427 1429 This is the third line
1428 1430 $ cat editedfile.rej
1429 1431 --- editedfile
1430 1432 +++ editedfile
1431 1433 @@ -1,3 +1,3 @@
1432 1434 -That is the first line
1433 1435 -That change will be committed
1434 1436 -That is the third line
1435 1437 +That change will not be committed
1436 1438 +That is the second line
1437 1439 +That line has been added
1438 1440
1439 1441 Malformed patch - error handling
1440 1442
1441 1443 $ cat > editor.sh << '__EOF__'
1442 1444 > sed -e '/^@/p' "$1" > tmp
1443 1445 > mv tmp "$1"
1444 1446 > __EOF__
1445 1447 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i <<EOF
1446 1448 > y
1447 1449 > e
1448 1450 > EOF
1449 1451 diff --git a/editedfile b/editedfile
1450 1452 1 hunks, 3 lines changed
1451 1453 examine changes to 'editedfile'? [Ynesfdaq?] y
1452 1454
1453 1455 @@ -1,3 +1,3 @@
1454 1456 -This is the first line
1455 1457 -This change will be committed
1456 1458 -This is the third line
1457 1459 +This change will not be committed
1458 1460 +This is the second line
1459 1461 +This line has been added
1460 1462 record this change to 'editedfile'? [Ynesfdaq?] e
1461 1463
1462 1464 abort: error parsing patch: unhandled transition: range -> range
1463 1465 [255]
1464 1466
1465 1467 Exiting editor with status 1, ignores the edit but does not stop the recording
1466 1468 session
1467 1469
1468 1470 $ HGEDITOR=false hg commit -i <<EOF
1469 1471 > y
1470 1472 > e
1471 1473 > n
1472 1474 > EOF
1473 1475 diff --git a/editedfile b/editedfile
1474 1476 1 hunks, 3 lines changed
1475 1477 examine changes to 'editedfile'? [Ynesfdaq?] y
1476 1478
1477 1479 @@ -1,3 +1,3 @@
1478 1480 -This is the first line
1479 1481 -This change will be committed
1480 1482 -This is the third line
1481 1483 +This change will not be committed
1482 1484 +This is the second line
1483 1485 +This line has been added
1484 1486 record this change to 'editedfile'? [Ynesfdaq?] e
1485 1487
1486 1488 editor exited with exit code 1
1487 1489 record this change to 'editedfile'? [Ynesfdaq?] n
1488 1490
1489 1491 no changes to record
1492 [1]
1490 1493
1491 1494
1492 1495 random text in random positions is still an error
1493 1496
1494 1497 $ cat > editor.sh << '__EOF__'
1495 1498 > sed -e '/^@/i\
1496 1499 > other' "$1" > tmp
1497 1500 > mv tmp "$1"
1498 1501 > __EOF__
1499 1502 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i <<EOF
1500 1503 > y
1501 1504 > e
1502 1505 > EOF
1503 1506 diff --git a/editedfile b/editedfile
1504 1507 1 hunks, 3 lines changed
1505 1508 examine changes to 'editedfile'? [Ynesfdaq?] y
1506 1509
1507 1510 @@ -1,3 +1,3 @@
1508 1511 -This is the first line
1509 1512 -This change will be committed
1510 1513 -This is the third line
1511 1514 +This change will not be committed
1512 1515 +This is the second line
1513 1516 +This line has been added
1514 1517 record this change to 'editedfile'? [Ynesfdaq?] e
1515 1518
1516 1519 abort: error parsing patch: unhandled transition: file -> other
1517 1520 [255]
1518 1521
1519 1522 $ hg up -C
1520 1523 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1521 1524
1522 1525 With win32text
1523 1526
1524 1527 $ echo '[extensions]' >> .hg/hgrc
1525 1528 $ echo 'win32text = ' >> .hg/hgrc
1526 1529 $ echo '[decode]' >> .hg/hgrc
1527 1530 $ echo '** = cleverdecode:' >> .hg/hgrc
1528 1531 $ echo '[encode]' >> .hg/hgrc
1529 1532 $ echo '** = cleverencode:' >> .hg/hgrc
1530 1533 $ echo '[patch]' >> .hg/hgrc
1531 1534 $ echo 'eol = crlf' >> .hg/hgrc
1532 1535
1533 1536 Ignore win32text deprecation warning for now:
1534 1537
1535 1538 $ echo '[win32text]' >> .hg/hgrc
1536 1539 $ echo 'warn = no' >> .hg/hgrc
1537 1540
1538 1541 $ echo d >> subdir/f1
1539 1542 $ hg commit -i -d '24 0' -mw1 <<EOF
1540 1543 > y
1541 1544 > y
1542 1545 > EOF
1543 1546 diff --git a/subdir/f1 b/subdir/f1
1544 1547 1 hunks, 1 lines changed
1545 1548 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1546 1549
1547 1550 @@ -3,3 +3,4 @@ a
1548 1551 a
1549 1552 b
1550 1553 c
1551 1554 +d
1552 1555 record this change to 'subdir/f1'? [Ynesfdaq?] y
1553 1556
1554 1557
1555 1558 $ hg status -A subdir/f1
1556 1559 C subdir/f1
1557 1560 $ hg tip -p
1558 1561 changeset: 30:* (glob)
1559 1562 tag: tip
1560 1563 user: test
1561 1564 date: Thu Jan 01 00:00:24 1970 +0000
1562 1565 summary: w1
1563 1566
1564 1567 diff -r ???????????? -r ???????????? subdir/f1 (glob)
1565 1568 --- a/subdir/f1 Thu Jan 01 00:00:23 1970 +0000
1566 1569 +++ b/subdir/f1 Thu Jan 01 00:00:24 1970 +0000
1567 1570 @@ -3,3 +3,4 @@
1568 1571 a
1569 1572 b
1570 1573 c
1571 1574 +d
1572 1575
1573 1576
1574 1577
1575 1578 Test --user when ui.username not set
1576 1579 $ unset HGUSER
1577 1580 $ echo e >> subdir/f1
1578 1581 $ hg commit -i --config ui.username= -d '8 0' --user xyz -m "user flag" <<EOF
1579 1582 > y
1580 1583 > y
1581 1584 > EOF
1582 1585 diff --git a/subdir/f1 b/subdir/f1
1583 1586 1 hunks, 1 lines changed
1584 1587 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1585 1588
1586 1589 @@ -4,3 +4,4 @@ a
1587 1590 b
1588 1591 c
1589 1592 d
1590 1593 +e
1591 1594 record this change to 'subdir/f1'? [Ynesfdaq?] y
1592 1595
1593 1596 $ hg status -A subdir/f1
1594 1597 C subdir/f1
1595 1598 $ hg log --template '{author}\n' -l 1
1596 1599 xyz
1597 1600 $ HGUSER="test"
1598 1601 $ export HGUSER
1599 1602
1600 1603
1601 1604 Moving files
1602 1605
1603 1606 $ hg update -C .
1604 1607 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1605 1608 $ hg mv plain plain3
1606 1609 $ echo somechange >> plain3
1607 1610 $ hg commit -i -d '23 0' -mmoving_files << EOF
1608 1611 > y
1609 1612 > y
1610 1613 > EOF
1611 1614 diff --git a/plain b/plain3
1612 1615 rename from plain
1613 1616 rename to plain3
1614 1617 1 hunks, 1 lines changed
1615 1618 examine changes to 'plain' and 'plain3'? [Ynesfdaq?] y
1616 1619
1617 1620 @@ -11,3 +11,4 @@ 8
1618 1621 9
1619 1622 10
1620 1623 11
1621 1624 +somechange
1622 1625 record this change to 'plain3'? [Ynesfdaq?] y
1623 1626
1624 1627 The #if execbit block above changes the hash here on some systems
1625 1628 $ hg status -A plain3
1626 1629 C plain3
1627 1630 $ hg tip
1628 1631 changeset: 32:* (glob)
1629 1632 tag: tip
1630 1633 user: test
1631 1634 date: Thu Jan 01 00:00:23 1970 +0000
1632 1635 summary: moving_files
1633 1636
1634 1637 Editing patch of newly added file
1635 1638
1636 1639 $ hg update -C .
1637 1640 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1638 1641 $ cat > editor.sh << '__EOF__'
1639 1642 > cat "$1" | sed "s/first/very/g" > tt
1640 1643 > mv tt "$1"
1641 1644 > __EOF__
1642 1645 $ cat > newfile << '__EOF__'
1643 1646 > This is the first line
1644 1647 > This is the second line
1645 1648 > This is the third line
1646 1649 > __EOF__
1647 1650 $ hg add newfile
1648 1651 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i -d '23 0' -medit-patch-new <<EOF
1649 1652 > y
1650 1653 > e
1651 1654 > EOF
1652 1655 diff --git a/newfile b/newfile
1653 1656 new file mode 100644
1654 1657 examine changes to 'newfile'? [Ynesfdaq?] y
1655 1658
1656 1659 @@ -0,0 +1,3 @@
1657 1660 +This is the first line
1658 1661 +This is the second line
1659 1662 +This is the third line
1660 1663 record this change to 'newfile'? [Ynesfdaq?] e
1661 1664
1662 1665 $ hg cat -r tip newfile
1663 1666 This is the very line
1664 1667 This is the second line
1665 1668 This is the third line
1666 1669
1667 1670 $ cat newfile
1668 1671 This is the first line
1669 1672 This is the second line
1670 1673 This is the third line
1671 1674
1672 1675 Add new file from within a subdirectory
1673 1676 $ hg update -C .
1674 1677 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1675 1678 $ mkdir folder
1676 1679 $ cd folder
1677 1680 $ echo "foo" > bar
1678 1681 $ hg add bar
1679 1682 $ hg commit -i -d '23 0' -mnewfilesubdir <<EOF
1680 1683 > y
1681 1684 > y
1682 1685 > EOF
1683 1686 diff --git a/folder/bar b/folder/bar
1684 1687 new file mode 100644
1685 1688 examine changes to 'folder/bar'? [Ynesfdaq?] y
1686 1689
1687 1690 @@ -0,0 +1,1 @@
1688 1691 +foo
1689 1692 record this change to 'folder/bar'? [Ynesfdaq?] y
1690 1693
1691 1694 The #if execbit block above changes the hashes here on some systems
1692 1695 $ hg tip -p
1693 1696 changeset: 34:* (glob)
1694 1697 tag: tip
1695 1698 user: test
1696 1699 date: Thu Jan 01 00:00:23 1970 +0000
1697 1700 summary: newfilesubdir
1698 1701
1699 1702 diff -r * -r * folder/bar (glob)
1700 1703 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1701 1704 +++ b/folder/bar Thu Jan 01 00:00:23 1970 +0000
1702 1705 @@ -0,0 +1,1 @@
1703 1706 +foo
1704 1707
1705 1708 $ cd ..
1706 1709
1707 1710 $ hg status -A folder/bar
1708 1711 C folder/bar
1709 1712
1710 1713 Clear win32text configuration before size/timestamp sensitive test
1711 1714
1712 1715 $ cat >> .hg/hgrc <<EOF
1713 1716 > [extensions]
1714 1717 > win32text = !
1715 1718 > [decode]
1716 1719 > ** = !
1717 1720 > [encode]
1718 1721 > ** = !
1719 1722 > [patch]
1720 1723 > eol = strict
1721 1724 > EOF
1722 1725 $ hg update -q -C null
1723 1726 $ hg update -q -C tip
1724 1727
1725 1728 Test that partially committed file is still treated as "modified",
1726 1729 even if none of mode, size and timestamp is changed on the filesystem
1727 1730 (see also issue4583).
1728 1731
1729 1732 $ cat > subdir/f1 <<EOF
1730 1733 > A
1731 1734 > a
1732 1735 > a
1733 1736 > b
1734 1737 > c
1735 1738 > d
1736 1739 > E
1737 1740 > EOF
1738 1741 $ hg diff --git subdir/f1
1739 1742 diff --git a/subdir/f1 b/subdir/f1
1740 1743 --- a/subdir/f1
1741 1744 +++ b/subdir/f1
1742 1745 @@ -1,7 +1,7 @@
1743 1746 -a
1744 1747 +A
1745 1748 a
1746 1749 a
1747 1750 b
1748 1751 c
1749 1752 d
1750 1753 -e
1751 1754 +E
1752 1755
1753 1756 $ touch -t 200001010000 subdir/f1
1754 1757
1755 1758 $ cat >> .hg/hgrc <<EOF
1756 1759 > # emulate invoking patch.internalpatch() at 2000-01-01 00:00
1757 1760 > [fakepatchtime]
1758 1761 > fakenow = 200001010000
1759 1762 >
1760 1763 > [extensions]
1761 1764 > fakepatchtime = $TESTDIR/fakepatchtime.py
1762 1765 > EOF
1763 1766 $ hg commit -i -m 'commit subdir/f1 partially' <<EOF
1764 1767 > y
1765 1768 > y
1766 1769 > n
1767 1770 > EOF
1768 1771 diff --git a/subdir/f1 b/subdir/f1
1769 1772 2 hunks, 2 lines changed
1770 1773 examine changes to 'subdir/f1'? [Ynesfdaq?] y
1771 1774
1772 1775 @@ -1,6 +1,6 @@
1773 1776 -a
1774 1777 +A
1775 1778 a
1776 1779 a
1777 1780 b
1778 1781 c
1779 1782 d
1780 1783 record change 1/2 to 'subdir/f1'? [Ynesfdaq?] y
1781 1784
1782 1785 @@ -2,6 +2,6 @@
1783 1786 a
1784 1787 a
1785 1788 b
1786 1789 c
1787 1790 d
1788 1791 -e
1789 1792 +E
1790 1793 record change 2/2 to 'subdir/f1'? [Ynesfdaq?] n
1791 1794
1792 1795 $ cat >> .hg/hgrc <<EOF
1793 1796 > [extensions]
1794 1797 > fakepatchtime = !
1795 1798 > EOF
1796 1799
1797 1800 $ hg debugstate | grep ' subdir/f1$'
1798 1801 n 0 -1 unset subdir/f1
1799 1802 $ hg status -A subdir/f1
1800 1803 M subdir/f1
General Comments 0
You need to be logged in to leave comments. Login now