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