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