##// END OF EJS Templates
Add in and out aliases
mpm@selenic.com -
r940:1300271b default
parent child Browse files
Show More
@@ -1,620 +1,624 b''
1 1 HG(1)
2 2 =====
3 3 Matt Mackall <mpm@selenic.com>
4 4
5 5 NAME
6 6 ----
7 7 hg - Mercurial source code management system
8 8
9 9 SYNOPSIS
10 10 --------
11 11 'hg' [-v -d -q -y] <command> [command options] [files]
12 12
13 13 DESCRIPTION
14 14 -----------
15 15 The hg(1) command provides a command line interface to the Mercurial system.
16 16
17 17 OPTIONS
18 18 -------
19 19
20 20 --debug, -d::
21 21 enable debugging output
22 22
23 23 --quiet, -q::
24 24 suppress output
25 25
26 26 --verbose, -v::
27 27 enable additional output
28 28
29 29 --noninteractive, -y::
30 30 do not prompt, assume 'yes' for any required answers
31 31
32 32 COMMAND ELEMENTS
33 33 ----------------
34 34
35 35 files ...::
36 36 indicates one or more filename or relative path filenames; see
37 37 "FILE NAME PATTERNS" for information on pattern matching
38 38
39 39 path::
40 40 indicates a path on the local machine
41 41
42 42 revision::
43 43 indicates a changeset which can be specified as a changeset revision
44 44 number, a tag, or a unique substring of the changeset hash value
45 45
46 46 repository path::
47 47 either the pathname of a local repository or the URI of a remote
48 48 repository. There are two available URI protocols, http:// which is
49 49 fast and the old-http:// protocol which is much slower but does not
50 50 require a special server on the web host.
51 51
52 52 COMMANDS
53 53 --------
54 54
55 55 add [options] [files ...]::
56 56 Schedule files to be version controlled and added to the repository.
57 57
58 58 The files will be added to the repository at the next commit.
59 59
60 60 If no names are given, add all files in the current directory and
61 61 its subdirectories.
62 62
63 63 addremove [options] [files ...]::
64 64 Add all new files and remove all missing files from the repository.
65 65
66 66 New files are ignored if they match any of the patterns in .hgignore. As
67 67 with add, these changes take effect at the next commit.
68 68
69 69 annotate [-r <rev> -u -n -c] [files ...]::
70 70 List changes in files, showing the revision id responsible for each line
71 71
72 72 This command is useful to discover who did a change or when a change took
73 73 place.
74 74
75 75 options:
76 76 -I, --include <pat> include names matching the given patterns
77 77 -X, --exclude <pat> exclude names matching the given patterns
78 78 -r, --revision <rev> annotate the specified revision
79 79 -u, --user list the author
80 80 -c, --changeset list the changeset
81 81 -n, --number list the revision number (default)
82 82
83 83 cat <file> [revision]::
84 84 Output to stdout the given revision for the specified file.
85 85
86 86 If no revision is given then the tip is used.
87 87
88 88 clone [-U] <source> [dest]::
89 89 Create a copy of an existing repository in a new directory.
90 90
91 91 If no destination directory name is specified, it defaults to the
92 92 basename of the source.
93 93
94 94 The source is added to the new repository's .hg/hgrc file to be used in
95 95 future pulls.
96 96
97 97 For efficiency, hardlinks are used for cloning whenever the
98 98 source and destination are on the same filesystem.
99 99
100 100 options:
101 101 -U, --noupdate do not update the new working directory
102 102
103 103 commit [options] [files...]::
104 104 Commit changes to the given files into the repository.
105 105
106 106 If a list of files is omitted, all changes reported by "hg status"
107 107 from the root of the repository will be commited.
108 108
109 109 The HGEDITOR or EDITOR environment variables are used to start an
110 110 editor to add a commit comment.
111 111
112 112 Options:
113 113
114 114 -A, --addremove run addremove during commit
115 115 -I, --include <pat> include names matching the given patterns
116 116 -X, --exclude <pat> exclude names matching the given patterns
117 117 -m, --message <text> use <text> as commit message
118 118 -l, --logfile <file> show the commit message for the given file
119 119 -d, --date <datecode> record datecode as commit date
120 120 -u, --user <user> record user as commiter
121 121
122 122 aliases: ci
123 123
124 124 copy <source> <dest>::
125 125 Mark <dest> file as a copy or rename of a <source> one
126 126
127 127 This command takes effect for the next commit.
128 128
129 129 diff [-r revision] [-r revision] [files ...]::
130 130 Show differences between revisions for the specified files.
131 131
132 132 Differences between files are shown using the unified diff format.
133 133
134 134 When two revision arguments are given, then changes are shown
135 135 between those revisions. If only one revision is specified then
136 136 that revision is compared to the working directory, and, when no
137 137 revisions are specified, the working directory files are compared
138 138 to its parent.
139 139
140 140 options:
141 141 -I, --include <pat> include names matching the given patterns
142 142 -X, --exclude <pat> exclude names matching the given patterns
143 143
144 144 export [-o filespec] [revision] ...::
145 145 Print the changeset header and diffs for one or more revisions.
146 146
147 147 The information shown in the changeset header is: author,
148 148 changeset hash, parent and commit comment.
149 149
150 150 Output may be to a file, in which case the name of the file is
151 151 given using a format string. The formatting rules are as follows:
152 152
153 153 %% literal "%" character
154 154 %H changeset hash (40 bytes of hexadecimal)
155 155 %N number of patches being generated
156 156 %R changeset revision number
157 157 %b basename of the exporting repository
158 158 %h short-form changeset hash (12 bytes of hexadecimal)
159 159 %n zero-padded sequence number, starting at 1
160 160 %r zero-padded changeset revision number
161 161
162 162 Options:
163 163
164 164 -o, --output <filespec> print output to file with formatted named
165 165
166 166 forget [options] [files]::
167 167 Undo an 'hg add' scheduled for the next commit.
168 168
169 169 options:
170 170 -I, --include <pat> include names matching the given patterns
171 171 -X, --exclude <pat> exclude names matching the given patterns
172 172
173 173 heads::
174 174 Show all repository head changesets.
175 175
176 176 Repository "heads" are changesets that don't have children
177 177 changesets. They are where development generally takes place and
178 178 are the usual targets for update and merge operations.
179 179
180 180 identify::
181 181 Print a short summary of the current state of the repo.
182 182
183 183 This summary identifies the repository state using one or two parent
184 184 hash identifiers, followed by a "+" if there are uncommitted changes
185 185 in the working directory, followed by a list of tags for this revision.
186 186
187 187 aliases: id
188 188
189 189 import [-p <n> -b <base> -q] <patches>::
190 190 Import a list of patches and commit them individually.
191 191
192 192 options:
193 193 -p, --strip <n> directory strip option for patch. This has the same
194 194 meaning as the correnponding patch option
195 195 -b <path> base directory to read patches from
196 196
197 197 aliases: patch
198 198
199 199 incoming [source]::
200 200 Show new changesets found in the specified repo or the default
201 201 pull repo. These are the changesets that would be pulled if a pull
202 202 was requested.
203 203
204 204 Currently only local repositories are supported.
205 205
206 aliases: in
207
206 208 init [dest]::
207 209 Initialize a new repository in the given directory. If the given
208 210 directory does not exist, it is created.
209 211
210 212 If no directory is given, the current directory is used.
211 213
212 214 locate [options] [files]::
213 215 Print all files under Mercurial control whose names match the
214 216 given patterns.
215 217
216 218 This command searches the current directory and its
217 219 subdirectories. To search an entire repository, move to the root
218 220 of the repository.
219 221
220 222 If no patterns are given to match, this command prints all file
221 223 names.
222 224
223 225 If you want to feed the output of this command into the "xargs"
224 226 command, use the "-0" option to both this command and "xargs".
225 227 This will avoid the problem of "xargs" treating single filenames
226 228 that contain white space as multiple file names.
227 229
228 230 options:
229 231
230 232 -0, --print0 end filenames with NUL, for use with xargs
231 233 -f, --fullpath print complete paths from the filesystem root
232 234 -I, --include <pat> include names matching the given patterns
233 235 -r, --rev <rev> search the repository as it stood at rev
234 236 -X, --exclude <pat> exclude names matching the given patterns
235 237
236 238 log [-r revision ...] [-p] [file]::
237 239 Print the revision history of the specified file or the entire project.
238 240
239 241 By default this command outputs: changeset id and hash, tags,
240 242 parents, user, date and time, and a summary for each commit. The
241 243 -v switch adds some more detail, such as changed files, manifest
242 244 hashes or message signatures.
243 245
244 246 options:
245 247 -r, --rev <A>, ... When a revision argument is given, only this file or
246 248 changelog revision is displayed. With two revision
247 249 arguments all revisions in this range are listed.
248 250 Additional revision arguments may be given repeating
249 251 the above cycle.
250 252 -p, --patch show patch
251 253
252 254 aliases: history
253 255
254 256 manifest [revision]::
255 257 Print a list of version controlled files for the given revision.
256 258
257 259 The manifest is the list of files being version controlled. If no revision
258 260 is given then the tip is used.
259 261
260 262 outgoing [dest]::
261 263 Show changesets not found in the specified destination repo or the
262 264 default push repo. These are the changesets that would be pushed
263 265 if a push was requested.
264 266
267 aliases: out
268
265 269 parents::
266 270 Print the working directory's parent revisions.
267 271
268 272 paths [NAME]::
269 273 Show definition of symbolic path name NAME. If no name is given, show
270 274 definition of available names.
271 275
272 276 Path names are defined in the [paths] section of the $HOME/.hgrc and
273 277 <repo>/.hg/hgrc configuration files. If run outside a repo, 'paths'
274 278 queries only $HOME/.hgrc.
275 279
276 280 pull <repository path>::
277 281 Pull changes from a remote repository to a local one.
278 282
279 283 This finds all changes from the repository at the specified path
280 284 or URL and adds them to the local repository. By default, this
281 285 does not update the copy of the project in the working directory.
282 286
283 287 options:
284 288 -u, --update update the working directory to tip after pull
285 289
286 290 push <destination>::
287 291 Push changes from the local repository to the given destination.
288 292
289 293 This is the symmetrical operation for pull. It helps to move
290 294 changes from the current repository to a different one. If the
291 295 destination is local this is identical to a pull in that directory
292 296 from the current one.
293 297
294 298 The other currently available push method is SSH. This requires an
295 299 accessible shell account on the destination machine and a copy of
296 300 hg in the remote path. Destinations are specified in the following
297 301 form:
298 302
299 303 ssh://[user@]host[:port]/path
300 304
301 305 rawcommit [-p -d -u -F -m -l]::
302 306 Lowlevel commit, for use in helper scripts.
303 307
304 308 This command is not intended to be used by normal users, as it is
305 309 primarily useful for importing from other SCMs.
306 310
307 311 recover::
308 312 Recover from an interrupted commit or pull.
309 313
310 314 This command tries to fix the repository status after an interrupted
311 315 operation. It should only be necessary when Mercurial suggests it.
312 316
313 317 remove [files ...]::
314 318 Schedule the indicated files for removal from the repository.
315 319
316 320 This command shedules the files to be removed at the next commit.
317 321 This only removes files from the current branch, not from the
318 322 entire project history.
319 323
320 324 aliases: rm
321 325
322 326 revert [names ...]::
323 327 Revert any uncommitted modifications made to the named files or
324 328 directories. This restores the contents of the affected files to
325 329 an unmodified state.
326 330
327 331 If a file has been deleted, it is recreated. If the executable
328 332 mode of a file was changed, it is reset.
329 333
330 334 If a directory is given, all files in that directory and its
331 335 subdirectories are reverted.
332 336
333 337 If no arguments are given, all files in the current directory and
334 338 its subdirectories are reverted.
335 339
336 340 options:
337 341 -r, --rev <rev> revision to revert to
338 342 -n, --nonrecursive do not recurse into subdirectories
339 343
340 344 root::
341 345 Print the root directory of the current repository.
342 346
343 347 serve [options]::
344 348 Start a local HTTP repository browser and pull server.
345 349
346 350 By default, the server logs accesses to stdout and errors to
347 351 stderr. Use the "-A" and "-E" options to log to files.
348 352
349 353 options:
350 354 -A, --accesslog <file> name of access log file to write to
351 355 -E, --errorlog <file> name of error log file to write to
352 356 -a, --address <addr> address to use
353 357 -p, --port <n> port to use (default: 8000)
354 358 -n, --name <name> name to show in web pages (default: working dir)
355 359 -t, --templatedir <path> web templates to use
356 360 -6, --ipv6 use IPv6 in addition to IPv4
357 361
358 362 status [options] [files]::
359 363 Show changed files in the working directory. If no names are
360 364 given, all files are shown. Otherwise, only files matching the
361 365 given names are shown.
362 366
363 367 The codes used to show the status of files are:
364 368
365 369 M = changed
366 370 A = added
367 371 R = removed
368 372 ? = not tracked
369 373
370 374 options:
371 375
372 376 -m, --modified show only modified files
373 377 -a, --added show only added files
374 378 -r, --removed show only removed files
375 379 -u, --unknown show only unknown (not tracked) files
376 380 -I, --include <pat> include names matching the given patterns
377 381 -X, --exclude <pat> exclude names matching the given patterns
378 382
379 383 tag [-l -m <text> -d <datecode> -u <user>] <name> [revision]::
380 384 Name a particular revision using <name>.
381 385
382 386 Tags are used to name particular revisions of the repository and are
383 387 very useful to compare different revision, to go back to significant
384 388 earlier versions or to mark branch points as releases, etc.
385 389
386 390 If no revision is given, the tip is used.
387 391
388 392 To facilitate version control, distribution, and merging of tags,
389 393 they are stored as a file named ".hgtags" which is managed
390 394 similarly to other project files and can be hand-edited if
391 395 necessary.
392 396
393 397 options:
394 398 -l, --local make the tag local
395 399 -m, --message <text> message for tag commit log entry
396 400 -d, --date <datecode> datecode for commit
397 401 -u, --user <user> user for commit
398 402
399 403 Note: Local tags are not version-controlled or distributed and are
400 404 stored in the .hg/localtags file. If there exists a local tag and
401 405 a public tag with the same name, local tag is used.
402 406
403 407 tags::
404 408 List the repository tags.
405 409
406 410 This lists both regular and local tags.
407 411
408 412 tip::
409 413 Show the tip revision.
410 414
411 415 undo::
412 416 Undo the last commit or pull transaction.
413 417
414 418 Roll back the last pull or commit transaction on the
415 419 repository, restoring the project to its earlier state.
416 420
417 421 This command should be used with care. There is only one level of
418 422 undo and there is no redo.
419 423
420 424 This command is not intended for use on public repositories. Once
421 425 a change is visible for pull by other users, undoing it locally is
422 426 ineffective.
423 427
424 428 update [-m -C] [revision]::
425 429 Update the working directory to the specified revision.
426 430
427 431 By default, update will refuse to run if doing so would require
428 432 merging or discarding local changes.
429 433
430 434 With the -m option, a merge will be performed.
431 435
432 436 With the -C option, local changes will be lost.
433 437
434 438 options:
435 439 -m, --merge allow merging of branches
436 440 -C, --clean overwrite locally modified files
437 441
438 442 aliases: up checkout co
439 443
440 444 verify::
441 445 Verify the integrity of the current repository.
442 446
443 447 This will perform an extensive check of the repository's
444 448 integrity, validating the hashes and checksums of each entry in
445 449 the changelog, manifest, and tracked files, as well as the
446 450 integrity of their crosslinks and indices.
447 451
448 452 FILE NAME PATTERNS
449 453 ------------------
450 454
451 455 Mercurial accepts several notations for identifying one or more
452 456 file at a time.
453 457
454 458 By default, Mercurial treats file names as shell-style extended
455 459 glob patterns.
456 460
457 461 Alternate pattern notations must be specified explicitly.
458 462
459 463 To use a plain path name without any pattern matching, start a
460 464 name with "path:". These path names must match completely, from
461 465 the root of the current repository.
462 466
463 467 To use an extended glob, start a name with "glob:". Globs are
464 468 rooted at the current directory; a glob such as "*.c" will match
465 469 files ending in ".c" in the current directory only.
466 470
467 471 The supported glob syntax extensions are "**" to match any string
468 472 across path separators, and "{a,b}" to mean "a or b".
469 473
470 474 To use a Perl/Python regular expression, start a name with "re:".
471 475 Regexp pattern matching is anchored at the root of the repository.
472 476
473 477 Plain examples:
474 478
475 479 path:foo/bar a name bar in a directory named foo in the root of
476 480 the repository
477 481 path:path:name a file or directory named "path:name"
478 482
479 483 Glob examples:
480 484
481 485 glob:*.c any name ending in ".c" in the current directory
482 486 *.c any name ending in ".c" in the current directory
483 487 **.c any name ending in ".c" in the current directory, or
484 488 any subdirectory
485 489 foo/*.c any name ending in ".c" in the directory foo
486 490 foo/**.c any name ending in ".c" in the directory foo, or any
487 491 subdirectory
488 492
489 493 Regexp examples:
490 494
491 495 re:.*\.c$ any name ending in ".c", anywhere in the repsitory
492 496
493 497
494 498 SPECIFYING SINGLE REVISIONS
495 499 ---------------------------
496 500
497 501 Mercurial accepts several notations for identifying individual
498 502 revisions.
499 503
500 504 A plain integer is treated as a revision number. Negative
501 505 integers are treated as offsets from the tip, with -1 denoting the
502 506 tip.
503 507
504 508 A 40-digit hexadecimal string is treated as a unique revision
505 509 identifier.
506 510
507 511 A hexadecimal string less than 40 characters long is treated as a
508 512 unique revision identifier, and referred to as a short-form
509 513 identifier. A short-form identifier is only valid if it is the
510 514 prefix of one full-length identifier.
511 515
512 516 Any other string is treated as a tag name, which is a symbolic
513 517 name associated with a revision identifier. Tag names may not
514 518 contain the ":" character.
515 519
516 520 The reserved name "tip" is a special tag that always identifies
517 521 the most recent revision.
518 522
519 523 SPECIFYING MULTIPLE REVISIONS
520 524 -----------------------------
521 525
522 526 When Mercurial accepts more than one revision, they may be
523 527 specified individually, or provided as a continuous range,
524 528 separated by the ":" character.
525 529
526 530 The syntax of range notation is [BEGIN]:[END], where BEGIN and END
527 531 are revision identifiers. Both BEGIN and END are optional. If
528 532 BEGIN is not specified, it defaults to revision number 0. If END
529 533 is not specified, it defaults to the tip. The range ":" thus
530 534 means "all revisions".
531 535
532 536 If BEGIN is greater than END, revisions are treated in reverse
533 537 order.
534 538
535 539 A range acts as a closed interval. This means that a range of 3:5
536 540 gives 3, 4 and 5. Similarly, a range of 4:2 gives 4, 3, and 2.
537 541
538 542 ENVIRONMENT VARIABLES
539 543 ---------------------
540 544
541 545 HGEDITOR::
542 546 This is the name of the editor to use when committing. Defaults to the
543 547 value of EDITOR.
544 548
545 549 (deprecated, use .hgrc)
546 550
547 551 HGMERGE::
548 552 An executable to use for resolving merge conflicts. The program
549 553 will be executed with three arguments: local file, remote file,
550 554 ancestor file.
551 555
552 556 The default program is "hgmerge", which is a shell script provided
553 557 by Mercurial with some sensible defaults.
554 558
555 559 (deprecated, use .hgrc)
556 560
557 561 HGUSER::
558 562 This is the string used for the author of a commit.
559 563
560 564 (deprecated, use .hgrc)
561 565
562 566 EMAIL::
563 567 If HGUSER is not set, this will be used as the author for a commit.
564 568
565 569 LOGNAME::
566 570 If neither HGUSER nor EMAIL is set, LOGNAME will be used (with
567 571 '@hostname' appended) as the author value for a commit.
568 572
569 573 EDITOR::
570 574 This is the name of the editor used in the hgmerge script. It will be
571 575 used for commit messages if HGEDITOR isn't set. Defaults to 'vi'.
572 576
573 577 PYTHONPATH::
574 578 This is used by Python to find imported modules and may need to be set
575 579 appropriately if Mercurial is not installed system-wide.
576 580
577 581 FILES
578 582 -----
579 583 .hgignore::
580 584 This file contains regular expressions (one per line) that describe file
581 585 names that should be ignored by hg.
582 586
583 587 .hgtags::
584 588 This file contains changeset hash values and text tag names (one of each
585 589 seperated by spaces) that correspond to tagged versions of the repository
586 590 contents.
587 591
588 592 $HOME/.hgrc, .hg/hgrc::
589 593 This file contains defaults and configuration. Values in .hg/hgrc
590 594 override those in .hgrc. See hgrc(5) for details of the contents
591 595 and format of these files.
592 596
593 597 BUGS
594 598 ----
595 599 Probably lots, please post them to the mailing list (See Resources below)
596 600 when you find them.
597 601
598 602 SEE ALSO
599 603 --------
600 604 hgrc(5)
601 605
602 606 AUTHOR
603 607 ------
604 608 Written by Matt Mackall <mpm@selenic.com>
605 609
606 610 RESOURCES
607 611 ---------
608 612 http://selenic.com/mercurial[Main Web Site]
609 613
610 614 http://www.serpentine.com/mercurial[Wiki site]
611 615
612 616 http://selenic.com/hg[Source code repository]
613 617
614 618 http://selenic.com/mailman/listinfo/mercurial[Mailing list]
615 619
616 620 COPYING
617 621 -------
618 622 Copyright (C) 2005 Matt Mackall.
619 623 Free use of this software is granted under the terms of the GNU General
620 624 Public License (GPL).
@@ -1,1577 +1,1577 b''
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005 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 demandload import demandload
9 9 demandload(globals(), "os re sys signal shutil")
10 10 demandload(globals(), "fancyopts ui hg util lock")
11 11 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
12 12 demandload(globals(), "errno socket version struct atexit")
13 13
14 14 class UnknownCommand(Exception):
15 15 """Exception raised if command is not in the command table."""
16 16
17 17 def filterfiles(filters, files):
18 18 l = [x for x in files if x in filters]
19 19
20 20 for t in filters:
21 21 if t and t[-1] != "/":
22 22 t += "/"
23 23 l += [x for x in files if x.startswith(t)]
24 24 return l
25 25
26 26 def relfilter(repo, files):
27 27 cwd = repo.getcwd()
28 28 if cwd:
29 29 return filterfiles([util.pconvert(cwd)], files)
30 30 return files
31 31
32 32 def relpath(repo, args):
33 33 cwd = repo.getcwd()
34 34 if cwd:
35 35 return [util.normpath(os.path.join(cwd, x)) for x in args]
36 36 return args
37 37
38 38 def matchpats(repo, cwd, pats = [], opts = {}, head = ''):
39 39 return util.matcher(repo, cwd, pats or ['.'], opts.get('include'),
40 40 opts.get('exclude'), head)
41 41
42 42 def makewalk(repo, pats, opts, head = ''):
43 43 cwd = repo.getcwd()
44 44 files, matchfn = matchpats(repo, cwd, pats, opts, head)
45 45 def walk():
46 46 for src, fn in repo.walk(files = files, match = matchfn):
47 47 yield src, fn, util.pathto(cwd, fn)
48 48 return files, matchfn, walk()
49 49
50 50 def walk(repo, pats, opts, head = ''):
51 51 files, matchfn, results = makewalk(repo, pats, opts, head)
52 52 for r in results: yield r
53 53
54 54 revrangesep = ':'
55 55
56 56 def revrange(ui, repo, revs, revlog=None):
57 57 if revlog is None:
58 58 revlog = repo.changelog
59 59 revcount = revlog.count()
60 60 def fix(val, defval):
61 61 if not val:
62 62 return defval
63 63 try:
64 64 num = int(val)
65 65 if str(num) != val:
66 66 raise ValueError
67 67 if num < 0:
68 68 num += revcount
69 69 if not (0 <= num < revcount):
70 70 raise ValueError
71 71 except ValueError:
72 72 try:
73 73 num = repo.changelog.rev(repo.lookup(val))
74 74 except KeyError:
75 75 try:
76 76 num = revlog.rev(revlog.lookup(val))
77 77 except KeyError:
78 78 raise util.Abort('invalid revision identifier %s', val)
79 79 return num
80 80 for spec in revs:
81 81 if spec.find(revrangesep) >= 0:
82 82 start, end = spec.split(revrangesep, 1)
83 83 start = fix(start, 0)
84 84 end = fix(end, revcount - 1)
85 85 if end > start:
86 86 end += 1
87 87 step = 1
88 88 else:
89 89 end -= 1
90 90 step = -1
91 91 for rev in xrange(start, end, step):
92 92 yield str(rev)
93 93 else:
94 94 yield spec
95 95
96 96 def make_filename(repo, r, pat, node=None,
97 97 total=None, seqno=None, revwidth=None):
98 98 node_expander = {
99 99 'H': lambda: hg.hex(node),
100 100 'R': lambda: str(r.rev(node)),
101 101 'h': lambda: hg.short(node),
102 102 }
103 103 expander = {
104 104 '%': lambda: '%',
105 105 'b': lambda: os.path.basename(repo.root),
106 106 }
107 107
108 108 try:
109 109 if node:
110 110 expander.update(node_expander)
111 111 if node and revwidth is not None:
112 112 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
113 113 if total is not None:
114 114 expander['N'] = lambda: str(total)
115 115 if seqno is not None:
116 116 expander['n'] = lambda: str(seqno)
117 117 if total is not None and seqno is not None:
118 118 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
119 119
120 120 newname = []
121 121 patlen = len(pat)
122 122 i = 0
123 123 while i < patlen:
124 124 c = pat[i]
125 125 if c == '%':
126 126 i += 1
127 127 c = pat[i]
128 128 c = expander[c]()
129 129 newname.append(c)
130 130 i += 1
131 131 return ''.join(newname)
132 132 except KeyError, inst:
133 133 raise util.Abort("invalid format spec '%%%s' in output file name",
134 134 inst.args[0])
135 135
136 136 def make_file(repo, r, pat, node=None,
137 137 total=None, seqno=None, revwidth=None, mode='wb'):
138 138 if not pat or pat == '-':
139 139 if 'w' in mode: return sys.stdout
140 140 else: return sys.stdin
141 141 if hasattr(pat, 'write') and 'w' in mode:
142 142 return pat
143 143 if hasattr(pat, 'read') and 'r' in mode:
144 144 return pat
145 145 return open(make_filename(repo, r, pat, node, total, seqno, revwidth),
146 146 mode)
147 147
148 148 def dodiff(fp, ui, repo, files=None, node1=None, node2=None, match=util.always, changes=None):
149 149 def date(c):
150 150 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
151 151
152 152 if not changes:
153 153 (c, a, d, u) = repo.changes(node1, node2, files, match = match)
154 154 else:
155 155 (c, a, d, u) = changes
156 156 if files:
157 157 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
158 158
159 159 if not c and not a and not d:
160 160 return
161 161
162 162 if node2:
163 163 change = repo.changelog.read(node2)
164 164 mmap2 = repo.manifest.read(change[0])
165 165 date2 = date(change)
166 166 def read(f):
167 167 return repo.file(f).read(mmap2[f])
168 168 else:
169 169 date2 = time.asctime()
170 170 if not node1:
171 171 node1 = repo.dirstate.parents()[0]
172 172 def read(f):
173 173 return repo.wfile(f).read()
174 174
175 175 if ui.quiet:
176 176 r = None
177 177 else:
178 178 hexfunc = ui.verbose and hg.hex or hg.short
179 179 r = [hexfunc(node) for node in [node1, node2] if node]
180 180
181 181 change = repo.changelog.read(node1)
182 182 mmap = repo.manifest.read(change[0])
183 183 date1 = date(change)
184 184
185 185 for f in c:
186 186 to = None
187 187 if f in mmap:
188 188 to = repo.file(f).read(mmap[f])
189 189 tn = read(f)
190 190 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
191 191 for f in a:
192 192 to = None
193 193 tn = read(f)
194 194 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
195 195 for f in d:
196 196 to = repo.file(f).read(mmap[f])
197 197 tn = None
198 198 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
199 199
200 200 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None, brinfo=None):
201 201 """show a single changeset or file revision"""
202 202 changelog = repo.changelog
203 203 if filelog:
204 204 log = filelog
205 205 filerev = rev
206 206 node = filenode = filelog.node(filerev)
207 207 changerev = filelog.linkrev(filenode)
208 208 changenode = changenode or changelog.node(changerev)
209 209 else:
210 210 log = changelog
211 211 changerev = rev
212 212 if changenode is None:
213 213 changenode = changelog.node(changerev)
214 214 elif not changerev:
215 215 rev = changerev = changelog.rev(changenode)
216 216 node = changenode
217 217
218 218 if ui.quiet:
219 219 ui.write("%d:%s\n" % (rev, hg.short(node)))
220 220 return
221 221
222 222 changes = changelog.read(changenode)
223 223
224 224 parents = [(log.rev(p), ui.verbose and hg.hex(p) or hg.short(p))
225 225 for p in log.parents(node)
226 226 if ui.debugflag or p != hg.nullid]
227 227 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
228 228 parents = []
229 229
230 230 if ui.verbose:
231 231 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
232 232 else:
233 233 ui.write("changeset: %d:%s\n" % (changerev, hg.short(changenode)))
234 234
235 235 for tag in repo.nodetags(changenode):
236 236 ui.status("tag: %s\n" % tag)
237 237 for parent in parents:
238 238 ui.write("parent: %d:%s\n" % parent)
239 239 if filelog:
240 240 ui.debug("file rev: %d:%s\n" % (filerev, hg.hex(filenode)))
241 241
242 242 if brinfo and changenode in brinfo:
243 243 br = brinfo[changenode]
244 244 ui.write("branch: %s\n" % " ".join(br))
245 245
246 246 ui.debug("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
247 247 hg.hex(changes[0])))
248 248 ui.status("user: %s\n" % changes[1])
249 249 ui.status("date: %s\n" % time.asctime(
250 250 time.localtime(float(changes[2].split(' ')[0]))))
251 251
252 252 if ui.debugflag:
253 253 files = repo.changes(changelog.parents(changenode)[0], changenode)
254 254 for key, value in zip(["files:", "files+:", "files-:"], files):
255 255 if value:
256 256 ui.note("%-12s %s\n" % (key, " ".join(value)))
257 257 else:
258 258 ui.note("files: %s\n" % " ".join(changes[3]))
259 259
260 260 description = changes[4].strip()
261 261 if description:
262 262 if ui.verbose:
263 263 ui.status("description:\n")
264 264 ui.status(description)
265 265 ui.status("\n\n")
266 266 else:
267 267 ui.status("summary: %s\n" % description.splitlines()[0])
268 268 ui.status("\n")
269 269
270 270 def show_version(ui):
271 271 """output version and copyright information"""
272 272 ui.write("Mercurial Distributed SCM (version %s)\n"
273 273 % version.get_version())
274 274 ui.status(
275 275 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
276 276 "This is free software; see the source for copying conditions. "
277 277 "There is NO\nwarranty; "
278 278 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
279 279 )
280 280
281 281 def help_(ui, cmd=None):
282 282 """show help for a given command or all commands"""
283 283 if cmd and cmd != 'shortlist':
284 284 key, i = find(cmd)
285 285 # synopsis
286 286 ui.write("%s\n\n" % i[2])
287 287
288 288 # description
289 289 doc = i[0].__doc__
290 290 if ui.quiet:
291 291 doc = doc.splitlines(0)[0]
292 292 ui.write("%s\n" % doc.rstrip())
293 293
294 294 # aliases
295 295 if not ui.quiet:
296 296 aliases = ', '.join(key.split('|')[1:])
297 297 if aliases:
298 298 ui.write("\naliases: %s\n" % aliases)
299 299
300 300 # options
301 301 if not ui.quiet and i[1]:
302 302 ui.write("\noptions:\n\n")
303 303 for s, l, d, c in i[1]:
304 304 opt = ' '
305 305 if s:
306 306 opt = opt + '-' + s + ' '
307 307 if l:
308 308 opt = opt + '--' + l + ' '
309 309 if d:
310 310 opt = opt + '(' + str(d) + ')'
311 311 ui.write(opt, "\n")
312 312 if c:
313 313 ui.write(' %s\n' % c)
314 314
315 315 else:
316 316 # program name
317 317 if ui.verbose:
318 318 show_version(ui)
319 319 else:
320 320 ui.status("Mercurial Distributed SCM\n")
321 321 ui.status('\n')
322 322
323 323 # list of commands
324 324 if cmd == "shortlist":
325 325 ui.status('basic commands (use "hg help" '
326 326 'for the full list or option "-v" for details):\n\n')
327 327 elif ui.verbose:
328 328 ui.status('list of commands:\n\n')
329 329 else:
330 330 ui.status('list of commands (use "hg help -v" '
331 331 'to show aliases and global options):\n\n')
332 332
333 333 h = {}
334 334 cmds = {}
335 335 for c, e in table.items():
336 336 f = c.split("|")[0]
337 337 if cmd == "shortlist" and not f.startswith("^"):
338 338 continue
339 339 f = f.lstrip("^")
340 340 if not ui.debugflag and f.startswith("debug"):
341 341 continue
342 342 d = ""
343 343 if e[0].__doc__:
344 344 d = e[0].__doc__.splitlines(0)[0].rstrip()
345 345 h[f] = d
346 346 cmds[f]=c.lstrip("^")
347 347
348 348 fns = h.keys()
349 349 fns.sort()
350 350 m = max(map(len, fns))
351 351 for f in fns:
352 352 if ui.verbose:
353 353 commands = cmds[f].replace("|",", ")
354 354 ui.write(" %s:\n %s\n"%(commands,h[f]))
355 355 else:
356 356 ui.write(' %-*s %s\n' % (m, f, h[f]))
357 357
358 358 # global options
359 359 if ui.verbose:
360 360 ui.write("\nglobal options:\n\n")
361 361 for s, l, d, c in globalopts:
362 362 opt = ' '
363 363 if s:
364 364 opt = opt + '-' + s + ' '
365 365 if l:
366 366 opt = opt + '--' + l + ' '
367 367 if d:
368 368 opt = opt + '(' + str(d) + ')'
369 369 ui.write(opt, "\n")
370 370 if c:
371 371 ui.write(' %s\n' % c)
372 372
373 373 # Commands start here, listed alphabetically
374 374
375 375 def add(ui, repo, *pats, **opts):
376 376 '''add the specified files on the next commit'''
377 377 names = []
378 378 q = dict(zip(pats, pats))
379 379 for src, abs, rel in walk(repo, pats, opts):
380 380 if rel in q or abs in q:
381 381 names.append(abs)
382 382 elif repo.dirstate.state(abs) == '?':
383 383 ui.status('adding %s\n' % rel)
384 384 names.append(abs)
385 385 repo.add(names)
386 386
387 387 def addremove(ui, repo, *pats, **opts):
388 388 """add all new files, delete all missing files"""
389 389 q = dict(zip(pats, pats))
390 390 add, remove = [], []
391 391 for src, abs, rel in walk(repo, pats, opts):
392 392 if src == 'f' and repo.dirstate.state(abs) == '?':
393 393 add.append(abs)
394 394 if rel not in q: ui.status('adding ', rel, '\n')
395 395 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
396 396 remove.append(abs)
397 397 if rel not in q: ui.status('removing ', rel, '\n')
398 398 repo.add(add)
399 399 repo.remove(remove)
400 400
401 401 def annotate(ui, repo, *pats, **opts):
402 402 """show changeset information per file line"""
403 403 def getnode(rev):
404 404 return hg.short(repo.changelog.node(rev))
405 405
406 406 def getname(rev):
407 407 try:
408 408 return bcache[rev]
409 409 except KeyError:
410 410 cl = repo.changelog.read(repo.changelog.node(rev))
411 411 name = cl[1]
412 412 f = name.find('@')
413 413 if f >= 0:
414 414 name = name[:f]
415 415 f = name.find('<')
416 416 if f >= 0:
417 417 name = name[f+1:]
418 418 bcache[rev] = name
419 419 return name
420 420
421 421 if not pats:
422 422 raise util.Abort('at least one file name or pattern required')
423 423
424 424 bcache = {}
425 425 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
426 426 if not opts['user'] and not opts['changeset']:
427 427 opts['number'] = 1
428 428
429 429 if opts['rev']:
430 430 node = repo.changelog.lookup(opts['rev'])
431 431 else:
432 432 node = repo.dirstate.parents()[0]
433 433 change = repo.changelog.read(node)
434 434 mmap = repo.manifest.read(change[0])
435 435 for src, abs, rel in walk(repo, pats, opts):
436 436 if abs not in mmap:
437 437 ui.warn("warning: %s is not in the repository!\n" % rel)
438 438 continue
439 439
440 440 lines = repo.file(abs).annotate(mmap[abs])
441 441 pieces = []
442 442
443 443 for o, f in opmap:
444 444 if opts[o]:
445 445 l = [f(n) for n, dummy in lines]
446 446 if l:
447 447 m = max(map(len, l))
448 448 pieces.append(["%*s" % (m, x) for x in l])
449 449
450 450 if pieces:
451 451 for p, l in zip(zip(*pieces), lines):
452 452 ui.write("%s: %s" % (" ".join(p), l[1]))
453 453
454 454 def cat(ui, repo, file1, rev=None, **opts):
455 455 """output the latest or given revision of a file"""
456 456 r = repo.file(relpath(repo, [file1])[0])
457 457 if rev:
458 458 try:
459 459 # assume all revision numbers are for changesets
460 460 n = repo.lookup(rev)
461 461 change = repo.changelog.read(n)
462 462 m = repo.manifest.read(change[0])
463 463 n = m[relpath(repo, [file1])[0]]
464 464 except hg.RepoError, KeyError:
465 465 n = r.lookup(rev)
466 466 else:
467 467 n = r.tip()
468 468 fp = make_file(repo, r, opts['output'], node=n)
469 469 fp.write(r.read(n))
470 470
471 471 def clone(ui, source, dest=None, **opts):
472 472 """make a copy of an existing repository"""
473 473 if dest is None:
474 474 dest = os.path.basename(os.path.normpath(source))
475 475
476 476 if os.path.exists(dest):
477 477 ui.warn("abort: destination '%s' already exists\n" % dest)
478 478 return 1
479 479
480 480 dest = os.path.realpath(dest)
481 481
482 482 class Dircleanup:
483 483 def __init__(self, dir_):
484 484 self.rmtree = shutil.rmtree
485 485 self.dir_ = dir_
486 486 os.mkdir(dir_)
487 487 def close(self):
488 488 self.dir_ = None
489 489 def __del__(self):
490 490 if self.dir_:
491 491 self.rmtree(self.dir_, True)
492 492
493 493 d = Dircleanup(dest)
494 494 abspath = source
495 495 source = ui.expandpath(source)
496 496 other = hg.repository(ui, source)
497 497
498 498 if other.dev() != -1:
499 499 abspath = os.path.abspath(source)
500 500 copyfile = (os.stat(dest).st_dev == other.dev()
501 501 and getattr(os, 'link', None) or shutil.copy2)
502 502 if copyfile is not shutil.copy2:
503 503 ui.note("cloning by hardlink\n")
504 504 # we use a lock here because because we're not nicely ordered
505 505 l = lock.lock(os.path.join(source, ".hg", "lock"))
506 506
507 507 util.copytree(os.path.join(source, ".hg"), os.path.join(dest, ".hg"),
508 508 copyfile)
509 509 try:
510 510 os.unlink(os.path.join(dest, ".hg", "dirstate"))
511 511 except OSError:
512 512 pass
513 513
514 514 repo = hg.repository(ui, dest)
515 515
516 516 else:
517 517 repo = hg.repository(ui, dest, create=1)
518 518 repo.pull(other)
519 519
520 520 f = repo.opener("hgrc", "w")
521 521 f.write("[paths]\n")
522 522 f.write("default = %s\n" % abspath)
523 523
524 524 if not opts['noupdate']:
525 525 update(ui, repo)
526 526
527 527 d.close()
528 528
529 529 def commit(ui, repo, *pats, **opts):
530 530 """commit the specified files or all outstanding changes"""
531 531 if opts['text']:
532 532 ui.warn("Warning: -t and --text is deprecated,"
533 533 " please use -m or --message instead.\n")
534 534 message = opts['message'] or opts['text']
535 535 logfile = opts['logfile']
536 536 if not message and logfile:
537 537 try:
538 538 if logfile == '-':
539 539 message = sys.stdin.read()
540 540 else:
541 541 message = open(logfile).read()
542 542 except IOError, why:
543 543 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
544 544
545 545 if opts['addremove']:
546 546 addremove(ui, repo, *pats, **opts)
547 547 cwd = repo.getcwd()
548 548 if not pats and cwd:
549 549 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
550 550 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
551 551 fns, match = matchpats(repo, (pats and repo.getcwd()) or '', pats, opts)
552 552 if pats:
553 553 c, a, d, u = repo.changes(files = fns, match = match)
554 554 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
555 555 else:
556 556 files = []
557 557 repo.commit(files, message, opts['user'], opts['date'], match)
558 558
559 559 def copy(ui, repo, source, dest):
560 560 """mark a file as copied or renamed for the next commit"""
561 561 return repo.copy(*relpath(repo, (source, dest)))
562 562
563 563 def debugcheckstate(ui, repo):
564 564 """validate the correctness of the current dirstate"""
565 565 parent1, parent2 = repo.dirstate.parents()
566 566 repo.dirstate.read()
567 567 dc = repo.dirstate.map
568 568 keys = dc.keys()
569 569 keys.sort()
570 570 m1n = repo.changelog.read(parent1)[0]
571 571 m2n = repo.changelog.read(parent2)[0]
572 572 m1 = repo.manifest.read(m1n)
573 573 m2 = repo.manifest.read(m2n)
574 574 errors = 0
575 575 for f in dc:
576 576 state = repo.dirstate.state(f)
577 577 if state in "nr" and f not in m1:
578 578 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
579 579 errors += 1
580 580 if state in "a" and f in m1:
581 581 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
582 582 errors += 1
583 583 if state in "m" and f not in m1 and f not in m2:
584 584 ui.warn("%s in state %s, but not in either manifest\n" %
585 585 (f, state))
586 586 errors += 1
587 587 for f in m1:
588 588 state = repo.dirstate.state(f)
589 589 if state not in "nrm":
590 590 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
591 591 errors += 1
592 592 if errors:
593 593 raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
594 594
595 595 def debugstate(ui, repo):
596 596 """show the contents of the current dirstate"""
597 597 repo.dirstate.read()
598 598 dc = repo.dirstate.map
599 599 keys = dc.keys()
600 600 keys.sort()
601 601 for file_ in keys:
602 602 ui.write("%c %3o %10d %s %s\n"
603 603 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
604 604 time.strftime("%x %X",
605 605 time.localtime(dc[file_][3])), file_))
606 606
607 607 def debugindex(ui, file_):
608 608 """dump the contents of an index file"""
609 609 r = hg.revlog(hg.opener(""), file_, "")
610 610 ui.write(" rev offset length base linkrev" +
611 611 " p1 p2 nodeid\n")
612 612 for i in range(r.count()):
613 613 e = r.index[i]
614 614 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
615 615 i, e[0], e[1], e[2], e[3],
616 616 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
617 617
618 618 def debugindexdot(ui, file_):
619 619 """dump an index DAG as a .dot file"""
620 620 r = hg.revlog(hg.opener(""), file_, "")
621 621 ui.write("digraph G {\n")
622 622 for i in range(r.count()):
623 623 e = r.index[i]
624 624 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
625 625 if e[5] != hg.nullid:
626 626 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
627 627 ui.write("}\n")
628 628
629 629 def debugwalk(ui, repo, *pats, **opts):
630 630 items = list(walk(repo, pats, opts))
631 631 if not items: return
632 632 fmt = '%%s %%-%ds %%s' % max([len(abs) for (src, abs, rel) in items])
633 633 for i in items: print fmt % i
634 634
635 635 def diff(ui, repo, *pats, **opts):
636 636 """diff working directory (or selected files)"""
637 637 revs = []
638 638 if opts['rev']:
639 639 revs = map(lambda x: repo.lookup(x), opts['rev'])
640 640
641 641 if len(revs) > 2:
642 642 raise util.Abort("too many revisions to diff")
643 643
644 644 files = []
645 645 match = util.always
646 646 if pats:
647 647 roots, match, results = makewalk(repo, pats, opts)
648 648 for src, abs, rel in results:
649 649 files.append(abs)
650 650 dodiff(sys.stdout, ui, repo, files, *revs, **{'match': match})
651 651
652 652 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
653 653 node = repo.lookup(changeset)
654 654 prev, other = repo.changelog.parents(node)
655 655 change = repo.changelog.read(node)
656 656
657 657 fp = make_file(repo, repo.changelog, opts['output'],
658 658 node=node, total=total, seqno=seqno,
659 659 revwidth=revwidth)
660 660 if fp != sys.stdout:
661 661 ui.note("%s\n" % fp.name)
662 662
663 663 fp.write("# HG changeset patch\n")
664 664 fp.write("# User %s\n" % change[1])
665 665 fp.write("# Node ID %s\n" % hg.hex(node))
666 666 fp.write("# Parent %s\n" % hg.hex(prev))
667 667 if other != hg.nullid:
668 668 fp.write("# Parent %s\n" % hg.hex(other))
669 669 fp.write(change[4].rstrip())
670 670 fp.write("\n\n")
671 671
672 672 dodiff(fp, ui, repo, None, prev, node)
673 673 if fp != sys.stdout: fp.close()
674 674
675 675 def export(ui, repo, *changesets, **opts):
676 676 """dump the header and diffs for one or more changesets"""
677 677 if not changesets:
678 678 raise util.Abort("export requires at least one changeset")
679 679 seqno = 0
680 680 revs = list(revrange(ui, repo, changesets))
681 681 total = len(revs)
682 682 revwidth = max(len(revs[0]), len(revs[-1]))
683 683 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
684 684 for cset in revs:
685 685 seqno += 1
686 686 doexport(ui, repo, cset, seqno, total, revwidth, opts)
687 687
688 688 def forget(ui, repo, *pats, **opts):
689 689 """don't add the specified files on the next commit"""
690 690 q = dict(zip(pats, pats))
691 691 forget = []
692 692 for src, abs, rel in walk(repo, pats, opts):
693 693 if repo.dirstate.state(abs) == 'a':
694 694 forget.append(abs)
695 695 if rel not in q: ui.status('forgetting ', rel, '\n')
696 696 repo.forget(forget)
697 697
698 698 def heads(ui, repo, **opts):
699 699 """show current repository heads"""
700 700 heads = repo.changelog.heads()
701 701 br = None
702 702 if opts['branches']:
703 703 br = repo.branchlookup(heads)
704 704 for n in repo.changelog.heads():
705 705 show_changeset(ui, repo, changenode=n, brinfo=br)
706 706
707 707 def identify(ui, repo):
708 708 """print information about the working copy"""
709 709 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
710 710 if not parents:
711 711 ui.write("unknown\n")
712 712 return
713 713
714 714 hexfunc = ui.verbose and hg.hex or hg.short
715 715 (c, a, d, u) = repo.changes()
716 716 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
717 717 (c or a or d) and "+" or "")]
718 718
719 719 if not ui.quiet:
720 720 # multiple tags for a single parent separated by '/'
721 721 parenttags = ['/'.join(tags)
722 722 for tags in map(repo.nodetags, parents) if tags]
723 723 # tags for multiple parents separated by ' + '
724 724 if parenttags:
725 725 output.append(' + '.join(parenttags))
726 726
727 727 ui.write("%s\n" % ' '.join(output))
728 728
729 729 def import_(ui, repo, patch1, *patches, **opts):
730 730 """import an ordered set of patches"""
731 731 patches = (patch1,) + patches
732 732
733 733 d = opts["base"]
734 734 strip = opts["strip"]
735 735
736 736 for patch in patches:
737 737 ui.status("applying %s\n" % patch)
738 738 pf = os.path.join(d, patch)
739 739
740 740 message = []
741 741 user = None
742 742 hgpatch = False
743 743 for line in file(pf):
744 744 line = line.rstrip()
745 745 if line.startswith("--- ") or line.startswith("diff -r"):
746 746 break
747 747 elif hgpatch:
748 748 # parse values when importing the result of an hg export
749 749 if line.startswith("# User "):
750 750 user = line[7:]
751 751 ui.debug('User: %s\n' % user)
752 752 elif not line.startswith("# ") and line:
753 753 message.append(line)
754 754 hgpatch = False
755 755 elif line == '# HG changeset patch':
756 756 hgpatch = True
757 757 message = [] # We may have collected garbage
758 758 else:
759 759 message.append(line)
760 760
761 761 # make sure message isn't empty
762 762 if not message:
763 763 message = "imported patch %s\n" % patch
764 764 else:
765 765 message = "%s\n" % '\n'.join(message)
766 766 ui.debug('message:\n%s\n' % message)
767 767
768 768 f = os.popen("patch -p%d < '%s'" % (strip, pf))
769 769 files = []
770 770 for l in f.read().splitlines():
771 771 l.rstrip('\r\n');
772 772 ui.status("%s\n" % l)
773 773 if l.startswith('patching file '):
774 774 pf = l[14:]
775 775 if pf not in files:
776 776 files.append(pf)
777 777 patcherr = f.close()
778 778 if patcherr:
779 779 raise util.Abort("patch failed")
780 780
781 781 if len(files) > 0:
782 782 addremove(ui, repo, *files)
783 783 repo.commit(files, message, user)
784 784
785 785 def incoming(ui, repo, source="default"):
786 786 """show new changesets found in source"""
787 787 source = ui.expandpath(source)
788 788 other = hg.repository(ui, source)
789 789 if not other.local():
790 790 ui.warn("abort: incoming doesn't work for remote"
791 791 + " repositories yet, sorry!\n")
792 792 return 1
793 793 o = repo.findincoming(other)
794 794 if not o:
795 795 return
796 796 o = other.newer(o)
797 797 o.reverse()
798 798 for n in o:
799 799 show_changeset(ui, other, changenode=n)
800 800
801 801 def init(ui, dest="."):
802 802 """create a new repository in the given directory"""
803 803 if not os.path.exists(dest):
804 804 os.mkdir(dest)
805 805 hg.repository(ui, dest, create=1)
806 806
807 807 def locate(ui, repo, *pats, **opts):
808 808 """locate files matching specific patterns"""
809 809 end = '\n'
810 810 if opts['print0']: end = '\0'
811 811
812 812 for src, abs, rel in walk(repo, pats, opts, '(?:.*/|)'):
813 813 if repo.dirstate.state(abs) == '?': continue
814 814 if opts['fullpath']:
815 815 ui.write(os.path.join(repo.root, abs), end)
816 816 else:
817 817 ui.write(rel, end)
818 818
819 819 def log(ui, repo, f=None, **opts):
820 820 """show the revision history of the repository or a single file"""
821 821 if f:
822 822 files = relpath(repo, [f])
823 823 filelog = repo.file(files[0])
824 824 log = filelog
825 825 lookup = filelog.lookup
826 826 else:
827 827 files = None
828 828 filelog = None
829 829 log = repo.changelog
830 830 lookup = repo.lookup
831 831 revlist = []
832 832 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
833 833 while revs:
834 834 if len(revs) == 1:
835 835 revlist.append(revs.pop(0))
836 836 else:
837 837 a = revs.pop(0)
838 838 b = revs.pop(0)
839 839 off = a > b and -1 or 1
840 840 revlist.extend(range(a, b + off, off))
841 841
842 842 for i in revlist or range(log.count() - 1, -1, -1):
843 843 show_changeset(ui, repo, filelog=filelog, rev=i)
844 844 if opts['patch']:
845 845 if filelog:
846 846 filenode = filelog.node(i)
847 847 i = filelog.linkrev(filenode)
848 848 changenode = repo.changelog.node(i)
849 849 prev, other = repo.changelog.parents(changenode)
850 850 dodiff(sys.stdout, ui, repo, files, prev, changenode)
851 851 ui.write("\n\n")
852 852
853 853 def manifest(ui, repo, rev=None):
854 854 """output the latest or given revision of the project manifest"""
855 855 if rev:
856 856 try:
857 857 # assume all revision numbers are for changesets
858 858 n = repo.lookup(rev)
859 859 change = repo.changelog.read(n)
860 860 n = change[0]
861 861 except hg.RepoError:
862 862 n = repo.manifest.lookup(rev)
863 863 else:
864 864 n = repo.manifest.tip()
865 865 m = repo.manifest.read(n)
866 866 mf = repo.manifest.readflags(n)
867 867 files = m.keys()
868 868 files.sort()
869 869
870 870 for f in files:
871 871 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
872 872
873 873 def outgoing(ui, repo, dest="default-push"):
874 874 """show changesets not found in destination"""
875 875 dest = ui.expandpath(dest)
876 876 other = hg.repository(ui, dest)
877 877 o = repo.findoutgoing(other)
878 878 o = repo.newer(o)
879 879 o.reverse()
880 880 for n in o:
881 881 show_changeset(ui, repo, changenode=n)
882 882
883 883 def parents(ui, repo, rev=None):
884 884 """show the parents of the working dir or revision"""
885 885 if rev:
886 886 p = repo.changelog.parents(repo.lookup(rev))
887 887 else:
888 888 p = repo.dirstate.parents()
889 889
890 890 for n in p:
891 891 if n != hg.nullid:
892 892 show_changeset(ui, repo, changenode=n)
893 893
894 894 def paths(ui, search = None):
895 895 """show definition of symbolic path names"""
896 896 try:
897 897 repo = hg.repository(ui=ui)
898 898 except:
899 899 pass
900 900
901 901 if search:
902 902 for name, path in ui.configitems("paths"):
903 903 if name == search:
904 904 ui.write("%s\n" % path)
905 905 return
906 906 ui.warn("not found!\n")
907 907 return 1
908 908 else:
909 909 for name, path in ui.configitems("paths"):
910 910 ui.write("%s = %s\n" % (name, path))
911 911
912 912 def pull(ui, repo, source="default", **opts):
913 913 """pull changes from the specified source"""
914 914 source = ui.expandpath(source)
915 915 ui.status('pulling from %s\n' % (source))
916 916
917 917 other = hg.repository(ui, source)
918 918 r = repo.pull(other)
919 919 if not r:
920 920 if opts['update']:
921 921 return update(ui, repo)
922 922 else:
923 923 ui.status("(run 'hg update' to get a working copy)\n")
924 924
925 925 return r
926 926
927 927 def push(ui, repo, dest="default-push", force=False):
928 928 """push changes to the specified destination"""
929 929 dest = ui.expandpath(dest)
930 930 ui.status('pushing to %s\n' % (dest))
931 931
932 932 other = hg.repository(ui, dest)
933 933 r = repo.push(other, force)
934 934 return r
935 935
936 936 def rawcommit(ui, repo, *flist, **rc):
937 937 "raw commit interface"
938 938 if rc['text']:
939 939 ui.warn("Warning: -t and --text is deprecated,"
940 940 " please use -m or --message instead.\n")
941 941 message = rc['message'] or rc['text']
942 942 if not message and rc['logfile']:
943 943 try:
944 944 message = open(rc['logfile']).read()
945 945 except IOError:
946 946 pass
947 947 if not message and not rc['logfile']:
948 948 ui.warn("abort: missing commit message\n")
949 949 return 1
950 950
951 951 files = relpath(repo, list(flist))
952 952 if rc['files']:
953 953 files += open(rc['files']).read().splitlines()
954 954
955 955 rc['parent'] = map(repo.lookup, rc['parent'])
956 956
957 957 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
958 958
959 959 def recover(ui, repo):
960 960 """roll back an interrupted transaction"""
961 961 repo.recover()
962 962
963 963 def remove(ui, repo, file1, *files):
964 964 """remove the specified files on the next commit"""
965 965 repo.remove(relpath(repo, (file1,) + files))
966 966
967 967 def revert(ui, repo, *names, **opts):
968 968 """revert modified files or dirs back to their unmodified states"""
969 969 node = opts['rev'] and repo.lookup(opts['rev']) or \
970 970 repo.dirstate.parents()[0]
971 971 root = os.path.realpath(repo.root)
972 972
973 973 def trimpath(p):
974 974 p = os.path.realpath(p)
975 975 if p.startswith(root):
976 976 rest = p[len(root):]
977 977 if not rest:
978 978 return rest
979 979 if p.startswith(os.sep):
980 980 return rest[1:]
981 981 return p
982 982
983 983 relnames = map(trimpath, names or [os.getcwd()])
984 984 chosen = {}
985 985
986 986 def choose(name):
987 987 def body(name):
988 988 for r in relnames:
989 989 if not name.startswith(r):
990 990 continue
991 991 rest = name[len(r):]
992 992 if not rest:
993 993 return r, True
994 994 depth = rest.count(os.sep)
995 995 if not r:
996 996 if depth == 0 or not opts['nonrecursive']:
997 997 return r, True
998 998 elif rest[0] == os.sep:
999 999 if depth == 1 or not opts['nonrecursive']:
1000 1000 return r, True
1001 1001 return None, False
1002 1002 relname, ret = body(name)
1003 1003 if ret:
1004 1004 chosen[relname] = 1
1005 1005 return ret
1006 1006
1007 1007 r = repo.update(node, False, True, choose, False)
1008 1008 for n in relnames:
1009 1009 if n not in chosen:
1010 1010 ui.warn('error: no matches for %s\n' % n)
1011 1011 r = 1
1012 1012 sys.stdout.flush()
1013 1013 return r
1014 1014
1015 1015 def root(ui, repo):
1016 1016 """print the root (top) of the current working dir"""
1017 1017 ui.write(repo.root + "\n")
1018 1018
1019 1019 def serve(ui, repo, **opts):
1020 1020 """export the repository via HTTP"""
1021 1021
1022 1022 if opts["stdio"]:
1023 1023 fin, fout = sys.stdin, sys.stdout
1024 1024 sys.stdout = sys.stderr
1025 1025
1026 1026 def getarg():
1027 1027 argline = fin.readline()[:-1]
1028 1028 arg, l = argline.split()
1029 1029 val = fin.read(int(l))
1030 1030 return arg, val
1031 1031 def respond(v):
1032 1032 fout.write("%d\n" % len(v))
1033 1033 fout.write(v)
1034 1034 fout.flush()
1035 1035
1036 1036 lock = None
1037 1037
1038 1038 while 1:
1039 1039 cmd = fin.readline()[:-1]
1040 1040 if cmd == '':
1041 1041 return
1042 1042 if cmd == "heads":
1043 1043 h = repo.heads()
1044 1044 respond(" ".join(map(hg.hex, h)) + "\n")
1045 1045 if cmd == "lock":
1046 1046 lock = repo.lock()
1047 1047 respond("")
1048 1048 if cmd == "unlock":
1049 1049 if lock:
1050 1050 lock.release()
1051 1051 lock = None
1052 1052 respond("")
1053 1053 elif cmd == "branches":
1054 1054 arg, nodes = getarg()
1055 1055 nodes = map(hg.bin, nodes.split(" "))
1056 1056 r = []
1057 1057 for b in repo.branches(nodes):
1058 1058 r.append(" ".join(map(hg.hex, b)) + "\n")
1059 1059 respond("".join(r))
1060 1060 elif cmd == "between":
1061 1061 arg, pairs = getarg()
1062 1062 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
1063 1063 r = []
1064 1064 for b in repo.between(pairs):
1065 1065 r.append(" ".join(map(hg.hex, b)) + "\n")
1066 1066 respond("".join(r))
1067 1067 elif cmd == "changegroup":
1068 1068 nodes = []
1069 1069 arg, roots = getarg()
1070 1070 nodes = map(hg.bin, roots.split(" "))
1071 1071
1072 1072 cg = repo.changegroup(nodes)
1073 1073 while 1:
1074 1074 d = cg.read(4096)
1075 1075 if not d:
1076 1076 break
1077 1077 fout.write(d)
1078 1078
1079 1079 fout.flush()
1080 1080
1081 1081 elif cmd == "addchangegroup":
1082 1082 if not lock:
1083 1083 respond("not locked")
1084 1084 continue
1085 1085 respond("")
1086 1086
1087 1087 r = repo.addchangegroup(fin)
1088 1088 respond("")
1089 1089
1090 1090 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
1091 1091 opts["address"], opts["port"], opts["ipv6"],
1092 1092 opts['accesslog'], opts['errorlog'])
1093 1093 if ui.verbose:
1094 1094 addr, port = httpd.socket.getsockname()
1095 1095 if addr == '0.0.0.0':
1096 1096 addr = socket.gethostname()
1097 1097 else:
1098 1098 try:
1099 1099 addr = socket.gethostbyaddr(addr)[0]
1100 1100 except socket.error:
1101 1101 pass
1102 1102 if port != 80:
1103 1103 ui.status('listening at http://%s:%d/\n' % (addr, port))
1104 1104 else:
1105 1105 ui.status('listening at http://%s/\n' % addr)
1106 1106 httpd.serve_forever()
1107 1107
1108 1108 def status(ui, repo, *pats, **opts):
1109 1109 '''show changed files in the working directory
1110 1110
1111 1111 M = modified
1112 1112 A = added
1113 1113 R = removed
1114 1114 ? = not tracked
1115 1115 '''
1116 1116
1117 1117 cwd = repo.getcwd()
1118 1118 files, matchfn = matchpats(repo, cwd, pats, opts)
1119 1119 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1120 1120 for n in repo.changes(files=files, match=matchfn)]
1121 1121
1122 1122 changetypes = [('modified', 'M', c),
1123 1123 ('added', 'A', a),
1124 1124 ('removed', 'R', d),
1125 1125 ('unknown', '?', u)]
1126 1126
1127 1127 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1128 1128 or changetypes):
1129 1129 for f in changes:
1130 1130 ui.write("%s %s\n" % (char, f))
1131 1131
1132 1132 def tag(ui, repo, name, rev=None, **opts):
1133 1133 """add a tag for the current tip or a given revision"""
1134 1134 if opts['text']:
1135 1135 ui.warn("Warning: -t and --text is deprecated,"
1136 1136 " please use -m or --message instead.\n")
1137 1137 if name == "tip":
1138 1138 ui.warn("abort: 'tip' is a reserved name!\n")
1139 1139 return -1
1140 1140 if rev:
1141 1141 r = hg.hex(repo.lookup(rev))
1142 1142 else:
1143 1143 r = hg.hex(repo.changelog.tip())
1144 1144
1145 1145 if name.find(revrangesep) >= 0:
1146 1146 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1147 1147 return -1
1148 1148
1149 1149 if opts['local']:
1150 1150 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1151 1151 return
1152 1152
1153 1153 (c, a, d, u) = repo.changes()
1154 1154 for x in (c, a, d, u):
1155 1155 if ".hgtags" in x:
1156 1156 ui.warn("abort: working copy of .hgtags is changed!\n")
1157 1157 ui.status("(please commit .hgtags manually)\n")
1158 1158 return -1
1159 1159
1160 1160 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1161 1161 if repo.dirstate.state(".hgtags") == '?':
1162 1162 repo.add([".hgtags"])
1163 1163
1164 1164 message = (opts['message'] or opts['text'] or
1165 1165 "Added tag %s for changeset %s" % (name, r))
1166 1166 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1167 1167
1168 1168 def tags(ui, repo):
1169 1169 """list repository tags"""
1170 1170
1171 1171 l = repo.tagslist()
1172 1172 l.reverse()
1173 1173 for t, n in l:
1174 1174 try:
1175 1175 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1176 1176 except KeyError:
1177 1177 r = " ?:?"
1178 1178 ui.write("%-30s %s\n" % (t, r))
1179 1179
1180 1180 def tip(ui, repo):
1181 1181 """show the tip revision"""
1182 1182 n = repo.changelog.tip()
1183 1183 show_changeset(ui, repo, changenode=n)
1184 1184
1185 1185 def undo(ui, repo):
1186 1186 """undo the last commit or pull
1187 1187
1188 1188 Roll back the last pull or commit transaction on the
1189 1189 repository, restoring the project to its earlier state.
1190 1190
1191 1191 This command should be used with care. There is only one level of
1192 1192 undo and there is no redo.
1193 1193
1194 1194 This command is not intended for use on public repositories. Once
1195 1195 a change is visible for pull by other users, undoing it locally is
1196 1196 ineffective.
1197 1197 """
1198 1198 repo.undo()
1199 1199
1200 1200 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1201 1201 '''update or merge working directory
1202 1202
1203 1203 If there are no outstanding changes in the working directory and
1204 1204 there is a linear relationship between the current version and the
1205 1205 requested version, the result is the requested version.
1206 1206
1207 1207 Otherwise the result is a merge between the contents of the
1208 1208 current working directory and the requested version. Files that
1209 1209 changed between either parent are marked as changed for the next
1210 1210 commit and a commit must be performed before any further updates
1211 1211 are allowed.
1212 1212 '''
1213 1213 if branch:
1214 1214 br = repo.branchlookup(branch=branch)
1215 1215 found = []
1216 1216 for x in br:
1217 1217 if branch in br[x]:
1218 1218 found.append(x)
1219 1219 if len(found) > 1:
1220 1220 ui.warn("Found multiple heads for %s\n" % branch)
1221 1221 for x in found:
1222 1222 show_changeset(ui, repo, changenode=x, brinfo=br)
1223 1223 return 1
1224 1224 if len(found) == 1:
1225 1225 node = found[0]
1226 1226 ui.warn("Using head %s for branch %s\n" % (hg.short(node), branch))
1227 1227 else:
1228 1228 ui.warn("branch %s not found\n" % (branch))
1229 1229 return 1
1230 1230 else:
1231 1231 node = node and repo.lookup(node) or repo.changelog.tip()
1232 1232 return repo.update(node, allow=merge, force=clean)
1233 1233
1234 1234 def verify(ui, repo):
1235 1235 """verify the integrity of the repository"""
1236 1236 return repo.verify()
1237 1237
1238 1238 # Command options and aliases are listed here, alphabetically
1239 1239
1240 1240 table = {
1241 1241 "^add":
1242 1242 (add,
1243 1243 [('I', 'include', [], 'include path in search'),
1244 1244 ('X', 'exclude', [], 'exclude path from search')],
1245 1245 "hg add [OPTION]... [FILE]..."),
1246 1246 "addremove":
1247 1247 (addremove,
1248 1248 [('I', 'include', [], 'include path in search'),
1249 1249 ('X', 'exclude', [], 'exclude path from search')],
1250 1250 "hg addremove [OPTION]... [FILE]..."),
1251 1251 "^annotate":
1252 1252 (annotate,
1253 1253 [('r', 'rev', '', 'revision'),
1254 1254 ('u', 'user', None, 'show user'),
1255 1255 ('n', 'number', None, 'show revision number'),
1256 1256 ('c', 'changeset', None, 'show changeset'),
1257 1257 ('I', 'include', [], 'include path in search'),
1258 1258 ('X', 'exclude', [], 'exclude path from search')],
1259 1259 'hg annotate [OPTION]... FILE...'),
1260 1260 "cat":
1261 1261 (cat,
1262 1262 [('o', 'output', "", 'output to file')],
1263 1263 'hg cat [-o OUTFILE] FILE [REV]'),
1264 1264 "^clone":
1265 1265 (clone,
1266 1266 [('U', 'noupdate', None, 'skip update after cloning')],
1267 1267 'hg clone [-U] SOURCE [DEST]'),
1268 1268 "^commit|ci":
1269 1269 (commit,
1270 1270 [('A', 'addremove', None, 'run add/remove during commit'),
1271 1271 ('I', 'include', [], 'include path in search'),
1272 1272 ('X', 'exclude', [], 'exclude path from search'),
1273 1273 ('m', 'message', "", 'commit message'),
1274 1274 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1275 1275 ('l', 'logfile', "", 'commit message file'),
1276 1276 ('d', 'date', "", 'date code'),
1277 1277 ('u', 'user', "", 'user')],
1278 1278 'hg commit [OPTION]... [FILE]...'),
1279 1279 "copy": (copy, [], 'hg copy SOURCE DEST'),
1280 1280 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1281 1281 "debugstate": (debugstate, [], 'debugstate'),
1282 1282 "debugindex": (debugindex, [], 'debugindex FILE'),
1283 1283 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1284 1284 "debugwalk":
1285 1285 (debugwalk,
1286 1286 [('I', 'include', [], 'include path in search'),
1287 1287 ('X', 'exclude', [], 'exclude path from search')],
1288 1288 'debugwalk [OPTION]... [FILE]...'),
1289 1289 "^diff":
1290 1290 (diff,
1291 1291 [('r', 'rev', [], 'revision'),
1292 1292 ('I', 'include', [], 'include path in search'),
1293 1293 ('X', 'exclude', [], 'exclude path from search')],
1294 1294 'hg diff [-I] [-X] [-r REV1 [-r REV2]] [FILE]...'),
1295 1295 "^export":
1296 1296 (export,
1297 1297 [('o', 'output', "", 'output to file')],
1298 1298 "hg export [-o OUTFILE] REV..."),
1299 1299 "forget":
1300 1300 (forget,
1301 1301 [('I', 'include', [], 'include path in search'),
1302 1302 ('X', 'exclude', [], 'exclude path from search')],
1303 1303 "hg forget [OPTION]... FILE..."),
1304 1304 "heads":
1305 1305 (heads,
1306 1306 [('b', 'branches', None, 'find branch info')],
1307 1307 'hg [-b] heads'),
1308 1308 "help": (help_, [], 'hg help [COMMAND]'),
1309 1309 "identify|id": (identify, [], 'hg identify'),
1310 1310 "import|patch":
1311 1311 (import_,
1312 1312 [('p', 'strip', 1, 'path strip'),
1313 1313 ('b', 'base', "", 'base path')],
1314 1314 "hg import [-p NUM] [-b BASE] PATCH..."),
1315 "incoming": (incoming, [], 'hg incoming [SOURCE]'),
1315 "incoming|in": (incoming, [], 'hg incoming [SOURCE]'),
1316 1316 "^init": (init, [], 'hg init [DEST]'),
1317 1317 "locate":
1318 1318 (locate,
1319 1319 [('r', 'rev', '', 'revision'),
1320 1320 ('0', 'print0', None, 'end records with NUL'),
1321 1321 ('f', 'fullpath', None, 'print complete paths'),
1322 1322 ('I', 'include', [], 'include path in search'),
1323 1323 ('X', 'exclude', [], 'exclude path from search')],
1324 1324 'hg locate [OPTION]... [PATTERN]...'),
1325 1325 "^log|history":
1326 1326 (log,
1327 1327 [('r', 'rev', [], 'revision'),
1328 1328 ('p', 'patch', None, 'show patch')],
1329 1329 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1330 1330 "manifest": (manifest, [], 'hg manifest [REV]'),
1331 "outgoing": (outgoing, [], 'hg outgoing [DEST]'),
1331 "outgoing|out": (outgoing, [], 'hg outgoing [DEST]'),
1332 1332 "parents": (parents, [], 'hg parents [REV]'),
1333 1333 "paths": (paths, [], 'hg paths [NAME]'),
1334 1334 "^pull":
1335 1335 (pull,
1336 1336 [('u', 'update', None, 'update working directory')],
1337 1337 'hg pull [-u] [SOURCE]'),
1338 1338 "^push":
1339 1339 (push,
1340 1340 [('f', 'force', None, 'force push')],
1341 1341 'hg push [-f] [DEST]'),
1342 1342 "rawcommit":
1343 1343 (rawcommit,
1344 1344 [('p', 'parent', [], 'parent'),
1345 1345 ('d', 'date', "", 'date code'),
1346 1346 ('u', 'user', "", 'user'),
1347 1347 ('F', 'files', "", 'file list'),
1348 1348 ('m', 'message', "", 'commit message'),
1349 1349 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1350 1350 ('l', 'logfile', "", 'commit message file')],
1351 1351 'hg rawcommit [OPTION]... [FILE]...'),
1352 1352 "recover": (recover, [], "hg recover"),
1353 1353 "^remove|rm": (remove, [], "hg remove FILE..."),
1354 1354 "^revert":
1355 1355 (revert,
1356 1356 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1357 1357 ("r", "rev", "", "revision")],
1358 1358 "hg revert [-n] [-r REV] [NAME]..."),
1359 1359 "root": (root, [], "hg root"),
1360 1360 "^serve":
1361 1361 (serve,
1362 1362 [('A', 'accesslog', '', 'access log file'),
1363 1363 ('E', 'errorlog', '', 'error log file'),
1364 1364 ('p', 'port', 0, 'listen port'),
1365 1365 ('a', 'address', '', 'interface address'),
1366 1366 ('n', 'name', "", 'repository name'),
1367 1367 ('', 'stdio', None, 'for remote clients'),
1368 1368 ('t', 'templates', "", 'template map'),
1369 1369 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1370 1370 "hg serve [OPTION]..."),
1371 1371 "^status":
1372 1372 (status,
1373 1373 [('m', 'modified', None, 'show only modified files'),
1374 1374 ('a', 'added', None, 'show only added files'),
1375 1375 ('r', 'removed', None, 'show only removed files'),
1376 1376 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1377 1377 ('I', 'include', [], 'include path in search'),
1378 1378 ('X', 'exclude', [], 'exclude path from search')],
1379 1379 "hg status [OPTION]... [FILE]..."),
1380 1380 "tag":
1381 1381 (tag,
1382 1382 [('l', 'local', None, 'make the tag local'),
1383 1383 ('m', 'message', "", 'commit message'),
1384 1384 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1385 1385 ('d', 'date', "", 'date code'),
1386 1386 ('u', 'user', "", 'user')],
1387 1387 'hg tag [OPTION]... NAME [REV]'),
1388 1388 "tags": (tags, [], 'hg tags'),
1389 1389 "tip": (tip, [], 'hg tip'),
1390 1390 "undo": (undo, [], 'hg undo'),
1391 1391 "^update|up|checkout|co":
1392 1392 (update,
1393 1393 [('b', 'branch', "", 'checkout the head of a specific branch'),
1394 1394 ('m', 'merge', None, 'allow merging of conflicts'),
1395 1395 ('C', 'clean', None, 'overwrite locally modified files')],
1396 1396 'hg update [-b TAG] [-m] [-C] [REV]'),
1397 1397 "verify": (verify, [], 'hg verify'),
1398 1398 "version": (show_version, [], 'hg version'),
1399 1399 }
1400 1400
1401 1401 globalopts = [('v', 'verbose', None, 'verbose mode'),
1402 1402 ('', 'debug', None, 'debug mode'),
1403 1403 ('q', 'quiet', None, 'quiet mode'),
1404 1404 ('', 'profile', None, 'profile'),
1405 1405 ('R', 'repository', "", 'repository root directory'),
1406 1406 ('', 'traceback', None, 'print traceback on exception'),
1407 1407 ('y', 'noninteractive', None, 'run non-interactively'),
1408 1408 ('', 'version', None, 'output version information and exit'),
1409 1409 ('', 'time', None, 'time how long the command takes'),
1410 1410 ]
1411 1411
1412 1412 norepo = "clone init version help debugindex debugindexdot paths"
1413 1413
1414 1414 def find(cmd):
1415 1415 for e in table.keys():
1416 1416 if re.match("(%s)$" % e, cmd):
1417 1417 return e, table[e]
1418 1418
1419 1419 raise UnknownCommand(cmd)
1420 1420
1421 1421 class SignalInterrupt(Exception):
1422 1422 """Exception raised on SIGTERM and SIGHUP."""
1423 1423
1424 1424 def catchterm(*args):
1425 1425 raise SignalInterrupt
1426 1426
1427 1427 def run():
1428 1428 sys.exit(dispatch(sys.argv[1:]))
1429 1429
1430 1430 class ParseError(Exception):
1431 1431 """Exception raised on errors in parsing the command line."""
1432 1432
1433 1433 def parse(args):
1434 1434 options = {}
1435 1435 cmdoptions = {}
1436 1436
1437 1437 try:
1438 1438 args = fancyopts.fancyopts(args, globalopts, options)
1439 1439 except fancyopts.getopt.GetoptError, inst:
1440 1440 raise ParseError(None, inst)
1441 1441
1442 1442 if options["version"]:
1443 1443 return ("version", show_version, [], options, cmdoptions)
1444 1444 elif not args:
1445 1445 return ("help", help_, ["shortlist"], options, cmdoptions)
1446 1446 else:
1447 1447 cmd, args = args[0], args[1:]
1448 1448
1449 1449 i = find(cmd)[1]
1450 1450
1451 1451 # combine global options into local
1452 1452 c = list(i[1])
1453 1453 for o in globalopts:
1454 1454 c.append((o[0], o[1], options[o[1]], o[3]))
1455 1455
1456 1456 try:
1457 1457 args = fancyopts.fancyopts(args, c, cmdoptions)
1458 1458 except fancyopts.getopt.GetoptError, inst:
1459 1459 raise ParseError(cmd, inst)
1460 1460
1461 1461 # separate global options back out
1462 1462 for o in globalopts:
1463 1463 n = o[1]
1464 1464 options[n] = cmdoptions[n]
1465 1465 del cmdoptions[n]
1466 1466
1467 1467 return (cmd, i[0], args, options, cmdoptions)
1468 1468
1469 1469 def dispatch(args):
1470 1470 signal.signal(signal.SIGTERM, catchterm)
1471 1471 try:
1472 1472 signal.signal(signal.SIGHUP, catchterm)
1473 1473 except AttributeError:
1474 1474 pass
1475 1475
1476 1476 try:
1477 1477 cmd, func, args, options, cmdoptions = parse(args)
1478 1478 except ParseError, inst:
1479 1479 u = ui.ui()
1480 1480 if inst.args[0]:
1481 1481 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1482 1482 help_(u, inst.args[0])
1483 1483 else:
1484 1484 u.warn("hg: %s\n" % inst.args[1])
1485 1485 help_(u, 'shortlist')
1486 1486 sys.exit(-1)
1487 1487 except UnknownCommand, inst:
1488 1488 u = ui.ui()
1489 1489 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1490 1490 help_(u, 'shortlist')
1491 1491 sys.exit(1)
1492 1492
1493 1493 if options["time"]:
1494 1494 def get_times():
1495 1495 t = os.times()
1496 1496 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
1497 1497 t = (t[0], t[1], t[2], t[3], time.clock())
1498 1498 return t
1499 1499 s = get_times()
1500 1500 def print_time():
1501 1501 t = get_times()
1502 1502 u = ui.ui()
1503 1503 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
1504 1504 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
1505 1505 atexit.register(print_time)
1506 1506
1507 1507 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1508 1508 not options["noninteractive"])
1509 1509
1510 1510 try:
1511 1511 try:
1512 1512 if cmd not in norepo.split():
1513 1513 path = options["repository"] or ""
1514 1514 repo = hg.repository(ui=u, path=path)
1515 1515 d = lambda: func(u, repo, *args, **cmdoptions)
1516 1516 else:
1517 1517 d = lambda: func(u, *args, **cmdoptions)
1518 1518
1519 1519 if options['profile']:
1520 1520 import hotshot, hotshot.stats
1521 1521 prof = hotshot.Profile("hg.prof")
1522 1522 r = prof.runcall(d)
1523 1523 prof.close()
1524 1524 stats = hotshot.stats.load("hg.prof")
1525 1525 stats.strip_dirs()
1526 1526 stats.sort_stats('time', 'calls')
1527 1527 stats.print_stats(40)
1528 1528 return r
1529 1529 else:
1530 1530 return d()
1531 1531 except:
1532 1532 if options['traceback']:
1533 1533 traceback.print_exc()
1534 1534 raise
1535 1535 except hg.RepoError, inst:
1536 1536 u.warn("abort: ", inst, "!\n")
1537 1537 except SignalInterrupt:
1538 1538 u.warn("killed!\n")
1539 1539 except KeyboardInterrupt:
1540 1540 try:
1541 1541 u.warn("interrupted!\n")
1542 1542 except IOError, inst:
1543 1543 if inst.errno == errno.EPIPE:
1544 1544 if u.debugflag:
1545 1545 u.warn("\nbroken pipe\n")
1546 1546 else:
1547 1547 raise
1548 1548 except IOError, inst:
1549 1549 if hasattr(inst, "code"):
1550 1550 u.warn("abort: %s\n" % inst)
1551 1551 elif hasattr(inst, "reason"):
1552 1552 u.warn("abort: error: %s\n" % inst.reason[1])
1553 1553 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1554 1554 if u.debugflag: u.warn("broken pipe\n")
1555 1555 else:
1556 1556 raise
1557 1557 except OSError, inst:
1558 1558 if hasattr(inst, "filename"):
1559 1559 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1560 1560 else:
1561 1561 u.warn("abort: %s\n" % inst.strerror)
1562 1562 except util.Abort, inst:
1563 1563 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1564 1564 sys.exit(1)
1565 1565 except TypeError, inst:
1566 1566 # was this an argument error?
1567 1567 tb = traceback.extract_tb(sys.exc_info()[2])
1568 1568 if len(tb) > 2: # no
1569 1569 raise
1570 1570 u.debug(inst, "\n")
1571 1571 u.warn("%s: invalid arguments\n" % cmd)
1572 1572 help_(u, cmd)
1573 1573 except UnknownCommand, inst:
1574 1574 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1575 1575 help_(u, 'shortlist')
1576 1576
1577 1577 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now