##// END OF EJS Templates
Get addremove to use new walk code....
Bryan O'Sullivan -
r766:b444a7e0 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 [options] [files ...]::
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, --message <text> use <text> as commit message
115 -m, --message <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 -m -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 -m <text> -d <datecode> -u <user>] <name> [revision]::
345 tag [-l -m <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 -m, --message <text> message for tag commit log entry
361 -m, --message <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,1366 +1,1365 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, *pats, **opts):
333 """add all new files, delete all missing files"""
333 """add all new files, delete all missing files"""
334 if files:
334 q = dict(zip(pats, pats))
335 files = relpath(repo, files)
335 cwd = repo.getcwd()
336 d = []
336 n = (cwd and len(cwd) + 1) or 0
337 u = []
337 c, a, d, u = repo.changes(match = matchpats(cwd, pats, opts))
338 for f in files:
338 for f in u:
339 p = repo.wjoin(f)
339 if f not in q:
340 s = repo.dirstate.state(f)
340 ui.status('adding %s\n' % f[n:])
341 isfile = os.path.isfile(p)
342 if s != 'r' and not isfile:
343 d.append(f)
344 elif s not in 'nmai' and isfile:
345 u.append(f)
346 else:
347 (c, a, d, u) = repo.changes()
348 repo.add(u)
341 repo.add(u)
342 for f in d:
343 if f not in q:
344 ui.status('removing %s\n' % f[n:])
349 repo.remove(d)
345 repo.remove(d)
350
346
351 def annotate(ui, repo, *pats, **opts):
347 def annotate(ui, repo, *pats, **opts):
352 """show changeset information per file line"""
348 """show changeset information per file line"""
353 def getnode(rev):
349 def getnode(rev):
354 return hg.short(repo.changelog.node(rev))
350 return hg.short(repo.changelog.node(rev))
355
351
356 def getname(rev):
352 def getname(rev):
357 try:
353 try:
358 return bcache[rev]
354 return bcache[rev]
359 except KeyError:
355 except KeyError:
360 cl = repo.changelog.read(repo.changelog.node(rev))
356 cl = repo.changelog.read(repo.changelog.node(rev))
361 name = cl[1]
357 name = cl[1]
362 f = name.find('@')
358 f = name.find('@')
363 if f >= 0:
359 if f >= 0:
364 name = name[:f]
360 name = name[:f]
365 f = name.find('<')
361 f = name.find('<')
366 if f >= 0:
362 if f >= 0:
367 name = name[f+1:]
363 name = name[f+1:]
368 bcache[rev] = name
364 bcache[rev] = name
369 return name
365 return name
370
366
371 if not pats:
367 if not pats:
372 raise Abort('at least one file name or pattern required')
368 raise Abort('at least one file name or pattern required')
373
369
374 bcache = {}
370 bcache = {}
375 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
371 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
376 if not opts['user'] and not opts['changeset']:
372 if not opts['user'] and not opts['changeset']:
377 opts['number'] = 1
373 opts['number'] = 1
378
374
379 if opts['rev']:
375 if opts['rev']:
380 node = repo.changelog.lookup(opts['rev'])
376 node = repo.changelog.lookup(opts['rev'])
381 else:
377 else:
382 node = repo.dirstate.parents()[0]
378 node = repo.dirstate.parents()[0]
383 change = repo.changelog.read(node)
379 change = repo.changelog.read(node)
384 mmap = repo.manifest.read(change[0])
380 mmap = repo.manifest.read(change[0])
385 for src, abs, rel in walk(repo, pats, opts):
381 for src, abs, rel in walk(repo, pats, opts):
386 lines = repo.file(abs).annotate(mmap[abs])
382 lines = repo.file(abs).annotate(mmap[abs])
387 pieces = []
383 pieces = []
388
384
389 for o, f in opmap:
385 for o, f in opmap:
390 if opts[o]:
386 if opts[o]:
391 l = [f(n) for n, dummy in lines]
387 l = [f(n) for n, dummy in lines]
392 m = max(map(len, l))
388 m = max(map(len, l))
393 pieces.append(["%*s" % (m, x) for x in l])
389 pieces.append(["%*s" % (m, x) for x in l])
394
390
395 for p, l in zip(zip(*pieces), lines):
391 for p, l in zip(zip(*pieces), lines):
396 ui.write("%s: %s" % (" ".join(p), l[1]))
392 ui.write("%s: %s" % (" ".join(p), l[1]))
397
393
398 def cat(ui, repo, file1, rev=None, **opts):
394 def cat(ui, repo, file1, rev=None, **opts):
399 """output the latest or given revision of a file"""
395 """output the latest or given revision of a file"""
400 r = repo.file(relpath(repo, [file1])[0])
396 r = repo.file(relpath(repo, [file1])[0])
401 if rev:
397 if rev:
402 n = r.lookup(rev)
398 n = r.lookup(rev)
403 else:
399 else:
404 n = r.tip()
400 n = r.tip()
405 fp = make_file(repo, r, opts['output'], node=n)
401 fp = make_file(repo, r, opts['output'], node=n)
406 fp.write(r.read(n))
402 fp.write(r.read(n))
407
403
408 def clone(ui, source, dest=None, **opts):
404 def clone(ui, source, dest=None, **opts):
409 """make a copy of an existing repository"""
405 """make a copy of an existing repository"""
410 if dest is None:
406 if dest is None:
411 dest = os.path.basename(os.path.normpath(source))
407 dest = os.path.basename(os.path.normpath(source))
412
408
413 if os.path.exists(dest):
409 if os.path.exists(dest):
414 ui.warn("abort: destination '%s' already exists\n" % dest)
410 ui.warn("abort: destination '%s' already exists\n" % dest)
415 return 1
411 return 1
416
412
417 class Dircleanup:
413 class Dircleanup:
418 def __init__(self, dir_):
414 def __init__(self, dir_):
419 self.rmtree = shutil.rmtree
415 self.rmtree = shutil.rmtree
420 self.dir_ = dir_
416 self.dir_ = dir_
421 os.mkdir(dir_)
417 os.mkdir(dir_)
422 def close(self):
418 def close(self):
423 self.dir_ = None
419 self.dir_ = None
424 def __del__(self):
420 def __del__(self):
425 if self.dir_:
421 if self.dir_:
426 self.rmtree(self.dir_, True)
422 self.rmtree(self.dir_, True)
427
423
428 d = Dircleanup(dest)
424 d = Dircleanup(dest)
429 abspath = source
425 abspath = source
430 source = ui.expandpath(source)
426 source = ui.expandpath(source)
431 other = hg.repository(ui, source)
427 other = hg.repository(ui, source)
432
428
433 if other.dev() != -1:
429 if other.dev() != -1:
434 abspath = os.path.abspath(source)
430 abspath = os.path.abspath(source)
435 copyfile = (os.stat(dest).st_dev == other.dev()
431 copyfile = (os.stat(dest).st_dev == other.dev()
436 and getattr(os, 'link', None) or shutil.copy2)
432 and getattr(os, 'link', None) or shutil.copy2)
437 if copyfile is not shutil.copy2:
433 if copyfile is not shutil.copy2:
438 ui.note("cloning by hardlink\n")
434 ui.note("cloning by hardlink\n")
439 util.copytree(os.path.join(source, ".hg"), os.path.join(dest, ".hg"),
435 util.copytree(os.path.join(source, ".hg"), os.path.join(dest, ".hg"),
440 copyfile)
436 copyfile)
441 try:
437 try:
442 os.unlink(os.path.join(dest, ".hg", "dirstate"))
438 os.unlink(os.path.join(dest, ".hg", "dirstate"))
443 except IOError:
439 except IOError:
444 pass
440 pass
445
441
446 repo = hg.repository(ui, dest)
442 repo = hg.repository(ui, dest)
447
443
448 else:
444 else:
449 repo = hg.repository(ui, dest, create=1)
445 repo = hg.repository(ui, dest, create=1)
450 repo.pull(other)
446 repo.pull(other)
451
447
452 f = repo.opener("hgrc", "w")
448 f = repo.opener("hgrc", "w")
453 f.write("[paths]\n")
449 f.write("[paths]\n")
454 f.write("default = %s\n" % abspath)
450 f.write("default = %s\n" % abspath)
455
451
456 if not opts['noupdate']:
452 if not opts['noupdate']:
457 update(ui, repo)
453 update(ui, repo)
458
454
459 d.close()
455 d.close()
460
456
461 def commit(ui, repo, *files, **opts):
457 def commit(ui, repo, *files, **opts):
462 """commit the specified files or all outstanding changes"""
458 """commit the specified files or all outstanding changes"""
463 if opts['text']:
459 if opts['text']:
464 ui.warn("Warning: -t and --text is deprecated,"
460 ui.warn("Warning: -t and --text is deprecated,"
465 " please use -m or --message instead.\n")
461 " please use -m or --message instead.\n")
466 message = opts['message'] or opts['text']
462 message = opts['message'] or opts['text']
467 logfile = opts['logfile']
463 logfile = opts['logfile']
468 if not message and logfile:
464 if not message and logfile:
469 try:
465 try:
470 message = open(logfile).read()
466 message = open(logfile).read()
471 except IOError, why:
467 except IOError, why:
472 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
468 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
473
469
474 if opts['addremove']:
470 if opts['addremove']:
475 addremove(ui, repo, *files)
471 addremove(ui, repo, *files)
476 repo.commit(relpath(repo, files), message, opts['user'], opts['date'])
472 repo.commit(relpath(repo, files), message, opts['user'], opts['date'])
477
473
478 def copy(ui, repo, source, dest):
474 def copy(ui, repo, source, dest):
479 """mark a file as copied or renamed for the next commit"""
475 """mark a file as copied or renamed for the next commit"""
480 return repo.copy(*relpath(repo, (source, dest)))
476 return repo.copy(*relpath(repo, (source, dest)))
481
477
482 def debugcheckstate(ui, repo):
478 def debugcheckstate(ui, repo):
483 """validate the correctness of the current dirstate"""
479 """validate the correctness of the current dirstate"""
484 parent1, parent2 = repo.dirstate.parents()
480 parent1, parent2 = repo.dirstate.parents()
485 repo.dirstate.read()
481 repo.dirstate.read()
486 dc = repo.dirstate.map
482 dc = repo.dirstate.map
487 keys = dc.keys()
483 keys = dc.keys()
488 keys.sort()
484 keys.sort()
489 m1n = repo.changelog.read(parent1)[0]
485 m1n = repo.changelog.read(parent1)[0]
490 m2n = repo.changelog.read(parent2)[0]
486 m2n = repo.changelog.read(parent2)[0]
491 m1 = repo.manifest.read(m1n)
487 m1 = repo.manifest.read(m1n)
492 m2 = repo.manifest.read(m2n)
488 m2 = repo.manifest.read(m2n)
493 errors = 0
489 errors = 0
494 for f in dc:
490 for f in dc:
495 state = repo.dirstate.state(f)
491 state = repo.dirstate.state(f)
496 if state in "nr" and f not in m1:
492 if state in "nr" and f not in m1:
497 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
493 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
498 errors += 1
494 errors += 1
499 if state in "a" and f in m1:
495 if state in "a" and f in m1:
500 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
496 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
501 errors += 1
497 errors += 1
502 if state in "m" and f not in m1 and f not in m2:
498 if state in "m" and f not in m1 and f not in m2:
503 ui.warn("%s in state %s, but not in either manifest\n" %
499 ui.warn("%s in state %s, but not in either manifest\n" %
504 (f, state))
500 (f, state))
505 errors += 1
501 errors += 1
506 for f in m1:
502 for f in m1:
507 state = repo.dirstate.state(f)
503 state = repo.dirstate.state(f)
508 if state not in "nrm":
504 if state not in "nrm":
509 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
505 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
510 errors += 1
506 errors += 1
511 if errors:
507 if errors:
512 raise Abort(".hg/dirstate inconsistent with current parent's manifest")
508 raise Abort(".hg/dirstate inconsistent with current parent's manifest")
513
509
514 def debugstate(ui, repo):
510 def debugstate(ui, repo):
515 """show the contents of the current dirstate"""
511 """show the contents of the current dirstate"""
516 repo.dirstate.read()
512 repo.dirstate.read()
517 dc = repo.dirstate.map
513 dc = repo.dirstate.map
518 keys = dc.keys()
514 keys = dc.keys()
519 keys.sort()
515 keys.sort()
520 for file_ in keys:
516 for file_ in keys:
521 ui.write("%c %s\n" % (dc[file_][0], file_))
517 ui.write("%c %s\n" % (dc[file_][0], file_))
522
518
523 def debugindex(ui, file_):
519 def debugindex(ui, file_):
524 """dump the contents of an index file"""
520 """dump the contents of an index file"""
525 r = hg.revlog(hg.opener(""), file_, "")
521 r = hg.revlog(hg.opener(""), file_, "")
526 ui.write(" rev offset length base linkrev" +
522 ui.write(" rev offset length base linkrev" +
527 " p1 p2 nodeid\n")
523 " p1 p2 nodeid\n")
528 for i in range(r.count()):
524 for i in range(r.count()):
529 e = r.index[i]
525 e = r.index[i]
530 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
526 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
531 i, e[0], e[1], e[2], e[3],
527 i, e[0], e[1], e[2], e[3],
532 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
528 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
533
529
534 def debugindexdot(ui, file_):
530 def debugindexdot(ui, file_):
535 """dump an index DAG as a .dot file"""
531 """dump an index DAG as a .dot file"""
536 r = hg.revlog(hg.opener(""), file_, "")
532 r = hg.revlog(hg.opener(""), file_, "")
537 ui.write("digraph G {\n")
533 ui.write("digraph G {\n")
538 for i in range(r.count()):
534 for i in range(r.count()):
539 e = r.index[i]
535 e = r.index[i]
540 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
536 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
541 if e[5] != hg.nullid:
537 if e[5] != hg.nullid:
542 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
538 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
543 ui.write("}\n")
539 ui.write("}\n")
544
540
545 def diff(ui, repo, *pats, **opts):
541 def diff(ui, repo, *pats, **opts):
546 """diff working directory (or selected files)"""
542 """diff working directory (or selected files)"""
547 revs = []
543 revs = []
548 if opts['rev']:
544 if opts['rev']:
549 revs = map(lambda x: repo.lookup(x), opts['rev'])
545 revs = map(lambda x: repo.lookup(x), opts['rev'])
550
546
551 if len(revs) > 2:
547 if len(revs) > 2:
552 raise Abort("too many revisions to diff")
548 raise Abort("too many revisions to diff")
553
549
554 files = []
550 files = []
555 for src, abs, rel in walk(repo, pats, opts):
551 for src, abs, rel in walk(repo, pats, opts):
556 files.append(abs)
552 files.append(abs)
557 dodiff(sys.stdout, ui, repo, files, *revs)
553 dodiff(sys.stdout, ui, repo, files, *revs)
558
554
559 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
555 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
560 node = repo.lookup(changeset)
556 node = repo.lookup(changeset)
561 prev, other = repo.changelog.parents(node)
557 prev, other = repo.changelog.parents(node)
562 change = repo.changelog.read(node)
558 change = repo.changelog.read(node)
563
559
564 fp = make_file(repo, repo.changelog, opts['output'],
560 fp = make_file(repo, repo.changelog, opts['output'],
565 node=node, total=total, seqno=seqno,
561 node=node, total=total, seqno=seqno,
566 revwidth=revwidth)
562 revwidth=revwidth)
567 if fp != sys.stdout:
563 if fp != sys.stdout:
568 ui.note("%s\n" % fp.name)
564 ui.note("%s\n" % fp.name)
569
565
570 fp.write("# HG changeset patch\n")
566 fp.write("# HG changeset patch\n")
571 fp.write("# User %s\n" % change[1])
567 fp.write("# User %s\n" % change[1])
572 fp.write("# Node ID %s\n" % hg.hex(node))
568 fp.write("# Node ID %s\n" % hg.hex(node))
573 fp.write("# Parent %s\n" % hg.hex(prev))
569 fp.write("# Parent %s\n" % hg.hex(prev))
574 if other != hg.nullid:
570 if other != hg.nullid:
575 fp.write("# Parent %s\n" % hg.hex(other))
571 fp.write("# Parent %s\n" % hg.hex(other))
576 fp.write(change[4].rstrip())
572 fp.write(change[4].rstrip())
577 fp.write("\n\n")
573 fp.write("\n\n")
578
574
579 dodiff(fp, ui, repo, None, prev, node)
575 dodiff(fp, ui, repo, None, prev, node)
580 if fp != sys.stdout: fp.close()
576 if fp != sys.stdout: fp.close()
581
577
582 def export(ui, repo, *changesets, **opts):
578 def export(ui, repo, *changesets, **opts):
583 """dump the header and diffs for one or more changesets"""
579 """dump the header and diffs for one or more changesets"""
584 if not changesets:
580 if not changesets:
585 raise Abort("export requires at least one changeset")
581 raise Abort("export requires at least one changeset")
586 seqno = 0
582 seqno = 0
587 revs = list(revrange(ui, repo, changesets))
583 revs = list(revrange(ui, repo, changesets))
588 total = len(revs)
584 total = len(revs)
589 revwidth = max(len(revs[0]), len(revs[-1]))
585 revwidth = max(len(revs[0]), len(revs[-1]))
590 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
586 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
591 for cset in revs:
587 for cset in revs:
592 seqno += 1
588 seqno += 1
593 doexport(ui, repo, cset, seqno, total, revwidth, opts)
589 doexport(ui, repo, cset, seqno, total, revwidth, opts)
594
590
595 def forget(ui, repo, file1, *files):
591 def forget(ui, repo, file1, *files):
596 """don't add the specified files on the next commit"""
592 """don't add the specified files on the next commit"""
597 repo.forget(relpath(repo, (file1,) + files))
593 repo.forget(relpath(repo, (file1,) + files))
598
594
599 def heads(ui, repo):
595 def heads(ui, repo):
600 """show current repository heads"""
596 """show current repository heads"""
601 for n in repo.changelog.heads():
597 for n in repo.changelog.heads():
602 show_changeset(ui, repo, changenode=n)
598 show_changeset(ui, repo, changenode=n)
603
599
604 def identify(ui, repo):
600 def identify(ui, repo):
605 """print information about the working copy"""
601 """print information about the working copy"""
606 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]
607 if not parents:
603 if not parents:
608 ui.write("unknown\n")
604 ui.write("unknown\n")
609 return
605 return
610
606
611 hexfunc = ui.verbose and hg.hex or hg.short
607 hexfunc = ui.verbose and hg.hex or hg.short
612 (c, a, d, u) = repo.changes()
608 (c, a, d, u) = repo.changes()
613 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
609 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
614 (c or a or d) and "+" or "")]
610 (c or a or d) and "+" or "")]
615
611
616 if not ui.quiet:
612 if not ui.quiet:
617 # multiple tags for a single parent separated by '/'
613 # multiple tags for a single parent separated by '/'
618 parenttags = ['/'.join(tags)
614 parenttags = ['/'.join(tags)
619 for tags in map(repo.nodetags, parents) if tags]
615 for tags in map(repo.nodetags, parents) if tags]
620 # tags for multiple parents separated by ' + '
616 # tags for multiple parents separated by ' + '
621 if parenttags:
617 if parenttags:
622 output.append(' + '.join(parenttags))
618 output.append(' + '.join(parenttags))
623
619
624 ui.write("%s\n" % ' '.join(output))
620 ui.write("%s\n" % ' '.join(output))
625
621
626 def import_(ui, repo, patch1, *patches, **opts):
622 def import_(ui, repo, patch1, *patches, **opts):
627 """import an ordered set of patches"""
623 """import an ordered set of patches"""
628 try:
624 try:
629 import psyco
625 import psyco
630 psyco.full()
626 psyco.full()
631 except ImportError:
627 except ImportError:
632 pass
628 pass
633
629
634 patches = (patch1,) + patches
630 patches = (patch1,) + patches
635
631
636 d = opts["base"]
632 d = opts["base"]
637 strip = opts["strip"]
633 strip = opts["strip"]
638
634
639 for patch in patches:
635 for patch in patches:
640 ui.status("applying %s\n" % patch)
636 ui.status("applying %s\n" % patch)
641 pf = os.path.join(d, patch)
637 pf = os.path.join(d, patch)
642
638
643 message = []
639 message = []
644 user = None
640 user = None
645 hgpatch = False
641 hgpatch = False
646 for line in file(pf):
642 for line in file(pf):
647 line = line.rstrip()
643 line = line.rstrip()
648 if line.startswith("--- ") or line.startswith("diff -r"):
644 if line.startswith("--- ") or line.startswith("diff -r"):
649 break
645 break
650 elif hgpatch:
646 elif hgpatch:
651 # parse values when importing the result of an hg export
647 # parse values when importing the result of an hg export
652 if line.startswith("# User "):
648 if line.startswith("# User "):
653 user = line[7:]
649 user = line[7:]
654 ui.debug('User: %s\n' % user)
650 ui.debug('User: %s\n' % user)
655 elif not line.startswith("# ") and line:
651 elif not line.startswith("# ") and line:
656 message.append(line)
652 message.append(line)
657 hgpatch = False
653 hgpatch = False
658 elif line == '# HG changeset patch':
654 elif line == '# HG changeset patch':
659 hgpatch = True
655 hgpatch = True
660 else:
656 else:
661 message.append(line)
657 message.append(line)
662
658
663 # make sure message isn't empty
659 # make sure message isn't empty
664 if not message:
660 if not message:
665 message = "imported patch %s\n" % patch
661 message = "imported patch %s\n" % patch
666 else:
662 else:
667 message = "%s\n" % '\n'.join(message)
663 message = "%s\n" % '\n'.join(message)
668 ui.debug('message:\n%s\n' % message)
664 ui.debug('message:\n%s\n' % message)
669
665
670 f = os.popen("patch -p%d < %s" % (strip, pf))
666 f = os.popen("patch -p%d < %s" % (strip, pf))
671 files = []
667 files = []
672 for l in f.read().splitlines():
668 for l in f.read().splitlines():
673 l.rstrip('\r\n');
669 l.rstrip('\r\n');
674 ui.status("%s\n" % l)
670 ui.status("%s\n" % l)
675 if l.startswith('patching file '):
671 if l.startswith('patching file '):
676 pf = l[14:]
672 pf = l[14:]
677 if pf not in files:
673 if pf not in files:
678 files.append(pf)
674 files.append(pf)
679 patcherr = f.close()
675 patcherr = f.close()
680 if patcherr:
676 if patcherr:
681 raise Abort("patch failed")
677 raise Abort("patch failed")
682
678
683 if len(files) > 0:
679 if len(files) > 0:
684 addremove(ui, repo, *files)
680 addremove(ui, repo, *files)
685 repo.commit(files, message, user)
681 repo.commit(files, message, user)
686
682
687 def init(ui, source=None):
683 def init(ui, source=None):
688 """create a new repository in the current directory"""
684 """create a new repository in the current directory"""
689
685
690 if source:
686 if source:
691 raise Abort("no longer supported: use \"hg clone\" instead")
687 raise Abort("no longer supported: use \"hg clone\" instead")
692 hg.repository(ui, ".", create=1)
688 hg.repository(ui, ".", create=1)
693
689
694 def locate(ui, repo, *pats, **opts):
690 def locate(ui, repo, *pats, **opts):
695 """locate files matching specific patterns"""
691 """locate files matching specific patterns"""
696 end = '\n'
692 end = '\n'
697 if opts['print0']: end = '\0'
693 if opts['print0']: end = '\0'
698
694
699 for src, abs, rel in walk(repo, pats, opts, '(?:.*/|)'):
695 for src, abs, rel in walk(repo, pats, opts, '(?:.*/|)'):
700 if repo.dirstate.state(abs) == '?': continue
696 if repo.dirstate.state(abs) == '?': continue
701 if opts['fullpath']:
697 if opts['fullpath']:
702 ui.write(os.path.join(repo.root, abs), end)
698 ui.write(os.path.join(repo.root, abs), end)
703 else:
699 else:
704 ui.write(rel, end)
700 ui.write(rel, end)
705
701
706 def log(ui, repo, f=None, **opts):
702 def log(ui, repo, f=None, **opts):
707 """show the revision history of the repository or a single file"""
703 """show the revision history of the repository or a single file"""
708 if f:
704 if f:
709 files = relpath(repo, [f])
705 files = relpath(repo, [f])
710 filelog = repo.file(files[0])
706 filelog = repo.file(files[0])
711 log = filelog
707 log = filelog
712 lookup = filelog.lookup
708 lookup = filelog.lookup
713 else:
709 else:
714 files = None
710 files = None
715 filelog = None
711 filelog = None
716 log = repo.changelog
712 log = repo.changelog
717 lookup = repo.lookup
713 lookup = repo.lookup
718 revlist = []
714 revlist = []
719 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
715 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
720 while revs:
716 while revs:
721 if len(revs) == 1:
717 if len(revs) == 1:
722 revlist.append(revs.pop(0))
718 revlist.append(revs.pop(0))
723 else:
719 else:
724 a = revs.pop(0)
720 a = revs.pop(0)
725 b = revs.pop(0)
721 b = revs.pop(0)
726 off = a > b and -1 or 1
722 off = a > b and -1 or 1
727 revlist.extend(range(a, b + off, off))
723 revlist.extend(range(a, b + off, off))
728
724
729 for i in revlist or range(log.count() - 1, -1, -1):
725 for i in revlist or range(log.count() - 1, -1, -1):
730 show_changeset(ui, repo, filelog=filelog, rev=i)
726 show_changeset(ui, repo, filelog=filelog, rev=i)
731 if opts['patch']:
727 if opts['patch']:
732 if filelog:
728 if filelog:
733 filenode = filelog.node(i)
729 filenode = filelog.node(i)
734 i = filelog.linkrev(filenode)
730 i = filelog.linkrev(filenode)
735 changenode = repo.changelog.node(i)
731 changenode = repo.changelog.node(i)
736 prev, other = repo.changelog.parents(changenode)
732 prev, other = repo.changelog.parents(changenode)
737 dodiff(sys.stdout, ui, repo, files, prev, changenode)
733 dodiff(sys.stdout, ui, repo, files, prev, changenode)
738 ui.write("\n\n")
734 ui.write("\n\n")
739
735
740 def manifest(ui, repo, rev=None):
736 def manifest(ui, repo, rev=None):
741 """output the latest or given revision of the project manifest"""
737 """output the latest or given revision of the project manifest"""
742 if rev:
738 if rev:
743 try:
739 try:
744 # assume all revision numbers are for changesets
740 # assume all revision numbers are for changesets
745 n = repo.lookup(rev)
741 n = repo.lookup(rev)
746 change = repo.changelog.read(n)
742 change = repo.changelog.read(n)
747 n = change[0]
743 n = change[0]
748 except hg.RepoError:
744 except hg.RepoError:
749 n = repo.manifest.lookup(rev)
745 n = repo.manifest.lookup(rev)
750 else:
746 else:
751 n = repo.manifest.tip()
747 n = repo.manifest.tip()
752 m = repo.manifest.read(n)
748 m = repo.manifest.read(n)
753 mf = repo.manifest.readflags(n)
749 mf = repo.manifest.readflags(n)
754 files = m.keys()
750 files = m.keys()
755 files.sort()
751 files.sort()
756
752
757 for f in files:
753 for f in files:
758 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
754 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
759
755
760 def parents(ui, repo, rev=None):
756 def parents(ui, repo, rev=None):
761 """show the parents of the working dir or revision"""
757 """show the parents of the working dir or revision"""
762 if rev:
758 if rev:
763 p = repo.changelog.parents(repo.lookup(rev))
759 p = repo.changelog.parents(repo.lookup(rev))
764 else:
760 else:
765 p = repo.dirstate.parents()
761 p = repo.dirstate.parents()
766
762
767 for n in p:
763 for n in p:
768 if n != hg.nullid:
764 if n != hg.nullid:
769 show_changeset(ui, repo, changenode=n)
765 show_changeset(ui, repo, changenode=n)
770
766
771 def pull(ui, repo, source="default", **opts):
767 def pull(ui, repo, source="default", **opts):
772 """pull changes from the specified source"""
768 """pull changes from the specified source"""
773 source = ui.expandpath(source)
769 source = ui.expandpath(source)
774 ui.status('pulling from %s\n' % (source))
770 ui.status('pulling from %s\n' % (source))
775
771
776 other = hg.repository(ui, source)
772 other = hg.repository(ui, source)
777 r = repo.pull(other)
773 r = repo.pull(other)
778 if not r:
774 if not r:
779 if opts['update']:
775 if opts['update']:
780 return update(ui, repo)
776 return update(ui, repo)
781 else:
777 else:
782 ui.status("(run 'hg update' to get a working copy)\n")
778 ui.status("(run 'hg update' to get a working copy)\n")
783
779
784 return r
780 return r
785
781
786 def push(ui, repo, dest="default-push"):
782 def push(ui, repo, dest="default-push"):
787 """push changes to the specified destination"""
783 """push changes to the specified destination"""
788 dest = ui.expandpath(dest)
784 dest = ui.expandpath(dest)
789 ui.status('pushing to %s\n' % (dest))
785 ui.status('pushing to %s\n' % (dest))
790
786
791 other = hg.repository(ui, dest)
787 other = hg.repository(ui, dest)
792 r = repo.push(other)
788 r = repo.push(other)
793 return r
789 return r
794
790
795 def rawcommit(ui, repo, *flist, **rc):
791 def rawcommit(ui, repo, *flist, **rc):
796 "raw commit interface"
792 "raw commit interface"
797 if rc['text']:
793 if rc['text']:
798 ui.warn("Warning: -t and --text is deprecated,"
794 ui.warn("Warning: -t and --text is deprecated,"
799 " please use -m or --message instead.\n")
795 " please use -m or --message instead.\n")
800 message = rc['message'] or rc['text']
796 message = rc['message'] or rc['text']
801 if not message and rc['logfile']:
797 if not message and rc['logfile']:
802 try:
798 try:
803 message = open(rc['logfile']).read()
799 message = open(rc['logfile']).read()
804 except IOError:
800 except IOError:
805 pass
801 pass
806 if not message and not rc['logfile']:
802 if not message and not rc['logfile']:
807 ui.warn("abort: missing commit message\n")
803 ui.warn("abort: missing commit message\n")
808 return 1
804 return 1
809
805
810 files = relpath(repo, list(flist))
806 files = relpath(repo, list(flist))
811 if rc['files']:
807 if rc['files']:
812 files += open(rc['files']).read().splitlines()
808 files += open(rc['files']).read().splitlines()
813
809
814 rc['parent'] = map(repo.lookup, rc['parent'])
810 rc['parent'] = map(repo.lookup, rc['parent'])
815
811
816 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
812 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
817
813
818 def recover(ui, repo):
814 def recover(ui, repo):
819 """roll back an interrupted transaction"""
815 """roll back an interrupted transaction"""
820 repo.recover()
816 repo.recover()
821
817
822 def remove(ui, repo, file1, *files):
818 def remove(ui, repo, file1, *files):
823 """remove the specified files on the next commit"""
819 """remove the specified files on the next commit"""
824 repo.remove(relpath(repo, (file1,) + files))
820 repo.remove(relpath(repo, (file1,) + files))
825
821
826 def revert(ui, repo, *names, **opts):
822 def revert(ui, repo, *names, **opts):
827 """revert modified files or dirs back to their unmodified states"""
823 """revert modified files or dirs back to their unmodified states"""
828 node = opts['rev'] and repo.lookup(opts['rev']) or \
824 node = opts['rev'] and repo.lookup(opts['rev']) or \
829 repo.dirstate.parents()[0]
825 repo.dirstate.parents()[0]
830 root = os.path.realpath(repo.root)
826 root = os.path.realpath(repo.root)
831
827
832 def trimpath(p):
828 def trimpath(p):
833 p = os.path.realpath(p)
829 p = os.path.realpath(p)
834 if p.startswith(root):
830 if p.startswith(root):
835 rest = p[len(root):]
831 rest = p[len(root):]
836 if not rest:
832 if not rest:
837 return rest
833 return rest
838 if p.startswith(os.sep):
834 if p.startswith(os.sep):
839 return rest[1:]
835 return rest[1:]
840 return p
836 return p
841
837
842 relnames = map(trimpath, names or [os.getcwd()])
838 relnames = map(trimpath, names or [os.getcwd()])
843 chosen = {}
839 chosen = {}
844
840
845 def choose(name):
841 def choose(name):
846 def body(name):
842 def body(name):
847 for r in relnames:
843 for r in relnames:
848 if not name.startswith(r):
844 if not name.startswith(r):
849 continue
845 continue
850 rest = name[len(r):]
846 rest = name[len(r):]
851 if not rest:
847 if not rest:
852 return r, True
848 return r, True
853 depth = rest.count(os.sep)
849 depth = rest.count(os.sep)
854 if not r:
850 if not r:
855 if depth == 0 or not opts['nonrecursive']:
851 if depth == 0 or not opts['nonrecursive']:
856 return r, True
852 return r, True
857 elif rest[0] == os.sep:
853 elif rest[0] == os.sep:
858 if depth == 1 or not opts['nonrecursive']:
854 if depth == 1 or not opts['nonrecursive']:
859 return r, True
855 return r, True
860 return None, False
856 return None, False
861 relname, ret = body(name)
857 relname, ret = body(name)
862 if ret:
858 if ret:
863 chosen[relname] = 1
859 chosen[relname] = 1
864 return ret
860 return ret
865
861
866 r = repo.update(node, False, True, choose, False)
862 r = repo.update(node, False, True, choose, False)
867 for n in relnames:
863 for n in relnames:
868 if n not in chosen:
864 if n not in chosen:
869 ui.warn('error: no matches for %s\n' % n)
865 ui.warn('error: no matches for %s\n' % n)
870 r = 1
866 r = 1
871 sys.stdout.flush()
867 sys.stdout.flush()
872 return r
868 return r
873
869
874 def root(ui, repo):
870 def root(ui, repo):
875 """print the root (top) of the current working dir"""
871 """print the root (top) of the current working dir"""
876 ui.write(repo.root + "\n")
872 ui.write(repo.root + "\n")
877
873
878 def serve(ui, repo, **opts):
874 def serve(ui, repo, **opts):
879 """export the repository via HTTP"""
875 """export the repository via HTTP"""
880
876
881 if opts["stdio"]:
877 if opts["stdio"]:
882 fin, fout = sys.stdin, sys.stdout
878 fin, fout = sys.stdin, sys.stdout
883 sys.stdout = sys.stderr
879 sys.stdout = sys.stderr
884
880
885 def getarg():
881 def getarg():
886 argline = fin.readline()[:-1]
882 argline = fin.readline()[:-1]
887 arg, l = argline.split()
883 arg, l = argline.split()
888 val = fin.read(int(l))
884 val = fin.read(int(l))
889 return arg, val
885 return arg, val
890 def respond(v):
886 def respond(v):
891 fout.write("%d\n" % len(v))
887 fout.write("%d\n" % len(v))
892 fout.write(v)
888 fout.write(v)
893 fout.flush()
889 fout.flush()
894
890
895 lock = None
891 lock = None
896
892
897 while 1:
893 while 1:
898 cmd = fin.readline()[:-1]
894 cmd = fin.readline()[:-1]
899 if cmd == '':
895 if cmd == '':
900 return
896 return
901 if cmd == "heads":
897 if cmd == "heads":
902 h = repo.heads()
898 h = repo.heads()
903 respond(" ".join(map(hg.hex, h)) + "\n")
899 respond(" ".join(map(hg.hex, h)) + "\n")
904 if cmd == "lock":
900 if cmd == "lock":
905 lock = repo.lock()
901 lock = repo.lock()
906 respond("")
902 respond("")
907 if cmd == "unlock":
903 if cmd == "unlock":
908 if lock:
904 if lock:
909 lock.release()
905 lock.release()
910 lock = None
906 lock = None
911 respond("")
907 respond("")
912 elif cmd == "branches":
908 elif cmd == "branches":
913 arg, nodes = getarg()
909 arg, nodes = getarg()
914 nodes = map(hg.bin, nodes.split(" "))
910 nodes = map(hg.bin, nodes.split(" "))
915 r = []
911 r = []
916 for b in repo.branches(nodes):
912 for b in repo.branches(nodes):
917 r.append(" ".join(map(hg.hex, b)) + "\n")
913 r.append(" ".join(map(hg.hex, b)) + "\n")
918 respond("".join(r))
914 respond("".join(r))
919 elif cmd == "between":
915 elif cmd == "between":
920 arg, pairs = getarg()
916 arg, pairs = getarg()
921 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
917 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
922 r = []
918 r = []
923 for b in repo.between(pairs):
919 for b in repo.between(pairs):
924 r.append(" ".join(map(hg.hex, b)) + "\n")
920 r.append(" ".join(map(hg.hex, b)) + "\n")
925 respond("".join(r))
921 respond("".join(r))
926 elif cmd == "changegroup":
922 elif cmd == "changegroup":
927 nodes = []
923 nodes = []
928 arg, roots = getarg()
924 arg, roots = getarg()
929 nodes = map(hg.bin, roots.split(" "))
925 nodes = map(hg.bin, roots.split(" "))
930
926
931 cg = repo.changegroup(nodes)
927 cg = repo.changegroup(nodes)
932 while 1:
928 while 1:
933 d = cg.read(4096)
929 d = cg.read(4096)
934 if not d:
930 if not d:
935 break
931 break
936 fout.write(d)
932 fout.write(d)
937
933
938 fout.flush()
934 fout.flush()
939
935
940 elif cmd == "addchangegroup":
936 elif cmd == "addchangegroup":
941 if not lock:
937 if not lock:
942 respond("not locked")
938 respond("not locked")
943 continue
939 continue
944 respond("")
940 respond("")
945
941
946 r = repo.addchangegroup(fin)
942 r = repo.addchangegroup(fin)
947 respond("")
943 respond("")
948
944
949 def openlog(opt, default):
945 def openlog(opt, default):
950 if opts[opt] and opts[opt] != '-':
946 if opts[opt] and opts[opt] != '-':
951 return open(opts[opt], 'w')
947 return open(opts[opt], 'w')
952 else:
948 else:
953 return default
949 return default
954
950
955 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
951 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
956 opts["address"], opts["port"],
952 opts["address"], opts["port"],
957 openlog('accesslog', sys.stdout),
953 openlog('accesslog', sys.stdout),
958 openlog('errorlog', sys.stderr))
954 openlog('errorlog', sys.stderr))
959 if ui.verbose:
955 if ui.verbose:
960 addr, port = httpd.socket.getsockname()
956 addr, port = httpd.socket.getsockname()
961 if addr == '0.0.0.0':
957 if addr == '0.0.0.0':
962 addr = socket.gethostname()
958 addr = socket.gethostname()
963 else:
959 else:
964 try:
960 try:
965 addr = socket.gethostbyaddr(addr)[0]
961 addr = socket.gethostbyaddr(addr)[0]
966 except socket.error:
962 except socket.error:
967 pass
963 pass
968 if port != 80:
964 if port != 80:
969 ui.status('listening at http://%s:%d/\n' % (addr, port))
965 ui.status('listening at http://%s:%d/\n' % (addr, port))
970 else:
966 else:
971 ui.status('listening at http://%s/\n' % addr)
967 ui.status('listening at http://%s/\n' % addr)
972 httpd.serve_forever()
968 httpd.serve_forever()
973
969
974 def status(ui, repo, *pats, **opts):
970 def status(ui, repo, *pats, **opts):
975 '''show changed files in the working directory
971 '''show changed files in the working directory
976
972
977 M = modified
973 M = modified
978 A = added
974 A = added
979 R = removed
975 R = removed
980 ? = not tracked'''
976 ? = not tracked'''
981
977
982 (c, a, d, u) = repo.changes(match = matchpats(repo.getcwd(), pats, opts))
978 (c, a, d, u) = repo.changes(match = matchpats(repo.getcwd(), pats, opts))
983 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
979 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
984
980
985 for f in c:
981 for f in c:
986 ui.write("M ", f, "\n")
982 ui.write("M ", f, "\n")
987 for f in a:
983 for f in a:
988 ui.write("A ", f, "\n")
984 ui.write("A ", f, "\n")
989 for f in d:
985 for f in d:
990 ui.write("R ", f, "\n")
986 ui.write("R ", f, "\n")
991 for f in u:
987 for f in u:
992 ui.write("? ", f, "\n")
988 ui.write("? ", f, "\n")
993
989
994 def tag(ui, repo, name, rev=None, **opts):
990 def tag(ui, repo, name, rev=None, **opts):
995 """add a tag for the current tip or a given revision"""
991 """add a tag for the current tip or a given revision"""
996 if opts['text']:
992 if opts['text']:
997 ui.warn("Warning: -t and --text is deprecated,"
993 ui.warn("Warning: -t and --text is deprecated,"
998 " please use -m or --message instead.\n")
994 " please use -m or --message instead.\n")
999 if name == "tip":
995 if name == "tip":
1000 ui.warn("abort: 'tip' is a reserved name!\n")
996 ui.warn("abort: 'tip' is a reserved name!\n")
1001 return -1
997 return -1
1002 if rev:
998 if rev:
1003 r = hg.hex(repo.lookup(rev))
999 r = hg.hex(repo.lookup(rev))
1004 else:
1000 else:
1005 r = hg.hex(repo.changelog.tip())
1001 r = hg.hex(repo.changelog.tip())
1006
1002
1007 if name.find(revrangesep) >= 0:
1003 if name.find(revrangesep) >= 0:
1008 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1004 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1009 return -1
1005 return -1
1010
1006
1011 if opts['local']:
1007 if opts['local']:
1012 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1008 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1013 return
1009 return
1014
1010
1015 (c, a, d, u) = repo.changes()
1011 (c, a, d, u) = repo.changes()
1016 for x in (c, a, d, u):
1012 for x in (c, a, d, u):
1017 if ".hgtags" in x:
1013 if ".hgtags" in x:
1018 ui.warn("abort: working copy of .hgtags is changed!\n")
1014 ui.warn("abort: working copy of .hgtags is changed!\n")
1019 ui.status("(please commit .hgtags manually)\n")
1015 ui.status("(please commit .hgtags manually)\n")
1020 return -1
1016 return -1
1021
1017
1022 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1018 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1023 if repo.dirstate.state(".hgtags") == '?':
1019 if repo.dirstate.state(".hgtags") == '?':
1024 repo.add([".hgtags"])
1020 repo.add([".hgtags"])
1025
1021
1026 message = (opts['message'] or opts['text'] or
1022 message = (opts['message'] or opts['text'] or
1027 "Added tag %s for changeset %s" % (name, r))
1023 "Added tag %s for changeset %s" % (name, r))
1028 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1024 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1029
1025
1030 def tags(ui, repo):
1026 def tags(ui, repo):
1031 """list repository tags"""
1027 """list repository tags"""
1032
1028
1033 l = repo.tagslist()
1029 l = repo.tagslist()
1034 l.reverse()
1030 l.reverse()
1035 for t, n in l:
1031 for t, n in l:
1036 try:
1032 try:
1037 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1033 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1038 except KeyError:
1034 except KeyError:
1039 r = " ?:?"
1035 r = " ?:?"
1040 ui.write("%-30s %s\n" % (t, r))
1036 ui.write("%-30s %s\n" % (t, r))
1041
1037
1042 def tip(ui, repo):
1038 def tip(ui, repo):
1043 """show the tip revision"""
1039 """show the tip revision"""
1044 n = repo.changelog.tip()
1040 n = repo.changelog.tip()
1045 show_changeset(ui, repo, changenode=n)
1041 show_changeset(ui, repo, changenode=n)
1046
1042
1047 def undo(ui, repo):
1043 def undo(ui, repo):
1048 """undo the last commit or pull
1044 """undo the last commit or pull
1049
1045
1050 Roll back the last pull or commit transaction on the
1046 Roll back the last pull or commit transaction on the
1051 repository, restoring the project to its earlier state.
1047 repository, restoring the project to its earlier state.
1052
1048
1053 This command should be used with care. There is only one level of
1049 This command should be used with care. There is only one level of
1054 undo and there is no redo.
1050 undo and there is no redo.
1055
1051
1056 This command is not intended for use on public repositories. Once
1052 This command is not intended for use on public repositories. Once
1057 a change is visible for pull by other users, undoing it locally is
1053 a change is visible for pull by other users, undoing it locally is
1058 ineffective.
1054 ineffective.
1059 """
1055 """
1060 repo.undo()
1056 repo.undo()
1061
1057
1062 def update(ui, repo, node=None, merge=False, clean=False):
1058 def update(ui, repo, node=None, merge=False, clean=False):
1063 '''update or merge working directory
1059 '''update or merge working directory
1064
1060
1065 If there are no outstanding changes in the working directory and
1061 If there are no outstanding changes in the working directory and
1066 there is a linear relationship between the current version and the
1062 there is a linear relationship between the current version and the
1067 requested version, the result is the requested version.
1063 requested version, the result is the requested version.
1068
1064
1069 Otherwise the result is a merge between the contents of the
1065 Otherwise the result is a merge between the contents of the
1070 current working directory and the requested version. Files that
1066 current working directory and the requested version. Files that
1071 changed between either parent are marked as changed for the next
1067 changed between either parent are marked as changed for the next
1072 commit and a commit must be performed before any further updates
1068 commit and a commit must be performed before any further updates
1073 are allowed.
1069 are allowed.
1074 '''
1070 '''
1075 node = node and repo.lookup(node) or repo.changelog.tip()
1071 node = node and repo.lookup(node) or repo.changelog.tip()
1076 return repo.update(node, allow=merge, force=clean)
1072 return repo.update(node, allow=merge, force=clean)
1077
1073
1078 def verify(ui, repo):
1074 def verify(ui, repo):
1079 """verify the integrity of the repository"""
1075 """verify the integrity of the repository"""
1080 return repo.verify()
1076 return repo.verify()
1081
1077
1082 # Command options and aliases are listed here, alphabetically
1078 # Command options and aliases are listed here, alphabetically
1083
1079
1084 table = {
1080 table = {
1085 "^add": (add,
1081 "^add": (add,
1086 [('I', 'include', [], 'include path in search'),
1082 [('I', 'include', [], 'include path in search'),
1087 ('X', 'exclude', [], 'exclude path from search')],
1083 ('X', 'exclude', [], 'exclude path from search')],
1088 "hg add [FILE]..."),
1084 "hg add [FILE]..."),
1089 "addremove": (addremove, [], "hg addremove [FILE]..."),
1085 "addremove": (addremove,
1086 [('I', 'include', [], 'include path in search'),
1087 ('X', 'exclude', [], 'exclude path from search')],
1088 "hg addremove [OPTION]... [FILE]..."),
1090 "^annotate":
1089 "^annotate":
1091 (annotate,
1090 (annotate,
1092 [('r', 'rev', '', 'revision'),
1091 [('r', 'rev', '', 'revision'),
1093 ('u', 'user', None, 'show user'),
1092 ('u', 'user', None, 'show user'),
1094 ('n', 'number', None, 'show revision number'),
1093 ('n', 'number', None, 'show revision number'),
1095 ('c', 'changeset', None, 'show changeset'),
1094 ('c', 'changeset', None, 'show changeset'),
1096 ('I', 'include', [], 'include path in search'),
1095 ('I', 'include', [], 'include path in search'),
1097 ('X', 'exclude', [], 'exclude path from search')],
1096 ('X', 'exclude', [], 'exclude path from search')],
1098 'hg annotate [-r REV] [-u] [-n] [-c] FILE...'),
1097 'hg annotate [-r REV] [-u] [-n] [-c] FILE...'),
1099 "cat":
1098 "cat":
1100 (cat,
1099 (cat,
1101 [('o', 'output', "", 'output to file')],
1100 [('o', 'output', "", 'output to file')],
1102 'hg cat [-o OUTFILE] FILE [REV]'),
1101 'hg cat [-o OUTFILE] FILE [REV]'),
1103 "^clone":
1102 "^clone":
1104 (clone,
1103 (clone,
1105 [('U', 'noupdate', None, 'skip update after cloning')],
1104 [('U', 'noupdate', None, 'skip update after cloning')],
1106 'hg clone [-U] SOURCE [DEST]'),
1105 'hg clone [-U] SOURCE [DEST]'),
1107 "^commit|ci":
1106 "^commit|ci":
1108 (commit,
1107 (commit,
1109 [('A', 'addremove', None, 'run add/remove during commit'),
1108 [('A', 'addremove', None, 'run add/remove during commit'),
1110 ('m', 'message', "", 'commit message'),
1109 ('m', 'message', "", 'commit message'),
1111 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1110 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1112 ('l', 'logfile', "", 'commit message file'),
1111 ('l', 'logfile', "", 'commit message file'),
1113 ('d', 'date', "", 'date code'),
1112 ('d', 'date', "", 'date code'),
1114 ('u', 'user', "", 'user')],
1113 ('u', 'user', "", 'user')],
1115 'hg commit [OPTION]... [FILE]...'),
1114 'hg commit [OPTION]... [FILE]...'),
1116 "copy": (copy, [], 'hg copy SOURCE DEST'),
1115 "copy": (copy, [], 'hg copy SOURCE DEST'),
1117 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1116 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1118 "debugstate": (debugstate, [], 'debugstate'),
1117 "debugstate": (debugstate, [], 'debugstate'),
1119 "debugindex": (debugindex, [], 'debugindex FILE'),
1118 "debugindex": (debugindex, [], 'debugindex FILE'),
1120 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1119 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1121 "^diff":
1120 "^diff":
1122 (diff,
1121 (diff,
1123 [('r', 'rev', [], 'revision'),
1122 [('r', 'rev', [], 'revision'),
1124 ('I', 'include', [], 'include path in search'),
1123 ('I', 'include', [], 'include path in search'),
1125 ('X', 'exclude', [], 'exclude path from search')],
1124 ('X', 'exclude', [], 'exclude path from search')],
1126 'hg diff [-r REV1 [-r REV2]] [FILE]...'),
1125 'hg diff [-r REV1 [-r REV2]] [FILE]...'),
1127 "^export":
1126 "^export":
1128 (export,
1127 (export,
1129 [('o', 'output', "", 'output to file')],
1128 [('o', 'output', "", 'output to file')],
1130 "hg export [-o OUTFILE] REV..."),
1129 "hg export [-o OUTFILE] REV..."),
1131 "forget": (forget, [], "hg forget FILE..."),
1130 "forget": (forget, [], "hg forget FILE..."),
1132 "heads": (heads, [], 'hg heads'),
1131 "heads": (heads, [], 'hg heads'),
1133 "help": (help_, [], 'hg help [COMMAND]'),
1132 "help": (help_, [], 'hg help [COMMAND]'),
1134 "identify|id": (identify, [], 'hg identify'),
1133 "identify|id": (identify, [], 'hg identify'),
1135 "import|patch":
1134 "import|patch":
1136 (import_,
1135 (import_,
1137 [('p', 'strip', 1, 'path strip'),
1136 [('p', 'strip', 1, 'path strip'),
1138 ('b', 'base', "", 'base path')],
1137 ('b', 'base', "", 'base path')],
1139 "hg import [-p NUM] [-b BASE] PATCH..."),
1138 "hg import [-p NUM] [-b BASE] PATCH..."),
1140 "^init": (init, [], 'hg init'),
1139 "^init": (init, [], 'hg init'),
1141 "locate":
1140 "locate":
1142 (locate,
1141 (locate,
1143 [('r', 'rev', '', 'revision'),
1142 [('r', 'rev', '', 'revision'),
1144 ('0', 'print0', None, 'end records with NUL'),
1143 ('0', 'print0', None, 'end records with NUL'),
1145 ('f', 'fullpath', None, 'print complete paths'),
1144 ('f', 'fullpath', None, 'print complete paths'),
1146 ('I', 'include', [], 'include path in search'),
1145 ('I', 'include', [], 'include path in search'),
1147 ('X', 'exclude', [], 'exclude path from search')],
1146 ('X', 'exclude', [], 'exclude path from search')],
1148 'hg locate [-r REV] [-f] [-0] [PATTERN]...'),
1147 'hg locate [-r REV] [-f] [-0] [PATTERN]...'),
1149 "^log|history":
1148 "^log|history":
1150 (log,
1149 (log,
1151 [('r', 'rev', [], 'revision'),
1150 [('r', 'rev', [], 'revision'),
1152 ('p', 'patch', None, 'show patch')],
1151 ('p', 'patch', None, 'show patch')],
1153 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1152 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1154 "manifest": (manifest, [], 'hg manifest [REV]'),
1153 "manifest": (manifest, [], 'hg manifest [REV]'),
1155 "parents": (parents, [], 'hg parents [REV]'),
1154 "parents": (parents, [], 'hg parents [REV]'),
1156 "^pull":
1155 "^pull":
1157 (pull,
1156 (pull,
1158 [('u', 'update', None, 'update working directory')],
1157 [('u', 'update', None, 'update working directory')],
1159 'hg pull [-u] [SOURCE]'),
1158 'hg pull [-u] [SOURCE]'),
1160 "^push": (push, [], 'hg push [DEST]'),
1159 "^push": (push, [], 'hg push [DEST]'),
1161 "rawcommit":
1160 "rawcommit":
1162 (rawcommit,
1161 (rawcommit,
1163 [('p', 'parent', [], 'parent'),
1162 [('p', 'parent', [], 'parent'),
1164 ('d', 'date', "", 'date code'),
1163 ('d', 'date', "", 'date code'),
1165 ('u', 'user', "", 'user'),
1164 ('u', 'user', "", 'user'),
1166 ('F', 'files', "", 'file list'),
1165 ('F', 'files', "", 'file list'),
1167 ('m', 'message', "", 'commit message'),
1166 ('m', 'message', "", 'commit message'),
1168 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1167 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1169 ('l', 'logfile', "", 'commit message file')],
1168 ('l', 'logfile', "", 'commit message file')],
1170 'hg rawcommit [OPTION]... [FILE]...'),
1169 'hg rawcommit [OPTION]... [FILE]...'),
1171 "recover": (recover, [], "hg recover"),
1170 "recover": (recover, [], "hg recover"),
1172 "^remove|rm": (remove, [], "hg remove FILE..."),
1171 "^remove|rm": (remove, [], "hg remove FILE..."),
1173 "^revert":
1172 "^revert":
1174 (revert,
1173 (revert,
1175 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1174 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1176 ("r", "rev", "", "revision")],
1175 ("r", "rev", "", "revision")],
1177 "hg revert [-n] [-r REV] [NAME]..."),
1176 "hg revert [-n] [-r REV] [NAME]..."),
1178 "root": (root, [], "hg root"),
1177 "root": (root, [], "hg root"),
1179 "^serve":
1178 "^serve":
1180 (serve,
1179 (serve,
1181 [('A', 'accesslog', '', 'access log file'),
1180 [('A', 'accesslog', '', 'access log file'),
1182 ('E', 'errorlog', '', 'error log file'),
1181 ('E', 'errorlog', '', 'error log file'),
1183 ('p', 'port', 8000, 'listen port'),
1182 ('p', 'port', 8000, 'listen port'),
1184 ('a', 'address', '', 'interface address'),
1183 ('a', 'address', '', 'interface address'),
1185 ('n', 'name', os.getcwd(), 'repository name'),
1184 ('n', 'name', os.getcwd(), 'repository name'),
1186 ('', 'stdio', None, 'for remote clients'),
1185 ('', 'stdio', None, 'for remote clients'),
1187 ('t', 'templates', "", 'template map')],
1186 ('t', 'templates', "", 'template map')],
1188 "hg serve [OPTION]..."),
1187 "hg serve [OPTION]..."),
1189 "^status": (status,
1188 "^status": (status,
1190 [('I', 'include', [], 'include path in search'),
1189 [('I', 'include', [], 'include path in search'),
1191 ('X', 'exclude', [], 'exclude path from search')],
1190 ('X', 'exclude', [], 'exclude path from search')],
1192 'hg status [FILE]...'),
1191 'hg status [FILE]...'),
1193 "tag":
1192 "tag":
1194 (tag,
1193 (tag,
1195 [('l', 'local', None, 'make the tag local'),
1194 [('l', 'local', None, 'make the tag local'),
1196 ('m', 'message', "", 'commit message'),
1195 ('m', 'message', "", 'commit message'),
1197 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1196 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1198 ('d', 'date', "", 'date code'),
1197 ('d', 'date', "", 'date code'),
1199 ('u', 'user', "", 'user')],
1198 ('u', 'user', "", 'user')],
1200 'hg tag [OPTION]... NAME [REV]'),
1199 'hg tag [OPTION]... NAME [REV]'),
1201 "tags": (tags, [], 'hg tags'),
1200 "tags": (tags, [], 'hg tags'),
1202 "tip": (tip, [], 'hg tip'),
1201 "tip": (tip, [], 'hg tip'),
1203 "undo": (undo, [], 'hg undo'),
1202 "undo": (undo, [], 'hg undo'),
1204 "^update|up|checkout|co":
1203 "^update|up|checkout|co":
1205 (update,
1204 (update,
1206 [('m', 'merge', None, 'allow merging of conflicts'),
1205 [('m', 'merge', None, 'allow merging of conflicts'),
1207 ('C', 'clean', None, 'overwrite locally modified files')],
1206 ('C', 'clean', None, 'overwrite locally modified files')],
1208 'hg update [-m] [-C] [REV]'),
1207 'hg update [-m] [-C] [REV]'),
1209 "verify": (verify, [], 'hg verify'),
1208 "verify": (verify, [], 'hg verify'),
1210 "version": (show_version, [], 'hg version'),
1209 "version": (show_version, [], 'hg version'),
1211 }
1210 }
1212
1211
1213 globalopts = [('v', 'verbose', None, 'verbose'),
1212 globalopts = [('v', 'verbose', None, 'verbose'),
1214 ('', 'debug', None, 'debug'),
1213 ('', 'debug', None, 'debug'),
1215 ('q', 'quiet', None, 'quiet'),
1214 ('q', 'quiet', None, 'quiet'),
1216 ('', 'profile', None, 'profile'),
1215 ('', 'profile', None, 'profile'),
1217 ('R', 'repository', "", 'repository root directory'),
1216 ('R', 'repository', "", 'repository root directory'),
1218 ('', 'traceback', None, 'print traceback on exception'),
1217 ('', 'traceback', None, 'print traceback on exception'),
1219 ('y', 'noninteractive', None, 'run non-interactively'),
1218 ('y', 'noninteractive', None, 'run non-interactively'),
1220 ('', 'version', None, 'output version information and exit'),
1219 ('', 'version', None, 'output version information and exit'),
1221 ]
1220 ]
1222
1221
1223 norepo = "clone init version help debugindex debugindexdot"
1222 norepo = "clone init version help debugindex debugindexdot"
1224
1223
1225 def find(cmd):
1224 def find(cmd):
1226 for e in table.keys():
1225 for e in table.keys():
1227 if re.match("(%s)$" % e, cmd):
1226 if re.match("(%s)$" % e, cmd):
1228 return table[e]
1227 return table[e]
1229
1228
1230 raise UnknownCommand(cmd)
1229 raise UnknownCommand(cmd)
1231
1230
1232 class SignalInterrupt(Exception):
1231 class SignalInterrupt(Exception):
1233 """Exception raised on SIGTERM and SIGHUP."""
1232 """Exception raised on SIGTERM and SIGHUP."""
1234
1233
1235 def catchterm(*args):
1234 def catchterm(*args):
1236 raise SignalInterrupt
1235 raise SignalInterrupt
1237
1236
1238 def run():
1237 def run():
1239 sys.exit(dispatch(sys.argv[1:]))
1238 sys.exit(dispatch(sys.argv[1:]))
1240
1239
1241 class ParseError(Exception):
1240 class ParseError(Exception):
1242 """Exception raised on errors in parsing the command line."""
1241 """Exception raised on errors in parsing the command line."""
1243
1242
1244 def parse(args):
1243 def parse(args):
1245 options = {}
1244 options = {}
1246 cmdoptions = {}
1245 cmdoptions = {}
1247
1246
1248 try:
1247 try:
1249 args = fancyopts.fancyopts(args, globalopts, options)
1248 args = fancyopts.fancyopts(args, globalopts, options)
1250 except fancyopts.getopt.GetoptError, inst:
1249 except fancyopts.getopt.GetoptError, inst:
1251 raise ParseError(None, inst)
1250 raise ParseError(None, inst)
1252
1251
1253 if options["version"]:
1252 if options["version"]:
1254 return ("version", show_version, [], options, cmdoptions)
1253 return ("version", show_version, [], options, cmdoptions)
1255 elif not args:
1254 elif not args:
1256 return ("help", help_, [], options, cmdoptions)
1255 return ("help", help_, [], options, cmdoptions)
1257 else:
1256 else:
1258 cmd, args = args[0], args[1:]
1257 cmd, args = args[0], args[1:]
1259
1258
1260 i = find(cmd)
1259 i = find(cmd)
1261
1260
1262 # combine global options into local
1261 # combine global options into local
1263 c = list(i[1])
1262 c = list(i[1])
1264 for o in globalopts:
1263 for o in globalopts:
1265 c.append((o[0], o[1], options[o[1]], o[3]))
1264 c.append((o[0], o[1], options[o[1]], o[3]))
1266
1265
1267 try:
1266 try:
1268 args = fancyopts.fancyopts(args, c, cmdoptions)
1267 args = fancyopts.fancyopts(args, c, cmdoptions)
1269 except fancyopts.getopt.GetoptError, inst:
1268 except fancyopts.getopt.GetoptError, inst:
1270 raise ParseError(cmd, inst)
1269 raise ParseError(cmd, inst)
1271
1270
1272 # separate global options back out
1271 # separate global options back out
1273 for o in globalopts:
1272 for o in globalopts:
1274 n = o[1]
1273 n = o[1]
1275 options[n] = cmdoptions[n]
1274 options[n] = cmdoptions[n]
1276 del cmdoptions[n]
1275 del cmdoptions[n]
1277
1276
1278 return (cmd, i[0], args, options, cmdoptions)
1277 return (cmd, i[0], args, options, cmdoptions)
1279
1278
1280 def dispatch(args):
1279 def dispatch(args):
1281 signal.signal(signal.SIGTERM, catchterm)
1280 signal.signal(signal.SIGTERM, catchterm)
1282 try:
1281 try:
1283 signal.signal(signal.SIGHUP, catchterm)
1282 signal.signal(signal.SIGHUP, catchterm)
1284 except AttributeError:
1283 except AttributeError:
1285 pass
1284 pass
1286
1285
1287 try:
1286 try:
1288 cmd, func, args, options, cmdoptions = parse(args)
1287 cmd, func, args, options, cmdoptions = parse(args)
1289 except ParseError, inst:
1288 except ParseError, inst:
1290 u = ui.ui()
1289 u = ui.ui()
1291 if inst.args[0]:
1290 if inst.args[0]:
1292 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1291 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1293 help_(u, inst.args[0])
1292 help_(u, inst.args[0])
1294 else:
1293 else:
1295 u.warn("hg: %s\n" % inst.args[1])
1294 u.warn("hg: %s\n" % inst.args[1])
1296 help_(u)
1295 help_(u)
1297 sys.exit(-1)
1296 sys.exit(-1)
1298 except UnknownCommand, inst:
1297 except UnknownCommand, inst:
1299 u = ui.ui()
1298 u = ui.ui()
1300 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1299 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1301 help_(u)
1300 help_(u)
1302 sys.exit(1)
1301 sys.exit(1)
1303
1302
1304 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1303 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1305 not options["noninteractive"])
1304 not options["noninteractive"])
1306
1305
1307 try:
1306 try:
1308 try:
1307 try:
1309 if cmd not in norepo.split():
1308 if cmd not in norepo.split():
1310 path = options["repository"] or ""
1309 path = options["repository"] or ""
1311 repo = hg.repository(ui=u, path=path)
1310 repo = hg.repository(ui=u, path=path)
1312 d = lambda: func(u, repo, *args, **cmdoptions)
1311 d = lambda: func(u, repo, *args, **cmdoptions)
1313 else:
1312 else:
1314 d = lambda: func(u, *args, **cmdoptions)
1313 d = lambda: func(u, *args, **cmdoptions)
1315
1314
1316 if options['profile']:
1315 if options['profile']:
1317 import hotshot, hotshot.stats
1316 import hotshot, hotshot.stats
1318 prof = hotshot.Profile("hg.prof")
1317 prof = hotshot.Profile("hg.prof")
1319 r = prof.runcall(d)
1318 r = prof.runcall(d)
1320 prof.close()
1319 prof.close()
1321 stats = hotshot.stats.load("hg.prof")
1320 stats = hotshot.stats.load("hg.prof")
1322 stats.strip_dirs()
1321 stats.strip_dirs()
1323 stats.sort_stats('time', 'calls')
1322 stats.sort_stats('time', 'calls')
1324 stats.print_stats(40)
1323 stats.print_stats(40)
1325 return r
1324 return r
1326 else:
1325 else:
1327 return d()
1326 return d()
1328 except:
1327 except:
1329 if options['traceback']:
1328 if options['traceback']:
1330 traceback.print_exc()
1329 traceback.print_exc()
1331 raise
1330 raise
1332 except util.CommandError, inst:
1331 except util.CommandError, inst:
1333 u.warn("abort: %s\n" % inst.args)
1332 u.warn("abort: %s\n" % inst.args)
1334 except hg.RepoError, inst:
1333 except hg.RepoError, inst:
1335 u.warn("abort: ", inst, "!\n")
1334 u.warn("abort: ", inst, "!\n")
1336 except SignalInterrupt:
1335 except SignalInterrupt:
1337 u.warn("killed!\n")
1336 u.warn("killed!\n")
1338 except KeyboardInterrupt:
1337 except KeyboardInterrupt:
1339 u.warn("interrupted!\n")
1338 u.warn("interrupted!\n")
1340 except IOError, inst:
1339 except IOError, inst:
1341 if hasattr(inst, "code"):
1340 if hasattr(inst, "code"):
1342 u.warn("abort: %s\n" % inst)
1341 u.warn("abort: %s\n" % inst)
1343 elif hasattr(inst, "reason"):
1342 elif hasattr(inst, "reason"):
1344 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1343 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1345 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1344 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1346 if u.debugflag: u.warn("broken pipe\n")
1345 if u.debugflag: u.warn("broken pipe\n")
1347 else:
1346 else:
1348 raise
1347 raise
1349 except OSError, inst:
1348 except OSError, inst:
1350 if hasattr(inst, "filename"):
1349 if hasattr(inst, "filename"):
1351 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1350 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1352 else:
1351 else:
1353 u.warn("abort: %s\n" % inst.strerror)
1352 u.warn("abort: %s\n" % inst.strerror)
1354 except Abort, inst:
1353 except Abort, inst:
1355 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1354 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1356 sys.exit(1)
1355 sys.exit(1)
1357 except TypeError, inst:
1356 except TypeError, inst:
1358 # was this an argument error?
1357 # was this an argument error?
1359 tb = traceback.extract_tb(sys.exc_info()[2])
1358 tb = traceback.extract_tb(sys.exc_info()[2])
1360 if len(tb) > 2: # no
1359 if len(tb) > 2: # no
1361 raise
1360 raise
1362 u.debug(inst, "\n")
1361 u.debug(inst, "\n")
1363 u.warn("%s: invalid arguments\n" % cmd)
1362 u.warn("%s: invalid arguments\n" % cmd)
1364 help_(u, cmd)
1363 help_(u, cmd)
1365
1364
1366 sys.exit(-1)
1365 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now