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