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