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