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