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