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