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