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