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