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