##// END OF EJS Templates
On Sat, Jul 02, 2005 at 02:11:34PM -0700, Matt Mackall wrote:...
Alecs King -
r612:9cd74543 default
parent child Browse files
Show More
@@ -1,560 +1,563 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
36 indicates one or more filename or relative path filenames
37
37
38 path::
38 path::
39 indicates a path on the local machine
39 indicates a path on the local machine
40
40
41 revision::
41 revision::
42 indicates a changeset which can be specified as a changeset revision
42 indicates a changeset which can be specified as a changeset revision
43 number, a tag, or a unique substring of the changeset hash value
43 number, a tag, or a unique substring of the changeset hash value
44
44
45 repository path::
45 repository path::
46 either the pathname of a local repository or the URI of a remote
46 either the pathname of a local repository or the URI of a remote
47 repository. There are two available URI protocols, http:// which is
47 repository. There are two available URI protocols, http:// which is
48 fast and the old-http:// protocol which is much slower but does not
48 fast and the old-http:// protocol which is much slower but does not
49 require a special server on the web host.
49 require a special server on the web host.
50
50
51 COMMANDS
51 COMMANDS
52 --------
52 --------
53
53
54 add [files ...]::
54 add [files ...]::
55 Schedule files to be version controlled and added to the repository.
55 Schedule files to be version controlled and added to the repository.
56
56
57 The files will be added to the repository at the next commit.
57 The files will be added to the repository at the next commit.
58
58
59 addremove::
59 addremove::
60 Add all new files and remove all missing files from the repository.
60 Add all new files and remove all missing files from the repository.
61
61
62 New files are ignored if they match any of the patterns in .hgignore. As
62 New files are ignored if they match any of the patterns in .hgignore. As
63 with add, these changes take effect at the next commit.
63 with add, these changes take effect at the next commit.
64
64
65 annotate [-r <rev> -u -n -c] [files ...]::
65 annotate [-r <rev> -u -n -c] [files ...]::
66 List changes in files, showing the revision id responsible for each line
66 List changes in files, showing the revision id responsible for each line
67
67
68 This command is useful to discover who did a change or when a change took
68 This command is useful to discover who did a change or when a change took
69 place.
69 place.
70
70
71 options:
71 options:
72 -r, --revision <rev> annotate the specified revision
72 -r, --revision <rev> annotate the specified revision
73 -u, --user list the author
73 -u, --user list the author
74 -c, --changeset list the changeset
74 -c, --changeset list the changeset
75 -n, --number list the revision number (default)
75 -n, --number list the revision number (default)
76
76
77 cat <file> [revision]::
77 cat <file> [revision]::
78 Output to stdout the given revision for the specified file.
78 Output to stdout the given revision for the specified file.
79
79
80 If no revision is given then the tip is used.
80 If no revision is given then the tip is used.
81
81
82 clone [-U] <source> [dest]::
82 clone [-U] <source> [dest]::
83 Create a copy of an existing repository in a new directory.
83 Create a copy of an existing repository in a new directory.
84
84
85 If no destination directory name is specified, it defaults to the
85 If no destination directory name is specified, it defaults to the
86 basename of the source.
86 basename of the source.
87
87
88 The source is added to the new repository's .hg/hgrc file to be used in
88 The source is added to the new repository's .hg/hgrc file to be used in
89 future pulls.
89 future pulls.
90
90
91 For efficiency, hardlinks are used for cloning whenever the
91 For efficiency, hardlinks are used for cloning whenever the
92 source and destination are on the same filesystem.
92 source and destination are on the same filesystem.
93
93
94 options:
94 options:
95 -U, --noupdate do not update the new working directory
95 -U, --noupdate do not update the new working directory
96
96
97 commit [-A -t -l <file> -t <text> -u <user> -d <datecode>] [files...]::
97 commit [-A -t -l <file> -t <text> -u <user> -d <datecode>] [files...]::
98 Commit changes to the given files into the repository.
98 Commit changes to the given files into the repository.
99
99
100 If a list of files is omitted, all changes reported by "hg status"
100 If a list of files is omitted, all changes reported by "hg status"
101 will be commited.
101 will be commited.
102
102
103 The HGEDITOR or EDITOR environment variables are used to start an
103 The HGEDITOR or EDITOR environment variables are used to start an
104 editor to add a commit comment.
104 editor to add a commit comment.
105
105
106 Options:
106 Options:
107
107
108 -A, --addremove run addremove during commit
108 -A, --addremove run addremove during commit
109 -t, --text <text> use <text> as commit message
109 -t, --text <text> use <text> as commit message
110 -l, --logfile <file> show the commit message for the given file
110 -l, --logfile <file> show the commit message for the given file
111 -d, --date <datecode> record datecode as commit date
111 -d, --date <datecode> record datecode as commit date
112 -u, --user <user> record user as commiter
112 -u, --user <user> record user as commiter
113
113
114 aliases: ci
114 aliases: ci
115
115
116 copy <source> <dest>::
116 copy <source> <dest>::
117 Mark <dest> file as a copy or rename of a <source> one
117 Mark <dest> file as a copy or rename of a <source> one
118
118
119 This command takes effect for the next commit.
119 This command takes effect for the next commit.
120
120
121 diff [-r revision] [-r revision] [files ...]::
121 diff [-r revision] [-r revision] [files ...]::
122 Show differences between revisions for the specified files.
122 Show differences between revisions for the specified files.
123
123
124 Differences between files are shown using the unified diff format.
124 Differences between files are shown using the unified diff format.
125
125
126 When two revision arguments are given, then changes are shown
126 When two revision arguments are given, then changes are shown
127 between those revisions. If only one revision is specified then
127 between those revisions. If only one revision is specified then
128 that revision is compared to the working directory, and, when no
128 that revision is compared to the working directory, and, when no
129 revisions are specified, the working directory files are compared
129 revisions are specified, the working directory files are compared
130 to its parent.
130 to its parent.
131
131
132 export [-o filespec] [revision] ...::
132 export [-o filespec] [revision] ...::
133 Print the changeset header and diffs for one or more revisions.
133 Print the changeset header and diffs for one or more revisions.
134
134
135 The information shown in the changeset header is: author,
135 The information shown in the changeset header is: author,
136 changeset hash, parent and commit comment.
136 changeset hash, parent and commit comment.
137
137
138 Output may be to a file, in which case the name of the file is
138 Output may be to a file, in which case the name of the file is
139 given using a format string. The formatting rules are as follows:
139 given using a format string. The formatting rules are as follows:
140
140
141 %% literal "%" character
141 %% literal "%" character
142 %H changeset hash (40 bytes of hexadecimal)
142 %H changeset hash (40 bytes of hexadecimal)
143 %N number of patches being generated
143 %N number of patches being generated
144 %R changeset revision number
144 %R changeset revision number
145 %b basename of the exporting repository
145 %b basename of the exporting repository
146 %h short-form changeset hash (12 bytes of hexadecimal)
146 %h short-form changeset hash (12 bytes of hexadecimal)
147 %n zero-padded sequence number, starting at 1
147 %n zero-padded sequence number, starting at 1
148 %r zero-padded changeset revision number
148 %r zero-padded changeset revision number
149
149
150 Options:
150 Options:
151
151
152 -o, --output <filespec> print output to file with formatted named
152 -o, --output <filespec> print output to file with formatted named
153
153
154 forget [files]::
154 forget [files]::
155 Undo an 'hg add' scheduled for the next commit.
155 Undo an 'hg add' scheduled for the next commit.
156
156
157 heads::
157 heads::
158 Show all repository head changesets.
158 Show all repository head changesets.
159
159
160 Repository "heads" are changesets that don't have children
160 Repository "heads" are changesets that don't have children
161 changesets. They are where development generally takes place and
161 changesets. They are where development generally takes place and
162 are the usual targets for update and merge operations.
162 are the usual targets for update and merge operations.
163
163
164 identify::
164 identify::
165 Print a short summary of the current state of the repo.
165 Print a short summary of the current state of the repo.
166
166
167 This summary identifies the repository state using one or two parent
167 This summary identifies the repository state using one or two parent
168 hash identifiers, followed by a "+" if there are uncommitted changes
168 hash identifiers, followed by a "+" if there are uncommitted changes
169 in the working directory, followed by a list of tags for this revision.
169 in the working directory, followed by a list of tags for this revision.
170
170
171 aliases: id
171 aliases: id
172
172
173 import [-p <n> -b <base> -q] <patches>::
173 import [-p <n> -b <base> -q] <patches>::
174 Import a list of patches and commit them individually.
174 Import a list of patches and commit them individually.
175
175
176 options:
176 options:
177 -p, --strip <n> directory strip option for patch. This has the same
177 -p, --strip <n> directory strip option for patch. This has the same
178 meaning as the correnponding patch option
178 meaning as the correnponding patch option
179 -b <path> base directory to read patches from
179 -b <path> base directory to read patches from
180
180
181 aliases: patch
181 aliases: patch
182
182
183 init::
183 init::
184 Initialize a new repository in the current directory.
184 Initialize a new repository in the current directory.
185
185
186 log [-r revision ...] [file]::
186 log [-r revision ...] [-p] [file]::
187 Print the revision history of the specified file or the entire project.
187 Print the revision history of the specified file or the entire project.
188
188
189 By default this command outputs: changeset id and hash, tags,
189 By default this command outputs: changeset id and hash, tags,
190 parents, user, date and time, and a summary for each commit. The
190 parents, user, date and time, and a summary for each commit. The
191 -v switch adds some more detail, such as changed files, manifest
191 -v switch adds some more detail, such as changed files, manifest
192 hashes or message signatures.
192 hashes or message signatures.
193
193
194 When a revision argument is given, only this file or changelog revision
194 options:
195 is displayed. With two revision arguments all revisions in this range
195 -r, --rev <A>, ... When a revision argument is given, only this file or
196 are listed. Additional revision arguments may be given repeating the above
196 changelog revision is displayed. With two revision
197 cycle.
197 arguments all revisions in this range are listed.
198 Additional revision arguments may be given repeating
199 the above cycle.
200 -p, --patch show patch
198
201
199 aliases: history
202 aliases: history
200
203
201 manifest [revision]::
204 manifest [revision]::
202 Print a list of version controlled files for the given revision.
205 Print a list of version controlled files for the given revision.
203
206
204 The manifest is the list of files being version controlled. If no revision
207 The manifest is the list of files being version controlled. If no revision
205 is given then the tip is used.
208 is given then the tip is used.
206
209
207 parents::
210 parents::
208 Print the working directory's parent revisions.
211 Print the working directory's parent revisions.
209
212
210 pull <repository path>::
213 pull <repository path>::
211 Pull changes from a remote repository to a local one.
214 Pull changes from a remote repository to a local one.
212
215
213 This finds all changes from the repository at the specified path
216 This finds all changes from the repository at the specified path
214 or URL and adds them to the local repository. By default, this
217 or URL and adds them to the local repository. By default, this
215 does not update the copy of the project in the working directory.
218 does not update the copy of the project in the working directory.
216
219
217 options:
220 options:
218 -u, --update update the working directory to tip after pull
221 -u, --update update the working directory to tip after pull
219
222
220 push <destination>::
223 push <destination>::
221 Push changes from the local repository to the given destination.
224 Push changes from the local repository to the given destination.
222
225
223 This is the symmetrical operation for pull. It helps to move
226 This is the symmetrical operation for pull. It helps to move
224 changes from the current repository to a different one. If the
227 changes from the current repository to a different one. If the
225 destination is local this is identical to a pull in that directory
228 destination is local this is identical to a pull in that directory
226 from the current one.
229 from the current one.
227
230
228 The other currently available push method is SSH. This requires an
231 The other currently available push method is SSH. This requires an
229 accessible shell account on the destination machine and a copy of
232 accessible shell account on the destination machine and a copy of
230 hg in the remote path. Destinations are specified in the following
233 hg in the remote path. Destinations are specified in the following
231 form:
234 form:
232
235
233 ssh://[user@]host[:port]/path
236 ssh://[user@]host[:port]/path
234
237
235 rawcommit [-p -d -u -F -t -l]::
238 rawcommit [-p -d -u -F -t -l]::
236 Lowlevel commit, for use in helper scripts.
239 Lowlevel commit, for use in helper scripts.
237
240
238 This command is not intended to be used by normal users, as it is
241 This command is not intended to be used by normal users, as it is
239 primarily useful for importing from other SCMs.
242 primarily useful for importing from other SCMs.
240
243
241 recover::
244 recover::
242 Recover from an interrupted commit or pull.
245 Recover from an interrupted commit or pull.
243
246
244 This command tries to fix the repository status after an interrupted
247 This command tries to fix the repository status after an interrupted
245 operation. It should only be necessary when Mercurial suggests it.
248 operation. It should only be necessary when Mercurial suggests it.
246
249
247 remove [files ...]::
250 remove [files ...]::
248 Schedule the indicated files for removal from the repository.
251 Schedule the indicated files for removal from the repository.
249
252
250 This command shedules the files to be removed at the next commit.
253 This command shedules the files to be removed at the next commit.
251 This only removes files from the current branch, not from the
254 This only removes files from the current branch, not from the
252 entire project history.
255 entire project history.
253
256
254 aliases: rm
257 aliases: rm
255
258
256 revert [names ...]::
259 revert [names ...]::
257 Revert any uncommitted modifications made to the named files or
260 Revert any uncommitted modifications made to the named files or
258 directories. This restores the contents of the affected files to
261 directories. This restores the contents of the affected files to
259 an unmodified state.
262 an unmodified state.
260
263
261 If a file has been deleted, it is recreated. If the executable
264 If a file has been deleted, it is recreated. If the executable
262 mode of a file was changed, it is reset.
265 mode of a file was changed, it is reset.
263
266
264 If a directory is given, all files in that directory and its
267 If a directory is given, all files in that directory and its
265 subdirectories are reverted.
268 subdirectories are reverted.
266
269
267 If no arguments are given, all files in the current directory and
270 If no arguments are given, all files in the current directory and
268 its subdirectories are reverted.
271 its subdirectories are reverted.
269
272
270 options:
273 options:
271 -r, --rev <rev> revision to revert to
274 -r, --rev <rev> revision to revert to
272 -n, --nonrecursive do not recurse into subdirectories
275 -n, --nonrecursive do not recurse into subdirectories
273
276
274 root::
277 root::
275 Print the root directory of the current repository.
278 Print the root directory of the current repository.
276
279
277 serve [options]::
280 serve [options]::
278 Start a local HTTP repository browser and pull server.
281 Start a local HTTP repository browser and pull server.
279
282
280 By default, the server logs accesses to stdout and errors to
283 By default, the server logs accesses to stdout and errors to
281 stderr. Use the "-A" and "-E" options to log to files.
284 stderr. Use the "-A" and "-E" options to log to files.
282
285
283 options:
286 options:
284 -A, --accesslog <file> name of access log file to write to
287 -A, --accesslog <file> name of access log file to write to
285 -E, --errorlog <file> name of error log file to write to
288 -E, --errorlog <file> name of error log file to write to
286 -a, --address <addr> address to use
289 -a, --address <addr> address to use
287 -p, --port <n> port to use (default: 8000)
290 -p, --port <n> port to use (default: 8000)
288 -n, --name <name> name to show in web pages (default: working dir)
291 -n, --name <name> name to show in web pages (default: working dir)
289 -t, --templatedir <path> web templates to use
292 -t, --templatedir <path> web templates to use
290
293
291 status::
294 status::
292 Show changed files in the working directory.
295 Show changed files in the working directory.
293
296
294 The codes used to show the status of files are:
297 The codes used to show the status of files are:
295
298
296 C = changed
299 C = changed
297 A = added
300 A = added
298 R = removed
301 R = removed
299 ? = not tracked
302 ? = not tracked
300
303
301 tag [-t <text> -d <datecode> -u <user>] <name> [revision]::
304 tag [-t <text> -d <datecode> -u <user>] <name> [revision]::
302 Name a particular revision using <name>.
305 Name a particular revision using <name>.
303
306
304 Tags are used to name particular revisions of the repository and are
307 Tags are used to name particular revisions of the repository and are
305 very useful to compare different revision, to go back to significant
308 very useful to compare different revision, to go back to significant
306 earlier versions or to mark branch points as releases, etc.
309 earlier versions or to mark branch points as releases, etc.
307
310
308 If no revision is given, the tip is used.
311 If no revision is given, the tip is used.
309
312
310 To facilitate version control, distribution, and merging of tags,
313 To facilitate version control, distribution, and merging of tags,
311 they are stored as a file named ".hgtags" which is managed
314 they are stored as a file named ".hgtags" which is managed
312 similarly to other project files and can be hand-edited if
315 similarly to other project files and can be hand-edited if
313 necessary.
316 necessary.
314
317
315 options:
318 options:
316 -t, --text <text> message for tag commit log entry
319 -t, --text <text> message for tag commit log entry
317 -d, --date <datecode> datecode for commit
320 -d, --date <datecode> datecode for commit
318 -u, --user <user> user for commit
321 -u, --user <user> user for commit
319
322
320 Note: Mercurial also has support for "local tags" that are not
323 Note: Mercurial also has support for "local tags" that are not
321 version-controlled or distributed which are stored in the .hg/hgrc
324 version-controlled or distributed which are stored in the .hg/hgrc
322 file.
325 file.
323
326
324 tags::
327 tags::
325 List the repository tags.
328 List the repository tags.
326
329
327 This lists both regular and local tags.
330 This lists both regular and local tags.
328
331
329 tip::
332 tip::
330 Show the tip revision.
333 Show the tip revision.
331
334
332 undo::
335 undo::
333 Undo the last commit or pull transaction.
336 Undo the last commit or pull transaction.
334
337
335 Roll back the last pull or commit transaction on the
338 Roll back the last pull or commit transaction on the
336 repository, restoring the project to its earlier state.
339 repository, restoring the project to its earlier state.
337
340
338 This command should be used with care. There is only one level of
341 This command should be used with care. There is only one level of
339 undo and there is no redo.
342 undo and there is no redo.
340
343
341 This command is not intended for use on public repositories. Once
344 This command is not intended for use on public repositories. Once
342 a change is visible for pull by other users, undoing it locally is
345 a change is visible for pull by other users, undoing it locally is
343 ineffective.
346 ineffective.
344
347
345 update [-m -C] [revision]::
348 update [-m -C] [revision]::
346 Update the working directory to the specified revision.
349 Update the working directory to the specified revision.
347
350
348 By default, update will refuse to run if doing so would require
351 By default, update will refuse to run if doing so would require
349 merging or discarding local changes.
352 merging or discarding local changes.
350
353
351 With the -m option, a merge will be performed.
354 With the -m option, a merge will be performed.
352
355
353 With the -C option, local changes will be lost.
356 With the -C option, local changes will be lost.
354
357
355 options:
358 options:
356 -m, --merge allow merging of branches
359 -m, --merge allow merging of branches
357 -C, --clean overwrite locally modified files
360 -C, --clean overwrite locally modified files
358
361
359 aliases: up checkout co
362 aliases: up checkout co
360
363
361 verify::
364 verify::
362 Verify the integrity of the current repository.
365 Verify the integrity of the current repository.
363
366
364 This will perform an extensive check of the repository's
367 This will perform an extensive check of the repository's
365 integrity, validating the hashes and checksums of each entry in
368 integrity, validating the hashes and checksums of each entry in
366 the changelog, manifest, and tracked files, as well as the
369 the changelog, manifest, and tracked files, as well as the
367 integrity of their crosslinks and indices.
370 integrity of their crosslinks and indices.
368
371
369 SPECIFYING SINGLE REVISIONS
372 SPECIFYING SINGLE REVISIONS
370 ---------------------------
373 ---------------------------
371
374
372 Mercurial accepts several notations for identifying individual
375 Mercurial accepts several notations for identifying individual
373 revisions.
376 revisions.
374
377
375 A plain integer is treated as a revision number. Negative
378 A plain integer is treated as a revision number. Negative
376 integers are treated as offsets from the tip, with -1 denoting the
379 integers are treated as offsets from the tip, with -1 denoting the
377 tip.
380 tip.
378
381
379 A 40-digit hexadecimal string is treated as a unique revision
382 A 40-digit hexadecimal string is treated as a unique revision
380 identifier.
383 identifier.
381
384
382 A hexadecimal string less than 40 characters long is treated as a
385 A hexadecimal string less than 40 characters long is treated as a
383 unique revision identifier, and referred to as a short-form
386 unique revision identifier, and referred to as a short-form
384 identifier. A short-form identifier is only valid if it is the
387 identifier. A short-form identifier is only valid if it is the
385 prefix of one full-length identifier.
388 prefix of one full-length identifier.
386
389
387 Any other string is treated as a tag name, which is a symbolic
390 Any other string is treated as a tag name, which is a symbolic
388 name associated with a revision identifier. Tag names may not
391 name associated with a revision identifier. Tag names may not
389 contain the ":" character.
392 contain the ":" character.
390
393
391 The reserved name "tip" is a special tag that always identifies
394 The reserved name "tip" is a special tag that always identifies
392 the most recent revision.
395 the most recent revision.
393
396
394 SPECIFYING MULTIPLE REVISIONS
397 SPECIFYING MULTIPLE REVISIONS
395 -----------------------------
398 -----------------------------
396
399
397 When Mercurial accepts more than one revision, they may be
400 When Mercurial accepts more than one revision, they may be
398 specified individually, or provided as a continuous range,
401 specified individually, or provided as a continuous range,
399 separated by the ":" character.
402 separated by the ":" character.
400
403
401 The syntax of range notation is [BEGIN]:[END], where BEGIN and END
404 The syntax of range notation is [BEGIN]:[END], where BEGIN and END
402 are revision identifiers. Both BEGIN and END are optional. If
405 are revision identifiers. Both BEGIN and END are optional. If
403 BEGIN is not specified, it defaults to revision number 0. If END
406 BEGIN is not specified, it defaults to revision number 0. If END
404 is not specified, it defaults to the tip. The range ":" thus
407 is not specified, it defaults to the tip. The range ":" thus
405 means "all revisions".
408 means "all revisions".
406
409
407 If BEGIN is greater than END, revisions are treated in reverse
410 If BEGIN is greater than END, revisions are treated in reverse
408 order.
411 order.
409
412
410 A range acts as an open interval. This means that a range of 3:5
413 A range acts as an open interval. This means that a range of 3:5
411 gives 3, 4 and 5. Similarly, a range of 4:2 gives 4, 3, and 2.
414 gives 3, 4 and 5. Similarly, a range of 4:2 gives 4, 3, and 2.
412
415
413 ENVIRONMENT VARIABLES
416 ENVIRONMENT VARIABLES
414 ---------------------
417 ---------------------
415
418
416 HGEDITOR::
419 HGEDITOR::
417 This is the name of the editor to use when committing. Defaults to the
420 This is the name of the editor to use when committing. Defaults to the
418 value of EDITOR.
421 value of EDITOR.
419
422
420 (deprecated, use .hgrc)
423 (deprecated, use .hgrc)
421
424
422 HGMERGE::
425 HGMERGE::
423 An executable to use for resolving merge conflicts. The program
426 An executable to use for resolving merge conflicts. The program
424 will be executed with three arguments: local file, remote file,
427 will be executed with three arguments: local file, remote file,
425 ancestor file.
428 ancestor file.
426
429
427 The default program is "hgmerge", which is a shell script provided
430 The default program is "hgmerge", which is a shell script provided
428 by Mercurial with some sensible defaults.
431 by Mercurial with some sensible defaults.
429
432
430 (deprecated, use .hgrc)
433 (deprecated, use .hgrc)
431
434
432 HGUSER::
435 HGUSER::
433 This is the string used for the author of a commit.
436 This is the string used for the author of a commit.
434
437
435 (deprecated, use .hgrc)
438 (deprecated, use .hgrc)
436
439
437 EMAIL::
440 EMAIL::
438 If HGUSER is not set, this will be used as the author for a commit.
441 If HGUSER is not set, this will be used as the author for a commit.
439
442
440 LOGNAME::
443 LOGNAME::
441 If neither HGUSER nor EMAIL is set, LOGNAME will be used (with
444 If neither HGUSER nor EMAIL is set, LOGNAME will be used (with
442 '@hostname' appended) as the author value for a commit.
445 '@hostname' appended) as the author value for a commit.
443
446
444 EDITOR::
447 EDITOR::
445 This is the name of the editor used in the hgmerge script. It will be
448 This is the name of the editor used in the hgmerge script. It will be
446 used for commit messages if HGEDITOR isn't set. Defaults to 'vi'.
449 used for commit messages if HGEDITOR isn't set. Defaults to 'vi'.
447
450
448 PYTHONPATH::
451 PYTHONPATH::
449 This is used by Python to find imported modules and may need to be set
452 This is used by Python to find imported modules and may need to be set
450 appropriately if Mercurial is not installed system-wide.
453 appropriately if Mercurial is not installed system-wide.
451
454
452 FILES
455 FILES
453 -----
456 -----
454 .hgignore::
457 .hgignore::
455 This file contains regular expressions (one per line) that describe file
458 This file contains regular expressions (one per line) that describe file
456 names that should be ignored by hg.
459 names that should be ignored by hg.
457
460
458 .hgtags::
461 .hgtags::
459 This file contains changeset hash values and text tag names (one of each
462 This file contains changeset hash values and text tag names (one of each
460 seperated by spaces) that correspond to tagged versions of the repository
463 seperated by spaces) that correspond to tagged versions of the repository
461 contents.
464 contents.
462
465
463 $HOME/.hgrc, .hg/hgrc::
466 $HOME/.hgrc, .hg/hgrc::
464 This file contains defaults and configuration. Values in .hg/hgrc
467 This file contains defaults and configuration. Values in .hg/hgrc
465 override those in .hgrc.
468 override those in .hgrc.
466
469
467
470
468 UI OPTIONS
471 UI OPTIONS
469 ----------
472 ----------
470
473
471 Various configuration options can be set in .hgrc:
474 Various configuration options can be set in .hgrc:
472
475
473 -------------
476 -------------
474 [ui]
477 [ui]
475 verbose = 0
478 verbose = 0
476 username = Matt Mackall <mpm@selenic.com>
479 username = Matt Mackall <mpm@selenic.com>
477 editor = hgeditor
480 editor = hgeditor
478 merge = hgmerge
481 merge = hgmerge
479 -------------
482 -------------
480
483
481
484
482 NAMED REPOSITORIES
485 NAMED REPOSITORIES
483 ------------------
486 ------------------
484
487
485 To give symbolic names to a repository, create a section in .hgrc
488 To give symbolic names to a repository, create a section in .hgrc
486 or .hg/hgrc containing assignments of names to paths. Example:
489 or .hg/hgrc containing assignments of names to paths. Example:
487
490
488 -----------------
491 -----------------
489 [paths]
492 [paths]
490 hg = http://selenic.com/hg
493 hg = http://selenic.com/hg
491 tah = http://hg.intevation.org/mercurial-tah/
494 tah = http://hg.intevation.org/mercurial-tah/
492 -----------------
495 -----------------
493
496
494
497
495 LOCAL TAGS
498 LOCAL TAGS
496 ----------
499 ----------
497
500
498 To create tags that are local to the repository and not distributed or
501 To create tags that are local to the repository and not distributed or
499 version-controlled, create an hgrc section like the following:
502 version-controlled, create an hgrc section like the following:
500
503
501 ----------------
504 ----------------
502 [tags]
505 [tags]
503 working = 2dcced388cab3677a8f543c3c47a0ad34ac9d435
506 working = 2dcced388cab3677a8f543c3c47a0ad34ac9d435
504 tested = 12e0fdbc57a0be78f0e817fd1d170a3615cd35da
507 tested = 12e0fdbc57a0be78f0e817fd1d170a3615cd35da
505 ----------------
508 ----------------
506
509
507
510
508 HOOKS
511 HOOKS
509 -----
512 -----
510
513
511 Mercurial supports a set of 'hook', commands that get automatically
514 Mercurial supports a set of 'hook', commands that get automatically
512 executed by various actions such as starting or finishing a commit. To
515 executed by various actions such as starting or finishing a commit. To
513 specify a hook, simply create an hgrc section like the following:
516 specify a hook, simply create an hgrc section like the following:
514
517
515 -----------------
518 -----------------
516 [hooks]
519 [hooks]
517 precommit = echo "this hook gets executed immediately before a commit"
520 precommit = echo "this hook gets executed immediately before a commit"
518 commit = hg export $NODE | mail -s "new commit $NODE" commit-list
521 commit = hg export $NODE | mail -s "new commit $NODE" commit-list
519 -----------------
522 -----------------
520
523
521
524
522 NON_TRANSPARENT PROXY SUPPORT
525 NON_TRANSPARENT PROXY SUPPORT
523 -----------------------------
526 -----------------------------
524
527
525 To access a Mercurial repository through a proxy, create a file
528 To access a Mercurial repository through a proxy, create a file
526 $HOME/.hgrc in the following format:
529 $HOME/.hgrc in the following format:
527
530
528 --------------
531 --------------
529 [http_proxy]
532 [http_proxy]
530 host=myproxy:8080
533 host=myproxy:8080
531 user=<username>
534 user=<username>
532 passwd=<password>
535 passwd=<password>
533 no=<localhost1>,<localhost2>,<localhost3>,...
536 no=<localhost1>,<localhost2>,<localhost3>,...
534 --------------
537 --------------
535
538
536 "user" and "passwd" fields are used for authenticating proxies, "no" is a
539 "user" and "passwd" fields are used for authenticating proxies, "no" is a
537 comma-separated list of local host names to not proxy.
540 comma-separated list of local host names to not proxy.
538
541
539 BUGS
542 BUGS
540 ----
543 ----
541 Probably lots, please post them to the mailing list (See Resources below)
544 Probably lots, please post them to the mailing list (See Resources below)
542 when you find them.
545 when you find them.
543
546
544 AUTHOR
547 AUTHOR
545 ------
548 ------
546 Written by Matt Mackall <mpm@selenic.com>
549 Written by Matt Mackall <mpm@selenic.com>
547
550
548 RESOURCES
551 RESOURCES
549 ---------
552 ---------
550 http://selenic.com/mercurial[Main Web Site]
553 http://selenic.com/mercurial[Main Web Site]
551
554
552 http://selenic.com/hg[Source code repository]
555 http://selenic.com/hg[Source code repository]
553
556
554 http://selenic.com/mailman/listinfo/mercurial[Mailing list]
557 http://selenic.com/mailman/listinfo/mercurial[Mailing list]
555
558
556 COPYING
559 COPYING
557 -------
560 -------
558 Copyright (C) 2005 Matt Mackall.
561 Copyright (C) 2005 Matt Mackall.
559 Free use of this software is granted under the terms of the GNU General
562 Free use of this software is granted under the terms of the GNU General
560 Public License (GPL).
563 Public License (GPL).
@@ -1,1173 +1,1185 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 import os, re, sys, signal
8 import os, re, sys, signal
9 import fancyopts, ui, hg, util
9 import fancyopts, ui, hg, util
10 from demandload import *
10 from demandload import *
11 demandload(globals(), "mdiff time hgweb traceback random signal")
11 demandload(globals(), "mdiff time hgweb traceback random signal")
12 demandload(globals(), "socket errno version")
12 demandload(globals(), "socket errno version")
13
13
14 class UnknownCommand(Exception): pass
14 class UnknownCommand(Exception): pass
15
15
16 def filterfiles(filters, files):
16 def filterfiles(filters, files):
17 l = [ x for x in files if x in filters ]
17 l = [ x for x in files if x in filters ]
18
18
19 for t in filters:
19 for t in filters:
20 if t and t[-1] != "/": t += "/"
20 if t and t[-1] != "/": t += "/"
21 l += [ x for x in files if x.startswith(t) ]
21 l += [ x for x in files if x.startswith(t) ]
22 return l
22 return l
23
23
24 def relfilter(repo, files):
24 def relfilter(repo, files):
25 if os.getcwd() != repo.root:
25 if os.getcwd() != repo.root:
26 p = os.getcwd()[len(repo.root) + 1: ]
26 p = os.getcwd()[len(repo.root) + 1: ]
27 return filterfiles([util.pconvert(p)], files)
27 return filterfiles([util.pconvert(p)], files)
28 return files
28 return files
29
29
30 def relpath(repo, args):
30 def relpath(repo, args):
31 if os.getcwd() != repo.root:
31 if os.getcwd() != repo.root:
32 p = os.getcwd()[len(repo.root) + 1: ]
32 p = os.getcwd()[len(repo.root) + 1: ]
33 return [ util.pconvert(os.path.normpath(os.path.join(p, x)))
33 return [ util.pconvert(os.path.normpath(os.path.join(p, x)))
34 for x in args ]
34 for x in args ]
35 return args
35 return args
36
36
37 revrangesep = ':'
37 revrangesep = ':'
38
38
39 def revrange(ui, repo, revs = [], revlog = None):
39 def revrange(ui, repo, revs = [], revlog = None):
40 if revlog is None:
40 if revlog is None:
41 revlog = repo.changelog
41 revlog = repo.changelog
42 revcount = revlog.count()
42 revcount = revlog.count()
43 def fix(val, defval):
43 def fix(val, defval):
44 if not val: return defval
44 if not val: return defval
45 try:
45 try:
46 num = int(val)
46 num = int(val)
47 if str(num) != val: raise ValueError
47 if str(num) != val: raise ValueError
48 if num < 0: num += revcount
48 if num < 0: num += revcount
49 if not (0 <= num < revcount):
49 if not (0 <= num < revcount):
50 raise ValueError
50 raise ValueError
51 except ValueError:
51 except ValueError:
52 try:
52 try:
53 num = repo.changelog.rev(repo.lookup(val))
53 num = repo.changelog.rev(repo.lookup(val))
54 except KeyError:
54 except KeyError:
55 try:
55 try:
56 num = revlog.rev(revlog.lookup(val))
56 num = revlog.rev(revlog.lookup(val))
57 except KeyError:
57 except KeyError:
58 ui.warn('abort: invalid revision identifier %s\n' % val)
58 ui.warn('abort: invalid revision identifier %s\n' % val)
59 sys.exit(1)
59 sys.exit(1)
60 return num
60 return num
61 for spec in revs:
61 for spec in revs:
62 if spec.find(revrangesep) >= 0:
62 if spec.find(revrangesep) >= 0:
63 start, end = spec.split(revrangesep, 1)
63 start, end = spec.split(revrangesep, 1)
64 start = fix(start, 0)
64 start = fix(start, 0)
65 end = fix(end, revcount - 1)
65 end = fix(end, revcount - 1)
66 if end > start:
66 if end > start:
67 end += 1
67 end += 1
68 step = 1
68 step = 1
69 else:
69 else:
70 end -= 1
70 end -= 1
71 step = -1
71 step = -1
72 for rev in xrange(start, end, step):
72 for rev in xrange(start, end, step):
73 yield str(rev)
73 yield str(rev)
74 else:
74 else:
75 yield spec
75 yield spec
76
76
77 def dodiff(fp, ui, repo, files = None, node1 = None, node2 = None):
77 def dodiff(fp, ui, repo, files = None, node1 = None, node2 = None):
78 def date(c):
78 def date(c):
79 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
79 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
80
80
81 (c, a, d, u) = repo.changes(node1, node2, files)
81 (c, a, d, u) = repo.changes(node1, node2, files)
82 if files:
82 if files:
83 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
83 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
84
84
85 if not c and not a and not d:
85 if not c and not a and not d:
86 return
86 return
87
87
88 if node2:
88 if node2:
89 change = repo.changelog.read(node2)
89 change = repo.changelog.read(node2)
90 mmap2 = repo.manifest.read(change[0])
90 mmap2 = repo.manifest.read(change[0])
91 def read(f): return repo.file(f).read(mmap2[f])
91 def read(f): return repo.file(f).read(mmap2[f])
92 date2 = date(change)
92 date2 = date(change)
93 else:
93 else:
94 date2 = time.asctime()
94 date2 = time.asctime()
95 if not node1:
95 if not node1:
96 node1 = repo.dirstate.parents()[0]
96 node1 = repo.dirstate.parents()[0]
97 def read(f): return repo.wfile(f).read()
97 def read(f): return repo.wfile(f).read()
98
98
99 if ui.quiet:
99 if ui.quiet:
100 r = None
100 r = None
101 else:
101 else:
102 hexfunc = ui.verbose and hg.hex or hg.short
102 hexfunc = ui.verbose and hg.hex or hg.short
103 r = [hexfunc(node) for node in [node1, node2] if node]
103 r = [hexfunc(node) for node in [node1, node2] if node]
104
104
105 change = repo.changelog.read(node1)
105 change = repo.changelog.read(node1)
106 mmap = repo.manifest.read(change[0])
106 mmap = repo.manifest.read(change[0])
107 date1 = date(change)
107 date1 = date(change)
108
108
109 for f in c:
109 for f in c:
110 to = None
110 to = None
111 if f in mmap:
111 if f in mmap:
112 to = repo.file(f).read(mmap[f])
112 to = repo.file(f).read(mmap[f])
113 tn = read(f)
113 tn = read(f)
114 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
114 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
115 for f in a:
115 for f in a:
116 to = None
116 to = None
117 tn = read(f)
117 tn = read(f)
118 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
118 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
119 for f in d:
119 for f in d:
120 to = repo.file(f).read(mmap[f])
120 to = repo.file(f).read(mmap[f])
121 tn = None
121 tn = None
122 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
122 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
123
123
124 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
124 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
125 """show a single changeset or file revision"""
125 """show a single changeset or file revision"""
126 changelog = repo.changelog
126 changelog = repo.changelog
127 if filelog:
127 if filelog:
128 log = filelog
128 log = filelog
129 filerev = rev
129 filerev = rev
130 node = filenode = filelog.node(filerev)
130 node = filenode = filelog.node(filerev)
131 changerev = filelog.linkrev(filenode)
131 changerev = filelog.linkrev(filenode)
132 changenode = changenode or changelog.node(changerev)
132 changenode = changenode or changelog.node(changerev)
133 else:
133 else:
134 log = changelog
134 log = changelog
135 changerev = rev
135 changerev = rev
136 if changenode is None:
136 if changenode is None:
137 changenode = changelog.node(changerev)
137 changenode = changelog.node(changerev)
138 elif not changerev:
138 elif not changerev:
139 rev = changerev = changelog.rev(changenode)
139 rev = changerev = changelog.rev(changenode)
140 node = changenode
140 node = changenode
141
141
142 if ui.quiet:
142 if ui.quiet:
143 ui.write("%d:%s\n" % (rev, hg.hex(node)))
143 ui.write("%d:%s\n" % (rev, hg.hex(node)))
144 return
144 return
145
145
146 changes = changelog.read(changenode)
146 changes = changelog.read(changenode)
147
147
148 parents = [(log.rev(parent), hg.hex(parent))
148 parents = [(log.rev(parent), hg.hex(parent))
149 for parent in log.parents(node)
149 for parent in log.parents(node)
150 if ui.debugflag or parent != hg.nullid]
150 if ui.debugflag or parent != hg.nullid]
151 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
151 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
152 parents = []
152 parents = []
153
153
154 if filelog:
154 if filelog:
155 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
155 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
156 for parent in parents:
156 for parent in parents:
157 ui.write("parent: %d:%s\n" % parent)
157 ui.write("parent: %d:%s\n" % parent)
158 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
158 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
159 else:
159 else:
160 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
160 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
161 for tag in repo.nodetags(changenode):
161 for tag in repo.nodetags(changenode):
162 ui.status("tag: %s\n" % tag)
162 ui.status("tag: %s\n" % tag)
163 for parent in parents:
163 for parent in parents:
164 ui.write("parent: %d:%s\n" % parent)
164 ui.write("parent: %d:%s\n" % parent)
165 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
165 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
166 hg.hex(changes[0])))
166 hg.hex(changes[0])))
167 ui.status("user: %s\n" % changes[1])
167 ui.status("user: %s\n" % changes[1])
168 ui.status("date: %s\n" % time.asctime(
168 ui.status("date: %s\n" % time.asctime(
169 time.localtime(float(changes[2].split(' ')[0]))))
169 time.localtime(float(changes[2].split(' ')[0]))))
170 if ui.debugflag:
170 if ui.debugflag:
171 files = repo.changes(changelog.parents(changenode)[0], changenode)
171 files = repo.changes(changelog.parents(changenode)[0], changenode)
172 for key, value in zip(["files:", "files+:", "files-:"], files):
172 for key, value in zip(["files:", "files+:", "files-:"], files):
173 if value:
173 if value:
174 ui.note("%-12s %s\n" % (key, " ".join(value)))
174 ui.note("%-12s %s\n" % (key, " ".join(value)))
175 else:
175 else:
176 ui.note("files: %s\n" % " ".join(changes[3]))
176 ui.note("files: %s\n" % " ".join(changes[3]))
177 description = changes[4].strip()
177 description = changes[4].strip()
178 if description:
178 if description:
179 if ui.verbose:
179 if ui.verbose:
180 ui.status("description:\n")
180 ui.status("description:\n")
181 ui.status(description)
181 ui.status(description)
182 ui.status("\n\n")
182 ui.status("\n\n")
183 else:
183 else:
184 ui.status("summary: %s\n" % description.splitlines()[0])
184 ui.status("summary: %s\n" % description.splitlines()[0])
185 ui.status("\n")
185 ui.status("\n")
186
186
187 def show_version(ui):
187 def show_version(ui):
188 """output version and copyright information"""
188 """output version and copyright information"""
189 ui.write("Mercurial version %s\n" % version.get_version())
189 ui.write("Mercurial version %s\n" % version.get_version())
190 ui.status(
190 ui.status(
191 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
191 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
192 "This is free software; see the source for copying conditions. "
192 "This is free software; see the source for copying conditions. "
193 "There is NO\nwarranty; "
193 "There is NO\nwarranty; "
194 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
194 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
195 )
195 )
196
196
197 def help(ui, cmd=None):
197 def help(ui, cmd=None):
198 '''show help for a given command or all commands'''
198 '''show help for a given command or all commands'''
199 if cmd:
199 if cmd:
200 try:
200 try:
201 i = find(cmd)
201 i = find(cmd)
202 ui.write("%s\n\n" % i[2])
202 ui.write("%s\n\n" % i[2])
203
203
204 if i[1]:
204 if i[1]:
205 for s, l, d, c in i[1]:
205 for s, l, d, c in i[1]:
206 opt=' '
206 opt=' '
207 if s: opt = opt + '-' + s + ' '
207 if s: opt = opt + '-' + s + ' '
208 if l: opt = opt + '--' + l + ' '
208 if l: opt = opt + '--' + l + ' '
209 if d: opt = opt + '(' + str(d) + ')'
209 if d: opt = opt + '(' + str(d) + ')'
210 ui.write(opt, "\n")
210 ui.write(opt, "\n")
211 if c: ui.write(' %s\n' % c)
211 if c: ui.write(' %s\n' % c)
212 ui.write("\n")
212 ui.write("\n")
213
213
214 ui.write(i[0].__doc__, "\n")
214 ui.write(i[0].__doc__, "\n")
215 except UnknownCommand:
215 except UnknownCommand:
216 ui.warn("hg: unknown command %s\n" % cmd)
216 ui.warn("hg: unknown command %s\n" % cmd)
217 sys.exit(0)
217 sys.exit(0)
218 else:
218 else:
219 if ui.verbose:
219 if ui.verbose:
220 show_version(ui)
220 show_version(ui)
221 ui.write('\n')
221 ui.write('\n')
222 if ui.verbose:
222 if ui.verbose:
223 ui.write('hg commands:\n\n')
223 ui.write('hg commands:\n\n')
224 else:
224 else:
225 ui.write('basic hg commands (use "hg help -v" for more):\n\n')
225 ui.write('basic hg commands (use "hg help -v" for more):\n\n')
226
226
227 h = {}
227 h = {}
228 for c, e in table.items():
228 for c, e in table.items():
229 f = c.split("|")[0]
229 f = c.split("|")[0]
230 if not ui.verbose and not f.startswith("^"):
230 if not ui.verbose and not f.startswith("^"):
231 continue
231 continue
232 if not ui.debugflag and f.startswith("debug"):
232 if not ui.debugflag and f.startswith("debug"):
233 continue
233 continue
234 f = f.lstrip("^")
234 f = f.lstrip("^")
235 d = ""
235 d = ""
236 if e[0].__doc__:
236 if e[0].__doc__:
237 d = e[0].__doc__.splitlines(0)[0].rstrip()
237 d = e[0].__doc__.splitlines(0)[0].rstrip()
238 h[f] = d
238 h[f] = d
239
239
240 fns = h.keys()
240 fns = h.keys()
241 fns.sort()
241 fns.sort()
242 m = max(map(len, fns))
242 m = max(map(len, fns))
243 for f in fns:
243 for f in fns:
244 ui.write(' %-*s %s\n' % (m, f, h[f]))
244 ui.write(' %-*s %s\n' % (m, f, h[f]))
245
245
246 # Commands start here, listed alphabetically
246 # Commands start here, listed alphabetically
247
247
248 def add(ui, repo, file, *files):
248 def add(ui, repo, file, *files):
249 '''add the specified files on the next commit'''
249 '''add the specified files on the next commit'''
250 repo.add(relpath(repo, (file,) + files))
250 repo.add(relpath(repo, (file,) + files))
251
251
252 def addremove(ui, repo, *files):
252 def addremove(ui, repo, *files):
253 """add all new files, delete all missing files"""
253 """add all new files, delete all missing files"""
254 if files:
254 if files:
255 files = relpath(repo, files)
255 files = relpath(repo, files)
256 d = []
256 d = []
257 u = []
257 u = []
258 for f in files:
258 for f in files:
259 p = repo.wjoin(f)
259 p = repo.wjoin(f)
260 s = repo.dirstate.state(f)
260 s = repo.dirstate.state(f)
261 isfile = os.path.isfile(p)
261 isfile = os.path.isfile(p)
262 if s != 'r' and not isfile:
262 if s != 'r' and not isfile:
263 d.append(f)
263 d.append(f)
264 elif s not in 'nmai' and isfile:
264 elif s not in 'nmai' and isfile:
265 u.append(f)
265 u.append(f)
266 else:
266 else:
267 (c, a, d, u) = repo.changes(None, None)
267 (c, a, d, u) = repo.changes(None, None)
268 repo.add(u)
268 repo.add(u)
269 repo.remove(d)
269 repo.remove(d)
270
270
271 def annotate(u, repo, file, *files, **ops):
271 def annotate(u, repo, file, *files, **ops):
272 """show changeset information per file line"""
272 """show changeset information per file line"""
273 def getnode(rev):
273 def getnode(rev):
274 return hg.short(repo.changelog.node(rev))
274 return hg.short(repo.changelog.node(rev))
275
275
276 def getname(rev):
276 def getname(rev):
277 try:
277 try:
278 return bcache[rev]
278 return bcache[rev]
279 except KeyError:
279 except KeyError:
280 cl = repo.changelog.read(repo.changelog.node(rev))
280 cl = repo.changelog.read(repo.changelog.node(rev))
281 name = cl[1]
281 name = cl[1]
282 f = name.find('@')
282 f = name.find('@')
283 if f >= 0:
283 if f >= 0:
284 name = name[:f]
284 name = name[:f]
285 f = name.find('<')
285 f = name.find('<')
286 if f >= 0:
286 if f >= 0:
287 name = name[f+1:]
287 name = name[f+1:]
288 bcache[rev] = name
288 bcache[rev] = name
289 return name
289 return name
290
290
291 bcache = {}
291 bcache = {}
292 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
292 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
293 if not ops['user'] and not ops['changeset']:
293 if not ops['user'] and not ops['changeset']:
294 ops['number'] = 1
294 ops['number'] = 1
295
295
296 node = repo.dirstate.parents()[0]
296 node = repo.dirstate.parents()[0]
297 if ops['revision']:
297 if ops['revision']:
298 node = repo.changelog.lookup(ops['revision'])
298 node = repo.changelog.lookup(ops['revision'])
299 change = repo.changelog.read(node)
299 change = repo.changelog.read(node)
300 mmap = repo.manifest.read(change[0])
300 mmap = repo.manifest.read(change[0])
301 for f in relpath(repo, (file,) + files):
301 for f in relpath(repo, (file,) + files):
302 lines = repo.file(f).annotate(mmap[f])
302 lines = repo.file(f).annotate(mmap[f])
303 pieces = []
303 pieces = []
304
304
305 for o, f in opmap:
305 for o, f in opmap:
306 if ops[o]:
306 if ops[o]:
307 l = [ f(n) for n,t in lines ]
307 l = [ f(n) for n,t in lines ]
308 m = max(map(len, l))
308 m = max(map(len, l))
309 pieces.append([ "%*s" % (m, x) for x in l])
309 pieces.append([ "%*s" % (m, x) for x in l])
310
310
311 for p,l in zip(zip(*pieces), lines):
311 for p,l in zip(zip(*pieces), lines):
312 u.write(" ".join(p) + ": " + l[1])
312 u.write(" ".join(p) + ": " + l[1])
313
313
314 def cat(ui, repo, file, rev = []):
314 def cat(ui, repo, file, rev = []):
315 """output the latest or given revision of a file"""
315 """output the latest or given revision of a file"""
316 r = repo.file(relpath(repo, [file])[0])
316 r = repo.file(relpath(repo, [file])[0])
317 n = r.tip()
317 n = r.tip()
318 if rev: n = r.lookup(rev)
318 if rev: n = r.lookup(rev)
319 sys.stdout.write(r.read(n))
319 sys.stdout.write(r.read(n))
320
320
321 def clone(ui, source, dest = None, **opts):
321 def clone(ui, source, dest = None, **opts):
322 """make a copy of an existing repository"""
322 """make a copy of an existing repository"""
323 source = ui.expandpath(source)
323 source = ui.expandpath(source)
324
324
325 if dest is None:
325 if dest is None:
326 dest = os.path.basename(os.path.normpath(source))
326 dest = os.path.basename(os.path.normpath(source))
327
327
328 if os.path.exists(dest):
328 if os.path.exists(dest):
329 ui.warn("abort: destination '%s' already exists\n" % dest)
329 ui.warn("abort: destination '%s' already exists\n" % dest)
330 return 1
330 return 1
331
331
332 class dircleanup:
332 class dircleanup:
333 def __init__(self, dir):
333 def __init__(self, dir):
334 self.dir = dir
334 self.dir = dir
335 os.mkdir(dir)
335 os.mkdir(dir)
336 def close(self):
336 def close(self):
337 self.dir = None
337 self.dir = None
338 def __del__(self):
338 def __del__(self):
339 if self.dir:
339 if self.dir:
340 import shutil
340 import shutil
341 shutil.rmtree(self.dir, True)
341 shutil.rmtree(self.dir, True)
342
342
343 d = dircleanup(dest)
343 d = dircleanup(dest)
344
344
345 link = 0
345 link = 0
346 abspath = source
346 abspath = source
347 if not (source.startswith("http://") or
347 if not (source.startswith("http://") or
348 source.startswith("hg://") or
348 source.startswith("hg://") or
349 source.startswith("old-http://")):
349 source.startswith("old-http://")):
350 abspath = os.path.abspath(source)
350 abspath = os.path.abspath(source)
351 d1 = os.stat(dest).st_dev
351 d1 = os.stat(dest).st_dev
352 d2 = os.stat(source).st_dev
352 d2 = os.stat(source).st_dev
353 if d1 == d2: link = 1
353 if d1 == d2: link = 1
354
354
355 if link:
355 if link:
356 ui.note("copying by hardlink\n")
356 ui.note("copying by hardlink\n")
357 util.system("cp -al '%s'/.hg '%s'/.hg" % (source, dest))
357 util.system("cp -al '%s'/.hg '%s'/.hg" % (source, dest))
358 try:
358 try:
359 os.remove(os.path.join(dest, ".hg", "dirstate"))
359 os.remove(os.path.join(dest, ".hg", "dirstate"))
360 except: pass
360 except: pass
361
361
362 repo = hg.repository(ui, dest)
362 repo = hg.repository(ui, dest)
363
363
364 else:
364 else:
365 repo = hg.repository(ui, dest, create=1)
365 repo = hg.repository(ui, dest, create=1)
366 other = hg.repository(ui, source)
366 other = hg.repository(ui, source)
367 fetch = repo.findincoming(other)
367 fetch = repo.findincoming(other)
368 if fetch:
368 if fetch:
369 cg = other.changegroup(fetch)
369 cg = other.changegroup(fetch)
370 repo.addchangegroup(cg)
370 repo.addchangegroup(cg)
371
371
372 f = repo.opener("hgrc", "w")
372 f = repo.opener("hgrc", "w")
373 f.write("[paths]\n")
373 f.write("[paths]\n")
374 f.write("default = %s\n" % abspath)
374 f.write("default = %s\n" % abspath)
375
375
376 if not opts['noupdate']:
376 if not opts['noupdate']:
377 update(ui, repo)
377 update(ui, repo)
378
378
379 d.close()
379 d.close()
380
380
381 def commit(ui, repo, *files, **opts):
381 def commit(ui, repo, *files, **opts):
382 """commit the specified files or all outstanding changes"""
382 """commit the specified files or all outstanding changes"""
383 text = opts['text']
383 text = opts['text']
384 if not text and opts['logfile']:
384 if not text and opts['logfile']:
385 try: text = open(opts['logfile']).read()
385 try: text = open(opts['logfile']).read()
386 except IOError: pass
386 except IOError: pass
387
387
388 if opts['addremove']:
388 if opts['addremove']:
389 addremove(ui, repo, *files)
389 addremove(ui, repo, *files)
390 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
390 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
391
391
392 def copy(ui, repo, source, dest):
392 def copy(ui, repo, source, dest):
393 """mark a file as copied or renamed for the next commit"""
393 """mark a file as copied or renamed for the next commit"""
394 return repo.copy(*relpath(repo, (source, dest)))
394 return repo.copy(*relpath(repo, (source, dest)))
395
395
396 def debugcheckstate(ui, repo):
396 def debugcheckstate(ui, repo):
397 """validate the correctness of the current dirstate"""
397 """validate the correctness of the current dirstate"""
398 parent1, parent2 = repo.dirstate.parents()
398 parent1, parent2 = repo.dirstate.parents()
399 repo.dirstate.read()
399 repo.dirstate.read()
400 dc = repo.dirstate.map
400 dc = repo.dirstate.map
401 keys = dc.keys()
401 keys = dc.keys()
402 keys.sort()
402 keys.sort()
403 m1n = repo.changelog.read(parent1)[0]
403 m1n = repo.changelog.read(parent1)[0]
404 m2n = repo.changelog.read(parent2)[0]
404 m2n = repo.changelog.read(parent2)[0]
405 m1 = repo.manifest.read(m1n)
405 m1 = repo.manifest.read(m1n)
406 m2 = repo.manifest.read(m2n)
406 m2 = repo.manifest.read(m2n)
407 errors = 0
407 errors = 0
408 for f in dc:
408 for f in dc:
409 state = repo.dirstate.state(f)
409 state = repo.dirstate.state(f)
410 if state in "nr" and f not in m1:
410 if state in "nr" and f not in m1:
411 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
411 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
412 errors += 1
412 errors += 1
413 if state in "a" and f in m1:
413 if state in "a" and f in m1:
414 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
414 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
415 errors += 1
415 errors += 1
416 if state in "m" and f not in m1 and f not in m2:
416 if state in "m" and f not in m1 and f not in m2:
417 ui.warn("%s in state %s, but not in either manifest\n" %
417 ui.warn("%s in state %s, but not in either manifest\n" %
418 (f, state))
418 (f, state))
419 errors += 1
419 errors += 1
420 for f in m1:
420 for f in m1:
421 state = repo.dirstate.state(f)
421 state = repo.dirstate.state(f)
422 if state not in "nrm":
422 if state not in "nrm":
423 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
423 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
424 errors += 1
424 errors += 1
425 if errors:
425 if errors:
426 ui.warn(".hg/dirstate inconsistent with current parent's manifest\n")
426 ui.warn(".hg/dirstate inconsistent with current parent's manifest\n")
427 sys.exit(1)
427 sys.exit(1)
428
428
429 def debugstate(ui, repo):
429 def debugstate(ui, repo):
430 """show the contents of the current dirstate"""
430 """show the contents of the current dirstate"""
431 repo.dirstate.read()
431 repo.dirstate.read()
432 dc = repo.dirstate.map
432 dc = repo.dirstate.map
433 keys = dc.keys()
433 keys = dc.keys()
434 keys.sort()
434 keys.sort()
435 for file in keys:
435 for file in keys:
436 ui.write("%c %s\n" % (dc[file][0], file))
436 ui.write("%c %s\n" % (dc[file][0], file))
437
437
438 def debugindex(ui, file):
438 def debugindex(ui, file):
439 """dump the contents of an index file"""
439 """dump the contents of an index file"""
440 r = hg.revlog(hg.opener(""), file, "")
440 r = hg.revlog(hg.opener(""), file, "")
441 ui.write(" rev offset length base linkrev" +
441 ui.write(" rev offset length base linkrev" +
442 " p1 p2 nodeid\n")
442 " p1 p2 nodeid\n")
443 for i in range(r.count()):
443 for i in range(r.count()):
444 e = r.index[i]
444 e = r.index[i]
445 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
445 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
446 i, e[0], e[1], e[2], e[3],
446 i, e[0], e[1], e[2], e[3],
447 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
447 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
448
448
449 def debugindexdot(ui, file):
449 def debugindexdot(ui, file):
450 """dump an index DAG as a .dot file"""
450 """dump an index DAG as a .dot file"""
451 r = hg.revlog(hg.opener(""), file, "")
451 r = hg.revlog(hg.opener(""), file, "")
452 ui.write("digraph G {\n")
452 ui.write("digraph G {\n")
453 for i in range(r.count()):
453 for i in range(r.count()):
454 e = r.index[i]
454 e = r.index[i]
455 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
455 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
456 if e[5] != hg.nullid:
456 if e[5] != hg.nullid:
457 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
457 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
458 ui.write("}\n")
458 ui.write("}\n")
459
459
460 def diff(ui, repo, *files, **opts):
460 def diff(ui, repo, *files, **opts):
461 """diff working directory (or selected files)"""
461 """diff working directory (or selected files)"""
462 revs = []
462 revs = []
463 if opts['rev']:
463 if opts['rev']:
464 revs = map(lambda x: repo.lookup(x), opts['rev'])
464 revs = map(lambda x: repo.lookup(x), opts['rev'])
465
465
466 if len(revs) > 2:
466 if len(revs) > 2:
467 ui.warn("too many revisions to diff\n")
467 ui.warn("too many revisions to diff\n")
468 sys.exit(1)
468 sys.exit(1)
469
469
470 if files:
470 if files:
471 files = relpath(repo, files)
471 files = relpath(repo, files)
472 else:
472 else:
473 files = relpath(repo, [""])
473 files = relpath(repo, [""])
474
474
475 dodiff(sys.stdout, ui, repo, files, *revs)
475 dodiff(sys.stdout, ui, repo, files, *revs)
476
476
477 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
477 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
478 node = repo.lookup(changeset)
478 node = repo.lookup(changeset)
479 prev, other = repo.changelog.parents(node)
479 prev, other = repo.changelog.parents(node)
480 change = repo.changelog.read(node)
480 change = repo.changelog.read(node)
481
481
482 def expand(name):
482 def expand(name):
483 expansions = {
483 expansions = {
484 '%': lambda: '%',
484 '%': lambda: '%',
485 'H': lambda: hg.hex(node),
485 'H': lambda: hg.hex(node),
486 'N': lambda: str(total),
486 'N': lambda: str(total),
487 'R': lambda: str(repo.changelog.rev(node)),
487 'R': lambda: str(repo.changelog.rev(node)),
488 'b': lambda: os.path.basename(repo.root),
488 'b': lambda: os.path.basename(repo.root),
489 'h': lambda: hg.short(node),
489 'h': lambda: hg.short(node),
490 'n': lambda: str(seqno).zfill(len(str(total))),
490 'n': lambda: str(seqno).zfill(len(str(total))),
491 'r': lambda: str(repo.changelog.rev(node)).zfill(revwidth),
491 'r': lambda: str(repo.changelog.rev(node)).zfill(revwidth),
492 }
492 }
493 newname = []
493 newname = []
494 namelen = len(name)
494 namelen = len(name)
495 i = 0
495 i = 0
496 while i < namelen:
496 while i < namelen:
497 c = name[i]
497 c = name[i]
498 if c == '%':
498 if c == '%':
499 i += 1
499 i += 1
500 c = name[i]
500 c = name[i]
501 c = expansions[c]()
501 c = expansions[c]()
502 newname.append(c)
502 newname.append(c)
503 i += 1
503 i += 1
504 return ''.join(newname)
504 return ''.join(newname)
505
505
506 if opts['output'] and opts['output'] != '-':
506 if opts['output'] and opts['output'] != '-':
507 try:
507 try:
508 fp = open(expand(opts['output']), 'w')
508 fp = open(expand(opts['output']), 'w')
509 except KeyError, inst:
509 except KeyError, inst:
510 ui.warn("error: invalid format spec '%%%s' in output file name\n" %
510 ui.warn("error: invalid format spec '%%%s' in output file name\n" %
511 inst.args[0])
511 inst.args[0])
512 sys.exit(1)
512 sys.exit(1)
513 else:
513 else:
514 fp = sys.stdout
514 fp = sys.stdout
515
515
516 fp.write("# HG changeset patch\n")
516 fp.write("# HG changeset patch\n")
517 fp.write("# User %s\n" % change[1])
517 fp.write("# User %s\n" % change[1])
518 fp.write("# Node ID %s\n" % hg.hex(node))
518 fp.write("# Node ID %s\n" % hg.hex(node))
519 fp.write("# Parent %s\n" % hg.hex(prev))
519 fp.write("# Parent %s\n" % hg.hex(prev))
520 if other != hg.nullid:
520 if other != hg.nullid:
521 fp.write("# Parent %s\n" % hg.hex(other))
521 fp.write("# Parent %s\n" % hg.hex(other))
522 fp.write(change[4].rstrip())
522 fp.write(change[4].rstrip())
523 fp.write("\n\n")
523 fp.write("\n\n")
524
524
525 dodiff(fp, ui, repo, None, prev, node)
525 dodiff(fp, ui, repo, None, prev, node)
526
526
527 def export(ui, repo, *changesets, **opts):
527 def export(ui, repo, *changesets, **opts):
528 """dump the header and diffs for one or more changesets"""
528 """dump the header and diffs for one or more changesets"""
529 if not changesets:
529 if not changesets:
530 ui.warn("error: export requires at least one changeset\n")
530 ui.warn("error: export requires at least one changeset\n")
531 sys.exit(1)
531 sys.exit(1)
532 seqno = 0
532 seqno = 0
533 revs = list(revrange(ui, repo, changesets))
533 revs = list(revrange(ui, repo, changesets))
534 total = len(revs)
534 total = len(revs)
535 revwidth = max(len(revs[0]), len(revs[-1]))
535 revwidth = max(len(revs[0]), len(revs[-1]))
536 for cset in revs:
536 for cset in revs:
537 seqno += 1
537 seqno += 1
538 doexport(ui, repo, cset, seqno, total, revwidth, opts)
538 doexport(ui, repo, cset, seqno, total, revwidth, opts)
539
539
540 def forget(ui, repo, file, *files):
540 def forget(ui, repo, file, *files):
541 """don't add the specified files on the next commit"""
541 """don't add the specified files on the next commit"""
542 repo.forget(relpath(repo, (file,) + files))
542 repo.forget(relpath(repo, (file,) + files))
543
543
544 def heads(ui, repo):
544 def heads(ui, repo):
545 """show current repository heads"""
545 """show current repository heads"""
546 for n in repo.changelog.heads():
546 for n in repo.changelog.heads():
547 show_changeset(ui, repo, changenode=n)
547 show_changeset(ui, repo, changenode=n)
548
548
549 def identify(ui, repo):
549 def identify(ui, repo):
550 """print information about the working copy"""
550 """print information about the working copy"""
551 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
551 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
552 if not parents:
552 if not parents:
553 ui.write("unknown\n")
553 ui.write("unknown\n")
554 return
554 return
555
555
556 hexfunc = ui.verbose and hg.hex or hg.short
556 hexfunc = ui.verbose and hg.hex or hg.short
557 (c, a, d, u) = repo.changes(None, None)
557 (c, a, d, u) = repo.changes(None, None)
558 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
558 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
559 (c or a or d) and "+" or "")]
559 (c or a or d) and "+" or "")]
560
560
561 if not ui.quiet:
561 if not ui.quiet:
562 # multiple tags for a single parent separated by '/'
562 # multiple tags for a single parent separated by '/'
563 parenttags = ['/'.join(tags)
563 parenttags = ['/'.join(tags)
564 for tags in map(repo.nodetags, parents) if tags]
564 for tags in map(repo.nodetags, parents) if tags]
565 # tags for multiple parents separated by ' + '
565 # tags for multiple parents separated by ' + '
566 output.append(' + '.join(parenttags))
566 output.append(' + '.join(parenttags))
567
567
568 ui.write("%s\n" % ' '.join(output))
568 ui.write("%s\n" % ' '.join(output))
569
569
570 def import_(ui, repo, patch1, *patches, **opts):
570 def import_(ui, repo, patch1, *patches, **opts):
571 """import an ordered set of patches"""
571 """import an ordered set of patches"""
572 try:
572 try:
573 import psyco
573 import psyco
574 psyco.full()
574 psyco.full()
575 except:
575 except:
576 pass
576 pass
577
577
578 patches = (patch1,) + patches
578 patches = (patch1,) + patches
579
579
580 d = opts["base"]
580 d = opts["base"]
581 strip = opts["strip"]
581 strip = opts["strip"]
582
582
583 for patch in patches:
583 for patch in patches:
584 ui.status("applying %s\n" % patch)
584 ui.status("applying %s\n" % patch)
585 pf = os.path.join(d, patch)
585 pf = os.path.join(d, patch)
586
586
587 text = ""
587 text = ""
588 for l in file(pf):
588 for l in file(pf):
589 if l[:4] == "--- ": break
589 if l[:4] == "--- ": break
590 text += l
590 text += l
591
591
592 # parse values that exist when importing the result of an hg export
592 # parse values that exist when importing the result of an hg export
593 hgpatch = user = snippet = None
593 hgpatch = user = snippet = None
594 ui.debug('text:\n')
594 ui.debug('text:\n')
595 for t in text.splitlines():
595 for t in text.splitlines():
596 ui.debug(t,'\n')
596 ui.debug(t,'\n')
597 if t == '# HG changeset patch' or hgpatch == True:
597 if t == '# HG changeset patch' or hgpatch == True:
598 hgpatch = True
598 hgpatch = True
599 if t[:7] == "# User ":
599 if t[:7] == "# User ":
600 user = t[7:]
600 user = t[7:]
601 ui.debug('User: %s\n' % user)
601 ui.debug('User: %s\n' % user)
602 if t[:2] <> "# " and t.strip() and not snippet: snippet = t
602 if t[:2] <> "# " and t.strip() and not snippet: snippet = t
603 if snippet: text = snippet + '\n' + text
603 if snippet: text = snippet + '\n' + text
604 ui.debug('text:\n%s\n' % text)
604 ui.debug('text:\n%s\n' % text)
605
605
606 # make sure text isn't empty
606 # make sure text isn't empty
607 if not text: text = "imported patch %s\n" % patch
607 if not text: text = "imported patch %s\n" % patch
608
608
609 f = os.popen("patch -p%d < %s" % (strip, pf))
609 f = os.popen("patch -p%d < %s" % (strip, pf))
610 files = []
610 files = []
611 for l in f.read().splitlines():
611 for l in f.read().splitlines():
612 l.rstrip('\r\n');
612 l.rstrip('\r\n');
613 ui.status("%s\n" % l)
613 ui.status("%s\n" % l)
614 if l[:14] == 'patching file ':
614 if l[:14] == 'patching file ':
615 pf = l[14:]
615 pf = l[14:]
616 if pf not in files:
616 if pf not in files:
617 files.append(pf)
617 files.append(pf)
618 patcherr = f.close()
618 patcherr = f.close()
619 if patcherr:
619 if patcherr:
620 sys.stderr.write("patch failed")
620 sys.stderr.write("patch failed")
621 sys.exit(1)
621 sys.exit(1)
622
622
623 if len(files) > 0:
623 if len(files) > 0:
624 addremove(ui, repo, *files)
624 addremove(ui, repo, *files)
625 repo.commit(files, text, user)
625 repo.commit(files, text, user)
626
626
627 def init(ui, source=None):
627 def init(ui, source=None):
628 """create a new repository in the current directory"""
628 """create a new repository in the current directory"""
629
629
630 if source:
630 if source:
631 ui.warn("no longer supported: use \"hg clone\" instead\n")
631 ui.warn("no longer supported: use \"hg clone\" instead\n")
632 sys.exit(1)
632 sys.exit(1)
633 repo = hg.repository(ui, ".", create=1)
633 repo = hg.repository(ui, ".", create=1)
634
634
635 def log(ui, repo, f=None, **opts):
635 def log(ui, repo, f=None, **opts):
636 """show the revision history of the repository or a single file"""
636 """show the revision history of the repository or a single file"""
637 if f:
637 if f:
638 filelog = repo.file(relpath(repo, [f])[0])
638 files = relpath(repo, [f])
639 filelog = repo.file(files[0])
639 log = filelog
640 log = filelog
640 lookup = filelog.lookup
641 lookup = filelog.lookup
641 else:
642 else:
643 files = None
642 filelog = None
644 filelog = None
643 log = repo.changelog
645 log = repo.changelog
644 lookup = repo.lookup
646 lookup = repo.lookup
645 revlist = []
647 revlist = []
646 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
648 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
647 while revs:
649 while revs:
648 if len(revs) == 1:
650 if len(revs) == 1:
649 revlist.append(revs.pop(0))
651 revlist.append(revs.pop(0))
650 else:
652 else:
651 a = revs.pop(0)
653 a = revs.pop(0)
652 b = revs.pop(0)
654 b = revs.pop(0)
653 off = a > b and -1 or 1
655 off = a > b and -1 or 1
654 revlist.extend(range(a, b + off, off))
656 revlist.extend(range(a, b + off, off))
655
657
656 for i in revlist or range(log.count() - 1, -1, -1):
658 for i in revlist or range(log.count() - 1, -1, -1):
657 show_changeset(ui, repo, filelog=filelog, rev=i)
659 show_changeset(ui, repo, filelog=filelog, rev=i)
660 if opts['patch']:
661 if filelog:
662 filenode = filelog.node(i)
663 i = filelog.linkrev(filenode)
664 changenode = repo.changelog.node(i)
665 prev, other = repo.changelog.parents(changenode)
666 dodiff(sys.stdout, ui, repo, files, prev, changenode)
667 ui.write("\n")
668 ui.write("\n")
658
669
659 def manifest(ui, repo, rev = []):
670 def manifest(ui, repo, rev = []):
660 """output the latest or given revision of the project manifest"""
671 """output the latest or given revision of the project manifest"""
661 n = repo.manifest.tip()
672 n = repo.manifest.tip()
662 if rev:
673 if rev:
663 n = repo.manifest.lookup(rev)
674 n = repo.manifest.lookup(rev)
664 m = repo.manifest.read(n)
675 m = repo.manifest.read(n)
665 mf = repo.manifest.readflags(n)
676 mf = repo.manifest.readflags(n)
666 files = m.keys()
677 files = m.keys()
667 files.sort()
678 files.sort()
668
679
669 for f in files:
680 for f in files:
670 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
681 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
671
682
672 def parents(ui, repo, node = None):
683 def parents(ui, repo, node = None):
673 '''show the parents of the current working dir'''
684 '''show the parents of the current working dir'''
674 if node:
685 if node:
675 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
686 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
676 else:
687 else:
677 p = repo.dirstate.parents()
688 p = repo.dirstate.parents()
678
689
679 for n in p:
690 for n in p:
680 if n != hg.nullid:
691 if n != hg.nullid:
681 show_changeset(ui, repo, changenode=n)
692 show_changeset(ui, repo, changenode=n)
682
693
683 def pull(ui, repo, source="default", **opts):
694 def pull(ui, repo, source="default", **opts):
684 """pull changes from the specified source"""
695 """pull changes from the specified source"""
685 source = ui.expandpath(source)
696 source = ui.expandpath(source)
686
697
687 ui.status('pulling from %s\n' % (source))
698 ui.status('pulling from %s\n' % (source))
688
699
689 other = hg.repository(ui, source)
700 other = hg.repository(ui, source)
690 fetch = repo.findincoming(other)
701 fetch = repo.findincoming(other)
691 if not fetch:
702 if not fetch:
692 ui.status("no changes found\n")
703 ui.status("no changes found\n")
693 return
704 return
694
705
695 cg = other.changegroup(fetch)
706 cg = other.changegroup(fetch)
696 r = repo.addchangegroup(cg)
707 r = repo.addchangegroup(cg)
697 if cg and not r:
708 if cg and not r:
698 if opts['update']:
709 if opts['update']:
699 return update(ui, repo)
710 return update(ui, repo)
700 else:
711 else:
701 ui.status("(run 'hg update' to get a working copy)\n")
712 ui.status("(run 'hg update' to get a working copy)\n")
702
713
703 return r
714 return r
704
715
705 def push(ui, repo, dest="default-push"):
716 def push(ui, repo, dest="default-push"):
706 """push changes to the specified destination"""
717 """push changes to the specified destination"""
707 dest = ui.expandpath(dest)
718 dest = ui.expandpath(dest)
708
719
709 if not dest.startswith("ssh://"):
720 if not dest.startswith("ssh://"):
710 ui.warn("abort: can only push to ssh:// destinations currently\n")
721 ui.warn("abort: can only push to ssh:// destinations currently\n")
711 return 1
722 return 1
712
723
713 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
724 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
714 if not m:
725 if not m:
715 ui.warn("abort: couldn't parse destination %s\n" % dest)
726 ui.warn("abort: couldn't parse destination %s\n" % dest)
716 return 1
727 return 1
717
728
718 user, host, port, path = map(m.group, (2, 3, 5, 7))
729 user, host, port, path = map(m.group, (2, 3, 5, 7))
719 uhost = user and ("%s@%s" % (user, host)) or host
730 uhost = user and ("%s@%s" % (user, host)) or host
720 port = port and (" -p %s") % port or ""
731 port = port and (" -p %s") % port or ""
721 path = path or ""
732 path = path or ""
722
733
723 sport = random.randrange(30000, 60000)
734 sport = random.randrange(30000, 60000)
724 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
735 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
725 cmd = cmd % (uhost, port, sport+1, sport, path, sport+1)
736 cmd = cmd % (uhost, port, sport+1, sport, path, sport+1)
726
737
727 child = os.fork()
738 child = os.fork()
728 if not child:
739 if not child:
729 sys.stdout = file("/dev/null", "w")
740 sys.stdout = file("/dev/null", "w")
730 sys.stderr = sys.stdout
741 sys.stderr = sys.stdout
731 hgweb.server(repo.root, "pull", "", "localhost", sport)
742 hgweb.server(repo.root, "pull", "", "localhost", sport)
732 else:
743 else:
733 ui.status("connecting to %s\n" % host)
744 ui.status("connecting to %s\n" % host)
734 r = os.system(cmd)
745 r = os.system(cmd)
735 os.kill(child, signal.SIGTERM)
746 os.kill(child, signal.SIGTERM)
736 return r
747 return r
737
748
738 def rawcommit(ui, repo, *flist, **rc):
749 def rawcommit(ui, repo, *flist, **rc):
739 "raw commit interface"
750 "raw commit interface"
740
751
741 text = rc['text']
752 text = rc['text']
742 if not text and rc['logfile']:
753 if not text and rc['logfile']:
743 try: text = open(rc['logfile']).read()
754 try: text = open(rc['logfile']).read()
744 except IOError: pass
755 except IOError: pass
745 if not text and not rc['logfile']:
756 if not text and not rc['logfile']:
746 ui.warn("abort: missing commit text\n")
757 ui.warn("abort: missing commit text\n")
747 return 1
758 return 1
748
759
749 files = relpath(repo, list(flist))
760 files = relpath(repo, list(flist))
750 if rc['files']:
761 if rc['files']:
751 files += open(rc['files']).read().splitlines()
762 files += open(rc['files']).read().splitlines()
752
763
753 rc['parent'] = map(repo.lookup, rc['parent'])
764 rc['parent'] = map(repo.lookup, rc['parent'])
754
765
755 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
766 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
756
767
757 def recover(ui, repo):
768 def recover(ui, repo):
758 """roll back an interrupted transaction"""
769 """roll back an interrupted transaction"""
759 repo.recover()
770 repo.recover()
760
771
761 def remove(ui, repo, file, *files):
772 def remove(ui, repo, file, *files):
762 """remove the specified files on the next commit"""
773 """remove the specified files on the next commit"""
763 repo.remove(relpath(repo, (file,) + files))
774 repo.remove(relpath(repo, (file,) + files))
764
775
765 def revert(ui, repo, *names, **opts):
776 def revert(ui, repo, *names, **opts):
766 """revert modified files or dirs back to their unmodified states"""
777 """revert modified files or dirs back to their unmodified states"""
767 node = opts['rev'] and repo.lookup(opts['rev']) or \
778 node = opts['rev'] and repo.lookup(opts['rev']) or \
768 repo.dirstate.parents()[0]
779 repo.dirstate.parents()[0]
769 root = os.path.realpath(repo.root)
780 root = os.path.realpath(repo.root)
770
781
771 def trimpath(p):
782 def trimpath(p):
772 p = os.path.realpath(p)
783 p = os.path.realpath(p)
773 if p.startswith(root):
784 if p.startswith(root):
774 rest = p[len(root):]
785 rest = p[len(root):]
775 if not rest:
786 if not rest:
776 return rest
787 return rest
777 if p.startswith(os.sep):
788 if p.startswith(os.sep):
778 return rest[1:]
789 return rest[1:]
779 return p
790 return p
780
791
781 relnames = map(trimpath, names or [os.getcwd()])
792 relnames = map(trimpath, names or [os.getcwd()])
782 chosen = {}
793 chosen = {}
783
794
784 def choose(name):
795 def choose(name):
785 def body(name):
796 def body(name):
786 for r in relnames:
797 for r in relnames:
787 if not name.startswith(r): continue
798 if not name.startswith(r): continue
788 rest = name[len(r):]
799 rest = name[len(r):]
789 if not rest: return r, True
800 if not rest: return r, True
790 depth = rest.count(os.sep)
801 depth = rest.count(os.sep)
791 if not r:
802 if not r:
792 if depth == 0 or not opts['nonrecursive']: return r, True
803 if depth == 0 or not opts['nonrecursive']: return r, True
793 elif rest[0] == os.sep:
804 elif rest[0] == os.sep:
794 if depth == 1 or not opts['nonrecursive']: return r, True
805 if depth == 1 or not opts['nonrecursive']: return r, True
795 return None, False
806 return None, False
796 relname, ret = body(name)
807 relname, ret = body(name)
797 if ret:
808 if ret:
798 chosen[relname] = 1
809 chosen[relname] = 1
799 return ret
810 return ret
800
811
801 r = repo.update(node, False, True, choose, False)
812 r = repo.update(node, False, True, choose, False)
802 for n in relnames:
813 for n in relnames:
803 if n not in chosen:
814 if n not in chosen:
804 ui.warn('error: no matches for %s\n' % n)
815 ui.warn('error: no matches for %s\n' % n)
805 r = 1
816 r = 1
806 sys.stdout.flush()
817 sys.stdout.flush()
807 return r
818 return r
808
819
809 def root(ui, repo):
820 def root(ui, repo):
810 """print the root (top) of the current working dir"""
821 """print the root (top) of the current working dir"""
811 ui.write(repo.root + "\n")
822 ui.write(repo.root + "\n")
812
823
813 def serve(ui, repo, **opts):
824 def serve(ui, repo, **opts):
814 """export the repository via HTTP"""
825 """export the repository via HTTP"""
815 def openlog(opt, default):
826 def openlog(opt, default):
816 if opts[opt] and opts[opt] != '-': return open(opts[opt], 'w')
827 if opts[opt] and opts[opt] != '-': return open(opts[opt], 'w')
817 else: return default
828 else: return default
818 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
829 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
819 opts["address"], opts["port"],
830 opts["address"], opts["port"],
820 openlog('accesslog', sys.stdout),
831 openlog('accesslog', sys.stdout),
821 openlog('errorlog', sys.stderr))
832 openlog('errorlog', sys.stderr))
822 if ui.verbose:
833 if ui.verbose:
823 addr, port = httpd.socket.getsockname()
834 addr, port = httpd.socket.getsockname()
824 if addr == '0.0.0.0':
835 if addr == '0.0.0.0':
825 addr = socket.gethostname()
836 addr = socket.gethostname()
826 else:
837 else:
827 try:
838 try:
828 addr = socket.gethostbyaddr(addr)[0]
839 addr = socket.gethostbyaddr(addr)[0]
829 except: pass
840 except: pass
830 if port != 80:
841 if port != 80:
831 ui.status('listening at http://%s:%d/\n' % (addr, port))
842 ui.status('listening at http://%s:%d/\n' % (addr, port))
832 else:
843 else:
833 ui.status('listening at http://%s/\n' % addr)
844 ui.status('listening at http://%s/\n' % addr)
834 httpd.serve_forever()
845 httpd.serve_forever()
835
846
836 def status(ui, repo):
847 def status(ui, repo):
837 '''show changed files in the working directory
848 '''show changed files in the working directory
838
849
839 C = changed
850 C = changed
840 A = added
851 A = added
841 R = removed
852 R = removed
842 ? = not tracked'''
853 ? = not tracked'''
843
854
844 (c, a, d, u) = repo.changes(None, None)
855 (c, a, d, u) = repo.changes(None, None)
845 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
856 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
846
857
847 for f in c: ui.write("C ", f, "\n")
858 for f in c: ui.write("C ", f, "\n")
848 for f in a: ui.write("A ", f, "\n")
859 for f in a: ui.write("A ", f, "\n")
849 for f in d: ui.write("R ", f, "\n")
860 for f in d: ui.write("R ", f, "\n")
850 for f in u: ui.write("? ", f, "\n")
861 for f in u: ui.write("? ", f, "\n")
851
862
852 def tag(ui, repo, name, rev = None, **opts):
863 def tag(ui, repo, name, rev = None, **opts):
853 """add a tag for the current tip or a given revision"""
864 """add a tag for the current tip or a given revision"""
854
865
855 if name == "tip":
866 if name == "tip":
856 ui.warn("abort: 'tip' is a reserved name!\n")
867 ui.warn("abort: 'tip' is a reserved name!\n")
857 return -1
868 return -1
858 if rev:
869 if rev:
859 r = hg.hex(repo.lookup(rev))
870 r = hg.hex(repo.lookup(rev))
860 else:
871 else:
861 r = hg.hex(repo.changelog.tip())
872 r = hg.hex(repo.changelog.tip())
862
873
863 if name.find(revrangesep) >= 0:
874 if name.find(revrangesep) >= 0:
864 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
875 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
865 return -1
876 return -1
866
877
867 if opts['local']:
878 if opts['local']:
868 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
879 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
869 return
880 return
870
881
871 (c, a, d, u) = repo.changes(None, None)
882 (c, a, d, u) = repo.changes(None, None)
872 for x in (c, a, d, u):
883 for x in (c, a, d, u):
873 if ".hgtags" in x:
884 if ".hgtags" in x:
874 ui.warn("abort: working copy of .hgtags is changed!\n")
885 ui.warn("abort: working copy of .hgtags is changed!\n")
875 ui.status("(please commit .hgtags manually)\n")
886 ui.status("(please commit .hgtags manually)\n")
876 return -1
887 return -1
877
888
878 add = 0
889 add = 0
879 if not os.path.exists(repo.wjoin(".hgtags")): add = 1
890 if not os.path.exists(repo.wjoin(".hgtags")): add = 1
880 repo.wfile(".hgtags", "a").write("%s %s\n" % (r, name))
891 repo.wfile(".hgtags", "a").write("%s %s\n" % (r, name))
881 if add: repo.add([".hgtags"])
892 if add: repo.add([".hgtags"])
882
893
883 if not opts['text']:
894 if not opts['text']:
884 opts['text'] = "Added tag %s for changeset %s" % (name, r)
895 opts['text'] = "Added tag %s for changeset %s" % (name, r)
885
896
886 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
897 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
887
898
888 def tags(ui, repo):
899 def tags(ui, repo):
889 """list repository tags"""
900 """list repository tags"""
890
901
891 l = repo.tagslist()
902 l = repo.tagslist()
892 l.reverse()
903 l.reverse()
893 for t, n in l:
904 for t, n in l:
894 try:
905 try:
895 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
906 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
896 except KeyError:
907 except KeyError:
897 r = " ?:?"
908 r = " ?:?"
898 ui.write("%-30s %s\n" % (t, r))
909 ui.write("%-30s %s\n" % (t, r))
899
910
900 def tip(ui, repo):
911 def tip(ui, repo):
901 """show the tip revision"""
912 """show the tip revision"""
902 n = repo.changelog.tip()
913 n = repo.changelog.tip()
903 show_changeset(ui, repo, changenode=n)
914 show_changeset(ui, repo, changenode=n)
904
915
905 def undo(ui, repo):
916 def undo(ui, repo):
906 """undo the last commit or pull
917 """undo the last commit or pull
907
918
908 Roll back the last pull or commit transaction on the
919 Roll back the last pull or commit transaction on the
909 repository, restoring the project to its earlier state.
920 repository, restoring the project to its earlier state.
910
921
911 This command should be used with care. There is only one level of
922 This command should be used with care. There is only one level of
912 undo and there is no redo.
923 undo and there is no redo.
913
924
914 This command is not intended for use on public repositories. Once
925 This command is not intended for use on public repositories. Once
915 a change is visible for pull by other users, undoing it locally is
926 a change is visible for pull by other users, undoing it locally is
916 ineffective.
927 ineffective.
917 """
928 """
918 repo.undo()
929 repo.undo()
919
930
920 def update(ui, repo, node=None, merge=False, clean=False):
931 def update(ui, repo, node=None, merge=False, clean=False):
921 '''update or merge working directory
932 '''update or merge working directory
922
933
923 If there are no outstanding changes in the working directory and
934 If there are no outstanding changes in the working directory and
924 there is a linear relationship between the current version and the
935 there is a linear relationship between the current version and the
925 requested version, the result is the requested version.
936 requested version, the result is the requested version.
926
937
927 Otherwise the result is a merge between the contents of the
938 Otherwise the result is a merge between the contents of the
928 current working directory and the requested version. Files that
939 current working directory and the requested version. Files that
929 changed between either parent are marked as changed for the next
940 changed between either parent are marked as changed for the next
930 commit and a commit must be performed before any further updates
941 commit and a commit must be performed before any further updates
931 are allowed.
942 are allowed.
932 '''
943 '''
933 node = node and repo.lookup(node) or repo.changelog.tip()
944 node = node and repo.lookup(node) or repo.changelog.tip()
934 return repo.update(node, allow=merge, force=clean)
945 return repo.update(node, allow=merge, force=clean)
935
946
936 def verify(ui, repo):
947 def verify(ui, repo):
937 """verify the integrity of the repository"""
948 """verify the integrity of the repository"""
938 return repo.verify()
949 return repo.verify()
939
950
940 # Command options and aliases are listed here, alphabetically
951 # Command options and aliases are listed here, alphabetically
941
952
942 table = {
953 table = {
943 "^add": (add, [], "hg add [files]"),
954 "^add": (add, [], "hg add [files]"),
944 "addremove": (addremove, [], "hg addremove [files]"),
955 "addremove": (addremove, [], "hg addremove [files]"),
945 "^annotate": (annotate,
956 "^annotate": (annotate,
946 [('r', 'revision', '', 'revision'),
957 [('r', 'revision', '', 'revision'),
947 ('u', 'user', None, 'show user'),
958 ('u', 'user', None, 'show user'),
948 ('n', 'number', None, 'show revision number'),
959 ('n', 'number', None, 'show revision number'),
949 ('c', 'changeset', None, 'show changeset')],
960 ('c', 'changeset', None, 'show changeset')],
950 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
961 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
951 "cat": (cat, [], 'hg cat <file> [rev]'),
962 "cat": (cat, [], 'hg cat <file> [rev]'),
952 "^clone": (clone, [('U', 'noupdate', None, 'skip update after cloning')],
963 "^clone": (clone, [('U', 'noupdate', None, 'skip update after cloning')],
953 'hg clone [options] <source> [dest]'),
964 'hg clone [options] <source> [dest]'),
954 "^commit|ci": (commit,
965 "^commit|ci": (commit,
955 [('t', 'text', "", 'commit text'),
966 [('t', 'text', "", 'commit text'),
956 ('A', 'addremove', None, 'run add/remove during commit'),
967 ('A', 'addremove', None, 'run add/remove during commit'),
957 ('l', 'logfile', "", 'commit text file'),
968 ('l', 'logfile', "", 'commit text file'),
958 ('d', 'date', "", 'date code'),
969 ('d', 'date', "", 'date code'),
959 ('u', 'user', "", 'user')],
970 ('u', 'user', "", 'user')],
960 'hg commit [files]'),
971 'hg commit [files]'),
961 "copy": (copy, [], 'hg copy <source> <dest>'),
972 "copy": (copy, [], 'hg copy <source> <dest>'),
962 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
973 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
963 "debugstate": (debugstate, [], 'debugstate'),
974 "debugstate": (debugstate, [], 'debugstate'),
964 "debugindex": (debugindex, [], 'debugindex <file>'),
975 "debugindex": (debugindex, [], 'debugindex <file>'),
965 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
976 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
966 "^diff": (diff, [('r', 'rev', [], 'revision')],
977 "^diff": (diff, [('r', 'rev', [], 'revision')],
967 'hg diff [-r A] [-r B] [files]'),
978 'hg diff [-r A] [-r B] [files]'),
968 "^export": (export, [('o', 'output', "", 'output to file')],
979 "^export": (export, [('o', 'output', "", 'output to file')],
969 "hg export [-o file] <changeset> ..."),
980 "hg export [-o file] <changeset> ..."),
970 "forget": (forget, [], "hg forget [files]"),
981 "forget": (forget, [], "hg forget [files]"),
971 "heads": (heads, [], 'hg heads'),
982 "heads": (heads, [], 'hg heads'),
972 "help": (help, [], 'hg help [command]'),
983 "help": (help, [], 'hg help [command]'),
973 "identify|id": (identify, [], 'hg identify'),
984 "identify|id": (identify, [], 'hg identify'),
974 "import|patch": (import_,
985 "import|patch": (import_,
975 [('p', 'strip', 1, 'path strip'),
986 [('p', 'strip', 1, 'path strip'),
976 ('b', 'base', "", 'base path')],
987 ('b', 'base', "", 'base path')],
977 "hg import [options] <patches>"),
988 "hg import [options] <patches>"),
978 "^init": (init, [], 'hg init'),
989 "^init": (init, [], 'hg init'),
979 "^log|history": (log,
990 "^log|history": (log,
980 [('r', 'rev', [], 'revision')],
991 [('r', 'rev', [], 'revision'),
981 'hg log [-r A] [-r B] [file]'),
992 ('p', 'patch', None, 'show patch')],
993 'hg log [-r A] [-r B] [-p] [file]'),
982 "manifest": (manifest, [], 'hg manifest [rev]'),
994 "manifest": (manifest, [], 'hg manifest [rev]'),
983 "parents": (parents, [], 'hg parents [node]'),
995 "parents": (parents, [], 'hg parents [node]'),
984 "^pull": (pull,
996 "^pull": (pull,
985 [('u', 'update', None, 'update working directory')],
997 [('u', 'update', None, 'update working directory')],
986 'hg pull [options] [source]'),
998 'hg pull [options] [source]'),
987 "^push": (push, [], 'hg push <destination>'),
999 "^push": (push, [], 'hg push <destination>'),
988 "rawcommit": (rawcommit,
1000 "rawcommit": (rawcommit,
989 [('p', 'parent', [], 'parent'),
1001 [('p', 'parent', [], 'parent'),
990 ('d', 'date', "", 'date code'),
1002 ('d', 'date', "", 'date code'),
991 ('u', 'user', "", 'user'),
1003 ('u', 'user', "", 'user'),
992 ('F', 'files', "", 'file list'),
1004 ('F', 'files', "", 'file list'),
993 ('t', 'text', "", 'commit text'),
1005 ('t', 'text', "", 'commit text'),
994 ('l', 'logfile', "", 'commit text file')],
1006 ('l', 'logfile', "", 'commit text file')],
995 'hg rawcommit [options] [files]'),
1007 'hg rawcommit [options] [files]'),
996 "recover": (recover, [], "hg recover"),
1008 "recover": (recover, [], "hg recover"),
997 "^remove|rm": (remove, [], "hg remove [files]"),
1009 "^remove|rm": (remove, [], "hg remove [files]"),
998 "^revert": (revert,
1010 "^revert": (revert,
999 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1011 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1000 ("r", "rev", "", "revision")],
1012 ("r", "rev", "", "revision")],
1001 "hg revert [files|dirs]"),
1013 "hg revert [files|dirs]"),
1002 "root": (root, [], "hg root"),
1014 "root": (root, [], "hg root"),
1003 "^serve": (serve, [('A', 'accesslog', '', 'access log file'),
1015 "^serve": (serve, [('A', 'accesslog', '', 'access log file'),
1004 ('E', 'errorlog', '', 'error log file'),
1016 ('E', 'errorlog', '', 'error log file'),
1005 ('p', 'port', 8000, 'listen port'),
1017 ('p', 'port', 8000, 'listen port'),
1006 ('a', 'address', '', 'interface address'),
1018 ('a', 'address', '', 'interface address'),
1007 ('n', 'name', os.getcwd(), 'repository name'),
1019 ('n', 'name', os.getcwd(), 'repository name'),
1008 ('t', 'templates', "", 'template map')],
1020 ('t', 'templates', "", 'template map')],
1009 "hg serve [options]"),
1021 "hg serve [options]"),
1010 "^status": (status, [], 'hg status'),
1022 "^status": (status, [], 'hg status'),
1011 "tag": (tag, [('l', 'local', None, 'make the tag local'),
1023 "tag": (tag, [('l', 'local', None, 'make the tag local'),
1012 ('t', 'text', "", 'commit text'),
1024 ('t', 'text', "", 'commit text'),
1013 ('d', 'date', "", 'date code'),
1025 ('d', 'date', "", 'date code'),
1014 ('u', 'user', "", 'user')],
1026 ('u', 'user', "", 'user')],
1015 'hg tag [options] <name> [rev]'),
1027 'hg tag [options] <name> [rev]'),
1016 "tags": (tags, [], 'hg tags'),
1028 "tags": (tags, [], 'hg tags'),
1017 "tip": (tip, [], 'hg tip'),
1029 "tip": (tip, [], 'hg tip'),
1018 "undo": (undo, [], 'hg undo'),
1030 "undo": (undo, [], 'hg undo'),
1019 "^update|up|checkout|co":
1031 "^update|up|checkout|co":
1020 (update,
1032 (update,
1021 [('m', 'merge', None, 'allow merging of conflicts'),
1033 [('m', 'merge', None, 'allow merging of conflicts'),
1022 ('C', 'clean', None, 'overwrite locally modified files')],
1034 ('C', 'clean', None, 'overwrite locally modified files')],
1023 'hg update [options] [node]'),
1035 'hg update [options] [node]'),
1024 "verify": (verify, [], 'hg verify'),
1036 "verify": (verify, [], 'hg verify'),
1025 "version": (show_version, [], 'hg version'),
1037 "version": (show_version, [], 'hg version'),
1026 }
1038 }
1027
1039
1028 globalopts = [('v', 'verbose', None, 'verbose'),
1040 globalopts = [('v', 'verbose', None, 'verbose'),
1029 ('', 'debug', None, 'debug'),
1041 ('', 'debug', None, 'debug'),
1030 ('q', 'quiet', None, 'quiet'),
1042 ('q', 'quiet', None, 'quiet'),
1031 ('', 'profile', None, 'profile'),
1043 ('', 'profile', None, 'profile'),
1032 ('R', 'repository', "", 'repository root directory'),
1044 ('R', 'repository', "", 'repository root directory'),
1033 ('', 'traceback', None, 'print traceback on exception'),
1045 ('', 'traceback', None, 'print traceback on exception'),
1034 ('y', 'noninteractive', None, 'run non-interactively'),
1046 ('y', 'noninteractive', None, 'run non-interactively'),
1035 ('', 'version', None, 'output version information and exit'),
1047 ('', 'version', None, 'output version information and exit'),
1036 ]
1048 ]
1037
1049
1038 norepo = "clone init version help debugindex debugindexdot"
1050 norepo = "clone init version help debugindex debugindexdot"
1039
1051
1040 def find(cmd):
1052 def find(cmd):
1041 for e in table.keys():
1053 for e in table.keys():
1042 if re.match("(%s)$" % e, cmd):
1054 if re.match("(%s)$" % e, cmd):
1043 return table[e]
1055 return table[e]
1044
1056
1045 raise UnknownCommand(cmd)
1057 raise UnknownCommand(cmd)
1046
1058
1047 class SignalInterrupt(Exception): pass
1059 class SignalInterrupt(Exception): pass
1048
1060
1049 def catchterm(*args):
1061 def catchterm(*args):
1050 raise SignalInterrupt
1062 raise SignalInterrupt
1051
1063
1052 def run():
1064 def run():
1053 sys.exit(dispatch(sys.argv[1:]))
1065 sys.exit(dispatch(sys.argv[1:]))
1054
1066
1055 class ParseError(Exception): pass
1067 class ParseError(Exception): pass
1056
1068
1057 def parse(args):
1069 def parse(args):
1058 options = {}
1070 options = {}
1059 cmdoptions = {}
1071 cmdoptions = {}
1060
1072
1061 try:
1073 try:
1062 args = fancyopts.fancyopts(args, globalopts, options)
1074 args = fancyopts.fancyopts(args, globalopts, options)
1063 except fancyopts.getopt.GetoptError, inst:
1075 except fancyopts.getopt.GetoptError, inst:
1064 raise ParseError(cmd, inst)
1076 raise ParseError(cmd, inst)
1065
1077
1066 if options["version"]:
1078 if options["version"]:
1067 return ("version", show_version, [], options, cmdoptions)
1079 return ("version", show_version, [], options, cmdoptions)
1068 elif not args:
1080 elif not args:
1069 return ("help", help, [], options, cmdoptions)
1081 return ("help", help, [], options, cmdoptions)
1070 else:
1082 else:
1071 cmd, args = args[0], args[1:]
1083 cmd, args = args[0], args[1:]
1072
1084
1073 i = find(cmd)
1085 i = find(cmd)
1074
1086
1075 # combine global options into local
1087 # combine global options into local
1076 c = list(i[1])
1088 c = list(i[1])
1077 l = len(c)
1089 l = len(c)
1078 for o in globalopts:
1090 for o in globalopts:
1079 c.append((o[0], o[1], options[o[1]], o[3]))
1091 c.append((o[0], o[1], options[o[1]], o[3]))
1080
1092
1081 try:
1093 try:
1082 args = fancyopts.fancyopts(args, c, cmdoptions)
1094 args = fancyopts.fancyopts(args, c, cmdoptions)
1083 except fancyopts.getopt.GetoptError, inst:
1095 except fancyopts.getopt.GetoptError, inst:
1084 raise ParseError(cmd, inst)
1096 raise ParseError(cmd, inst)
1085
1097
1086 # separate global options back out
1098 # separate global options back out
1087 for o in globalopts:
1099 for o in globalopts:
1088 n = o[1]
1100 n = o[1]
1089 options[n] = cmdoptions[n]
1101 options[n] = cmdoptions[n]
1090 del cmdoptions[n]
1102 del cmdoptions[n]
1091
1103
1092 return (cmd, i[0], args, options, cmdoptions)
1104 return (cmd, i[0], args, options, cmdoptions)
1093
1105
1094 def dispatch(args):
1106 def dispatch(args):
1095 signal.signal(signal.SIGTERM, catchterm)
1107 signal.signal(signal.SIGTERM, catchterm)
1096
1108
1097 try:
1109 try:
1098 cmd, func, args, options, cmdoptions = parse(args)
1110 cmd, func, args, options, cmdoptions = parse(args)
1099 except ParseError, inst:
1111 except ParseError, inst:
1100 u = ui.ui()
1112 u = ui.ui()
1101 if inst.args[0]:
1113 if inst.args[0]:
1102 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1114 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1103 help(u, inst.args[0])
1115 help(u, inst.args[0])
1104 else:
1116 else:
1105 u.warn("hg: %s\n" % inst.args[1])
1117 u.warn("hg: %s\n" % inst.args[1])
1106 help(u)
1118 help(u)
1107 sys.exit(-1)
1119 sys.exit(-1)
1108 except UnknownCommand, inst:
1120 except UnknownCommand, inst:
1109 u = ui.ui()
1121 u = ui.ui()
1110 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1122 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1111 help(u)
1123 help(u)
1112 sys.exit(1)
1124 sys.exit(1)
1113
1125
1114 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1126 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1115 not options["noninteractive"])
1127 not options["noninteractive"])
1116
1128
1117 try:
1129 try:
1118 try:
1130 try:
1119 if cmd not in norepo.split():
1131 if cmd not in norepo.split():
1120 path = options["repository"] or ""
1132 path = options["repository"] or ""
1121 repo = hg.repository(ui=u, path=path)
1133 repo = hg.repository(ui=u, path=path)
1122 d = lambda: func(u, repo, *args, **cmdoptions)
1134 d = lambda: func(u, repo, *args, **cmdoptions)
1123 else:
1135 else:
1124 d = lambda: func(u, *args, **cmdoptions)
1136 d = lambda: func(u, *args, **cmdoptions)
1125
1137
1126 if options['profile']:
1138 if options['profile']:
1127 import hotshot, hotshot.stats
1139 import hotshot, hotshot.stats
1128 prof = hotshot.Profile("hg.prof")
1140 prof = hotshot.Profile("hg.prof")
1129 r = prof.runcall(d)
1141 r = prof.runcall(d)
1130 prof.close()
1142 prof.close()
1131 stats = hotshot.stats.load("hg.prof")
1143 stats = hotshot.stats.load("hg.prof")
1132 stats.strip_dirs()
1144 stats.strip_dirs()
1133 stats.sort_stats('time', 'calls')
1145 stats.sort_stats('time', 'calls')
1134 stats.print_stats(40)
1146 stats.print_stats(40)
1135 return r
1147 return r
1136 else:
1148 else:
1137 return d()
1149 return d()
1138 except:
1150 except:
1139 if options['traceback']:
1151 if options['traceback']:
1140 traceback.print_exc()
1152 traceback.print_exc()
1141 raise
1153 raise
1142 except util.CommandError, inst:
1154 except util.CommandError, inst:
1143 u.warn("abort: %s\n" % inst.args)
1155 u.warn("abort: %s\n" % inst.args)
1144 except hg.RepoError, inst:
1156 except hg.RepoError, inst:
1145 u.warn("abort: ", inst, "!\n")
1157 u.warn("abort: ", inst, "!\n")
1146 except SignalInterrupt:
1158 except SignalInterrupt:
1147 u.warn("killed!\n")
1159 u.warn("killed!\n")
1148 except KeyboardInterrupt:
1160 except KeyboardInterrupt:
1149 u.warn("interrupted!\n")
1161 u.warn("interrupted!\n")
1150 except IOError, inst:
1162 except IOError, inst:
1151 if hasattr(inst, "code"):
1163 if hasattr(inst, "code"):
1152 u.warn("abort: %s\n" % inst)
1164 u.warn("abort: %s\n" % inst)
1153 elif hasattr(inst, "reason"):
1165 elif hasattr(inst, "reason"):
1154 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1166 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1155 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1167 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1156 u.warn("broken pipe\n")
1168 u.warn("broken pipe\n")
1157 else:
1169 else:
1158 raise
1170 raise
1159 except OSError, inst:
1171 except OSError, inst:
1160 if hasattr(inst, "filename"):
1172 if hasattr(inst, "filename"):
1161 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1173 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1162 else:
1174 else:
1163 u.warn("abort: %s\n" % inst.strerror)
1175 u.warn("abort: %s\n" % inst.strerror)
1164 except TypeError, inst:
1176 except TypeError, inst:
1165 # was this an argument error?
1177 # was this an argument error?
1166 tb = traceback.extract_tb(sys.exc_info()[2])
1178 tb = traceback.extract_tb(sys.exc_info()[2])
1167 if len(tb) > 2: # no
1179 if len(tb) > 2: # no
1168 raise
1180 raise
1169 u.debug(inst, "\n")
1181 u.debug(inst, "\n")
1170 u.warn("%s: invalid arguments\n" % cmd)
1182 u.warn("%s: invalid arguments\n" % cmd)
1171 help(u, cmd)
1183 help(u, cmd)
1172
1184
1173 sys.exit(-1)
1185 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now