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