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