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