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