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