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