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