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