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