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