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