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