##// END OF EJS Templates
bisect with command: ability to skip revision or abort bisection
Alexander Solovyov -
r7228:9b72c732 default
parent child Browse files
Show More
@@ -1,3364 +1,3374 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
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from node import hex, nullid, nullrev, short
9 9 from repo import RepoError, NoCapability
10 10 from i18n import _, gettext
11 11 import os, re, sys, urllib
12 12 import hg, util, revlog, bundlerepo, extensions, copies
13 13 import difflib, patch, time, help, mdiff, tempfile
14 14 import version, socket
15 15 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
16 16 import merge as merge_
17 17
18 18 # Commands start here, listed alphabetically
19 19
20 20 def add(ui, repo, *pats, **opts):
21 21 """add the specified files on the next commit
22 22
23 23 Schedule files to be version controlled and added to the repository.
24 24
25 25 The files will be added to the repository at the next commit. To
26 26 undo an add before that, see hg revert.
27 27
28 28 If no names are given, add all files in the repository.
29 29 """
30 30
31 31 rejected = None
32 32 exacts = {}
33 33 names = []
34 34 m = cmdutil.match(repo, pats, opts)
35 35 m.bad = lambda x,y: True
36 36 for abs in repo.walk(m):
37 37 if m.exact(abs):
38 38 if ui.verbose:
39 39 ui.status(_('adding %s\n') % m.rel(abs))
40 40 names.append(abs)
41 41 exacts[abs] = 1
42 42 elif abs not in repo.dirstate:
43 43 ui.status(_('adding %s\n') % m.rel(abs))
44 44 names.append(abs)
45 45 if not opts.get('dry_run'):
46 46 rejected = repo.add(names)
47 47 rejected = [p for p in rejected if p in exacts]
48 48 return rejected and 1 or 0
49 49
50 50 def addremove(ui, repo, *pats, **opts):
51 51 """add all new files, delete all missing files
52 52
53 53 Add all new files and remove all missing files from the repository.
54 54
55 55 New files are ignored if they match any of the patterns in .hgignore. As
56 56 with add, these changes take effect at the next commit.
57 57
58 58 Use the -s option to detect renamed files. With a parameter > 0,
59 59 this compares every removed file with every added file and records
60 60 those similar enough as renames. This option takes a percentage
61 61 between 0 (disabled) and 100 (files must be identical) as its
62 62 parameter. Detecting renamed files this way can be expensive.
63 63 """
64 64 try:
65 65 sim = float(opts.get('similarity') or 0)
66 66 except ValueError:
67 67 raise util.Abort(_('similarity must be a number'))
68 68 if sim < 0 or sim > 100:
69 69 raise util.Abort(_('similarity must be between 0 and 100'))
70 70 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
71 71
72 72 def annotate(ui, repo, *pats, **opts):
73 73 """show changeset information per file line
74 74
75 75 List changes in files, showing the revision id responsible for each line
76 76
77 77 This command is useful to discover who did a change or when a change took
78 78 place.
79 79
80 80 Without the -a option, annotate will avoid processing files it
81 81 detects as binary. With -a, annotate will generate an annotation
82 82 anyway, probably with undesirable results.
83 83 """
84 84 datefunc = ui.quiet and util.shortdate or util.datestr
85 85 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
86 86
87 87 if not pats:
88 88 raise util.Abort(_('at least one file name or pattern required'))
89 89
90 90 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
91 91 ('number', lambda x: str(x[0].rev())),
92 92 ('changeset', lambda x: short(x[0].node())),
93 93 ('date', getdate),
94 94 ('follow', lambda x: x[0].path()),
95 95 ]
96 96
97 97 if (not opts.get('user') and not opts.get('changeset') and not opts.get('date')
98 98 and not opts.get('follow')):
99 99 opts['number'] = 1
100 100
101 101 linenumber = opts.get('line_number') is not None
102 102 if (linenumber and (not opts.get('changeset')) and (not opts.get('number'))):
103 103 raise util.Abort(_('at least one of -n/-c is required for -l'))
104 104
105 105 funcmap = [func for op, func in opmap if opts.get(op)]
106 106 if linenumber:
107 107 lastfunc = funcmap[-1]
108 108 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
109 109
110 110 ctx = repo[opts.get('rev')]
111 111
112 112 m = cmdutil.match(repo, pats, opts)
113 113 for abs in ctx.walk(m):
114 114 fctx = ctx[abs]
115 115 if not opts.get('text') and util.binary(fctx.data()):
116 116 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
117 117 continue
118 118
119 119 lines = fctx.annotate(follow=opts.get('follow'),
120 120 linenumber=linenumber)
121 121 pieces = []
122 122
123 123 for f in funcmap:
124 124 l = [f(n) for n, dummy in lines]
125 125 if l:
126 126 ml = max(map(len, l))
127 127 pieces.append(["%*s" % (ml, x) for x in l])
128 128
129 129 if pieces:
130 130 for p, l in zip(zip(*pieces), lines):
131 131 ui.write("%s: %s" % (" ".join(p), l[1]))
132 132
133 133 def archive(ui, repo, dest, **opts):
134 134 '''create unversioned archive of a repository revision
135 135
136 136 By default, the revision used is the parent of the working
137 137 directory; use "-r" to specify a different revision.
138 138
139 139 To specify the type of archive to create, use "-t". Valid
140 140 types are:
141 141
142 142 "files" (default): a directory full of files
143 143 "tar": tar archive, uncompressed
144 144 "tbz2": tar archive, compressed using bzip2
145 145 "tgz": tar archive, compressed using gzip
146 146 "uzip": zip archive, uncompressed
147 147 "zip": zip archive, compressed using deflate
148 148
149 149 The exact name of the destination archive or directory is given
150 150 using a format string; see "hg help export" for details.
151 151
152 152 Each member added to an archive file has a directory prefix
153 153 prepended. Use "-p" to specify a format string for the prefix.
154 154 The default is the basename of the archive, with suffixes removed.
155 155 '''
156 156
157 157 ctx = repo[opts.get('rev')]
158 158 if not ctx:
159 159 raise util.Abort(_('repository has no revisions'))
160 160 node = ctx.node()
161 161 dest = cmdutil.make_filename(repo, dest, node)
162 162 if os.path.realpath(dest) == repo.root:
163 163 raise util.Abort(_('repository root cannot be destination'))
164 164 matchfn = cmdutil.match(repo, [], opts)
165 165 kind = opts.get('type') or 'files'
166 166 prefix = opts.get('prefix')
167 167 if dest == '-':
168 168 if kind == 'files':
169 169 raise util.Abort(_('cannot archive plain files to stdout'))
170 170 dest = sys.stdout
171 171 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
172 172 prefix = cmdutil.make_filename(repo, prefix, node)
173 173 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
174 174 matchfn, prefix)
175 175
176 176 def backout(ui, repo, node=None, rev=None, **opts):
177 177 '''reverse effect of earlier changeset
178 178
179 179 Commit the backed out changes as a new changeset. The new
180 180 changeset is a child of the backed out changeset.
181 181
182 182 If you back out a changeset other than the tip, a new head is
183 183 created. This head will be the new tip and you should merge this
184 184 backout changeset with another head (current one by default).
185 185
186 186 The --merge option remembers the parent of the working directory
187 187 before starting the backout, then merges the new head with that
188 188 changeset afterwards. This saves you from doing the merge by
189 189 hand. The result of this merge is not committed, as for a normal
190 190 merge.
191 191
192 192 See \'hg help dates\' for a list of formats valid for -d/--date.
193 193 '''
194 194 if rev and node:
195 195 raise util.Abort(_("please specify just one revision"))
196 196
197 197 if not rev:
198 198 rev = node
199 199
200 200 if not rev:
201 201 raise util.Abort(_("please specify a revision to backout"))
202 202
203 203 date = opts.get('date')
204 204 if date:
205 205 opts['date'] = util.parsedate(date)
206 206
207 207 cmdutil.bail_if_changed(repo)
208 208 node = repo.lookup(rev)
209 209
210 210 op1, op2 = repo.dirstate.parents()
211 211 a = repo.changelog.ancestor(op1, node)
212 212 if a != node:
213 213 raise util.Abort(_('cannot back out change on a different branch'))
214 214
215 215 p1, p2 = repo.changelog.parents(node)
216 216 if p1 == nullid:
217 217 raise util.Abort(_('cannot back out a change with no parents'))
218 218 if p2 != nullid:
219 219 if not opts.get('parent'):
220 220 raise util.Abort(_('cannot back out a merge changeset without '
221 221 '--parent'))
222 222 p = repo.lookup(opts['parent'])
223 223 if p not in (p1, p2):
224 224 raise util.Abort(_('%s is not a parent of %s') %
225 225 (short(p), short(node)))
226 226 parent = p
227 227 else:
228 228 if opts.get('parent'):
229 229 raise util.Abort(_('cannot use --parent on non-merge changeset'))
230 230 parent = p1
231 231
232 232 # the backout should appear on the same branch
233 233 branch = repo.dirstate.branch()
234 234 hg.clean(repo, node, show_stats=False)
235 235 repo.dirstate.setbranch(branch)
236 236 revert_opts = opts.copy()
237 237 revert_opts['date'] = None
238 238 revert_opts['all'] = True
239 239 revert_opts['rev'] = hex(parent)
240 240 revert_opts['no_backup'] = None
241 241 revert(ui, repo, **revert_opts)
242 242 commit_opts = opts.copy()
243 243 commit_opts['addremove'] = False
244 244 if not commit_opts['message'] and not commit_opts['logfile']:
245 245 commit_opts['message'] = _("Backed out changeset %s") % (short(node))
246 246 commit_opts['force_editor'] = True
247 247 commit(ui, repo, **commit_opts)
248 248 def nice(node):
249 249 return '%d:%s' % (repo.changelog.rev(node), short(node))
250 250 ui.status(_('changeset %s backs out changeset %s\n') %
251 251 (nice(repo.changelog.tip()), nice(node)))
252 252 if op1 != node:
253 253 hg.clean(repo, op1, show_stats=False)
254 254 if opts.get('merge'):
255 255 ui.status(_('merging with changeset %s\n') % nice(repo.changelog.tip()))
256 256 hg.merge(repo, hex(repo.changelog.tip()))
257 257 else:
258 258 ui.status(_('the backout changeset is a new head - '
259 259 'do not forget to merge\n'))
260 260 ui.status(_('(use "backout --merge" '
261 261 'if you want to auto-merge)\n'))
262 262
263 263 def bisect(ui, repo, rev=None, extra=None, command=None,
264 264 reset=None, good=None, bad=None, skip=None, noupdate=None):
265 265 """subdivision search of changesets
266 266
267 267 This command helps to find changesets which introduce problems.
268 268 To use, mark the earliest changeset you know exhibits the problem
269 269 as bad, then mark the latest changeset which is free from the
270 270 problem as good. Bisect will update your working directory to a
271 271 revision for testing (unless the --noupdate option is specified).
272 272 Once you have performed tests, mark the working directory as bad
273 273 or good and bisect will either update to another candidate changeset
274 274 or announce that it has found the bad revision.
275 275
276 276 As a shortcut, you can also use the revision argument to mark a
277 277 revision as good or bad without checking it out first.
278 278
279 If you supply a command it will be used for automatic bisection. Its
280 exit status will be used as flag to mark revision as bad or good (good
281 in case of 0 and bad in any other case).
279 If you supply a command it will be used for automatic bisection. Its exit
280 status will be used as flag to mark revision as bad or good. In case exit
281 status is 0 the revision is marked as good, 125 - skipped, 127 (command not
282 found) - bisection will be aborted and any other status bigger than 0 will
283 mark revision as bad.
282 284 """
283 285 def print_result(nodes, good):
284 286 displayer = cmdutil.show_changeset(ui, repo, {})
285 287 transition = (good and "good" or "bad")
286 288 if len(nodes) == 1:
287 289 # narrowed it down to a single revision
288 290 ui.write(_("The first %s revision is:\n") % transition)
289 291 displayer.show(changenode=nodes[0])
290 292 else:
291 293 # multiple possible revisions
292 294 ui.write(_("Due to skipped revisions, the first "
293 295 "%s revision could be any of:\n") % transition)
294 296 for n in nodes:
295 297 displayer.show(changenode=n)
296 298
297 299 def check_state(state, interactive=True):
298 300 if not state['good'] or not state['bad']:
299 301 if (good or bad or skip or reset) and interactive:
300 302 return
301 303 if not state['good']:
302 304 raise util.Abort(_('cannot bisect (no known good revisions)'))
303 305 else:
304 306 raise util.Abort(_('cannot bisect (no known bad revisions)'))
305 307 return True
306 308
307 309 # backward compatibility
308 310 if rev in "good bad reset init".split():
309 311 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
310 312 cmd, rev, extra = rev, extra, None
311 313 if cmd == "good":
312 314 good = True
313 315 elif cmd == "bad":
314 316 bad = True
315 317 else:
316 318 reset = True
317 319 elif extra or good + bad + skip + reset + bool(command) > 1:
318 320 raise util.Abort(_('incompatible arguments'))
319 321
320 322 if reset:
321 323 p = repo.join("bisect.state")
322 324 if os.path.exists(p):
323 325 os.unlink(p)
324 326 return
325 327
326 328 state = hbisect.load_state(repo)
327 329
328 330 if command:
329 331 changesets = 1
330 332 while changesets:
331 # check state
332 status = bool(list(os.popen3(command)[2]))
333 # update state
334 status = os.spawnlp(os.P_WAIT, command)
333 335 node = repo.lookup(rev or '.')
334 transition = (status and 'bad' or 'good')
336 if status == 125:
337 transition = "skip"
338 elif status == 0:
339 transition = "good"
340 # status < 0 means process was killed
341 elif status == 127 or status < 0:
342 break
343 else:
344 transition = "bad"
335 345 state[transition].append(node)
336 346 ui.note(_('Changeset %s: %s\n') % (short(node), transition))
337 347 check_state(state, interactive=False)
338 348 # bisect
339 349 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
340 350 # update to next check
341 351 cmdutil.bail_if_changed(repo)
342 352 hg.clean(repo, nodes[0], show_stats=False)
343 353 hbisect.save_state(repo, state)
344 354 return print_result(nodes, not status)
345 355
346 356 # update state
347 357 node = repo.lookup(rev or '.')
348 358 if good:
349 359 state['good'].append(node)
350 360 elif bad:
351 361 state['bad'].append(node)
352 362 elif skip:
353 363 state['skip'].append(node)
354 364
355 365 hbisect.save_state(repo, state)
356 366
357 367 if not check_state(state):
358 368 return
359 369
360 370 # actually bisect
361 371 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
362 372 if changesets == 0:
363 373 print_result(nodes, good)
364 374 else:
365 375 assert len(nodes) == 1 # only a single node can be tested next
366 376 node = nodes[0]
367 377 # compute the approximate number of remaining tests
368 378 tests, size = 0, 2
369 379 while size <= changesets:
370 380 tests, size = tests + 1, size * 2
371 381 rev = repo.changelog.rev(node)
372 382 ui.write(_("Testing changeset %s:%s "
373 383 "(%s changesets remaining, ~%s tests)\n")
374 384 % (rev, short(node), changesets, tests))
375 385 if not noupdate:
376 386 cmdutil.bail_if_changed(repo)
377 387 return hg.clean(repo, node)
378 388
379 389 def branch(ui, repo, label=None, **opts):
380 390 """set or show the current branch name
381 391
382 392 With no argument, show the current branch name. With one argument,
383 393 set the working directory branch name (the branch does not exist in
384 394 the repository until the next commit).
385 395
386 396 Unless --force is specified, branch will not let you set a
387 397 branch name that shadows an existing branch.
388 398
389 399 Use --clean to reset the working directory branch to that of the
390 400 parent of the working directory, negating a previous branch change.
391 401
392 402 Use the command 'hg update' to switch to an existing branch.
393 403 """
394 404
395 405 if opts.get('clean'):
396 406 label = repo[None].parents()[0].branch()
397 407 repo.dirstate.setbranch(label)
398 408 ui.status(_('reset working directory to branch %s\n') % label)
399 409 elif label:
400 410 if not opts.get('force') and label in repo.branchtags():
401 411 if label not in [p.branch() for p in repo.parents()]:
402 412 raise util.Abort(_('a branch of the same name already exists'
403 413 ' (use --force to override)'))
404 414 repo.dirstate.setbranch(util.fromlocal(label))
405 415 ui.status(_('marked working directory as branch %s\n') % label)
406 416 else:
407 417 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
408 418
409 419 def branches(ui, repo, active=False):
410 420 """list repository named branches
411 421
412 422 List the repository's named branches, indicating which ones are
413 423 inactive. If active is specified, only show active branches.
414 424
415 425 A branch is considered active if it contains repository heads.
416 426
417 427 Use the command 'hg update' to switch to an existing branch.
418 428 """
419 429 hexfunc = ui.debugflag and hex or short
420 430 activebranches = [util.tolocal(repo[n].branch())
421 431 for n in repo.heads()]
422 432 branches = util.sort([(tag in activebranches, repo.changelog.rev(node), tag)
423 433 for tag, node in repo.branchtags().items()])
424 434 branches.reverse()
425 435
426 436 for isactive, node, tag in branches:
427 437 if (not active) or isactive:
428 438 if ui.quiet:
429 439 ui.write("%s\n" % tag)
430 440 else:
431 441 rev = str(node).rjust(31 - util.locallen(tag))
432 442 isinactive = ((not isactive) and " (inactive)") or ''
433 443 data = tag, rev, hexfunc(repo.lookup(node)), isinactive
434 444 ui.write("%s %s:%s%s\n" % data)
435 445
436 446 def bundle(ui, repo, fname, dest=None, **opts):
437 447 """create a changegroup file
438 448
439 449 Generate a compressed changegroup file collecting changesets not
440 450 found in the other repository.
441 451
442 452 If no destination repository is specified the destination is
443 453 assumed to have all the nodes specified by one or more --base
444 454 parameters. To create a bundle containing all changesets, use
445 455 --all (or --base null). To change the compression method applied,
446 456 use the -t option (by default, bundles are compressed using bz2).
447 457
448 458 The bundle file can then be transferred using conventional means and
449 459 applied to another repository with the unbundle or pull command.
450 460 This is useful when direct push and pull are not available or when
451 461 exporting an entire repository is undesirable.
452 462
453 463 Applying bundles preserves all changeset contents including
454 464 permissions, copy/rename information, and revision history.
455 465 """
456 466 revs = opts.get('rev') or None
457 467 if revs:
458 468 revs = [repo.lookup(rev) for rev in revs]
459 469 if opts.get('all'):
460 470 base = ['null']
461 471 else:
462 472 base = opts.get('base')
463 473 if base:
464 474 if dest:
465 475 raise util.Abort(_("--base is incompatible with specifiying "
466 476 "a destination"))
467 477 base = [repo.lookup(rev) for rev in base]
468 478 # create the right base
469 479 # XXX: nodesbetween / changegroup* should be "fixed" instead
470 480 o = []
471 481 has = {nullid: None}
472 482 for n in base:
473 483 has.update(repo.changelog.reachable(n))
474 484 if revs:
475 485 visit = list(revs)
476 486 else:
477 487 visit = repo.changelog.heads()
478 488 seen = {}
479 489 while visit:
480 490 n = visit.pop(0)
481 491 parents = [p for p in repo.changelog.parents(n) if p not in has]
482 492 if len(parents) == 0:
483 493 o.insert(0, n)
484 494 else:
485 495 for p in parents:
486 496 if p not in seen:
487 497 seen[p] = 1
488 498 visit.append(p)
489 499 else:
490 500 cmdutil.setremoteconfig(ui, opts)
491 501 dest, revs, checkout = hg.parseurl(
492 502 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
493 503 other = hg.repository(ui, dest)
494 504 o = repo.findoutgoing(other, force=opts.get('force'))
495 505
496 506 if revs:
497 507 cg = repo.changegroupsubset(o, revs, 'bundle')
498 508 else:
499 509 cg = repo.changegroup(o, 'bundle')
500 510
501 511 bundletype = opts.get('type', 'bzip2').lower()
502 512 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
503 513 bundletype = btypes.get(bundletype)
504 514 if bundletype not in changegroup.bundletypes:
505 515 raise util.Abort(_('unknown bundle type specified with --type'))
506 516
507 517 changegroup.writebundle(cg, fname, bundletype)
508 518
509 519 def cat(ui, repo, file1, *pats, **opts):
510 520 """output the current or given revision of files
511 521
512 522 Print the specified files as they were at the given revision.
513 523 If no revision is given, the parent of the working directory is used,
514 524 or tip if no revision is checked out.
515 525
516 526 Output may be to a file, in which case the name of the file is
517 527 given using a format string. The formatting rules are the same as
518 528 for the export command, with the following additions:
519 529
520 530 %s basename of file being printed
521 531 %d dirname of file being printed, or '.' if in repo root
522 532 %p root-relative path name of file being printed
523 533 """
524 534 ctx = repo[opts.get('rev')]
525 535 err = 1
526 536 m = cmdutil.match(repo, (file1,) + pats, opts)
527 537 for abs in ctx.walk(m):
528 538 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
529 539 data = ctx[abs].data()
530 540 if opts.get('decode'):
531 541 data = repo.wwritedata(abs, data)
532 542 fp.write(data)
533 543 err = 0
534 544 return err
535 545
536 546 def clone(ui, source, dest=None, **opts):
537 547 """make a copy of an existing repository
538 548
539 549 Create a copy of an existing repository in a new directory.
540 550
541 551 If no destination directory name is specified, it defaults to the
542 552 basename of the source.
543 553
544 554 The location of the source is added to the new repository's
545 555 .hg/hgrc file, as the default to be used for future pulls.
546 556
547 557 For efficiency, hardlinks are used for cloning whenever the source
548 558 and destination are on the same filesystem (note this applies only
549 559 to the repository data, not to the checked out files). Some
550 560 filesystems, such as AFS, implement hardlinking incorrectly, but
551 561 do not report errors. In these cases, use the --pull option to
552 562 avoid hardlinking.
553 563
554 564 In some cases, you can clone repositories and checked out files
555 565 using full hardlinks with
556 566
557 567 $ cp -al REPO REPOCLONE
558 568
559 569 This is the fastest way to clone, but it is not always safe. The
560 570 operation is not atomic (making sure REPO is not modified during
561 571 the operation is up to you) and you have to make sure your editor
562 572 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
563 573 this is not compatible with certain extensions that place their
564 574 metadata under the .hg directory, such as mq.
565 575
566 576 If you use the -r option to clone up to a specific revision, no
567 577 subsequent revisions will be present in the cloned repository.
568 578 This option implies --pull, even on local repositories.
569 579
570 580 If the -U option is used, the new clone will contain only a repository
571 581 (.hg) and no working copy (the working copy parent is the null revision).
572 582
573 583 See pull for valid source format details.
574 584
575 585 It is possible to specify an ssh:// URL as the destination, but no
576 586 .hg/hgrc and working directory will be created on the remote side.
577 587 Look at the help text for the pull command for important details
578 588 about ssh:// URLs.
579 589 """
580 590 cmdutil.setremoteconfig(ui, opts)
581 591 hg.clone(ui, source, dest,
582 592 pull=opts.get('pull'),
583 593 stream=opts.get('uncompressed'),
584 594 rev=opts.get('rev'),
585 595 update=not opts.get('noupdate'))
586 596
587 597 def commit(ui, repo, *pats, **opts):
588 598 """commit the specified files or all outstanding changes
589 599
590 600 Commit changes to the given files into the repository.
591 601
592 602 If a list of files is omitted, all changes reported by "hg status"
593 603 will be committed.
594 604
595 605 If you are committing the result of a merge, do not provide any
596 606 file names or -I/-X filters.
597 607
598 608 If no commit message is specified, the configured editor is started to
599 609 enter a message.
600 610
601 611 See 'hg help dates' for a list of formats valid for -d/--date.
602 612 """
603 613 def commitfunc(ui, repo, message, match, opts):
604 614 return repo.commit(match.files(), message, opts.get('user'), opts.get('date'),
605 615 match, force_editor=opts.get('force_editor'))
606 616
607 617 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
608 618 if not node:
609 619 return
610 620 cl = repo.changelog
611 621 rev = cl.rev(node)
612 622 parents = cl.parentrevs(rev)
613 623 if rev - 1 in parents:
614 624 # one of the parents was the old tip
615 625 pass
616 626 elif (parents == (nullrev, nullrev) or
617 627 len(cl.heads(cl.node(parents[0]))) > 1 and
618 628 (parents[1] == nullrev or len(cl.heads(cl.node(parents[1]))) > 1)):
619 629 ui.status(_('created new head\n'))
620 630
621 631 if ui.debugflag:
622 632 ui.write(_('committed changeset %d:%s\n') % (rev,hex(node)))
623 633 elif ui.verbose:
624 634 ui.write(_('committed changeset %d:%s\n') % (rev,short(node)))
625 635
626 636 def copy(ui, repo, *pats, **opts):
627 637 """mark files as copied for the next commit
628 638
629 639 Mark dest as having copies of source files. If dest is a
630 640 directory, copies are put in that directory. If dest is a file,
631 641 there can only be one source.
632 642
633 643 By default, this command copies the contents of files as they
634 644 stand in the working directory. If invoked with --after, the
635 645 operation is recorded, but no copying is performed.
636 646
637 647 This command takes effect in the next commit. To undo a copy
638 648 before that, see hg revert.
639 649 """
640 650 wlock = repo.wlock(False)
641 651 try:
642 652 return cmdutil.copy(ui, repo, pats, opts)
643 653 finally:
644 654 del wlock
645 655
646 656 def debugancestor(ui, repo, *args):
647 657 """find the ancestor revision of two revisions in a given index"""
648 658 if len(args) == 3:
649 659 index, rev1, rev2 = args
650 660 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
651 661 lookup = r.lookup
652 662 elif len(args) == 2:
653 663 if not repo:
654 664 raise util.Abort(_("There is no Mercurial repository here "
655 665 "(.hg not found)"))
656 666 rev1, rev2 = args
657 667 r = repo.changelog
658 668 lookup = repo.lookup
659 669 else:
660 670 raise util.Abort(_('either two or three arguments required'))
661 671 a = r.ancestor(lookup(rev1), lookup(rev2))
662 672 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
663 673
664 674 def debugcomplete(ui, cmd='', **opts):
665 675 """returns the completion list associated with the given command"""
666 676
667 677 if opts.get('options'):
668 678 options = []
669 679 otables = [globalopts]
670 680 if cmd:
671 681 aliases, entry = cmdutil.findcmd(cmd, table, False)
672 682 otables.append(entry[1])
673 683 for t in otables:
674 684 for o in t:
675 685 if o[0]:
676 686 options.append('-%s' % o[0])
677 687 options.append('--%s' % o[1])
678 688 ui.write("%s\n" % "\n".join(options))
679 689 return
680 690
681 691 ui.write("%s\n" % "\n".join(util.sort(cmdutil.findpossible(cmd, table))))
682 692
683 693 def debugfsinfo(ui, path = "."):
684 694 file('.debugfsinfo', 'w').write('')
685 695 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
686 696 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
687 697 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
688 698 and 'yes' or 'no'))
689 699 os.unlink('.debugfsinfo')
690 700
691 701 def debugrebuildstate(ui, repo, rev="tip"):
692 702 """rebuild the dirstate as it would look like for the given revision"""
693 703 ctx = repo[rev]
694 704 wlock = repo.wlock()
695 705 try:
696 706 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
697 707 finally:
698 708 del wlock
699 709
700 710 def debugcheckstate(ui, repo):
701 711 """validate the correctness of the current dirstate"""
702 712 parent1, parent2 = repo.dirstate.parents()
703 713 m1 = repo[parent1].manifest()
704 714 m2 = repo[parent2].manifest()
705 715 errors = 0
706 716 for f in repo.dirstate:
707 717 state = repo.dirstate[f]
708 718 if state in "nr" and f not in m1:
709 719 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
710 720 errors += 1
711 721 if state in "a" and f in m1:
712 722 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
713 723 errors += 1
714 724 if state in "m" and f not in m1 and f not in m2:
715 725 ui.warn(_("%s in state %s, but not in either manifest\n") %
716 726 (f, state))
717 727 errors += 1
718 728 for f in m1:
719 729 state = repo.dirstate[f]
720 730 if state not in "nrm":
721 731 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
722 732 errors += 1
723 733 if errors:
724 734 error = _(".hg/dirstate inconsistent with current parent's manifest")
725 735 raise util.Abort(error)
726 736
727 737 def showconfig(ui, repo, *values, **opts):
728 738 """show combined config settings from all hgrc files
729 739
730 740 With no args, print names and values of all config items.
731 741
732 742 With one arg of the form section.name, print just the value of
733 743 that config item.
734 744
735 745 With multiple args, print names and values of all config items
736 746 with matching section names."""
737 747
738 748 untrusted = bool(opts.get('untrusted'))
739 749 if values:
740 750 if len([v for v in values if '.' in v]) > 1:
741 751 raise util.Abort(_('only one config item permitted'))
742 752 for section, name, value in ui.walkconfig(untrusted=untrusted):
743 753 sectname = section + '.' + name
744 754 if values:
745 755 for v in values:
746 756 if v == section:
747 757 ui.write('%s=%s\n' % (sectname, value))
748 758 elif v == sectname:
749 759 ui.write(value, '\n')
750 760 else:
751 761 ui.write('%s=%s\n' % (sectname, value))
752 762
753 763 def debugsetparents(ui, repo, rev1, rev2=None):
754 764 """manually set the parents of the current working directory
755 765
756 766 This is useful for writing repository conversion tools, but should
757 767 be used with care.
758 768 """
759 769
760 770 if not rev2:
761 771 rev2 = hex(nullid)
762 772
763 773 wlock = repo.wlock()
764 774 try:
765 775 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
766 776 finally:
767 777 del wlock
768 778
769 779 def debugstate(ui, repo, nodates=None):
770 780 """show the contents of the current dirstate"""
771 781 timestr = ""
772 782 showdate = not nodates
773 783 for file_, ent in util.sort(repo.dirstate._map.items()):
774 784 if showdate:
775 785 if ent[3] == -1:
776 786 # Pad or slice to locale representation
777 787 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(0)))
778 788 timestr = 'unset'
779 789 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
780 790 else:
781 791 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(ent[3]))
782 792 if ent[1] & 020000:
783 793 mode = 'lnk'
784 794 else:
785 795 mode = '%3o' % (ent[1] & 0777)
786 796 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
787 797 for f in repo.dirstate.copies():
788 798 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
789 799
790 800 def debugdata(ui, file_, rev):
791 801 """dump the contents of a data file revision"""
792 802 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
793 803 try:
794 804 ui.write(r.revision(r.lookup(rev)))
795 805 except KeyError:
796 806 raise util.Abort(_('invalid revision identifier %s') % rev)
797 807
798 808 def debugdate(ui, date, range=None, **opts):
799 809 """parse and display a date"""
800 810 if opts["extended"]:
801 811 d = util.parsedate(date, util.extendeddateformats)
802 812 else:
803 813 d = util.parsedate(date)
804 814 ui.write("internal: %s %s\n" % d)
805 815 ui.write("standard: %s\n" % util.datestr(d))
806 816 if range:
807 817 m = util.matchdate(range)
808 818 ui.write("match: %s\n" % m(d[0]))
809 819
810 820 def debugindex(ui, file_):
811 821 """dump the contents of an index file"""
812 822 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
813 823 ui.write(" rev offset length base linkrev" +
814 824 " nodeid p1 p2\n")
815 825 for i in r:
816 826 node = r.node(i)
817 827 try:
818 828 pp = r.parents(node)
819 829 except:
820 830 pp = [nullid, nullid]
821 831 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
822 832 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
823 833 short(node), short(pp[0]), short(pp[1])))
824 834
825 835 def debugindexdot(ui, file_):
826 836 """dump an index DAG as a .dot file"""
827 837 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
828 838 ui.write("digraph G {\n")
829 839 for i in r:
830 840 node = r.node(i)
831 841 pp = r.parents(node)
832 842 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
833 843 if pp[1] != nullid:
834 844 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
835 845 ui.write("}\n")
836 846
837 847 def debuginstall(ui):
838 848 '''test Mercurial installation'''
839 849
840 850 def writetemp(contents):
841 851 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
842 852 f = os.fdopen(fd, "wb")
843 853 f.write(contents)
844 854 f.close()
845 855 return name
846 856
847 857 problems = 0
848 858
849 859 # encoding
850 860 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
851 861 try:
852 862 util.fromlocal("test")
853 863 except util.Abort, inst:
854 864 ui.write(" %s\n" % inst)
855 865 ui.write(_(" (check that your locale is properly set)\n"))
856 866 problems += 1
857 867
858 868 # compiled modules
859 869 ui.status(_("Checking extensions...\n"))
860 870 try:
861 871 import bdiff, mpatch, base85
862 872 except Exception, inst:
863 873 ui.write(" %s\n" % inst)
864 874 ui.write(_(" One or more extensions could not be found"))
865 875 ui.write(_(" (check that you compiled the extensions)\n"))
866 876 problems += 1
867 877
868 878 # templates
869 879 ui.status(_("Checking templates...\n"))
870 880 try:
871 881 import templater
872 882 t = templater.templater(templater.templatepath("map-cmdline.default"))
873 883 except Exception, inst:
874 884 ui.write(" %s\n" % inst)
875 885 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
876 886 problems += 1
877 887
878 888 # patch
879 889 ui.status(_("Checking patch...\n"))
880 890 patchproblems = 0
881 891 a = "1\n2\n3\n4\n"
882 892 b = "1\n2\n3\ninsert\n4\n"
883 893 fa = writetemp(a)
884 894 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
885 895 os.path.basename(fa))
886 896 fd = writetemp(d)
887 897
888 898 files = {}
889 899 try:
890 900 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
891 901 except util.Abort, e:
892 902 ui.write(_(" patch call failed:\n"))
893 903 ui.write(" " + str(e) + "\n")
894 904 patchproblems += 1
895 905 else:
896 906 if list(files) != [os.path.basename(fa)]:
897 907 ui.write(_(" unexpected patch output!\n"))
898 908 patchproblems += 1
899 909 a = file(fa).read()
900 910 if a != b:
901 911 ui.write(_(" patch test failed!\n"))
902 912 patchproblems += 1
903 913
904 914 if patchproblems:
905 915 if ui.config('ui', 'patch'):
906 916 ui.write(_(" (Current patch tool may be incompatible with patch,"
907 917 " or misconfigured. Please check your .hgrc file)\n"))
908 918 else:
909 919 ui.write(_(" Internal patcher failure, please report this error"
910 920 " to http://www.selenic.com/mercurial/bts\n"))
911 921 problems += patchproblems
912 922
913 923 os.unlink(fa)
914 924 os.unlink(fd)
915 925
916 926 # editor
917 927 ui.status(_("Checking commit editor...\n"))
918 928 editor = ui.geteditor()
919 929 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
920 930 if not cmdpath:
921 931 if editor == 'vi':
922 932 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
923 933 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
924 934 else:
925 935 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
926 936 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
927 937 problems += 1
928 938
929 939 # check username
930 940 ui.status(_("Checking username...\n"))
931 941 user = os.environ.get("HGUSER")
932 942 if user is None:
933 943 user = ui.config("ui", "username")
934 944 if user is None:
935 945 user = os.environ.get("EMAIL")
936 946 if not user:
937 947 ui.warn(" ")
938 948 ui.username()
939 949 ui.write(_(" (specify a username in your .hgrc file)\n"))
940 950
941 951 if not problems:
942 952 ui.status(_("No problems detected\n"))
943 953 else:
944 954 ui.write(_("%s problems detected,"
945 955 " please check your install!\n") % problems)
946 956
947 957 return problems
948 958
949 959 def debugrename(ui, repo, file1, *pats, **opts):
950 960 """dump rename information"""
951 961
952 962 ctx = repo[opts.get('rev')]
953 963 m = cmdutil.match(repo, (file1,) + pats, opts)
954 964 for abs in ctx.walk(m):
955 965 fctx = ctx[abs]
956 966 o = fctx.filelog().renamed(fctx.filenode())
957 967 rel = m.rel(abs)
958 968 if o:
959 969 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
960 970 else:
961 971 ui.write(_("%s not renamed\n") % rel)
962 972
963 973 def debugwalk(ui, repo, *pats, **opts):
964 974 """show how files match on given patterns"""
965 975 m = cmdutil.match(repo, pats, opts)
966 976 items = list(repo.walk(m))
967 977 if not items:
968 978 return
969 979 fmt = 'f %%-%ds %%-%ds %%s' % (
970 980 max([len(abs) for abs in items]),
971 981 max([len(m.rel(abs)) for abs in items]))
972 982 for abs in items:
973 983 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
974 984 ui.write("%s\n" % line.rstrip())
975 985
976 986 def diff(ui, repo, *pats, **opts):
977 987 """diff repository (or selected files)
978 988
979 989 Show differences between revisions for the specified files.
980 990
981 991 Differences between files are shown using the unified diff format.
982 992
983 993 NOTE: diff may generate unexpected results for merges, as it will
984 994 default to comparing against the working directory's first parent
985 995 changeset if no revisions are specified.
986 996
987 997 When two revision arguments are given, then changes are shown
988 998 between those revisions. If only one revision is specified then
989 999 that revision is compared to the working directory, and, when no
990 1000 revisions are specified, the working directory files are compared
991 1001 to its parent.
992 1002
993 1003 Without the -a option, diff will avoid generating diffs of files
994 1004 it detects as binary. With -a, diff will generate a diff anyway,
995 1005 probably with undesirable results.
996 1006 """
997 1007 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
998 1008
999 1009 m = cmdutil.match(repo, pats, opts)
1000 1010 patch.diff(repo, node1, node2, match=m, opts=patch.diffopts(ui, opts))
1001 1011
1002 1012 def export(ui, repo, *changesets, **opts):
1003 1013 """dump the header and diffs for one or more changesets
1004 1014
1005 1015 Print the changeset header and diffs for one or more revisions.
1006 1016
1007 1017 The information shown in the changeset header is: author,
1008 1018 changeset hash, parent(s) and commit comment.
1009 1019
1010 1020 NOTE: export may generate unexpected diff output for merge changesets,
1011 1021 as it will compare the merge changeset against its first parent only.
1012 1022
1013 1023 Output may be to a file, in which case the name of the file is
1014 1024 given using a format string. The formatting rules are as follows:
1015 1025
1016 1026 %% literal "%" character
1017 1027 %H changeset hash (40 bytes of hexadecimal)
1018 1028 %N number of patches being generated
1019 1029 %R changeset revision number
1020 1030 %b basename of the exporting repository
1021 1031 %h short-form changeset hash (12 bytes of hexadecimal)
1022 1032 %n zero-padded sequence number, starting at 1
1023 1033 %r zero-padded changeset revision number
1024 1034
1025 1035 Without the -a option, export will avoid generating diffs of files
1026 1036 it detects as binary. With -a, export will generate a diff anyway,
1027 1037 probably with undesirable results.
1028 1038
1029 1039 With the --switch-parent option, the diff will be against the second
1030 1040 parent. It can be useful to review a merge.
1031 1041 """
1032 1042 if not changesets:
1033 1043 raise util.Abort(_("export requires at least one changeset"))
1034 1044 revs = cmdutil.revrange(repo, changesets)
1035 1045 if len(revs) > 1:
1036 1046 ui.note(_('exporting patches:\n'))
1037 1047 else:
1038 1048 ui.note(_('exporting patch:\n'))
1039 1049 patch.export(repo, revs, template=opts.get('output'),
1040 1050 switch_parent=opts.get('switch_parent'),
1041 1051 opts=patch.diffopts(ui, opts))
1042 1052
1043 1053 def grep(ui, repo, pattern, *pats, **opts):
1044 1054 """search for a pattern in specified files and revisions
1045 1055
1046 1056 Search revisions of files for a regular expression.
1047 1057
1048 1058 This command behaves differently than Unix grep. It only accepts
1049 1059 Python/Perl regexps. It searches repository history, not the
1050 1060 working directory. It always prints the revision number in which
1051 1061 a match appears.
1052 1062
1053 1063 By default, grep only prints output for the first revision of a
1054 1064 file in which it finds a match. To get it to print every revision
1055 1065 that contains a change in match status ("-" for a match that
1056 1066 becomes a non-match, or "+" for a non-match that becomes a match),
1057 1067 use the --all flag.
1058 1068 """
1059 1069 reflags = 0
1060 1070 if opts.get('ignore_case'):
1061 1071 reflags |= re.I
1062 1072 try:
1063 1073 regexp = re.compile(pattern, reflags)
1064 1074 except Exception, inst:
1065 1075 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1066 1076 return None
1067 1077 sep, eol = ':', '\n'
1068 1078 if opts.get('print0'):
1069 1079 sep = eol = '\0'
1070 1080
1071 1081 fcache = {}
1072 1082 def getfile(fn):
1073 1083 if fn not in fcache:
1074 1084 fcache[fn] = repo.file(fn)
1075 1085 return fcache[fn]
1076 1086
1077 1087 def matchlines(body):
1078 1088 begin = 0
1079 1089 linenum = 0
1080 1090 while True:
1081 1091 match = regexp.search(body, begin)
1082 1092 if not match:
1083 1093 break
1084 1094 mstart, mend = match.span()
1085 1095 linenum += body.count('\n', begin, mstart) + 1
1086 1096 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1087 1097 lend = body.find('\n', mend)
1088 1098 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1089 1099 begin = lend + 1
1090 1100
1091 1101 class linestate(object):
1092 1102 def __init__(self, line, linenum, colstart, colend):
1093 1103 self.line = line
1094 1104 self.linenum = linenum
1095 1105 self.colstart = colstart
1096 1106 self.colend = colend
1097 1107
1098 1108 def __hash__(self):
1099 1109 return hash((self.linenum, self.line))
1100 1110
1101 1111 def __eq__(self, other):
1102 1112 return self.line == other.line
1103 1113
1104 1114 matches = {}
1105 1115 copies = {}
1106 1116 def grepbody(fn, rev, body):
1107 1117 matches[rev].setdefault(fn, [])
1108 1118 m = matches[rev][fn]
1109 1119 for lnum, cstart, cend, line in matchlines(body):
1110 1120 s = linestate(line, lnum, cstart, cend)
1111 1121 m.append(s)
1112 1122
1113 1123 def difflinestates(a, b):
1114 1124 sm = difflib.SequenceMatcher(None, a, b)
1115 1125 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1116 1126 if tag == 'insert':
1117 1127 for i in xrange(blo, bhi):
1118 1128 yield ('+', b[i])
1119 1129 elif tag == 'delete':
1120 1130 for i in xrange(alo, ahi):
1121 1131 yield ('-', a[i])
1122 1132 elif tag == 'replace':
1123 1133 for i in xrange(alo, ahi):
1124 1134 yield ('-', a[i])
1125 1135 for i in xrange(blo, bhi):
1126 1136 yield ('+', b[i])
1127 1137
1128 1138 prev = {}
1129 1139 def display(fn, rev, states, prevstates):
1130 1140 datefunc = ui.quiet and util.shortdate or util.datestr
1131 1141 found = False
1132 1142 filerevmatches = {}
1133 1143 r = prev.get(fn, -1)
1134 1144 if opts.get('all'):
1135 1145 iter = difflinestates(states, prevstates)
1136 1146 else:
1137 1147 iter = [('', l) for l in prevstates]
1138 1148 for change, l in iter:
1139 1149 cols = [fn, str(r)]
1140 1150 if opts.get('line_number'):
1141 1151 cols.append(str(l.linenum))
1142 1152 if opts.get('all'):
1143 1153 cols.append(change)
1144 1154 if opts.get('user'):
1145 1155 cols.append(ui.shortuser(get(r)[1]))
1146 1156 if opts.get('date'):
1147 1157 cols.append(datefunc(get(r)[2]))
1148 1158 if opts.get('files_with_matches'):
1149 1159 c = (fn, r)
1150 1160 if c in filerevmatches:
1151 1161 continue
1152 1162 filerevmatches[c] = 1
1153 1163 else:
1154 1164 cols.append(l.line)
1155 1165 ui.write(sep.join(cols), eol)
1156 1166 found = True
1157 1167 return found
1158 1168
1159 1169 fstate = {}
1160 1170 skip = {}
1161 1171 get = util.cachefunc(lambda r: repo[r].changeset())
1162 1172 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1163 1173 found = False
1164 1174 follow = opts.get('follow')
1165 1175 for st, rev, fns in changeiter:
1166 1176 if st == 'window':
1167 1177 matches.clear()
1168 1178 elif st == 'add':
1169 1179 ctx = repo[rev]
1170 1180 matches[rev] = {}
1171 1181 for fn in fns:
1172 1182 if fn in skip:
1173 1183 continue
1174 1184 try:
1175 1185 grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn)))
1176 1186 fstate.setdefault(fn, [])
1177 1187 if follow:
1178 1188 copied = getfile(fn).renamed(ctx.filenode(fn))
1179 1189 if copied:
1180 1190 copies.setdefault(rev, {})[fn] = copied[0]
1181 1191 except revlog.LookupError:
1182 1192 pass
1183 1193 elif st == 'iter':
1184 1194 for fn, m in util.sort(matches[rev].items()):
1185 1195 copy = copies.get(rev, {}).get(fn)
1186 1196 if fn in skip:
1187 1197 if copy:
1188 1198 skip[copy] = True
1189 1199 continue
1190 1200 if fn in prev or fstate[fn]:
1191 1201 r = display(fn, rev, m, fstate[fn])
1192 1202 found = found or r
1193 1203 if r and not opts.get('all'):
1194 1204 skip[fn] = True
1195 1205 if copy:
1196 1206 skip[copy] = True
1197 1207 fstate[fn] = m
1198 1208 if copy:
1199 1209 fstate[copy] = m
1200 1210 prev[fn] = rev
1201 1211
1202 1212 for fn, state in util.sort(fstate.items()):
1203 1213 if fn in skip:
1204 1214 continue
1205 1215 if fn not in copies.get(prev[fn], {}):
1206 1216 found = display(fn, rev, {}, state) or found
1207 1217 return (not found and 1) or 0
1208 1218
1209 1219 def heads(ui, repo, *branchrevs, **opts):
1210 1220 """show current repository heads or show branch heads
1211 1221
1212 1222 With no arguments, show all repository head changesets.
1213 1223
1214 1224 If branch or revisions names are given this will show the heads of
1215 1225 the specified branches or the branches those revisions are tagged
1216 1226 with.
1217 1227
1218 1228 Repository "heads" are changesets that don't have child
1219 1229 changesets. They are where development generally takes place and
1220 1230 are the usual targets for update and merge operations.
1221 1231
1222 1232 Branch heads are changesets that have a given branch tag, but have
1223 1233 no child changesets with that tag. They are usually where
1224 1234 development on the given branch takes place.
1225 1235 """
1226 1236 if opts.get('rev'):
1227 1237 start = repo.lookup(opts['rev'])
1228 1238 else:
1229 1239 start = None
1230 1240 if not branchrevs:
1231 1241 # Assume we're looking repo-wide heads if no revs were specified.
1232 1242 heads = repo.heads(start)
1233 1243 else:
1234 1244 heads = []
1235 1245 visitedset = util.set()
1236 1246 for branchrev in branchrevs:
1237 1247 branch = repo[branchrev].branch()
1238 1248 if branch in visitedset:
1239 1249 continue
1240 1250 visitedset.add(branch)
1241 1251 bheads = repo.branchheads(branch, start)
1242 1252 if not bheads:
1243 1253 if branch != branchrev:
1244 1254 ui.warn(_("no changes on branch %s containing %s are "
1245 1255 "reachable from %s\n")
1246 1256 % (branch, branchrev, opts.get('rev')))
1247 1257 else:
1248 1258 ui.warn(_("no changes on branch %s are reachable from %s\n")
1249 1259 % (branch, opts.get('rev')))
1250 1260 heads.extend(bheads)
1251 1261 if not heads:
1252 1262 return 1
1253 1263 displayer = cmdutil.show_changeset(ui, repo, opts)
1254 1264 for n in heads:
1255 1265 displayer.show(changenode=n)
1256 1266
1257 1267 def help_(ui, name=None, with_version=False):
1258 1268 """show help for a given topic or a help overview
1259 1269
1260 1270 With no arguments, print a list of commands and short help.
1261 1271
1262 1272 Given a topic, extension, or command name, print help for that topic."""
1263 1273 option_lists = []
1264 1274
1265 1275 def addglobalopts(aliases):
1266 1276 if ui.verbose:
1267 1277 option_lists.append((_("global options:"), globalopts))
1268 1278 if name == 'shortlist':
1269 1279 option_lists.append((_('use "hg help" for the full list '
1270 1280 'of commands'), ()))
1271 1281 else:
1272 1282 if name == 'shortlist':
1273 1283 msg = _('use "hg help" for the full list of commands '
1274 1284 'or "hg -v" for details')
1275 1285 elif aliases:
1276 1286 msg = _('use "hg -v help%s" to show aliases and '
1277 1287 'global options') % (name and " " + name or "")
1278 1288 else:
1279 1289 msg = _('use "hg -v help %s" to show global options') % name
1280 1290 option_lists.append((msg, ()))
1281 1291
1282 1292 def helpcmd(name):
1283 1293 if with_version:
1284 1294 version_(ui)
1285 1295 ui.write('\n')
1286 1296
1287 1297 try:
1288 1298 aliases, i = cmdutil.findcmd(name, table, False)
1289 1299 except cmdutil.AmbiguousCommand, inst:
1290 1300 select = lambda c: c.lstrip('^').startswith(inst.args[0])
1291 1301 helplist(_('list of commands:\n\n'), select)
1292 1302 return
1293 1303
1294 1304 # synopsis
1295 1305 ui.write("%s\n" % i[2])
1296 1306
1297 1307 # aliases
1298 1308 if not ui.quiet and len(aliases) > 1:
1299 1309 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1300 1310
1301 1311 # description
1302 1312 doc = gettext(i[0].__doc__)
1303 1313 if not doc:
1304 1314 doc = _("(No help text available)")
1305 1315 if ui.quiet:
1306 1316 doc = doc.splitlines(0)[0]
1307 1317 ui.write("\n%s\n" % doc.rstrip())
1308 1318
1309 1319 if not ui.quiet:
1310 1320 # options
1311 1321 if i[1]:
1312 1322 option_lists.append((_("options:\n"), i[1]))
1313 1323
1314 1324 addglobalopts(False)
1315 1325
1316 1326 def helplist(header, select=None):
1317 1327 h = {}
1318 1328 cmds = {}
1319 1329 for c, e in table.items():
1320 1330 f = c.split("|", 1)[0]
1321 1331 if select and not select(f):
1322 1332 continue
1323 1333 if (not select and name != 'shortlist' and
1324 1334 e[0].__module__ != __name__):
1325 1335 continue
1326 1336 if name == "shortlist" and not f.startswith("^"):
1327 1337 continue
1328 1338 f = f.lstrip("^")
1329 1339 if not ui.debugflag and f.startswith("debug"):
1330 1340 continue
1331 1341 doc = gettext(e[0].__doc__)
1332 1342 if not doc:
1333 1343 doc = _("(No help text available)")
1334 1344 h[f] = doc.splitlines(0)[0].rstrip()
1335 1345 cmds[f] = c.lstrip("^")
1336 1346
1337 1347 if not h:
1338 1348 ui.status(_('no commands defined\n'))
1339 1349 return
1340 1350
1341 1351 ui.status(header)
1342 1352 fns = util.sort(h)
1343 1353 m = max(map(len, fns))
1344 1354 for f in fns:
1345 1355 if ui.verbose:
1346 1356 commands = cmds[f].replace("|",", ")
1347 1357 ui.write(" %s:\n %s\n"%(commands, h[f]))
1348 1358 else:
1349 1359 ui.write(' %-*s %s\n' % (m, f, h[f]))
1350 1360
1351 1361 exts = list(extensions.extensions())
1352 1362 if exts and name != 'shortlist':
1353 1363 ui.write(_('\nenabled extensions:\n\n'))
1354 1364 maxlength = 0
1355 1365 exthelps = []
1356 1366 for ename, ext in exts:
1357 1367 doc = (ext.__doc__ or _('(no help text available)'))
1358 1368 ename = ename.split('.')[-1]
1359 1369 maxlength = max(len(ename), maxlength)
1360 1370 exthelps.append((ename, doc.splitlines(0)[0].strip()))
1361 1371 for ename, text in exthelps:
1362 1372 ui.write(_(' %s %s\n') % (ename.ljust(maxlength), text))
1363 1373
1364 1374 if not ui.quiet:
1365 1375 addglobalopts(True)
1366 1376
1367 1377 def helptopic(name):
1368 1378 for names, header, doc in help.helptable:
1369 1379 if name in names:
1370 1380 break
1371 1381 else:
1372 1382 raise cmdutil.UnknownCommand(name)
1373 1383
1374 1384 # description
1375 1385 if not doc:
1376 1386 doc = _("(No help text available)")
1377 1387 if callable(doc):
1378 1388 doc = doc()
1379 1389
1380 1390 ui.write("%s\n" % header)
1381 1391 ui.write("%s\n" % doc.rstrip())
1382 1392
1383 1393 def helpext(name):
1384 1394 try:
1385 1395 mod = extensions.find(name)
1386 1396 except KeyError:
1387 1397 raise cmdutil.UnknownCommand(name)
1388 1398
1389 1399 doc = gettext(mod.__doc__) or _('No help text available')
1390 1400 doc = doc.splitlines(0)
1391 1401 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1392 1402 for d in doc[1:]:
1393 1403 ui.write(d, '\n')
1394 1404
1395 1405 ui.status('\n')
1396 1406
1397 1407 try:
1398 1408 ct = mod.cmdtable
1399 1409 except AttributeError:
1400 1410 ct = {}
1401 1411
1402 1412 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1403 1413 helplist(_('list of commands:\n\n'), modcmds.has_key)
1404 1414
1405 1415 if name and name != 'shortlist':
1406 1416 i = None
1407 1417 for f in (helpcmd, helptopic, helpext):
1408 1418 try:
1409 1419 f(name)
1410 1420 i = None
1411 1421 break
1412 1422 except cmdutil.UnknownCommand, inst:
1413 1423 i = inst
1414 1424 if i:
1415 1425 raise i
1416 1426
1417 1427 else:
1418 1428 # program name
1419 1429 if ui.verbose or with_version:
1420 1430 version_(ui)
1421 1431 else:
1422 1432 ui.status(_("Mercurial Distributed SCM\n"))
1423 1433 ui.status('\n')
1424 1434
1425 1435 # list of commands
1426 1436 if name == "shortlist":
1427 1437 header = _('basic commands:\n\n')
1428 1438 else:
1429 1439 header = _('list of commands:\n\n')
1430 1440
1431 1441 helplist(header)
1432 1442
1433 1443 # list all option lists
1434 1444 opt_output = []
1435 1445 for title, options in option_lists:
1436 1446 opt_output.append(("\n%s" % title, None))
1437 1447 for shortopt, longopt, default, desc in options:
1438 1448 if "DEPRECATED" in desc and not ui.verbose: continue
1439 1449 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1440 1450 longopt and " --%s" % longopt),
1441 1451 "%s%s" % (desc,
1442 1452 default
1443 1453 and _(" (default: %s)") % default
1444 1454 or "")))
1445 1455
1446 1456 if not name:
1447 1457 ui.write(_("\nadditional help topics:\n\n"))
1448 1458 topics = []
1449 1459 for names, header, doc in help.helptable:
1450 1460 names = [(-len(name), name) for name in names]
1451 1461 names.sort()
1452 1462 topics.append((names[0][1], header))
1453 1463 topics_len = max([len(s[0]) for s in topics])
1454 1464 for t, desc in topics:
1455 1465 ui.write(" %-*s %s\n" % (topics_len, t, desc))
1456 1466
1457 1467 if opt_output:
1458 1468 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1459 1469 for first, second in opt_output:
1460 1470 if second:
1461 1471 ui.write(" %-*s %s\n" % (opts_len, first, second))
1462 1472 else:
1463 1473 ui.write("%s\n" % first)
1464 1474
1465 1475 def identify(ui, repo, source=None,
1466 1476 rev=None, num=None, id=None, branch=None, tags=None):
1467 1477 """identify the working copy or specified revision
1468 1478
1469 1479 With no revision, print a summary of the current state of the repo.
1470 1480
1471 1481 With a path, do a lookup in another repository.
1472 1482
1473 1483 This summary identifies the repository state using one or two parent
1474 1484 hash identifiers, followed by a "+" if there are uncommitted changes
1475 1485 in the working directory, a list of tags for this revision and a branch
1476 1486 name for non-default branches.
1477 1487 """
1478 1488
1479 1489 if not repo and not source:
1480 1490 raise util.Abort(_("There is no Mercurial repository here "
1481 1491 "(.hg not found)"))
1482 1492
1483 1493 hexfunc = ui.debugflag and hex or short
1484 1494 default = not (num or id or branch or tags)
1485 1495 output = []
1486 1496
1487 1497 if source:
1488 1498 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1489 1499 srepo = hg.repository(ui, source)
1490 1500 if not rev and revs:
1491 1501 rev = revs[0]
1492 1502 if not rev:
1493 1503 rev = "tip"
1494 1504 if num or branch or tags:
1495 1505 raise util.Abort(
1496 1506 "can't query remote revision number, branch, or tags")
1497 1507 output = [hexfunc(srepo.lookup(rev))]
1498 1508 elif not rev:
1499 1509 ctx = repo[None]
1500 1510 parents = ctx.parents()
1501 1511 changed = False
1502 1512 if default or id or num:
1503 1513 changed = ctx.files() + ctx.deleted()
1504 1514 if default or id:
1505 1515 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1506 1516 (changed) and "+" or "")]
1507 1517 if num:
1508 1518 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1509 1519 (changed) and "+" or ""))
1510 1520 else:
1511 1521 ctx = repo[rev]
1512 1522 if default or id:
1513 1523 output = [hexfunc(ctx.node())]
1514 1524 if num:
1515 1525 output.append(str(ctx.rev()))
1516 1526
1517 1527 if not source and default and not ui.quiet:
1518 1528 b = util.tolocal(ctx.branch())
1519 1529 if b != 'default':
1520 1530 output.append("(%s)" % b)
1521 1531
1522 1532 # multiple tags for a single parent separated by '/'
1523 1533 t = "/".join(ctx.tags())
1524 1534 if t:
1525 1535 output.append(t)
1526 1536
1527 1537 if branch:
1528 1538 output.append(util.tolocal(ctx.branch()))
1529 1539
1530 1540 if tags:
1531 1541 output.extend(ctx.tags())
1532 1542
1533 1543 ui.write("%s\n" % ' '.join(output))
1534 1544
1535 1545 def import_(ui, repo, patch1, *patches, **opts):
1536 1546 """import an ordered set of patches
1537 1547
1538 1548 Import a list of patches and commit them individually.
1539 1549
1540 1550 If there are outstanding changes in the working directory, import
1541 1551 will abort unless given the -f flag.
1542 1552
1543 1553 You can import a patch straight from a mail message. Even patches
1544 1554 as attachments work (body part must be type text/plain or
1545 1555 text/x-patch to be used). From and Subject headers of email
1546 1556 message are used as default committer and commit message. All
1547 1557 text/plain body parts before first diff are added to commit
1548 1558 message.
1549 1559
1550 1560 If the imported patch was generated by hg export, user and description
1551 1561 from patch override values from message headers and body. Values
1552 1562 given on command line with -m and -u override these.
1553 1563
1554 1564 If --exact is specified, import will set the working directory
1555 1565 to the parent of each patch before applying it, and will abort
1556 1566 if the resulting changeset has a different ID than the one
1557 1567 recorded in the patch. This may happen due to character set
1558 1568 problems or other deficiencies in the text patch format.
1559 1569
1560 1570 To read a patch from standard input, use patch name "-".
1561 1571 See 'hg help dates' for a list of formats valid for -d/--date.
1562 1572 """
1563 1573 patches = (patch1,) + patches
1564 1574
1565 1575 date = opts.get('date')
1566 1576 if date:
1567 1577 opts['date'] = util.parsedate(date)
1568 1578
1569 1579 if opts.get('exact') or not opts.get('force'):
1570 1580 cmdutil.bail_if_changed(repo)
1571 1581
1572 1582 d = opts["base"]
1573 1583 strip = opts["strip"]
1574 1584 wlock = lock = None
1575 1585 try:
1576 1586 wlock = repo.wlock()
1577 1587 lock = repo.lock()
1578 1588 for p in patches:
1579 1589 pf = os.path.join(d, p)
1580 1590
1581 1591 if pf == '-':
1582 1592 ui.status(_("applying patch from stdin\n"))
1583 1593 data = patch.extract(ui, sys.stdin)
1584 1594 else:
1585 1595 ui.status(_("applying %s\n") % p)
1586 1596 if os.path.exists(pf):
1587 1597 data = patch.extract(ui, file(pf, 'rb'))
1588 1598 else:
1589 1599 data = patch.extract(ui, urllib.urlopen(pf))
1590 1600 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1591 1601
1592 1602 if tmpname is None:
1593 1603 raise util.Abort(_('no diffs found'))
1594 1604
1595 1605 try:
1596 1606 cmdline_message = cmdutil.logmessage(opts)
1597 1607 if cmdline_message:
1598 1608 # pickup the cmdline msg
1599 1609 message = cmdline_message
1600 1610 elif message:
1601 1611 # pickup the patch msg
1602 1612 message = message.strip()
1603 1613 else:
1604 1614 # launch the editor
1605 1615 message = None
1606 1616 ui.debug(_('message:\n%s\n') % message)
1607 1617
1608 1618 wp = repo.parents()
1609 1619 if opts.get('exact'):
1610 1620 if not nodeid or not p1:
1611 1621 raise util.Abort(_('not a mercurial patch'))
1612 1622 p1 = repo.lookup(p1)
1613 1623 p2 = repo.lookup(p2 or hex(nullid))
1614 1624
1615 1625 if p1 != wp[0].node():
1616 1626 hg.clean(repo, p1)
1617 1627 repo.dirstate.setparents(p1, p2)
1618 1628 elif p2:
1619 1629 try:
1620 1630 p1 = repo.lookup(p1)
1621 1631 p2 = repo.lookup(p2)
1622 1632 if p1 == wp[0].node():
1623 1633 repo.dirstate.setparents(p1, p2)
1624 1634 except RepoError:
1625 1635 pass
1626 1636 if opts.get('exact') or opts.get('import_branch'):
1627 1637 repo.dirstate.setbranch(branch or 'default')
1628 1638
1629 1639 files = {}
1630 1640 try:
1631 1641 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1632 1642 files=files)
1633 1643 finally:
1634 1644 files = patch.updatedir(ui, repo, files)
1635 1645 if not opts.get('no_commit'):
1636 1646 n = repo.commit(files, message, opts.get('user') or user,
1637 1647 opts.get('date') or date)
1638 1648 if opts.get('exact'):
1639 1649 if hex(n) != nodeid:
1640 1650 repo.rollback()
1641 1651 raise util.Abort(_('patch is damaged'
1642 1652 ' or loses information'))
1643 1653 # Force a dirstate write so that the next transaction
1644 1654 # backups an up-do-date file.
1645 1655 repo.dirstate.write()
1646 1656 finally:
1647 1657 os.unlink(tmpname)
1648 1658 finally:
1649 1659 del lock, wlock
1650 1660
1651 1661 def incoming(ui, repo, source="default", **opts):
1652 1662 """show new changesets found in source
1653 1663
1654 1664 Show new changesets found in the specified path/URL or the default
1655 1665 pull location. These are the changesets that would be pulled if a pull
1656 1666 was requested.
1657 1667
1658 1668 For remote repository, using --bundle avoids downloading the changesets
1659 1669 twice if the incoming is followed by a pull.
1660 1670
1661 1671 See pull for valid source format details.
1662 1672 """
1663 1673 limit = cmdutil.loglimit(opts)
1664 1674 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
1665 1675 cmdutil.setremoteconfig(ui, opts)
1666 1676
1667 1677 other = hg.repository(ui, source)
1668 1678 ui.status(_('comparing with %s\n') % util.hidepassword(source))
1669 1679 if revs:
1670 1680 revs = [other.lookup(rev) for rev in revs]
1671 1681 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1672 1682 if not incoming:
1673 1683 try:
1674 1684 os.unlink(opts["bundle"])
1675 1685 except:
1676 1686 pass
1677 1687 ui.status(_("no changes found\n"))
1678 1688 return 1
1679 1689
1680 1690 cleanup = None
1681 1691 try:
1682 1692 fname = opts["bundle"]
1683 1693 if fname or not other.local():
1684 1694 # create a bundle (uncompressed if other repo is not local)
1685 1695 if revs is None:
1686 1696 cg = other.changegroup(incoming, "incoming")
1687 1697 else:
1688 1698 cg = other.changegroupsubset(incoming, revs, 'incoming')
1689 1699 bundletype = other.local() and "HG10BZ" or "HG10UN"
1690 1700 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1691 1701 # keep written bundle?
1692 1702 if opts["bundle"]:
1693 1703 cleanup = None
1694 1704 if not other.local():
1695 1705 # use the created uncompressed bundlerepo
1696 1706 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1697 1707
1698 1708 o = other.changelog.nodesbetween(incoming, revs)[0]
1699 1709 if opts.get('newest_first'):
1700 1710 o.reverse()
1701 1711 displayer = cmdutil.show_changeset(ui, other, opts)
1702 1712 count = 0
1703 1713 for n in o:
1704 1714 if count >= limit:
1705 1715 break
1706 1716 parents = [p for p in other.changelog.parents(n) if p != nullid]
1707 1717 if opts.get('no_merges') and len(parents) == 2:
1708 1718 continue
1709 1719 count += 1
1710 1720 displayer.show(changenode=n)
1711 1721 finally:
1712 1722 if hasattr(other, 'close'):
1713 1723 other.close()
1714 1724 if cleanup:
1715 1725 os.unlink(cleanup)
1716 1726
1717 1727 def init(ui, dest=".", **opts):
1718 1728 """create a new repository in the given directory
1719 1729
1720 1730 Initialize a new repository in the given directory. If the given
1721 1731 directory does not exist, it is created.
1722 1732
1723 1733 If no directory is given, the current directory is used.
1724 1734
1725 1735 It is possible to specify an ssh:// URL as the destination.
1726 1736 Look at the help text for the pull command for important details
1727 1737 about ssh:// URLs.
1728 1738 """
1729 1739 cmdutil.setremoteconfig(ui, opts)
1730 1740 hg.repository(ui, dest, create=1)
1731 1741
1732 1742 def locate(ui, repo, *pats, **opts):
1733 1743 """locate files matching specific patterns
1734 1744
1735 1745 Print all files under Mercurial control whose names match the
1736 1746 given patterns.
1737 1747
1738 1748 This command searches the entire repository by default. To search
1739 1749 just the current directory and its subdirectories, use
1740 1750 "--include .".
1741 1751
1742 1752 If no patterns are given to match, this command prints all file
1743 1753 names.
1744 1754
1745 1755 If you want to feed the output of this command into the "xargs"
1746 1756 command, use the "-0" option to both this command and "xargs".
1747 1757 This will avoid the problem of "xargs" treating single filenames
1748 1758 that contain white space as multiple filenames.
1749 1759 """
1750 1760 end = opts.get('print0') and '\0' or '\n'
1751 1761 rev = opts.get('rev') or None
1752 1762
1753 1763 ret = 1
1754 1764 m = cmdutil.match(repo, pats, opts, default='relglob')
1755 1765 m.bad = lambda x,y: False
1756 1766 for abs in repo[rev].walk(m):
1757 1767 if not rev and abs not in repo.dirstate:
1758 1768 continue
1759 1769 if opts.get('fullpath'):
1760 1770 ui.write(os.path.join(repo.root, abs), end)
1761 1771 else:
1762 1772 ui.write(((pats and m.rel(abs)) or abs), end)
1763 1773 ret = 0
1764 1774
1765 1775 return ret
1766 1776
1767 1777 def log(ui, repo, *pats, **opts):
1768 1778 """show revision history of entire repository or files
1769 1779
1770 1780 Print the revision history of the specified files or the entire
1771 1781 project.
1772 1782
1773 1783 File history is shown without following rename or copy history of
1774 1784 files. Use -f/--follow with a file name to follow history across
1775 1785 renames and copies. --follow without a file name will only show
1776 1786 ancestors or descendants of the starting revision. --follow-first
1777 1787 only follows the first parent of merge revisions.
1778 1788
1779 1789 If no revision range is specified, the default is tip:0 unless
1780 1790 --follow is set, in which case the working directory parent is
1781 1791 used as the starting revision.
1782 1792
1783 1793 See 'hg help dates' for a list of formats valid for -d/--date.
1784 1794
1785 1795 By default this command outputs: changeset id and hash, tags,
1786 1796 non-trivial parents, user, date and time, and a summary for each
1787 1797 commit. When the -v/--verbose switch is used, the list of changed
1788 1798 files and full commit message is shown.
1789 1799
1790 1800 NOTE: log -p may generate unexpected diff output for merge
1791 1801 changesets, as it will compare the merge changeset against its
1792 1802 first parent only. Also, the files: list will only reflect files
1793 1803 that are different from BOTH parents.
1794 1804
1795 1805 """
1796 1806
1797 1807 get = util.cachefunc(lambda r: repo[r].changeset())
1798 1808 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1799 1809
1800 1810 limit = cmdutil.loglimit(opts)
1801 1811 count = 0
1802 1812
1803 1813 if opts.get('copies') and opts.get('rev'):
1804 1814 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
1805 1815 else:
1806 1816 endrev = len(repo)
1807 1817 rcache = {}
1808 1818 ncache = {}
1809 1819 def getrenamed(fn, rev):
1810 1820 '''looks up all renames for a file (up to endrev) the first
1811 1821 time the file is given. It indexes on the changerev and only
1812 1822 parses the manifest if linkrev != changerev.
1813 1823 Returns rename info for fn at changerev rev.'''
1814 1824 if fn not in rcache:
1815 1825 rcache[fn] = {}
1816 1826 ncache[fn] = {}
1817 1827 fl = repo.file(fn)
1818 1828 for i in fl:
1819 1829 node = fl.node(i)
1820 1830 lr = fl.linkrev(node)
1821 1831 renamed = fl.renamed(node)
1822 1832 rcache[fn][lr] = renamed
1823 1833 if renamed:
1824 1834 ncache[fn][node] = renamed
1825 1835 if lr >= endrev:
1826 1836 break
1827 1837 if rev in rcache[fn]:
1828 1838 return rcache[fn][rev]
1829 1839
1830 1840 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1831 1841 # filectx logic.
1832 1842
1833 1843 try:
1834 1844 return repo[rev][fn].renamed()
1835 1845 except revlog.LookupError:
1836 1846 pass
1837 1847 return None
1838 1848
1839 1849 df = False
1840 1850 if opts["date"]:
1841 1851 df = util.matchdate(opts["date"])
1842 1852
1843 1853 only_branches = opts.get('only_branch')
1844 1854
1845 1855 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1846 1856 for st, rev, fns in changeiter:
1847 1857 if st == 'add':
1848 1858 changenode = repo.changelog.node(rev)
1849 1859 parents = [p for p in repo.changelog.parentrevs(rev)
1850 1860 if p != nullrev]
1851 1861 if opts.get('no_merges') and len(parents) == 2:
1852 1862 continue
1853 1863 if opts.get('only_merges') and len(parents) != 2:
1854 1864 continue
1855 1865
1856 1866 if only_branches:
1857 1867 revbranch = get(rev)[5]['branch']
1858 1868 if revbranch not in only_branches:
1859 1869 continue
1860 1870
1861 1871 if df:
1862 1872 changes = get(rev)
1863 1873 if not df(changes[2][0]):
1864 1874 continue
1865 1875
1866 1876 if opts.get('keyword'):
1867 1877 changes = get(rev)
1868 1878 miss = 0
1869 1879 for k in [kw.lower() for kw in opts['keyword']]:
1870 1880 if not (k in changes[1].lower() or
1871 1881 k in changes[4].lower() or
1872 1882 k in " ".join(changes[3]).lower()):
1873 1883 miss = 1
1874 1884 break
1875 1885 if miss:
1876 1886 continue
1877 1887
1878 1888 if opts['user']:
1879 1889 changes = get(rev)
1880 1890 miss = 0
1881 1891 for k in opts['user']:
1882 1892 if k != changes[1]:
1883 1893 miss = 1
1884 1894 break
1885 1895 if miss:
1886 1896 continue
1887 1897
1888 1898 copies = []
1889 1899 if opts.get('copies') and rev:
1890 1900 for fn in get(rev)[3]:
1891 1901 rename = getrenamed(fn, rev)
1892 1902 if rename:
1893 1903 copies.append((fn, rename[0]))
1894 1904 displayer.show(rev, changenode, copies=copies)
1895 1905 elif st == 'iter':
1896 1906 if count == limit: break
1897 1907 if displayer.flush(rev):
1898 1908 count += 1
1899 1909
1900 1910 def manifest(ui, repo, node=None, rev=None):
1901 1911 """output the current or given revision of the project manifest
1902 1912
1903 1913 Print a list of version controlled files for the given revision.
1904 1914 If no revision is given, the parent of the working directory is used,
1905 1915 or tip if no revision is checked out.
1906 1916
1907 1917 The manifest is the list of files being version controlled. If no revision
1908 1918 is given then the first parent of the working directory is used.
1909 1919
1910 1920 With -v flag, print file permissions, symlink and executable bits. With
1911 1921 --debug flag, print file revision hashes.
1912 1922 """
1913 1923
1914 1924 if rev and node:
1915 1925 raise util.Abort(_("please specify just one revision"))
1916 1926
1917 1927 if not node:
1918 1928 node = rev
1919 1929
1920 1930 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
1921 1931 ctx = repo[node]
1922 1932 for f in ctx:
1923 1933 if ui.debugflag:
1924 1934 ui.write("%40s " % hex(ctx.manifest()[f]))
1925 1935 if ui.verbose:
1926 1936 ui.write(decor[ctx.flags(f)])
1927 1937 ui.write("%s\n" % f)
1928 1938
1929 1939 def merge(ui, repo, node=None, force=None, rev=None):
1930 1940 """merge working directory with another revision
1931 1941
1932 1942 Merge the contents of the current working directory and the
1933 1943 requested revision. Files that changed between either parent are
1934 1944 marked as changed for the next commit and a commit must be
1935 1945 performed before any further updates are allowed.
1936 1946
1937 1947 If no revision is specified, the working directory's parent is a
1938 1948 head revision, and the current branch contains exactly one other head,
1939 1949 the other head is merged with by default. Otherwise, an explicit
1940 1950 revision to merge with must be provided.
1941 1951 """
1942 1952
1943 1953 if rev and node:
1944 1954 raise util.Abort(_("please specify just one revision"))
1945 1955 if not node:
1946 1956 node = rev
1947 1957
1948 1958 if not node:
1949 1959 branch = repo.changectx(None).branch()
1950 1960 bheads = repo.branchheads(branch)
1951 1961 if len(bheads) > 2:
1952 1962 raise util.Abort(_("branch '%s' has %d heads - "
1953 1963 "please merge with an explicit rev") %
1954 1964 (branch, len(bheads)))
1955 1965
1956 1966 parent = repo.dirstate.parents()[0]
1957 1967 if len(bheads) == 1:
1958 1968 if len(repo.heads()) > 1:
1959 1969 raise util.Abort(_("branch '%s' has one head - "
1960 1970 "please merge with an explicit rev") %
1961 1971 branch)
1962 1972 msg = _('there is nothing to merge')
1963 1973 if parent != repo.lookup(repo[None].branch()):
1964 1974 msg = _('%s - use "hg update" instead') % msg
1965 1975 raise util.Abort(msg)
1966 1976
1967 1977 if parent not in bheads:
1968 1978 raise util.Abort(_('working dir not at a head rev - '
1969 1979 'use "hg update" or merge with an explicit rev'))
1970 1980 node = parent == bheads[0] and bheads[-1] or bheads[0]
1971 1981 return hg.merge(repo, node, force=force)
1972 1982
1973 1983 def outgoing(ui, repo, dest=None, **opts):
1974 1984 """show changesets not found in destination
1975 1985
1976 1986 Show changesets not found in the specified destination repository or
1977 1987 the default push location. These are the changesets that would be pushed
1978 1988 if a push was requested.
1979 1989
1980 1990 See pull for valid destination format details.
1981 1991 """
1982 1992 limit = cmdutil.loglimit(opts)
1983 1993 dest, revs, checkout = hg.parseurl(
1984 1994 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
1985 1995 cmdutil.setremoteconfig(ui, opts)
1986 1996 if revs:
1987 1997 revs = [repo.lookup(rev) for rev in revs]
1988 1998
1989 1999 other = hg.repository(ui, dest)
1990 2000 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
1991 2001 o = repo.findoutgoing(other, force=opts.get('force'))
1992 2002 if not o:
1993 2003 ui.status(_("no changes found\n"))
1994 2004 return 1
1995 2005 o = repo.changelog.nodesbetween(o, revs)[0]
1996 2006 if opts.get('newest_first'):
1997 2007 o.reverse()
1998 2008 displayer = cmdutil.show_changeset(ui, repo, opts)
1999 2009 count = 0
2000 2010 for n in o:
2001 2011 if count >= limit:
2002 2012 break
2003 2013 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2004 2014 if opts.get('no_merges') and len(parents) == 2:
2005 2015 continue
2006 2016 count += 1
2007 2017 displayer.show(changenode=n)
2008 2018
2009 2019 def parents(ui, repo, file_=None, **opts):
2010 2020 """show the parents of the working dir or revision
2011 2021
2012 2022 Print the working directory's parent revisions. If a
2013 2023 revision is given via --rev, the parent of that revision
2014 2024 will be printed. If a file argument is given, revision in
2015 2025 which the file was last changed (before the working directory
2016 2026 revision or the argument to --rev if given) is printed.
2017 2027 """
2018 2028 rev = opts.get('rev')
2019 2029 if rev:
2020 2030 ctx = repo[rev]
2021 2031 else:
2022 2032 ctx = repo[None]
2023 2033
2024 2034 if file_:
2025 2035 m = cmdutil.match(repo, (file_,), opts)
2026 2036 if m.anypats() or len(m.files()) != 1:
2027 2037 raise util.Abort(_('can only specify an explicit file name'))
2028 2038 file_ = m.files()[0]
2029 2039 filenodes = []
2030 2040 for cp in ctx.parents():
2031 2041 if not cp:
2032 2042 continue
2033 2043 try:
2034 2044 filenodes.append(cp.filenode(file_))
2035 2045 except revlog.LookupError:
2036 2046 pass
2037 2047 if not filenodes:
2038 2048 raise util.Abort(_("'%s' not found in manifest!") % file_)
2039 2049 fl = repo.file(file_)
2040 2050 p = [repo.lookup(fl.linkrev(fn)) for fn in filenodes]
2041 2051 else:
2042 2052 p = [cp.node() for cp in ctx.parents()]
2043 2053
2044 2054 displayer = cmdutil.show_changeset(ui, repo, opts)
2045 2055 for n in p:
2046 2056 if n != nullid:
2047 2057 displayer.show(changenode=n)
2048 2058
2049 2059 def paths(ui, repo, search=None):
2050 2060 """show definition of symbolic path names
2051 2061
2052 2062 Show definition of symbolic path name NAME. If no name is given, show
2053 2063 definition of available names.
2054 2064
2055 2065 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2056 2066 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2057 2067 """
2058 2068 if search:
2059 2069 for name, path in ui.configitems("paths"):
2060 2070 if name == search:
2061 2071 ui.write("%s\n" % util.hidepassword(path))
2062 2072 return
2063 2073 ui.warn(_("not found!\n"))
2064 2074 return 1
2065 2075 else:
2066 2076 for name, path in ui.configitems("paths"):
2067 2077 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
2068 2078
2069 2079 def postincoming(ui, repo, modheads, optupdate, checkout):
2070 2080 if modheads == 0:
2071 2081 return
2072 2082 if optupdate:
2073 2083 if modheads <= 1 or checkout:
2074 2084 return hg.update(repo, checkout)
2075 2085 else:
2076 2086 ui.status(_("not updating, since new heads added\n"))
2077 2087 if modheads > 1:
2078 2088 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2079 2089 else:
2080 2090 ui.status(_("(run 'hg update' to get a working copy)\n"))
2081 2091
2082 2092 def pull(ui, repo, source="default", **opts):
2083 2093 """pull changes from the specified source
2084 2094
2085 2095 Pull changes from a remote repository to a local one.
2086 2096
2087 2097 This finds all changes from the repository at the specified path
2088 2098 or URL and adds them to the local repository. By default, this
2089 2099 does not update the copy of the project in the working directory.
2090 2100
2091 2101 Valid URLs are of the form:
2092 2102
2093 2103 local/filesystem/path (or file://local/filesystem/path)
2094 2104 http://[user[:pass]@]host[:port]/[path]
2095 2105 https://[user[:pass]@]host[:port]/[path]
2096 2106 ssh://[user[:pass]@]host[:port]/[path]
2097 2107
2098 2108 Paths in the local filesystem can either point to Mercurial
2099 2109 repositories or to bundle files (as created by 'hg bundle' or
2100 2110 'hg incoming --bundle').
2101 2111
2102 2112 An optional identifier after # indicates a particular branch, tag,
2103 2113 or changeset to pull.
2104 2114
2105 2115 Some notes about using SSH with Mercurial:
2106 2116 - SSH requires an accessible shell account on the destination machine
2107 2117 and a copy of hg in the remote path or specified with as remotecmd.
2108 2118 - path is relative to the remote user's home directory by default.
2109 2119 Use an extra slash at the start of a path to specify an absolute path:
2110 2120 ssh://example.com//tmp/repository
2111 2121 - Mercurial doesn't use its own compression via SSH; the right thing
2112 2122 to do is to configure it in your ~/.ssh/config, e.g.:
2113 2123 Host *.mylocalnetwork.example.com
2114 2124 Compression no
2115 2125 Host *
2116 2126 Compression yes
2117 2127 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2118 2128 with the --ssh command line option.
2119 2129 """
2120 2130 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
2121 2131 cmdutil.setremoteconfig(ui, opts)
2122 2132
2123 2133 other = hg.repository(ui, source)
2124 2134 ui.status(_('pulling from %s\n') % util.hidepassword(source))
2125 2135 if revs:
2126 2136 try:
2127 2137 revs = [other.lookup(rev) for rev in revs]
2128 2138 except NoCapability:
2129 2139 error = _("Other repository doesn't support revision lookup, "
2130 2140 "so a rev cannot be specified.")
2131 2141 raise util.Abort(error)
2132 2142
2133 2143 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2134 2144 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2135 2145
2136 2146 def push(ui, repo, dest=None, **opts):
2137 2147 """push changes to the specified destination
2138 2148
2139 2149 Push changes from the local repository to the given destination.
2140 2150
2141 2151 This is the symmetrical operation for pull. It helps to move
2142 2152 changes from the current repository to a different one. If the
2143 2153 destination is local this is identical to a pull in that directory
2144 2154 from the current one.
2145 2155
2146 2156 By default, push will refuse to run if it detects the result would
2147 2157 increase the number of remote heads. This generally indicates the
2148 2158 the client has forgotten to pull and merge before pushing.
2149 2159
2150 2160 Valid URLs are of the form:
2151 2161
2152 2162 local/filesystem/path (or file://local/filesystem/path)
2153 2163 ssh://[user[:pass]@]host[:port]/[path]
2154 2164 http://[user[:pass]@]host[:port]/[path]
2155 2165 https://[user[:pass]@]host[:port]/[path]
2156 2166
2157 2167 An optional identifier after # indicates a particular branch, tag,
2158 2168 or changeset to push. If -r is used, the named changeset and all its
2159 2169 ancestors will be pushed to the remote repository.
2160 2170
2161 2171 Look at the help text for the pull command for important details
2162 2172 about ssh:// URLs.
2163 2173
2164 2174 Pushing to http:// and https:// URLs is only possible, if this
2165 2175 feature is explicitly enabled on the remote Mercurial server.
2166 2176 """
2167 2177 dest, revs, checkout = hg.parseurl(
2168 2178 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
2169 2179 cmdutil.setremoteconfig(ui, opts)
2170 2180
2171 2181 other = hg.repository(ui, dest)
2172 2182 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
2173 2183 if revs:
2174 2184 revs = [repo.lookup(rev) for rev in revs]
2175 2185 r = repo.push(other, opts.get('force'), revs=revs)
2176 2186 return r == 0
2177 2187
2178 2188 def rawcommit(ui, repo, *pats, **opts):
2179 2189 """raw commit interface (DEPRECATED)
2180 2190
2181 2191 (DEPRECATED)
2182 2192 Lowlevel commit, for use in helper scripts.
2183 2193
2184 2194 This command is not intended to be used by normal users, as it is
2185 2195 primarily useful for importing from other SCMs.
2186 2196
2187 2197 This command is now deprecated and will be removed in a future
2188 2198 release, please use debugsetparents and commit instead.
2189 2199 """
2190 2200
2191 2201 ui.warn(_("(the rawcommit command is deprecated)\n"))
2192 2202
2193 2203 message = cmdutil.logmessage(opts)
2194 2204
2195 2205 files = cmdutil.match(repo, pats, opts).files()
2196 2206 if opts.get('files'):
2197 2207 files += open(opts['files']).read().splitlines()
2198 2208
2199 2209 parents = [repo.lookup(p) for p in opts['parent']]
2200 2210
2201 2211 try:
2202 2212 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2203 2213 except ValueError, inst:
2204 2214 raise util.Abort(str(inst))
2205 2215
2206 2216 def recover(ui, repo):
2207 2217 """roll back an interrupted transaction
2208 2218
2209 2219 Recover from an interrupted commit or pull.
2210 2220
2211 2221 This command tries to fix the repository status after an interrupted
2212 2222 operation. It should only be necessary when Mercurial suggests it.
2213 2223 """
2214 2224 if repo.recover():
2215 2225 return hg.verify(repo)
2216 2226 return 1
2217 2227
2218 2228 def remove(ui, repo, *pats, **opts):
2219 2229 """remove the specified files on the next commit
2220 2230
2221 2231 Schedule the indicated files for removal from the repository.
2222 2232
2223 2233 This only removes files from the current branch, not from the entire
2224 2234 project history. -A can be used to remove only files that have already
2225 2235 been deleted, -f can be used to force deletion, and -Af can be used
2226 2236 to remove files from the next revision without deleting them.
2227 2237
2228 2238 The following table details the behavior of remove for different file
2229 2239 states (columns) and option combinations (rows). The file states are
2230 2240 Added, Clean, Modified and Missing (as reported by hg status). The
2231 2241 actions are Warn, Remove (from branch) and Delete (from disk).
2232 2242
2233 2243 A C M !
2234 2244 none W RD W R
2235 2245 -f R RD RD R
2236 2246 -A W W W R
2237 2247 -Af R R R R
2238 2248
2239 2249 This command schedules the files to be removed at the next commit.
2240 2250 To undo a remove before that, see hg revert.
2241 2251 """
2242 2252
2243 2253 after, force = opts.get('after'), opts.get('force')
2244 2254 if not pats and not after:
2245 2255 raise util.Abort(_('no files specified'))
2246 2256
2247 2257 m = cmdutil.match(repo, pats, opts)
2248 2258 s = repo.status(match=m, clean=True)
2249 2259 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2250 2260
2251 2261 def warn(files, reason):
2252 2262 for f in files:
2253 2263 ui.warn(_('not removing %s: file %s (use -f to force removal)\n')
2254 2264 % (m.rel(f), reason))
2255 2265
2256 2266 if force:
2257 2267 remove, forget = modified + deleted + clean, added
2258 2268 elif after:
2259 2269 remove, forget = deleted, []
2260 2270 warn(modified + added + clean, _('still exists'))
2261 2271 else:
2262 2272 remove, forget = deleted + clean, []
2263 2273 warn(modified, _('is modified'))
2264 2274 warn(added, _('has been marked for add'))
2265 2275
2266 2276 for f in util.sort(remove + forget):
2267 2277 if ui.verbose or not m.exact(f):
2268 2278 ui.status(_('removing %s\n') % m.rel(f))
2269 2279
2270 2280 repo.forget(forget)
2271 2281 repo.remove(remove, unlink=not after)
2272 2282
2273 2283 def rename(ui, repo, *pats, **opts):
2274 2284 """rename files; equivalent of copy + remove
2275 2285
2276 2286 Mark dest as copies of sources; mark sources for deletion. If
2277 2287 dest is a directory, copies are put in that directory. If dest is
2278 2288 a file, there can only be one source.
2279 2289
2280 2290 By default, this command copies the contents of files as they
2281 2291 stand in the working directory. If invoked with --after, the
2282 2292 operation is recorded, but no copying is performed.
2283 2293
2284 2294 This command takes effect in the next commit. To undo a rename
2285 2295 before that, see hg revert.
2286 2296 """
2287 2297 wlock = repo.wlock(False)
2288 2298 try:
2289 2299 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2290 2300 finally:
2291 2301 del wlock
2292 2302
2293 2303 def resolve(ui, repo, *pats, **opts):
2294 2304 """resolve file merges from a branch merge or update
2295 2305
2296 2306 This command will attempt to resolve unresolved merges from the
2297 2307 last update or merge command. This will use the local file
2298 2308 revision preserved at the last update or merge to cleanly retry
2299 2309 the file merge attempt. With no file or options specified, this
2300 2310 command will attempt to resolve all unresolved files.
2301 2311
2302 2312 The codes used to show the status of files are:
2303 2313 U = unresolved
2304 2314 R = resolved
2305 2315 """
2306 2316
2307 2317 if len([x for x in opts if opts[x]]) > 1:
2308 2318 raise util.Abort(_("too many options specified"))
2309 2319
2310 2320 ms = merge_.mergestate(repo)
2311 2321 m = cmdutil.match(repo, pats, opts)
2312 2322
2313 2323 for f in ms:
2314 2324 if m(f):
2315 2325 if opts.get("list"):
2316 2326 ui.write("%s %s\n" % (ms[f].upper(), f))
2317 2327 elif opts.get("mark"):
2318 2328 ms.mark(f, "r")
2319 2329 elif opts.get("unmark"):
2320 2330 ms.mark(f, "u")
2321 2331 else:
2322 2332 wctx = repo[None]
2323 2333 mctx = wctx.parents()[-1]
2324 2334 ms.resolve(f, wctx, mctx)
2325 2335
2326 2336 def revert(ui, repo, *pats, **opts):
2327 2337 """restore individual files or dirs to an earlier state
2328 2338
2329 2339 (use update -r to check out earlier revisions, revert does not
2330 2340 change the working dir parents)
2331 2341
2332 2342 With no revision specified, revert the named files or directories
2333 2343 to the contents they had in the parent of the working directory.
2334 2344 This restores the contents of the affected files to an unmodified
2335 2345 state and unschedules adds, removes, copies, and renames. If the
2336 2346 working directory has two parents, you must explicitly specify the
2337 2347 revision to revert to.
2338 2348
2339 2349 Using the -r option, revert the given files or directories to their
2340 2350 contents as of a specific revision. This can be helpful to "roll
2341 2351 back" some or all of an earlier change.
2342 2352 See 'hg help dates' for a list of formats valid for -d/--date.
2343 2353
2344 2354 Revert modifies the working directory. It does not commit any
2345 2355 changes, or change the parent of the working directory. If you
2346 2356 revert to a revision other than the parent of the working
2347 2357 directory, the reverted files will thus appear modified
2348 2358 afterwards.
2349 2359
2350 2360 If a file has been deleted, it is restored. If the executable
2351 2361 mode of a file was changed, it is reset.
2352 2362
2353 2363 If names are given, all files matching the names are reverted.
2354 2364 If no arguments are given, no files are reverted.
2355 2365
2356 2366 Modified files are saved with a .orig suffix before reverting.
2357 2367 To disable these backups, use --no-backup.
2358 2368 """
2359 2369
2360 2370 if opts["date"]:
2361 2371 if opts["rev"]:
2362 2372 raise util.Abort(_("you can't specify a revision and a date"))
2363 2373 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2364 2374
2365 2375 if not pats and not opts.get('all'):
2366 2376 raise util.Abort(_('no files or directories specified; '
2367 2377 'use --all to revert the whole repo'))
2368 2378
2369 2379 parent, p2 = repo.dirstate.parents()
2370 2380 if not opts.get('rev') and p2 != nullid:
2371 2381 raise util.Abort(_('uncommitted merge - please provide a '
2372 2382 'specific revision'))
2373 2383 ctx = repo[opts.get('rev')]
2374 2384 node = ctx.node()
2375 2385 mf = ctx.manifest()
2376 2386 if node == parent:
2377 2387 pmf = mf
2378 2388 else:
2379 2389 pmf = None
2380 2390
2381 2391 # need all matching names in dirstate and manifest of target rev,
2382 2392 # so have to walk both. do not print errors if files exist in one
2383 2393 # but not other.
2384 2394
2385 2395 names = {}
2386 2396
2387 2397 wlock = repo.wlock()
2388 2398 try:
2389 2399 # walk dirstate.
2390 2400 files = []
2391 2401
2392 2402 m = cmdutil.match(repo, pats, opts)
2393 2403 m.bad = lambda x,y: False
2394 2404 for abs in repo.walk(m):
2395 2405 names[abs] = m.rel(abs), m.exact(abs)
2396 2406
2397 2407 # walk target manifest.
2398 2408
2399 2409 def badfn(path, msg):
2400 2410 if path in names:
2401 2411 return False
2402 2412 path_ = path + '/'
2403 2413 for f in names:
2404 2414 if f.startswith(path_):
2405 2415 return False
2406 2416 repo.ui.warn("%s: %s\n" % (m.rel(path), msg))
2407 2417 return False
2408 2418
2409 2419 m = cmdutil.match(repo, pats, opts)
2410 2420 m.bad = badfn
2411 2421 for abs in repo[node].walk(m):
2412 2422 if abs not in names:
2413 2423 names[abs] = m.rel(abs), m.exact(abs)
2414 2424
2415 2425 m = cmdutil.matchfiles(repo, names)
2416 2426 changes = repo.status(match=m)[:4]
2417 2427 modified, added, removed, deleted = map(dict.fromkeys, changes)
2418 2428
2419 2429 # if f is a rename, also revert the source
2420 2430 cwd = repo.getcwd()
2421 2431 for f in added:
2422 2432 src = repo.dirstate.copied(f)
2423 2433 if src and src not in names and repo.dirstate[src] == 'r':
2424 2434 removed[src] = None
2425 2435 names[src] = (repo.pathto(src, cwd), True)
2426 2436
2427 2437 def removeforget(abs):
2428 2438 if repo.dirstate[abs] == 'a':
2429 2439 return _('forgetting %s\n')
2430 2440 return _('removing %s\n')
2431 2441
2432 2442 revert = ([], _('reverting %s\n'))
2433 2443 add = ([], _('adding %s\n'))
2434 2444 remove = ([], removeforget)
2435 2445 undelete = ([], _('undeleting %s\n'))
2436 2446
2437 2447 disptable = (
2438 2448 # dispatch table:
2439 2449 # file state
2440 2450 # action if in target manifest
2441 2451 # action if not in target manifest
2442 2452 # make backup if in target manifest
2443 2453 # make backup if not in target manifest
2444 2454 (modified, revert, remove, True, True),
2445 2455 (added, revert, remove, True, False),
2446 2456 (removed, undelete, None, False, False),
2447 2457 (deleted, revert, remove, False, False),
2448 2458 )
2449 2459
2450 2460 for abs, (rel, exact) in util.sort(names.items()):
2451 2461 mfentry = mf.get(abs)
2452 2462 target = repo.wjoin(abs)
2453 2463 def handle(xlist, dobackup):
2454 2464 xlist[0].append(abs)
2455 2465 if dobackup and not opts.get('no_backup') and util.lexists(target):
2456 2466 bakname = "%s.orig" % rel
2457 2467 ui.note(_('saving current version of %s as %s\n') %
2458 2468 (rel, bakname))
2459 2469 if not opts.get('dry_run'):
2460 2470 util.copyfile(target, bakname)
2461 2471 if ui.verbose or not exact:
2462 2472 msg = xlist[1]
2463 2473 if not isinstance(msg, basestring):
2464 2474 msg = msg(abs)
2465 2475 ui.status(msg % rel)
2466 2476 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2467 2477 if abs not in table: continue
2468 2478 # file has changed in dirstate
2469 2479 if mfentry:
2470 2480 handle(hitlist, backuphit)
2471 2481 elif misslist is not None:
2472 2482 handle(misslist, backupmiss)
2473 2483 break
2474 2484 else:
2475 2485 if abs not in repo.dirstate:
2476 2486 if mfentry:
2477 2487 handle(add, True)
2478 2488 elif exact:
2479 2489 ui.warn(_('file not managed: %s\n') % rel)
2480 2490 continue
2481 2491 # file has not changed in dirstate
2482 2492 if node == parent:
2483 2493 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2484 2494 continue
2485 2495 if pmf is None:
2486 2496 # only need parent manifest in this unlikely case,
2487 2497 # so do not read by default
2488 2498 pmf = repo[parent].manifest()
2489 2499 if abs in pmf:
2490 2500 if mfentry:
2491 2501 # if version of file is same in parent and target
2492 2502 # manifests, do nothing
2493 2503 if (pmf[abs] != mfentry or
2494 2504 pmf.flags(abs) != mf.flags(abs)):
2495 2505 handle(revert, False)
2496 2506 else:
2497 2507 handle(remove, False)
2498 2508
2499 2509 if not opts.get('dry_run'):
2500 2510 def checkout(f):
2501 2511 fc = ctx[f]
2502 2512 repo.wwrite(f, fc.data(), fc.flags())
2503 2513
2504 2514 audit_path = util.path_auditor(repo.root)
2505 2515 for f in remove[0]:
2506 2516 if repo.dirstate[f] == 'a':
2507 2517 repo.dirstate.forget(f)
2508 2518 continue
2509 2519 audit_path(f)
2510 2520 try:
2511 2521 util.unlink(repo.wjoin(f))
2512 2522 except OSError:
2513 2523 pass
2514 2524 repo.dirstate.remove(f)
2515 2525
2516 2526 normal = None
2517 2527 if node == parent:
2518 2528 # We're reverting to our parent. If possible, we'd like status
2519 2529 # to report the file as clean. We have to use normallookup for
2520 2530 # merges to avoid losing information about merged/dirty files.
2521 2531 if p2 != nullid:
2522 2532 normal = repo.dirstate.normallookup
2523 2533 else:
2524 2534 normal = repo.dirstate.normal
2525 2535 for f in revert[0]:
2526 2536 checkout(f)
2527 2537 if normal:
2528 2538 normal(f)
2529 2539
2530 2540 for f in add[0]:
2531 2541 checkout(f)
2532 2542 repo.dirstate.add(f)
2533 2543
2534 2544 normal = repo.dirstate.normallookup
2535 2545 if node == parent and p2 == nullid:
2536 2546 normal = repo.dirstate.normal
2537 2547 for f in undelete[0]:
2538 2548 checkout(f)
2539 2549 normal(f)
2540 2550
2541 2551 finally:
2542 2552 del wlock
2543 2553
2544 2554 def rollback(ui, repo):
2545 2555 """roll back the last transaction
2546 2556
2547 2557 This command should be used with care. There is only one level of
2548 2558 rollback, and there is no way to undo a rollback. It will also
2549 2559 restore the dirstate at the time of the last transaction, losing
2550 2560 any dirstate changes since that time.
2551 2561
2552 2562 Transactions are used to encapsulate the effects of all commands
2553 2563 that create new changesets or propagate existing changesets into a
2554 2564 repository. For example, the following commands are transactional,
2555 2565 and their effects can be rolled back:
2556 2566
2557 2567 commit
2558 2568 import
2559 2569 pull
2560 2570 push (with this repository as destination)
2561 2571 unbundle
2562 2572
2563 2573 This command is not intended for use on public repositories. Once
2564 2574 changes are visible for pull by other users, rolling a transaction
2565 2575 back locally is ineffective (someone else may already have pulled
2566 2576 the changes). Furthermore, a race is possible with readers of the
2567 2577 repository; for example an in-progress pull from the repository
2568 2578 may fail if a rollback is performed.
2569 2579 """
2570 2580 repo.rollback()
2571 2581
2572 2582 def root(ui, repo):
2573 2583 """print the root (top) of the current working dir
2574 2584
2575 2585 Print the root directory of the current repository.
2576 2586 """
2577 2587 ui.write(repo.root + "\n")
2578 2588
2579 2589 def serve(ui, repo, **opts):
2580 2590 """export the repository via HTTP
2581 2591
2582 2592 Start a local HTTP repository browser and pull server.
2583 2593
2584 2594 By default, the server logs accesses to stdout and errors to
2585 2595 stderr. Use the "-A" and "-E" options to log to files.
2586 2596 """
2587 2597
2588 2598 if opts["stdio"]:
2589 2599 if repo is None:
2590 2600 raise RepoError(_("There is no Mercurial repository here"
2591 2601 " (.hg not found)"))
2592 2602 s = sshserver.sshserver(ui, repo)
2593 2603 s.serve_forever()
2594 2604
2595 2605 parentui = ui.parentui or ui
2596 2606 optlist = ("name templates style address port prefix ipv6"
2597 2607 " accesslog errorlog webdir_conf certificate")
2598 2608 for o in optlist.split():
2599 2609 if opts[o]:
2600 2610 parentui.setconfig("web", o, str(opts[o]))
2601 2611 if (repo is not None) and (repo.ui != parentui):
2602 2612 repo.ui.setconfig("web", o, str(opts[o]))
2603 2613
2604 2614 if repo is None and not ui.config("web", "webdir_conf"):
2605 2615 raise RepoError(_("There is no Mercurial repository here"
2606 2616 " (.hg not found)"))
2607 2617
2608 2618 class service:
2609 2619 def init(self):
2610 2620 util.set_signal_handler()
2611 2621 self.httpd = hgweb.server.create_server(parentui, repo)
2612 2622
2613 2623 if not ui.verbose: return
2614 2624
2615 2625 if self.httpd.prefix:
2616 2626 prefix = self.httpd.prefix.strip('/') + '/'
2617 2627 else:
2618 2628 prefix = ''
2619 2629
2620 2630 port = ':%d' % self.httpd.port
2621 2631 if port == ':80':
2622 2632 port = ''
2623 2633
2624 2634 bindaddr = self.httpd.addr
2625 2635 if bindaddr == '0.0.0.0':
2626 2636 bindaddr = '*'
2627 2637 elif ':' in bindaddr: # IPv6
2628 2638 bindaddr = '[%s]' % bindaddr
2629 2639
2630 2640 fqaddr = self.httpd.fqaddr
2631 2641 if ':' in fqaddr:
2632 2642 fqaddr = '[%s]' % fqaddr
2633 2643 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2634 2644 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2635 2645
2636 2646 def run(self):
2637 2647 self.httpd.serve_forever()
2638 2648
2639 2649 service = service()
2640 2650
2641 2651 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2642 2652
2643 2653 def status(ui, repo, *pats, **opts):
2644 2654 """show changed files in the working directory
2645 2655
2646 2656 Show status of files in the repository. If names are given, only
2647 2657 files that match are shown. Files that are clean or ignored or
2648 2658 source of a copy/move operation, are not listed unless -c (clean),
2649 2659 -i (ignored), -C (copies) or -A is given. Unless options described
2650 2660 with "show only ..." are given, the options -mardu are used.
2651 2661
2652 2662 Option -q/--quiet hides untracked (unknown and ignored) files
2653 2663 unless explicitly requested with -u/--unknown or -i/-ignored.
2654 2664
2655 2665 NOTE: status may appear to disagree with diff if permissions have
2656 2666 changed or a merge has occurred. The standard diff format does not
2657 2667 report permission changes and diff only reports changes relative
2658 2668 to one merge parent.
2659 2669
2660 2670 If one revision is given, it is used as the base revision.
2661 2671 If two revisions are given, the difference between them is shown.
2662 2672
2663 2673 The codes used to show the status of files are:
2664 2674 M = modified
2665 2675 A = added
2666 2676 R = removed
2667 2677 C = clean
2668 2678 ! = deleted, but still tracked
2669 2679 ? = not tracked
2670 2680 I = ignored
2671 2681 = the previous added file was copied from here
2672 2682 """
2673 2683
2674 2684 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2675 2685 cwd = (pats and repo.getcwd()) or ''
2676 2686 end = opts.get('print0') and '\0' or '\n'
2677 2687 copy = {}
2678 2688 states = 'modified added removed deleted unknown ignored clean'.split()
2679 2689 show = [k for k in states if opts[k]]
2680 2690 if opts.get('all'):
2681 2691 show += ui.quiet and (states[:4] + ['clean']) or states
2682 2692 if not show:
2683 2693 show = ui.quiet and states[:4] or states[:5]
2684 2694
2685 2695 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
2686 2696 'ignored' in show, 'clean' in show, 'unknown' in show)
2687 2697 changestates = zip(states, 'MAR!?IC', stat)
2688 2698
2689 2699 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
2690 2700 ctxn = repo[nullid]
2691 2701 ctx1 = repo[node1]
2692 2702 ctx2 = repo[node2]
2693 2703 added = stat[1]
2694 2704 if node2 is None:
2695 2705 added = stat[0] + stat[1] # merged?
2696 2706
2697 2707 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].items():
2698 2708 if k in added:
2699 2709 copy[k] = v
2700 2710 elif v in added:
2701 2711 copy[v] = k
2702 2712
2703 2713 for state, char, files in changestates:
2704 2714 if state in show:
2705 2715 format = "%s %%s%s" % (char, end)
2706 2716 if opts.get('no_status'):
2707 2717 format = "%%s%s" % end
2708 2718
2709 2719 for f in files:
2710 2720 ui.write(format % repo.pathto(f, cwd))
2711 2721 if f in copy:
2712 2722 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end))
2713 2723
2714 2724 def tag(ui, repo, name1, *names, **opts):
2715 2725 """add one or more tags for the current or given revision
2716 2726
2717 2727 Name a particular revision using <name>.
2718 2728
2719 2729 Tags are used to name particular revisions of the repository and are
2720 2730 very useful to compare different revisions, to go back to significant
2721 2731 earlier versions or to mark branch points as releases, etc.
2722 2732
2723 2733 If no revision is given, the parent of the working directory is used,
2724 2734 or tip if no revision is checked out.
2725 2735
2726 2736 To facilitate version control, distribution, and merging of tags,
2727 2737 they are stored as a file named ".hgtags" which is managed
2728 2738 similarly to other project files and can be hand-edited if
2729 2739 necessary. The file '.hg/localtags' is used for local tags (not
2730 2740 shared among repositories).
2731 2741
2732 2742 See 'hg help dates' for a list of formats valid for -d/--date.
2733 2743 """
2734 2744
2735 2745 rev_ = "."
2736 2746 names = (name1,) + names
2737 2747 if len(names) != len(dict.fromkeys(names)):
2738 2748 raise util.Abort(_('tag names must be unique'))
2739 2749 for n in names:
2740 2750 if n in ['tip', '.', 'null']:
2741 2751 raise util.Abort(_('the name \'%s\' is reserved') % n)
2742 2752 if opts.get('rev') and opts.get('remove'):
2743 2753 raise util.Abort(_("--rev and --remove are incompatible"))
2744 2754 if opts.get('rev'):
2745 2755 rev_ = opts['rev']
2746 2756 message = opts.get('message')
2747 2757 if opts.get('remove'):
2748 2758 expectedtype = opts.get('local') and 'local' or 'global'
2749 2759 for n in names:
2750 2760 if not repo.tagtype(n):
2751 2761 raise util.Abort(_('tag \'%s\' does not exist') % n)
2752 2762 if repo.tagtype(n) != expectedtype:
2753 2763 raise util.Abort(_('tag \'%s\' is not a %s tag') %
2754 2764 (n, expectedtype))
2755 2765 rev_ = nullid
2756 2766 if not message:
2757 2767 message = _('Removed tag %s') % ', '.join(names)
2758 2768 elif not opts.get('force'):
2759 2769 for n in names:
2760 2770 if n in repo.tags():
2761 2771 raise util.Abort(_('tag \'%s\' already exists '
2762 2772 '(use -f to force)') % n)
2763 2773 if not rev_ and repo.dirstate.parents()[1] != nullid:
2764 2774 raise util.Abort(_('uncommitted merge - please provide a '
2765 2775 'specific revision'))
2766 2776 r = repo[rev_].node()
2767 2777
2768 2778 if not message:
2769 2779 message = (_('Added tag %s for changeset %s') %
2770 2780 (', '.join(names), short(r)))
2771 2781
2772 2782 date = opts.get('date')
2773 2783 if date:
2774 2784 date = util.parsedate(date)
2775 2785
2776 2786 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
2777 2787
2778 2788 def tags(ui, repo):
2779 2789 """list repository tags
2780 2790
2781 2791 List the repository tags.
2782 2792
2783 2793 This lists both regular and local tags. When the -v/--verbose switch
2784 2794 is used, a third column "local" is printed for local tags.
2785 2795 """
2786 2796
2787 2797 l = repo.tagslist()
2788 2798 l.reverse()
2789 2799 hexfunc = ui.debugflag and hex or short
2790 2800 tagtype = ""
2791 2801
2792 2802 for t, n in l:
2793 2803 if ui.quiet:
2794 2804 ui.write("%s\n" % t)
2795 2805 continue
2796 2806
2797 2807 try:
2798 2808 hn = hexfunc(n)
2799 2809 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2800 2810 except revlog.LookupError:
2801 2811 r = " ?:%s" % hn
2802 2812 else:
2803 2813 spaces = " " * (30 - util.locallen(t))
2804 2814 if ui.verbose:
2805 2815 if repo.tagtype(t) == 'local':
2806 2816 tagtype = " local"
2807 2817 else:
2808 2818 tagtype = ""
2809 2819 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2810 2820
2811 2821 def tip(ui, repo, **opts):
2812 2822 """show the tip revision
2813 2823
2814 2824 The tip revision (usually just called the tip) is the most
2815 2825 recently added changeset in the repository, the most recently
2816 2826 changed head.
2817 2827
2818 2828 If you have just made a commit, that commit will be the tip. If
2819 2829 you have just pulled changes from another repository, the tip of
2820 2830 that repository becomes the current tip. The "tip" tag is special
2821 2831 and cannot be renamed or assigned to a different changeset.
2822 2832 """
2823 2833 cmdutil.show_changeset(ui, repo, opts).show(len(repo) - 1)
2824 2834
2825 2835 def unbundle(ui, repo, fname1, *fnames, **opts):
2826 2836 """apply one or more changegroup files
2827 2837
2828 2838 Apply one or more compressed changegroup files generated by the
2829 2839 bundle command.
2830 2840 """
2831 2841 fnames = (fname1,) + fnames
2832 2842
2833 2843 lock = None
2834 2844 try:
2835 2845 lock = repo.lock()
2836 2846 for fname in fnames:
2837 2847 if os.path.exists(fname):
2838 2848 f = open(fname, "rb")
2839 2849 else:
2840 2850 f = urllib.urlopen(fname)
2841 2851 gen = changegroup.readbundle(f, fname)
2842 2852 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2843 2853 finally:
2844 2854 del lock
2845 2855
2846 2856 return postincoming(ui, repo, modheads, opts.get('update'), None)
2847 2857
2848 2858 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2849 2859 """update working directory
2850 2860
2851 2861 Update the repository's working directory to the specified revision,
2852 2862 or the tip of the current branch if none is specified. Use null as
2853 2863 the revision to remove the working copy (like 'hg clone -U').
2854 2864
2855 2865 If the requested revision is a descendant of the working
2856 2866 directory, any outstanding changes in the working directory will
2857 2867 be merged into the result. If it is not directly descended but is
2858 2868 on the same named branch, update aborts with a suggestion to use
2859 2869 merge or update -C instead.
2860 2870
2861 2871 If the requested revision is on a different named branch and the
2862 2872 working directory is clean, update quietly switches branches.
2863 2873
2864 2874 If you want to update just one file to an older revision, use revert.
2865 2875
2866 2876 See 'hg help dates' for a list of formats valid for --date.
2867 2877 """
2868 2878 if rev and node:
2869 2879 raise util.Abort(_("please specify just one revision"))
2870 2880
2871 2881 if not rev:
2872 2882 rev = node
2873 2883
2874 2884 if date:
2875 2885 if rev:
2876 2886 raise util.Abort(_("you can't specify a revision and a date"))
2877 2887 rev = cmdutil.finddate(ui, repo, date)
2878 2888
2879 2889 if clean:
2880 2890 return hg.clean(repo, rev)
2881 2891 else:
2882 2892 return hg.update(repo, rev)
2883 2893
2884 2894 def verify(ui, repo):
2885 2895 """verify the integrity of the repository
2886 2896
2887 2897 Verify the integrity of the current repository.
2888 2898
2889 2899 This will perform an extensive check of the repository's
2890 2900 integrity, validating the hashes and checksums of each entry in
2891 2901 the changelog, manifest, and tracked files, as well as the
2892 2902 integrity of their crosslinks and indices.
2893 2903 """
2894 2904 return hg.verify(repo)
2895 2905
2896 2906 def version_(ui):
2897 2907 """output version and copyright information"""
2898 2908 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2899 2909 % version.get_version())
2900 2910 ui.status(_(
2901 2911 "\nCopyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others\n"
2902 2912 "This is free software; see the source for copying conditions. "
2903 2913 "There is NO\nwarranty; "
2904 2914 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2905 2915 ))
2906 2916
2907 2917 # Command options and aliases are listed here, alphabetically
2908 2918
2909 2919 globalopts = [
2910 2920 ('R', 'repository', '',
2911 2921 _('repository root directory or symbolic path name')),
2912 2922 ('', 'cwd', '', _('change working directory')),
2913 2923 ('y', 'noninteractive', None,
2914 2924 _('do not prompt, assume \'yes\' for any required answers')),
2915 2925 ('q', 'quiet', None, _('suppress output')),
2916 2926 ('v', 'verbose', None, _('enable additional output')),
2917 2927 ('', 'config', [], _('set/override config option')),
2918 2928 ('', 'debug', None, _('enable debugging output')),
2919 2929 ('', 'debugger', None, _('start debugger')),
2920 2930 ('', 'encoding', util._encoding, _('set the charset encoding')),
2921 2931 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2922 2932 ('', 'lsprof', None, _('print improved command execution profile')),
2923 2933 ('', 'traceback', None, _('print traceback on exception')),
2924 2934 ('', 'time', None, _('time how long the command takes')),
2925 2935 ('', 'profile', None, _('print command execution profile')),
2926 2936 ('', 'version', None, _('output version information and exit')),
2927 2937 ('h', 'help', None, _('display help and exit')),
2928 2938 ]
2929 2939
2930 2940 dryrunopts = [('n', 'dry-run', None,
2931 2941 _('do not perform actions, just print output'))]
2932 2942
2933 2943 remoteopts = [
2934 2944 ('e', 'ssh', '', _('specify ssh command to use')),
2935 2945 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2936 2946 ]
2937 2947
2938 2948 walkopts = [
2939 2949 ('I', 'include', [], _('include names matching the given patterns')),
2940 2950 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2941 2951 ]
2942 2952
2943 2953 commitopts = [
2944 2954 ('m', 'message', '', _('use <text> as commit message')),
2945 2955 ('l', 'logfile', '', _('read commit message from <file>')),
2946 2956 ]
2947 2957
2948 2958 commitopts2 = [
2949 2959 ('d', 'date', '', _('record datecode as commit date')),
2950 2960 ('u', 'user', '', _('record user as committer')),
2951 2961 ]
2952 2962
2953 2963 templateopts = [
2954 2964 ('', 'style', '', _('display using template map file')),
2955 2965 ('', 'template', '', _('display with template')),
2956 2966 ]
2957 2967
2958 2968 logopts = [
2959 2969 ('p', 'patch', None, _('show patch')),
2960 2970 ('l', 'limit', '', _('limit number of changes displayed')),
2961 2971 ('M', 'no-merges', None, _('do not show merges')),
2962 2972 ] + templateopts
2963 2973
2964 2974 diffopts = [
2965 2975 ('a', 'text', None, _('treat all files as text')),
2966 2976 ('g', 'git', None, _('use git extended diff format')),
2967 2977 ('', 'nodates', None, _("don't include dates in diff headers"))
2968 2978 ]
2969 2979
2970 2980 diffopts2 = [
2971 2981 ('p', 'show-function', None, _('show which function each change is in')),
2972 2982 ('w', 'ignore-all-space', None,
2973 2983 _('ignore white space when comparing lines')),
2974 2984 ('b', 'ignore-space-change', None,
2975 2985 _('ignore changes in the amount of white space')),
2976 2986 ('B', 'ignore-blank-lines', None,
2977 2987 _('ignore changes whose lines are all blank')),
2978 2988 ('U', 'unified', '', _('number of lines of context to show'))
2979 2989 ]
2980 2990
2981 2991 table = {
2982 2992 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2983 2993 "addremove":
2984 2994 (addremove,
2985 2995 [('s', 'similarity', '',
2986 2996 _('guess renamed files by similarity (0<=s<=100)')),
2987 2997 ] + walkopts + dryrunopts,
2988 2998 _('hg addremove [OPTION]... [FILE]...')),
2989 2999 "^annotate|blame":
2990 3000 (annotate,
2991 3001 [('r', 'rev', '', _('annotate the specified revision')),
2992 3002 ('f', 'follow', None, _('follow file copies and renames')),
2993 3003 ('a', 'text', None, _('treat all files as text')),
2994 3004 ('u', 'user', None, _('list the author (long with -v)')),
2995 3005 ('d', 'date', None, _('list the date (short with -q)')),
2996 3006 ('n', 'number', None, _('list the revision number (default)')),
2997 3007 ('c', 'changeset', None, _('list the changeset')),
2998 3008 ('l', 'line-number', None,
2999 3009 _('show line number at the first appearance'))
3000 3010 ] + walkopts,
3001 3011 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3002 3012 "archive":
3003 3013 (archive,
3004 3014 [('', 'no-decode', None, _('do not pass files through decoders')),
3005 3015 ('p', 'prefix', '', _('directory prefix for files in archive')),
3006 3016 ('r', 'rev', '', _('revision to distribute')),
3007 3017 ('t', 'type', '', _('type of distribution to create')),
3008 3018 ] + walkopts,
3009 3019 _('hg archive [OPTION]... DEST')),
3010 3020 "backout":
3011 3021 (backout,
3012 3022 [('', 'merge', None,
3013 3023 _('merge with old dirstate parent after backout')),
3014 3024 ('', 'parent', '', _('parent to choose when backing out merge')),
3015 3025 ('r', 'rev', '', _('revision to backout')),
3016 3026 ] + walkopts + commitopts + commitopts2,
3017 3027 _('hg backout [OPTION]... [-r] REV')),
3018 3028 "bisect":
3019 3029 (bisect,
3020 3030 [('r', 'reset', False, _('reset bisect state')),
3021 3031 ('g', 'good', False, _('mark changeset good')),
3022 3032 ('b', 'bad', False, _('mark changeset bad')),
3023 3033 ('s', 'skip', False, _('skip testing changeset')),
3024 3034 ('c', 'command', '', _('Use command to check changeset state')),
3025 3035 ('U', 'noupdate', False, _('do not update to target'))],
3026 3036 _("hg bisect [-gbsr] [REV] [-c COMMAND]")),
3027 3037 "branch":
3028 3038 (branch,
3029 3039 [('f', 'force', None,
3030 3040 _('set branch name even if it shadows an existing branch')),
3031 3041 ('C', 'clean', None, _('reset branch name to parent branch name'))],
3032 3042 _('hg branch [-fC] [NAME]')),
3033 3043 "branches":
3034 3044 (branches,
3035 3045 [('a', 'active', False,
3036 3046 _('show only branches that have unmerged heads'))],
3037 3047 _('hg branches [-a]')),
3038 3048 "bundle":
3039 3049 (bundle,
3040 3050 [('f', 'force', None,
3041 3051 _('run even when remote repository is unrelated')),
3042 3052 ('r', 'rev', [],
3043 3053 _('a changeset up to which you would like to bundle')),
3044 3054 ('', 'base', [],
3045 3055 _('a base changeset to specify instead of a destination')),
3046 3056 ('a', 'all', None, _('bundle all changesets in the repository')),
3047 3057 ('t', 'type', 'bzip2', _('bundle compression type to use')),
3048 3058 ] + remoteopts,
3049 3059 _('hg bundle [-f] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
3050 3060 "cat":
3051 3061 (cat,
3052 3062 [('o', 'output', '', _('print output to file with formatted name')),
3053 3063 ('r', 'rev', '', _('print the given revision')),
3054 3064 ('', 'decode', None, _('apply any matching decode filter')),
3055 3065 ] + walkopts,
3056 3066 _('hg cat [OPTION]... FILE...')),
3057 3067 "^clone":
3058 3068 (clone,
3059 3069 [('U', 'noupdate', None,
3060 3070 _('the clone will only contain a repository (no working copy)')),
3061 3071 ('r', 'rev', [],
3062 3072 _('a changeset you would like to have after cloning')),
3063 3073 ('', 'pull', None, _('use pull protocol to copy metadata')),
3064 3074 ('', 'uncompressed', None,
3065 3075 _('use uncompressed transfer (fast over LAN)')),
3066 3076 ] + remoteopts,
3067 3077 _('hg clone [OPTION]... SOURCE [DEST]')),
3068 3078 "^commit|ci":
3069 3079 (commit,
3070 3080 [('A', 'addremove', None,
3071 3081 _('mark new/missing files as added/removed before committing')),
3072 3082 ] + walkopts + commitopts + commitopts2,
3073 3083 _('hg commit [OPTION]... [FILE]...')),
3074 3084 "copy|cp":
3075 3085 (copy,
3076 3086 [('A', 'after', None, _('record a copy that has already occurred')),
3077 3087 ('f', 'force', None,
3078 3088 _('forcibly copy over an existing managed file')),
3079 3089 ] + walkopts + dryrunopts,
3080 3090 _('hg copy [OPTION]... [SOURCE]... DEST')),
3081 3091 "debugancestor": (debugancestor, [],
3082 3092 _('hg debugancestor [INDEX] REV1 REV2')),
3083 3093 "debugcheckstate": (debugcheckstate, [], _('hg debugcheckstate')),
3084 3094 "debugcomplete":
3085 3095 (debugcomplete,
3086 3096 [('o', 'options', None, _('show the command options'))],
3087 3097 _('hg debugcomplete [-o] CMD')),
3088 3098 "debugdate":
3089 3099 (debugdate,
3090 3100 [('e', 'extended', None, _('try extended date formats'))],
3091 3101 _('hg debugdate [-e] DATE [RANGE]')),
3092 3102 "debugdata": (debugdata, [], _('hg debugdata FILE REV')),
3093 3103 "debugfsinfo": (debugfsinfo, [], _('hg debugfsinfo [PATH]')),
3094 3104 "debugindex": (debugindex, [], _('hg debugindex FILE')),
3095 3105 "debugindexdot": (debugindexdot, [], _('hg debugindexdot FILE')),
3096 3106 "debuginstall": (debuginstall, [], _('hg debuginstall')),
3097 3107 "debugrawcommit|rawcommit":
3098 3108 (rawcommit,
3099 3109 [('p', 'parent', [], _('parent')),
3100 3110 ('F', 'files', '', _('file list'))
3101 3111 ] + commitopts + commitopts2,
3102 3112 _('hg debugrawcommit [OPTION]... [FILE]...')),
3103 3113 "debugrebuildstate":
3104 3114 (debugrebuildstate,
3105 3115 [('r', 'rev', '', _('revision to rebuild to'))],
3106 3116 _('hg debugrebuildstate [-r REV] [REV]')),
3107 3117 "debugrename":
3108 3118 (debugrename,
3109 3119 [('r', 'rev', '', _('revision to debug'))],
3110 3120 _('hg debugrename [-r REV] FILE')),
3111 3121 "debugsetparents":
3112 3122 (debugsetparents,
3113 3123 [],
3114 3124 _('hg debugsetparents REV1 [REV2]')),
3115 3125 "debugstate":
3116 3126 (debugstate,
3117 3127 [('', 'nodates', None, _('do not display the saved mtime'))],
3118 3128 _('hg debugstate [OPTS]')),
3119 3129 "debugwalk": (debugwalk, walkopts, _('hg debugwalk [OPTION]... [FILE]...')),
3120 3130 "^diff":
3121 3131 (diff,
3122 3132 [('r', 'rev', [], _('revision'))
3123 3133 ] + diffopts + diffopts2 + walkopts,
3124 3134 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
3125 3135 "^export":
3126 3136 (export,
3127 3137 [('o', 'output', '', _('print output to file with formatted name')),
3128 3138 ('', 'switch-parent', None, _('diff against the second parent'))
3129 3139 ] + diffopts,
3130 3140 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
3131 3141 "grep":
3132 3142 (grep,
3133 3143 [('0', 'print0', None, _('end fields with NUL')),
3134 3144 ('', 'all', None, _('print all revisions that match')),
3135 3145 ('f', 'follow', None,
3136 3146 _('follow changeset history, or file history across copies and renames')),
3137 3147 ('i', 'ignore-case', None, _('ignore case when matching')),
3138 3148 ('l', 'files-with-matches', None,
3139 3149 _('print only filenames and revs that match')),
3140 3150 ('n', 'line-number', None, _('print matching line numbers')),
3141 3151 ('r', 'rev', [], _('search in given revision range')),
3142 3152 ('u', 'user', None, _('list the author (long with -v)')),
3143 3153 ('d', 'date', None, _('list the date (short with -q)')),
3144 3154 ] + walkopts,
3145 3155 _('hg grep [OPTION]... PATTERN [FILE]...')),
3146 3156 "heads":
3147 3157 (heads,
3148 3158 [('r', 'rev', '', _('show only heads which are descendants of rev')),
3149 3159 ] + templateopts,
3150 3160 _('hg heads [-r REV] [REV]...')),
3151 3161 "help": (help_, [], _('hg help [TOPIC]')),
3152 3162 "identify|id":
3153 3163 (identify,
3154 3164 [('r', 'rev', '', _('identify the specified rev')),
3155 3165 ('n', 'num', None, _('show local revision number')),
3156 3166 ('i', 'id', None, _('show global revision id')),
3157 3167 ('b', 'branch', None, _('show branch')),
3158 3168 ('t', 'tags', None, _('show tags'))],
3159 3169 _('hg identify [-nibt] [-r REV] [SOURCE]')),
3160 3170 "import|patch":
3161 3171 (import_,
3162 3172 [('p', 'strip', 1,
3163 3173 _('directory strip option for patch. This has the same\n'
3164 3174 'meaning as the corresponding patch option')),
3165 3175 ('b', 'base', '', _('base path')),
3166 3176 ('f', 'force', None,
3167 3177 _('skip check for outstanding uncommitted changes')),
3168 3178 ('', 'no-commit', None, _("don't commit, just update the working directory")),
3169 3179 ('', 'exact', None,
3170 3180 _('apply patch to the nodes from which it was generated')),
3171 3181 ('', 'import-branch', None,
3172 3182 _('Use any branch information in patch (implied by --exact)'))] +
3173 3183 commitopts + commitopts2,
3174 3184 _('hg import [OPTION]... PATCH...')),
3175 3185 "incoming|in":
3176 3186 (incoming,
3177 3187 [('f', 'force', None,
3178 3188 _('run even when remote repository is unrelated')),
3179 3189 ('n', 'newest-first', None, _('show newest record first')),
3180 3190 ('', 'bundle', '', _('file to store the bundles into')),
3181 3191 ('r', 'rev', [],
3182 3192 _('a specific revision up to which you would like to pull')),
3183 3193 ] + logopts + remoteopts,
3184 3194 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
3185 3195 ' [--bundle FILENAME] [SOURCE]')),
3186 3196 "^init":
3187 3197 (init,
3188 3198 remoteopts,
3189 3199 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
3190 3200 "locate":
3191 3201 (locate,
3192 3202 [('r', 'rev', '', _('search the repository as it stood at rev')),
3193 3203 ('0', 'print0', None,
3194 3204 _('end filenames with NUL, for use with xargs')),
3195 3205 ('f', 'fullpath', None,
3196 3206 _('print complete paths from the filesystem root')),
3197 3207 ] + walkopts,
3198 3208 _('hg locate [OPTION]... [PATTERN]...')),
3199 3209 "^log|history":
3200 3210 (log,
3201 3211 [('f', 'follow', None,
3202 3212 _('follow changeset history, or file history across copies and renames')),
3203 3213 ('', 'follow-first', None,
3204 3214 _('only follow the first parent of merge changesets')),
3205 3215 ('d', 'date', '', _('show revs matching date spec')),
3206 3216 ('C', 'copies', None, _('show copied files')),
3207 3217 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3208 3218 ('r', 'rev', [], _('show the specified revision or range')),
3209 3219 ('', 'removed', None, _('include revs where files were removed')),
3210 3220 ('m', 'only-merges', None, _('show only merges')),
3211 3221 ('u', 'user', [], _('revs committed by user')),
3212 3222 ('b', 'only-branch', [],
3213 3223 _('show only changesets within the given named branch')),
3214 3224 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3215 3225 ] + logopts + walkopts,
3216 3226 _('hg log [OPTION]... [FILE]')),
3217 3227 "manifest":
3218 3228 (manifest,
3219 3229 [('r', 'rev', '', _('revision to display'))],
3220 3230 _('hg manifest [-r REV]')),
3221 3231 "^merge":
3222 3232 (merge,
3223 3233 [('f', 'force', None, _('force a merge with outstanding changes')),
3224 3234 ('r', 'rev', '', _('revision to merge')),
3225 3235 ],
3226 3236 _('hg merge [-f] [[-r] REV]')),
3227 3237 "outgoing|out":
3228 3238 (outgoing,
3229 3239 [('f', 'force', None,
3230 3240 _('run even when remote repository is unrelated')),
3231 3241 ('r', 'rev', [],
3232 3242 _('a specific revision up to which you would like to push')),
3233 3243 ('n', 'newest-first', None, _('show newest record first')),
3234 3244 ] + logopts + remoteopts,
3235 3245 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3236 3246 "^parents":
3237 3247 (parents,
3238 3248 [('r', 'rev', '', _('show parents from the specified rev')),
3239 3249 ] + templateopts,
3240 3250 _('hg parents [-r REV] [FILE]')),
3241 3251 "paths": (paths, [], _('hg paths [NAME]')),
3242 3252 "^pull":
3243 3253 (pull,
3244 3254 [('u', 'update', None,
3245 3255 _('update to new tip if changesets were pulled')),
3246 3256 ('f', 'force', None,
3247 3257 _('run even when remote repository is unrelated')),
3248 3258 ('r', 'rev', [],
3249 3259 _('a specific revision up to which you would like to pull')),
3250 3260 ] + remoteopts,
3251 3261 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3252 3262 "^push":
3253 3263 (push,
3254 3264 [('f', 'force', None, _('force push')),
3255 3265 ('r', 'rev', [],
3256 3266 _('a specific revision up to which you would like to push')),
3257 3267 ] + remoteopts,
3258 3268 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3259 3269 "recover": (recover, [], _('hg recover')),
3260 3270 "^remove|rm":
3261 3271 (remove,
3262 3272 [('A', 'after', None, _('record delete for missing files')),
3263 3273 ('f', 'force', None,
3264 3274 _('remove (and delete) file even if added or modified')),
3265 3275 ] + walkopts,
3266 3276 _('hg remove [OPTION]... FILE...')),
3267 3277 "rename|mv":
3268 3278 (rename,
3269 3279 [('A', 'after', None, _('record a rename that has already occurred')),
3270 3280 ('f', 'force', None,
3271 3281 _('forcibly copy over an existing managed file')),
3272 3282 ] + walkopts + dryrunopts,
3273 3283 _('hg rename [OPTION]... SOURCE... DEST')),
3274 3284 "resolve":
3275 3285 (resolve,
3276 3286 [('l', 'list', None, _('list state of files needing merge')),
3277 3287 ('m', 'mark', None, _('mark files as resolved')),
3278 3288 ('u', 'unmark', None, _('unmark files as resolved'))],
3279 3289 _('hg resolve [OPTION] [FILES...]')),
3280 3290 "revert":
3281 3291 (revert,
3282 3292 [('a', 'all', None, _('revert all changes when no arguments given')),
3283 3293 ('d', 'date', '', _('tipmost revision matching date')),
3284 3294 ('r', 'rev', '', _('revision to revert to')),
3285 3295 ('', 'no-backup', None, _('do not save backup copies of files')),
3286 3296 ] + walkopts + dryrunopts,
3287 3297 _('hg revert [OPTION]... [-r REV] [NAME]...')),
3288 3298 "rollback": (rollback, [], _('hg rollback')),
3289 3299 "root": (root, [], _('hg root')),
3290 3300 "^serve":
3291 3301 (serve,
3292 3302 [('A', 'accesslog', '', _('name of access log file to write to')),
3293 3303 ('d', 'daemon', None, _('run server in background')),
3294 3304 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3295 3305 ('E', 'errorlog', '', _('name of error log file to write to')),
3296 3306 ('p', 'port', 0, _('port to listen on (default: 8000)')),
3297 3307 ('a', 'address', '', _('address to listen on (default: all interfaces)')),
3298 3308 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3299 3309 ('n', 'name', '',
3300 3310 _('name to show in web pages (default: working dir)')),
3301 3311 ('', 'webdir-conf', '', _('name of the webdir config file'
3302 3312 ' (serve more than one repo)')),
3303 3313 ('', 'pid-file', '', _('name of file to write process ID to')),
3304 3314 ('', 'stdio', None, _('for remote clients')),
3305 3315 ('t', 'templates', '', _('web templates to use')),
3306 3316 ('', 'style', '', _('template style to use')),
3307 3317 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3308 3318 ('', 'certificate', '', _('SSL certificate file'))],
3309 3319 _('hg serve [OPTION]...')),
3310 3320 "showconfig|debugconfig":
3311 3321 (showconfig,
3312 3322 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3313 3323 _('hg showconfig [-u] [NAME]...')),
3314 3324 "^status|st":
3315 3325 (status,
3316 3326 [('A', 'all', None, _('show status of all files')),
3317 3327 ('m', 'modified', None, _('show only modified files')),
3318 3328 ('a', 'added', None, _('show only added files')),
3319 3329 ('r', 'removed', None, _('show only removed files')),
3320 3330 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3321 3331 ('c', 'clean', None, _('show only files without changes')),
3322 3332 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3323 3333 ('i', 'ignored', None, _('show only ignored files')),
3324 3334 ('n', 'no-status', None, _('hide status prefix')),
3325 3335 ('C', 'copies', None, _('show source of copied files')),
3326 3336 ('0', 'print0', None,
3327 3337 _('end filenames with NUL, for use with xargs')),
3328 3338 ('', 'rev', [], _('show difference from revision')),
3329 3339 ] + walkopts,
3330 3340 _('hg status [OPTION]... [FILE]...')),
3331 3341 "tag":
3332 3342 (tag,
3333 3343 [('f', 'force', None, _('replace existing tag')),
3334 3344 ('l', 'local', None, _('make the tag local')),
3335 3345 ('r', 'rev', '', _('revision to tag')),
3336 3346 ('', 'remove', None, _('remove a tag')),
3337 3347 # -l/--local is already there, commitopts cannot be used
3338 3348 ('m', 'message', '', _('use <text> as commit message')),
3339 3349 ] + commitopts2,
3340 3350 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
3341 3351 "tags": (tags, [], _('hg tags')),
3342 3352 "tip":
3343 3353 (tip,
3344 3354 [('p', 'patch', None, _('show patch')),
3345 3355 ] + templateopts,
3346 3356 _('hg tip [-p]')),
3347 3357 "unbundle":
3348 3358 (unbundle,
3349 3359 [('u', 'update', None,
3350 3360 _('update to new tip if changesets were unbundled'))],
3351 3361 _('hg unbundle [-u] FILE...')),
3352 3362 "^update|up|checkout|co":
3353 3363 (update,
3354 3364 [('C', 'clean', None, _('overwrite locally modified files (no backup)')),
3355 3365 ('d', 'date', '', _('tipmost revision matching date')),
3356 3366 ('r', 'rev', '', _('revision'))],
3357 3367 _('hg update [-C] [-d DATE] [[-r] REV]')),
3358 3368 "verify": (verify, [], _('hg verify')),
3359 3369 "version": (version_, [], _('hg version')),
3360 3370 }
3361 3371
3362 3372 norepo = ("clone init version help debugcomplete debugdata"
3363 3373 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3364 3374 optionalrepo = ("identify paths serve showconfig debugancestor")
General Comments 0
You need to be logged in to leave comments. Login now