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