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