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