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