##// END OF EJS Templates
[PATCH] replace history with log...
mpm@selenic.com -
r509:98a2935c default
parent child Browse files
Show More
@@ -1,449 +1,443 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 the destination directory is specified but doesn't exist, it is
85 If the destination directory is specified but doesn't exist, it is
86 created. If no destination directory is specified, it defaults to the
86 created. If no destination directory is specified, it defaults to the
87 current directory.
87 current directory.
88
88
89 The source is added to the new repository's .hg/hgrc file to be used in
89 The source is added to the new repository's .hg/hgrc file to be used in
90 future pulls.
90 future pulls.
91
91
92 For efficiency, hardlinks are used for cloning whenever the
92 For efficiency, hardlinks are used for cloning whenever the
93 source and destination are on the same filesystem.
93 source and destination are on the same filesystem.
94
94
95 options:
95 options:
96 -U, --noupdate do not update the new working directory
96 -U, --noupdate do not update the new working directory
97
97
98 commit [-A -t -l <file> -t <text> -u <user> -d <datecode>] [files...]::
98 commit [-A -t -l <file> -t <text> -u <user> -d <datecode>] [files...]::
99 Commit changes to the given files into the repository.
99 Commit changes to the given files into the repository.
100
100
101 If a list of files is omitted, all changes reported by "hg status"
101 If a list of files is omitted, all changes reported by "hg status"
102 will be commited.
102 will be commited.
103
103
104 The HGEDITOR or EDITOR environment variables are used to start an
104 The HGEDITOR or EDITOR environment variables are used to start an
105 editor to add a commit comment.
105 editor to add a commit comment.
106
106
107 Options:
107 Options:
108
108
109 -A, --addremove run addremove during commit
109 -A, --addremove run addremove during commit
110 -t, --text <text> use <text> as commit message
110 -t, --text <text> use <text> as commit message
111 -l, --logfile <file> show the commit message for the given file
111 -l, --logfile <file> show the commit message for the given file
112 -d, --date <datecode> record datecode as commit date
112 -d, --date <datecode> record datecode as commit date
113 -u, --user <user> record user as commiter
113 -u, --user <user> record user as commiter
114
114
115 aliases: ci
115 aliases: ci
116
116
117 copy <source> <dest>::
117 copy <source> <dest>::
118 Mark <dest> file as a copy or rename of a <source> one
118 Mark <dest> file as a copy or rename of a <source> one
119
119
120 This command takes effect for the next commit.
120 This command takes effect for the next commit.
121
121
122 diff [-r revision] [-r revision] [files ...]::
122 diff [-r revision] [-r revision] [files ...]::
123 Show differences between revisions for the specified files.
123 Show differences between revisions for the specified files.
124
124
125 Differences between files are shown using the unified diff format.
125 Differences between files are shown using the unified diff format.
126
126
127 When two revision arguments are given, then changes are shown
127 When two revision arguments are given, then changes are shown
128 between those revisions. If only one revision is specified then
128 between those revisions. If only one revision is specified then
129 that revision is compared to the working directory, and, when no
129 that revision is compared to the working directory, and, when no
130 revisions are specified, the working directory files are compared
130 revisions are specified, the working directory files are compared
131 to its parent.
131 to its parent.
132
132
133 export [revision]::
133 export [revision]::
134 Print the changeset header and diffs for a particular revision.
134 Print the changeset header and diffs for a particular revision.
135
135
136 The information shown in the changeset header is: author, changeset hash,
136 The information shown in the changeset header is: author, changeset hash,
137 parent and commit comment.
137 parent and commit comment.
138
138
139 forget [files]::
139 forget [files]::
140 Undo an 'hg add' scheduled for the next commit.
140 Undo an 'hg add' scheduled for the next commit.
141
141
142 heads::
142 heads::
143 Show all repository head changesets.
143 Show all repository head changesets.
144
144
145 Repository "heads" are changesets that don't have children
145 Repository "heads" are changesets that don't have children
146 changesets. They are where development generally takes place and
146 changesets. They are where development generally takes place and
147 are the usual targets for update and merge operations.
147 are the usual targets for update and merge operations.
148
148
149 history::
150 Print a log of the revision history of the repository.
151
152 By default this command outputs: changeset id and hash, tags,
153 parents, user, date and time, and a summary for each commit. The
154 -v switch adds some more detail, such as changed files, manifest
155 hashes or message signatures.
156
157 To display the history of a given file, see the log command.
158
159 identify::
149 identify::
160 Print a short summary of the current state of the repo.
150 Print a short summary of the current state of the repo.
161
151
162 This summary identifies the repository state using one or two parent
152 This summary identifies the repository state using one or two parent
163 hash identifiers, followed by a "+" if there are uncommitted changes
153 hash identifiers, followed by a "+" if there are uncommitted changes
164 in the working directory, followed by a list of tags for this revision.
154 in the working directory, followed by a list of tags for this revision.
165
155
166 aliases: id
156 aliases: id
167
157
168 import [-p <n> -b <base> -q] <patches>::
158 import [-p <n> -b <base> -q] <patches>::
169 Import a list of patches and commit them individually.
159 Import a list of patches and commit them individually.
170
160
171 options:
161 options:
172 -p, --strip <n> directory strip option for patch. This has the same
162 -p, --strip <n> directory strip option for patch. This has the same
173 meaning as the correnponding patch option
163 meaning as the correnponding patch option
174 -b <path> base directory to read patches from
164 -b <path> base directory to read patches from
175
165
176 aliases: patch
166 aliases: patch
177
167
178 init::
168 init::
179 Initialize a new repository in the current directory.
169 Initialize a new repository in the current directory.
180
170
181 log <file>::
171 log [file]::
182 Print the revision history of the specified file.
172 Print the revision history of the specified file or the entire project.
183
173
184 To display the revision history for the whole repository, use the history
174 By default this command outputs: changeset id and hash, tags,
185 command.
175 parents, user, date and time, and a summary for each commit. The
176 -v switch adds some more detail, such as changed files, manifest
177 hashes or message signatures.
178
179 aliases: history
186
180
187 manifest [revision]::
181 manifest [revision]::
188 Print a list of version controlled files for the given revision.
182 Print a list of version controlled files for the given revision.
189
183
190 The manifest is the list of files being version controlled. If no revision
184 The manifest is the list of files being version controlled. If no revision
191 is given then the tip is used.
185 is given then the tip is used.
192
186
193 parents::
187 parents::
194 Print the working directory's parent revisions.
188 Print the working directory's parent revisions.
195
189
196 pull <repository path>::
190 pull <repository path>::
197 Pull changes from a remote repository to a local one.
191 Pull changes from a remote repository to a local one.
198
192
199 This finds all changes from the repository at the specified path
193 This finds all changes from the repository at the specified path
200 or URL and adds them to the local repository. By default, this
194 or URL and adds them to the local repository. By default, this
201 does not update the copy of the project in the working directory.
195 does not update the copy of the project in the working directory.
202
196
203 options:
197 options:
204 -u, --update update the working directory to tip after pull
198 -u, --update update the working directory to tip after pull
205
199
206 push <destination>::
200 push <destination>::
207 Push changes from the local repository to the given destination.
201 Push changes from the local repository to the given destination.
208
202
209 This is the symmetrical operation for pull. It helps to move
203 This is the symmetrical operation for pull. It helps to move
210 changes from the current repository to a different one. If the
204 changes from the current repository to a different one. If the
211 destination is local this is identical to a pull in that directory
205 destination is local this is identical to a pull in that directory
212 from the current one.
206 from the current one.
213
207
214 The other currently available push method is SSH. This requires an
208 The other currently available push method is SSH. This requires an
215 accessible shell account on the destination machine and a copy of
209 accessible shell account on the destination machine and a copy of
216 hg in the remote path. Destinations are specified in the following
210 hg in the remote path. Destinations are specified in the following
217 form:
211 form:
218
212
219 ssh://[user@]host[:port]/path
213 ssh://[user@]host[:port]/path
220
214
221 rawcommit [-p -d -u -F -t -l]::
215 rawcommit [-p -d -u -F -t -l]::
222 Lowlevel commit, for use in helper scripts.
216 Lowlevel commit, for use in helper scripts.
223
217
224 This command is not intended to be used by normal users, as it is
218 This command is not intended to be used by normal users, as it is
225 primarily useful for importing from other SCMs.
219 primarily useful for importing from other SCMs.
226
220
227 recover::
221 recover::
228 Recover from an interrupted commit or pull.
222 Recover from an interrupted commit or pull.
229
223
230 This command tries to fix the repository status after an interrupted
224 This command tries to fix the repository status after an interrupted
231 operation. It should only be necessary when Mercurial suggests it.
225 operation. It should only be necessary when Mercurial suggests it.
232
226
233 remove [files ...]::
227 remove [files ...]::
234 Schedule the indicated files for removal from the repository.
228 Schedule the indicated files for removal from the repository.
235
229
236 This command shedules the files to be removed at the next commit.
230 This command shedules the files to be removed at the next commit.
237 This only removes files from the current branch, not from the
231 This only removes files from the current branch, not from the
238 entire project history.
232 entire project history.
239
233
240 aliases: rm
234 aliases: rm
241
235
242 root::
236 root::
243 Print the root directory of the current repository.
237 Print the root directory of the current repository.
244
238
245 serve [-a addr -n name -p port -t templatedir]::
239 serve [-a addr -n name -p port -t templatedir]::
246 Start a local HTTP repository browser and pull server.
240 Start a local HTTP repository browser and pull server.
247
241
248 options:
242 options:
249 -a, --address <addr> address to use
243 -a, --address <addr> address to use
250 -p, --port <n> port to use (default: 8000)
244 -p, --port <n> port to use (default: 8000)
251 -n, --name <name> name to show in web pages (default: working dir)
245 -n, --name <name> name to show in web pages (default: working dir)
252 -t, --templatedir <path> web templates to use
246 -t, --templatedir <path> web templates to use
253
247
254 status::
248 status::
255 Show changed files in the working directory.
249 Show changed files in the working directory.
256
250
257 The codes used to show the status of files are:
251 The codes used to show the status of files are:
258
252
259 C = changed
253 C = changed
260 A = added
254 A = added
261 R = removed
255 R = removed
262 ? = not tracked
256 ? = not tracked
263
257
264 tag [-t <text> -d <datecode> -u <user>] <name> [revision]::
258 tag [-t <text> -d <datecode> -u <user>] <name> [revision]::
265 Name a particular revision using <name>.
259 Name a particular revision using <name>.
266
260
267 Tags are used to name particular revisions of the repository and are
261 Tags are used to name particular revisions of the repository and are
268 very useful to compare different revision, to go back to significant
262 very useful to compare different revision, to go back to significant
269 earlier versions or to mark branch points as releases, etc.
263 earlier versions or to mark branch points as releases, etc.
270
264
271 If no revision is given, the tip is used.
265 If no revision is given, the tip is used.
272
266
273 To facilitate version control, distribution, and merging of tags,
267 To facilitate version control, distribution, and merging of tags,
274 they are stored as a file named ".hgtags" which is managed
268 they are stored as a file named ".hgtags" which is managed
275 similarly to other project files and can be hand-edited if
269 similarly to other project files and can be hand-edited if
276 necessary.
270 necessary.
277
271
278 options:
272 options:
279 -t, --text <text> message for tag commit log entry
273 -t, --text <text> message for tag commit log entry
280 -d, --date <datecode> datecode for commit
274 -d, --date <datecode> datecode for commit
281 -u, --user <user> user for commit
275 -u, --user <user> user for commit
282
276
283 Note: Mercurial also has support for "local tags" that are not
277 Note: Mercurial also has support for "local tags" that are not
284 version-controlled or distributed which are stored in the .hg/hgrc
278 version-controlled or distributed which are stored in the .hg/hgrc
285 file.
279 file.
286
280
287 tags::
281 tags::
288 List the repository tags.
282 List the repository tags.
289
283
290 This lists both regular and local tags.
284 This lists both regular and local tags.
291
285
292 tip::
286 tip::
293 Show the tip revision.
287 Show the tip revision.
294
288
295 undo::
289 undo::
296 Undo the last commit or pull transaction.
290 Undo the last commit or pull transaction.
297
291
298 update [-m -C] [revision]::
292 update [-m -C] [revision]::
299 Update the working directory to the specified revision.
293 Update the working directory to the specified revision.
300
294
301 By default, update will refuse to run if doing so would require
295 By default, update will refuse to run if doing so would require
302 merging or discarding local changes.
296 merging or discarding local changes.
303
297
304 With the -m option, a merge will be performed.
298 With the -m option, a merge will be performed.
305
299
306 With the -C option, local changes will be lost.
300 With the -C option, local changes will be lost.
307
301
308 options:
302 options:
309 -m, --merge allow merging of branches
303 -m, --merge allow merging of branches
310 -C, --clean overwrite locally modified files
304 -C, --clean overwrite locally modified files
311
305
312 aliases: up checkout co
306 aliases: up checkout co
313
307
314 verify::
308 verify::
315 Verify the integrity of the current repository.
309 Verify the integrity of the current repository.
316
310
317 This will perform an extensive check of the repository's
311 This will perform an extensive check of the repository's
318 integrity, validating the hashes and checksums of each entry in
312 integrity, validating the hashes and checksums of each entry in
319 the changelog, manifest, and tracked files, as well as the
313 the changelog, manifest, and tracked files, as well as the
320 integrity of their crosslinks and indices.
314 integrity of their crosslinks and indices.
321
315
322
316
323 ENVIRONMENT VARIABLES
317 ENVIRONMENT VARIABLES
324 ---------------------
318 ---------------------
325
319
326 HGEDITOR::
320 HGEDITOR::
327 This is the name of the editor to use when committing. Defaults to the
321 This is the name of the editor to use when committing. Defaults to the
328 value of EDITOR.
322 value of EDITOR.
329
323
330 HGMERGE::
324 HGMERGE::
331 An executable to use for resolving merge conflicts. The program
325 An executable to use for resolving merge conflicts. The program
332 will be executed with three arguments: local file, remote file,
326 will be executed with three arguments: local file, remote file,
333 ancestor file.
327 ancestor file.
334
328
335 The default program is "hgmerge", which is a shell script provided
329 The default program is "hgmerge", which is a shell script provided
336 by Mercurial with some sensible defaults.
330 by Mercurial with some sensible defaults.
337
331
338 HGUSER::
332 HGUSER::
339 This is the string used for the author of a commit.
333 This is the string used for the author of a commit.
340
334
341 EMAIL::
335 EMAIL::
342 If HGUSER is not set, this will be used as the author for a commit.
336 If HGUSER is not set, this will be used as the author for a commit.
343
337
344 LOGNAME::
338 LOGNAME::
345 If neither HGUSER nor EMAIL is set, LOGNAME will be used (with
339 If neither HGUSER nor EMAIL is set, LOGNAME will be used (with
346 '@hostname' appended) as the author value for a commit.
340 '@hostname' appended) as the author value for a commit.
347
341
348 EDITOR::
342 EDITOR::
349 This is the name of the editor used in the hgmerge script. It will be
343 This is the name of the editor used in the hgmerge script. It will be
350 used for commit messages if HGEDITOR isn't set. Defaults to 'vi'.
344 used for commit messages if HGEDITOR isn't set. Defaults to 'vi'.
351
345
352 PYTHONPATH::
346 PYTHONPATH::
353 This is used by Python to find imported modules and may need to be set
347 This is used by Python to find imported modules and may need to be set
354 appropriately if Mercurial is not installed system-wide.
348 appropriately if Mercurial is not installed system-wide.
355
349
356 FILES
350 FILES
357 -----
351 -----
358 .hgignore::
352 .hgignore::
359 This file contains regular expressions (one per line) that describe file
353 This file contains regular expressions (one per line) that describe file
360 names that should be ignored by hg.
354 names that should be ignored by hg.
361
355
362 .hgtags::
356 .hgtags::
363 This file contains changeset hash values and text tag names (one of each
357 This file contains changeset hash values and text tag names (one of each
364 seperated by spaces) that correspond to tagged versions of the repository
358 seperated by spaces) that correspond to tagged versions of the repository
365 contents.
359 contents.
366
360
367 $HOME/.hgrc, .hg/hgrc::
361 $HOME/.hgrc, .hg/hgrc::
368 This file contains defaults and configuration. Values in .hg/hgrc
362 This file contains defaults and configuration. Values in .hg/hgrc
369 override those in .hgrc.
363 override those in .hgrc.
370
364
371 NAMED REPOSITORIES
365 NAMED REPOSITORIES
372 ------------------
366 ------------------
373
367
374 To give symbolic names to a repository, create a section in .hgrc
368 To give symbolic names to a repository, create a section in .hgrc
375 or .hg/hgrc containing assignments of names to paths. Example:
369 or .hg/hgrc containing assignments of names to paths. Example:
376
370
377 -----------------
371 -----------------
378 [paths]
372 [paths]
379 hg = http://selenic.com/hg
373 hg = http://selenic.com/hg
380 tah = http://hg.intevation.org/mercurial-tah/
374 tah = http://hg.intevation.org/mercurial-tah/
381 -----------------
375 -----------------
382
376
383
377
384 LOCAL TAGS
378 LOCAL TAGS
385 ----------
379 ----------
386
380
387 To create tags that are local to the repository and not distributed or
381 To create tags that are local to the repository and not distributed or
388 version-controlled, create an hgrc section like the following:
382 version-controlled, create an hgrc section like the following:
389
383
390 ----------------
384 ----------------
391 [tags]
385 [tags]
392 working = 2dcced388cab3677a8f543c3c47a0ad34ac9d435
386 working = 2dcced388cab3677a8f543c3c47a0ad34ac9d435
393 tested = 12e0fdbc57a0be78f0e817fd1d170a3615cd35da
387 tested = 12e0fdbc57a0be78f0e817fd1d170a3615cd35da
394 ----------------
388 ----------------
395
389
396
390
397 HOOKS
391 HOOKS
398 -----
392 -----
399
393
400 Mercurial supports a set of 'hook', commands that get automatically
394 Mercurial supports a set of 'hook', commands that get automatically
401 executed by various actions such as starting or finishing a commit. To
395 executed by various actions such as starting or finishing a commit. To
402 specify a hook, simply create an hgrc section like the following:
396 specify a hook, simply create an hgrc section like the following:
403
397
404 -----------------
398 -----------------
405 [hooks]
399 [hooks]
406 precommit = echo "this hook gets executed immediately before a commit"
400 precommit = echo "this hook gets executed immediately before a commit"
407 commit = hg export $NODE | mail -s "new commit $NODE" commit-list
401 commit = hg export $NODE | mail -s "new commit $NODE" commit-list
408 -----------------
402 -----------------
409
403
410
404
411 NON_TRANSPARENT PROXY SUPPORT
405 NON_TRANSPARENT PROXY SUPPORT
412 -----------------------------
406 -----------------------------
413
407
414 To access a Mercurial repository through a proxy, create a file
408 To access a Mercurial repository through a proxy, create a file
415 $HOME/.hgrc in the following format:
409 $HOME/.hgrc in the following format:
416
410
417 --------------
411 --------------
418 [http_proxy]
412 [http_proxy]
419 host=myproxy:8080
413 host=myproxy:8080
420 user=<username>
414 user=<username>
421 passwd=<password>
415 passwd=<password>
422 no=<localhost1>,<localhost2>,<localhost3>,...
416 no=<localhost1>,<localhost2>,<localhost3>,...
423 --------------
417 --------------
424
418
425 "user" and "passwd" fields are used for authenticating proxies, "no" is a
419 "user" and "passwd" fields are used for authenticating proxies, "no" is a
426 comma-separated list of local host names to not proxy.
420 comma-separated list of local host names to not proxy.
427
421
428 BUGS
422 BUGS
429 ----
423 ----
430 Probably lots, please post them to the mailing list (See Resources below)
424 Probably lots, please post them to the mailing list (See Resources below)
431 when you find them.
425 when you find them.
432
426
433 AUTHOR
427 AUTHOR
434 ------
428 ------
435 Written by Matt Mackall <mpm@selenic.com>
429 Written by Matt Mackall <mpm@selenic.com>
436
430
437 RESOURCES
431 RESOURCES
438 ---------
432 ---------
439 http://selenic.com/mercurial[Main Web Site]
433 http://selenic.com/mercurial[Main Web Site]
440
434
441 http://selenic.com/hg[Source code repository]
435 http://selenic.com/hg[Source code repository]
442
436
443 http://selenic.com/mailman/listinfo/mercurial[Mailing list]
437 http://selenic.com/mailman/listinfo/mercurial[Mailing list]
444
438
445 COPYING
439 COPYING
446 -------
440 -------
447 Copyright (C) 2005 Matt Mackall.
441 Copyright (C) 2005 Matt Mackall.
448 Free use of this software is granted under the terms of the GNU General
442 Free use of this software is granted under the terms of the GNU General
449 Public License (GPL).
443 Public License (GPL).
@@ -1,901 +1,898 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 errno version")
11 demandload(globals(), "mdiff time hgweb traceback random signal errno version")
12
12
13 class UnknownCommand(Exception): pass
13 class UnknownCommand(Exception): pass
14
14
15 def filterfiles(filters, files):
15 def filterfiles(filters, files):
16 l = [ x for x in files if x in filters ]
16 l = [ x for x in files if x in filters ]
17
17
18 for t in filters:
18 for t in filters:
19 if t and t[-1] != "/": t += "/"
19 if t and t[-1] != "/": t += "/"
20 l += [ x for x in files if x.startswith(t) ]
20 l += [ x for x in files if x.startswith(t) ]
21 return l
21 return l
22
22
23 def relfilter(repo, files):
23 def relfilter(repo, files):
24 if os.getcwd() != repo.root:
24 if os.getcwd() != repo.root:
25 p = os.getcwd()[len(repo.root) + 1: ]
25 p = os.getcwd()[len(repo.root) + 1: ]
26 return filterfiles([util.pconvert(p)], files)
26 return filterfiles([util.pconvert(p)], files)
27 return files
27 return files
28
28
29 def relpath(repo, args):
29 def relpath(repo, args):
30 if os.getcwd() != repo.root:
30 if os.getcwd() != repo.root:
31 p = os.getcwd()[len(repo.root) + 1: ]
31 p = os.getcwd()[len(repo.root) + 1: ]
32 return [ util.pconvert(os.path.normpath(os.path.join(p, x))) for x in args ]
32 return [ util.pconvert(os.path.normpath(os.path.join(p, x))) for x in args ]
33 return args
33 return args
34
34
35 def dodiff(ui, repo, path, files = None, node1 = None, node2 = None):
35 def dodiff(ui, repo, path, files = None, node1 = None, node2 = None):
36 def date(c):
36 def date(c):
37 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
37 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
38
38
39 if node2:
39 if node2:
40 change = repo.changelog.read(node2)
40 change = repo.changelog.read(node2)
41 mmap2 = repo.manifest.read(change[0])
41 mmap2 = repo.manifest.read(change[0])
42 (c, a, d) = repo.diffrevs(node1, node2)
42 (c, a, d) = repo.diffrevs(node1, node2)
43 def read(f): return repo.file(f).read(mmap2[f])
43 def read(f): return repo.file(f).read(mmap2[f])
44 date2 = date(change)
44 date2 = date(change)
45 else:
45 else:
46 date2 = time.asctime()
46 date2 = time.asctime()
47 (c, a, d, u) = repo.diffdir(path, node1)
47 (c, a, d, u) = repo.diffdir(path, node1)
48 if not node1:
48 if not node1:
49 node1 = repo.dirstate.parents()[0]
49 node1 = repo.dirstate.parents()[0]
50 def read(f): return repo.wfile(f).read()
50 def read(f): return repo.wfile(f).read()
51
51
52 if ui.quiet:
52 if ui.quiet:
53 r = None
53 r = None
54 else:
54 else:
55 hexfunc = ui.verbose and hg.hex or hg.short
55 hexfunc = ui.verbose and hg.hex or hg.short
56 r = [hexfunc(node) for node in [node1, node2] if node]
56 r = [hexfunc(node) for node in [node1, node2] if node]
57
57
58 change = repo.changelog.read(node1)
58 change = repo.changelog.read(node1)
59 mmap = repo.manifest.read(change[0])
59 mmap = repo.manifest.read(change[0])
60 date1 = date(change)
60 date1 = date(change)
61
61
62 if files:
62 if files:
63 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
63 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
64
64
65 for f in c:
65 for f in c:
66 to = None
66 to = None
67 if f in mmap:
67 if f in mmap:
68 to = repo.file(f).read(mmap[f])
68 to = repo.file(f).read(mmap[f])
69 tn = read(f)
69 tn = read(f)
70 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f, r))
70 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f, r))
71 for f in a:
71 for f in a:
72 to = None
72 to = None
73 tn = read(f)
73 tn = read(f)
74 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f, r))
74 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f, r))
75 for f in d:
75 for f in d:
76 to = repo.file(f).read(mmap[f])
76 to = repo.file(f).read(mmap[f])
77 tn = None
77 tn = None
78 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f, r))
78 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f, r))
79
79
80 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
80 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
81 """show a single changeset or file revision"""
81 """show a single changeset or file revision"""
82 changelog = repo.changelog
82 changelog = repo.changelog
83 if filelog:
83 if filelog:
84 log = filelog
84 log = filelog
85 filerev = rev
85 filerev = rev
86 node = filenode = filelog.node(filerev)
86 node = filenode = filelog.node(filerev)
87 changerev = filelog.linkrev(filenode)
87 changerev = filelog.linkrev(filenode)
88 changenode = changenode or changelog.node(changerev)
88 changenode = changenode or changelog.node(changerev)
89 else:
89 else:
90 log = changelog
90 log = changelog
91 changerev = rev
91 changerev = rev
92 if changenode is None:
92 if changenode is None:
93 changenode = changelog.node(changerev)
93 changenode = changelog.node(changerev)
94 elif not changerev:
94 elif not changerev:
95 rev = changerev = changelog.rev(changenode)
95 rev = changerev = changelog.rev(changenode)
96 node = changenode
96 node = changenode
97
97
98 if ui.quiet:
98 if ui.quiet:
99 ui.write("%d:%s\n" % (rev, hg.hex(node)))
99 ui.write("%d:%s\n" % (rev, hg.hex(node)))
100 return
100 return
101
101
102 changes = changelog.read(changenode)
102 changes = changelog.read(changenode)
103
103
104 parents = [(log.rev(parent), hg.hex(parent))
104 parents = [(log.rev(parent), hg.hex(parent))
105 for parent in log.parents(node)
105 for parent in log.parents(node)
106 if ui.debugflag or parent != hg.nullid]
106 if ui.debugflag or parent != hg.nullid]
107 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
107 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
108 parents = []
108 parents = []
109
109
110 if filelog:
110 if filelog:
111 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
111 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
112 for parent in parents:
112 for parent in parents:
113 ui.write("parent: %d:%s\n" % parent)
113 ui.write("parent: %d:%s\n" % parent)
114 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
114 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
115 else:
115 else:
116 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
116 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
117 for tag in repo.nodetags(changenode):
117 for tag in repo.nodetags(changenode):
118 ui.status("tag: %s\n" % tag)
118 ui.status("tag: %s\n" % tag)
119 for parent in parents:
119 for parent in parents:
120 ui.write("parent: %d:%s\n" % parent)
120 ui.write("parent: %d:%s\n" % parent)
121 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
121 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
122 hg.hex(changes[0])))
122 hg.hex(changes[0])))
123 ui.status("user: %s\n" % changes[1])
123 ui.status("user: %s\n" % changes[1])
124 ui.status("date: %s\n" % time.asctime(
124 ui.status("date: %s\n" % time.asctime(
125 time.localtime(float(changes[2].split(' ')[0]))))
125 time.localtime(float(changes[2].split(' ')[0]))))
126 if ui.debugflag:
126 if ui.debugflag:
127 files = repo.diffrevs(changelog.parents(changenode)[0], changenode)
127 files = repo.diffrevs(changelog.parents(changenode)[0], changenode)
128 for key, value in zip(["files:", "files+:", "files-:"], files):
128 for key, value in zip(["files:", "files+:", "files-:"], files):
129 if value:
129 if value:
130 ui.note("%-12s %s\n" % (key, " ".join(value)))
130 ui.note("%-12s %s\n" % (key, " ".join(value)))
131 else:
131 else:
132 ui.note("files: %s\n" % " ".join(changes[3]))
132 ui.note("files: %s\n" % " ".join(changes[3]))
133 description = changes[4].strip()
133 description = changes[4].strip()
134 if description:
134 if description:
135 if ui.verbose:
135 if ui.verbose:
136 ui.status("description:\n")
136 ui.status("description:\n")
137 ui.status(description)
137 ui.status(description)
138 ui.status("\n")
138 ui.status("\n")
139 else:
139 else:
140 ui.status("summary: %s\n" % description.splitlines()[0])
140 ui.status("summary: %s\n" % description.splitlines()[0])
141 ui.status("\n")
141 ui.status("\n")
142
142
143 def show_version(ui):
143 def show_version(ui):
144 """output version and copyright information"""
144 """output version and copyright information"""
145 ui.write("Mercurial version %s\n" % version.get_version())
145 ui.write("Mercurial version %s\n" % version.get_version())
146 ui.status(
146 ui.status(
147 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
147 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
148 "This is free software; see the source for copying conditions. "
148 "This is free software; see the source for copying conditions. "
149 "There is NO\nwarranty; "
149 "There is NO\nwarranty; "
150 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
150 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
151 )
151 )
152
152
153 def help(ui, cmd=None):
153 def help(ui, cmd=None):
154 '''show help for a given command or all commands'''
154 '''show help for a given command or all commands'''
155 if cmd:
155 if cmd:
156 try:
156 try:
157 i = find(cmd)
157 i = find(cmd)
158 ui.write("%s\n\n" % i[2])
158 ui.write("%s\n\n" % i[2])
159
159
160 if i[1]:
160 if i[1]:
161 for s, l, d, c in i[1]:
161 for s, l, d, c in i[1]:
162 opt=' '
162 opt=' '
163 if s: opt = opt + '-' + s + ' '
163 if s: opt = opt + '-' + s + ' '
164 if l: opt = opt + '--' + l + ' '
164 if l: opt = opt + '--' + l + ' '
165 if d: opt = opt + '(' + str(d) + ')'
165 if d: opt = opt + '(' + str(d) + ')'
166 ui.write(opt, "\n")
166 ui.write(opt, "\n")
167 if c: ui.write(' %s\n' % c)
167 if c: ui.write(' %s\n' % c)
168 ui.write("\n")
168 ui.write("\n")
169
169
170 ui.write(i[0].__doc__, "\n")
170 ui.write(i[0].__doc__, "\n")
171 except UnknownCommand:
171 except UnknownCommand:
172 ui.warn("hg: unknown command %s\n" % cmd)
172 ui.warn("hg: unknown command %s\n" % cmd)
173 sys.exit(0)
173 sys.exit(0)
174 else:
174 else:
175 if not ui.quiet:
175 if not ui.quiet:
176 show_version(ui)
176 show_version(ui)
177 ui.write('\n')
177 ui.write('\n')
178 ui.write('hg commands:\n\n')
178 ui.write('hg commands:\n\n')
179
179
180 h = {}
180 h = {}
181 for c, e in table.items():
181 for c, e in table.items():
182 f = c.split("|")[0]
182 f = c.split("|")[0]
183 if f.startswith("debug"):
183 if f.startswith("debug"):
184 continue
184 continue
185 d = ""
185 d = ""
186 if e[0].__doc__:
186 if e[0].__doc__:
187 d = e[0].__doc__.splitlines(0)[0].rstrip()
187 d = e[0].__doc__.splitlines(0)[0].rstrip()
188 h[f] = d
188 h[f] = d
189
189
190 fns = h.keys()
190 fns = h.keys()
191 fns.sort()
191 fns.sort()
192 m = max(map(len, fns))
192 m = max(map(len, fns))
193 for f in fns:
193 for f in fns:
194 ui.write(' %-*s %s\n' % (m, f, h[f]))
194 ui.write(' %-*s %s\n' % (m, f, h[f]))
195
195
196 # Commands start here, listed alphabetically
196 # Commands start here, listed alphabetically
197
197
198 def add(ui, repo, file, *files):
198 def add(ui, repo, file, *files):
199 '''add the specified files on the next commit'''
199 '''add the specified files on the next commit'''
200 repo.add(relpath(repo, (file,) + files))
200 repo.add(relpath(repo, (file,) + files))
201
201
202 def addremove(ui, repo, *files):
202 def addremove(ui, repo, *files):
203 """add all new files, delete all missing files"""
203 """add all new files, delete all missing files"""
204 if files:
204 if files:
205 files = relpath(repo, files)
205 files = relpath(repo, files)
206 d = []
206 d = []
207 u = []
207 u = []
208 for f in files:
208 for f in files:
209 p = repo.wjoin(f)
209 p = repo.wjoin(f)
210 s = repo.dirstate.state(f)
210 s = repo.dirstate.state(f)
211 isfile = os.path.isfile(p)
211 isfile = os.path.isfile(p)
212 if s != 'r' and not isfile:
212 if s != 'r' and not isfile:
213 d.append(f)
213 d.append(f)
214 elif s not in 'nmai' and isfile:
214 elif s not in 'nmai' and isfile:
215 u.append(f)
215 u.append(f)
216 else:
216 else:
217 (c, a, d, u) = repo.diffdir(repo.root)
217 (c, a, d, u) = repo.diffdir(repo.root)
218 repo.add(u)
218 repo.add(u)
219 repo.remove(d)
219 repo.remove(d)
220
220
221 def annotate(u, repo, file, *files, **ops):
221 def annotate(u, repo, file, *files, **ops):
222 """show changeset information per file line"""
222 """show changeset information per file line"""
223 def getnode(rev):
223 def getnode(rev):
224 return hg.short(repo.changelog.node(rev))
224 return hg.short(repo.changelog.node(rev))
225
225
226 def getname(rev):
226 def getname(rev):
227 try:
227 try:
228 return bcache[rev]
228 return bcache[rev]
229 except KeyError:
229 except KeyError:
230 cl = repo.changelog.read(repo.changelog.node(rev))
230 cl = repo.changelog.read(repo.changelog.node(rev))
231 name = cl[1]
231 name = cl[1]
232 f = name.find('@')
232 f = name.find('@')
233 if f >= 0:
233 if f >= 0:
234 name = name[:f]
234 name = name[:f]
235 bcache[rev] = name
235 bcache[rev] = name
236 return name
236 return name
237
237
238 bcache = {}
238 bcache = {}
239 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
239 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
240 if not ops['user'] and not ops['changeset']:
240 if not ops['user'] and not ops['changeset']:
241 ops['number'] = 1
241 ops['number'] = 1
242
242
243 node = repo.dirstate.parents()[0]
243 node = repo.dirstate.parents()[0]
244 if ops['revision']:
244 if ops['revision']:
245 node = repo.changelog.lookup(ops['revision'])
245 node = repo.changelog.lookup(ops['revision'])
246 change = repo.changelog.read(node)
246 change = repo.changelog.read(node)
247 mmap = repo.manifest.read(change[0])
247 mmap = repo.manifest.read(change[0])
248 for f in relpath(repo, (file,) + files):
248 for f in relpath(repo, (file,) + files):
249 lines = repo.file(f).annotate(mmap[f])
249 lines = repo.file(f).annotate(mmap[f])
250 pieces = []
250 pieces = []
251
251
252 for o, f in opmap:
252 for o, f in opmap:
253 if ops[o]:
253 if ops[o]:
254 l = [ f(n) for n,t in lines ]
254 l = [ f(n) for n,t in lines ]
255 m = max(map(len, l))
255 m = max(map(len, l))
256 pieces.append([ "%*s" % (m, x) for x in l])
256 pieces.append([ "%*s" % (m, x) for x in l])
257
257
258 for p,l in zip(zip(*pieces), lines):
258 for p,l in zip(zip(*pieces), lines):
259 u.write(" ".join(p) + ": " + l[1])
259 u.write(" ".join(p) + ": " + l[1])
260
260
261 def cat(ui, repo, file, rev = []):
261 def cat(ui, repo, file, rev = []):
262 """output the latest or given revision of a file"""
262 """output the latest or given revision of a file"""
263 r = repo.file(relpath(repo, [file])[0])
263 r = repo.file(relpath(repo, [file])[0])
264 n = r.tip()
264 n = r.tip()
265 if rev: n = r.lookup(rev)
265 if rev: n = r.lookup(rev)
266 sys.stdout.write(r.read(n))
266 sys.stdout.write(r.read(n))
267
267
268 def clone(ui, source, dest = None, **opts):
268 def clone(ui, source, dest = None, **opts):
269 """make a copy of an existing repository"""
269 """make a copy of an existing repository"""
270 source = ui.expandpath(source)
270 source = ui.expandpath(source)
271
271
272 created = success = False
272 created = success = False
273
273
274 if dest is None:
274 if dest is None:
275 dest = os.getcwd()
275 dest = os.getcwd()
276 elif not os.path.exists(dest):
276 elif not os.path.exists(dest):
277 os.mkdir(dest)
277 os.mkdir(dest)
278 created = True
278 created = True
279
279
280 try:
280 try:
281 dest = os.path.realpath(dest)
281 dest = os.path.realpath(dest)
282
282
283 link = 0
283 link = 0
284 if not source.startswith("http://"):
284 if not source.startswith("http://"):
285 source = os.path.realpath(source)
285 source = os.path.realpath(source)
286 d1 = os.stat(dest).st_dev
286 d1 = os.stat(dest).st_dev
287 d2 = os.stat(source).st_dev
287 d2 = os.stat(source).st_dev
288 if d1 == d2: link = 1
288 if d1 == d2: link = 1
289
289
290 os.chdir(dest)
290 os.chdir(dest)
291
291
292 if link:
292 if link:
293 ui.debug("copying by hardlink\n")
293 ui.debug("copying by hardlink\n")
294 util.system("cp -al %s/.hg .hg" % source)
294 util.system("cp -al %s/.hg .hg" % source)
295 try:
295 try:
296 os.remove(".hg/dirstate")
296 os.remove(".hg/dirstate")
297 except: pass
297 except: pass
298
298
299 repo = hg.repository(ui, ".")
299 repo = hg.repository(ui, ".")
300
300
301 else:
301 else:
302 repo = hg.repository(ui, ".", create=1)
302 repo = hg.repository(ui, ".", create=1)
303 other = hg.repository(ui, source)
303 other = hg.repository(ui, source)
304 cg = repo.getchangegroup(other)
304 cg = repo.getchangegroup(other)
305 repo.addchangegroup(cg)
305 repo.addchangegroup(cg)
306
306
307 f = repo.opener("hgrc", "w")
307 f = repo.opener("hgrc", "w")
308 f.write("[paths]\n")
308 f.write("[paths]\n")
309 f.write("default = %s\n" % source)
309 f.write("default = %s\n" % source)
310
310
311 if not opts['noupdate']:
311 if not opts['noupdate']:
312 update(ui, repo)
312 update(ui, repo)
313
313
314 success = True
314 success = True
315
315
316 finally:
316 finally:
317 if not success:
317 if not success:
318 del repo
318 del repo
319 import shutil
319 import shutil
320 shutil.rmtree(dest, True)
320 shutil.rmtree(dest, True)
321
321
322 def commit(ui, repo, *files, **opts):
322 def commit(ui, repo, *files, **opts):
323 """commit the specified files or all outstanding changes"""
323 """commit the specified files or all outstanding changes"""
324 text = opts['text']
324 text = opts['text']
325 if not text and opts['logfile']:
325 if not text and opts['logfile']:
326 try: text = open(opts['logfile']).read()
326 try: text = open(opts['logfile']).read()
327 except IOError: pass
327 except IOError: pass
328
328
329 if opts['addremove']:
329 if opts['addremove']:
330 addremove(ui, repo, *files)
330 addremove(ui, repo, *files)
331 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
331 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
332
332
333 def copy(ui, repo, source, dest):
333 def copy(ui, repo, source, dest):
334 """mark a file as copied or renamed for the next commit"""
334 """mark a file as copied or renamed for the next commit"""
335 return repo.copy(*relpath(repo, (source, dest)))
335 return repo.copy(*relpath(repo, (source, dest)))
336
336
337 def debugcheckdirstate(ui, repo):
337 def debugcheckdirstate(ui, repo):
338 parent1, parent2 = repo.dirstate.parents()
338 parent1, parent2 = repo.dirstate.parents()
339 dc = repo.dirstate.dup()
339 dc = repo.dirstate.dup()
340 keys = dc.keys()
340 keys = dc.keys()
341 keys.sort()
341 keys.sort()
342 m1n = repo.changelog.read(parent1)[0]
342 m1n = repo.changelog.read(parent1)[0]
343 m2n = repo.changelog.read(parent2)[0]
343 m2n = repo.changelog.read(parent2)[0]
344 m1 = repo.manifest.read(m1n)
344 m1 = repo.manifest.read(m1n)
345 m2 = repo.manifest.read(m2n)
345 m2 = repo.manifest.read(m2n)
346 errors = 0
346 errors = 0
347 for f in dc:
347 for f in dc:
348 state = repo.dirstate.state(f)
348 state = repo.dirstate.state(f)
349 if state in "nr" and f not in m1:
349 if state in "nr" and f not in m1:
350 print "%s in state %s, but not listed in manifest1" % (f, state)
350 print "%s in state %s, but not listed in manifest1" % (f, state)
351 errors += 1
351 errors += 1
352 if state in "a" and f in m1:
352 if state in "a" and f in m1:
353 print "%s in state %s, but also listed in manifest1" % (f, state)
353 print "%s in state %s, but also listed in manifest1" % (f, state)
354 errors += 1
354 errors += 1
355 if state in "m" and f not in m1 and f not in m2:
355 if state in "m" and f not in m1 and f not in m2:
356 print "%s in state %s, but not listed in either manifest" % (f, state)
356 print "%s in state %s, but not listed in either manifest" % (f, state)
357 errors += 1
357 errors += 1
358 for f in m1:
358 for f in m1:
359 state = repo.dirstate.state(f)
359 state = repo.dirstate.state(f)
360 if state not in "nrm":
360 if state not in "nrm":
361 print "%s in manifest1, but listed as state %s" % (f, state)
361 print "%s in manifest1, but listed as state %s" % (f, state)
362 errors += 1
362 errors += 1
363 if errors:
363 if errors:
364 print ".hg/dirstate inconsistent with current parent's manifest, aborting"
364 print ".hg/dirstate inconsistent with current parent's manifest, aborting"
365 sys.exit(1)
365 sys.exit(1)
366
366
367 def debugdumpdirstate(ui, repo):
367 def debugdumpdirstate(ui, repo):
368 dc = repo.dirstate.dup()
368 dc = repo.dirstate.dup()
369 keys = dc.keys()
369 keys = dc.keys()
370 keys.sort()
370 keys.sort()
371 for file in keys:
371 for file in keys:
372 print "%s => %c" % (file, dc[file][0])
372 print "%s => %c" % (file, dc[file][0])
373
373
374 def debugindex(ui, file):
374 def debugindex(ui, file):
375 r = hg.revlog(hg.opener(""), file, "")
375 r = hg.revlog(hg.opener(""), file, "")
376 print " rev offset length base linkrev"+\
376 print " rev offset length base linkrev"+\
377 " p1 p2 nodeid"
377 " p1 p2 nodeid"
378 for i in range(r.count()):
378 for i in range(r.count()):
379 e = r.index[i]
379 e = r.index[i]
380 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
380 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
381 i, e[0], e[1], e[2], e[3],
381 i, e[0], e[1], e[2], e[3],
382 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
382 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
383
383
384 def debugindexdot(ui, file):
384 def debugindexdot(ui, file):
385 r = hg.revlog(hg.opener(""), file, "")
385 r = hg.revlog(hg.opener(""), file, "")
386 print "digraph G {"
386 print "digraph G {"
387 for i in range(r.count()):
387 for i in range(r.count()):
388 e = r.index[i]
388 e = r.index[i]
389 print "\t%d -> %d" % (r.rev(e[4]), i)
389 print "\t%d -> %d" % (r.rev(e[4]), i)
390 if e[5] != hg.nullid:
390 if e[5] != hg.nullid:
391 print "\t%d -> %d" % (r.rev(e[5]), i)
391 print "\t%d -> %d" % (r.rev(e[5]), i)
392 print "}"
392 print "}"
393
393
394 def diff(ui, repo, *files, **opts):
394 def diff(ui, repo, *files, **opts):
395 """diff working directory (or selected files)"""
395 """diff working directory (or selected files)"""
396 revs = []
396 revs = []
397 if opts['rev']:
397 if opts['rev']:
398 revs = map(lambda x: repo.lookup(x), opts['rev'])
398 revs = map(lambda x: repo.lookup(x), opts['rev'])
399
399
400 if len(revs) > 2:
400 if len(revs) > 2:
401 ui.warn("too many revisions to diff\n")
401 ui.warn("too many revisions to diff\n")
402 sys.exit(1)
402 sys.exit(1)
403
403
404 if files:
404 if files:
405 files = relpath(repo, files)
405 files = relpath(repo, files)
406 else:
406 else:
407 files = relpath(repo, [""])
407 files = relpath(repo, [""])
408
408
409 dodiff(ui, repo, os.getcwd(), files, *revs)
409 dodiff(ui, repo, os.getcwd(), files, *revs)
410
410
411 def export(ui, repo, changeset):
411 def export(ui, repo, changeset):
412 """dump the changeset header and diffs for a revision"""
412 """dump the changeset header and diffs for a revision"""
413 node = repo.lookup(changeset)
413 node = repo.lookup(changeset)
414 prev, other = repo.changelog.parents(node)
414 prev, other = repo.changelog.parents(node)
415 change = repo.changelog.read(node)
415 change = repo.changelog.read(node)
416 print "# HG changeset patch"
416 print "# HG changeset patch"
417 print "# User %s" % change[1]
417 print "# User %s" % change[1]
418 print "# Node ID %s" % hg.hex(node)
418 print "# Node ID %s" % hg.hex(node)
419 print "# Parent %s" % hg.hex(prev)
419 print "# Parent %s" % hg.hex(prev)
420 print
420 print
421 if other != hg.nullid:
421 if other != hg.nullid:
422 print "# Parent %s" % hg.hex(other)
422 print "# Parent %s" % hg.hex(other)
423 print change[4].rstrip()
423 print change[4].rstrip()
424 print
424 print
425
425
426 dodiff(ui, repo, "", None, prev, node)
426 dodiff(ui, repo, "", None, prev, node)
427
427
428 def forget(ui, repo, file, *files):
428 def forget(ui, repo, file, *files):
429 """don't add the specified files on the next commit"""
429 """don't add the specified files on the next commit"""
430 repo.forget(relpath(repo, (file,) + files))
430 repo.forget(relpath(repo, (file,) + files))
431
431
432 def heads(ui, repo):
432 def heads(ui, repo):
433 """show current repository heads"""
433 """show current repository heads"""
434 for n in repo.changelog.heads():
434 for n in repo.changelog.heads():
435 show_changeset(ui, repo, changenode=n)
435 show_changeset(ui, repo, changenode=n)
436
436
437 def history(ui, repo):
438 """show the changelog history"""
439 for i in range(repo.changelog.count() - 1, -1, -1):
440 show_changeset(ui, repo, rev=i)
441
442 def identify(ui, repo):
437 def identify(ui, repo):
443 """print information about the working copy"""
438 """print information about the working copy"""
444 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
439 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
445 if not parents:
440 if not parents:
446 ui.write("unknown\n")
441 ui.write("unknown\n")
447 return
442 return
448
443
449 hexfunc = ui.verbose and hg.hex or hg.short
444 hexfunc = ui.verbose and hg.hex or hg.short
450 (c, a, d, u) = repo.diffdir(repo.root)
445 (c, a, d, u) = repo.diffdir(repo.root)
451 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
446 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
452 (c or a or d) and "+" or "")]
447 (c or a or d) and "+" or "")]
453
448
454 if not ui.quiet:
449 if not ui.quiet:
455 # multiple tags for a single parent separated by '/'
450 # multiple tags for a single parent separated by '/'
456 parenttags = ['/'.join(tags)
451 parenttags = ['/'.join(tags)
457 for tags in map(repo.nodetags, parents) if tags]
452 for tags in map(repo.nodetags, parents) if tags]
458 # tags for multiple parents separated by ' + '
453 # tags for multiple parents separated by ' + '
459 output.append(' + '.join(parenttags))
454 output.append(' + '.join(parenttags))
460
455
461 ui.write("%s\n" % ' '.join(output))
456 ui.write("%s\n" % ' '.join(output))
462
457
463 def import_(ui, repo, patch1, *patches, **opts):
458 def import_(ui, repo, patch1, *patches, **opts):
464 """import an ordered set of patches"""
459 """import an ordered set of patches"""
465 try:
460 try:
466 import psyco
461 import psyco
467 psyco.full()
462 psyco.full()
468 except:
463 except:
469 pass
464 pass
470
465
471 patches = (patch1,) + patches
466 patches = (patch1,) + patches
472
467
473 d = opts["base"]
468 d = opts["base"]
474 strip = opts["strip"]
469 strip = opts["strip"]
475
470
476 for patch in patches:
471 for patch in patches:
477 ui.status("applying %s\n" % patch)
472 ui.status("applying %s\n" % patch)
478 pf = os.path.join(d, patch)
473 pf = os.path.join(d, patch)
479
474
480 text = ""
475 text = ""
481 for l in file(pf):
476 for l in file(pf):
482 if l[:4] == "--- ": break
477 if l[:4] == "--- ": break
483 text += l
478 text += l
484
479
485 # make sure text isn't empty
480 # make sure text isn't empty
486 if not text: text = "imported patch %s\n" % patch
481 if not text: text = "imported patch %s\n" % patch
487
482
488 f = os.popen("patch -p%d < %s" % (strip, pf))
483 f = os.popen("patch -p%d < %s" % (strip, pf))
489 files = []
484 files = []
490 for l in f.read().splitlines():
485 for l in f.read().splitlines():
491 l.rstrip('\r\n');
486 l.rstrip('\r\n');
492 ui.status("%s\n" % l)
487 ui.status("%s\n" % l)
493 if l[:14] == 'patching file ':
488 if l[:14] == 'patching file ':
494 pf = l[14:]
489 pf = l[14:]
495 if pf not in files:
490 if pf not in files:
496 files.append(pf)
491 files.append(pf)
497 patcherr = f.close()
492 patcherr = f.close()
498 if patcherr:
493 if patcherr:
499 sys.stderr.write("patch failed")
494 sys.stderr.write("patch failed")
500 sys.exit(1)
495 sys.exit(1)
501
496
502 if len(files) > 0:
497 if len(files) > 0:
503 addremove(ui, repo, *files)
498 addremove(ui, repo, *files)
504 repo.commit(files, text)
499 repo.commit(files, text)
505
500
506 def init(ui, source=None):
501 def init(ui, source=None):
507 """create a new repository in the current directory"""
502 """create a new repository in the current directory"""
508
503
509 if source:
504 if source:
510 ui.warn("no longer supported: use \"hg clone\" instead\n")
505 ui.warn("no longer supported: use \"hg clone\" instead\n")
511 sys.exit(1)
506 sys.exit(1)
512 repo = hg.repository(ui, ".", create=1)
507 repo = hg.repository(ui, ".", create=1)
513
508
514 def log(ui, repo, f):
509 def log(ui, repo, f = None):
515 """show the revision history of a single file"""
510 """show the revision history of the repository or a single file"""
516 f = relpath(repo, [f])[0]
511 if f:
517
512 f = relpath(repo, [f])[0]
518 r = repo.file(f)
513 r = repo.file(f)
519 for i in range(r.count() - 1, -1, -1):
514 for i in range(r.count() - 1, -1, -1):
520 show_changeset(ui, repo, filelog=r, rev=i)
515 show_changeset(ui, repo, filelog=r, rev=i)
516 else:
517 for i in range(repo.changelog.count() - 1, -1, -1):
518 show_changeset(ui, repo, rev=i)
521
519
522 def manifest(ui, repo, rev = []):
520 def manifest(ui, repo, rev = []):
523 """output the latest or given revision of the project manifest"""
521 """output the latest or given revision of the project manifest"""
524 n = repo.manifest.tip()
522 n = repo.manifest.tip()
525 if rev:
523 if rev:
526 n = repo.manifest.lookup(rev)
524 n = repo.manifest.lookup(rev)
527 m = repo.manifest.read(n)
525 m = repo.manifest.read(n)
528 mf = repo.manifest.readflags(n)
526 mf = repo.manifest.readflags(n)
529 files = m.keys()
527 files = m.keys()
530 files.sort()
528 files.sort()
531
529
532 for f in files:
530 for f in files:
533 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
531 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
534
532
535 def parents(ui, repo, node = None):
533 def parents(ui, repo, node = None):
536 '''show the parents of the current working dir'''
534 '''show the parents of the current working dir'''
537 if node:
535 if node:
538 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
536 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
539 else:
537 else:
540 p = repo.dirstate.parents()
538 p = repo.dirstate.parents()
541
539
542 for n in p:
540 for n in p:
543 if n != hg.nullid:
541 if n != hg.nullid:
544 show_changeset(ui, repo, changenode=n)
542 show_changeset(ui, repo, changenode=n)
545
543
546 def pull(ui, repo, source="default", **opts):
544 def pull(ui, repo, source="default", **opts):
547 """pull changes from the specified source"""
545 """pull changes from the specified source"""
548 source = ui.expandpath(source)
546 source = ui.expandpath(source)
549
547
550 ui.status('pulling from %s\n' % (source))
548 ui.status('pulling from %s\n' % (source))
551
549
552 other = hg.repository(ui, source)
550 other = hg.repository(ui, source)
553 cg = repo.getchangegroup(other)
551 cg = repo.getchangegroup(other)
554 r = repo.addchangegroup(cg)
552 r = repo.addchangegroup(cg)
555 if cg and not r:
553 if cg and not r:
556 if opts['update']:
554 if opts['update']:
557 return update(ui, repo)
555 return update(ui, repo)
558 else:
556 else:
559 ui.status("(run 'hg update' to get a working copy)\n")
557 ui.status("(run 'hg update' to get a working copy)\n")
560
558
561 return r
559 return r
562
560
563 def push(ui, repo, dest="default-push"):
561 def push(ui, repo, dest="default-push"):
564 """push changes to the specified destination"""
562 """push changes to the specified destination"""
565 dest = ui.expandpath(dest)
563 dest = ui.expandpath(dest)
566
564
567 if not dest.startswith("ssh://"):
565 if not dest.startswith("ssh://"):
568 ui.warn("abort: can only push to ssh:// destinations currently\n")
566 ui.warn("abort: can only push to ssh:// destinations currently\n")
569 return 1
567 return 1
570
568
571 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
569 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
572 if not m:
570 if not m:
573 ui.warn("abort: couldn't parse destination %s\n" % dest)
571 ui.warn("abort: couldn't parse destination %s\n" % dest)
574 return 1
572 return 1
575
573
576 user, host, port, path = map(m.group, (2, 3, 5, 7))
574 user, host, port, path = map(m.group, (2, 3, 5, 7))
577 host = user and ("%s@%s" % (user, host)) or host
575 host = user and ("%s@%s" % (user, host)) or host
578 port = port and (" -p %s") % port or ""
576 port = port and (" -p %s") % port or ""
579 path = path or ""
577 path = path or ""
580
578
581 sport = random.randrange(30000, 60000)
579 sport = random.randrange(30000, 60000)
582 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
580 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
583 cmd = cmd % (host, port, sport+1, sport, path, sport+1)
581 cmd = cmd % (host, port, sport+1, sport, path, sport+1)
584
582
585 child = os.fork()
583 child = os.fork()
586 if not child:
584 if not child:
587 sys.stdout = file("/dev/null", "w")
585 sys.stdout = file("/dev/null", "w")
588 sys.stderr = sys.stdout
586 sys.stderr = sys.stdout
589 hgweb.server(repo.root, "pull", "", "localhost", sport)
587 hgweb.server(repo.root, "pull", "", "localhost", sport)
590 else:
588 else:
591 r = os.system(cmd)
589 r = os.system(cmd)
592 os.kill(child, signal.SIGTERM)
590 os.kill(child, signal.SIGTERM)
593 return r
591 return r
594
592
595 def rawcommit(ui, repo, *flist, **rc):
593 def rawcommit(ui, repo, *flist, **rc):
596 "raw commit interface"
594 "raw commit interface"
597
595
598 text = rc['text']
596 text = rc['text']
599 if not text and rc['logfile']:
597 if not text and rc['logfile']:
600 try: text = open(rc['logfile']).read()
598 try: text = open(rc['logfile']).read()
601 except IOError: pass
599 except IOError: pass
602 if not text and not rc['logfile']:
600 if not text and not rc['logfile']:
603 print "missing commit text"
601 print "missing commit text"
604 return 1
602 return 1
605
603
606 files = relpath(repo, list(flist))
604 files = relpath(repo, list(flist))
607 if rc['files']:
605 if rc['files']:
608 files += open(rc['files']).read().splitlines()
606 files += open(rc['files']).read().splitlines()
609
607
610 rc['parent'] = map(repo.lookup, rc['parent'])
608 rc['parent'] = map(repo.lookup, rc['parent'])
611
609
612 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
610 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
613
611
614 def recover(ui, repo):
612 def recover(ui, repo):
615 """roll back an interrupted transaction"""
613 """roll back an interrupted transaction"""
616 repo.recover()
614 repo.recover()
617
615
618 def remove(ui, repo, file, *files):
616 def remove(ui, repo, file, *files):
619 """remove the specified files on the next commit"""
617 """remove the specified files on the next commit"""
620 repo.remove(relpath(repo, (file,) + files))
618 repo.remove(relpath(repo, (file,) + files))
621
619
622 def root(ui, repo):
620 def root(ui, repo):
623 """print the root (top) of the current working dir"""
621 """print the root (top) of the current working dir"""
624 ui.write(repo.root + "\n")
622 ui.write(repo.root + "\n")
625
623
626 def serve(ui, repo, **opts):
624 def serve(ui, repo, **opts):
627 """export the repository via HTTP"""
625 """export the repository via HTTP"""
628 hgweb.server(repo.root, opts["name"], opts["templates"],
626 hgweb.server(repo.root, opts["name"], opts["templates"],
629 opts["address"], opts["port"])
627 opts["address"], opts["port"])
630
628
631 def status(ui, repo):
629 def status(ui, repo):
632 '''show changed files in the working directory
630 '''show changed files in the working directory
633
631
634 C = changed
632 C = changed
635 A = added
633 A = added
636 R = removed
634 R = removed
637 ? = not tracked'''
635 ? = not tracked'''
638
636
639 (c, a, d, u) = repo.diffdir(os.getcwd())
637 (c, a, d, u) = repo.diffdir(os.getcwd())
640 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
638 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
641
639
642 for f in c: print "C", f
640 for f in c: print "C", f
643 for f in a: print "A", f
641 for f in a: print "A", f
644 for f in d: print "R", f
642 for f in d: print "R", f
645 for f in u: print "?", f
643 for f in u: print "?", f
646
644
647 def tag(ui, repo, name, rev = None, **opts):
645 def tag(ui, repo, name, rev = None, **opts):
648 """add a tag for the current tip or a given revision"""
646 """add a tag for the current tip or a given revision"""
649
647
650 if name == "tip":
648 if name == "tip":
651 ui.warn("abort: 'tip' is a reserved name!\n")
649 ui.warn("abort: 'tip' is a reserved name!\n")
652 return -1
650 return -1
653
651
654 (c, a, d, u) = repo.diffdir(repo.root)
652 (c, a, d, u) = repo.diffdir(repo.root)
655 for x in (c, a, d, u):
653 for x in (c, a, d, u):
656 if ".hgtags" in x:
654 if ".hgtags" in x:
657 ui.warn("abort: working copy of .hgtags is changed!\n")
655 ui.warn("abort: working copy of .hgtags is changed!\n")
658 ui.status("(please commit .hgtags manually)\n")
656 ui.status("(please commit .hgtags manually)\n")
659 return -1
657 return -1
660
658
661 if rev:
659 if rev:
662 r = hg.hex(repo.lookup(rev))
660 r = hg.hex(repo.lookup(rev))
663 else:
661 else:
664 r = hg.hex(repo.changelog.tip())
662 r = hg.hex(repo.changelog.tip())
665
663
666 add = 0
664 add = 0
667 if not os.path.exists(repo.wjoin(".hgtags")): add = 1
665 if not os.path.exists(repo.wjoin(".hgtags")): add = 1
668 repo.wfile(".hgtags", "a").write("%s %s\n" % (r, name))
666 repo.wfile(".hgtags", "a").write("%s %s\n" % (r, name))
669 if add: repo.add([".hgtags"])
667 if add: repo.add([".hgtags"])
670
668
671 if not opts['text']:
669 if not opts['text']:
672 opts['text'] = "Added tag %s for changeset %s" % (name, r)
670 opts['text'] = "Added tag %s for changeset %s" % (name, r)
673
671
674 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
672 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
675
673
676 def tags(ui, repo):
674 def tags(ui, repo):
677 """list repository tags"""
675 """list repository tags"""
678
676
679 l = repo.tagslist()
677 l = repo.tagslist()
680 l.reverse()
678 l.reverse()
681 for t, n in l:
679 for t, n in l:
682 try:
680 try:
683 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
681 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
684 except KeyError:
682 except KeyError:
685 r = " ?:?"
683 r = " ?:?"
686 ui.write("%-30s %s\n" % (t, r))
684 ui.write("%-30s %s\n" % (t, r))
687
685
688 def tip(ui, repo):
686 def tip(ui, repo):
689 """show the tip revision"""
687 """show the tip revision"""
690 n = repo.changelog.tip()
688 n = repo.changelog.tip()
691 show_changeset(ui, repo, changenode=n)
689 show_changeset(ui, repo, changenode=n)
692
690
693 def undo(ui, repo):
691 def undo(ui, repo):
694 """undo the last transaction"""
692 """undo the last transaction"""
695 repo.undo()
693 repo.undo()
696
694
697 def update(ui, repo, node=None, merge=False, clean=False):
695 def update(ui, repo, node=None, merge=False, clean=False):
698 '''update or merge working directory
696 '''update or merge working directory
699
697
700 If there are no outstanding changes in the working directory and
698 If there are no outstanding changes in the working directory and
701 there is a linear relationship between the current version and the
699 there is a linear relationship between the current version and the
702 requested version, the result is the requested version.
700 requested version, the result is the requested version.
703
701
704 Otherwise the result is a merge between the contents of the
702 Otherwise the result is a merge between the contents of the
705 current working directory and the requested version. Files that
703 current working directory and the requested version. Files that
706 changed between either parent are marked as changed for the next
704 changed between either parent are marked as changed for the next
707 commit and a commit must be performed before any further updates
705 commit and a commit must be performed before any further updates
708 are allowed.
706 are allowed.
709 '''
707 '''
710 node = node and repo.lookup(node) or repo.changelog.tip()
708 node = node and repo.lookup(node) or repo.changelog.tip()
711 return repo.update(node, allow=merge, force=clean)
709 return repo.update(node, allow=merge, force=clean)
712
710
713 def verify(ui, repo):
711 def verify(ui, repo):
714 """verify the integrity of the repository"""
712 """verify the integrity of the repository"""
715 return repo.verify()
713 return repo.verify()
716
714
717 # Command options and aliases are listed here, alphabetically
715 # Command options and aliases are listed here, alphabetically
718
716
719 table = {
717 table = {
720 "add": (add, [], "hg add [files]"),
718 "add": (add, [], "hg add [files]"),
721 "addremove": (addremove, [], "hg addremove [files]"),
719 "addremove": (addremove, [], "hg addremove [files]"),
722 "annotate": (annotate,
720 "annotate": (annotate,
723 [('r', 'revision', '', 'revision'),
721 [('r', 'revision', '', 'revision'),
724 ('u', 'user', None, 'show user'),
722 ('u', 'user', None, 'show user'),
725 ('n', 'number', None, 'show revision number'),
723 ('n', 'number', None, 'show revision number'),
726 ('c', 'changeset', None, 'show changeset')],
724 ('c', 'changeset', None, 'show changeset')],
727 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
725 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
728 "cat": (cat, [], 'hg cat <file> [rev]'),
726 "cat": (cat, [], 'hg cat <file> [rev]'),
729 "clone": (clone, [('U', 'noupdate', None, 'skip update after cloning')],
727 "clone": (clone, [('U', 'noupdate', None, 'skip update after cloning')],
730 'hg clone [options] <source> [dest]'),
728 'hg clone [options] <source> [dest]'),
731 "commit|ci": (commit,
729 "commit|ci": (commit,
732 [('t', 'text', "", 'commit text'),
730 [('t', 'text', "", 'commit text'),
733 ('A', 'addremove', None, 'run add/remove during commit'),
731 ('A', 'addremove', None, 'run add/remove during commit'),
734 ('l', 'logfile', "", 'commit text file'),
732 ('l', 'logfile', "", 'commit text file'),
735 ('d', 'date', "", 'data'),
733 ('d', 'date', "", 'data'),
736 ('u', 'user', "", 'user')],
734 ('u', 'user', "", 'user')],
737 'hg commit [files]'),
735 'hg commit [files]'),
738 "copy": (copy, [], 'hg copy <source> <dest>'),
736 "copy": (copy, [], 'hg copy <source> <dest>'),
739 "debugcheckdirstate": (debugcheckdirstate, [], 'debugcheckdirstate'),
737 "debugcheckdirstate": (debugcheckdirstate, [], 'debugcheckdirstate'),
740 "debugdumpdirstate": (debugdumpdirstate, [], 'debugdumpdirstate'),
738 "debugdumpdirstate": (debugdumpdirstate, [], 'debugdumpdirstate'),
741 "debugindex": (debugindex, [], 'debugindex <file>'),
739 "debugindex": (debugindex, [], 'debugindex <file>'),
742 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
740 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
743 "diff": (diff, [('r', 'rev', [], 'revision')],
741 "diff": (diff, [('r', 'rev', [], 'revision')],
744 'hg diff [-r A] [-r B] [files]'),
742 'hg diff [-r A] [-r B] [files]'),
745 "export": (export, [], "hg export <changeset>"),
743 "export": (export, [], "hg export <changeset>"),
746 "forget": (forget, [], "hg forget [files]"),
744 "forget": (forget, [], "hg forget [files]"),
747 "heads": (heads, [], 'hg heads'),
745 "heads": (heads, [], 'hg heads'),
748 "history": (history, [], 'hg history'),
749 "help": (help, [], 'hg help [command]'),
746 "help": (help, [], 'hg help [command]'),
750 "identify|id": (identify, [], 'hg identify'),
747 "identify|id": (identify, [], 'hg identify'),
751 "import|patch": (import_,
748 "import|patch": (import_,
752 [('p', 'strip', 1, 'path strip'),
749 [('p', 'strip', 1, 'path strip'),
753 ('b', 'base', "", 'base path')],
750 ('b', 'base', "", 'base path')],
754 "hg import [options] <patches>"),
751 "hg import [options] <patches>"),
755 "init": (init, [], 'hg init'),
752 "init": (init, [], 'hg init'),
756 "log": (log, [], 'hg log <file>'),
753 "log|history": (log, [], 'hg log [file]'),
757 "manifest": (manifest, [], 'hg manifest [rev]'),
754 "manifest": (manifest, [], 'hg manifest [rev]'),
758 "parents": (parents, [], 'hg parents [node]'),
755 "parents": (parents, [], 'hg parents [node]'),
759 "pull": (pull,
756 "pull": (pull,
760 [('u', 'update', None, 'update working directory')],
757 [('u', 'update', None, 'update working directory')],
761 'hg pull [options] [source]'),
758 'hg pull [options] [source]'),
762 "push": (push, [], 'hg push <destination>'),
759 "push": (push, [], 'hg push <destination>'),
763 "rawcommit": (rawcommit,
760 "rawcommit": (rawcommit,
764 [('p', 'parent', [], 'parent'),
761 [('p', 'parent', [], 'parent'),
765 ('d', 'date', "", 'data'),
762 ('d', 'date', "", 'data'),
766 ('u', 'user', "", 'user'),
763 ('u', 'user', "", 'user'),
767 ('F', 'files', "", 'file list'),
764 ('F', 'files', "", 'file list'),
768 ('t', 'text', "", 'commit text'),
765 ('t', 'text', "", 'commit text'),
769 ('l', 'logfile', "", 'commit text file')],
766 ('l', 'logfile', "", 'commit text file')],
770 'hg rawcommit [options] [files]'),
767 'hg rawcommit [options] [files]'),
771 "recover": (recover, [], "hg recover"),
768 "recover": (recover, [], "hg recover"),
772 "remove|rm": (remove, [], "hg remove [files]"),
769 "remove|rm": (remove, [], "hg remove [files]"),
773 "root": (root, [], "hg root"),
770 "root": (root, [], "hg root"),
774 "serve": (serve, [('p', 'port', 8000, 'listen port'),
771 "serve": (serve, [('p', 'port', 8000, 'listen port'),
775 ('a', 'address', '', 'interface address'),
772 ('a', 'address', '', 'interface address'),
776 ('n', 'name', os.getcwd(), 'repository name'),
773 ('n', 'name', os.getcwd(), 'repository name'),
777 ('t', 'templates', "", 'template map')],
774 ('t', 'templates', "", 'template map')],
778 "hg serve [options]"),
775 "hg serve [options]"),
779 "status": (status, [], 'hg status'),
776 "status": (status, [], 'hg status'),
780 "tag": (tag, [('t', 'text', "", 'commit text'),
777 "tag": (tag, [('t', 'text', "", 'commit text'),
781 ('d', 'date', "", 'date'),
778 ('d', 'date', "", 'date'),
782 ('u', 'user', "", 'user')],
779 ('u', 'user', "", 'user')],
783 'hg tag [options] <name> [rev]'),
780 'hg tag [options] <name> [rev]'),
784 "tags": (tags, [], 'hg tags'),
781 "tags": (tags, [], 'hg tags'),
785 "tip": (tip, [], 'hg tip'),
782 "tip": (tip, [], 'hg tip'),
786 "undo": (undo, [], 'hg undo'),
783 "undo": (undo, [], 'hg undo'),
787 "update|up|checkout|co":
784 "update|up|checkout|co":
788 (update,
785 (update,
789 [('m', 'merge', None, 'allow merging of conflicts'),
786 [('m', 'merge', None, 'allow merging of conflicts'),
790 ('C', 'clean', None, 'overwrite locally modified files')],
787 ('C', 'clean', None, 'overwrite locally modified files')],
791 'hg update [options] [node]'),
788 'hg update [options] [node]'),
792 "verify": (verify, [], 'hg verify'),
789 "verify": (verify, [], 'hg verify'),
793 "version": (show_version, [], 'hg version'),
790 "version": (show_version, [], 'hg version'),
794 }
791 }
795
792
796 norepo = "clone init version help debugindex debugindexdot"
793 norepo = "clone init version help debugindex debugindexdot"
797
794
798 def find(cmd):
795 def find(cmd):
799 for e in table.keys():
796 for e in table.keys():
800 if re.match("(%s)$" % e, cmd):
797 if re.match("(%s)$" % e, cmd):
801 return table[e]
798 return table[e]
802
799
803 raise UnknownCommand(cmd)
800 raise UnknownCommand(cmd)
804
801
805 class SignalInterrupt(Exception): pass
802 class SignalInterrupt(Exception): pass
806
803
807 def catchterm(*args):
804 def catchterm(*args):
808 raise SignalInterrupt
805 raise SignalInterrupt
809
806
810 def run():
807 def run():
811 sys.exit(dispatch(sys.argv[1:]))
808 sys.exit(dispatch(sys.argv[1:]))
812
809
813 def dispatch(args):
810 def dispatch(args):
814 options = {}
811 options = {}
815 opts = [('v', 'verbose', None, 'verbose'),
812 opts = [('v', 'verbose', None, 'verbose'),
816 ('d', 'debug', None, 'debug'),
813 ('d', 'debug', None, 'debug'),
817 ('q', 'quiet', None, 'quiet'),
814 ('q', 'quiet', None, 'quiet'),
818 ('p', 'profile', None, 'profile'),
815 ('p', 'profile', None, 'profile'),
819 ('y', 'noninteractive', None, 'run non-interactively'),
816 ('y', 'noninteractive', None, 'run non-interactively'),
820 ('', 'version', None, 'output version information and exit'),
817 ('', 'version', None, 'output version information and exit'),
821 ]
818 ]
822
819
823 args = fancyopts.fancyopts(args, opts, options,
820 args = fancyopts.fancyopts(args, opts, options,
824 'hg [options] <command> [options] [files]')
821 'hg [options] <command> [options] [files]')
825
822
826 if not args:
823 if not args:
827 cmd = "help"
824 cmd = "help"
828 else:
825 else:
829 cmd, args = args[0], args[1:]
826 cmd, args = args[0], args[1:]
830
827
831 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
828 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
832 not options["noninteractive"])
829 not options["noninteractive"])
833
830
834 if options["version"]:
831 if options["version"]:
835 show_version(u)
832 show_version(u)
836 sys.exit(0)
833 sys.exit(0)
837
834
838 try:
835 try:
839 i = find(cmd)
836 i = find(cmd)
840 except UnknownCommand:
837 except UnknownCommand:
841 u.warn("hg: unknown command '%s'\n" % cmd)
838 u.warn("hg: unknown command '%s'\n" % cmd)
842 help(u)
839 help(u)
843 sys.exit(1)
840 sys.exit(1)
844
841
845 signal.signal(signal.SIGTERM, catchterm)
842 signal.signal(signal.SIGTERM, catchterm)
846
843
847 cmdoptions = {}
844 cmdoptions = {}
848 try:
845 try:
849 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
846 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
850 except fancyopts.getopt.GetoptError, inst:
847 except fancyopts.getopt.GetoptError, inst:
851 u.warn("hg %s: %s\n" % (cmd, inst))
848 u.warn("hg %s: %s\n" % (cmd, inst))
852 help(u, cmd)
849 help(u, cmd)
853 sys.exit(-1)
850 sys.exit(-1)
854
851
855 try:
852 try:
856 if cmd not in norepo.split():
853 if cmd not in norepo.split():
857 repo = hg.repository(ui = u)
854 repo = hg.repository(ui = u)
858 d = lambda: i[0](u, repo, *args, **cmdoptions)
855 d = lambda: i[0](u, repo, *args, **cmdoptions)
859 else:
856 else:
860 d = lambda: i[0](u, *args, **cmdoptions)
857 d = lambda: i[0](u, *args, **cmdoptions)
861
858
862 if options['profile']:
859 if options['profile']:
863 import hotshot, hotshot.stats
860 import hotshot, hotshot.stats
864 prof = hotshot.Profile("hg.prof")
861 prof = hotshot.Profile("hg.prof")
865 r = prof.runcall(d)
862 r = prof.runcall(d)
866 prof.close()
863 prof.close()
867 stats = hotshot.stats.load("hg.prof")
864 stats = hotshot.stats.load("hg.prof")
868 stats.strip_dirs()
865 stats.strip_dirs()
869 stats.sort_stats('time', 'calls')
866 stats.sort_stats('time', 'calls')
870 stats.print_stats(40)
867 stats.print_stats(40)
871 return r
868 return r
872 else:
869 else:
873 return d()
870 return d()
874 except util.CommandError, inst:
871 except util.CommandError, inst:
875 u.warn("abort: %s\n" % inst.args)
872 u.warn("abort: %s\n" % inst.args)
876 except hg.RepoError, inst:
873 except hg.RepoError, inst:
877 u.warn("abort: ", inst, "!\n")
874 u.warn("abort: ", inst, "!\n")
878 except SignalInterrupt:
875 except SignalInterrupt:
879 u.warn("killed!\n")
876 u.warn("killed!\n")
880 except KeyboardInterrupt:
877 except KeyboardInterrupt:
881 u.warn("interrupted!\n")
878 u.warn("interrupted!\n")
882 except IOError, inst:
879 except IOError, inst:
883 if hasattr(inst, "code"):
880 if hasattr(inst, "code"):
884 u.warn("abort: %s\n" % inst)
881 u.warn("abort: %s\n" % inst)
885 elif hasattr(inst, "reason"):
882 elif hasattr(inst, "reason"):
886 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
883 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
887 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
884 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
888 u.warn("broken pipe\n")
885 u.warn("broken pipe\n")
889 else:
886 else:
890 raise
887 raise
891 except TypeError, inst:
888 except TypeError, inst:
892 # was this an argument error?
889 # was this an argument error?
893 tb = traceback.extract_tb(sys.exc_info()[2])
890 tb = traceback.extract_tb(sys.exc_info()[2])
894 if len(tb) > 2: # no
891 if len(tb) > 2: # no
895 raise
892 raise
896 u.debug(inst, "\n")
893 u.debug(inst, "\n")
897 u.warn("%s: invalid arguments\n" % i[0].__name__)
894 u.warn("%s: invalid arguments\n" % i[0].__name__)
898 help(u, cmd)
895 help(u, cmd)
899
896
900 sys.exit(-1)
897 sys.exit(-1)
901
898
@@ -1,90 +1,88 b''
1 + hg -q help
1 + hg -q help
2 hg commands:
2 hg commands:
3
3
4 add add the specified files on the next commit
4 add add the specified files on the next commit
5 addremove add all new files, delete all missing files
5 addremove add all new files, delete all missing files
6 annotate show changeset information per file line
6 annotate show changeset information per file line
7 cat output the latest or given revision of a file
7 cat output the latest or given revision of a file
8 clone make a copy of an existing repository
8 clone make a copy of an existing repository
9 commit commit the specified files or all outstanding changes
9 commit commit the specified files or all outstanding changes
10 copy mark a file as copied or renamed for the next commit
10 copy mark a file as copied or renamed for the next commit
11 diff diff working directory (or selected files)
11 diff diff working directory (or selected files)
12 export dump the changeset header and diffs for a revision
12 export dump the changeset header and diffs for a revision
13 forget don't add the specified files on the next commit
13 forget don't add the specified files on the next commit
14 heads show current repository heads
14 heads show current repository heads
15 help show help for a given command or all commands
15 help show help for a given command or all commands
16 history show the changelog history
17 identify print information about the working copy
16 identify print information about the working copy
18 import import an ordered set of patches
17 import import an ordered set of patches
19 init create a new repository in the current directory
18 init create a new repository in the current directory
20 log show the revision history of a single file
19 log show the revision history of the repository or a single file
21 manifest output the latest or given revision of the project manifest
20 manifest output the latest or given revision of the project manifest
22 parents show the parents of the current working dir
21 parents show the parents of the current working dir
23 pull pull changes from the specified source
22 pull pull changes from the specified source
24 push push changes to the specified destination
23 push push changes to the specified destination
25 rawcommit raw commit interface
24 rawcommit raw commit interface
26 recover roll back an interrupted transaction
25 recover roll back an interrupted transaction
27 remove remove the specified files on the next commit
26 remove remove the specified files on the next commit
28 root print the root (top) of the current working dir
27 root print the root (top) of the current working dir
29 serve export the repository via HTTP
28 serve export the repository via HTTP
30 status show changed files in the working directory
29 status show changed files in the working directory
31 tag add a tag for the current tip or a given revision
30 tag add a tag for the current tip or a given revision
32 tags list repository tags
31 tags list repository tags
33 tip show the tip revision
32 tip show the tip revision
34 undo undo the last transaction
33 undo undo the last transaction
35 update update or merge working directory
34 update update or merge working directory
36 verify verify the integrity of the repository
35 verify verify the integrity of the repository
37 version output version and copyright information
36 version output version and copyright information
38 + hg add -h
37 + hg add -h
39 hg add: option -h not recognized
38 hg add: option -h not recognized
40 hg add [files]
39 hg add [files]
41
40
42 add the specified files on the next commit
41 add the specified files on the next commit
43 + hg help diff
42 + hg help diff
44 hg diff [-r A] [-r B] [files]
43 hg diff [-r A] [-r B] [files]
45
44
46 -r --rev
45 -r --rev
47 revision
46 revision
48
47
49 diff working directory (or selected files)
48 diff working directory (or selected files)
50 + hg help foo
49 + hg help foo
51 hg: unknown command foo
50 hg: unknown command foo
52 + hg -q commands
51 + hg -q commands
53 hg: unknown command 'commands'
52 hg: unknown command 'commands'
54 hg commands:
53 hg commands:
55
54
56 add add the specified files on the next commit
55 add add the specified files on the next commit
57 addremove add all new files, delete all missing files
56 addremove add all new files, delete all missing files
58 annotate show changeset information per file line
57 annotate show changeset information per file line
59 cat output the latest or given revision of a file
58 cat output the latest or given revision of a file
60 clone make a copy of an existing repository
59 clone make a copy of an existing repository
61 commit commit the specified files or all outstanding changes
60 commit commit the specified files or all outstanding changes
62 copy mark a file as copied or renamed for the next commit
61 copy mark a file as copied or renamed for the next commit
63 diff diff working directory (or selected files)
62 diff diff working directory (or selected files)
64 export dump the changeset header and diffs for a revision
63 export dump the changeset header and diffs for a revision
65 forget don't add the specified files on the next commit
64 forget don't add the specified files on the next commit
66 heads show current repository heads
65 heads show current repository heads
67 help show help for a given command or all commands
66 help show help for a given command or all commands
68 history show the changelog history
69 identify print information about the working copy
67 identify print information about the working copy
70 import import an ordered set of patches
68 import import an ordered set of patches
71 init create a new repository in the current directory
69 init create a new repository in the current directory
72 log show the revision history of a single file
70 log show the revision history of the repository or a single file
73 manifest output the latest or given revision of the project manifest
71 manifest output the latest or given revision of the project manifest
74 parents show the parents of the current working dir
72 parents show the parents of the current working dir
75 pull pull changes from the specified source
73 pull pull changes from the specified source
76 push push changes to the specified destination
74 push push changes to the specified destination
77 rawcommit raw commit interface
75 rawcommit raw commit interface
78 recover roll back an interrupted transaction
76 recover roll back an interrupted transaction
79 remove remove the specified files on the next commit
77 remove remove the specified files on the next commit
80 root print the root (top) of the current working dir
78 root print the root (top) of the current working dir
81 serve export the repository via HTTP
79 serve export the repository via HTTP
82 status show changed files in the working directory
80 status show changed files in the working directory
83 tag add a tag for the current tip or a given revision
81 tag add a tag for the current tip or a given revision
84 tags list repository tags
82 tags list repository tags
85 tip show the tip revision
83 tip show the tip revision
86 undo undo the last transaction
84 undo undo the last transaction
87 update update or merge working directory
85 update update or merge working directory
88 verify verify the integrity of the repository
86 verify verify the integrity of the repository
89 version output version and copyright information
87 version output version and copyright information
90 + exit 0
88 + exit 0
General Comments 0
You need to be logged in to leave comments. Login now