##// END OF EJS Templates
Merge with BOS
mpm@selenic.com -
r1282:c1a507ba merge default
parent child Browse files
Show More
@@ -1,803 +1,807 b''
1 HG(1)
1 HG(1)
2 =====
2 =====
3 Matt Mackall <mpm@selenic.com>
3 Matt Mackall <mpm@selenic.com>
4
4
5 NAME
5 NAME
6 ----
6 ----
7 hg - Mercurial source code management system
7 hg - Mercurial source code management system
8
8
9 SYNOPSIS
9 SYNOPSIS
10 --------
10 --------
11 'hg' [-v -d -q -y] <command> [command options] [files]
11 'hg' [-v -d -q -y] <command> [command options] [files]
12
12
13 DESCRIPTION
13 DESCRIPTION
14 -----------
14 -----------
15 The hg(1) command provides a command line interface to the Mercurial system.
15 The hg(1) command provides a command line interface to the Mercurial system.
16
16
17 OPTIONS
17 OPTIONS
18 -------
18 -------
19
19
20 -R, --repository::
20 -R, --repository::
21 repository root directory
21 repository root directory
22
22
23 --cwd::
23 --cwd::
24 change working directory
24 change working directory
25
25
26 -y, --noninteractive::
26 -y, --noninteractive::
27 do not prompt, assume 'yes' for any required answers
27 do not prompt, assume 'yes' for any required answers
28
28
29 -q, --quiet::
29 -q, --quiet::
30 suppress output
30 suppress output
31
31
32 -v, --verbose::
32 -v, --verbose::
33 enable additional output
33 enable additional output
34
34
35 --debug::
35 --debug::
36 enable debugging output
36 enable debugging output
37
37
38 --traceback::
38 --traceback::
39 print traceback on exception
39 print traceback on exception
40
40
41 --time::
41 --time::
42 time how long the command takes
42 time how long the command takes
43
43
44 --profile::
44 --profile::
45 print command execution profile
45 print command execution profile
46
46
47 --version::
47 --version::
48 output version information and exit
48 output version information and exit
49
49
50 -h, --help::
50 -h, --help::
51 display help and exit
51 display help and exit
52
52
53 COMMAND ELEMENTS
53 COMMAND ELEMENTS
54 ----------------
54 ----------------
55
55
56 files ...::
56 files ...::
57 indicates one or more filename or relative path filenames; see
57 indicates one or more filename or relative path filenames; see
58 "FILE NAME PATTERNS" for information on pattern matching
58 "FILE NAME PATTERNS" for information on pattern matching
59
59
60 path::
60 path::
61 indicates a path on the local machine
61 indicates a path on the local machine
62
62
63 revision::
63 revision::
64 indicates a changeset which can be specified as a changeset revision
64 indicates a changeset which can be specified as a changeset revision
65 number, a tag, or a unique substring of the changeset hash value
65 number, a tag, or a unique substring of the changeset hash value
66
66
67 repository path::
67 repository path::
68 either the pathname of a local repository or the URI of a remote
68 either the pathname of a local repository or the URI of a remote
69 repository. There are two available URI protocols, http:// which is
69 repository. There are two available URI protocols, http:// which is
70 fast and the old-http:// protocol which is much slower but does not
70 fast and the old-http:// protocol which is much slower but does not
71 require a special server on the web host.
71 require a special server on the web host.
72
72
73 COMMANDS
73 COMMANDS
74 --------
74 --------
75
75
76 add [options] [files ...]::
76 add [options] [files ...]::
77 Schedule files to be version controlled and added to the repository.
77 Schedule files to be version controlled and added to the repository.
78
78
79 The files will be added to the repository at the next commit.
79 The files will be added to the repository at the next commit.
80
80
81 If no names are given, add all files in the current directory and
81 If no names are given, add all files in the current directory and
82 its subdirectories.
82 its subdirectories.
83
83
84 addremove [options] [files ...]::
84 addremove [options] [files ...]::
85 Add all new files and remove all missing files from the repository.
85 Add all new files and remove all missing files from the repository.
86
86
87 New files are ignored if they match any of the patterns in .hgignore. As
87 New files are ignored if they match any of the patterns in .hgignore. As
88 with add, these changes take effect at the next commit.
88 with add, these changes take effect at the next commit.
89
89
90 annotate [-r <rev> -u -n -c] [files ...]::
90 annotate [-r <rev> -u -n -c] [files ...]::
91 List changes in files, showing the revision id responsible for each line
91 List changes in files, showing the revision id responsible for each line
92
92
93 This command is useful to discover who did a change or when a change took
93 This command is useful to discover who did a change or when a change took
94 place.
94 place.
95
95
96 Without the -a option, annotate will avoid processing files it
96 Without the -a option, annotate will avoid processing files it
97 detects as binary. With -a, annotate will generate an annotation
97 detects as binary. With -a, annotate will generate an annotation
98 anyway, probably with undesirable results.
98 anyway, probably with undesirable results.
99
99
100 options:
100 options:
101 -a, --text treat all files as text
101 -a, --text treat all files as text
102 -I, --include <pat> include names matching the given patterns
102 -I, --include <pat> include names matching the given patterns
103 -X, --exclude <pat> exclude names matching the given patterns
103 -X, --exclude <pat> exclude names matching the given patterns
104 -r, --revision <rev> annotate the specified revision
104 -r, --revision <rev> annotate the specified revision
105 -u, --user list the author
105 -u, --user list the author
106 -c, --changeset list the changeset
106 -c, --changeset list the changeset
107 -n, --number list the revision number (default)
107 -n, --number list the revision number (default)
108
108
109 bundle <file> <other>::
109 bundle <file> <other>::
110 (EXPERIMENTAL)
110 (EXPERIMENTAL)
111
111
112 Generate a compressed changegroup file collecting all changesets
112 Generate a compressed changegroup file collecting all changesets
113 not found in the other repository.
113 not found in the other repository.
114
114
115 This file can then be transferred using conventional means and
115 This file can then be transferred using conventional means and
116 applied to another repository with the unbundle command. This is
116 applied to another repository with the unbundle command. This is
117 useful when native push and pull are not available or when
117 useful when native push and pull are not available or when
118 exporting an entire repository is undesirable. The standard file
118 exporting an entire repository is undesirable. The standard file
119 extension is ".hg".
119 extension is ".hg".
120
120
121 Unlike import/export, this exactly preserves all changeset
121 Unlike import/export, this exactly preserves all changeset
122 contents including permissions, rename data, and revision history.
122 contents including permissions, rename data, and revision history.
123
123
124 cat [options] <file ...>::
124 cat [options] <file ...>::
125 Print the specified files as they were at the given revision.
125 Print the specified files as they were at the given revision.
126 If no revision is given then the tip is used.
126 If no revision is given then the tip is used.
127
127
128 Output may be to a file, in which case the name of the file is
128 Output may be to a file, in which case the name of the file is
129 given using a format string. The formatting rules are the same as
129 given using a format string. The formatting rules are the same as
130 for the export command, with the following additions:
130 for the export command, with the following additions:
131
131
132 %s basename of file being printed
132 %s basename of file being printed
133 %d dirname of file being printed, or '.' if in repo root
133 %d dirname of file being printed, or '.' if in repo root
134 %p root-relative path name of file being printed
134 %p root-relative path name of file being printed
135
135
136 options:
136 options:
137 -I, --include <pat> include names matching the given patterns
137 -I, --include <pat> include names matching the given patterns
138 -X, --exclude <pat> exclude names matching the given patterns
138 -X, --exclude <pat> exclude names matching the given patterns
139 -o, --output <filespec> print output to file with formatted name
139 -o, --output <filespec> print output to file with formatted name
140 -r, --rev <rev> print the given revision
140 -r, --rev <rev> print the given revision
141
141
142 clone [-U] <source> [dest]::
142 clone [options] <source> [dest]::
143 Create a copy of an existing repository in a new directory.
143 Create a copy of an existing repository in a new directory.
144
144
145 If no destination directory name is specified, it defaults to the
145 If no destination directory name is specified, it defaults to the
146 basename of the source.
146 basename of the source.
147
147
148 The source is added to the new repository's .hg/hgrc file to be used in
148 The location of the source is added to the new repository's
149 future pulls.
149 .hg/hgrc file, as the default to be used for future pulls.
150
150
151 For efficiency, hardlinks are used for cloning whenever the
151 For efficiency, hardlinks are used for cloning whenever the source
152 source and destination are on the same filesystem.
152 and destination are on the same filesystem. Some filesystems,
153 such as AFS, implement hardlinking incorrectly, but do not report
154 errors. In these cases, use the --pull option to avoid
155 hardlinking.
153
156
154 options:
157 options:
155 -U, --noupdate do not update the new working directory
158 -U, --noupdate do not update the new working directory
159 --pull use pull protocol to copy metadata
156 -e, --ssh specify ssh command to use
160 -e, --ssh specify ssh command to use
157 --remotecmd specify hg command to run on the remote side
161 --remotecmd specify hg command to run on the remote side
158
162
159 commit [options] [files...]::
163 commit [options] [files...]::
160 Commit changes to the given files into the repository.
164 Commit changes to the given files into the repository.
161
165
162 If a list of files is omitted, all changes reported by "hg status"
166 If a list of files is omitted, all changes reported by "hg status"
163 from the root of the repository will be commited.
167 from the root of the repository will be commited.
164
168
165 The HGEDITOR or EDITOR environment variables are used to start an
169 The HGEDITOR or EDITOR environment variables are used to start an
166 editor to add a commit comment.
170 editor to add a commit comment.
167
171
168 Options:
172 Options:
169
173
170 -A, --addremove run addremove during commit
174 -A, --addremove run addremove during commit
171 -I, --include <pat> include names matching the given patterns
175 -I, --include <pat> include names matching the given patterns
172 -X, --exclude <pat> exclude names matching the given patterns
176 -X, --exclude <pat> exclude names matching the given patterns
173 -m, --message <text> use <text> as commit message
177 -m, --message <text> use <text> as commit message
174 -l, --logfile <file> read the commit message from <file>
178 -l, --logfile <file> read the commit message from <file>
175 -d, --date <datecode> record datecode as commit date
179 -d, --date <datecode> record datecode as commit date
176 -u, --user <user> record user as commiter
180 -u, --user <user> record user as commiter
177
181
178 aliases: ci
182 aliases: ci
179
183
180 copy <source ...> <dest>::
184 copy <source ...> <dest>::
181 Mark dest as having copies of source files. If dest is a
185 Mark dest as having copies of source files. If dest is a
182 directory, copies are put in that directory. If dest is a file,
186 directory, copies are put in that directory. If dest is a file,
183 there can only be one source.
187 there can only be one source.
184
188
185 By default, this command copies the contents of files as they
189 By default, this command copies the contents of files as they
186 stand in the working directory. If invoked with --after, the
190 stand in the working directory. If invoked with --after, the
187 operation is recorded, but no copying is performed.
191 operation is recorded, but no copying is performed.
188
192
189 This command takes effect in the next commit.
193 This command takes effect in the next commit.
190
194
191 NOTE: This command should be treated as experimental. While it
195 NOTE: This command should be treated as experimental. While it
192 should properly record copied files, this information is not yet
196 should properly record copied files, this information is not yet
193 fully used by merge, nor fully reported by log.
197 fully used by merge, nor fully reported by log.
194
198
195 Options:
199 Options:
196 -A, --after record a copy that has already occurred
200 -A, --after record a copy that has already occurred
197 -I, --include <pat> include names matching the given patterns
201 -I, --include <pat> include names matching the given patterns
198 -X, --exclude <pat> exclude names matching the given patterns
202 -X, --exclude <pat> exclude names matching the given patterns
199 -f, --force forcibly copy over an existing managed file
203 -f, --force forcibly copy over an existing managed file
200 -p, --parents append source path to dest
204 -p, --parents append source path to dest
201
205
202 aliases: cp
206 aliases: cp
203
207
204 diff [-a] [-r revision] [-r revision] [files ...]::
208 diff [-a] [-r revision] [-r revision] [files ...]::
205 Show differences between revisions for the specified files.
209 Show differences between revisions for the specified files.
206
210
207 Differences between files are shown using the unified diff format.
211 Differences between files are shown using the unified diff format.
208
212
209 When two revision arguments are given, then changes are shown
213 When two revision arguments are given, then changes are shown
210 between those revisions. If only one revision is specified then
214 between those revisions. If only one revision is specified then
211 that revision is compared to the working directory, and, when no
215 that revision is compared to the working directory, and, when no
212 revisions are specified, the working directory files are compared
216 revisions are specified, the working directory files are compared
213 to its parent.
217 to its parent.
214
218
215 Without the -a option, diff will avoid generating diffs of files
219 Without the -a option, diff will avoid generating diffs of files
216 it detects as binary. With -a, diff will generate a diff anyway,
220 it detects as binary. With -a, diff will generate a diff anyway,
217 probably with undesirable results.
221 probably with undesirable results.
218
222
219 options:
223 options:
220 -a, --text treat all files as text
224 -a, --text treat all files as text
221 -I, --include <pat> include names matching the given patterns
225 -I, --include <pat> include names matching the given patterns
222 -X, --exclude <pat> exclude names matching the given patterns
226 -X, --exclude <pat> exclude names matching the given patterns
223
227
224 export [-o filespec] [revision] ...::
228 export [-o filespec] [revision] ...::
225 Print the changeset header and diffs for one or more revisions.
229 Print the changeset header and diffs for one or more revisions.
226
230
227 The information shown in the changeset header is: author,
231 The information shown in the changeset header is: author,
228 changeset hash, parent and commit comment.
232 changeset hash, parent and commit comment.
229
233
230 Output may be to a file, in which case the name of the file is
234 Output may be to a file, in which case the name of the file is
231 given using a format string. The formatting rules are as follows:
235 given using a format string. The formatting rules are as follows:
232
236
233 %% literal "%" character
237 %% literal "%" character
234 %H changeset hash (40 bytes of hexadecimal)
238 %H changeset hash (40 bytes of hexadecimal)
235 %N number of patches being generated
239 %N number of patches being generated
236 %R changeset revision number
240 %R changeset revision number
237 %b basename of the exporting repository
241 %b basename of the exporting repository
238 %h short-form changeset hash (12 bytes of hexadecimal)
242 %h short-form changeset hash (12 bytes of hexadecimal)
239 %n zero-padded sequence number, starting at 1
243 %n zero-padded sequence number, starting at 1
240 %r zero-padded changeset revision number
244 %r zero-padded changeset revision number
241
245
242 Without the -a option, export will avoid generating diffs of files
246 Without the -a option, export will avoid generating diffs of files
243 it detects as binary. With -a, export will generate a diff anyway,
247 it detects as binary. With -a, export will generate a diff anyway,
244 probably with undesirable results.
248 probably with undesirable results.
245
249
246 options:
250 options:
247 -a, --text treat all files as text
251 -a, --text treat all files as text
248 -o, --output <filespec> print output to file with formatted name
252 -o, --output <filespec> print output to file with formatted name
249
253
250 forget [options] [files]::
254 forget [options] [files]::
251 Undo an 'hg add' scheduled for the next commit.
255 Undo an 'hg add' scheduled for the next commit.
252
256
253 options:
257 options:
254 -I, --include <pat> include names matching the given patterns
258 -I, --include <pat> include names matching the given patterns
255 -X, --exclude <pat> exclude names matching the given patterns
259 -X, --exclude <pat> exclude names matching the given patterns
256
260
257 grep [options] pattern [files]::
261 grep [options] pattern [files]::
258 Search revisions of files for a regular expression.
262 Search revisions of files for a regular expression.
259
263
260 This command behaves differently than Unix grep. It only accepts
264 This command behaves differently than Unix grep. It only accepts
261 Python/Perl regexps. It searches repository history, not the
265 Python/Perl regexps. It searches repository history, not the
262 working directory. It always prints the revision number in which
266 working directory. It always prints the revision number in which
263 a match appears.
267 a match appears.
264
268
265 By default, grep only prints output for the first revision of a
269 By default, grep only prints output for the first revision of a
266 file in which it finds a match. To get it to print every revision
270 file in which it finds a match. To get it to print every revision
267 that contains a change in match status ("-" for a match that
271 that contains a change in match status ("-" for a match that
268 becomes a non-match, or "+" for a non-match that becomes a match),
272 becomes a non-match, or "+" for a non-match that becomes a match),
269 use the --all flag.
273 use the --all flag.
270
274
271 options:
275 options:
272 -0, --print0 end fields with NUL
276 -0, --print0 end fields with NUL
273 -I, --include <pat> include names matching the given patterns
277 -I, --include <pat> include names matching the given patterns
274 -X, --exclude <pat> exclude names matching the given patterns
278 -X, --exclude <pat> exclude names matching the given patterns
275 --all print all revisions that match
279 --all print all revisions that match
276 -i, --ignore-case ignore case when matching
280 -i, --ignore-case ignore case when matching
277 -l, --files-with-matches print only filenames and revs that match
281 -l, --files-with-matches print only filenames and revs that match
278 -n, --line-number print matching line numbers
282 -n, --line-number print matching line numbers
279 -r <rev>, --rev <rev> search in given revision range
283 -r <rev>, --rev <rev> search in given revision range
280 -u, --user print user who committed change
284 -u, --user print user who committed change
281
285
282 heads::
286 heads::
283 Show all repository head changesets.
287 Show all repository head changesets.
284
288
285 Repository "heads" are changesets that don't have children
289 Repository "heads" are changesets that don't have children
286 changesets. They are where development generally takes place and
290 changesets. They are where development generally takes place and
287 are the usual targets for update and merge operations.
291 are the usual targets for update and merge operations.
288
292
289 identify::
293 identify::
290 Print a short summary of the current state of the repo.
294 Print a short summary of the current state of the repo.
291
295
292 This summary identifies the repository state using one or two parent
296 This summary identifies the repository state using one or two parent
293 hash identifiers, followed by a "+" if there are uncommitted changes
297 hash identifiers, followed by a "+" if there are uncommitted changes
294 in the working directory, followed by a list of tags for this revision.
298 in the working directory, followed by a list of tags for this revision.
295
299
296 aliases: id
300 aliases: id
297
301
298 import [-p <n> -b <base> -f] <patches>::
302 import [-p <n> -b <base> -f] <patches>::
299 Import a list of patches and commit them individually.
303 Import a list of patches and commit them individually.
300
304
301 If there are outstanding changes in the working directory, import
305 If there are outstanding changes in the working directory, import
302 will abort unless given the -f flag.
306 will abort unless given the -f flag.
303
307
304 If a patch looks like a mail message (its first line starts with
308 If a patch looks like a mail message (its first line starts with
305 "From " or looks like an RFC822 header), it will not be applied
309 "From " or looks like an RFC822 header), it will not be applied
306 unless the -f option is used. The importer neither parses nor
310 unless the -f option is used. The importer neither parses nor
307 discards mail headers, so use -f only to override the "mailness"
311 discards mail headers, so use -f only to override the "mailness"
308 safety check, not to import a real mail message.
312 safety check, not to import a real mail message.
309
313
310 options:
314 options:
311 -p, --strip <n> directory strip option for patch. This has the same
315 -p, --strip <n> directory strip option for patch. This has the same
312 meaning as the corresponding patch option
316 meaning as the corresponding patch option
313 -b <path> base directory to read patches from
317 -b <path> base directory to read patches from
314 -f, --force skip check for outstanding uncommitted changes
318 -f, --force skip check for outstanding uncommitted changes
315
319
316 aliases: patch
320 aliases: patch
317
321
318 incoming [-p] [source]::
322 incoming [-p] [source]::
319 Show new changesets found in the specified repo or the default
323 Show new changesets found in the specified repo or the default
320 pull repo. These are the changesets that would be pulled if a pull
324 pull repo. These are the changesets that would be pulled if a pull
321 was requested.
325 was requested.
322
326
323 Currently only local repositories are supported.
327 Currently only local repositories are supported.
324
328
325 options:
329 options:
326 -p, --patch show patch
330 -p, --patch show patch
327
331
328 aliases: in
332 aliases: in
329
333
330 init [dest]::
334 init [dest]::
331 Initialize a new repository in the given directory. If the given
335 Initialize a new repository in the given directory. If the given
332 directory does not exist, it is created.
336 directory does not exist, it is created.
333
337
334 If no directory is given, the current directory is used.
338 If no directory is given, the current directory is used.
335
339
336 locate [options] [files]::
340 locate [options] [files]::
337 Print all files under Mercurial control whose names match the
341 Print all files under Mercurial control whose names match the
338 given patterns.
342 given patterns.
339
343
340 This command searches the current directory and its
344 This command searches the current directory and its
341 subdirectories. To search an entire repository, move to the root
345 subdirectories. To search an entire repository, move to the root
342 of the repository.
346 of the repository.
343
347
344 If no patterns are given to match, this command prints all file
348 If no patterns are given to match, this command prints all file
345 names.
349 names.
346
350
347 If you want to feed the output of this command into the "xargs"
351 If you want to feed the output of this command into the "xargs"
348 command, use the "-0" option to both this command and "xargs".
352 command, use the "-0" option to both this command and "xargs".
349 This will avoid the problem of "xargs" treating single filenames
353 This will avoid the problem of "xargs" treating single filenames
350 that contain white space as multiple filenames.
354 that contain white space as multiple filenames.
351
355
352 options:
356 options:
353
357
354 -0, --print0 end filenames with NUL, for use with xargs
358 -0, --print0 end filenames with NUL, for use with xargs
355 -f, --fullpath print complete paths from the filesystem root
359 -f, --fullpath print complete paths from the filesystem root
356 -I, --include <pat> include names matching the given patterns
360 -I, --include <pat> include names matching the given patterns
357 -r, --rev <rev> search the repository as it stood at rev
361 -r, --rev <rev> search the repository as it stood at rev
358 -X, --exclude <pat> exclude names matching the given patterns
362 -X, --exclude <pat> exclude names matching the given patterns
359
363
360 log [-r revision ...] [-p] [files]::
364 log [-r revision ...] [-p] [files]::
361 Print the revision history of the specified files or the entire project.
365 Print the revision history of the specified files or the entire project.
362
366
363 By default this command outputs: changeset id and hash, tags,
367 By default this command outputs: changeset id and hash, tags,
364 parents, user, date and time, and a summary for each commit. The
368 parents, user, date and time, and a summary for each commit. The
365 -v switch adds some more detail, such as changed files, manifest
369 -v switch adds some more detail, such as changed files, manifest
366 hashes or message signatures.
370 hashes or message signatures.
367
371
368 options:
372 options:
369 -I, --include <pat> include names matching the given patterns
373 -I, --include <pat> include names matching the given patterns
370 -X, --exclude <pat> exclude names matching the given patterns
374 -X, --exclude <pat> exclude names matching the given patterns
371 -r, --rev <A> show the specified revision or range
375 -r, --rev <A> show the specified revision or range
372 -p, --patch show patch
376 -p, --patch show patch
373
377
374 aliases: history
378 aliases: history
375
379
376 manifest [revision]::
380 manifest [revision]::
377 Print a list of version controlled files for the given revision.
381 Print a list of version controlled files for the given revision.
378
382
379 The manifest is the list of files being version controlled. If no revision
383 The manifest is the list of files being version controlled. If no revision
380 is given then the tip is used.
384 is given then the tip is used.
381
385
382 outgoing [-p] [dest]::
386 outgoing [-p] [dest]::
383 Show changesets not found in the specified destination repo or the
387 Show changesets not found in the specified destination repo or the
384 default push repo. These are the changesets that would be pushed
388 default push repo. These are the changesets that would be pushed
385 if a push was requested.
389 if a push was requested.
386
390
387 options:
391 options:
388 -p, --patch show patch
392 -p, --patch show patch
389
393
390 aliases: out
394 aliases: out
391
395
392 parents::
396 parents::
393 Print the working directory's parent revisions.
397 Print the working directory's parent revisions.
394
398
395 paths [NAME]::
399 paths [NAME]::
396 Show definition of symbolic path name NAME. If no name is given, show
400 Show definition of symbolic path name NAME. If no name is given, show
397 definition of available names.
401 definition of available names.
398
402
399 Path names are defined in the [paths] section of /etc/mercurial/hgrc
403 Path names are defined in the [paths] section of /etc/mercurial/hgrc
400 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
404 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
401
405
402 pull <repository path>::
406 pull <repository path>::
403 Pull changes from a remote repository to a local one.
407 Pull changes from a remote repository to a local one.
404
408
405 This finds all changes from the repository at the specified path
409 This finds all changes from the repository at the specified path
406 or URL and adds them to the local repository. By default, this
410 or URL and adds them to the local repository. By default, this
407 does not update the copy of the project in the working directory.
411 does not update the copy of the project in the working directory.
408
412
409 Valid URLs are of the form:
413 Valid URLs are of the form:
410
414
411 local/filesystem/path
415 local/filesystem/path
412 http://[user@]host[:port][/path]
416 http://[user@]host[:port][/path]
413 https://[user@]host[:port][/path]
417 https://[user@]host[:port][/path]
414 ssh://[user@]host[:port][/path]
418 ssh://[user@]host[:port][/path]
415
419
416 SSH requires an accessible shell account on the destination machine
420 SSH requires an accessible shell account on the destination machine
417 and a copy of hg in the remote path. With SSH, paths are relative
421 and a copy of hg in the remote path. With SSH, paths are relative
418 to the remote user's home directory by default; use two slashes at
422 to the remote user's home directory by default; use two slashes at
419 the start of a path to specify it as relative to the filesystem root.
423 the start of a path to specify it as relative to the filesystem root.
420
424
421 options:
425 options:
422 -u, --update update the working directory to tip after pull
426 -u, --update update the working directory to tip after pull
423 -e, --ssh specify ssh command to use
427 -e, --ssh specify ssh command to use
424 --remotecmd specify hg command to run on the remote side
428 --remotecmd specify hg command to run on the remote side
425
429
426 push <destination>::
430 push <destination>::
427 Push changes from the local repository to the given destination.
431 Push changes from the local repository to the given destination.
428
432
429 This is the symmetrical operation for pull. It helps to move
433 This is the symmetrical operation for pull. It helps to move
430 changes from the current repository to a different one. If the
434 changes from the current repository to a different one. If the
431 destination is local this is identical to a pull in that directory
435 destination is local this is identical to a pull in that directory
432 from the current one.
436 from the current one.
433
437
434 By default, push will refuse to run if it detects the result would
438 By default, push will refuse to run if it detects the result would
435 increase the number of remote heads. This generally indicates the
439 increase the number of remote heads. This generally indicates the
436 the client has forgotten to sync and merge before pushing.
440 the client has forgotten to sync and merge before pushing.
437
441
438 Valid URLs are of the form:
442 Valid URLs are of the form:
439
443
440 local/filesystem/path
444 local/filesystem/path
441 ssh://[user@]host[:port][/path]
445 ssh://[user@]host[:port][/path]
442
446
443 SSH requires an accessible shell account on the destination
447 SSH requires an accessible shell account on the destination
444 machine and a copy of hg in the remote path.
448 machine and a copy of hg in the remote path.
445
449
446 options:
450 options:
447
451
448 -f, --force force update
452 -f, --force force update
449 -e, --ssh specify ssh command to use
453 -e, --ssh specify ssh command to use
450 --remotecmd specify hg command to run on the remote side
454 --remotecmd specify hg command to run on the remote side
451
455
452 rawcommit [-p -d -u -F -m -l]::
456 rawcommit [-p -d -u -F -m -l]::
453 Lowlevel commit, for use in helper scripts.
457 Lowlevel commit, for use in helper scripts.
454
458
455 This command is not intended to be used by normal users, as it is
459 This command is not intended to be used by normal users, as it is
456 primarily useful for importing from other SCMs.
460 primarily useful for importing from other SCMs.
457
461
458 recover::
462 recover::
459 Recover from an interrupted commit or pull.
463 Recover from an interrupted commit or pull.
460
464
461 This command tries to fix the repository status after an interrupted
465 This command tries to fix the repository status after an interrupted
462 operation. It should only be necessary when Mercurial suggests it.
466 operation. It should only be necessary when Mercurial suggests it.
463
467
464 remove [options] [files ...]::
468 remove [options] [files ...]::
465 Schedule the indicated files for removal from the repository.
469 Schedule the indicated files for removal from the repository.
466
470
467 This command schedules the files to be removed at the next commit.
471 This command schedules the files to be removed at the next commit.
468 This only removes files from the current branch, not from the
472 This only removes files from the current branch, not from the
469 entire project history. If the files still exist in the working
473 entire project history. If the files still exist in the working
470 directory, they will be deleted from it.
474 directory, they will be deleted from it.
471
475
472 aliases: rm
476 aliases: rm
473
477
474 rename <source ...> <dest>::
478 rename <source ...> <dest>::
475 Mark dest as copies of sources; mark sources for deletion. If
479 Mark dest as copies of sources; mark sources for deletion. If
476 dest is a directory, copies are put in that directory. If dest is
480 dest is a directory, copies are put in that directory. If dest is
477 a file, there can only be one source.
481 a file, there can only be one source.
478
482
479 By default, this command copies the contents of files as they
483 By default, this command copies the contents of files as they
480 stand in the working directory. If invoked with --after, the
484 stand in the working directory. If invoked with --after, the
481 operation is recorded, but no copying is performed.
485 operation is recorded, but no copying is performed.
482
486
483 This command takes effect in the next commit.
487 This command takes effect in the next commit.
484
488
485 NOTE: This command should be treated as experimental. While it
489 NOTE: This command should be treated as experimental. While it
486 should properly record rename files, this information is not yet
490 should properly record rename files, this information is not yet
487 fully used by merge, nor fully reported by log.
491 fully used by merge, nor fully reported by log.
488
492
489 Options:
493 Options:
490 -A, --after record a rename that has already occurred
494 -A, --after record a rename that has already occurred
491 -f, --force forcibly copy over an existing managed file
495 -f, --force forcibly copy over an existing managed file
492 -p, --parents append source path to dest
496 -p, --parents append source path to dest
493
497
494 aliases: mv
498 aliases: mv
495
499
496 revert [names ...]::
500 revert [names ...]::
497 Revert any uncommitted modifications made to the named files or
501 Revert any uncommitted modifications made to the named files or
498 directories. This restores the contents of the affected files to
502 directories. This restores the contents of the affected files to
499 an unmodified state.
503 an unmodified state.
500
504
501 If a file has been deleted, it is recreated. If the executable
505 If a file has been deleted, it is recreated. If the executable
502 mode of a file was changed, it is reset.
506 mode of a file was changed, it is reset.
503
507
504 If a directory is given, all files in that directory and its
508 If a directory is given, all files in that directory and its
505 subdirectories are reverted.
509 subdirectories are reverted.
506
510
507 If no arguments are given, all files in the current directory and
511 If no arguments are given, all files in the current directory and
508 its subdirectories are reverted.
512 its subdirectories are reverted.
509
513
510 options:
514 options:
511 -r, --rev <rev> revision to revert to
515 -r, --rev <rev> revision to revert to
512 -n, --nonrecursive do not recurse into subdirectories
516 -n, --nonrecursive do not recurse into subdirectories
513
517
514 root::
518 root::
515 Print the root directory of the current repository.
519 Print the root directory of the current repository.
516
520
517 serve [options]::
521 serve [options]::
518 Start a local HTTP repository browser and pull server.
522 Start a local HTTP repository browser and pull server.
519
523
520 By default, the server logs accesses to stdout and errors to
524 By default, the server logs accesses to stdout and errors to
521 stderr. Use the "-A" and "-E" options to log to files.
525 stderr. Use the "-A" and "-E" options to log to files.
522
526
523 options:
527 options:
524 -A, --accesslog <file> name of access log file to write to
528 -A, --accesslog <file> name of access log file to write to
525 -E, --errorlog <file> name of error log file to write to
529 -E, --errorlog <file> name of error log file to write to
526 -a, --address <addr> address to use
530 -a, --address <addr> address to use
527 -p, --port <n> port to use (default: 8000)
531 -p, --port <n> port to use (default: 8000)
528 -n, --name <name> name to show in web pages (default: working dir)
532 -n, --name <name> name to show in web pages (default: working dir)
529 -t, --templatedir <path> web templates to use
533 -t, --templatedir <path> web templates to use
530 -6, --ipv6 use IPv6 in addition to IPv4
534 -6, --ipv6 use IPv6 in addition to IPv4
531
535
532 status [options] [files]::
536 status [options] [files]::
533 Show changed files in the working directory. If no names are
537 Show changed files in the working directory. If no names are
534 given, all files are shown. Otherwise, only files matching the
538 given, all files are shown. Otherwise, only files matching the
535 given names are shown.
539 given names are shown.
536
540
537 The codes used to show the status of files are:
541 The codes used to show the status of files are:
538
542
539 M = changed
543 M = changed
540 A = added
544 A = added
541 R = removed
545 R = removed
542 ? = not tracked
546 ? = not tracked
543
547
544 options:
548 options:
545
549
546 -m, --modified show only modified files
550 -m, --modified show only modified files
547 -a, --added show only added files
551 -a, --added show only added files
548 -r, --removed show only removed files
552 -r, --removed show only removed files
549 -u, --unknown show only unknown (not tracked) files
553 -u, --unknown show only unknown (not tracked) files
550 -n, --no-status hide status prefix
554 -n, --no-status hide status prefix
551 -0, --print0 end filenames with NUL, for use with xargs
555 -0, --print0 end filenames with NUL, for use with xargs
552 -I, --include <pat> include names matching the given patterns
556 -I, --include <pat> include names matching the given patterns
553 -X, --exclude <pat> exclude names matching the given patterns
557 -X, --exclude <pat> exclude names matching the given patterns
554
558
555 tag [-l -m <text> -d <datecode> -u <user>] <name> [revision]::
559 tag [-l -m <text> -d <datecode> -u <user>] <name> [revision]::
556 Name a particular revision using <name>.
560 Name a particular revision using <name>.
557
561
558 Tags are used to name particular revisions of the repository and are
562 Tags are used to name particular revisions of the repository and are
559 very useful to compare different revision, to go back to significant
563 very useful to compare different revision, to go back to significant
560 earlier versions or to mark branch points as releases, etc.
564 earlier versions or to mark branch points as releases, etc.
561
565
562 If no revision is given, the tip is used.
566 If no revision is given, the tip is used.
563
567
564 To facilitate version control, distribution, and merging of tags,
568 To facilitate version control, distribution, and merging of tags,
565 they are stored as a file named ".hgtags" which is managed
569 they are stored as a file named ".hgtags" which is managed
566 similarly to other project files and can be hand-edited if
570 similarly to other project files and can be hand-edited if
567 necessary.
571 necessary.
568
572
569 options:
573 options:
570 -l, --local make the tag local
574 -l, --local make the tag local
571 -m, --message <text> message for tag commit log entry
575 -m, --message <text> message for tag commit log entry
572 -d, --date <datecode> datecode for commit
576 -d, --date <datecode> datecode for commit
573 -u, --user <user> user for commit
577 -u, --user <user> user for commit
574
578
575 Note: Local tags are not version-controlled or distributed and are
579 Note: Local tags are not version-controlled or distributed and are
576 stored in the .hg/localtags file. If there exists a local tag and
580 stored in the .hg/localtags file. If there exists a local tag and
577 a public tag with the same name, local tag is used.
581 a public tag with the same name, local tag is used.
578
582
579 tags::
583 tags::
580 List the repository tags.
584 List the repository tags.
581
585
582 This lists both regular and local tags.
586 This lists both regular and local tags.
583
587
584 tip::
588 tip::
585 Show the tip revision.
589 Show the tip revision.
586
590
587 unbundle <file>::
591 unbundle <file>::
588 (EXPERIMENTAL)
592 (EXPERIMENTAL)
589
593
590 Apply a compressed changegroup file generated by the bundle
594 Apply a compressed changegroup file generated by the bundle
591 command.
595 command.
592
596
593 undo::
597 undo::
594 Undo the last commit or pull transaction.
598 Undo the last commit or pull transaction.
595
599
596 Roll back the last pull or commit transaction on the
600 Roll back the last pull or commit transaction on the
597 repository, restoring the project to its earlier state.
601 repository, restoring the project to its earlier state.
598
602
599 This command should be used with care. There is only one level of
603 This command should be used with care. There is only one level of
600 undo and there is no redo.
604 undo and there is no redo.
601
605
602 This command is not intended for use on public repositories. Once
606 This command is not intended for use on public repositories. Once
603 a change is visible for pull by other users, undoing it locally is
607 a change is visible for pull by other users, undoing it locally is
604 ineffective.
608 ineffective.
605
609
606 update [-m -C] [revision]::
610 update [-m -C] [revision]::
607 Update the working directory to the specified revision.
611 Update the working directory to the specified revision.
608
612
609 By default, update will refuse to run if doing so would require
613 By default, update will refuse to run if doing so would require
610 merging or discarding local changes.
614 merging or discarding local changes.
611
615
612 With the -m option, a merge will be performed.
616 With the -m option, a merge will be performed.
613
617
614 With the -C option, local changes will be lost.
618 With the -C option, local changes will be lost.
615
619
616 options:
620 options:
617 -m, --merge allow merging of branches
621 -m, --merge allow merging of branches
618 -C, --clean overwrite locally modified files
622 -C, --clean overwrite locally modified files
619
623
620 aliases: up checkout co
624 aliases: up checkout co
621
625
622 verify::
626 verify::
623 Verify the integrity of the current repository.
627 Verify the integrity of the current repository.
624
628
625 This will perform an extensive check of the repository's
629 This will perform an extensive check of the repository's
626 integrity, validating the hashes and checksums of each entry in
630 integrity, validating the hashes and checksums of each entry in
627 the changelog, manifest, and tracked files, as well as the
631 the changelog, manifest, and tracked files, as well as the
628 integrity of their crosslinks and indices.
632 integrity of their crosslinks and indices.
629
633
630 FILE NAME PATTERNS
634 FILE NAME PATTERNS
631 ------------------
635 ------------------
632
636
633 Mercurial accepts several notations for identifying one or more
637 Mercurial accepts several notations for identifying one or more
634 files at a time.
638 files at a time.
635
639
636 By default, Mercurial treats filenames as shell-style extended
640 By default, Mercurial treats filenames as shell-style extended
637 glob patterns.
641 glob patterns.
638
642
639 Alternate pattern notations must be specified explicitly.
643 Alternate pattern notations must be specified explicitly.
640
644
641 To use a plain path name without any pattern matching, start a
645 To use a plain path name without any pattern matching, start a
642 name with "path:". These path names must match completely, from
646 name with "path:". These path names must match completely, from
643 the root of the current repository.
647 the root of the current repository.
644
648
645 To use an extended glob, start a name with "glob:". Globs are
649 To use an extended glob, start a name with "glob:". Globs are
646 rooted at the current directory; a glob such as "*.c" will match
650 rooted at the current directory; a glob such as "*.c" will match
647 files ending in ".c" in the current directory only.
651 files ending in ".c" in the current directory only.
648
652
649 The supported glob syntax extensions are "**" to match any string
653 The supported glob syntax extensions are "**" to match any string
650 across path separators, and "{a,b}" to mean "a or b".
654 across path separators, and "{a,b}" to mean "a or b".
651
655
652 To use a Perl/Python regular expression, start a name with "re:".
656 To use a Perl/Python regular expression, start a name with "re:".
653 Regexp pattern matching is anchored at the root of the repository.
657 Regexp pattern matching is anchored at the root of the repository.
654
658
655 Plain examples:
659 Plain examples:
656
660
657 path:foo/bar a name bar in a directory named foo in the root of
661 path:foo/bar a name bar in a directory named foo in the root of
658 the repository
662 the repository
659 path:path:name a file or directory named "path:name"
663 path:path:name a file or directory named "path:name"
660
664
661 Glob examples:
665 Glob examples:
662
666
663 glob:*.c any name ending in ".c" in the current directory
667 glob:*.c any name ending in ".c" in the current directory
664 *.c any name ending in ".c" in the current directory
668 *.c any name ending in ".c" in the current directory
665 **.c any name ending in ".c" in the current directory, or
669 **.c any name ending in ".c" in the current directory, or
666 any subdirectory
670 any subdirectory
667 foo/*.c any name ending in ".c" in the directory foo
671 foo/*.c any name ending in ".c" in the directory foo
668 foo/**.c any name ending in ".c" in the directory foo, or any
672 foo/**.c any name ending in ".c" in the directory foo, or any
669 subdirectory
673 subdirectory
670
674
671 Regexp examples:
675 Regexp examples:
672
676
673 re:.*\.c$ any name ending in ".c", anywhere in the repository
677 re:.*\.c$ any name ending in ".c", anywhere in the repository
674
678
675
679
676 SPECIFYING SINGLE REVISIONS
680 SPECIFYING SINGLE REVISIONS
677 ---------------------------
681 ---------------------------
678
682
679 Mercurial accepts several notations for identifying individual
683 Mercurial accepts several notations for identifying individual
680 revisions.
684 revisions.
681
685
682 A plain integer is treated as a revision number. Negative
686 A plain integer is treated as a revision number. Negative
683 integers are treated as offsets from the tip, with -1 denoting the
687 integers are treated as offsets from the tip, with -1 denoting the
684 tip.
688 tip.
685
689
686 A 40-digit hexadecimal string is treated as a unique revision
690 A 40-digit hexadecimal string is treated as a unique revision
687 identifier.
691 identifier.
688
692
689 A hexadecimal string less than 40 characters long is treated as a
693 A hexadecimal string less than 40 characters long is treated as a
690 unique revision identifier, and referred to as a short-form
694 unique revision identifier, and referred to as a short-form
691 identifier. A short-form identifier is only valid if it is the
695 identifier. A short-form identifier is only valid if it is the
692 prefix of one full-length identifier.
696 prefix of one full-length identifier.
693
697
694 Any other string is treated as a tag name, which is a symbolic
698 Any other string is treated as a tag name, which is a symbolic
695 name associated with a revision identifier. Tag names may not
699 name associated with a revision identifier. Tag names may not
696 contain the ":" character.
700 contain the ":" character.
697
701
698 The reserved name "tip" is a special tag that always identifies
702 The reserved name "tip" is a special tag that always identifies
699 the most recent revision.
703 the most recent revision.
700
704
701 SPECIFYING MULTIPLE REVISIONS
705 SPECIFYING MULTIPLE REVISIONS
702 -----------------------------
706 -----------------------------
703
707
704 When Mercurial accepts more than one revision, they may be
708 When Mercurial accepts more than one revision, they may be
705 specified individually, or provided as a continuous range,
709 specified individually, or provided as a continuous range,
706 separated by the ":" character.
710 separated by the ":" character.
707
711
708 The syntax of range notation is [BEGIN]:[END], where BEGIN and END
712 The syntax of range notation is [BEGIN]:[END], where BEGIN and END
709 are revision identifiers. Both BEGIN and END are optional. If
713 are revision identifiers. Both BEGIN and END are optional. If
710 BEGIN is not specified, it defaults to revision number 0. If END
714 BEGIN is not specified, it defaults to revision number 0. If END
711 is not specified, it defaults to the tip. The range ":" thus
715 is not specified, it defaults to the tip. The range ":" thus
712 means "all revisions".
716 means "all revisions".
713
717
714 If BEGIN is greater than END, revisions are treated in reverse
718 If BEGIN is greater than END, revisions are treated in reverse
715 order.
719 order.
716
720
717 A range acts as a closed interval. This means that a range of 3:5
721 A range acts as a closed interval. This means that a range of 3:5
718 gives 3, 4 and 5. Similarly, a range of 4:2 gives 4, 3, and 2.
722 gives 3, 4 and 5. Similarly, a range of 4:2 gives 4, 3, and 2.
719
723
720 ENVIRONMENT VARIABLES
724 ENVIRONMENT VARIABLES
721 ---------------------
725 ---------------------
722
726
723 HGEDITOR::
727 HGEDITOR::
724 This is the name of the editor to use when committing. Defaults to the
728 This is the name of the editor to use when committing. Defaults to the
725 value of EDITOR.
729 value of EDITOR.
726
730
727 (deprecated, use .hgrc)
731 (deprecated, use .hgrc)
728
732
729 HGMERGE::
733 HGMERGE::
730 An executable to use for resolving merge conflicts. The program
734 An executable to use for resolving merge conflicts. The program
731 will be executed with three arguments: local file, remote file,
735 will be executed with three arguments: local file, remote file,
732 ancestor file.
736 ancestor file.
733
737
734 The default program is "hgmerge", which is a shell script provided
738 The default program is "hgmerge", which is a shell script provided
735 by Mercurial with some sensible defaults.
739 by Mercurial with some sensible defaults.
736
740
737 (deprecated, use .hgrc)
741 (deprecated, use .hgrc)
738
742
739 HGUSER::
743 HGUSER::
740 This is the string used for the author of a commit.
744 This is the string used for the author of a commit.
741
745
742 (deprecated, use .hgrc)
746 (deprecated, use .hgrc)
743
747
744 EMAIL::
748 EMAIL::
745 If HGUSER is not set, this will be used as the author for a commit.
749 If HGUSER is not set, this will be used as the author for a commit.
746
750
747 LOGNAME::
751 LOGNAME::
748 If neither HGUSER nor EMAIL is set, LOGNAME will be used (with
752 If neither HGUSER nor EMAIL is set, LOGNAME will be used (with
749 '@hostname' appended) as the author value for a commit.
753 '@hostname' appended) as the author value for a commit.
750
754
751 EDITOR::
755 EDITOR::
752 This is the name of the editor used in the hgmerge script. It will be
756 This is the name of the editor used in the hgmerge script. It will be
753 used for commit messages if HGEDITOR isn't set. Defaults to 'vi'.
757 used for commit messages if HGEDITOR isn't set. Defaults to 'vi'.
754
758
755 PYTHONPATH::
759 PYTHONPATH::
756 This is used by Python to find imported modules and may need to be set
760 This is used by Python to find imported modules and may need to be set
757 appropriately if Mercurial is not installed system-wide.
761 appropriately if Mercurial is not installed system-wide.
758
762
759 FILES
763 FILES
760 -----
764 -----
761 .hgignore::
765 .hgignore::
762 This file contains regular expressions (one per line) that describe file
766 This file contains regular expressions (one per line) that describe file
763 names that should be ignored by hg.
767 names that should be ignored by hg.
764
768
765 .hgtags::
769 .hgtags::
766 This file contains changeset hash values and text tag names (one of each
770 This file contains changeset hash values and text tag names (one of each
767 separated by spaces) that correspond to tagged versions of the repository
771 separated by spaces) that correspond to tagged versions of the repository
768 contents.
772 contents.
769
773
770 /etc/mercurial/hgrc, $HOME/.hgrc, .hg/hgrc::
774 /etc/mercurial/hgrc, $HOME/.hgrc, .hg/hgrc::
771 This file contains defaults and configuration. Values in .hg/hgrc
775 This file contains defaults and configuration. Values in .hg/hgrc
772 override those in $HOME/.hgrc, and these override settings made in the
776 override those in $HOME/.hgrc, and these override settings made in the
773 global /etc/mercurial/hgrc configuration. See hgrc(5) for details of
777 global /etc/mercurial/hgrc configuration. See hgrc(5) for details of
774 the contents and format of these files.
778 the contents and format of these files.
775
779
776 BUGS
780 BUGS
777 ----
781 ----
778 Probably lots, please post them to the mailing list (See Resources below)
782 Probably lots, please post them to the mailing list (See Resources below)
779 when you find them.
783 when you find them.
780
784
781 SEE ALSO
785 SEE ALSO
782 --------
786 --------
783 hgrc(5)
787 hgrc(5)
784
788
785 AUTHOR
789 AUTHOR
786 ------
790 ------
787 Written by Matt Mackall <mpm@selenic.com>
791 Written by Matt Mackall <mpm@selenic.com>
788
792
789 RESOURCES
793 RESOURCES
790 ---------
794 ---------
791 http://selenic.com/mercurial[Main Web Site]
795 http://selenic.com/mercurial[Main Web Site]
792
796
793 http://www.serpentine.com/mercurial[Wiki site]
797 http://www.serpentine.com/mercurial[Wiki site]
794
798
795 http://selenic.com/hg[Source code repository]
799 http://selenic.com/hg[Source code repository]
796
800
797 http://selenic.com/mailman/listinfo/mercurial[Mailing list]
801 http://selenic.com/mailman/listinfo/mercurial[Mailing list]
798
802
799 COPYING
803 COPYING
800 -------
804 -------
801 Copyright (C) 2005 Matt Mackall.
805 Copyright (C) 2005 Matt Mackall.
802 Free use of this software is granted under the terms of the GNU General
806 Free use of this software is granted under the terms of the GNU General
803 Public License (GPL).
807 Public License (GPL).
@@ -1,2205 +1,2206 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 from demandload import demandload
9 from node import *
9 from node import *
10 demandload(globals(), "os re sys signal shutil imp urllib pdb")
10 demandload(globals(), "os re sys signal shutil imp urllib pdb")
11 demandload(globals(), "fancyopts ui hg util lock revlog")
11 demandload(globals(), "fancyopts ui hg util lock revlog")
12 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
12 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
13 demandload(globals(), "errno socket version struct atexit sets bz2")
13 demandload(globals(), "errno socket version struct atexit sets bz2")
14
14
15 class UnknownCommand(Exception):
15 class UnknownCommand(Exception):
16 """Exception raised if command is not in the command table."""
16 """Exception raised if command is not in the command table."""
17
17
18 def filterfiles(filters, files):
18 def filterfiles(filters, files):
19 l = [x for x in files if x in filters]
19 l = [x for x in files if x in filters]
20
20
21 for t in filters:
21 for t in filters:
22 if t and t[-1] != "/":
22 if t and t[-1] != "/":
23 t += "/"
23 t += "/"
24 l += [x for x in files if x.startswith(t)]
24 l += [x for x in files if x.startswith(t)]
25 return l
25 return l
26
26
27 def relpath(repo, args):
27 def relpath(repo, args):
28 cwd = repo.getcwd()
28 cwd = repo.getcwd()
29 if cwd:
29 if cwd:
30 return [util.normpath(os.path.join(cwd, x)) for x in args]
30 return [util.normpath(os.path.join(cwd, x)) for x in args]
31 return args
31 return args
32
32
33 def matchpats(repo, cwd, pats=[], opts={}, head=''):
33 def matchpats(repo, cwd, pats=[], opts={}, head=''):
34 return util.matcher(repo.root, cwd, pats or ['.'], opts.get('include'),
34 return util.matcher(repo.root, cwd, pats or ['.'], opts.get('include'),
35 opts.get('exclude'), head)
35 opts.get('exclude'), head)
36
36
37 def makewalk(repo, pats, opts, head=''):
37 def makewalk(repo, pats, opts, head=''):
38 cwd = repo.getcwd()
38 cwd = repo.getcwd()
39 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
39 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
40 exact = dict(zip(files, files))
40 exact = dict(zip(files, files))
41 def walk():
41 def walk():
42 for src, fn in repo.walk(files=files, match=matchfn):
42 for src, fn in repo.walk(files=files, match=matchfn):
43 yield src, fn, util.pathto(cwd, fn), fn in exact
43 yield src, fn, util.pathto(cwd, fn), fn in exact
44 return files, matchfn, walk()
44 return files, matchfn, walk()
45
45
46 def walk(repo, pats, opts, head=''):
46 def walk(repo, pats, opts, head=''):
47 files, matchfn, results = makewalk(repo, pats, opts, head)
47 files, matchfn, results = makewalk(repo, pats, opts, head)
48 for r in results:
48 for r in results:
49 yield r
49 yield r
50
50
51 def walkchangerevs(ui, repo, cwd, pats, opts):
51 def walkchangerevs(ui, repo, cwd, pats, opts):
52 '''Iterate over files and the revs they changed in.
52 '''Iterate over files and the revs they changed in.
53
53
54 Callers most commonly need to iterate backwards over the history
54 Callers most commonly need to iterate backwards over the history
55 it is interested in. Doing so has awful (quadratic-looking)
55 it is interested in. Doing so has awful (quadratic-looking)
56 performance, so we use iterators in a "windowed" way.
56 performance, so we use iterators in a "windowed" way.
57
57
58 We walk a window of revisions in the desired order. Within the
58 We walk a window of revisions in the desired order. Within the
59 window, we first walk forwards to gather data, then in the desired
59 window, we first walk forwards to gather data, then in the desired
60 order (usually backwards) to display it.
60 order (usually backwards) to display it.
61
61
62 This function returns an (iterator, getchange) pair. The
62 This function returns an (iterator, getchange) pair. The
63 getchange function returns the changelog entry for a numeric
63 getchange function returns the changelog entry for a numeric
64 revision. The iterator yields 3-tuples. They will be of one of
64 revision. The iterator yields 3-tuples. They will be of one of
65 the following forms:
65 the following forms:
66
66
67 "window", incrementing, lastrev: stepping through a window,
67 "window", incrementing, lastrev: stepping through a window,
68 positive if walking forwards through revs, last rev in the
68 positive if walking forwards through revs, last rev in the
69 sequence iterated over - use to reset state for the current window
69 sequence iterated over - use to reset state for the current window
70
70
71 "add", rev, fns: out-of-order traversal of the given file names
71 "add", rev, fns: out-of-order traversal of the given file names
72 fns, which changed during revision rev - use to gather data for
72 fns, which changed during revision rev - use to gather data for
73 possible display
73 possible display
74
74
75 "iter", rev, None: in-order traversal of the revs earlier iterated
75 "iter", rev, None: in-order traversal of the revs earlier iterated
76 over with "add" - use to display data'''
76 over with "add" - use to display data'''
77 cwd = repo.getcwd()
77 cwd = repo.getcwd()
78 if not pats and cwd:
78 if not pats and cwd:
79 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
79 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
80 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
80 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
81 files, matchfn, anypats = matchpats(repo, (pats and cwd) or '',
81 files, matchfn, anypats = matchpats(repo, (pats and cwd) or '',
82 pats, opts)
82 pats, opts)
83 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
83 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
84 wanted = {}
84 wanted = {}
85 slowpath = anypats
85 slowpath = anypats
86 window = 300
86 window = 300
87 fncache = {}
87 fncache = {}
88
88
89 chcache = {}
89 chcache = {}
90 def getchange(rev):
90 def getchange(rev):
91 ch = chcache.get(rev)
91 ch = chcache.get(rev)
92 if ch is None:
92 if ch is None:
93 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
93 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
94 return ch
94 return ch
95
95
96 if not slowpath and not files:
96 if not slowpath and not files:
97 # No files, no patterns. Display all revs.
97 # No files, no patterns. Display all revs.
98 wanted = dict(zip(revs, revs))
98 wanted = dict(zip(revs, revs))
99 if not slowpath:
99 if not slowpath:
100 # Only files, no patterns. Check the history of each file.
100 # Only files, no patterns. Check the history of each file.
101 def filerevgen(filelog):
101 def filerevgen(filelog):
102 for i in xrange(filelog.count() - 1, -1, -window):
102 for i in xrange(filelog.count() - 1, -1, -window):
103 revs = []
103 revs = []
104 for j in xrange(max(0, i - window), i + 1):
104 for j in xrange(max(0, i - window), i + 1):
105 revs.append(filelog.linkrev(filelog.node(j)))
105 revs.append(filelog.linkrev(filelog.node(j)))
106 revs.reverse()
106 revs.reverse()
107 for rev in revs:
107 for rev in revs:
108 yield rev
108 yield rev
109
109
110 minrev, maxrev = min(revs), max(revs)
110 minrev, maxrev = min(revs), max(revs)
111 for file in files:
111 for file in files:
112 filelog = repo.file(file)
112 filelog = repo.file(file)
113 # A zero count may be a directory or deleted file, so
113 # A zero count may be a directory or deleted file, so
114 # try to find matching entries on the slow path.
114 # try to find matching entries on the slow path.
115 if filelog.count() == 0:
115 if filelog.count() == 0:
116 slowpath = True
116 slowpath = True
117 break
117 break
118 for rev in filerevgen(filelog):
118 for rev in filerevgen(filelog):
119 if rev <= maxrev:
119 if rev <= maxrev:
120 if rev < minrev:
120 if rev < minrev:
121 break
121 break
122 fncache.setdefault(rev, [])
122 fncache.setdefault(rev, [])
123 fncache[rev].append(file)
123 fncache[rev].append(file)
124 wanted[rev] = 1
124 wanted[rev] = 1
125 if slowpath:
125 if slowpath:
126 # The slow path checks files modified in every changeset.
126 # The slow path checks files modified in every changeset.
127 def changerevgen():
127 def changerevgen():
128 for i in xrange(repo.changelog.count() - 1, -1, -window):
128 for i in xrange(repo.changelog.count() - 1, -1, -window):
129 for j in xrange(max(0, i - window), i + 1):
129 for j in xrange(max(0, i - window), i + 1):
130 yield j, getchange(j)[3]
130 yield j, getchange(j)[3]
131
131
132 for rev, changefiles in changerevgen():
132 for rev, changefiles in changerevgen():
133 matches = filter(matchfn, changefiles)
133 matches = filter(matchfn, changefiles)
134 if matches:
134 if matches:
135 fncache[rev] = matches
135 fncache[rev] = matches
136 wanted[rev] = 1
136 wanted[rev] = 1
137
137
138 def iterate():
138 def iterate():
139 for i in xrange(0, len(revs), window):
139 for i in xrange(0, len(revs), window):
140 yield 'window', revs[0] < revs[-1], revs[-1]
140 yield 'window', revs[0] < revs[-1], revs[-1]
141 nrevs = [rev for rev in revs[i:min(i+window, len(revs))]
141 nrevs = [rev for rev in revs[i:min(i+window, len(revs))]
142 if rev in wanted]
142 if rev in wanted]
143 srevs = list(nrevs)
143 srevs = list(nrevs)
144 srevs.sort()
144 srevs.sort()
145 for rev in srevs:
145 for rev in srevs:
146 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
146 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
147 yield 'add', rev, fns
147 yield 'add', rev, fns
148 for rev in nrevs:
148 for rev in nrevs:
149 yield 'iter', rev, None
149 yield 'iter', rev, None
150 return iterate(), getchange
150 return iterate(), getchange
151
151
152 revrangesep = ':'
152 revrangesep = ':'
153
153
154 def revrange(ui, repo, revs, revlog=None):
154 def revrange(ui, repo, revs, revlog=None):
155 """Yield revision as strings from a list of revision specifications."""
155 """Yield revision as strings from a list of revision specifications."""
156 if revlog is None:
156 if revlog is None:
157 revlog = repo.changelog
157 revlog = repo.changelog
158 revcount = revlog.count()
158 revcount = revlog.count()
159 def fix(val, defval):
159 def fix(val, defval):
160 if not val:
160 if not val:
161 return defval
161 return defval
162 try:
162 try:
163 num = int(val)
163 num = int(val)
164 if str(num) != val:
164 if str(num) != val:
165 raise ValueError
165 raise ValueError
166 if num < 0: num += revcount
166 if num < 0: num += revcount
167 if num < 0: num = 0
167 if num < 0: num = 0
168 elif num >= revcount:
168 elif num >= revcount:
169 raise ValueError
169 raise ValueError
170 except ValueError:
170 except ValueError:
171 try:
171 try:
172 num = repo.changelog.rev(repo.lookup(val))
172 num = repo.changelog.rev(repo.lookup(val))
173 except KeyError:
173 except KeyError:
174 try:
174 try:
175 num = revlog.rev(revlog.lookup(val))
175 num = revlog.rev(revlog.lookup(val))
176 except KeyError:
176 except KeyError:
177 raise util.Abort('invalid revision identifier %s', val)
177 raise util.Abort('invalid revision identifier %s', val)
178 return num
178 return num
179 seen = {}
179 seen = {}
180 for spec in revs:
180 for spec in revs:
181 if spec.find(revrangesep) >= 0:
181 if spec.find(revrangesep) >= 0:
182 start, end = spec.split(revrangesep, 1)
182 start, end = spec.split(revrangesep, 1)
183 start = fix(start, 0)
183 start = fix(start, 0)
184 end = fix(end, revcount - 1)
184 end = fix(end, revcount - 1)
185 step = start > end and -1 or 1
185 step = start > end and -1 or 1
186 for rev in xrange(start, end+step, step):
186 for rev in xrange(start, end+step, step):
187 if rev in seen: continue
187 if rev in seen: continue
188 seen[rev] = 1
188 seen[rev] = 1
189 yield str(rev)
189 yield str(rev)
190 else:
190 else:
191 rev = fix(spec, None)
191 rev = fix(spec, None)
192 if rev in seen: continue
192 if rev in seen: continue
193 seen[rev] = 1
193 seen[rev] = 1
194 yield str(rev)
194 yield str(rev)
195
195
196 def make_filename(repo, r, pat, node=None,
196 def make_filename(repo, r, pat, node=None,
197 total=None, seqno=None, revwidth=None, pathname=None):
197 total=None, seqno=None, revwidth=None, pathname=None):
198 node_expander = {
198 node_expander = {
199 'H': lambda: hex(node),
199 'H': lambda: hex(node),
200 'R': lambda: str(r.rev(node)),
200 'R': lambda: str(r.rev(node)),
201 'h': lambda: short(node),
201 'h': lambda: short(node),
202 }
202 }
203 expander = {
203 expander = {
204 '%': lambda: '%',
204 '%': lambda: '%',
205 'b': lambda: os.path.basename(repo.root),
205 'b': lambda: os.path.basename(repo.root),
206 }
206 }
207
207
208 try:
208 try:
209 if node:
209 if node:
210 expander.update(node_expander)
210 expander.update(node_expander)
211 if node and revwidth is not None:
211 if node and revwidth is not None:
212 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
212 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
213 if total is not None:
213 if total is not None:
214 expander['N'] = lambda: str(total)
214 expander['N'] = lambda: str(total)
215 if seqno is not None:
215 if seqno is not None:
216 expander['n'] = lambda: str(seqno)
216 expander['n'] = lambda: str(seqno)
217 if total is not None and seqno is not None:
217 if total is not None and seqno is not None:
218 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
218 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
219 if pathname is not None:
219 if pathname is not None:
220 expander['s'] = lambda: os.path.basename(pathname)
220 expander['s'] = lambda: os.path.basename(pathname)
221 expander['d'] = lambda: os.path.dirname(pathname) or '.'
221 expander['d'] = lambda: os.path.dirname(pathname) or '.'
222 expander['p'] = lambda: pathname
222 expander['p'] = lambda: pathname
223
223
224 newname = []
224 newname = []
225 patlen = len(pat)
225 patlen = len(pat)
226 i = 0
226 i = 0
227 while i < patlen:
227 while i < patlen:
228 c = pat[i]
228 c = pat[i]
229 if c == '%':
229 if c == '%':
230 i += 1
230 i += 1
231 c = pat[i]
231 c = pat[i]
232 c = expander[c]()
232 c = expander[c]()
233 newname.append(c)
233 newname.append(c)
234 i += 1
234 i += 1
235 return ''.join(newname)
235 return ''.join(newname)
236 except KeyError, inst:
236 except KeyError, inst:
237 raise util.Abort("invalid format spec '%%%s' in output file name",
237 raise util.Abort("invalid format spec '%%%s' in output file name",
238 inst.args[0])
238 inst.args[0])
239
239
240 def make_file(repo, r, pat, node=None,
240 def make_file(repo, r, pat, node=None,
241 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
241 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
242 if not pat or pat == '-':
242 if not pat or pat == '-':
243 return 'w' in mode and sys.stdout or sys.stdin
243 return 'w' in mode and sys.stdout or sys.stdin
244 if hasattr(pat, 'write') and 'w' in mode:
244 if hasattr(pat, 'write') and 'w' in mode:
245 return pat
245 return pat
246 if hasattr(pat, 'read') and 'r' in mode:
246 if hasattr(pat, 'read') and 'r' in mode:
247 return pat
247 return pat
248 return open(make_filename(repo, r, pat, node, total, seqno, revwidth,
248 return open(make_filename(repo, r, pat, node, total, seqno, revwidth,
249 pathname),
249 pathname),
250 mode)
250 mode)
251
251
252 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
252 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
253 changes=None, text=False):
253 changes=None, text=False):
254 def date(c):
254 def date(c):
255 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
255 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
256
256
257 if not changes:
257 if not changes:
258 (c, a, d, u) = repo.changes(node1, node2, files, match=match)
258 (c, a, d, u) = repo.changes(node1, node2, files, match=match)
259 else:
259 else:
260 (c, a, d, u) = changes
260 (c, a, d, u) = changes
261 if files:
261 if files:
262 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
262 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
263
263
264 if not c and not a and not d:
264 if not c and not a and not d:
265 return
265 return
266
266
267 if node2:
267 if node2:
268 change = repo.changelog.read(node2)
268 change = repo.changelog.read(node2)
269 mmap2 = repo.manifest.read(change[0])
269 mmap2 = repo.manifest.read(change[0])
270 date2 = date(change)
270 date2 = date(change)
271 def read(f):
271 def read(f):
272 return repo.file(f).read(mmap2[f])
272 return repo.file(f).read(mmap2[f])
273 else:
273 else:
274 date2 = time.asctime()
274 date2 = time.asctime()
275 if not node1:
275 if not node1:
276 node1 = repo.dirstate.parents()[0]
276 node1 = repo.dirstate.parents()[0]
277 def read(f):
277 def read(f):
278 return repo.wfile(f).read()
278 return repo.wfile(f).read()
279
279
280 if ui.quiet:
280 if ui.quiet:
281 r = None
281 r = None
282 else:
282 else:
283 hexfunc = ui.verbose and hex or short
283 hexfunc = ui.verbose and hex or short
284 r = [hexfunc(node) for node in [node1, node2] if node]
284 r = [hexfunc(node) for node in [node1, node2] if node]
285
285
286 change = repo.changelog.read(node1)
286 change = repo.changelog.read(node1)
287 mmap = repo.manifest.read(change[0])
287 mmap = repo.manifest.read(change[0])
288 date1 = date(change)
288 date1 = date(change)
289
289
290 for f in c:
290 for f in c:
291 to = None
291 to = None
292 if f in mmap:
292 if f in mmap:
293 to = repo.file(f).read(mmap[f])
293 to = repo.file(f).read(mmap[f])
294 tn = read(f)
294 tn = read(f)
295 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
295 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
296 for f in a:
296 for f in a:
297 to = None
297 to = None
298 tn = read(f)
298 tn = read(f)
299 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
299 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
300 for f in d:
300 for f in d:
301 to = repo.file(f).read(mmap[f])
301 to = repo.file(f).read(mmap[f])
302 tn = None
302 tn = None
303 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
303 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
304
304
305 def trimuser(ui, name, rev, revcache):
305 def trimuser(ui, name, rev, revcache):
306 """trim the name of the user who committed a change"""
306 """trim the name of the user who committed a change"""
307 user = revcache.get(rev)
307 user = revcache.get(rev)
308 if user is None:
308 if user is None:
309 user = revcache[rev] = ui.shortuser(name)
309 user = revcache[rev] = ui.shortuser(name)
310 return user
310 return user
311
311
312 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
312 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
313 """show a single changeset or file revision"""
313 """show a single changeset or file revision"""
314 log = repo.changelog
314 log = repo.changelog
315 if changenode is None:
315 if changenode is None:
316 changenode = log.node(rev)
316 changenode = log.node(rev)
317 elif not rev:
317 elif not rev:
318 rev = log.rev(changenode)
318 rev = log.rev(changenode)
319
319
320 if ui.quiet:
320 if ui.quiet:
321 ui.write("%d:%s\n" % (rev, short(changenode)))
321 ui.write("%d:%s\n" % (rev, short(changenode)))
322 return
322 return
323
323
324 changes = log.read(changenode)
324 changes = log.read(changenode)
325
325
326 t, tz = changes[2].split(' ')
326 t, tz = changes[2].split(' ')
327 # a conversion tool was sticking non-integer offsets into repos
327 # a conversion tool was sticking non-integer offsets into repos
328 try:
328 try:
329 tz = int(tz)
329 tz = int(tz)
330 except ValueError:
330 except ValueError:
331 tz = 0
331 tz = 0
332 date = time.asctime(time.localtime(float(t))) + " %+05d" % (int(tz)/-36)
332 date = time.asctime(time.localtime(float(t))) + " %+05d" % (int(tz)/-36)
333
333
334 parents = [(log.rev(p), ui.verbose and hex(p) or short(p))
334 parents = [(log.rev(p), ui.verbose and hex(p) or short(p))
335 for p in log.parents(changenode)
335 for p in log.parents(changenode)
336 if ui.debugflag or p != nullid]
336 if ui.debugflag or p != nullid]
337 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
337 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
338 parents = []
338 parents = []
339
339
340 if ui.verbose:
340 if ui.verbose:
341 ui.write("changeset: %d:%s\n" % (rev, hex(changenode)))
341 ui.write("changeset: %d:%s\n" % (rev, hex(changenode)))
342 else:
342 else:
343 ui.write("changeset: %d:%s\n" % (rev, short(changenode)))
343 ui.write("changeset: %d:%s\n" % (rev, short(changenode)))
344
344
345 for tag in repo.nodetags(changenode):
345 for tag in repo.nodetags(changenode):
346 ui.status("tag: %s\n" % tag)
346 ui.status("tag: %s\n" % tag)
347 for parent in parents:
347 for parent in parents:
348 ui.write("parent: %d:%s\n" % parent)
348 ui.write("parent: %d:%s\n" % parent)
349
349
350 if brinfo and changenode in brinfo:
350 if brinfo and changenode in brinfo:
351 br = brinfo[changenode]
351 br = brinfo[changenode]
352 ui.write("branch: %s\n" % " ".join(br))
352 ui.write("branch: %s\n" % " ".join(br))
353
353
354 ui.debug("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
354 ui.debug("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
355 hex(changes[0])))
355 hex(changes[0])))
356 ui.status("user: %s\n" % changes[1])
356 ui.status("user: %s\n" % changes[1])
357 ui.status("date: %s\n" % date)
357 ui.status("date: %s\n" % date)
358
358
359 if ui.debugflag:
359 if ui.debugflag:
360 files = repo.changes(log.parents(changenode)[0], changenode)
360 files = repo.changes(log.parents(changenode)[0], changenode)
361 for key, value in zip(["files:", "files+:", "files-:"], files):
361 for key, value in zip(["files:", "files+:", "files-:"], files):
362 if value:
362 if value:
363 ui.note("%-12s %s\n" % (key, " ".join(value)))
363 ui.note("%-12s %s\n" % (key, " ".join(value)))
364 else:
364 else:
365 ui.note("files: %s\n" % " ".join(changes[3]))
365 ui.note("files: %s\n" % " ".join(changes[3]))
366
366
367 description = changes[4].strip()
367 description = changes[4].strip()
368 if description:
368 if description:
369 if ui.verbose:
369 if ui.verbose:
370 ui.status("description:\n")
370 ui.status("description:\n")
371 ui.status(description)
371 ui.status(description)
372 ui.status("\n\n")
372 ui.status("\n\n")
373 else:
373 else:
374 ui.status("summary: %s\n" % description.splitlines()[0])
374 ui.status("summary: %s\n" % description.splitlines()[0])
375 ui.status("\n")
375 ui.status("\n")
376
376
377 def show_version(ui):
377 def show_version(ui):
378 """output version and copyright information"""
378 """output version and copyright information"""
379 ui.write("Mercurial Distributed SCM (version %s)\n"
379 ui.write("Mercurial Distributed SCM (version %s)\n"
380 % version.get_version())
380 % version.get_version())
381 ui.status(
381 ui.status(
382 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
382 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
383 "This is free software; see the source for copying conditions. "
383 "This is free software; see the source for copying conditions. "
384 "There is NO\nwarranty; "
384 "There is NO\nwarranty; "
385 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
385 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
386 )
386 )
387
387
388 def help_(ui, cmd=None, with_version=False):
388 def help_(ui, cmd=None, with_version=False):
389 """show help for a given command or all commands"""
389 """show help for a given command or all commands"""
390 option_lists = []
390 option_lists = []
391 if cmd and cmd != 'shortlist':
391 if cmd and cmd != 'shortlist':
392 if with_version:
392 if with_version:
393 show_version(ui)
393 show_version(ui)
394 ui.write('\n')
394 ui.write('\n')
395 key, i = find(cmd)
395 key, i = find(cmd)
396 # synopsis
396 # synopsis
397 ui.write("%s\n\n" % i[2])
397 ui.write("%s\n\n" % i[2])
398
398
399 # description
399 # description
400 doc = i[0].__doc__
400 doc = i[0].__doc__
401 if ui.quiet:
401 if ui.quiet:
402 doc = doc.splitlines(0)[0]
402 doc = doc.splitlines(0)[0]
403 ui.write("%s\n" % doc.rstrip())
403 ui.write("%s\n" % doc.rstrip())
404
404
405 if not ui.quiet:
405 if not ui.quiet:
406 # aliases
406 # aliases
407 aliases = ', '.join(key.split('|')[1:])
407 aliases = ', '.join(key.split('|')[1:])
408 if aliases:
408 if aliases:
409 ui.write("\naliases: %s\n" % aliases)
409 ui.write("\naliases: %s\n" % aliases)
410
410
411 # options
411 # options
412 if i[1]:
412 if i[1]:
413 option_lists.append(("options", i[1]))
413 option_lists.append(("options", i[1]))
414
414
415 else:
415 else:
416 # program name
416 # program name
417 if ui.verbose or with_version:
417 if ui.verbose or with_version:
418 show_version(ui)
418 show_version(ui)
419 else:
419 else:
420 ui.status("Mercurial Distributed SCM\n")
420 ui.status("Mercurial Distributed SCM\n")
421 ui.status('\n')
421 ui.status('\n')
422
422
423 # list of commands
423 # list of commands
424 if cmd == "shortlist":
424 if cmd == "shortlist":
425 ui.status('basic commands (use "hg help" '
425 ui.status('basic commands (use "hg help" '
426 'for the full list or option "-v" for details):\n\n')
426 'for the full list or option "-v" for details):\n\n')
427 elif ui.verbose:
427 elif ui.verbose:
428 ui.status('list of commands:\n\n')
428 ui.status('list of commands:\n\n')
429 else:
429 else:
430 ui.status('list of commands (use "hg help -v" '
430 ui.status('list of commands (use "hg help -v" '
431 'to show aliases and global options):\n\n')
431 'to show aliases and global options):\n\n')
432
432
433 h = {}
433 h = {}
434 cmds = {}
434 cmds = {}
435 for c, e in table.items():
435 for c, e in table.items():
436 f = c.split("|")[0]
436 f = c.split("|")[0]
437 if cmd == "shortlist" and not f.startswith("^"):
437 if cmd == "shortlist" and not f.startswith("^"):
438 continue
438 continue
439 f = f.lstrip("^")
439 f = f.lstrip("^")
440 if not ui.debugflag and f.startswith("debug"):
440 if not ui.debugflag and f.startswith("debug"):
441 continue
441 continue
442 d = ""
442 d = ""
443 if e[0].__doc__:
443 if e[0].__doc__:
444 d = e[0].__doc__.splitlines(0)[0].rstrip()
444 d = e[0].__doc__.splitlines(0)[0].rstrip()
445 h[f] = d
445 h[f] = d
446 cmds[f]=c.lstrip("^")
446 cmds[f]=c.lstrip("^")
447
447
448 fns = h.keys()
448 fns = h.keys()
449 fns.sort()
449 fns.sort()
450 m = max(map(len, fns))
450 m = max(map(len, fns))
451 for f in fns:
451 for f in fns:
452 if ui.verbose:
452 if ui.verbose:
453 commands = cmds[f].replace("|",", ")
453 commands = cmds[f].replace("|",", ")
454 ui.write(" %s:\n %s\n"%(commands,h[f]))
454 ui.write(" %s:\n %s\n"%(commands,h[f]))
455 else:
455 else:
456 ui.write(' %-*s %s\n' % (m, f, h[f]))
456 ui.write(' %-*s %s\n' % (m, f, h[f]))
457
457
458 # global options
458 # global options
459 if ui.verbose:
459 if ui.verbose:
460 option_lists.append(("global options", globalopts))
460 option_lists.append(("global options", globalopts))
461
461
462 # list all option lists
462 # list all option lists
463 opt_output = []
463 opt_output = []
464 for title, options in option_lists:
464 for title, options in option_lists:
465 opt_output.append(("\n%s:\n" % title, None))
465 opt_output.append(("\n%s:\n" % title, None))
466 for shortopt, longopt, default, desc in options:
466 for shortopt, longopt, default, desc in options:
467 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
467 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
468 longopt and " --%s" % longopt),
468 longopt and " --%s" % longopt),
469 "%s%s" % (desc,
469 "%s%s" % (desc,
470 default and " (default: %s)" % default
470 default and " (default: %s)" % default
471 or "")))
471 or "")))
472
472
473 if opt_output:
473 if opt_output:
474 opts_len = max([len(line[0]) for line in opt_output if line[1]])
474 opts_len = max([len(line[0]) for line in opt_output if line[1]])
475 for first, second in opt_output:
475 for first, second in opt_output:
476 if second:
476 if second:
477 ui.write(" %-*s %s\n" % (opts_len, first, second))
477 ui.write(" %-*s %s\n" % (opts_len, first, second))
478 else:
478 else:
479 ui.write("%s\n" % first)
479 ui.write("%s\n" % first)
480
480
481 # Commands start here, listed alphabetically
481 # Commands start here, listed alphabetically
482
482
483 def add(ui, repo, *pats, **opts):
483 def add(ui, repo, *pats, **opts):
484 '''add the specified files on the next commit'''
484 '''add the specified files on the next commit'''
485 names = []
485 names = []
486 for src, abs, rel, exact in walk(repo, pats, opts):
486 for src, abs, rel, exact in walk(repo, pats, opts):
487 if exact:
487 if exact:
488 if ui.verbose: ui.status('adding %s\n' % rel)
488 if ui.verbose: ui.status('adding %s\n' % rel)
489 names.append(abs)
489 names.append(abs)
490 elif repo.dirstate.state(abs) == '?':
490 elif repo.dirstate.state(abs) == '?':
491 ui.status('adding %s\n' % rel)
491 ui.status('adding %s\n' % rel)
492 names.append(abs)
492 names.append(abs)
493 repo.add(names)
493 repo.add(names)
494
494
495 def addremove(ui, repo, *pats, **opts):
495 def addremove(ui, repo, *pats, **opts):
496 """add all new files, delete all missing files"""
496 """add all new files, delete all missing files"""
497 add, remove = [], []
497 add, remove = [], []
498 for src, abs, rel, exact in walk(repo, pats, opts):
498 for src, abs, rel, exact in walk(repo, pats, opts):
499 if src == 'f' and repo.dirstate.state(abs) == '?':
499 if src == 'f' and repo.dirstate.state(abs) == '?':
500 add.append(abs)
500 add.append(abs)
501 if ui.verbose or not exact:
501 if ui.verbose or not exact:
502 ui.status('adding ', rel, '\n')
502 ui.status('adding ', rel, '\n')
503 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
503 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
504 remove.append(abs)
504 remove.append(abs)
505 if ui.verbose or not exact:
505 if ui.verbose or not exact:
506 ui.status('removing ', rel, '\n')
506 ui.status('removing ', rel, '\n')
507 repo.add(add)
507 repo.add(add)
508 repo.remove(remove)
508 repo.remove(remove)
509
509
510 def annotate(ui, repo, *pats, **opts):
510 def annotate(ui, repo, *pats, **opts):
511 """show changeset information per file line"""
511 """show changeset information per file line"""
512 def getnode(rev):
512 def getnode(rev):
513 return short(repo.changelog.node(rev))
513 return short(repo.changelog.node(rev))
514
514
515 ucache = {}
515 ucache = {}
516 def getname(rev):
516 def getname(rev):
517 cl = repo.changelog.read(repo.changelog.node(rev))
517 cl = repo.changelog.read(repo.changelog.node(rev))
518 return trimuser(ui, cl[1], rev, ucache)
518 return trimuser(ui, cl[1], rev, ucache)
519
519
520 if not pats:
520 if not pats:
521 raise util.Abort('at least one file name or pattern required')
521 raise util.Abort('at least one file name or pattern required')
522
522
523 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
523 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
524 if not opts['user'] and not opts['changeset']:
524 if not opts['user'] and not opts['changeset']:
525 opts['number'] = 1
525 opts['number'] = 1
526
526
527 if opts['rev']:
527 if opts['rev']:
528 node = repo.changelog.lookup(opts['rev'])
528 node = repo.changelog.lookup(opts['rev'])
529 else:
529 else:
530 node = repo.dirstate.parents()[0]
530 node = repo.dirstate.parents()[0]
531 change = repo.changelog.read(node)
531 change = repo.changelog.read(node)
532 mmap = repo.manifest.read(change[0])
532 mmap = repo.manifest.read(change[0])
533
533
534 for src, abs, rel, exact in walk(repo, pats, opts):
534 for src, abs, rel, exact in walk(repo, pats, opts):
535 if abs not in mmap:
535 if abs not in mmap:
536 ui.warn("warning: %s is not in the repository!\n" % rel)
536 ui.warn("warning: %s is not in the repository!\n" % rel)
537 continue
537 continue
538
538
539 f = repo.file(abs)
539 f = repo.file(abs)
540 if not opts['text'] and util.binary(f.read(mmap[abs])):
540 if not opts['text'] and util.binary(f.read(mmap[abs])):
541 ui.write("%s: binary file\n" % rel)
541 ui.write("%s: binary file\n" % rel)
542 continue
542 continue
543
543
544 lines = f.annotate(mmap[abs])
544 lines = f.annotate(mmap[abs])
545 pieces = []
545 pieces = []
546
546
547 for o, f in opmap:
547 for o, f in opmap:
548 if opts[o]:
548 if opts[o]:
549 l = [f(n) for n, dummy in lines]
549 l = [f(n) for n, dummy in lines]
550 if l:
550 if l:
551 m = max(map(len, l))
551 m = max(map(len, l))
552 pieces.append(["%*s" % (m, x) for x in l])
552 pieces.append(["%*s" % (m, x) for x in l])
553
553
554 if pieces:
554 if pieces:
555 for p, l in zip(zip(*pieces), lines):
555 for p, l in zip(zip(*pieces), lines):
556 ui.write("%s: %s" % (" ".join(p), l[1]))
556 ui.write("%s: %s" % (" ".join(p), l[1]))
557
557
558 def bundle(ui, repo, fname, dest="default-push", **opts):
558 def bundle(ui, repo, fname, dest="default-push", **opts):
559 """create a changegroup file"""
559 """create a changegroup file"""
560 f = open(fname, "wb")
560 f = open(fname, "wb")
561 dest = ui.expandpath(dest)
561 dest = ui.expandpath(dest)
562 other = hg.repository(ui, dest)
562 other = hg.repository(ui, dest)
563 o = repo.findoutgoing(other)
563 o = repo.findoutgoing(other)
564 cg = repo.changegroup(o)
564 cg = repo.changegroup(o)
565
565
566 try:
566 try:
567 f.write("HG10")
567 f.write("HG10")
568 z = bz2.BZ2Compressor(9)
568 z = bz2.BZ2Compressor(9)
569 while 1:
569 while 1:
570 chunk = cg.read(4096)
570 chunk = cg.read(4096)
571 if not chunk:
571 if not chunk:
572 break
572 break
573 f.write(z.compress(chunk))
573 f.write(z.compress(chunk))
574 f.write(z.flush())
574 f.write(z.flush())
575 except:
575 except:
576 os.unlink(fname)
576 os.unlink(fname)
577
577
578 def cat(ui, repo, file1, *pats, **opts):
578 def cat(ui, repo, file1, *pats, **opts):
579 """output the latest or given revisions of files"""
579 """output the latest or given revisions of files"""
580 mf = {}
580 mf = {}
581 if opts['rev']:
581 if opts['rev']:
582 change = repo.changelog.read(repo.lookup(opts['rev']))
582 change = repo.changelog.read(repo.lookup(opts['rev']))
583 mf = repo.manifest.read(change[0])
583 mf = repo.manifest.read(change[0])
584 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts):
584 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts):
585 r = repo.file(abs)
585 r = repo.file(abs)
586 if opts['rev']:
586 if opts['rev']:
587 try:
587 try:
588 n = mf[abs]
588 n = mf[abs]
589 except (hg.RepoError, KeyError):
589 except (hg.RepoError, KeyError):
590 try:
590 try:
591 n = r.lookup(rev)
591 n = r.lookup(rev)
592 except KeyError, inst:
592 except KeyError, inst:
593 raise util.Abort('cannot find file %s in rev %s', rel, rev)
593 raise util.Abort('cannot find file %s in rev %s', rel, rev)
594 else:
594 else:
595 n = r.tip()
595 n = r.tip()
596 fp = make_file(repo, r, opts['output'], node=n, pathname=abs)
596 fp = make_file(repo, r, opts['output'], node=n, pathname=abs)
597 fp.write(r.read(n))
597 fp.write(r.read(n))
598
598
599 def clone(ui, source, dest=None, **opts):
599 def clone(ui, source, dest=None, **opts):
600 """make a copy of an existing repository"""
600 """make a copy of an existing repository"""
601 if dest is None:
601 if dest is None:
602 dest = os.path.basename(os.path.normpath(source))
602 dest = os.path.basename(os.path.normpath(source))
603
603
604 if os.path.exists(dest):
604 if os.path.exists(dest):
605 raise util.Abort("destination '%s' already exists", dest)
605 raise util.Abort("destination '%s' already exists", dest)
606
606
607 dest = os.path.realpath(dest)
607 dest = os.path.realpath(dest)
608
608
609 class Dircleanup:
609 class Dircleanup:
610 def __init__(self, dir_):
610 def __init__(self, dir_):
611 self.rmtree = shutil.rmtree
611 self.rmtree = shutil.rmtree
612 self.dir_ = dir_
612 self.dir_ = dir_
613 os.mkdir(dir_)
613 os.mkdir(dir_)
614 def close(self):
614 def close(self):
615 self.dir_ = None
615 self.dir_ = None
616 def __del__(self):
616 def __del__(self):
617 if self.dir_:
617 if self.dir_:
618 self.rmtree(self.dir_, True)
618 self.rmtree(self.dir_, True)
619
619
620 if opts['ssh']:
620 if opts['ssh']:
621 ui.setconfig("ui", "ssh", opts['ssh'])
621 ui.setconfig("ui", "ssh", opts['ssh'])
622 if opts['remotecmd']:
622 if opts['remotecmd']:
623 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
623 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
624
624
625 d = Dircleanup(dest)
625 d = Dircleanup(dest)
626 if not os.path.exists(source):
626 if not os.path.exists(source):
627 source = ui.expandpath(source)
627 source = ui.expandpath(source)
628 abspath = source
628 abspath = source
629 other = hg.repository(ui, source)
629 other = hg.repository(ui, source)
630
630
631 copy = False
631 copy = False
632 if other.dev() != -1:
632 if not opts['pull'] and other.dev() != -1:
633 abspath = os.path.abspath(source)
633 abspath = os.path.abspath(source)
634 copy = True
634 copy = True
635
635
636 if copy:
636 if copy:
637 try:
637 try:
638 # we use a lock here because if we race with commit, we
638 # we use a lock here because if we race with commit, we
639 # can end up with extra data in the cloned revlogs that's
639 # can end up with extra data in the cloned revlogs that's
640 # not pointed to by changesets, thus causing verify to
640 # not pointed to by changesets, thus causing verify to
641 # fail
641 # fail
642 l1 = lock.lock(os.path.join(source, ".hg", "lock"))
642 l1 = lock.lock(os.path.join(source, ".hg", "lock"))
643 except OSError:
643 except OSError:
644 copy = False
644 copy = False
645
645
646 if copy:
646 if copy:
647 # we lock here to avoid premature writing to the target
647 # we lock here to avoid premature writing to the target
648 os.mkdir(os.path.join(dest, ".hg"))
648 os.mkdir(os.path.join(dest, ".hg"))
649 l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
649 l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
650
650
651 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
651 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
652 for f in files.split():
652 for f in files.split():
653 src = os.path.join(source, ".hg", f)
653 src = os.path.join(source, ".hg", f)
654 dst = os.path.join(dest, ".hg", f)
654 dst = os.path.join(dest, ".hg", f)
655 util.copyfiles(src, dst)
655 util.copyfiles(src, dst)
656
656
657 repo = hg.repository(ui, dest)
657 repo = hg.repository(ui, dest)
658
658
659 else:
659 else:
660 repo = hg.repository(ui, dest, create=1)
660 repo = hg.repository(ui, dest, create=1)
661 repo.pull(other)
661 repo.pull(other)
662
662
663 f = repo.opener("hgrc", "w")
663 f = repo.opener("hgrc", "w")
664 f.write("[paths]\n")
664 f.write("[paths]\n")
665 f.write("default = %s\n" % abspath)
665 f.write("default = %s\n" % abspath)
666
666
667 if not opts['noupdate']:
667 if not opts['noupdate']:
668 update(ui, repo)
668 update(ui, repo)
669
669
670 d.close()
670 d.close()
671
671
672 def commit(ui, repo, *pats, **opts):
672 def commit(ui, repo, *pats, **opts):
673 """commit the specified files or all outstanding changes"""
673 """commit the specified files or all outstanding changes"""
674 if opts['text']:
674 if opts['text']:
675 ui.warn("Warning: -t and --text is deprecated,"
675 ui.warn("Warning: -t and --text is deprecated,"
676 " please use -m or --message instead.\n")
676 " please use -m or --message instead.\n")
677 message = opts['message'] or opts['text']
677 message = opts['message'] or opts['text']
678 logfile = opts['logfile']
678 logfile = opts['logfile']
679 if not message and logfile:
679 if not message and logfile:
680 try:
680 try:
681 if logfile == '-':
681 if logfile == '-':
682 message = sys.stdin.read()
682 message = sys.stdin.read()
683 else:
683 else:
684 message = open(logfile).read()
684 message = open(logfile).read()
685 except IOError, why:
685 except IOError, why:
686 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
686 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
687
687
688 if opts['addremove']:
688 if opts['addremove']:
689 addremove(ui, repo, *pats, **opts)
689 addremove(ui, repo, *pats, **opts)
690 cwd = repo.getcwd()
690 cwd = repo.getcwd()
691 if not pats and cwd:
691 if not pats and cwd:
692 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
692 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
693 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
693 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
694 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
694 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
695 pats, opts)
695 pats, opts)
696 if pats:
696 if pats:
697 c, a, d, u = repo.changes(files=fns, match=match)
697 c, a, d, u = repo.changes(files=fns, match=match)
698 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
698 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
699 else:
699 else:
700 files = []
700 files = []
701 try:
701 try:
702 repo.commit(files, message, opts['user'], opts['date'], match)
702 repo.commit(files, message, opts['user'], opts['date'], match)
703 except ValueError, inst:
703 except ValueError, inst:
704 raise util.Abort(str(inst))
704 raise util.Abort(str(inst))
705
705
706 def docopy(ui, repo, pats, opts):
706 def docopy(ui, repo, pats, opts):
707 if not pats:
707 if not pats:
708 raise util.Abort('no source or destination specified')
708 raise util.Abort('no source or destination specified')
709 elif len(pats) == 1:
709 elif len(pats) == 1:
710 raise util.Abort('no destination specified')
710 raise util.Abort('no destination specified')
711 pats = list(pats)
711 pats = list(pats)
712 dest = pats.pop()
712 dest = pats.pop()
713 sources = []
713 sources = []
714
714
715 def okaytocopy(abs, rel, exact):
715 def okaytocopy(abs, rel, exact):
716 reasons = {'?': 'is not managed',
716 reasons = {'?': 'is not managed',
717 'a': 'has been marked for add'}
717 'a': 'has been marked for add'}
718 reason = reasons.get(repo.dirstate.state(abs))
718 reason = reasons.get(repo.dirstate.state(abs))
719 if reason:
719 if reason:
720 if exact: ui.warn('%s: not copying - file %s\n' % (rel, reason))
720 if exact: ui.warn('%s: not copying - file %s\n' % (rel, reason))
721 else:
721 else:
722 return True
722 return True
723
723
724 for src, abs, rel, exact in walk(repo, pats, opts):
724 for src, abs, rel, exact in walk(repo, pats, opts):
725 if okaytocopy(abs, rel, exact):
725 if okaytocopy(abs, rel, exact):
726 sources.append((abs, rel, exact))
726 sources.append((abs, rel, exact))
727 if not sources:
727 if not sources:
728 raise util.Abort('no files to copy')
728 raise util.Abort('no files to copy')
729
729
730 cwd = repo.getcwd()
730 cwd = repo.getcwd()
731 absdest = util.canonpath(repo.root, cwd, dest)
731 absdest = util.canonpath(repo.root, cwd, dest)
732 reldest = util.pathto(cwd, absdest)
732 reldest = util.pathto(cwd, absdest)
733 if os.path.exists(reldest):
733 if os.path.exists(reldest):
734 destisfile = not os.path.isdir(reldest)
734 destisfile = not os.path.isdir(reldest)
735 else:
735 else:
736 destisfile = len(sources) == 1 or repo.dirstate.state(absdest) != '?'
736 destisfile = len(sources) == 1 or repo.dirstate.state(absdest) != '?'
737
737
738 if destisfile:
738 if destisfile:
739 if opts['parents']:
739 if opts['parents']:
740 raise util.Abort('with --parents, destination must be a directory')
740 raise util.Abort('with --parents, destination must be a directory')
741 elif len(sources) > 1:
741 elif len(sources) > 1:
742 raise util.Abort('with multiple sources, destination must be a '
742 raise util.Abort('with multiple sources, destination must be a '
743 'directory')
743 'directory')
744 errs, copied = 0, []
744 errs, copied = 0, []
745 for abs, rel, exact in sources:
745 for abs, rel, exact in sources:
746 if opts['parents']:
746 if opts['parents']:
747 mydest = os.path.join(dest, rel)
747 mydest = os.path.join(dest, rel)
748 elif destisfile:
748 elif destisfile:
749 mydest = reldest
749 mydest = reldest
750 else:
750 else:
751 mydest = os.path.join(dest, os.path.basename(rel))
751 mydest = os.path.join(dest, os.path.basename(rel))
752 myabsdest = util.canonpath(repo.root, cwd, mydest)
752 myabsdest = util.canonpath(repo.root, cwd, mydest)
753 myreldest = util.pathto(cwd, myabsdest)
753 myreldest = util.pathto(cwd, myabsdest)
754 if not opts['force'] and repo.dirstate.state(myabsdest) not in 'a?':
754 if not opts['force'] and repo.dirstate.state(myabsdest) not in 'a?':
755 ui.warn('%s: not overwriting - file already managed\n' % myreldest)
755 ui.warn('%s: not overwriting - file already managed\n' % myreldest)
756 continue
756 continue
757 mydestdir = os.path.dirname(myreldest) or '.'
757 mydestdir = os.path.dirname(myreldest) or '.'
758 if not opts['after']:
758 if not opts['after']:
759 try:
759 try:
760 if opts['parents']: os.makedirs(mydestdir)
760 if opts['parents']: os.makedirs(mydestdir)
761 elif not destisfile: os.mkdir(mydestdir)
761 elif not destisfile: os.mkdir(mydestdir)
762 except OSError, inst:
762 except OSError, inst:
763 if inst.errno != errno.EEXIST: raise
763 if inst.errno != errno.EEXIST: raise
764 if ui.verbose or not exact:
764 if ui.verbose or not exact:
765 ui.status('copying %s to %s\n' % (rel, myreldest))
765 ui.status('copying %s to %s\n' % (rel, myreldest))
766 if not opts['after']:
766 if not opts['after']:
767 try:
767 try:
768 shutil.copyfile(rel, myreldest)
768 shutil.copyfile(rel, myreldest)
769 n = repo.manifest.tip()
769 n = repo.manifest.tip()
770 mf = repo.manifest.readflags(n)
770 mf = repo.manifest.readflags(n)
771 util.set_exec(myreldest, util.is_exec(rel, mf[abs]))
771 util.set_exec(myreldest, util.is_exec(rel, mf[abs]))
772 except shutil.Error, inst:
772 except shutil.Error, inst:
773 raise util.Abort(str(inst))
773 raise util.Abort(str(inst))
774 except IOError, inst:
774 except IOError, inst:
775 if inst.errno == errno.ENOENT:
775 if inst.errno == errno.ENOENT:
776 ui.warn('%s: deleted in working copy\n' % rel)
776 ui.warn('%s: deleted in working copy\n' % rel)
777 else:
777 else:
778 ui.warn('%s: cannot copy - %s\n' % (rel, inst.strerror))
778 ui.warn('%s: cannot copy - %s\n' % (rel, inst.strerror))
779 errs += 1
779 errs += 1
780 continue
780 continue
781 repo.copy(abs, myabsdest)
781 repo.copy(abs, myabsdest)
782 copied.append((abs, rel, exact))
782 copied.append((abs, rel, exact))
783 if errs:
783 if errs:
784 ui.warn('(consider using --after)\n')
784 ui.warn('(consider using --after)\n')
785 return errs, copied
785 return errs, copied
786
786
787 def copy(ui, repo, *pats, **opts):
787 def copy(ui, repo, *pats, **opts):
788 """mark files as copied for the next commit"""
788 """mark files as copied for the next commit"""
789 errs, copied = docopy(ui, repo, pats, opts)
789 errs, copied = docopy(ui, repo, pats, opts)
790 return errs
790 return errs
791
791
792 def debugancestor(ui, index, rev1, rev2):
792 def debugancestor(ui, index, rev1, rev2):
793 """find the ancestor revision of two revisions in a given index"""
793 """find the ancestor revision of two revisions in a given index"""
794 r = revlog.revlog(file, index, "")
794 r = revlog.revlog(file, index, "")
795 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
795 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
796 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
796 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
797
797
798 def debugcheckstate(ui, repo):
798 def debugcheckstate(ui, repo):
799 """validate the correctness of the current dirstate"""
799 """validate the correctness of the current dirstate"""
800 parent1, parent2 = repo.dirstate.parents()
800 parent1, parent2 = repo.dirstate.parents()
801 repo.dirstate.read()
801 repo.dirstate.read()
802 dc = repo.dirstate.map
802 dc = repo.dirstate.map
803 keys = dc.keys()
803 keys = dc.keys()
804 keys.sort()
804 keys.sort()
805 m1n = repo.changelog.read(parent1)[0]
805 m1n = repo.changelog.read(parent1)[0]
806 m2n = repo.changelog.read(parent2)[0]
806 m2n = repo.changelog.read(parent2)[0]
807 m1 = repo.manifest.read(m1n)
807 m1 = repo.manifest.read(m1n)
808 m2 = repo.manifest.read(m2n)
808 m2 = repo.manifest.read(m2n)
809 errors = 0
809 errors = 0
810 for f in dc:
810 for f in dc:
811 state = repo.dirstate.state(f)
811 state = repo.dirstate.state(f)
812 if state in "nr" and f not in m1:
812 if state in "nr" and f not in m1:
813 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
813 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
814 errors += 1
814 errors += 1
815 if state in "a" and f in m1:
815 if state in "a" and f in m1:
816 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
816 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
817 errors += 1
817 errors += 1
818 if state in "m" and f not in m1 and f not in m2:
818 if state in "m" and f not in m1 and f not in m2:
819 ui.warn("%s in state %s, but not in either manifest\n" %
819 ui.warn("%s in state %s, but not in either manifest\n" %
820 (f, state))
820 (f, state))
821 errors += 1
821 errors += 1
822 for f in m1:
822 for f in m1:
823 state = repo.dirstate.state(f)
823 state = repo.dirstate.state(f)
824 if state not in "nrm":
824 if state not in "nrm":
825 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
825 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
826 errors += 1
826 errors += 1
827 if errors:
827 if errors:
828 raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
828 raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
829
829
830 def debugconfig(ui):
830 def debugconfig(ui):
831 """show combined config settings from all hgrc files"""
831 """show combined config settings from all hgrc files"""
832 try:
832 try:
833 repo = hg.repository(ui)
833 repo = hg.repository(ui)
834 except hg.RepoError:
834 except hg.RepoError:
835 pass
835 pass
836 for section, name, value in ui.walkconfig():
836 for section, name, value in ui.walkconfig():
837 ui.write('%s.%s=%s\n' % (section, name, value))
837 ui.write('%s.%s=%s\n' % (section, name, value))
838
838
839 def debugstate(ui, repo):
839 def debugstate(ui, repo):
840 """show the contents of the current dirstate"""
840 """show the contents of the current dirstate"""
841 repo.dirstate.read()
841 repo.dirstate.read()
842 dc = repo.dirstate.map
842 dc = repo.dirstate.map
843 keys = dc.keys()
843 keys = dc.keys()
844 keys.sort()
844 keys.sort()
845 for file_ in keys:
845 for file_ in keys:
846 ui.write("%c %3o %10d %s %s\n"
846 ui.write("%c %3o %10d %s %s\n"
847 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
847 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
848 time.strftime("%x %X",
848 time.strftime("%x %X",
849 time.localtime(dc[file_][3])), file_))
849 time.localtime(dc[file_][3])), file_))
850 for f in repo.dirstate.copies:
850 for f in repo.dirstate.copies:
851 ui.write("copy: %s -> %s\n" % (repo.dirstate.copies[f], f))
851 ui.write("copy: %s -> %s\n" % (repo.dirstate.copies[f], f))
852
852
853 def debugdata(ui, file_, rev):
853 def debugdata(ui, file_, rev):
854 """dump the contents of an data file revision"""
854 """dump the contents of an data file revision"""
855 r = revlog.revlog(file, file_[:-2] + ".i", file_)
855 r = revlog.revlog(file, file_[:-2] + ".i", file_)
856 ui.write(r.revision(r.lookup(rev)))
856 ui.write(r.revision(r.lookup(rev)))
857
857
858 def debugindex(ui, file_):
858 def debugindex(ui, file_):
859 """dump the contents of an index file"""
859 """dump the contents of an index file"""
860 r = revlog.revlog(file, file_, "")
860 r = revlog.revlog(file, file_, "")
861 ui.write(" rev offset length base linkrev" +
861 ui.write(" rev offset length base linkrev" +
862 " nodeid p1 p2\n")
862 " nodeid p1 p2\n")
863 for i in range(r.count()):
863 for i in range(r.count()):
864 e = r.index[i]
864 e = r.index[i]
865 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
865 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
866 i, e[0], e[1], e[2], e[3],
866 i, e[0], e[1], e[2], e[3],
867 short(e[6]), short(e[4]), short(e[5])))
867 short(e[6]), short(e[4]), short(e[5])))
868
868
869 def debugindexdot(ui, file_):
869 def debugindexdot(ui, file_):
870 """dump an index DAG as a .dot file"""
870 """dump an index DAG as a .dot file"""
871 r = revlog.revlog(file, file_, "")
871 r = revlog.revlog(file, file_, "")
872 ui.write("digraph G {\n")
872 ui.write("digraph G {\n")
873 for i in range(r.count()):
873 for i in range(r.count()):
874 e = r.index[i]
874 e = r.index[i]
875 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
875 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
876 if e[5] != nullid:
876 if e[5] != nullid:
877 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
877 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
878 ui.write("}\n")
878 ui.write("}\n")
879
879
880 def debugrename(ui, repo, file, rev=None):
880 def debugrename(ui, repo, file, rev=None):
881 """dump rename information"""
881 """dump rename information"""
882 r = repo.file(relpath(repo, [file])[0])
882 r = repo.file(relpath(repo, [file])[0])
883 if rev:
883 if rev:
884 try:
884 try:
885 # assume all revision numbers are for changesets
885 # assume all revision numbers are for changesets
886 n = repo.lookup(rev)
886 n = repo.lookup(rev)
887 change = repo.changelog.read(n)
887 change = repo.changelog.read(n)
888 m = repo.manifest.read(change[0])
888 m = repo.manifest.read(change[0])
889 n = m[relpath(repo, [file])[0]]
889 n = m[relpath(repo, [file])[0]]
890 except hg.RepoError, KeyError:
890 except hg.RepoError, KeyError:
891 n = r.lookup(rev)
891 n = r.lookup(rev)
892 else:
892 else:
893 n = r.tip()
893 n = r.tip()
894 m = r.renamed(n)
894 m = r.renamed(n)
895 if m:
895 if m:
896 ui.write("renamed from %s:%s\n" % (m[0], hex(m[1])))
896 ui.write("renamed from %s:%s\n" % (m[0], hex(m[1])))
897 else:
897 else:
898 ui.write("not renamed\n")
898 ui.write("not renamed\n")
899
899
900 def debugwalk(ui, repo, *pats, **opts):
900 def debugwalk(ui, repo, *pats, **opts):
901 """show how files match on given patterns"""
901 """show how files match on given patterns"""
902 items = list(walk(repo, pats, opts))
902 items = list(walk(repo, pats, opts))
903 if not items:
903 if not items:
904 return
904 return
905 fmt = '%%s %%-%ds %%-%ds %%s\n' % (
905 fmt = '%%s %%-%ds %%-%ds %%s\n' % (
906 max([len(abs) for (src, abs, rel, exact) in items]),
906 max([len(abs) for (src, abs, rel, exact) in items]),
907 max([len(rel) for (src, abs, rel, exact) in items]))
907 max([len(rel) for (src, abs, rel, exact) in items]))
908 for src, abs, rel, exact in items:
908 for src, abs, rel, exact in items:
909 ui.write(fmt % (src, abs, rel, exact and 'exact' or ''))
909 ui.write(fmt % (src, abs, rel, exact and 'exact' or ''))
910
910
911 def diff(ui, repo, *pats, **opts):
911 def diff(ui, repo, *pats, **opts):
912 """diff working directory (or selected files)"""
912 """diff working directory (or selected files)"""
913 node1, node2 = None, None
913 node1, node2 = None, None
914 revs = [repo.lookup(x) for x in opts['rev']]
914 revs = [repo.lookup(x) for x in opts['rev']]
915
915
916 if len(revs) > 0:
916 if len(revs) > 0:
917 node1 = revs[0]
917 node1 = revs[0]
918 if len(revs) > 1:
918 if len(revs) > 1:
919 node2 = revs[1]
919 node2 = revs[1]
920 if len(revs) > 2:
920 if len(revs) > 2:
921 raise util.Abort("too many revisions to diff")
921 raise util.Abort("too many revisions to diff")
922
922
923 fns, matchfn, anypats = matchpats(repo, repo.getcwd(), pats, opts)
923 fns, matchfn, anypats = matchpats(repo, repo.getcwd(), pats, opts)
924
924
925 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
925 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
926 text=opts['text'])
926 text=opts['text'])
927
927
928 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
928 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
929 node = repo.lookup(changeset)
929 node = repo.lookup(changeset)
930 prev, other = repo.changelog.parents(node)
930 prev, other = repo.changelog.parents(node)
931 change = repo.changelog.read(node)
931 change = repo.changelog.read(node)
932
932
933 fp = make_file(repo, repo.changelog, opts['output'],
933 fp = make_file(repo, repo.changelog, opts['output'],
934 node=node, total=total, seqno=seqno,
934 node=node, total=total, seqno=seqno,
935 revwidth=revwidth)
935 revwidth=revwidth)
936 if fp != sys.stdout:
936 if fp != sys.stdout:
937 ui.note("%s\n" % fp.name)
937 ui.note("%s\n" % fp.name)
938
938
939 fp.write("# HG changeset patch\n")
939 fp.write("# HG changeset patch\n")
940 fp.write("# User %s\n" % change[1])
940 fp.write("# User %s\n" % change[1])
941 fp.write("# Node ID %s\n" % hex(node))
941 fp.write("# Node ID %s\n" % hex(node))
942 fp.write("# Parent %s\n" % hex(prev))
942 fp.write("# Parent %s\n" % hex(prev))
943 if other != nullid:
943 if other != nullid:
944 fp.write("# Parent %s\n" % hex(other))
944 fp.write("# Parent %s\n" % hex(other))
945 fp.write(change[4].rstrip())
945 fp.write(change[4].rstrip())
946 fp.write("\n\n")
946 fp.write("\n\n")
947
947
948 dodiff(fp, ui, repo, prev, node, text=opts['text'])
948 dodiff(fp, ui, repo, prev, node, text=opts['text'])
949 if fp != sys.stdout:
949 if fp != sys.stdout:
950 fp.close()
950 fp.close()
951
951
952 def export(ui, repo, *changesets, **opts):
952 def export(ui, repo, *changesets, **opts):
953 """dump the header and diffs for one or more changesets"""
953 """dump the header and diffs for one or more changesets"""
954 if not changesets:
954 if not changesets:
955 raise util.Abort("export requires at least one changeset")
955 raise util.Abort("export requires at least one changeset")
956 seqno = 0
956 seqno = 0
957 revs = list(revrange(ui, repo, changesets))
957 revs = list(revrange(ui, repo, changesets))
958 total = len(revs)
958 total = len(revs)
959 revwidth = max(map(len, revs))
959 revwidth = max(map(len, revs))
960 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
960 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
961 for cset in revs:
961 for cset in revs:
962 seqno += 1
962 seqno += 1
963 doexport(ui, repo, cset, seqno, total, revwidth, opts)
963 doexport(ui, repo, cset, seqno, total, revwidth, opts)
964
964
965 def forget(ui, repo, *pats, **opts):
965 def forget(ui, repo, *pats, **opts):
966 """don't add the specified files on the next commit"""
966 """don't add the specified files on the next commit"""
967 forget = []
967 forget = []
968 for src, abs, rel, exact in walk(repo, pats, opts):
968 for src, abs, rel, exact in walk(repo, pats, opts):
969 if repo.dirstate.state(abs) == 'a':
969 if repo.dirstate.state(abs) == 'a':
970 forget.append(abs)
970 forget.append(abs)
971 if ui.verbose or not exact:
971 if ui.verbose or not exact:
972 ui.status('forgetting ', rel, '\n')
972 ui.status('forgetting ', rel, '\n')
973 repo.forget(forget)
973 repo.forget(forget)
974
974
975 def grep(ui, repo, pattern, *pats, **opts):
975 def grep(ui, repo, pattern, *pats, **opts):
976 """search for a pattern in specified files and revisions"""
976 """search for a pattern in specified files and revisions"""
977 reflags = 0
977 reflags = 0
978 if opts['ignore_case']:
978 if opts['ignore_case']:
979 reflags |= re.I
979 reflags |= re.I
980 regexp = re.compile(pattern, reflags)
980 regexp = re.compile(pattern, reflags)
981 sep, eol = ':', '\n'
981 sep, eol = ':', '\n'
982 if opts['print0']:
982 if opts['print0']:
983 sep = eol = '\0'
983 sep = eol = '\0'
984
984
985 fcache = {}
985 fcache = {}
986 def getfile(fn):
986 def getfile(fn):
987 if fn not in fcache:
987 if fn not in fcache:
988 fcache[fn] = repo.file(fn)
988 fcache[fn] = repo.file(fn)
989 return fcache[fn]
989 return fcache[fn]
990
990
991 def matchlines(body):
991 def matchlines(body):
992 begin = 0
992 begin = 0
993 linenum = 0
993 linenum = 0
994 while True:
994 while True:
995 match = regexp.search(body, begin)
995 match = regexp.search(body, begin)
996 if not match:
996 if not match:
997 break
997 break
998 mstart, mend = match.span()
998 mstart, mend = match.span()
999 linenum += body.count('\n', begin, mstart) + 1
999 linenum += body.count('\n', begin, mstart) + 1
1000 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1000 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1001 lend = body.find('\n', mend)
1001 lend = body.find('\n', mend)
1002 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1002 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1003 begin = lend + 1
1003 begin = lend + 1
1004
1004
1005 class linestate:
1005 class linestate:
1006 def __init__(self, line, linenum, colstart, colend):
1006 def __init__(self, line, linenum, colstart, colend):
1007 self.line = line
1007 self.line = line
1008 self.linenum = linenum
1008 self.linenum = linenum
1009 self.colstart = colstart
1009 self.colstart = colstart
1010 self.colend = colend
1010 self.colend = colend
1011 def __eq__(self, other):
1011 def __eq__(self, other):
1012 return self.line == other.line
1012 return self.line == other.line
1013 def __hash__(self):
1013 def __hash__(self):
1014 return hash(self.line)
1014 return hash(self.line)
1015
1015
1016 matches = {}
1016 matches = {}
1017 def grepbody(fn, rev, body):
1017 def grepbody(fn, rev, body):
1018 matches[rev].setdefault(fn, {})
1018 matches[rev].setdefault(fn, {})
1019 m = matches[rev][fn]
1019 m = matches[rev][fn]
1020 for lnum, cstart, cend, line in matchlines(body):
1020 for lnum, cstart, cend, line in matchlines(body):
1021 s = linestate(line, lnum, cstart, cend)
1021 s = linestate(line, lnum, cstart, cend)
1022 m[s] = s
1022 m[s] = s
1023
1023
1024 prev = {}
1024 prev = {}
1025 ucache = {}
1025 ucache = {}
1026 def display(fn, rev, states, prevstates):
1026 def display(fn, rev, states, prevstates):
1027 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1027 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1028 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1028 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1029 counts = {'-': 0, '+': 0}
1029 counts = {'-': 0, '+': 0}
1030 filerevmatches = {}
1030 filerevmatches = {}
1031 for l in diff:
1031 for l in diff:
1032 if incrementing or not opts['all']:
1032 if incrementing or not opts['all']:
1033 change = ((l in prevstates) and '-') or '+'
1033 change = ((l in prevstates) and '-') or '+'
1034 r = rev
1034 r = rev
1035 else:
1035 else:
1036 change = ((l in states) and '-') or '+'
1036 change = ((l in states) and '-') or '+'
1037 r = prev[fn]
1037 r = prev[fn]
1038 cols = [fn, str(rev)]
1038 cols = [fn, str(rev)]
1039 if opts['line_number']: cols.append(str(l.linenum))
1039 if opts['line_number']: cols.append(str(l.linenum))
1040 if opts['all']: cols.append(change)
1040 if opts['all']: cols.append(change)
1041 if opts['user']: cols.append(trimuser(ui, getchange(rev)[1], rev,
1041 if opts['user']: cols.append(trimuser(ui, getchange(rev)[1], rev,
1042 ucache))
1042 ucache))
1043 if opts['files_with_matches']:
1043 if opts['files_with_matches']:
1044 c = (fn, rev)
1044 c = (fn, rev)
1045 if c in filerevmatches: continue
1045 if c in filerevmatches: continue
1046 filerevmatches[c] = 1
1046 filerevmatches[c] = 1
1047 else:
1047 else:
1048 cols.append(l.line)
1048 cols.append(l.line)
1049 ui.write(sep.join(cols), eol)
1049 ui.write(sep.join(cols), eol)
1050 counts[change] += 1
1050 counts[change] += 1
1051 return counts['+'], counts['-']
1051 return counts['+'], counts['-']
1052
1052
1053 fstate = {}
1053 fstate = {}
1054 skip = {}
1054 skip = {}
1055 changeiter, getchange = walkchangerevs(ui, repo, repo.getcwd(), pats, opts)
1055 changeiter, getchange = walkchangerevs(ui, repo, repo.getcwd(), pats, opts)
1056 count = 0
1056 count = 0
1057 for st, rev, fns in changeiter:
1057 for st, rev, fns in changeiter:
1058 if st == 'window':
1058 if st == 'window':
1059 incrementing = rev
1059 incrementing = rev
1060 matches.clear()
1060 matches.clear()
1061 elif st == 'add':
1061 elif st == 'add':
1062 change = repo.changelog.read(repo.lookup(str(rev)))
1062 change = repo.changelog.read(repo.lookup(str(rev)))
1063 mf = repo.manifest.read(change[0])
1063 mf = repo.manifest.read(change[0])
1064 matches[rev] = {}
1064 matches[rev] = {}
1065 for fn in fns:
1065 for fn in fns:
1066 if fn in skip: continue
1066 if fn in skip: continue
1067 fstate.setdefault(fn, {})
1067 fstate.setdefault(fn, {})
1068 try:
1068 try:
1069 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1069 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1070 except KeyError:
1070 except KeyError:
1071 pass
1071 pass
1072 elif st == 'iter':
1072 elif st == 'iter':
1073 states = matches[rev].items()
1073 states = matches[rev].items()
1074 states.sort()
1074 states.sort()
1075 for fn, m in states:
1075 for fn, m in states:
1076 if fn in skip: continue
1076 if fn in skip: continue
1077 if incrementing or not opts['all'] or fstate[fn]:
1077 if incrementing or not opts['all'] or fstate[fn]:
1078 pos, neg = display(fn, rev, m, fstate[fn])
1078 pos, neg = display(fn, rev, m, fstate[fn])
1079 count += pos + neg
1079 count += pos + neg
1080 if pos and not opts['all']:
1080 if pos and not opts['all']:
1081 skip[fn] = True
1081 skip[fn] = True
1082 fstate[fn] = m
1082 fstate[fn] = m
1083 prev[fn] = rev
1083 prev[fn] = rev
1084
1084
1085 if not incrementing:
1085 if not incrementing:
1086 fstate = fstate.items()
1086 fstate = fstate.items()
1087 fstate.sort()
1087 fstate.sort()
1088 for fn, state in fstate:
1088 for fn, state in fstate:
1089 if fn in skip: continue
1089 if fn in skip: continue
1090 display(fn, rev, {}, state)
1090 display(fn, rev, {}, state)
1091 return (count == 0 and 1) or 0
1091 return (count == 0 and 1) or 0
1092
1092
1093 def heads(ui, repo, **opts):
1093 def heads(ui, repo, **opts):
1094 """show current repository heads"""
1094 """show current repository heads"""
1095 heads = repo.changelog.heads()
1095 heads = repo.changelog.heads()
1096 br = None
1096 br = None
1097 if opts['branches']:
1097 if opts['branches']:
1098 br = repo.branchlookup(heads)
1098 br = repo.branchlookup(heads)
1099 for n in repo.changelog.heads():
1099 for n in repo.changelog.heads():
1100 show_changeset(ui, repo, changenode=n, brinfo=br)
1100 show_changeset(ui, repo, changenode=n, brinfo=br)
1101
1101
1102 def identify(ui, repo):
1102 def identify(ui, repo):
1103 """print information about the working copy"""
1103 """print information about the working copy"""
1104 parents = [p for p in repo.dirstate.parents() if p != nullid]
1104 parents = [p for p in repo.dirstate.parents() if p != nullid]
1105 if not parents:
1105 if not parents:
1106 ui.write("unknown\n")
1106 ui.write("unknown\n")
1107 return
1107 return
1108
1108
1109 hexfunc = ui.verbose and hex or short
1109 hexfunc = ui.verbose and hex or short
1110 (c, a, d, u) = repo.changes()
1110 (c, a, d, u) = repo.changes()
1111 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
1111 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
1112 (c or a or d) and "+" or "")]
1112 (c or a or d) and "+" or "")]
1113
1113
1114 if not ui.quiet:
1114 if not ui.quiet:
1115 # multiple tags for a single parent separated by '/'
1115 # multiple tags for a single parent separated by '/'
1116 parenttags = ['/'.join(tags)
1116 parenttags = ['/'.join(tags)
1117 for tags in map(repo.nodetags, parents) if tags]
1117 for tags in map(repo.nodetags, parents) if tags]
1118 # tags for multiple parents separated by ' + '
1118 # tags for multiple parents separated by ' + '
1119 if parenttags:
1119 if parenttags:
1120 output.append(' + '.join(parenttags))
1120 output.append(' + '.join(parenttags))
1121
1121
1122 ui.write("%s\n" % ' '.join(output))
1122 ui.write("%s\n" % ' '.join(output))
1123
1123
1124 def import_(ui, repo, patch1, *patches, **opts):
1124 def import_(ui, repo, patch1, *patches, **opts):
1125 """import an ordered set of patches"""
1125 """import an ordered set of patches"""
1126 patches = (patch1,) + patches
1126 patches = (patch1,) + patches
1127
1127
1128 if not opts['force']:
1128 if not opts['force']:
1129 (c, a, d, u) = repo.changes()
1129 (c, a, d, u) = repo.changes()
1130 if c or a or d:
1130 if c or a or d:
1131 raise util.Abort("outstanding uncommitted changes")
1131 raise util.Abort("outstanding uncommitted changes")
1132
1132
1133 d = opts["base"]
1133 d = opts["base"]
1134 strip = opts["strip"]
1134 strip = opts["strip"]
1135
1135
1136 mailre = re.compile(r'(?:From |[\w-]+:)')
1136 mailre = re.compile(r'(?:From |[\w-]+:)')
1137 diffre = re.compile(r'(?:diff -|--- .*\s+\w+ \w+ +\d+ \d+:\d+:\d+ \d+)')
1137 diffre = re.compile(r'(?:diff -|--- .*\s+\w+ \w+ +\d+ \d+:\d+:\d+ \d+)')
1138
1138
1139 for patch in patches:
1139 for patch in patches:
1140 ui.status("applying %s\n" % patch)
1140 ui.status("applying %s\n" % patch)
1141 pf = os.path.join(d, patch)
1141 pf = os.path.join(d, patch)
1142
1142
1143 message = []
1143 message = []
1144 user = None
1144 user = None
1145 hgpatch = False
1145 hgpatch = False
1146 for line in file(pf):
1146 for line in file(pf):
1147 line = line.rstrip()
1147 line = line.rstrip()
1148 if (not message and not hgpatch and
1148 if (not message and not hgpatch and
1149 mailre.match(line) and not opts['force']):
1149 mailre.match(line) and not opts['force']):
1150 if len(line) > 35: line = line[:32] + '...'
1150 if len(line) > 35: line = line[:32] + '...'
1151 raise util.Abort('first line looks like a '
1151 raise util.Abort('first line looks like a '
1152 'mail header: ' + line)
1152 'mail header: ' + line)
1153 if diffre.match(line):
1153 if diffre.match(line):
1154 break
1154 break
1155 elif hgpatch:
1155 elif hgpatch:
1156 # parse values when importing the result of an hg export
1156 # parse values when importing the result of an hg export
1157 if line.startswith("# User "):
1157 if line.startswith("# User "):
1158 user = line[7:]
1158 user = line[7:]
1159 ui.debug('User: %s\n' % user)
1159 ui.debug('User: %s\n' % user)
1160 elif not line.startswith("# ") and line:
1160 elif not line.startswith("# ") and line:
1161 message.append(line)
1161 message.append(line)
1162 hgpatch = False
1162 hgpatch = False
1163 elif line == '# HG changeset patch':
1163 elif line == '# HG changeset patch':
1164 hgpatch = True
1164 hgpatch = True
1165 message = [] # We may have collected garbage
1165 message = [] # We may have collected garbage
1166 else:
1166 else:
1167 message.append(line)
1167 message.append(line)
1168
1168
1169 # make sure message isn't empty
1169 # make sure message isn't empty
1170 if not message:
1170 if not message:
1171 message = "imported patch %s\n" % patch
1171 message = "imported patch %s\n" % patch
1172 else:
1172 else:
1173 message = "%s\n" % '\n'.join(message)
1173 message = "%s\n" % '\n'.join(message)
1174 ui.debug('message:\n%s\n' % message)
1174 ui.debug('message:\n%s\n' % message)
1175
1175
1176 f = os.popen("patch -p%d < '%s'" % (strip, pf))
1176 f = os.popen("patch -p%d < '%s'" % (strip, pf))
1177 files = []
1177 files = []
1178 for l in f.read().splitlines():
1178 for l in f.read().splitlines():
1179 l.rstrip('\r\n');
1179 l.rstrip('\r\n');
1180 ui.status("%s\n" % l)
1180 ui.status("%s\n" % l)
1181 if l.startswith('patching file '):
1181 if l.startswith('patching file '):
1182 pf = l[14:]
1182 pf = l[14:]
1183 if pf not in files:
1183 if pf not in files:
1184 files.append(pf)
1184 files.append(pf)
1185 patcherr = f.close()
1185 patcherr = f.close()
1186 if patcherr:
1186 if patcherr:
1187 raise util.Abort("patch failed")
1187 raise util.Abort("patch failed")
1188
1188
1189 if len(files) > 0:
1189 if len(files) > 0:
1190 addremove(ui, repo, *files)
1190 addremove(ui, repo, *files)
1191 repo.commit(files, message, user)
1191 repo.commit(files, message, user)
1192
1192
1193 def incoming(ui, repo, source="default", **opts):
1193 def incoming(ui, repo, source="default", **opts):
1194 """show new changesets found in source"""
1194 """show new changesets found in source"""
1195 source = ui.expandpath(source)
1195 source = ui.expandpath(source)
1196 other = hg.repository(ui, source)
1196 other = hg.repository(ui, source)
1197 if not other.local():
1197 if not other.local():
1198 raise util.Abort("incoming doesn't work for remote repositories yet")
1198 raise util.Abort("incoming doesn't work for remote repositories yet")
1199 o = repo.findincoming(other)
1199 o = repo.findincoming(other)
1200 if not o:
1200 if not o:
1201 return
1201 return
1202 o = other.newer(o)
1202 o = other.newer(o)
1203 o.reverse()
1203 o.reverse()
1204 for n in o:
1204 for n in o:
1205 show_changeset(ui, other, changenode=n)
1205 show_changeset(ui, other, changenode=n)
1206 if opts['patch']:
1206 if opts['patch']:
1207 prev = other.changelog.parents(n)[0]
1207 prev = other.changelog.parents(n)[0]
1208 dodiff(ui, ui, other, prev, n)
1208 dodiff(ui, ui, other, prev, n)
1209 ui.write("\n")
1209 ui.write("\n")
1210
1210
1211 def init(ui, dest="."):
1211 def init(ui, dest="."):
1212 """create a new repository in the given directory"""
1212 """create a new repository in the given directory"""
1213 if not os.path.exists(dest):
1213 if not os.path.exists(dest):
1214 os.mkdir(dest)
1214 os.mkdir(dest)
1215 hg.repository(ui, dest, create=1)
1215 hg.repository(ui, dest, create=1)
1216
1216
1217 def locate(ui, repo, *pats, **opts):
1217 def locate(ui, repo, *pats, **opts):
1218 """locate files matching specific patterns"""
1218 """locate files matching specific patterns"""
1219 end = opts['print0'] and '\0' or '\n'
1219 end = opts['print0'] and '\0' or '\n'
1220
1220
1221 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1221 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1222 if repo.dirstate.state(abs) == '?':
1222 if repo.dirstate.state(abs) == '?':
1223 continue
1223 continue
1224 if opts['fullpath']:
1224 if opts['fullpath']:
1225 ui.write(os.path.join(repo.root, abs), end)
1225 ui.write(os.path.join(repo.root, abs), end)
1226 else:
1226 else:
1227 ui.write(rel, end)
1227 ui.write(rel, end)
1228
1228
1229 def log(ui, repo, *pats, **opts):
1229 def log(ui, repo, *pats, **opts):
1230 """show revision history of entire repository or files"""
1230 """show revision history of entire repository or files"""
1231 class dui:
1231 class dui:
1232 # Implement and delegate some ui protocol. Save hunks of
1232 # Implement and delegate some ui protocol. Save hunks of
1233 # output for later display in the desired order.
1233 # output for later display in the desired order.
1234 def __init__(self, ui):
1234 def __init__(self, ui):
1235 self.ui = ui
1235 self.ui = ui
1236 self.hunk = {}
1236 self.hunk = {}
1237 def bump(self, rev):
1237 def bump(self, rev):
1238 self.rev = rev
1238 self.rev = rev
1239 self.hunk[rev] = []
1239 self.hunk[rev] = []
1240 def note(self, *args):
1240 def note(self, *args):
1241 if self.verbose:
1241 if self.verbose:
1242 self.write(*args)
1242 self.write(*args)
1243 def status(self, *args):
1243 def status(self, *args):
1244 if not self.quiet:
1244 if not self.quiet:
1245 self.write(*args)
1245 self.write(*args)
1246 def write(self, *args):
1246 def write(self, *args):
1247 self.hunk[self.rev].append(args)
1247 self.hunk[self.rev].append(args)
1248 def __getattr__(self, key):
1248 def __getattr__(self, key):
1249 return getattr(self.ui, key)
1249 return getattr(self.ui, key)
1250 cwd = repo.getcwd()
1250 cwd = repo.getcwd()
1251 if not pats and cwd:
1251 if not pats and cwd:
1252 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1252 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1253 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1253 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1254 changeiter, getchange = walkchangerevs(ui, repo, (pats and cwd) or '',
1254 changeiter, getchange = walkchangerevs(ui, repo, (pats and cwd) or '',
1255 pats, opts)
1255 pats, opts)
1256 for st, rev, fns in changeiter:
1256 for st, rev, fns in changeiter:
1257 if st == 'window':
1257 if st == 'window':
1258 du = dui(ui)
1258 du = dui(ui)
1259 elif st == 'add':
1259 elif st == 'add':
1260 du.bump(rev)
1260 du.bump(rev)
1261 br = None
1261 br = None
1262 if opts['branch']:
1262 if opts['branch']:
1263 br = repo.branchlookup([repo.changelog.node(rev)])
1263 br = repo.branchlookup([repo.changelog.node(rev)])
1264 show_changeset(du, repo, rev, brinfo=br)
1264 show_changeset(du, repo, rev, brinfo=br)
1265 if opts['patch']:
1265 if opts['patch']:
1266 changenode = repo.changelog.node(rev)
1266 changenode = repo.changelog.node(rev)
1267 prev, other = repo.changelog.parents(changenode)
1267 prev, other = repo.changelog.parents(changenode)
1268 dodiff(du, du, repo, prev, changenode, fns)
1268 dodiff(du, du, repo, prev, changenode, fns)
1269 du.write("\n\n")
1269 du.write("\n\n")
1270 elif st == 'iter':
1270 elif st == 'iter':
1271 for args in du.hunk[rev]:
1271 for args in du.hunk[rev]:
1272 ui.write(*args)
1272 ui.write(*args)
1273
1273
1274 def manifest(ui, repo, rev=None):
1274 def manifest(ui, repo, rev=None):
1275 """output the latest or given revision of the project manifest"""
1275 """output the latest or given revision of the project manifest"""
1276 if rev:
1276 if rev:
1277 try:
1277 try:
1278 # assume all revision numbers are for changesets
1278 # assume all revision numbers are for changesets
1279 n = repo.lookup(rev)
1279 n = repo.lookup(rev)
1280 change = repo.changelog.read(n)
1280 change = repo.changelog.read(n)
1281 n = change[0]
1281 n = change[0]
1282 except hg.RepoError:
1282 except hg.RepoError:
1283 n = repo.manifest.lookup(rev)
1283 n = repo.manifest.lookup(rev)
1284 else:
1284 else:
1285 n = repo.manifest.tip()
1285 n = repo.manifest.tip()
1286 m = repo.manifest.read(n)
1286 m = repo.manifest.read(n)
1287 mf = repo.manifest.readflags(n)
1287 mf = repo.manifest.readflags(n)
1288 files = m.keys()
1288 files = m.keys()
1289 files.sort()
1289 files.sort()
1290
1290
1291 for f in files:
1291 for f in files:
1292 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1292 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1293
1293
1294 def outgoing(ui, repo, dest="default-push", **opts):
1294 def outgoing(ui, repo, dest="default-push", **opts):
1295 """show changesets not found in destination"""
1295 """show changesets not found in destination"""
1296 dest = ui.expandpath(dest)
1296 dest = ui.expandpath(dest)
1297 other = hg.repository(ui, dest)
1297 other = hg.repository(ui, dest)
1298 o = repo.findoutgoing(other)
1298 o = repo.findoutgoing(other)
1299 o = repo.newer(o)
1299 o = repo.newer(o)
1300 o.reverse()
1300 o.reverse()
1301 for n in o:
1301 for n in o:
1302 show_changeset(ui, repo, changenode=n)
1302 show_changeset(ui, repo, changenode=n)
1303 if opts['patch']:
1303 if opts['patch']:
1304 prev = repo.changelog.parents(n)[0]
1304 prev = repo.changelog.parents(n)[0]
1305 dodiff(ui, ui, repo, prev, n)
1305 dodiff(ui, ui, repo, prev, n)
1306 ui.write("\n")
1306 ui.write("\n")
1307
1307
1308 def parents(ui, repo, rev=None):
1308 def parents(ui, repo, rev=None):
1309 """show the parents of the working dir or revision"""
1309 """show the parents of the working dir or revision"""
1310 if rev:
1310 if rev:
1311 p = repo.changelog.parents(repo.lookup(rev))
1311 p = repo.changelog.parents(repo.lookup(rev))
1312 else:
1312 else:
1313 p = repo.dirstate.parents()
1313 p = repo.dirstate.parents()
1314
1314
1315 for n in p:
1315 for n in p:
1316 if n != nullid:
1316 if n != nullid:
1317 show_changeset(ui, repo, changenode=n)
1317 show_changeset(ui, repo, changenode=n)
1318
1318
1319 def paths(ui, search=None):
1319 def paths(ui, search=None):
1320 """show definition of symbolic path names"""
1320 """show definition of symbolic path names"""
1321 try:
1321 try:
1322 repo = hg.repository(ui=ui)
1322 repo = hg.repository(ui=ui)
1323 except hg.RepoError:
1323 except hg.RepoError:
1324 pass
1324 pass
1325
1325
1326 if search:
1326 if search:
1327 for name, path in ui.configitems("paths"):
1327 for name, path in ui.configitems("paths"):
1328 if name == search:
1328 if name == search:
1329 ui.write("%s\n" % path)
1329 ui.write("%s\n" % path)
1330 return
1330 return
1331 ui.warn("not found!\n")
1331 ui.warn("not found!\n")
1332 return 1
1332 return 1
1333 else:
1333 else:
1334 for name, path in ui.configitems("paths"):
1334 for name, path in ui.configitems("paths"):
1335 ui.write("%s = %s\n" % (name, path))
1335 ui.write("%s = %s\n" % (name, path))
1336
1336
1337 def pull(ui, repo, source="default", **opts):
1337 def pull(ui, repo, source="default", **opts):
1338 """pull changes from the specified source"""
1338 """pull changes from the specified source"""
1339 source = ui.expandpath(source)
1339 source = ui.expandpath(source)
1340 ui.status('pulling from %s\n' % (source))
1340 ui.status('pulling from %s\n' % (source))
1341
1341
1342 if opts['ssh']:
1342 if opts['ssh']:
1343 ui.setconfig("ui", "ssh", opts['ssh'])
1343 ui.setconfig("ui", "ssh", opts['ssh'])
1344 if opts['remotecmd']:
1344 if opts['remotecmd']:
1345 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1345 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1346
1346
1347 other = hg.repository(ui, source)
1347 other = hg.repository(ui, source)
1348 r = repo.pull(other)
1348 r = repo.pull(other)
1349 if not r:
1349 if not r:
1350 if opts['update']:
1350 if opts['update']:
1351 return update(ui, repo)
1351 return update(ui, repo)
1352 else:
1352 else:
1353 ui.status("(run 'hg update' to get a working copy)\n")
1353 ui.status("(run 'hg update' to get a working copy)\n")
1354
1354
1355 return r
1355 return r
1356
1356
1357 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1357 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1358 """push changes to the specified destination"""
1358 """push changes to the specified destination"""
1359 dest = ui.expandpath(dest)
1359 dest = ui.expandpath(dest)
1360 ui.status('pushing to %s\n' % (dest))
1360 ui.status('pushing to %s\n' % (dest))
1361
1361
1362 if ssh:
1362 if ssh:
1363 ui.setconfig("ui", "ssh", ssh)
1363 ui.setconfig("ui", "ssh", ssh)
1364 if remotecmd:
1364 if remotecmd:
1365 ui.setconfig("ui", "remotecmd", remotecmd)
1365 ui.setconfig("ui", "remotecmd", remotecmd)
1366
1366
1367 other = hg.repository(ui, dest)
1367 other = hg.repository(ui, dest)
1368 r = repo.push(other, force)
1368 r = repo.push(other, force)
1369 return r
1369 return r
1370
1370
1371 def rawcommit(ui, repo, *flist, **rc):
1371 def rawcommit(ui, repo, *flist, **rc):
1372 "raw commit interface"
1372 "raw commit interface"
1373 if rc['text']:
1373 if rc['text']:
1374 ui.warn("Warning: -t and --text is deprecated,"
1374 ui.warn("Warning: -t and --text is deprecated,"
1375 " please use -m or --message instead.\n")
1375 " please use -m or --message instead.\n")
1376 message = rc['message'] or rc['text']
1376 message = rc['message'] or rc['text']
1377 if not message and rc['logfile']:
1377 if not message and rc['logfile']:
1378 try:
1378 try:
1379 message = open(rc['logfile']).read()
1379 message = open(rc['logfile']).read()
1380 except IOError:
1380 except IOError:
1381 pass
1381 pass
1382 if not message and not rc['logfile']:
1382 if not message and not rc['logfile']:
1383 raise util.Abort("missing commit message")
1383 raise util.Abort("missing commit message")
1384
1384
1385 files = relpath(repo, list(flist))
1385 files = relpath(repo, list(flist))
1386 if rc['files']:
1386 if rc['files']:
1387 files += open(rc['files']).read().splitlines()
1387 files += open(rc['files']).read().splitlines()
1388
1388
1389 rc['parent'] = map(repo.lookup, rc['parent'])
1389 rc['parent'] = map(repo.lookup, rc['parent'])
1390
1390
1391 try:
1391 try:
1392 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1392 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1393 except ValueError, inst:
1393 except ValueError, inst:
1394 raise util.Abort(str(inst))
1394 raise util.Abort(str(inst))
1395
1395
1396 def recover(ui, repo):
1396 def recover(ui, repo):
1397 """roll back an interrupted transaction"""
1397 """roll back an interrupted transaction"""
1398 repo.recover()
1398 repo.recover()
1399
1399
1400 def remove(ui, repo, pat, *pats, **opts):
1400 def remove(ui, repo, pat, *pats, **opts):
1401 """remove the specified files on the next commit"""
1401 """remove the specified files on the next commit"""
1402 names = []
1402 names = []
1403 def okaytoremove(abs, rel, exact):
1403 def okaytoremove(abs, rel, exact):
1404 c, a, d, u = repo.changes(files = [abs])
1404 c, a, d, u = repo.changes(files = [abs])
1405 reason = None
1405 reason = None
1406 if c: reason = 'is modified'
1406 if c: reason = 'is modified'
1407 elif a: reason = 'has been marked for add'
1407 elif a: reason = 'has been marked for add'
1408 elif u: reason = 'is not managed'
1408 elif u: reason = 'is not managed'
1409 if reason:
1409 if reason:
1410 if exact: ui.warn('not removing %s: file %s\n' % (rel, reason))
1410 if exact: ui.warn('not removing %s: file %s\n' % (rel, reason))
1411 else:
1411 else:
1412 return True
1412 return True
1413 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
1413 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
1414 if okaytoremove(abs, rel, exact):
1414 if okaytoremove(abs, rel, exact):
1415 if ui.verbose or not exact: ui.status('removing %s\n' % rel)
1415 if ui.verbose or not exact: ui.status('removing %s\n' % rel)
1416 names.append(abs)
1416 names.append(abs)
1417 for name in names:
1417 for name in names:
1418 try:
1418 try:
1419 os.unlink(name)
1419 os.unlink(name)
1420 except OSError, inst:
1420 except OSError, inst:
1421 if inst.errno != errno.ENOENT: raise
1421 if inst.errno != errno.ENOENT: raise
1422 repo.remove(names)
1422 repo.remove(names)
1423
1423
1424 def rename(ui, repo, *pats, **opts):
1424 def rename(ui, repo, *pats, **opts):
1425 """rename files; equivalent of copy + remove"""
1425 """rename files; equivalent of copy + remove"""
1426 errs, copied = docopy(ui, repo, pats, opts)
1426 errs, copied = docopy(ui, repo, pats, opts)
1427 names = []
1427 names = []
1428 for abs, rel, exact in copied:
1428 for abs, rel, exact in copied:
1429 if ui.verbose or not exact: ui.status('removing %s\n' % rel)
1429 if ui.verbose or not exact: ui.status('removing %s\n' % rel)
1430 try:
1430 try:
1431 os.unlink(rel)
1431 os.unlink(rel)
1432 except OSError, inst:
1432 except OSError, inst:
1433 if inst.errno != errno.ENOENT: raise
1433 if inst.errno != errno.ENOENT: raise
1434 names.append(abs)
1434 names.append(abs)
1435 repo.remove(names)
1435 repo.remove(names)
1436 return errs
1436 return errs
1437
1437
1438 def revert(ui, repo, *names, **opts):
1438 def revert(ui, repo, *names, **opts):
1439 """revert modified files or dirs back to their unmodified states"""
1439 """revert modified files or dirs back to their unmodified states"""
1440 node = opts['rev'] and repo.lookup(opts['rev']) or \
1440 node = opts['rev'] and repo.lookup(opts['rev']) or \
1441 repo.dirstate.parents()[0]
1441 repo.dirstate.parents()[0]
1442 root = os.path.realpath(repo.root)
1442 root = os.path.realpath(repo.root)
1443
1443
1444 def trimpath(p):
1444 def trimpath(p):
1445 p = os.path.realpath(p)
1445 p = os.path.realpath(p)
1446 if p.startswith(root):
1446 if p.startswith(root):
1447 rest = p[len(root):]
1447 rest = p[len(root):]
1448 if not rest:
1448 if not rest:
1449 return rest
1449 return rest
1450 if p.startswith(os.sep):
1450 if p.startswith(os.sep):
1451 return rest[1:]
1451 return rest[1:]
1452 return p
1452 return p
1453
1453
1454 relnames = map(trimpath, names or [os.getcwd()])
1454 relnames = map(trimpath, names or [os.getcwd()])
1455 chosen = {}
1455 chosen = {}
1456
1456
1457 def choose(name):
1457 def choose(name):
1458 def body(name):
1458 def body(name):
1459 for r in relnames:
1459 for r in relnames:
1460 if not name.startswith(r):
1460 if not name.startswith(r):
1461 continue
1461 continue
1462 rest = name[len(r):]
1462 rest = name[len(r):]
1463 if not rest:
1463 if not rest:
1464 return r, True
1464 return r, True
1465 depth = rest.count(os.sep)
1465 depth = rest.count(os.sep)
1466 if not r:
1466 if not r:
1467 if depth == 0 or not opts['nonrecursive']:
1467 if depth == 0 or not opts['nonrecursive']:
1468 return r, True
1468 return r, True
1469 elif rest[0] == os.sep:
1469 elif rest[0] == os.sep:
1470 if depth == 1 or not opts['nonrecursive']:
1470 if depth == 1 or not opts['nonrecursive']:
1471 return r, True
1471 return r, True
1472 return None, False
1472 return None, False
1473 relname, ret = body(name)
1473 relname, ret = body(name)
1474 if ret:
1474 if ret:
1475 chosen[relname] = 1
1475 chosen[relname] = 1
1476 return ret
1476 return ret
1477
1477
1478 r = repo.update(node, False, True, choose, False)
1478 r = repo.update(node, False, True, choose, False)
1479 for n in relnames:
1479 for n in relnames:
1480 if n not in chosen:
1480 if n not in chosen:
1481 ui.warn('error: no matches for %s\n' % n)
1481 ui.warn('error: no matches for %s\n' % n)
1482 r = 1
1482 r = 1
1483 sys.stdout.flush()
1483 sys.stdout.flush()
1484 return r
1484 return r
1485
1485
1486 def root(ui, repo):
1486 def root(ui, repo):
1487 """print the root (top) of the current working dir"""
1487 """print the root (top) of the current working dir"""
1488 ui.write(repo.root + "\n")
1488 ui.write(repo.root + "\n")
1489
1489
1490 def serve(ui, repo, **opts):
1490 def serve(ui, repo, **opts):
1491 """export the repository via HTTP"""
1491 """export the repository via HTTP"""
1492
1492
1493 if opts["stdio"]:
1493 if opts["stdio"]:
1494 fin, fout = sys.stdin, sys.stdout
1494 fin, fout = sys.stdin, sys.stdout
1495 sys.stdout = sys.stderr
1495 sys.stdout = sys.stderr
1496
1496
1497 def getarg():
1497 def getarg():
1498 argline = fin.readline()[:-1]
1498 argline = fin.readline()[:-1]
1499 arg, l = argline.split()
1499 arg, l = argline.split()
1500 val = fin.read(int(l))
1500 val = fin.read(int(l))
1501 return arg, val
1501 return arg, val
1502 def respond(v):
1502 def respond(v):
1503 fout.write("%d\n" % len(v))
1503 fout.write("%d\n" % len(v))
1504 fout.write(v)
1504 fout.write(v)
1505 fout.flush()
1505 fout.flush()
1506
1506
1507 lock = None
1507 lock = None
1508
1508
1509 while 1:
1509 while 1:
1510 cmd = fin.readline()[:-1]
1510 cmd = fin.readline()[:-1]
1511 if cmd == '':
1511 if cmd == '':
1512 return
1512 return
1513 if cmd == "heads":
1513 if cmd == "heads":
1514 h = repo.heads()
1514 h = repo.heads()
1515 respond(" ".join(map(hex, h)) + "\n")
1515 respond(" ".join(map(hex, h)) + "\n")
1516 if cmd == "lock":
1516 if cmd == "lock":
1517 lock = repo.lock()
1517 lock = repo.lock()
1518 respond("")
1518 respond("")
1519 if cmd == "unlock":
1519 if cmd == "unlock":
1520 if lock:
1520 if lock:
1521 lock.release()
1521 lock.release()
1522 lock = None
1522 lock = None
1523 respond("")
1523 respond("")
1524 elif cmd == "branches":
1524 elif cmd == "branches":
1525 arg, nodes = getarg()
1525 arg, nodes = getarg()
1526 nodes = map(bin, nodes.split(" "))
1526 nodes = map(bin, nodes.split(" "))
1527 r = []
1527 r = []
1528 for b in repo.branches(nodes):
1528 for b in repo.branches(nodes):
1529 r.append(" ".join(map(hex, b)) + "\n")
1529 r.append(" ".join(map(hex, b)) + "\n")
1530 respond("".join(r))
1530 respond("".join(r))
1531 elif cmd == "between":
1531 elif cmd == "between":
1532 arg, pairs = getarg()
1532 arg, pairs = getarg()
1533 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
1533 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
1534 r = []
1534 r = []
1535 for b in repo.between(pairs):
1535 for b in repo.between(pairs):
1536 r.append(" ".join(map(hex, b)) + "\n")
1536 r.append(" ".join(map(hex, b)) + "\n")
1537 respond("".join(r))
1537 respond("".join(r))
1538 elif cmd == "changegroup":
1538 elif cmd == "changegroup":
1539 nodes = []
1539 nodes = []
1540 arg, roots = getarg()
1540 arg, roots = getarg()
1541 nodes = map(bin, roots.split(" "))
1541 nodes = map(bin, roots.split(" "))
1542
1542
1543 cg = repo.changegroup(nodes)
1543 cg = repo.changegroup(nodes)
1544 while 1:
1544 while 1:
1545 d = cg.read(4096)
1545 d = cg.read(4096)
1546 if not d:
1546 if not d:
1547 break
1547 break
1548 fout.write(d)
1548 fout.write(d)
1549
1549
1550 fout.flush()
1550 fout.flush()
1551
1551
1552 elif cmd == "addchangegroup":
1552 elif cmd == "addchangegroup":
1553 if not lock:
1553 if not lock:
1554 respond("not locked")
1554 respond("not locked")
1555 continue
1555 continue
1556 respond("")
1556 respond("")
1557
1557
1558 r = repo.addchangegroup(fin)
1558 r = repo.addchangegroup(fin)
1559 respond("")
1559 respond("")
1560
1560
1561 optlist = "name templates style address port ipv6 accesslog errorlog"
1561 optlist = "name templates style address port ipv6 accesslog errorlog"
1562 for o in optlist.split():
1562 for o in optlist.split():
1563 if opts[o]:
1563 if opts[o]:
1564 ui.setconfig("web", o, opts[o])
1564 ui.setconfig("web", o, opts[o])
1565
1565
1566 try:
1566 try:
1567 httpd = hgweb.create_server(repo)
1567 httpd = hgweb.create_server(repo)
1568 except socket.error, inst:
1568 except socket.error, inst:
1569 raise util.Abort('cannot start server: ' + inst.args[1])
1569 raise util.Abort('cannot start server: ' + inst.args[1])
1570
1570
1571 if ui.verbose:
1571 if ui.verbose:
1572 addr, port = httpd.socket.getsockname()
1572 addr, port = httpd.socket.getsockname()
1573 if addr == '0.0.0.0':
1573 if addr == '0.0.0.0':
1574 addr = socket.gethostname()
1574 addr = socket.gethostname()
1575 else:
1575 else:
1576 try:
1576 try:
1577 addr = socket.gethostbyaddr(addr)[0]
1577 addr = socket.gethostbyaddr(addr)[0]
1578 except socket.error:
1578 except socket.error:
1579 pass
1579 pass
1580 if port != 80:
1580 if port != 80:
1581 ui.status('listening at http://%s:%d/\n' % (addr, port))
1581 ui.status('listening at http://%s:%d/\n' % (addr, port))
1582 else:
1582 else:
1583 ui.status('listening at http://%s/\n' % addr)
1583 ui.status('listening at http://%s/\n' % addr)
1584 httpd.serve_forever()
1584 httpd.serve_forever()
1585
1585
1586 def status(ui, repo, *pats, **opts):
1586 def status(ui, repo, *pats, **opts):
1587 '''show changed files in the working directory
1587 '''show changed files in the working directory
1588
1588
1589 M = modified
1589 M = modified
1590 A = added
1590 A = added
1591 R = removed
1591 R = removed
1592 ? = not tracked
1592 ? = not tracked
1593 '''
1593 '''
1594
1594
1595 cwd = repo.getcwd()
1595 cwd = repo.getcwd()
1596 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1596 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1597 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1597 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1598 for n in repo.changes(files=files, match=matchfn)]
1598 for n in repo.changes(files=files, match=matchfn)]
1599
1599
1600 changetypes = [('modified', 'M', c),
1600 changetypes = [('modified', 'M', c),
1601 ('added', 'A', a),
1601 ('added', 'A', a),
1602 ('removed', 'R', d),
1602 ('removed', 'R', d),
1603 ('unknown', '?', u)]
1603 ('unknown', '?', u)]
1604
1604
1605 end = opts['print0'] and '\0' or '\n'
1605 end = opts['print0'] and '\0' or '\n'
1606
1606
1607 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1607 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1608 or changetypes):
1608 or changetypes):
1609 if opts['no_status']:
1609 if opts['no_status']:
1610 format = "%%s%s" % end
1610 format = "%%s%s" % end
1611 else:
1611 else:
1612 format = "%s %%s%s" % (char, end);
1612 format = "%s %%s%s" % (char, end);
1613
1613
1614 for f in changes:
1614 for f in changes:
1615 ui.write(format % f)
1615 ui.write(format % f)
1616
1616
1617 def tag(ui, repo, name, rev=None, **opts):
1617 def tag(ui, repo, name, rev=None, **opts):
1618 """add a tag for the current tip or a given revision"""
1618 """add a tag for the current tip or a given revision"""
1619 if opts['text']:
1619 if opts['text']:
1620 ui.warn("Warning: -t and --text is deprecated,"
1620 ui.warn("Warning: -t and --text is deprecated,"
1621 " please use -m or --message instead.\n")
1621 " please use -m or --message instead.\n")
1622 if name == "tip":
1622 if name == "tip":
1623 raise util.Abort("the name 'tip' is reserved")
1623 raise util.Abort("the name 'tip' is reserved")
1624 if rev:
1624 if rev:
1625 r = hex(repo.lookup(rev))
1625 r = hex(repo.lookup(rev))
1626 else:
1626 else:
1627 r = hex(repo.changelog.tip())
1627 r = hex(repo.changelog.tip())
1628
1628
1629 if name.find(revrangesep) >= 0:
1629 if name.find(revrangesep) >= 0:
1630 raise util.Abort("'%s' cannot be used in a tag name" % revrangesep)
1630 raise util.Abort("'%s' cannot be used in a tag name" % revrangesep)
1631
1631
1632 if opts['local']:
1632 if opts['local']:
1633 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1633 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1634 return
1634 return
1635
1635
1636 (c, a, d, u) = repo.changes()
1636 (c, a, d, u) = repo.changes()
1637 for x in (c, a, d, u):
1637 for x in (c, a, d, u):
1638 if ".hgtags" in x:
1638 if ".hgtags" in x:
1639 raise util.Abort("working copy of .hgtags is changed "
1639 raise util.Abort("working copy of .hgtags is changed "
1640 "(please commit .hgtags manually)")
1640 "(please commit .hgtags manually)")
1641
1641
1642 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1642 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1643 if repo.dirstate.state(".hgtags") == '?':
1643 if repo.dirstate.state(".hgtags") == '?':
1644 repo.add([".hgtags"])
1644 repo.add([".hgtags"])
1645
1645
1646 message = (opts['message'] or opts['text'] or
1646 message = (opts['message'] or opts['text'] or
1647 "Added tag %s for changeset %s" % (name, r))
1647 "Added tag %s for changeset %s" % (name, r))
1648 try:
1648 try:
1649 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1649 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1650 except ValueError, inst:
1650 except ValueError, inst:
1651 raise util.Abort(str(inst))
1651 raise util.Abort(str(inst))
1652
1652
1653 def tags(ui, repo):
1653 def tags(ui, repo):
1654 """list repository tags"""
1654 """list repository tags"""
1655
1655
1656 l = repo.tagslist()
1656 l = repo.tagslist()
1657 l.reverse()
1657 l.reverse()
1658 for t, n in l:
1658 for t, n in l:
1659 try:
1659 try:
1660 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
1660 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
1661 except KeyError:
1661 except KeyError:
1662 r = " ?:?"
1662 r = " ?:?"
1663 ui.write("%-30s %s\n" % (t, r))
1663 ui.write("%-30s %s\n" % (t, r))
1664
1664
1665 def tip(ui, repo):
1665 def tip(ui, repo):
1666 """show the tip revision"""
1666 """show the tip revision"""
1667 n = repo.changelog.tip()
1667 n = repo.changelog.tip()
1668 show_changeset(ui, repo, changenode=n)
1668 show_changeset(ui, repo, changenode=n)
1669
1669
1670 def unbundle(ui, repo, fname):
1670 def unbundle(ui, repo, fname):
1671 """apply a changegroup file"""
1671 """apply a changegroup file"""
1672 f = urllib.urlopen(fname)
1672 f = urllib.urlopen(fname)
1673
1673
1674 if f.read(4) != "HG10":
1674 if f.read(4) != "HG10":
1675 raise util.Abort("%s: not a Mercurial bundle file" % fname)
1675 raise util.Abort("%s: not a Mercurial bundle file" % fname)
1676
1676
1677 class bzread:
1677 class bzread:
1678 def __init__(self, f):
1678 def __init__(self, f):
1679 self.zd = bz2.BZ2Decompressor()
1679 self.zd = bz2.BZ2Decompressor()
1680 self.f = f
1680 self.f = f
1681 self.buf = ""
1681 self.buf = ""
1682 def read(self, l):
1682 def read(self, l):
1683 while l > len(self.buf):
1683 while l > len(self.buf):
1684 r = self.f.read(4096)
1684 r = self.f.read(4096)
1685 if r:
1685 if r:
1686 self.buf += self.zd.decompress(r)
1686 self.buf += self.zd.decompress(r)
1687 else:
1687 else:
1688 break
1688 break
1689 d, self.buf = self.buf[:l], self.buf[l:]
1689 d, self.buf = self.buf[:l], self.buf[l:]
1690 return d
1690 return d
1691
1691
1692 repo.addchangegroup(bzread(f))
1692 repo.addchangegroup(bzread(f))
1693
1693
1694 def undo(ui, repo):
1694 def undo(ui, repo):
1695 """undo the last commit or pull
1695 """undo the last commit or pull
1696
1696
1697 Roll back the last pull or commit transaction on the
1697 Roll back the last pull or commit transaction on the
1698 repository, restoring the project to its earlier state.
1698 repository, restoring the project to its earlier state.
1699
1699
1700 This command should be used with care. There is only one level of
1700 This command should be used with care. There is only one level of
1701 undo and there is no redo.
1701 undo and there is no redo.
1702
1702
1703 This command is not intended for use on public repositories. Once
1703 This command is not intended for use on public repositories. Once
1704 a change is visible for pull by other users, undoing it locally is
1704 a change is visible for pull by other users, undoing it locally is
1705 ineffective.
1705 ineffective.
1706 """
1706 """
1707 repo.undo()
1707 repo.undo()
1708
1708
1709 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1709 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1710 '''update or merge working directory
1710 '''update or merge working directory
1711
1711
1712 If there are no outstanding changes in the working directory and
1712 If there are no outstanding changes in the working directory and
1713 there is a linear relationship between the current version and the
1713 there is a linear relationship between the current version and the
1714 requested version, the result is the requested version.
1714 requested version, the result is the requested version.
1715
1715
1716 Otherwise the result is a merge between the contents of the
1716 Otherwise the result is a merge between the contents of the
1717 current working directory and the requested version. Files that
1717 current working directory and the requested version. Files that
1718 changed between either parent are marked as changed for the next
1718 changed between either parent are marked as changed for the next
1719 commit and a commit must be performed before any further updates
1719 commit and a commit must be performed before any further updates
1720 are allowed.
1720 are allowed.
1721 '''
1721 '''
1722 if branch:
1722 if branch:
1723 br = repo.branchlookup(branch=branch)
1723 br = repo.branchlookup(branch=branch)
1724 found = []
1724 found = []
1725 for x in br:
1725 for x in br:
1726 if branch in br[x]:
1726 if branch in br[x]:
1727 found.append(x)
1727 found.append(x)
1728 if len(found) > 1:
1728 if len(found) > 1:
1729 ui.warn("Found multiple heads for %s\n" % branch)
1729 ui.warn("Found multiple heads for %s\n" % branch)
1730 for x in found:
1730 for x in found:
1731 show_changeset(ui, repo, changenode=x, brinfo=br)
1731 show_changeset(ui, repo, changenode=x, brinfo=br)
1732 return 1
1732 return 1
1733 if len(found) == 1:
1733 if len(found) == 1:
1734 node = found[0]
1734 node = found[0]
1735 ui.warn("Using head %s for branch %s\n" % (short(node), branch))
1735 ui.warn("Using head %s for branch %s\n" % (short(node), branch))
1736 else:
1736 else:
1737 ui.warn("branch %s not found\n" % (branch))
1737 ui.warn("branch %s not found\n" % (branch))
1738 return 1
1738 return 1
1739 else:
1739 else:
1740 node = node and repo.lookup(node) or repo.changelog.tip()
1740 node = node and repo.lookup(node) or repo.changelog.tip()
1741 return repo.update(node, allow=merge, force=clean)
1741 return repo.update(node, allow=merge, force=clean)
1742
1742
1743 def verify(ui, repo):
1743 def verify(ui, repo):
1744 """verify the integrity of the repository"""
1744 """verify the integrity of the repository"""
1745 return repo.verify()
1745 return repo.verify()
1746
1746
1747 # Command options and aliases are listed here, alphabetically
1747 # Command options and aliases are listed here, alphabetically
1748
1748
1749 table = {
1749 table = {
1750 "^add":
1750 "^add":
1751 (add,
1751 (add,
1752 [('I', 'include', [], 'include path in search'),
1752 [('I', 'include', [], 'include path in search'),
1753 ('X', 'exclude', [], 'exclude path from search')],
1753 ('X', 'exclude', [], 'exclude path from search')],
1754 "hg add [OPTION]... [FILE]..."),
1754 "hg add [OPTION]... [FILE]..."),
1755 "addremove":
1755 "addremove":
1756 (addremove,
1756 (addremove,
1757 [('I', 'include', [], 'include path in search'),
1757 [('I', 'include', [], 'include path in search'),
1758 ('X', 'exclude', [], 'exclude path from search')],
1758 ('X', 'exclude', [], 'exclude path from search')],
1759 "hg addremove [OPTION]... [FILE]..."),
1759 "hg addremove [OPTION]... [FILE]..."),
1760 "^annotate":
1760 "^annotate":
1761 (annotate,
1761 (annotate,
1762 [('r', 'rev', '', 'revision'),
1762 [('r', 'rev', '', 'revision'),
1763 ('a', 'text', None, 'treat all files as text'),
1763 ('a', 'text', None, 'treat all files as text'),
1764 ('u', 'user', None, 'show user'),
1764 ('u', 'user', None, 'show user'),
1765 ('n', 'number', None, 'show revision number'),
1765 ('n', 'number', None, 'show revision number'),
1766 ('c', 'changeset', None, 'show changeset'),
1766 ('c', 'changeset', None, 'show changeset'),
1767 ('I', 'include', [], 'include path in search'),
1767 ('I', 'include', [], 'include path in search'),
1768 ('X', 'exclude', [], 'exclude path from search')],
1768 ('X', 'exclude', [], 'exclude path from search')],
1769 'hg annotate [OPTION]... FILE...'),
1769 'hg annotate [OPTION]... FILE...'),
1770 "bundle":
1770 "bundle":
1771 (bundle,
1771 (bundle,
1772 [],
1772 [],
1773 'hg bundle FILE DEST'),
1773 'hg bundle FILE DEST'),
1774 "cat":
1774 "cat":
1775 (cat,
1775 (cat,
1776 [('I', 'include', [], 'include path in search'),
1776 [('I', 'include', [], 'include path in search'),
1777 ('X', 'exclude', [], 'exclude path from search'),
1777 ('X', 'exclude', [], 'exclude path from search'),
1778 ('o', 'output', "", 'output to file'),
1778 ('o', 'output', "", 'output to file'),
1779 ('r', 'rev', '', 'revision')],
1779 ('r', 'rev', '', 'revision')],
1780 'hg cat [OPTION]... FILE...'),
1780 'hg cat [OPTION]... FILE...'),
1781 "^clone":
1781 "^clone":
1782 (clone,
1782 (clone,
1783 [('U', 'noupdate', None, 'skip update after cloning'),
1783 [('U', 'noupdate', None, 'skip update after cloning'),
1784 ('e', 'ssh', "", 'ssh command'),
1784 ('e', 'ssh', "", 'ssh command'),
1785 ('', 'pull', None, 'use pull protocol to copy metadata'),
1785 ('', 'remotecmd', "", 'remote hg command')],
1786 ('', 'remotecmd', "", 'remote hg command')],
1786 'hg clone [OPTION]... SOURCE [DEST]'),
1787 'hg clone [OPTION]... SOURCE [DEST]'),
1787 "^commit|ci":
1788 "^commit|ci":
1788 (commit,
1789 (commit,
1789 [('A', 'addremove', None, 'run add/remove during commit'),
1790 [('A', 'addremove', None, 'run add/remove during commit'),
1790 ('I', 'include', [], 'include path in search'),
1791 ('I', 'include', [], 'include path in search'),
1791 ('X', 'exclude', [], 'exclude path from search'),
1792 ('X', 'exclude', [], 'exclude path from search'),
1792 ('m', 'message', "", 'commit message'),
1793 ('m', 'message', "", 'commit message'),
1793 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1794 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1794 ('l', 'logfile', "", 'commit message file'),
1795 ('l', 'logfile', "", 'commit message file'),
1795 ('d', 'date', "", 'date code'),
1796 ('d', 'date', "", 'date code'),
1796 ('u', 'user', "", 'user')],
1797 ('u', 'user', "", 'user')],
1797 'hg commit [OPTION]... [FILE]...'),
1798 'hg commit [OPTION]... [FILE]...'),
1798 "copy|cp": (copy,
1799 "copy|cp": (copy,
1799 [('I', 'include', [], 'include path in search'),
1800 [('I', 'include', [], 'include path in search'),
1800 ('X', 'exclude', [], 'exclude path from search'),
1801 ('X', 'exclude', [], 'exclude path from search'),
1801 ('A', 'after', None, 'record a copy after it has happened'),
1802 ('A', 'after', None, 'record a copy after it has happened'),
1802 ('f', 'force', None, 'replace destination if it exists'),
1803 ('f', 'force', None, 'replace destination if it exists'),
1803 ('p', 'parents', None, 'append source path to dest')],
1804 ('p', 'parents', None, 'append source path to dest')],
1804 'hg copy [OPTION]... [SOURCE]... DEST'),
1805 'hg copy [OPTION]... [SOURCE]... DEST'),
1805 "debugancestor": (debugancestor, [], 'debugancestor INDEX REV1 REV2'),
1806 "debugancestor": (debugancestor, [], 'debugancestor INDEX REV1 REV2'),
1806 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1807 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1807 "debugconfig": (debugconfig, [], 'debugconfig'),
1808 "debugconfig": (debugconfig, [], 'debugconfig'),
1808 "debugstate": (debugstate, [], 'debugstate'),
1809 "debugstate": (debugstate, [], 'debugstate'),
1809 "debugdata": (debugdata, [], 'debugdata FILE REV'),
1810 "debugdata": (debugdata, [], 'debugdata FILE REV'),
1810 "debugindex": (debugindex, [], 'debugindex FILE'),
1811 "debugindex": (debugindex, [], 'debugindex FILE'),
1811 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1812 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1812 "debugrename": (debugrename, [], 'debugrename FILE [REV]'),
1813 "debugrename": (debugrename, [], 'debugrename FILE [REV]'),
1813 "debugwalk":
1814 "debugwalk":
1814 (debugwalk,
1815 (debugwalk,
1815 [('I', 'include', [], 'include path in search'),
1816 [('I', 'include', [], 'include path in search'),
1816 ('X', 'exclude', [], 'exclude path from search')],
1817 ('X', 'exclude', [], 'exclude path from search')],
1817 'debugwalk [OPTION]... [FILE]...'),
1818 'debugwalk [OPTION]... [FILE]...'),
1818 "^diff":
1819 "^diff":
1819 (diff,
1820 (diff,
1820 [('r', 'rev', [], 'revision'),
1821 [('r', 'rev', [], 'revision'),
1821 ('a', 'text', None, 'treat all files as text'),
1822 ('a', 'text', None, 'treat all files as text'),
1822 ('I', 'include', [], 'include path in search'),
1823 ('I', 'include', [], 'include path in search'),
1823 ('X', 'exclude', [], 'exclude path from search')],
1824 ('X', 'exclude', [], 'exclude path from search')],
1824 'hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...'),
1825 'hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...'),
1825 "^export":
1826 "^export":
1826 (export,
1827 (export,
1827 [('o', 'output', "", 'output to file'),
1828 [('o', 'output', "", 'output to file'),
1828 ('a', 'text', None, 'treat all files as text')],
1829 ('a', 'text', None, 'treat all files as text')],
1829 "hg export [-a] [-o OUTFILE] REV..."),
1830 "hg export [-a] [-o OUTFILE] REV..."),
1830 "forget":
1831 "forget":
1831 (forget,
1832 (forget,
1832 [('I', 'include', [], 'include path in search'),
1833 [('I', 'include', [], 'include path in search'),
1833 ('X', 'exclude', [], 'exclude path from search')],
1834 ('X', 'exclude', [], 'exclude path from search')],
1834 "hg forget [OPTION]... FILE..."),
1835 "hg forget [OPTION]... FILE..."),
1835 "grep":
1836 "grep":
1836 (grep,
1837 (grep,
1837 [('0', 'print0', None, 'end fields with NUL'),
1838 [('0', 'print0', None, 'end fields with NUL'),
1838 ('I', 'include', [], 'include path in search'),
1839 ('I', 'include', [], 'include path in search'),
1839 ('X', 'exclude', [], 'include path in search'),
1840 ('X', 'exclude', [], 'include path in search'),
1840 ('', 'all', None, 'print all revisions with matches'),
1841 ('', 'all', None, 'print all revisions with matches'),
1841 ('i', 'ignore-case', None, 'ignore case when matching'),
1842 ('i', 'ignore-case', None, 'ignore case when matching'),
1842 ('l', 'files-with-matches', None, 'print names of files and revs with matches'),
1843 ('l', 'files-with-matches', None, 'print names of files and revs with matches'),
1843 ('n', 'line-number', None, 'print line numbers'),
1844 ('n', 'line-number', None, 'print line numbers'),
1844 ('r', 'rev', [], 'search in revision rev'),
1845 ('r', 'rev', [], 'search in revision rev'),
1845 ('u', 'user', None, 'print user who made change')],
1846 ('u', 'user', None, 'print user who made change')],
1846 "hg grep [OPTION]... PATTERN [FILE]..."),
1847 "hg grep [OPTION]... PATTERN [FILE]..."),
1847 "heads":
1848 "heads":
1848 (heads,
1849 (heads,
1849 [('b', 'branches', None, 'find branch info')],
1850 [('b', 'branches', None, 'find branch info')],
1850 'hg heads [-b]'),
1851 'hg heads [-b]'),
1851 "help": (help_, [], 'hg help [COMMAND]'),
1852 "help": (help_, [], 'hg help [COMMAND]'),
1852 "identify|id": (identify, [], 'hg identify'),
1853 "identify|id": (identify, [], 'hg identify'),
1853 "import|patch":
1854 "import|patch":
1854 (import_,
1855 (import_,
1855 [('p', 'strip', 1, 'path strip'),
1856 [('p', 'strip', 1, 'path strip'),
1856 ('f', 'force', None, 'skip check for outstanding changes'),
1857 ('f', 'force', None, 'skip check for outstanding changes'),
1857 ('b', 'base', "", 'base path')],
1858 ('b', 'base', "", 'base path')],
1858 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
1859 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
1859 "incoming|in": (incoming,
1860 "incoming|in": (incoming,
1860 [('p', 'patch', None, 'show patch')],
1861 [('p', 'patch', None, 'show patch')],
1861 'hg incoming [-p] [SOURCE]'),
1862 'hg incoming [-p] [SOURCE]'),
1862 "^init": (init, [], 'hg init [DEST]'),
1863 "^init": (init, [], 'hg init [DEST]'),
1863 "locate":
1864 "locate":
1864 (locate,
1865 (locate,
1865 [('r', 'rev', '', 'revision'),
1866 [('r', 'rev', '', 'revision'),
1866 ('0', 'print0', None, 'end filenames with NUL'),
1867 ('0', 'print0', None, 'end filenames with NUL'),
1867 ('f', 'fullpath', None, 'print complete paths'),
1868 ('f', 'fullpath', None, 'print complete paths'),
1868 ('I', 'include', [], 'include path in search'),
1869 ('I', 'include', [], 'include path in search'),
1869 ('X', 'exclude', [], 'exclude path from search')],
1870 ('X', 'exclude', [], 'exclude path from search')],
1870 'hg locate [OPTION]... [PATTERN]...'),
1871 'hg locate [OPTION]... [PATTERN]...'),
1871 "^log|history":
1872 "^log|history":
1872 (log,
1873 (log,
1873 [('I', 'include', [], 'include path in search'),
1874 [('I', 'include', [], 'include path in search'),
1874 ('X', 'exclude', [], 'exclude path from search'),
1875 ('X', 'exclude', [], 'exclude path from search'),
1875 ('b', 'branch', None, 'show branches'),
1876 ('b', 'branch', None, 'show branches'),
1876 ('r', 'rev', [], 'revision'),
1877 ('r', 'rev', [], 'revision'),
1877 ('p', 'patch', None, 'show patch')],
1878 ('p', 'patch', None, 'show patch')],
1878 'hg log [-I] [-X] [-r REV]... [-p] [FILE]'),
1879 'hg log [-I] [-X] [-r REV]... [-p] [FILE]'),
1879 "manifest": (manifest, [], 'hg manifest [REV]'),
1880 "manifest": (manifest, [], 'hg manifest [REV]'),
1880 "outgoing|out": (outgoing,
1881 "outgoing|out": (outgoing,
1881 [('p', 'patch', None, 'show patch')],
1882 [('p', 'patch', None, 'show patch')],
1882 'hg outgoing [-p] [DEST]'),
1883 'hg outgoing [-p] [DEST]'),
1883 "parents": (parents, [], 'hg parents [REV]'),
1884 "parents": (parents, [], 'hg parents [REV]'),
1884 "paths": (paths, [], 'hg paths [NAME]'),
1885 "paths": (paths, [], 'hg paths [NAME]'),
1885 "^pull":
1886 "^pull":
1886 (pull,
1887 (pull,
1887 [('u', 'update', None, 'update working directory'),
1888 [('u', 'update', None, 'update working directory'),
1888 ('e', 'ssh', "", 'ssh command'),
1889 ('e', 'ssh', "", 'ssh command'),
1889 ('', 'remotecmd', "", 'remote hg command')],
1890 ('', 'remotecmd', "", 'remote hg command')],
1890 'hg pull [-u] [-e FILE] [--remotecmd FILE] [SOURCE]'),
1891 'hg pull [-u] [-e FILE] [--remotecmd FILE] [SOURCE]'),
1891 "^push":
1892 "^push":
1892 (push,
1893 (push,
1893 [('f', 'force', None, 'force push'),
1894 [('f', 'force', None, 'force push'),
1894 ('e', 'ssh', "", 'ssh command'),
1895 ('e', 'ssh', "", 'ssh command'),
1895 ('', 'remotecmd', "", 'remote hg command')],
1896 ('', 'remotecmd', "", 'remote hg command')],
1896 'hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]'),
1897 'hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]'),
1897 "rawcommit":
1898 "rawcommit":
1898 (rawcommit,
1899 (rawcommit,
1899 [('p', 'parent', [], 'parent'),
1900 [('p', 'parent', [], 'parent'),
1900 ('d', 'date', "", 'date code'),
1901 ('d', 'date', "", 'date code'),
1901 ('u', 'user', "", 'user'),
1902 ('u', 'user', "", 'user'),
1902 ('F', 'files', "", 'file list'),
1903 ('F', 'files', "", 'file list'),
1903 ('m', 'message', "", 'commit message'),
1904 ('m', 'message', "", 'commit message'),
1904 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1905 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1905 ('l', 'logfile', "", 'commit message file')],
1906 ('l', 'logfile', "", 'commit message file')],
1906 'hg rawcommit [OPTION]... [FILE]...'),
1907 'hg rawcommit [OPTION]... [FILE]...'),
1907 "recover": (recover, [], "hg recover"),
1908 "recover": (recover, [], "hg recover"),
1908 "^remove|rm": (remove,
1909 "^remove|rm": (remove,
1909 [('I', 'include', [], 'include path in search'),
1910 [('I', 'include', [], 'include path in search'),
1910 ('X', 'exclude', [], 'exclude path from search')],
1911 ('X', 'exclude', [], 'exclude path from search')],
1911 "hg remove [OPTION]... FILE..."),
1912 "hg remove [OPTION]... FILE..."),
1912 "rename|mv": (rename,
1913 "rename|mv": (rename,
1913 [('I', 'include', [], 'include path in search'),
1914 [('I', 'include', [], 'include path in search'),
1914 ('X', 'exclude', [], 'exclude path from search'),
1915 ('X', 'exclude', [], 'exclude path from search'),
1915 ('A', 'after', None, 'record a copy after it has happened'),
1916 ('A', 'after', None, 'record a copy after it has happened'),
1916 ('f', 'force', None, 'replace destination if it exists'),
1917 ('f', 'force', None, 'replace destination if it exists'),
1917 ('p', 'parents', None, 'append source path to dest')],
1918 ('p', 'parents', None, 'append source path to dest')],
1918 'hg rename [OPTION]... [SOURCE]... DEST'),
1919 'hg rename [OPTION]... [SOURCE]... DEST'),
1919 "^revert":
1920 "^revert":
1920 (revert,
1921 (revert,
1921 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1922 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1922 ("r", "rev", "", "revision")],
1923 ("r", "rev", "", "revision")],
1923 "hg revert [-n] [-r REV] [NAME]..."),
1924 "hg revert [-n] [-r REV] [NAME]..."),
1924 "root": (root, [], "hg root"),
1925 "root": (root, [], "hg root"),
1925 "^serve":
1926 "^serve":
1926 (serve,
1927 (serve,
1927 [('A', 'accesslog', '', 'access log file'),
1928 [('A', 'accesslog', '', 'access log file'),
1928 ('E', 'errorlog', '', 'error log file'),
1929 ('E', 'errorlog', '', 'error log file'),
1929 ('p', 'port', 0, 'listen port'),
1930 ('p', 'port', 0, 'listen port'),
1930 ('a', 'address', '', 'interface address'),
1931 ('a', 'address', '', 'interface address'),
1931 ('n', 'name', "", 'repository name'),
1932 ('n', 'name', "", 'repository name'),
1932 ('', 'stdio', None, 'for remote clients'),
1933 ('', 'stdio', None, 'for remote clients'),
1933 ('t', 'templates', "", 'template directory'),
1934 ('t', 'templates', "", 'template directory'),
1934 ('', 'style', "", 'template style'),
1935 ('', 'style', "", 'template style'),
1935 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1936 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1936 "hg serve [OPTION]..."),
1937 "hg serve [OPTION]..."),
1937 "^status":
1938 "^status":
1938 (status,
1939 (status,
1939 [('m', 'modified', None, 'show only modified files'),
1940 [('m', 'modified', None, 'show only modified files'),
1940 ('a', 'added', None, 'show only added files'),
1941 ('a', 'added', None, 'show only added files'),
1941 ('r', 'removed', None, 'show only removed files'),
1942 ('r', 'removed', None, 'show only removed files'),
1942 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1943 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1943 ('n', 'no-status', None, 'hide status prefix'),
1944 ('n', 'no-status', None, 'hide status prefix'),
1944 ('0', 'print0', None, 'end filenames with NUL'),
1945 ('0', 'print0', None, 'end filenames with NUL'),
1945 ('I', 'include', [], 'include path in search'),
1946 ('I', 'include', [], 'include path in search'),
1946 ('X', 'exclude', [], 'exclude path from search')],
1947 ('X', 'exclude', [], 'exclude path from search')],
1947 "hg status [OPTION]... [FILE]..."),
1948 "hg status [OPTION]... [FILE]..."),
1948 "tag":
1949 "tag":
1949 (tag,
1950 (tag,
1950 [('l', 'local', None, 'make the tag local'),
1951 [('l', 'local', None, 'make the tag local'),
1951 ('m', 'message', "", 'commit message'),
1952 ('m', 'message', "", 'commit message'),
1952 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1953 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1953 ('d', 'date', "", 'date code'),
1954 ('d', 'date', "", 'date code'),
1954 ('u', 'user', "", 'user')],
1955 ('u', 'user', "", 'user')],
1955 'hg tag [OPTION]... NAME [REV]'),
1956 'hg tag [OPTION]... NAME [REV]'),
1956 "tags": (tags, [], 'hg tags'),
1957 "tags": (tags, [], 'hg tags'),
1957 "tip": (tip, [], 'hg tip'),
1958 "tip": (tip, [], 'hg tip'),
1958 "unbundle":
1959 "unbundle":
1959 (unbundle,
1960 (unbundle,
1960 [],
1961 [],
1961 'hg unbundle FILE'),
1962 'hg unbundle FILE'),
1962 "undo": (undo, [], 'hg undo'),
1963 "undo": (undo, [], 'hg undo'),
1963 "^update|up|checkout|co":
1964 "^update|up|checkout|co":
1964 (update,
1965 (update,
1965 [('b', 'branch', "", 'checkout the head of a specific branch'),
1966 [('b', 'branch', "", 'checkout the head of a specific branch'),
1966 ('m', 'merge', None, 'allow merging of conflicts'),
1967 ('m', 'merge', None, 'allow merging of conflicts'),
1967 ('C', 'clean', None, 'overwrite locally modified files')],
1968 ('C', 'clean', None, 'overwrite locally modified files')],
1968 'hg update [-b TAG] [-m] [-C] [REV]'),
1969 'hg update [-b TAG] [-m] [-C] [REV]'),
1969 "verify": (verify, [], 'hg verify'),
1970 "verify": (verify, [], 'hg verify'),
1970 "version": (show_version, [], 'hg version'),
1971 "version": (show_version, [], 'hg version'),
1971 }
1972 }
1972
1973
1973 globalopts = [
1974 globalopts = [
1974 ('R', 'repository', "", 'repository root directory'),
1975 ('R', 'repository', "", 'repository root directory'),
1975 ('', 'cwd', '', 'change working directory'),
1976 ('', 'cwd', '', 'change working directory'),
1976 ('y', 'noninteractive', None, 'run non-interactively'),
1977 ('y', 'noninteractive', None, 'run non-interactively'),
1977 ('q', 'quiet', None, 'quiet mode'),
1978 ('q', 'quiet', None, 'quiet mode'),
1978 ('v', 'verbose', None, 'verbose mode'),
1979 ('v', 'verbose', None, 'verbose mode'),
1979 ('', 'debug', None, 'debug mode'),
1980 ('', 'debug', None, 'debug mode'),
1980 ('', 'debugger', None, 'start debugger'),
1981 ('', 'debugger', None, 'start debugger'),
1981 ('', 'traceback', None, 'print traceback on exception'),
1982 ('', 'traceback', None, 'print traceback on exception'),
1982 ('', 'time', None, 'time how long the command takes'),
1983 ('', 'time', None, 'time how long the command takes'),
1983 ('', 'profile', None, 'profile'),
1984 ('', 'profile', None, 'profile'),
1984 ('', 'version', None, 'output version information and exit'),
1985 ('', 'version', None, 'output version information and exit'),
1985 ('h', 'help', None, 'display help and exit'),
1986 ('h', 'help', None, 'display help and exit'),
1986 ]
1987 ]
1987
1988
1988 norepo = ("clone init version help debugancestor debugconfig debugdata"
1989 norepo = ("clone init version help debugancestor debugconfig debugdata"
1989 " debugindex debugindexdot paths")
1990 " debugindex debugindexdot paths")
1990
1991
1991 def find(cmd):
1992 def find(cmd):
1992 for e in table.keys():
1993 for e in table.keys():
1993 if re.match("(%s)$" % e, cmd):
1994 if re.match("(%s)$" % e, cmd):
1994 return e, table[e]
1995 return e, table[e]
1995
1996
1996 raise UnknownCommand(cmd)
1997 raise UnknownCommand(cmd)
1997
1998
1998 class SignalInterrupt(Exception):
1999 class SignalInterrupt(Exception):
1999 """Exception raised on SIGTERM and SIGHUP."""
2000 """Exception raised on SIGTERM and SIGHUP."""
2000
2001
2001 def catchterm(*args):
2002 def catchterm(*args):
2002 raise SignalInterrupt
2003 raise SignalInterrupt
2003
2004
2004 def run():
2005 def run():
2005 sys.exit(dispatch(sys.argv[1:]))
2006 sys.exit(dispatch(sys.argv[1:]))
2006
2007
2007 class ParseError(Exception):
2008 class ParseError(Exception):
2008 """Exception raised on errors in parsing the command line."""
2009 """Exception raised on errors in parsing the command line."""
2009
2010
2010 def parse(args):
2011 def parse(args):
2011 options = {}
2012 options = {}
2012 cmdoptions = {}
2013 cmdoptions = {}
2013
2014
2014 try:
2015 try:
2015 args = fancyopts.fancyopts(args, globalopts, options)
2016 args = fancyopts.fancyopts(args, globalopts, options)
2016 except fancyopts.getopt.GetoptError, inst:
2017 except fancyopts.getopt.GetoptError, inst:
2017 raise ParseError(None, inst)
2018 raise ParseError(None, inst)
2018
2019
2019 if args:
2020 if args:
2020 cmd, args = args[0], args[1:]
2021 cmd, args = args[0], args[1:]
2021 i = find(cmd)[1]
2022 i = find(cmd)[1]
2022 c = list(i[1])
2023 c = list(i[1])
2023 else:
2024 else:
2024 cmd = None
2025 cmd = None
2025 c = []
2026 c = []
2026
2027
2027 # combine global options into local
2028 # combine global options into local
2028 for o in globalopts:
2029 for o in globalopts:
2029 c.append((o[0], o[1], options[o[1]], o[3]))
2030 c.append((o[0], o[1], options[o[1]], o[3]))
2030
2031
2031 try:
2032 try:
2032 args = fancyopts.fancyopts(args, c, cmdoptions)
2033 args = fancyopts.fancyopts(args, c, cmdoptions)
2033 except fancyopts.getopt.GetoptError, inst:
2034 except fancyopts.getopt.GetoptError, inst:
2034 raise ParseError(cmd, inst)
2035 raise ParseError(cmd, inst)
2035
2036
2036 # separate global options back out
2037 # separate global options back out
2037 for o in globalopts:
2038 for o in globalopts:
2038 n = o[1]
2039 n = o[1]
2039 options[n] = cmdoptions[n]
2040 options[n] = cmdoptions[n]
2040 del cmdoptions[n]
2041 del cmdoptions[n]
2041
2042
2042 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
2043 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
2043
2044
2044 def dispatch(args):
2045 def dispatch(args):
2045 signal.signal(signal.SIGTERM, catchterm)
2046 signal.signal(signal.SIGTERM, catchterm)
2046 try:
2047 try:
2047 signal.signal(signal.SIGHUP, catchterm)
2048 signal.signal(signal.SIGHUP, catchterm)
2048 except AttributeError:
2049 except AttributeError:
2049 pass
2050 pass
2050
2051
2051 u = ui.ui()
2052 u = ui.ui()
2052 external = []
2053 external = []
2053 for x in u.extensions():
2054 for x in u.extensions():
2054 if x[1]:
2055 if x[1]:
2055 mod = imp.load_source(x[0], x[1])
2056 mod = imp.load_source(x[0], x[1])
2056 else:
2057 else:
2057 def importh(name):
2058 def importh(name):
2058 mod = __import__(name)
2059 mod = __import__(name)
2059 components = name.split('.')
2060 components = name.split('.')
2060 for comp in components[1:]:
2061 for comp in components[1:]:
2061 mod = getattr(mod, comp)
2062 mod = getattr(mod, comp)
2062 return mod
2063 return mod
2063 mod = importh(x[0])
2064 mod = importh(x[0])
2064 external.append(mod)
2065 external.append(mod)
2065 for x in external:
2066 for x in external:
2066 for t in x.cmdtable:
2067 for t in x.cmdtable:
2067 if t in table:
2068 if t in table:
2068 u.warn("module %s override %s\n" % (x.__name__, t))
2069 u.warn("module %s override %s\n" % (x.__name__, t))
2069 table.update(x.cmdtable)
2070 table.update(x.cmdtable)
2070
2071
2071 try:
2072 try:
2072 cmd, func, args, options, cmdoptions = parse(args)
2073 cmd, func, args, options, cmdoptions = parse(args)
2073 except ParseError, inst:
2074 except ParseError, inst:
2074 if inst.args[0]:
2075 if inst.args[0]:
2075 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
2076 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
2076 help_(u, inst.args[0])
2077 help_(u, inst.args[0])
2077 else:
2078 else:
2078 u.warn("hg: %s\n" % inst.args[1])
2079 u.warn("hg: %s\n" % inst.args[1])
2079 help_(u, 'shortlist')
2080 help_(u, 'shortlist')
2080 sys.exit(-1)
2081 sys.exit(-1)
2081 except UnknownCommand, inst:
2082 except UnknownCommand, inst:
2082 u.warn("hg: unknown command '%s'\n" % inst.args[0])
2083 u.warn("hg: unknown command '%s'\n" % inst.args[0])
2083 help_(u, 'shortlist')
2084 help_(u, 'shortlist')
2084 sys.exit(1)
2085 sys.exit(1)
2085
2086
2086 if options["time"]:
2087 if options["time"]:
2087 def get_times():
2088 def get_times():
2088 t = os.times()
2089 t = os.times()
2089 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
2090 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
2090 t = (t[0], t[1], t[2], t[3], time.clock())
2091 t = (t[0], t[1], t[2], t[3], time.clock())
2091 return t
2092 return t
2092 s = get_times()
2093 s = get_times()
2093 def print_time():
2094 def print_time():
2094 t = get_times()
2095 t = get_times()
2095 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
2096 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
2096 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
2097 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
2097 atexit.register(print_time)
2098 atexit.register(print_time)
2098
2099
2099 u.updateopts(options["verbose"], options["debug"], options["quiet"],
2100 u.updateopts(options["verbose"], options["debug"], options["quiet"],
2100 not options["noninteractive"])
2101 not options["noninteractive"])
2101
2102
2102 # enter the debugger before command execution
2103 # enter the debugger before command execution
2103 if options['debugger']:
2104 if options['debugger']:
2104 pdb.set_trace()
2105 pdb.set_trace()
2105
2106
2106 try:
2107 try:
2107 try:
2108 try:
2108 if options['help']:
2109 if options['help']:
2109 help_(u, cmd, options['version'])
2110 help_(u, cmd, options['version'])
2110 sys.exit(0)
2111 sys.exit(0)
2111 elif options['version']:
2112 elif options['version']:
2112 show_version(u)
2113 show_version(u)
2113 sys.exit(0)
2114 sys.exit(0)
2114 elif not cmd:
2115 elif not cmd:
2115 help_(u, 'shortlist')
2116 help_(u, 'shortlist')
2116 sys.exit(0)
2117 sys.exit(0)
2117
2118
2118 if options['cwd']:
2119 if options['cwd']:
2119 try:
2120 try:
2120 os.chdir(options['cwd'])
2121 os.chdir(options['cwd'])
2121 except OSError, inst:
2122 except OSError, inst:
2122 raise util.Abort('%s: %s' %
2123 raise util.Abort('%s: %s' %
2123 (options['cwd'], inst.strerror))
2124 (options['cwd'], inst.strerror))
2124
2125
2125 if cmd not in norepo.split():
2126 if cmd not in norepo.split():
2126 path = options["repository"] or ""
2127 path = options["repository"] or ""
2127 repo = hg.repository(ui=u, path=path)
2128 repo = hg.repository(ui=u, path=path)
2128 for x in external:
2129 for x in external:
2129 x.reposetup(u, repo)
2130 x.reposetup(u, repo)
2130 d = lambda: func(u, repo, *args, **cmdoptions)
2131 d = lambda: func(u, repo, *args, **cmdoptions)
2131 else:
2132 else:
2132 d = lambda: func(u, *args, **cmdoptions)
2133 d = lambda: func(u, *args, **cmdoptions)
2133
2134
2134 if options['profile']:
2135 if options['profile']:
2135 import hotshot, hotshot.stats
2136 import hotshot, hotshot.stats
2136 prof = hotshot.Profile("hg.prof")
2137 prof = hotshot.Profile("hg.prof")
2137 r = prof.runcall(d)
2138 r = prof.runcall(d)
2138 prof.close()
2139 prof.close()
2139 stats = hotshot.stats.load("hg.prof")
2140 stats = hotshot.stats.load("hg.prof")
2140 stats.strip_dirs()
2141 stats.strip_dirs()
2141 stats.sort_stats('time', 'calls')
2142 stats.sort_stats('time', 'calls')
2142 stats.print_stats(40)
2143 stats.print_stats(40)
2143 return r
2144 return r
2144 else:
2145 else:
2145 return d()
2146 return d()
2146 except:
2147 except:
2147 # enter the debugger when we hit an exception
2148 # enter the debugger when we hit an exception
2148 if options['debugger']:
2149 if options['debugger']:
2149 pdb.post_mortem(sys.exc_info()[2])
2150 pdb.post_mortem(sys.exc_info()[2])
2150 if options['traceback']:
2151 if options['traceback']:
2151 traceback.print_exc()
2152 traceback.print_exc()
2152 raise
2153 raise
2153 except hg.RepoError, inst:
2154 except hg.RepoError, inst:
2154 u.warn("abort: ", inst, "!\n")
2155 u.warn("abort: ", inst, "!\n")
2155 except revlog.RevlogError, inst:
2156 except revlog.RevlogError, inst:
2156 u.warn("abort: ", inst, "!\n")
2157 u.warn("abort: ", inst, "!\n")
2157 except SignalInterrupt:
2158 except SignalInterrupt:
2158 u.warn("killed!\n")
2159 u.warn("killed!\n")
2159 except KeyboardInterrupt:
2160 except KeyboardInterrupt:
2160 try:
2161 try:
2161 u.warn("interrupted!\n")
2162 u.warn("interrupted!\n")
2162 except IOError, inst:
2163 except IOError, inst:
2163 if inst.errno == errno.EPIPE:
2164 if inst.errno == errno.EPIPE:
2164 if u.debugflag:
2165 if u.debugflag:
2165 u.warn("\nbroken pipe\n")
2166 u.warn("\nbroken pipe\n")
2166 else:
2167 else:
2167 raise
2168 raise
2168 except IOError, inst:
2169 except IOError, inst:
2169 if hasattr(inst, "code"):
2170 if hasattr(inst, "code"):
2170 u.warn("abort: %s\n" % inst)
2171 u.warn("abort: %s\n" % inst)
2171 elif hasattr(inst, "reason"):
2172 elif hasattr(inst, "reason"):
2172 u.warn("abort: error: %s\n" % inst.reason[1])
2173 u.warn("abort: error: %s\n" % inst.reason[1])
2173 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
2174 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
2174 if u.debugflag:
2175 if u.debugflag:
2175 u.warn("broken pipe\n")
2176 u.warn("broken pipe\n")
2176 else:
2177 else:
2177 raise
2178 raise
2178 except OSError, inst:
2179 except OSError, inst:
2179 if hasattr(inst, "filename"):
2180 if hasattr(inst, "filename"):
2180 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
2181 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
2181 else:
2182 else:
2182 u.warn("abort: %s\n" % inst.strerror)
2183 u.warn("abort: %s\n" % inst.strerror)
2183 except util.Abort, inst:
2184 except util.Abort, inst:
2184 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
2185 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
2185 sys.exit(1)
2186 sys.exit(1)
2186 except TypeError, inst:
2187 except TypeError, inst:
2187 # was this an argument error?
2188 # was this an argument error?
2188 tb = traceback.extract_tb(sys.exc_info()[2])
2189 tb = traceback.extract_tb(sys.exc_info()[2])
2189 if len(tb) > 2: # no
2190 if len(tb) > 2: # no
2190 raise
2191 raise
2191 u.debug(inst, "\n")
2192 u.debug(inst, "\n")
2192 u.warn("%s: invalid arguments\n" % cmd)
2193 u.warn("%s: invalid arguments\n" % cmd)
2193 help_(u, cmd)
2194 help_(u, cmd)
2194 except UnknownCommand, inst:
2195 except UnknownCommand, inst:
2195 u.warn("hg: unknown command '%s'\n" % inst.args[0])
2196 u.warn("hg: unknown command '%s'\n" % inst.args[0])
2196 help_(u, 'shortlist')
2197 help_(u, 'shortlist')
2197 except SystemExit:
2198 except SystemExit:
2198 # don't catch this in the catch-all below
2199 # don't catch this in the catch-all below
2199 raise
2200 raise
2200 except:
2201 except:
2201 u.warn("** unknown exception encountered, details follow\n")
2202 u.warn("** unknown exception encountered, details follow\n")
2202 u.warn("** report bug details to mercurial@selenic.com\n")
2203 u.warn("** report bug details to mercurial@selenic.com\n")
2203 raise
2204 raise
2204
2205
2205 sys.exit(-1)
2206 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now