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