##// END OF EJS Templates
minirst: end all blocks with newlines...
Matt Mackall -
r15125:bdc59505 default
parent child Browse files
Show More
@@ -1,5368 +1,5368 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge
18 import dagparser, context, simplemerge
19 import random, setdiscovery, treediscovery, dagutil
19 import random, setdiscovery, treediscovery, dagutil
20
20
21 table = {}
21 table = {}
22
22
23 command = cmdutil.command(table)
23 command = cmdutil.command(table)
24
24
25 # common command options
25 # common command options
26
26
27 globalopts = [
27 globalopts = [
28 ('R', 'repository', '',
28 ('R', 'repository', '',
29 _('repository root directory or name of overlay bundle file'),
29 _('repository root directory or name of overlay bundle file'),
30 _('REPO')),
30 _('REPO')),
31 ('', 'cwd', '',
31 ('', 'cwd', '',
32 _('change working directory'), _('DIR')),
32 _('change working directory'), _('DIR')),
33 ('y', 'noninteractive', None,
33 ('y', 'noninteractive', None,
34 _('do not prompt, automatically pick the first choice for all prompts')),
34 _('do not prompt, automatically pick the first choice for all prompts')),
35 ('q', 'quiet', None, _('suppress output')),
35 ('q', 'quiet', None, _('suppress output')),
36 ('v', 'verbose', None, _('enable additional output')),
36 ('v', 'verbose', None, _('enable additional output')),
37 ('', 'config', [],
37 ('', 'config', [],
38 _('set/override config option (use \'section.name=value\')'),
38 _('set/override config option (use \'section.name=value\')'),
39 _('CONFIG')),
39 _('CONFIG')),
40 ('', 'debug', None, _('enable debugging output')),
40 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debugger', None, _('start debugger')),
41 ('', 'debugger', None, _('start debugger')),
42 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
42 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 _('ENCODE')),
43 _('ENCODE')),
44 ('', 'encodingmode', encoding.encodingmode,
44 ('', 'encodingmode', encoding.encodingmode,
45 _('set the charset encoding mode'), _('MODE')),
45 _('set the charset encoding mode'), _('MODE')),
46 ('', 'traceback', None, _('always print a traceback on exception')),
46 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'time', None, _('time how long the command takes')),
47 ('', 'time', None, _('time how long the command takes')),
48 ('', 'profile', None, _('print command execution profile')),
48 ('', 'profile', None, _('print command execution profile')),
49 ('', 'version', None, _('output version information and exit')),
49 ('', 'version', None, _('output version information and exit')),
50 ('h', 'help', None, _('display help and exit')),
50 ('h', 'help', None, _('display help and exit')),
51 ]
51 ]
52
52
53 dryrunopts = [('n', 'dry-run', None,
53 dryrunopts = [('n', 'dry-run', None,
54 _('do not perform actions, just print output'))]
54 _('do not perform actions, just print output'))]
55
55
56 remoteopts = [
56 remoteopts = [
57 ('e', 'ssh', '',
57 ('e', 'ssh', '',
58 _('specify ssh command to use'), _('CMD')),
58 _('specify ssh command to use'), _('CMD')),
59 ('', 'remotecmd', '',
59 ('', 'remotecmd', '',
60 _('specify hg command to run on the remote side'), _('CMD')),
60 _('specify hg command to run on the remote side'), _('CMD')),
61 ('', 'insecure', None,
61 ('', 'insecure', None,
62 _('do not verify server certificate (ignoring web.cacerts config)')),
62 _('do not verify server certificate (ignoring web.cacerts config)')),
63 ]
63 ]
64
64
65 walkopts = [
65 walkopts = [
66 ('I', 'include', [],
66 ('I', 'include', [],
67 _('include names matching the given patterns'), _('PATTERN')),
67 _('include names matching the given patterns'), _('PATTERN')),
68 ('X', 'exclude', [],
68 ('X', 'exclude', [],
69 _('exclude names matching the given patterns'), _('PATTERN')),
69 _('exclude names matching the given patterns'), _('PATTERN')),
70 ]
70 ]
71
71
72 commitopts = [
72 commitopts = [
73 ('m', 'message', '',
73 ('m', 'message', '',
74 _('use text as commit message'), _('TEXT')),
74 _('use text as commit message'), _('TEXT')),
75 ('l', 'logfile', '',
75 ('l', 'logfile', '',
76 _('read commit message from file'), _('FILE')),
76 _('read commit message from file'), _('FILE')),
77 ]
77 ]
78
78
79 commitopts2 = [
79 commitopts2 = [
80 ('d', 'date', '',
80 ('d', 'date', '',
81 _('record the specified date as commit date'), _('DATE')),
81 _('record the specified date as commit date'), _('DATE')),
82 ('u', 'user', '',
82 ('u', 'user', '',
83 _('record the specified user as committer'), _('USER')),
83 _('record the specified user as committer'), _('USER')),
84 ]
84 ]
85
85
86 templateopts = [
86 templateopts = [
87 ('', 'style', '',
87 ('', 'style', '',
88 _('display using template map file'), _('STYLE')),
88 _('display using template map file'), _('STYLE')),
89 ('', 'template', '',
89 ('', 'template', '',
90 _('display with template'), _('TEMPLATE')),
90 _('display with template'), _('TEMPLATE')),
91 ]
91 ]
92
92
93 logopts = [
93 logopts = [
94 ('p', 'patch', None, _('show patch')),
94 ('p', 'patch', None, _('show patch')),
95 ('g', 'git', None, _('use git extended diff format')),
95 ('g', 'git', None, _('use git extended diff format')),
96 ('l', 'limit', '',
96 ('l', 'limit', '',
97 _('limit number of changes displayed'), _('NUM')),
97 _('limit number of changes displayed'), _('NUM')),
98 ('M', 'no-merges', None, _('do not show merges')),
98 ('M', 'no-merges', None, _('do not show merges')),
99 ('', 'stat', None, _('output diffstat-style summary of changes')),
99 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ] + templateopts
100 ] + templateopts
101
101
102 diffopts = [
102 diffopts = [
103 ('a', 'text', None, _('treat all files as text')),
103 ('a', 'text', None, _('treat all files as text')),
104 ('g', 'git', None, _('use git extended diff format')),
104 ('g', 'git', None, _('use git extended diff format')),
105 ('', 'nodates', None, _('omit dates from diff headers'))
105 ('', 'nodates', None, _('omit dates from diff headers'))
106 ]
106 ]
107
107
108 diffopts2 = [
108 diffopts2 = [
109 ('p', 'show-function', None, _('show which function each change is in')),
109 ('p', 'show-function', None, _('show which function each change is in')),
110 ('', 'reverse', None, _('produce a diff that undoes the changes')),
110 ('', 'reverse', None, _('produce a diff that undoes the changes')),
111 ('w', 'ignore-all-space', None,
111 ('w', 'ignore-all-space', None,
112 _('ignore white space when comparing lines')),
112 _('ignore white space when comparing lines')),
113 ('b', 'ignore-space-change', None,
113 ('b', 'ignore-space-change', None,
114 _('ignore changes in the amount of white space')),
114 _('ignore changes in the amount of white space')),
115 ('B', 'ignore-blank-lines', None,
115 ('B', 'ignore-blank-lines', None,
116 _('ignore changes whose lines are all blank')),
116 _('ignore changes whose lines are all blank')),
117 ('U', 'unified', '',
117 ('U', 'unified', '',
118 _('number of lines of context to show'), _('NUM')),
118 _('number of lines of context to show'), _('NUM')),
119 ('', 'stat', None, _('output diffstat-style summary of changes')),
119 ('', 'stat', None, _('output diffstat-style summary of changes')),
120 ]
120 ]
121
121
122 mergetoolopts = [
122 mergetoolopts = [
123 ('t', 'tool', '', _('specify merge tool')),
123 ('t', 'tool', '', _('specify merge tool')),
124 ]
124 ]
125
125
126 similarityopts = [
126 similarityopts = [
127 ('s', 'similarity', '',
127 ('s', 'similarity', '',
128 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
128 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
129 ]
129 ]
130
130
131 subrepoopts = [
131 subrepoopts = [
132 ('S', 'subrepos', None,
132 ('S', 'subrepos', None,
133 _('recurse into subrepositories'))
133 _('recurse into subrepositories'))
134 ]
134 ]
135
135
136 # Commands start here, listed alphabetically
136 # Commands start here, listed alphabetically
137
137
138 @command('^add',
138 @command('^add',
139 walkopts + subrepoopts + dryrunopts,
139 walkopts + subrepoopts + dryrunopts,
140 _('[OPTION]... [FILE]...'))
140 _('[OPTION]... [FILE]...'))
141 def add(ui, repo, *pats, **opts):
141 def add(ui, repo, *pats, **opts):
142 """add the specified files on the next commit
142 """add the specified files on the next commit
143
143
144 Schedule files to be version controlled and added to the
144 Schedule files to be version controlled and added to the
145 repository.
145 repository.
146
146
147 The files will be added to the repository at the next commit. To
147 The files will be added to the repository at the next commit. To
148 undo an add before that, see :hg:`forget`.
148 undo an add before that, see :hg:`forget`.
149
149
150 If no names are given, add all files to the repository.
150 If no names are given, add all files to the repository.
151
151
152 .. container:: verbose
152 .. container:: verbose
153
153
154 An example showing how new (unknown) files are added
154 An example showing how new (unknown) files are added
155 automatically by :hg:`add`::
155 automatically by :hg:`add`::
156
156
157 $ ls
157 $ ls
158 foo.c
158 foo.c
159 $ hg status
159 $ hg status
160 ? foo.c
160 ? foo.c
161 $ hg add
161 $ hg add
162 adding foo.c
162 adding foo.c
163 $ hg status
163 $ hg status
164 A foo.c
164 A foo.c
165
165
166 Returns 0 if all files are successfully added.
166 Returns 0 if all files are successfully added.
167 """
167 """
168
168
169 m = scmutil.match(repo[None], pats, opts)
169 m = scmutil.match(repo[None], pats, opts)
170 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
170 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
171 opts.get('subrepos'), prefix="")
171 opts.get('subrepos'), prefix="")
172 return rejected and 1 or 0
172 return rejected and 1 or 0
173
173
174 @command('addremove',
174 @command('addremove',
175 similarityopts + walkopts + dryrunopts,
175 similarityopts + walkopts + dryrunopts,
176 _('[OPTION]... [FILE]...'))
176 _('[OPTION]... [FILE]...'))
177 def addremove(ui, repo, *pats, **opts):
177 def addremove(ui, repo, *pats, **opts):
178 """add all new files, delete all missing files
178 """add all new files, delete all missing files
179
179
180 Add all new files and remove all missing files from the
180 Add all new files and remove all missing files from the
181 repository.
181 repository.
182
182
183 New files are ignored if they match any of the patterns in
183 New files are ignored if they match any of the patterns in
184 ``.hgignore``. As with add, these changes take effect at the next
184 ``.hgignore``. As with add, these changes take effect at the next
185 commit.
185 commit.
186
186
187 Use the -s/--similarity option to detect renamed files. With a
187 Use the -s/--similarity option to detect renamed files. With a
188 parameter greater than 0, this compares every removed file with
188 parameter greater than 0, this compares every removed file with
189 every added file and records those similar enough as renames. This
189 every added file and records those similar enough as renames. This
190 option takes a percentage between 0 (disabled) and 100 (files must
190 option takes a percentage between 0 (disabled) and 100 (files must
191 be identical) as its parameter. Detecting renamed files this way
191 be identical) as its parameter. Detecting renamed files this way
192 can be expensive. After using this option, :hg:`status -C` can be
192 can be expensive. After using this option, :hg:`status -C` can be
193 used to check which files were identified as moved or renamed.
193 used to check which files were identified as moved or renamed.
194
194
195 Returns 0 if all files are successfully added.
195 Returns 0 if all files are successfully added.
196 """
196 """
197 try:
197 try:
198 sim = float(opts.get('similarity') or 100)
198 sim = float(opts.get('similarity') or 100)
199 except ValueError:
199 except ValueError:
200 raise util.Abort(_('similarity must be a number'))
200 raise util.Abort(_('similarity must be a number'))
201 if sim < 0 or sim > 100:
201 if sim < 0 or sim > 100:
202 raise util.Abort(_('similarity must be between 0 and 100'))
202 raise util.Abort(_('similarity must be between 0 and 100'))
203 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
203 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
204
204
205 @command('^annotate|blame',
205 @command('^annotate|blame',
206 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
206 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
207 ('', 'follow', None,
207 ('', 'follow', None,
208 _('follow copies/renames and list the filename (DEPRECATED)')),
208 _('follow copies/renames and list the filename (DEPRECATED)')),
209 ('', 'no-follow', None, _("don't follow copies and renames")),
209 ('', 'no-follow', None, _("don't follow copies and renames")),
210 ('a', 'text', None, _('treat all files as text')),
210 ('a', 'text', None, _('treat all files as text')),
211 ('u', 'user', None, _('list the author (long with -v)')),
211 ('u', 'user', None, _('list the author (long with -v)')),
212 ('f', 'file', None, _('list the filename')),
212 ('f', 'file', None, _('list the filename')),
213 ('d', 'date', None, _('list the date (short with -q)')),
213 ('d', 'date', None, _('list the date (short with -q)')),
214 ('n', 'number', None, _('list the revision number (default)')),
214 ('n', 'number', None, _('list the revision number (default)')),
215 ('c', 'changeset', None, _('list the changeset')),
215 ('c', 'changeset', None, _('list the changeset')),
216 ('l', 'line-number', None, _('show line number at the first appearance'))
216 ('l', 'line-number', None, _('show line number at the first appearance'))
217 ] + walkopts,
217 ] + walkopts,
218 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
218 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
219 def annotate(ui, repo, *pats, **opts):
219 def annotate(ui, repo, *pats, **opts):
220 """show changeset information by line for each file
220 """show changeset information by line for each file
221
221
222 List changes in files, showing the revision id responsible for
222 List changes in files, showing the revision id responsible for
223 each line
223 each line
224
224
225 This command is useful for discovering when a change was made and
225 This command is useful for discovering when a change was made and
226 by whom.
226 by whom.
227
227
228 Without the -a/--text option, annotate will avoid processing files
228 Without the -a/--text option, annotate will avoid processing files
229 it detects as binary. With -a, annotate will annotate the file
229 it detects as binary. With -a, annotate will annotate the file
230 anyway, although the results will probably be neither useful
230 anyway, although the results will probably be neither useful
231 nor desirable.
231 nor desirable.
232
232
233 Returns 0 on success.
233 Returns 0 on success.
234 """
234 """
235 if opts.get('follow'):
235 if opts.get('follow'):
236 # --follow is deprecated and now just an alias for -f/--file
236 # --follow is deprecated and now just an alias for -f/--file
237 # to mimic the behavior of Mercurial before version 1.5
237 # to mimic the behavior of Mercurial before version 1.5
238 opts['file'] = True
238 opts['file'] = True
239
239
240 datefunc = ui.quiet and util.shortdate or util.datestr
240 datefunc = ui.quiet and util.shortdate or util.datestr
241 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
241 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
242
242
243 if not pats:
243 if not pats:
244 raise util.Abort(_('at least one filename or pattern is required'))
244 raise util.Abort(_('at least one filename or pattern is required'))
245
245
246 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
246 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
247 ('number', ' ', lambda x: str(x[0].rev())),
247 ('number', ' ', lambda x: str(x[0].rev())),
248 ('changeset', ' ', lambda x: short(x[0].node())),
248 ('changeset', ' ', lambda x: short(x[0].node())),
249 ('date', ' ', getdate),
249 ('date', ' ', getdate),
250 ('file', ' ', lambda x: x[0].path()),
250 ('file', ' ', lambda x: x[0].path()),
251 ('line_number', ':', lambda x: str(x[1])),
251 ('line_number', ':', lambda x: str(x[1])),
252 ]
252 ]
253
253
254 if (not opts.get('user') and not opts.get('changeset')
254 if (not opts.get('user') and not opts.get('changeset')
255 and not opts.get('date') and not opts.get('file')):
255 and not opts.get('date') and not opts.get('file')):
256 opts['number'] = True
256 opts['number'] = True
257
257
258 linenumber = opts.get('line_number') is not None
258 linenumber = opts.get('line_number') is not None
259 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
259 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
260 raise util.Abort(_('at least one of -n/-c is required for -l'))
260 raise util.Abort(_('at least one of -n/-c is required for -l'))
261
261
262 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
262 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
263 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
263 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
264
264
265 def bad(x, y):
265 def bad(x, y):
266 raise util.Abort("%s: %s" % (x, y))
266 raise util.Abort("%s: %s" % (x, y))
267
267
268 ctx = scmutil.revsingle(repo, opts.get('rev'))
268 ctx = scmutil.revsingle(repo, opts.get('rev'))
269 m = scmutil.match(ctx, pats, opts)
269 m = scmutil.match(ctx, pats, opts)
270 m.bad = bad
270 m.bad = bad
271 follow = not opts.get('no_follow')
271 follow = not opts.get('no_follow')
272 for abs in ctx.walk(m):
272 for abs in ctx.walk(m):
273 fctx = ctx[abs]
273 fctx = ctx[abs]
274 if not opts.get('text') and util.binary(fctx.data()):
274 if not opts.get('text') and util.binary(fctx.data()):
275 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
275 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
276 continue
276 continue
277
277
278 lines = fctx.annotate(follow=follow, linenumber=linenumber)
278 lines = fctx.annotate(follow=follow, linenumber=linenumber)
279 pieces = []
279 pieces = []
280
280
281 for f, sep in funcmap:
281 for f, sep in funcmap:
282 l = [f(n) for n, dummy in lines]
282 l = [f(n) for n, dummy in lines]
283 if l:
283 if l:
284 sized = [(x, encoding.colwidth(x)) for x in l]
284 sized = [(x, encoding.colwidth(x)) for x in l]
285 ml = max([w for x, w in sized])
285 ml = max([w for x, w in sized])
286 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
286 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
287 for x, w in sized])
287 for x, w in sized])
288
288
289 if pieces:
289 if pieces:
290 for p, l in zip(zip(*pieces), lines):
290 for p, l in zip(zip(*pieces), lines):
291 ui.write("%s: %s" % ("".join(p), l[1]))
291 ui.write("%s: %s" % ("".join(p), l[1]))
292
292
293 @command('archive',
293 @command('archive',
294 [('', 'no-decode', None, _('do not pass files through decoders')),
294 [('', 'no-decode', None, _('do not pass files through decoders')),
295 ('p', 'prefix', '', _('directory prefix for files in archive'),
295 ('p', 'prefix', '', _('directory prefix for files in archive'),
296 _('PREFIX')),
296 _('PREFIX')),
297 ('r', 'rev', '', _('revision to distribute'), _('REV')),
297 ('r', 'rev', '', _('revision to distribute'), _('REV')),
298 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
298 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
299 ] + subrepoopts + walkopts,
299 ] + subrepoopts + walkopts,
300 _('[OPTION]... DEST'))
300 _('[OPTION]... DEST'))
301 def archive(ui, repo, dest, **opts):
301 def archive(ui, repo, dest, **opts):
302 '''create an unversioned archive of a repository revision
302 '''create an unversioned archive of a repository revision
303
303
304 By default, the revision used is the parent of the working
304 By default, the revision used is the parent of the working
305 directory; use -r/--rev to specify a different revision.
305 directory; use -r/--rev to specify a different revision.
306
306
307 The archive type is automatically detected based on file
307 The archive type is automatically detected based on file
308 extension (or override using -t/--type).
308 extension (or override using -t/--type).
309
309
310 .. container:: verbose
310 .. container:: verbose
311
311
312 Examples:
312 Examples:
313
313
314 - create a zip file containing the 1.0 release::
314 - create a zip file containing the 1.0 release::
315
315
316 hg archive -r 1.0 project-1.0.zip
316 hg archive -r 1.0 project-1.0.zip
317
317
318 - create a tarball excluding .hg files::
318 - create a tarball excluding .hg files::
319
319
320 hg archive project.tar.gz -X ".hg*"
320 hg archive project.tar.gz -X ".hg*"
321
321
322 Valid types are:
322 Valid types are:
323
323
324 :``files``: a directory full of files (default)
324 :``files``: a directory full of files (default)
325 :``tar``: tar archive, uncompressed
325 :``tar``: tar archive, uncompressed
326 :``tbz2``: tar archive, compressed using bzip2
326 :``tbz2``: tar archive, compressed using bzip2
327 :``tgz``: tar archive, compressed using gzip
327 :``tgz``: tar archive, compressed using gzip
328 :``uzip``: zip archive, uncompressed
328 :``uzip``: zip archive, uncompressed
329 :``zip``: zip archive, compressed using deflate
329 :``zip``: zip archive, compressed using deflate
330
330
331 The exact name of the destination archive or directory is given
331 The exact name of the destination archive or directory is given
332 using a format string; see :hg:`help export` for details.
332 using a format string; see :hg:`help export` for details.
333
333
334 Each member added to an archive file has a directory prefix
334 Each member added to an archive file has a directory prefix
335 prepended. Use -p/--prefix to specify a format string for the
335 prepended. Use -p/--prefix to specify a format string for the
336 prefix. The default is the basename of the archive, with suffixes
336 prefix. The default is the basename of the archive, with suffixes
337 removed.
337 removed.
338
338
339 Returns 0 on success.
339 Returns 0 on success.
340 '''
340 '''
341
341
342 ctx = scmutil.revsingle(repo, opts.get('rev'))
342 ctx = scmutil.revsingle(repo, opts.get('rev'))
343 if not ctx:
343 if not ctx:
344 raise util.Abort(_('no working directory: please specify a revision'))
344 raise util.Abort(_('no working directory: please specify a revision'))
345 node = ctx.node()
345 node = ctx.node()
346 dest = cmdutil.makefilename(repo, dest, node)
346 dest = cmdutil.makefilename(repo, dest, node)
347 if os.path.realpath(dest) == repo.root:
347 if os.path.realpath(dest) == repo.root:
348 raise util.Abort(_('repository root cannot be destination'))
348 raise util.Abort(_('repository root cannot be destination'))
349
349
350 kind = opts.get('type') or archival.guesskind(dest) or 'files'
350 kind = opts.get('type') or archival.guesskind(dest) or 'files'
351 prefix = opts.get('prefix')
351 prefix = opts.get('prefix')
352
352
353 if dest == '-':
353 if dest == '-':
354 if kind == 'files':
354 if kind == 'files':
355 raise util.Abort(_('cannot archive plain files to stdout'))
355 raise util.Abort(_('cannot archive plain files to stdout'))
356 dest = cmdutil.makefileobj(repo, dest)
356 dest = cmdutil.makefileobj(repo, dest)
357 if not prefix:
357 if not prefix:
358 prefix = os.path.basename(repo.root) + '-%h'
358 prefix = os.path.basename(repo.root) + '-%h'
359
359
360 prefix = cmdutil.makefilename(repo, prefix, node)
360 prefix = cmdutil.makefilename(repo, prefix, node)
361 matchfn = scmutil.match(ctx, [], opts)
361 matchfn = scmutil.match(ctx, [], opts)
362 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
362 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
363 matchfn, prefix, subrepos=opts.get('subrepos'))
363 matchfn, prefix, subrepos=opts.get('subrepos'))
364
364
365 @command('backout',
365 @command('backout',
366 [('', 'merge', None, _('merge with old dirstate parent after backout')),
366 [('', 'merge', None, _('merge with old dirstate parent after backout')),
367 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
367 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
368 ('r', 'rev', '', _('revision to backout'), _('REV')),
368 ('r', 'rev', '', _('revision to backout'), _('REV')),
369 ] + mergetoolopts + walkopts + commitopts + commitopts2,
369 ] + mergetoolopts + walkopts + commitopts + commitopts2,
370 _('[OPTION]... [-r] REV'))
370 _('[OPTION]... [-r] REV'))
371 def backout(ui, repo, node=None, rev=None, **opts):
371 def backout(ui, repo, node=None, rev=None, **opts):
372 '''reverse effect of earlier changeset
372 '''reverse effect of earlier changeset
373
373
374 Prepare a new changeset with the effect of REV undone in the
374 Prepare a new changeset with the effect of REV undone in the
375 current working directory.
375 current working directory.
376
376
377 If REV is the parent of the working directory, then this new changeset
377 If REV is the parent of the working directory, then this new changeset
378 is committed automatically. Otherwise, hg needs to merge the
378 is committed automatically. Otherwise, hg needs to merge the
379 changes and the merged result is left uncommitted.
379 changes and the merged result is left uncommitted.
380
380
381 By default, the pending changeset will have one parent,
381 By default, the pending changeset will have one parent,
382 maintaining a linear history. With --merge, the pending changeset
382 maintaining a linear history. With --merge, the pending changeset
383 will instead have two parents: the old parent of the working
383 will instead have two parents: the old parent of the working
384 directory and a new child of REV that simply undoes REV.
384 directory and a new child of REV that simply undoes REV.
385
385
386 Before version 1.7, the behavior without --merge was equivalent to
386 Before version 1.7, the behavior without --merge was equivalent to
387 specifying --merge followed by :hg:`update --clean .` to cancel
387 specifying --merge followed by :hg:`update --clean .` to cancel
388 the merge and leave the child of REV as a head to be merged
388 the merge and leave the child of REV as a head to be merged
389 separately.
389 separately.
390
390
391 See :hg:`help dates` for a list of formats valid for -d/--date.
391 See :hg:`help dates` for a list of formats valid for -d/--date.
392
392
393 Returns 0 on success.
393 Returns 0 on success.
394 '''
394 '''
395 if rev and node:
395 if rev and node:
396 raise util.Abort(_("please specify just one revision"))
396 raise util.Abort(_("please specify just one revision"))
397
397
398 if not rev:
398 if not rev:
399 rev = node
399 rev = node
400
400
401 if not rev:
401 if not rev:
402 raise util.Abort(_("please specify a revision to backout"))
402 raise util.Abort(_("please specify a revision to backout"))
403
403
404 date = opts.get('date')
404 date = opts.get('date')
405 if date:
405 if date:
406 opts['date'] = util.parsedate(date)
406 opts['date'] = util.parsedate(date)
407
407
408 cmdutil.bailifchanged(repo)
408 cmdutil.bailifchanged(repo)
409 node = scmutil.revsingle(repo, rev).node()
409 node = scmutil.revsingle(repo, rev).node()
410
410
411 op1, op2 = repo.dirstate.parents()
411 op1, op2 = repo.dirstate.parents()
412 a = repo.changelog.ancestor(op1, node)
412 a = repo.changelog.ancestor(op1, node)
413 if a != node:
413 if a != node:
414 raise util.Abort(_('cannot backout change on a different branch'))
414 raise util.Abort(_('cannot backout change on a different branch'))
415
415
416 p1, p2 = repo.changelog.parents(node)
416 p1, p2 = repo.changelog.parents(node)
417 if p1 == nullid:
417 if p1 == nullid:
418 raise util.Abort(_('cannot backout a change with no parents'))
418 raise util.Abort(_('cannot backout a change with no parents'))
419 if p2 != nullid:
419 if p2 != nullid:
420 if not opts.get('parent'):
420 if not opts.get('parent'):
421 raise util.Abort(_('cannot backout a merge changeset without '
421 raise util.Abort(_('cannot backout a merge changeset without '
422 '--parent'))
422 '--parent'))
423 p = repo.lookup(opts['parent'])
423 p = repo.lookup(opts['parent'])
424 if p not in (p1, p2):
424 if p not in (p1, p2):
425 raise util.Abort(_('%s is not a parent of %s') %
425 raise util.Abort(_('%s is not a parent of %s') %
426 (short(p), short(node)))
426 (short(p), short(node)))
427 parent = p
427 parent = p
428 else:
428 else:
429 if opts.get('parent'):
429 if opts.get('parent'):
430 raise util.Abort(_('cannot use --parent on non-merge changeset'))
430 raise util.Abort(_('cannot use --parent on non-merge changeset'))
431 parent = p1
431 parent = p1
432
432
433 # the backout should appear on the same branch
433 # the backout should appear on the same branch
434 branch = repo.dirstate.branch()
434 branch = repo.dirstate.branch()
435 hg.clean(repo, node, show_stats=False)
435 hg.clean(repo, node, show_stats=False)
436 repo.dirstate.setbranch(branch)
436 repo.dirstate.setbranch(branch)
437 revert_opts = opts.copy()
437 revert_opts = opts.copy()
438 revert_opts['date'] = None
438 revert_opts['date'] = None
439 revert_opts['all'] = True
439 revert_opts['all'] = True
440 revert_opts['rev'] = hex(parent)
440 revert_opts['rev'] = hex(parent)
441 revert_opts['no_backup'] = None
441 revert_opts['no_backup'] = None
442 revert(ui, repo, **revert_opts)
442 revert(ui, repo, **revert_opts)
443 if not opts.get('merge') and op1 != node:
443 if not opts.get('merge') and op1 != node:
444 try:
444 try:
445 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
445 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
446 return hg.update(repo, op1)
446 return hg.update(repo, op1)
447 finally:
447 finally:
448 ui.setconfig('ui', 'forcemerge', '')
448 ui.setconfig('ui', 'forcemerge', '')
449
449
450 commit_opts = opts.copy()
450 commit_opts = opts.copy()
451 commit_opts['addremove'] = False
451 commit_opts['addremove'] = False
452 if not commit_opts['message'] and not commit_opts['logfile']:
452 if not commit_opts['message'] and not commit_opts['logfile']:
453 # we don't translate commit messages
453 # we don't translate commit messages
454 commit_opts['message'] = "Backed out changeset %s" % short(node)
454 commit_opts['message'] = "Backed out changeset %s" % short(node)
455 commit_opts['force_editor'] = True
455 commit_opts['force_editor'] = True
456 commit(ui, repo, **commit_opts)
456 commit(ui, repo, **commit_opts)
457 def nice(node):
457 def nice(node):
458 return '%d:%s' % (repo.changelog.rev(node), short(node))
458 return '%d:%s' % (repo.changelog.rev(node), short(node))
459 ui.status(_('changeset %s backs out changeset %s\n') %
459 ui.status(_('changeset %s backs out changeset %s\n') %
460 (nice(repo.changelog.tip()), nice(node)))
460 (nice(repo.changelog.tip()), nice(node)))
461 if opts.get('merge') and op1 != node:
461 if opts.get('merge') and op1 != node:
462 hg.clean(repo, op1, show_stats=False)
462 hg.clean(repo, op1, show_stats=False)
463 ui.status(_('merging with changeset %s\n')
463 ui.status(_('merging with changeset %s\n')
464 % nice(repo.changelog.tip()))
464 % nice(repo.changelog.tip()))
465 try:
465 try:
466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
467 return hg.merge(repo, hex(repo.changelog.tip()))
467 return hg.merge(repo, hex(repo.changelog.tip()))
468 finally:
468 finally:
469 ui.setconfig('ui', 'forcemerge', '')
469 ui.setconfig('ui', 'forcemerge', '')
470 return 0
470 return 0
471
471
472 @command('bisect',
472 @command('bisect',
473 [('r', 'reset', False, _('reset bisect state')),
473 [('r', 'reset', False, _('reset bisect state')),
474 ('g', 'good', False, _('mark changeset good')),
474 ('g', 'good', False, _('mark changeset good')),
475 ('b', 'bad', False, _('mark changeset bad')),
475 ('b', 'bad', False, _('mark changeset bad')),
476 ('s', 'skip', False, _('skip testing changeset')),
476 ('s', 'skip', False, _('skip testing changeset')),
477 ('e', 'extend', False, _('extend the bisect range')),
477 ('e', 'extend', False, _('extend the bisect range')),
478 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
478 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
479 ('U', 'noupdate', False, _('do not update to target'))],
479 ('U', 'noupdate', False, _('do not update to target'))],
480 _("[-gbsr] [-U] [-c CMD] [REV]"))
480 _("[-gbsr] [-U] [-c CMD] [REV]"))
481 def bisect(ui, repo, rev=None, extra=None, command=None,
481 def bisect(ui, repo, rev=None, extra=None, command=None,
482 reset=None, good=None, bad=None, skip=None, extend=None,
482 reset=None, good=None, bad=None, skip=None, extend=None,
483 noupdate=None):
483 noupdate=None):
484 """subdivision search of changesets
484 """subdivision search of changesets
485
485
486 This command helps to find changesets which introduce problems. To
486 This command helps to find changesets which introduce problems. To
487 use, mark the earliest changeset you know exhibits the problem as
487 use, mark the earliest changeset you know exhibits the problem as
488 bad, then mark the latest changeset which is free from the problem
488 bad, then mark the latest changeset which is free from the problem
489 as good. Bisect will update your working directory to a revision
489 as good. Bisect will update your working directory to a revision
490 for testing (unless the -U/--noupdate option is specified). Once
490 for testing (unless the -U/--noupdate option is specified). Once
491 you have performed tests, mark the working directory as good or
491 you have performed tests, mark the working directory as good or
492 bad, and bisect will either update to another candidate changeset
492 bad, and bisect will either update to another candidate changeset
493 or announce that it has found the bad revision.
493 or announce that it has found the bad revision.
494
494
495 As a shortcut, you can also use the revision argument to mark a
495 As a shortcut, you can also use the revision argument to mark a
496 revision as good or bad without checking it out first.
496 revision as good or bad without checking it out first.
497
497
498 If you supply a command, it will be used for automatic bisection.
498 If you supply a command, it will be used for automatic bisection.
499 Its exit status will be used to mark revisions as good or bad:
499 Its exit status will be used to mark revisions as good or bad:
500 status 0 means good, 125 means to skip the revision, 127
500 status 0 means good, 125 means to skip the revision, 127
501 (command not found) will abort the bisection, and any other
501 (command not found) will abort the bisection, and any other
502 non-zero exit status means the revision is bad.
502 non-zero exit status means the revision is bad.
503
503
504 Returns 0 on success.
504 Returns 0 on success.
505 """
505 """
506 def extendbisectrange(nodes, good):
506 def extendbisectrange(nodes, good):
507 # bisect is incomplete when it ends on a merge node and
507 # bisect is incomplete when it ends on a merge node and
508 # one of the parent was not checked.
508 # one of the parent was not checked.
509 parents = repo[nodes[0]].parents()
509 parents = repo[nodes[0]].parents()
510 if len(parents) > 1:
510 if len(parents) > 1:
511 side = good and state['bad'] or state['good']
511 side = good and state['bad'] or state['good']
512 num = len(set(i.node() for i in parents) & set(side))
512 num = len(set(i.node() for i in parents) & set(side))
513 if num == 1:
513 if num == 1:
514 return parents[0].ancestor(parents[1])
514 return parents[0].ancestor(parents[1])
515 return None
515 return None
516
516
517 def print_result(nodes, good):
517 def print_result(nodes, good):
518 displayer = cmdutil.show_changeset(ui, repo, {})
518 displayer = cmdutil.show_changeset(ui, repo, {})
519 if len(nodes) == 1:
519 if len(nodes) == 1:
520 # narrowed it down to a single revision
520 # narrowed it down to a single revision
521 if good:
521 if good:
522 ui.write(_("The first good revision is:\n"))
522 ui.write(_("The first good revision is:\n"))
523 else:
523 else:
524 ui.write(_("The first bad revision is:\n"))
524 ui.write(_("The first bad revision is:\n"))
525 displayer.show(repo[nodes[0]])
525 displayer.show(repo[nodes[0]])
526 extendnode = extendbisectrange(nodes, good)
526 extendnode = extendbisectrange(nodes, good)
527 if extendnode is not None:
527 if extendnode is not None:
528 ui.write(_('Not all ancestors of this changeset have been'
528 ui.write(_('Not all ancestors of this changeset have been'
529 ' checked.\nUse bisect --extend to continue the '
529 ' checked.\nUse bisect --extend to continue the '
530 'bisection from\nthe common ancestor, %s.\n')
530 'bisection from\nthe common ancestor, %s.\n')
531 % extendnode)
531 % extendnode)
532 else:
532 else:
533 # multiple possible revisions
533 # multiple possible revisions
534 if good:
534 if good:
535 ui.write(_("Due to skipped revisions, the first "
535 ui.write(_("Due to skipped revisions, the first "
536 "good revision could be any of:\n"))
536 "good revision could be any of:\n"))
537 else:
537 else:
538 ui.write(_("Due to skipped revisions, the first "
538 ui.write(_("Due to skipped revisions, the first "
539 "bad revision could be any of:\n"))
539 "bad revision could be any of:\n"))
540 for n in nodes:
540 for n in nodes:
541 displayer.show(repo[n])
541 displayer.show(repo[n])
542 displayer.close()
542 displayer.close()
543
543
544 def check_state(state, interactive=True):
544 def check_state(state, interactive=True):
545 if not state['good'] or not state['bad']:
545 if not state['good'] or not state['bad']:
546 if (good or bad or skip or reset) and interactive:
546 if (good or bad or skip or reset) and interactive:
547 return
547 return
548 if not state['good']:
548 if not state['good']:
549 raise util.Abort(_('cannot bisect (no known good revisions)'))
549 raise util.Abort(_('cannot bisect (no known good revisions)'))
550 else:
550 else:
551 raise util.Abort(_('cannot bisect (no known bad revisions)'))
551 raise util.Abort(_('cannot bisect (no known bad revisions)'))
552 return True
552 return True
553
553
554 # backward compatibility
554 # backward compatibility
555 if rev in "good bad reset init".split():
555 if rev in "good bad reset init".split():
556 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
556 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
557 cmd, rev, extra = rev, extra, None
557 cmd, rev, extra = rev, extra, None
558 if cmd == "good":
558 if cmd == "good":
559 good = True
559 good = True
560 elif cmd == "bad":
560 elif cmd == "bad":
561 bad = True
561 bad = True
562 else:
562 else:
563 reset = True
563 reset = True
564 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
564 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
565 raise util.Abort(_('incompatible arguments'))
565 raise util.Abort(_('incompatible arguments'))
566
566
567 if reset:
567 if reset:
568 p = repo.join("bisect.state")
568 p = repo.join("bisect.state")
569 if os.path.exists(p):
569 if os.path.exists(p):
570 os.unlink(p)
570 os.unlink(p)
571 return
571 return
572
572
573 state = hbisect.load_state(repo)
573 state = hbisect.load_state(repo)
574
574
575 if command:
575 if command:
576 changesets = 1
576 changesets = 1
577 try:
577 try:
578 while changesets:
578 while changesets:
579 # update state
579 # update state
580 status = util.system(command, out=ui.fout)
580 status = util.system(command, out=ui.fout)
581 if status == 125:
581 if status == 125:
582 transition = "skip"
582 transition = "skip"
583 elif status == 0:
583 elif status == 0:
584 transition = "good"
584 transition = "good"
585 # status < 0 means process was killed
585 # status < 0 means process was killed
586 elif status == 127:
586 elif status == 127:
587 raise util.Abort(_("failed to execute %s") % command)
587 raise util.Abort(_("failed to execute %s") % command)
588 elif status < 0:
588 elif status < 0:
589 raise util.Abort(_("%s killed") % command)
589 raise util.Abort(_("%s killed") % command)
590 else:
590 else:
591 transition = "bad"
591 transition = "bad"
592 ctx = scmutil.revsingle(repo, rev)
592 ctx = scmutil.revsingle(repo, rev)
593 rev = None # clear for future iterations
593 rev = None # clear for future iterations
594 state[transition].append(ctx.node())
594 state[transition].append(ctx.node())
595 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
595 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
596 check_state(state, interactive=False)
596 check_state(state, interactive=False)
597 # bisect
597 # bisect
598 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
598 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
599 # update to next check
599 # update to next check
600 cmdutil.bailifchanged(repo)
600 cmdutil.bailifchanged(repo)
601 hg.clean(repo, nodes[0], show_stats=False)
601 hg.clean(repo, nodes[0], show_stats=False)
602 finally:
602 finally:
603 hbisect.save_state(repo, state)
603 hbisect.save_state(repo, state)
604 print_result(nodes, good)
604 print_result(nodes, good)
605 return
605 return
606
606
607 # update state
607 # update state
608
608
609 if rev:
609 if rev:
610 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
610 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
611 else:
611 else:
612 nodes = [repo.lookup('.')]
612 nodes = [repo.lookup('.')]
613
613
614 if good or bad or skip:
614 if good or bad or skip:
615 if good:
615 if good:
616 state['good'] += nodes
616 state['good'] += nodes
617 elif bad:
617 elif bad:
618 state['bad'] += nodes
618 state['bad'] += nodes
619 elif skip:
619 elif skip:
620 state['skip'] += nodes
620 state['skip'] += nodes
621 hbisect.save_state(repo, state)
621 hbisect.save_state(repo, state)
622
622
623 if not check_state(state):
623 if not check_state(state):
624 return
624 return
625
625
626 # actually bisect
626 # actually bisect
627 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
627 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
628 if extend:
628 if extend:
629 if not changesets:
629 if not changesets:
630 extendnode = extendbisectrange(nodes, good)
630 extendnode = extendbisectrange(nodes, good)
631 if extendnode is not None:
631 if extendnode is not None:
632 ui.write(_("Extending search to changeset %d:%s\n"
632 ui.write(_("Extending search to changeset %d:%s\n"
633 % (extendnode.rev(), extendnode)))
633 % (extendnode.rev(), extendnode)))
634 if noupdate:
634 if noupdate:
635 return
635 return
636 cmdutil.bailifchanged(repo)
636 cmdutil.bailifchanged(repo)
637 return hg.clean(repo, extendnode.node())
637 return hg.clean(repo, extendnode.node())
638 raise util.Abort(_("nothing to extend"))
638 raise util.Abort(_("nothing to extend"))
639
639
640 if changesets == 0:
640 if changesets == 0:
641 print_result(nodes, good)
641 print_result(nodes, good)
642 else:
642 else:
643 assert len(nodes) == 1 # only a single node can be tested next
643 assert len(nodes) == 1 # only a single node can be tested next
644 node = nodes[0]
644 node = nodes[0]
645 # compute the approximate number of remaining tests
645 # compute the approximate number of remaining tests
646 tests, size = 0, 2
646 tests, size = 0, 2
647 while size <= changesets:
647 while size <= changesets:
648 tests, size = tests + 1, size * 2
648 tests, size = tests + 1, size * 2
649 rev = repo.changelog.rev(node)
649 rev = repo.changelog.rev(node)
650 ui.write(_("Testing changeset %d:%s "
650 ui.write(_("Testing changeset %d:%s "
651 "(%d changesets remaining, ~%d tests)\n")
651 "(%d changesets remaining, ~%d tests)\n")
652 % (rev, short(node), changesets, tests))
652 % (rev, short(node), changesets, tests))
653 if not noupdate:
653 if not noupdate:
654 cmdutil.bailifchanged(repo)
654 cmdutil.bailifchanged(repo)
655 return hg.clean(repo, node)
655 return hg.clean(repo, node)
656
656
657 @command('bookmarks',
657 @command('bookmarks',
658 [('f', 'force', False, _('force')),
658 [('f', 'force', False, _('force')),
659 ('r', 'rev', '', _('revision'), _('REV')),
659 ('r', 'rev', '', _('revision'), _('REV')),
660 ('d', 'delete', False, _('delete a given bookmark')),
660 ('d', 'delete', False, _('delete a given bookmark')),
661 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
661 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
662 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
662 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
663 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
663 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
664 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
664 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
665 rename=None, inactive=False):
665 rename=None, inactive=False):
666 '''track a line of development with movable markers
666 '''track a line of development with movable markers
667
667
668 Bookmarks are pointers to certain commits that move when
668 Bookmarks are pointers to certain commits that move when
669 committing. Bookmarks are local. They can be renamed, copied and
669 committing. Bookmarks are local. They can be renamed, copied and
670 deleted. It is possible to use bookmark names in :hg:`merge` and
670 deleted. It is possible to use bookmark names in :hg:`merge` and
671 :hg:`update` to merge and update respectively to a given bookmark.
671 :hg:`update` to merge and update respectively to a given bookmark.
672
672
673 You can use :hg:`bookmark NAME` to set a bookmark on the working
673 You can use :hg:`bookmark NAME` to set a bookmark on the working
674 directory's parent revision with the given name. If you specify
674 directory's parent revision with the given name. If you specify
675 a revision using -r REV (where REV may be an existing bookmark),
675 a revision using -r REV (where REV may be an existing bookmark),
676 the bookmark is assigned to that revision.
676 the bookmark is assigned to that revision.
677
677
678 Bookmarks can be pushed and pulled between repositories (see :hg:`help
678 Bookmarks can be pushed and pulled between repositories (see :hg:`help
679 push` and :hg:`help pull`). This requires both the local and remote
679 push` and :hg:`help pull`). This requires both the local and remote
680 repositories to support bookmarks. For versions prior to 1.8, this means
680 repositories to support bookmarks. For versions prior to 1.8, this means
681 the bookmarks extension must be enabled.
681 the bookmarks extension must be enabled.
682 '''
682 '''
683 hexfn = ui.debugflag and hex or short
683 hexfn = ui.debugflag and hex or short
684 marks = repo._bookmarks
684 marks = repo._bookmarks
685 cur = repo.changectx('.').node()
685 cur = repo.changectx('.').node()
686
686
687 if rename:
687 if rename:
688 if rename not in marks:
688 if rename not in marks:
689 raise util.Abort(_("bookmark '%s' does not exist") % rename)
689 raise util.Abort(_("bookmark '%s' does not exist") % rename)
690 if mark in marks and not force:
690 if mark in marks and not force:
691 raise util.Abort(_("bookmark '%s' already exists "
691 raise util.Abort(_("bookmark '%s' already exists "
692 "(use -f to force)") % mark)
692 "(use -f to force)") % mark)
693 if mark is None:
693 if mark is None:
694 raise util.Abort(_("new bookmark name required"))
694 raise util.Abort(_("new bookmark name required"))
695 marks[mark] = marks[rename]
695 marks[mark] = marks[rename]
696 if repo._bookmarkcurrent == rename and not inactive:
696 if repo._bookmarkcurrent == rename and not inactive:
697 bookmarks.setcurrent(repo, mark)
697 bookmarks.setcurrent(repo, mark)
698 del marks[rename]
698 del marks[rename]
699 bookmarks.write(repo)
699 bookmarks.write(repo)
700 return
700 return
701
701
702 if delete:
702 if delete:
703 if mark is None:
703 if mark is None:
704 raise util.Abort(_("bookmark name required"))
704 raise util.Abort(_("bookmark name required"))
705 if mark not in marks:
705 if mark not in marks:
706 raise util.Abort(_("bookmark '%s' does not exist") % mark)
706 raise util.Abort(_("bookmark '%s' does not exist") % mark)
707 if mark == repo._bookmarkcurrent:
707 if mark == repo._bookmarkcurrent:
708 bookmarks.setcurrent(repo, None)
708 bookmarks.setcurrent(repo, None)
709 del marks[mark]
709 del marks[mark]
710 bookmarks.write(repo)
710 bookmarks.write(repo)
711 return
711 return
712
712
713 if mark is not None:
713 if mark is not None:
714 if "\n" in mark:
714 if "\n" in mark:
715 raise util.Abort(_("bookmark name cannot contain newlines"))
715 raise util.Abort(_("bookmark name cannot contain newlines"))
716 mark = mark.strip()
716 mark = mark.strip()
717 if not mark:
717 if not mark:
718 raise util.Abort(_("bookmark names cannot consist entirely of "
718 raise util.Abort(_("bookmark names cannot consist entirely of "
719 "whitespace"))
719 "whitespace"))
720 if inactive and mark == repo._bookmarkcurrent:
720 if inactive and mark == repo._bookmarkcurrent:
721 bookmarks.setcurrent(repo, None)
721 bookmarks.setcurrent(repo, None)
722 return
722 return
723 if mark in marks and not force:
723 if mark in marks and not force:
724 raise util.Abort(_("bookmark '%s' already exists "
724 raise util.Abort(_("bookmark '%s' already exists "
725 "(use -f to force)") % mark)
725 "(use -f to force)") % mark)
726 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
726 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
727 and not force):
727 and not force):
728 raise util.Abort(
728 raise util.Abort(
729 _("a bookmark cannot have the name of an existing branch"))
729 _("a bookmark cannot have the name of an existing branch"))
730 if rev:
730 if rev:
731 marks[mark] = repo.lookup(rev)
731 marks[mark] = repo.lookup(rev)
732 else:
732 else:
733 marks[mark] = repo.changectx('.').node()
733 marks[mark] = repo.changectx('.').node()
734 if not inactive and repo.changectx('.').node() == marks[mark]:
734 if not inactive and repo.changectx('.').node() == marks[mark]:
735 bookmarks.setcurrent(repo, mark)
735 bookmarks.setcurrent(repo, mark)
736 bookmarks.write(repo)
736 bookmarks.write(repo)
737 return
737 return
738
738
739 if mark is None:
739 if mark is None:
740 if rev:
740 if rev:
741 raise util.Abort(_("bookmark name required"))
741 raise util.Abort(_("bookmark name required"))
742 if len(marks) == 0:
742 if len(marks) == 0:
743 ui.status(_("no bookmarks set\n"))
743 ui.status(_("no bookmarks set\n"))
744 else:
744 else:
745 for bmark, n in sorted(marks.iteritems()):
745 for bmark, n in sorted(marks.iteritems()):
746 current = repo._bookmarkcurrent
746 current = repo._bookmarkcurrent
747 if bmark == current and n == cur:
747 if bmark == current and n == cur:
748 prefix, label = '*', 'bookmarks.current'
748 prefix, label = '*', 'bookmarks.current'
749 else:
749 else:
750 prefix, label = ' ', ''
750 prefix, label = ' ', ''
751
751
752 if ui.quiet:
752 if ui.quiet:
753 ui.write("%s\n" % bmark, label=label)
753 ui.write("%s\n" % bmark, label=label)
754 else:
754 else:
755 ui.write(" %s %-25s %d:%s\n" % (
755 ui.write(" %s %-25s %d:%s\n" % (
756 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
756 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
757 label=label)
757 label=label)
758 return
758 return
759
759
760 @command('branch',
760 @command('branch',
761 [('f', 'force', None,
761 [('f', 'force', None,
762 _('set branch name even if it shadows an existing branch')),
762 _('set branch name even if it shadows an existing branch')),
763 ('C', 'clean', None, _('reset branch name to parent branch name'))],
763 ('C', 'clean', None, _('reset branch name to parent branch name'))],
764 _('[-fC] [NAME]'))
764 _('[-fC] [NAME]'))
765 def branch(ui, repo, label=None, **opts):
765 def branch(ui, repo, label=None, **opts):
766 """set or show the current branch name
766 """set or show the current branch name
767
767
768 With no argument, show the current branch name. With one argument,
768 With no argument, show the current branch name. With one argument,
769 set the working directory branch name (the branch will not exist
769 set the working directory branch name (the branch will not exist
770 in the repository until the next commit). Standard practice
770 in the repository until the next commit). Standard practice
771 recommends that primary development take place on the 'default'
771 recommends that primary development take place on the 'default'
772 branch.
772 branch.
773
773
774 Unless -f/--force is specified, branch will not let you set a
774 Unless -f/--force is specified, branch will not let you set a
775 branch name that already exists, even if it's inactive.
775 branch name that already exists, even if it's inactive.
776
776
777 Use -C/--clean to reset the working directory branch to that of
777 Use -C/--clean to reset the working directory branch to that of
778 the parent of the working directory, negating a previous branch
778 the parent of the working directory, negating a previous branch
779 change.
779 change.
780
780
781 Use the command :hg:`update` to switch to an existing branch. Use
781 Use the command :hg:`update` to switch to an existing branch. Use
782 :hg:`commit --close-branch` to mark this branch as closed.
782 :hg:`commit --close-branch` to mark this branch as closed.
783
783
784 .. note::
784 .. note::
785
785
786 Branch names are permanent. Use :hg:`bookmark` to create a
786 Branch names are permanent. Use :hg:`bookmark` to create a
787 light-weight bookmark instead. See :hg:`help glossary` for more
787 light-weight bookmark instead. See :hg:`help glossary` for more
788 information about named branches and bookmarks.
788 information about named branches and bookmarks.
789
789
790 Returns 0 on success.
790 Returns 0 on success.
791 """
791 """
792
792
793 if opts.get('clean'):
793 if opts.get('clean'):
794 label = repo[None].p1().branch()
794 label = repo[None].p1().branch()
795 repo.dirstate.setbranch(label)
795 repo.dirstate.setbranch(label)
796 ui.status(_('reset working directory to branch %s\n') % label)
796 ui.status(_('reset working directory to branch %s\n') % label)
797 elif label:
797 elif label:
798 if not opts.get('force') and label in repo.branchtags():
798 if not opts.get('force') and label in repo.branchtags():
799 if label not in [p.branch() for p in repo.parents()]:
799 if label not in [p.branch() for p in repo.parents()]:
800 raise util.Abort(_('a branch of the same name already exists'),
800 raise util.Abort(_('a branch of the same name already exists'),
801 # i18n: "it" refers to an existing branch
801 # i18n: "it" refers to an existing branch
802 hint=_("use 'hg update' to switch to it"))
802 hint=_("use 'hg update' to switch to it"))
803 repo.dirstate.setbranch(label)
803 repo.dirstate.setbranch(label)
804 ui.status(_('marked working directory as branch %s\n') % label)
804 ui.status(_('marked working directory as branch %s\n') % label)
805 else:
805 else:
806 ui.write("%s\n" % repo.dirstate.branch())
806 ui.write("%s\n" % repo.dirstate.branch())
807
807
808 @command('branches',
808 @command('branches',
809 [('a', 'active', False, _('show only branches that have unmerged heads')),
809 [('a', 'active', False, _('show only branches that have unmerged heads')),
810 ('c', 'closed', False, _('show normal and closed branches'))],
810 ('c', 'closed', False, _('show normal and closed branches'))],
811 _('[-ac]'))
811 _('[-ac]'))
812 def branches(ui, repo, active=False, closed=False):
812 def branches(ui, repo, active=False, closed=False):
813 """list repository named branches
813 """list repository named branches
814
814
815 List the repository's named branches, indicating which ones are
815 List the repository's named branches, indicating which ones are
816 inactive. If -c/--closed is specified, also list branches which have
816 inactive. If -c/--closed is specified, also list branches which have
817 been marked closed (see :hg:`commit --close-branch`).
817 been marked closed (see :hg:`commit --close-branch`).
818
818
819 If -a/--active is specified, only show active branches. A branch
819 If -a/--active is specified, only show active branches. A branch
820 is considered active if it contains repository heads.
820 is considered active if it contains repository heads.
821
821
822 Use the command :hg:`update` to switch to an existing branch.
822 Use the command :hg:`update` to switch to an existing branch.
823
823
824 Returns 0.
824 Returns 0.
825 """
825 """
826
826
827 hexfunc = ui.debugflag and hex or short
827 hexfunc = ui.debugflag and hex or short
828 activebranches = [repo[n].branch() for n in repo.heads()]
828 activebranches = [repo[n].branch() for n in repo.heads()]
829 def testactive(tag, node):
829 def testactive(tag, node):
830 realhead = tag in activebranches
830 realhead = tag in activebranches
831 open = node in repo.branchheads(tag, closed=False)
831 open = node in repo.branchheads(tag, closed=False)
832 return realhead and open
832 return realhead and open
833 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
833 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
834 for tag, node in repo.branchtags().items()],
834 for tag, node in repo.branchtags().items()],
835 reverse=True)
835 reverse=True)
836
836
837 for isactive, node, tag in branches:
837 for isactive, node, tag in branches:
838 if (not active) or isactive:
838 if (not active) or isactive:
839 if ui.quiet:
839 if ui.quiet:
840 ui.write("%s\n" % tag)
840 ui.write("%s\n" % tag)
841 else:
841 else:
842 hn = repo.lookup(node)
842 hn = repo.lookup(node)
843 if isactive:
843 if isactive:
844 label = 'branches.active'
844 label = 'branches.active'
845 notice = ''
845 notice = ''
846 elif hn not in repo.branchheads(tag, closed=False):
846 elif hn not in repo.branchheads(tag, closed=False):
847 if not closed:
847 if not closed:
848 continue
848 continue
849 label = 'branches.closed'
849 label = 'branches.closed'
850 notice = _(' (closed)')
850 notice = _(' (closed)')
851 else:
851 else:
852 label = 'branches.inactive'
852 label = 'branches.inactive'
853 notice = _(' (inactive)')
853 notice = _(' (inactive)')
854 if tag == repo.dirstate.branch():
854 if tag == repo.dirstate.branch():
855 label = 'branches.current'
855 label = 'branches.current'
856 rev = str(node).rjust(31 - encoding.colwidth(tag))
856 rev = str(node).rjust(31 - encoding.colwidth(tag))
857 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
857 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
858 tag = ui.label(tag, label)
858 tag = ui.label(tag, label)
859 ui.write("%s %s%s\n" % (tag, rev, notice))
859 ui.write("%s %s%s\n" % (tag, rev, notice))
860
860
861 @command('bundle',
861 @command('bundle',
862 [('f', 'force', None, _('run even when the destination is unrelated')),
862 [('f', 'force', None, _('run even when the destination is unrelated')),
863 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
863 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
864 _('REV')),
864 _('REV')),
865 ('b', 'branch', [], _('a specific branch you would like to bundle'),
865 ('b', 'branch', [], _('a specific branch you would like to bundle'),
866 _('BRANCH')),
866 _('BRANCH')),
867 ('', 'base', [],
867 ('', 'base', [],
868 _('a base changeset assumed to be available at the destination'),
868 _('a base changeset assumed to be available at the destination'),
869 _('REV')),
869 _('REV')),
870 ('a', 'all', None, _('bundle all changesets in the repository')),
870 ('a', 'all', None, _('bundle all changesets in the repository')),
871 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
871 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
872 ] + remoteopts,
872 ] + remoteopts,
873 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
873 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
874 def bundle(ui, repo, fname, dest=None, **opts):
874 def bundle(ui, repo, fname, dest=None, **opts):
875 """create a changegroup file
875 """create a changegroup file
876
876
877 Generate a compressed changegroup file collecting changesets not
877 Generate a compressed changegroup file collecting changesets not
878 known to be in another repository.
878 known to be in another repository.
879
879
880 If you omit the destination repository, then hg assumes the
880 If you omit the destination repository, then hg assumes the
881 destination will have all the nodes you specify with --base
881 destination will have all the nodes you specify with --base
882 parameters. To create a bundle containing all changesets, use
882 parameters. To create a bundle containing all changesets, use
883 -a/--all (or --base null).
883 -a/--all (or --base null).
884
884
885 You can change compression method with the -t/--type option.
885 You can change compression method with the -t/--type option.
886 The available compression methods are: none, bzip2, and
886 The available compression methods are: none, bzip2, and
887 gzip (by default, bundles are compressed using bzip2).
887 gzip (by default, bundles are compressed using bzip2).
888
888
889 The bundle file can then be transferred using conventional means
889 The bundle file can then be transferred using conventional means
890 and applied to another repository with the unbundle or pull
890 and applied to another repository with the unbundle or pull
891 command. This is useful when direct push and pull are not
891 command. This is useful when direct push and pull are not
892 available or when exporting an entire repository is undesirable.
892 available or when exporting an entire repository is undesirable.
893
893
894 Applying bundles preserves all changeset contents including
894 Applying bundles preserves all changeset contents including
895 permissions, copy/rename information, and revision history.
895 permissions, copy/rename information, and revision history.
896
896
897 Returns 0 on success, 1 if no changes found.
897 Returns 0 on success, 1 if no changes found.
898 """
898 """
899 revs = None
899 revs = None
900 if 'rev' in opts:
900 if 'rev' in opts:
901 revs = scmutil.revrange(repo, opts['rev'])
901 revs = scmutil.revrange(repo, opts['rev'])
902
902
903 if opts.get('all'):
903 if opts.get('all'):
904 base = ['null']
904 base = ['null']
905 else:
905 else:
906 base = scmutil.revrange(repo, opts.get('base'))
906 base = scmutil.revrange(repo, opts.get('base'))
907 if base:
907 if base:
908 if dest:
908 if dest:
909 raise util.Abort(_("--base is incompatible with specifying "
909 raise util.Abort(_("--base is incompatible with specifying "
910 "a destination"))
910 "a destination"))
911 common = [repo.lookup(rev) for rev in base]
911 common = [repo.lookup(rev) for rev in base]
912 heads = revs and map(repo.lookup, revs) or revs
912 heads = revs and map(repo.lookup, revs) or revs
913 else:
913 else:
914 dest = ui.expandpath(dest or 'default-push', dest or 'default')
914 dest = ui.expandpath(dest or 'default-push', dest or 'default')
915 dest, branches = hg.parseurl(dest, opts.get('branch'))
915 dest, branches = hg.parseurl(dest, opts.get('branch'))
916 other = hg.peer(repo, opts, dest)
916 other = hg.peer(repo, opts, dest)
917 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
917 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
918 heads = revs and map(repo.lookup, revs) or revs
918 heads = revs and map(repo.lookup, revs) or revs
919 common, outheads = discovery.findcommonoutgoing(repo, other,
919 common, outheads = discovery.findcommonoutgoing(repo, other,
920 onlyheads=heads,
920 onlyheads=heads,
921 force=opts.get('force'))
921 force=opts.get('force'))
922
922
923 cg = repo.getbundle('bundle', common=common, heads=heads)
923 cg = repo.getbundle('bundle', common=common, heads=heads)
924 if not cg:
924 if not cg:
925 ui.status(_("no changes found\n"))
925 ui.status(_("no changes found\n"))
926 return 1
926 return 1
927
927
928 bundletype = opts.get('type', 'bzip2').lower()
928 bundletype = opts.get('type', 'bzip2').lower()
929 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
929 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
930 bundletype = btypes.get(bundletype)
930 bundletype = btypes.get(bundletype)
931 if bundletype not in changegroup.bundletypes:
931 if bundletype not in changegroup.bundletypes:
932 raise util.Abort(_('unknown bundle type specified with --type'))
932 raise util.Abort(_('unknown bundle type specified with --type'))
933
933
934 changegroup.writebundle(cg, fname, bundletype)
934 changegroup.writebundle(cg, fname, bundletype)
935
935
936 @command('cat',
936 @command('cat',
937 [('o', 'output', '',
937 [('o', 'output', '',
938 _('print output to file with formatted name'), _('FORMAT')),
938 _('print output to file with formatted name'), _('FORMAT')),
939 ('r', 'rev', '', _('print the given revision'), _('REV')),
939 ('r', 'rev', '', _('print the given revision'), _('REV')),
940 ('', 'decode', None, _('apply any matching decode filter')),
940 ('', 'decode', None, _('apply any matching decode filter')),
941 ] + walkopts,
941 ] + walkopts,
942 _('[OPTION]... FILE...'))
942 _('[OPTION]... FILE...'))
943 def cat(ui, repo, file1, *pats, **opts):
943 def cat(ui, repo, file1, *pats, **opts):
944 """output the current or given revision of files
944 """output the current or given revision of files
945
945
946 Print the specified files as they were at the given revision. If
946 Print the specified files as they were at the given revision. If
947 no revision is given, the parent of the working directory is used,
947 no revision is given, the parent of the working directory is used,
948 or tip if no revision is checked out.
948 or tip if no revision is checked out.
949
949
950 Output may be to a file, in which case the name of the file is
950 Output may be to a file, in which case the name of the file is
951 given using a format string. The formatting rules are the same as
951 given using a format string. The formatting rules are the same as
952 for the export command, with the following additions:
952 for the export command, with the following additions:
953
953
954 :``%s``: basename of file being printed
954 :``%s``: basename of file being printed
955 :``%d``: dirname of file being printed, or '.' if in repository root
955 :``%d``: dirname of file being printed, or '.' if in repository root
956 :``%p``: root-relative path name of file being printed
956 :``%p``: root-relative path name of file being printed
957
957
958 Returns 0 on success.
958 Returns 0 on success.
959 """
959 """
960 ctx = scmutil.revsingle(repo, opts.get('rev'))
960 ctx = scmutil.revsingle(repo, opts.get('rev'))
961 err = 1
961 err = 1
962 m = scmutil.match(ctx, (file1,) + pats, opts)
962 m = scmutil.match(ctx, (file1,) + pats, opts)
963 for abs in ctx.walk(m):
963 for abs in ctx.walk(m):
964 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
964 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
965 pathname=abs)
965 pathname=abs)
966 data = ctx[abs].data()
966 data = ctx[abs].data()
967 if opts.get('decode'):
967 if opts.get('decode'):
968 data = repo.wwritedata(abs, data)
968 data = repo.wwritedata(abs, data)
969 fp.write(data)
969 fp.write(data)
970 fp.close()
970 fp.close()
971 err = 0
971 err = 0
972 return err
972 return err
973
973
974 @command('^clone',
974 @command('^clone',
975 [('U', 'noupdate', None,
975 [('U', 'noupdate', None,
976 _('the clone will include an empty working copy (only a repository)')),
976 _('the clone will include an empty working copy (only a repository)')),
977 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
977 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
978 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
978 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
979 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
979 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
980 ('', 'pull', None, _('use pull protocol to copy metadata')),
980 ('', 'pull', None, _('use pull protocol to copy metadata')),
981 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
981 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
982 ] + remoteopts,
982 ] + remoteopts,
983 _('[OPTION]... SOURCE [DEST]'))
983 _('[OPTION]... SOURCE [DEST]'))
984 def clone(ui, source, dest=None, **opts):
984 def clone(ui, source, dest=None, **opts):
985 """make a copy of an existing repository
985 """make a copy of an existing repository
986
986
987 Create a copy of an existing repository in a new directory.
987 Create a copy of an existing repository in a new directory.
988
988
989 If no destination directory name is specified, it defaults to the
989 If no destination directory name is specified, it defaults to the
990 basename of the source.
990 basename of the source.
991
991
992 The location of the source is added to the new repository's
992 The location of the source is added to the new repository's
993 ``.hg/hgrc`` file, as the default to be used for future pulls.
993 ``.hg/hgrc`` file, as the default to be used for future pulls.
994
994
995 See :hg:`help urls` for valid source format details.
995 See :hg:`help urls` for valid source format details.
996
996
997 It is possible to specify an ``ssh://`` URL as the destination, but no
997 It is possible to specify an ``ssh://`` URL as the destination, but no
998 ``.hg/hgrc`` and working directory will be created on the remote side.
998 ``.hg/hgrc`` and working directory will be created on the remote side.
999 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
999 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
1000
1000
1001 A set of changesets (tags, or branch names) to pull may be specified
1001 A set of changesets (tags, or branch names) to pull may be specified
1002 by listing each changeset (tag, or branch name) with -r/--rev.
1002 by listing each changeset (tag, or branch name) with -r/--rev.
1003 If -r/--rev is used, the cloned repository will contain only a subset
1003 If -r/--rev is used, the cloned repository will contain only a subset
1004 of the changesets of the source repository. Only the set of changesets
1004 of the changesets of the source repository. Only the set of changesets
1005 defined by all -r/--rev options (including all their ancestors)
1005 defined by all -r/--rev options (including all their ancestors)
1006 will be pulled into the destination repository.
1006 will be pulled into the destination repository.
1007 No subsequent changesets (including subsequent tags) will be present
1007 No subsequent changesets (including subsequent tags) will be present
1008 in the destination.
1008 in the destination.
1009
1009
1010 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
1010 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
1011 local source repositories.
1011 local source repositories.
1012
1012
1013 For efficiency, hardlinks are used for cloning whenever the source
1013 For efficiency, hardlinks are used for cloning whenever the source
1014 and destination are on the same filesystem (note this applies only
1014 and destination are on the same filesystem (note this applies only
1015 to the repository data, not to the working directory). Some
1015 to the repository data, not to the working directory). Some
1016 filesystems, such as AFS, implement hardlinking incorrectly, but
1016 filesystems, such as AFS, implement hardlinking incorrectly, but
1017 do not report errors. In these cases, use the --pull option to
1017 do not report errors. In these cases, use the --pull option to
1018 avoid hardlinking.
1018 avoid hardlinking.
1019
1019
1020 In some cases, you can clone repositories and the working directory
1020 In some cases, you can clone repositories and the working directory
1021 using full hardlinks with ::
1021 using full hardlinks with ::
1022
1022
1023 $ cp -al REPO REPOCLONE
1023 $ cp -al REPO REPOCLONE
1024
1024
1025 This is the fastest way to clone, but it is not always safe. The
1025 This is the fastest way to clone, but it is not always safe. The
1026 operation is not atomic (making sure REPO is not modified during
1026 operation is not atomic (making sure REPO is not modified during
1027 the operation is up to you) and you have to make sure your editor
1027 the operation is up to you) and you have to make sure your editor
1028 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
1028 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
1029 this is not compatible with certain extensions that place their
1029 this is not compatible with certain extensions that place their
1030 metadata under the .hg directory, such as mq.
1030 metadata under the .hg directory, such as mq.
1031
1031
1032 Mercurial will update the working directory to the first applicable
1032 Mercurial will update the working directory to the first applicable
1033 revision from this list:
1033 revision from this list:
1034
1034
1035 a) null if -U or the source repository has no changesets
1035 a) null if -U or the source repository has no changesets
1036 b) if -u . and the source repository is local, the first parent of
1036 b) if -u . and the source repository is local, the first parent of
1037 the source repository's working directory
1037 the source repository's working directory
1038 c) the changeset specified with -u (if a branch name, this means the
1038 c) the changeset specified with -u (if a branch name, this means the
1039 latest head of that branch)
1039 latest head of that branch)
1040 d) the changeset specified with -r
1040 d) the changeset specified with -r
1041 e) the tipmost head specified with -b
1041 e) the tipmost head specified with -b
1042 f) the tipmost head specified with the url#branch source syntax
1042 f) the tipmost head specified with the url#branch source syntax
1043 g) the tipmost head of the default branch
1043 g) the tipmost head of the default branch
1044 h) tip
1044 h) tip
1045
1045
1046 Returns 0 on success.
1046 Returns 0 on success.
1047 """
1047 """
1048 if opts.get('noupdate') and opts.get('updaterev'):
1048 if opts.get('noupdate') and opts.get('updaterev'):
1049 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1049 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1050
1050
1051 r = hg.clone(ui, opts, source, dest,
1051 r = hg.clone(ui, opts, source, dest,
1052 pull=opts.get('pull'),
1052 pull=opts.get('pull'),
1053 stream=opts.get('uncompressed'),
1053 stream=opts.get('uncompressed'),
1054 rev=opts.get('rev'),
1054 rev=opts.get('rev'),
1055 update=opts.get('updaterev') or not opts.get('noupdate'),
1055 update=opts.get('updaterev') or not opts.get('noupdate'),
1056 branch=opts.get('branch'))
1056 branch=opts.get('branch'))
1057
1057
1058 return r is None
1058 return r is None
1059
1059
1060 @command('^commit|ci',
1060 @command('^commit|ci',
1061 [('A', 'addremove', None,
1061 [('A', 'addremove', None,
1062 _('mark new/missing files as added/removed before committing')),
1062 _('mark new/missing files as added/removed before committing')),
1063 ('', 'close-branch', None,
1063 ('', 'close-branch', None,
1064 _('mark a branch as closed, hiding it from the branch list')),
1064 _('mark a branch as closed, hiding it from the branch list')),
1065 ] + walkopts + commitopts + commitopts2,
1065 ] + walkopts + commitopts + commitopts2,
1066 _('[OPTION]... [FILE]...'))
1066 _('[OPTION]... [FILE]...'))
1067 def commit(ui, repo, *pats, **opts):
1067 def commit(ui, repo, *pats, **opts):
1068 """commit the specified files or all outstanding changes
1068 """commit the specified files or all outstanding changes
1069
1069
1070 Commit changes to the given files into the repository. Unlike a
1070 Commit changes to the given files into the repository. Unlike a
1071 centralized SCM, this operation is a local operation. See
1071 centralized SCM, this operation is a local operation. See
1072 :hg:`push` for a way to actively distribute your changes.
1072 :hg:`push` for a way to actively distribute your changes.
1073
1073
1074 If a list of files is omitted, all changes reported by :hg:`status`
1074 If a list of files is omitted, all changes reported by :hg:`status`
1075 will be committed.
1075 will be committed.
1076
1076
1077 If you are committing the result of a merge, do not provide any
1077 If you are committing the result of a merge, do not provide any
1078 filenames or -I/-X filters.
1078 filenames or -I/-X filters.
1079
1079
1080 If no commit message is specified, Mercurial starts your
1080 If no commit message is specified, Mercurial starts your
1081 configured editor where you can enter a message. In case your
1081 configured editor where you can enter a message. In case your
1082 commit fails, you will find a backup of your message in
1082 commit fails, you will find a backup of your message in
1083 ``.hg/last-message.txt``.
1083 ``.hg/last-message.txt``.
1084
1084
1085 See :hg:`help dates` for a list of formats valid for -d/--date.
1085 See :hg:`help dates` for a list of formats valid for -d/--date.
1086
1086
1087 Returns 0 on success, 1 if nothing changed.
1087 Returns 0 on success, 1 if nothing changed.
1088 """
1088 """
1089 extra = {}
1089 extra = {}
1090 if opts.get('close_branch'):
1090 if opts.get('close_branch'):
1091 if repo['.'].node() not in repo.branchheads():
1091 if repo['.'].node() not in repo.branchheads():
1092 # The topo heads set is included in the branch heads set of the
1092 # The topo heads set is included in the branch heads set of the
1093 # current branch, so it's sufficient to test branchheads
1093 # current branch, so it's sufficient to test branchheads
1094 raise util.Abort(_('can only close branch heads'))
1094 raise util.Abort(_('can only close branch heads'))
1095 extra['close'] = 1
1095 extra['close'] = 1
1096 e = cmdutil.commiteditor
1096 e = cmdutil.commiteditor
1097 if opts.get('force_editor'):
1097 if opts.get('force_editor'):
1098 e = cmdutil.commitforceeditor
1098 e = cmdutil.commitforceeditor
1099
1099
1100 def commitfunc(ui, repo, message, match, opts):
1100 def commitfunc(ui, repo, message, match, opts):
1101 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1101 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1102 editor=e, extra=extra)
1102 editor=e, extra=extra)
1103
1103
1104 branch = repo[None].branch()
1104 branch = repo[None].branch()
1105 bheads = repo.branchheads(branch)
1105 bheads = repo.branchheads(branch)
1106
1106
1107 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1107 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1108 if not node:
1108 if not node:
1109 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1109 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1110 if stat[3]:
1110 if stat[3]:
1111 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1111 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1112 % len(stat[3]))
1112 % len(stat[3]))
1113 else:
1113 else:
1114 ui.status(_("nothing changed\n"))
1114 ui.status(_("nothing changed\n"))
1115 return 1
1115 return 1
1116
1116
1117 ctx = repo[node]
1117 ctx = repo[node]
1118 parents = ctx.parents()
1118 parents = ctx.parents()
1119
1119
1120 if (bheads and node not in bheads and not
1120 if (bheads and node not in bheads and not
1121 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1121 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1122 ui.status(_('created new head\n'))
1122 ui.status(_('created new head\n'))
1123 # The message is not printed for initial roots. For the other
1123 # The message is not printed for initial roots. For the other
1124 # changesets, it is printed in the following situations:
1124 # changesets, it is printed in the following situations:
1125 #
1125 #
1126 # Par column: for the 2 parents with ...
1126 # Par column: for the 2 parents with ...
1127 # N: null or no parent
1127 # N: null or no parent
1128 # B: parent is on another named branch
1128 # B: parent is on another named branch
1129 # C: parent is a regular non head changeset
1129 # C: parent is a regular non head changeset
1130 # H: parent was a branch head of the current branch
1130 # H: parent was a branch head of the current branch
1131 # Msg column: whether we print "created new head" message
1131 # Msg column: whether we print "created new head" message
1132 # In the following, it is assumed that there already exists some
1132 # In the following, it is assumed that there already exists some
1133 # initial branch heads of the current branch, otherwise nothing is
1133 # initial branch heads of the current branch, otherwise nothing is
1134 # printed anyway.
1134 # printed anyway.
1135 #
1135 #
1136 # Par Msg Comment
1136 # Par Msg Comment
1137 # NN y additional topo root
1137 # NN y additional topo root
1138 #
1138 #
1139 # BN y additional branch root
1139 # BN y additional branch root
1140 # CN y additional topo head
1140 # CN y additional topo head
1141 # HN n usual case
1141 # HN n usual case
1142 #
1142 #
1143 # BB y weird additional branch root
1143 # BB y weird additional branch root
1144 # CB y branch merge
1144 # CB y branch merge
1145 # HB n merge with named branch
1145 # HB n merge with named branch
1146 #
1146 #
1147 # CC y additional head from merge
1147 # CC y additional head from merge
1148 # CH n merge with a head
1148 # CH n merge with a head
1149 #
1149 #
1150 # HH n head merge: head count decreases
1150 # HH n head merge: head count decreases
1151
1151
1152 if not opts.get('close_branch'):
1152 if not opts.get('close_branch'):
1153 for r in parents:
1153 for r in parents:
1154 if r.extra().get('close') and r.branch() == branch:
1154 if r.extra().get('close') and r.branch() == branch:
1155 ui.status(_('reopening closed branch head %d\n') % r)
1155 ui.status(_('reopening closed branch head %d\n') % r)
1156
1156
1157 if ui.debugflag:
1157 if ui.debugflag:
1158 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1158 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1159 elif ui.verbose:
1159 elif ui.verbose:
1160 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1160 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1161
1161
1162 @command('copy|cp',
1162 @command('copy|cp',
1163 [('A', 'after', None, _('record a copy that has already occurred')),
1163 [('A', 'after', None, _('record a copy that has already occurred')),
1164 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1164 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1165 ] + walkopts + dryrunopts,
1165 ] + walkopts + dryrunopts,
1166 _('[OPTION]... [SOURCE]... DEST'))
1166 _('[OPTION]... [SOURCE]... DEST'))
1167 def copy(ui, repo, *pats, **opts):
1167 def copy(ui, repo, *pats, **opts):
1168 """mark files as copied for the next commit
1168 """mark files as copied for the next commit
1169
1169
1170 Mark dest as having copies of source files. If dest is a
1170 Mark dest as having copies of source files. If dest is a
1171 directory, copies are put in that directory. If dest is a file,
1171 directory, copies are put in that directory. If dest is a file,
1172 the source must be a single file.
1172 the source must be a single file.
1173
1173
1174 By default, this command copies the contents of files as they
1174 By default, this command copies the contents of files as they
1175 exist in the working directory. If invoked with -A/--after, the
1175 exist in the working directory. If invoked with -A/--after, the
1176 operation is recorded, but no copying is performed.
1176 operation is recorded, but no copying is performed.
1177
1177
1178 This command takes effect with the next commit. To undo a copy
1178 This command takes effect with the next commit. To undo a copy
1179 before that, see :hg:`revert`.
1179 before that, see :hg:`revert`.
1180
1180
1181 Returns 0 on success, 1 if errors are encountered.
1181 Returns 0 on success, 1 if errors are encountered.
1182 """
1182 """
1183 wlock = repo.wlock(False)
1183 wlock = repo.wlock(False)
1184 try:
1184 try:
1185 return cmdutil.copy(ui, repo, pats, opts)
1185 return cmdutil.copy(ui, repo, pats, opts)
1186 finally:
1186 finally:
1187 wlock.release()
1187 wlock.release()
1188
1188
1189 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1189 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1190 def debugancestor(ui, repo, *args):
1190 def debugancestor(ui, repo, *args):
1191 """find the ancestor revision of two revisions in a given index"""
1191 """find the ancestor revision of two revisions in a given index"""
1192 if len(args) == 3:
1192 if len(args) == 3:
1193 index, rev1, rev2 = args
1193 index, rev1, rev2 = args
1194 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1194 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1195 lookup = r.lookup
1195 lookup = r.lookup
1196 elif len(args) == 2:
1196 elif len(args) == 2:
1197 if not repo:
1197 if not repo:
1198 raise util.Abort(_("there is no Mercurial repository here "
1198 raise util.Abort(_("there is no Mercurial repository here "
1199 "(.hg not found)"))
1199 "(.hg not found)"))
1200 rev1, rev2 = args
1200 rev1, rev2 = args
1201 r = repo.changelog
1201 r = repo.changelog
1202 lookup = repo.lookup
1202 lookup = repo.lookup
1203 else:
1203 else:
1204 raise util.Abort(_('either two or three arguments required'))
1204 raise util.Abort(_('either two or three arguments required'))
1205 a = r.ancestor(lookup(rev1), lookup(rev2))
1205 a = r.ancestor(lookup(rev1), lookup(rev2))
1206 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1206 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1207
1207
1208 @command('debugbuilddag',
1208 @command('debugbuilddag',
1209 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1209 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1210 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1210 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1211 ('n', 'new-file', None, _('add new file at each rev'))],
1211 ('n', 'new-file', None, _('add new file at each rev'))],
1212 _('[OPTION]... [TEXT]'))
1212 _('[OPTION]... [TEXT]'))
1213 def debugbuilddag(ui, repo, text=None,
1213 def debugbuilddag(ui, repo, text=None,
1214 mergeable_file=False,
1214 mergeable_file=False,
1215 overwritten_file=False,
1215 overwritten_file=False,
1216 new_file=False):
1216 new_file=False):
1217 """builds a repo with a given DAG from scratch in the current empty repo
1217 """builds a repo with a given DAG from scratch in the current empty repo
1218
1218
1219 The description of the DAG is read from stdin if not given on the
1219 The description of the DAG is read from stdin if not given on the
1220 command line.
1220 command line.
1221
1221
1222 Elements:
1222 Elements:
1223
1223
1224 - "+n" is a linear run of n nodes based on the current default parent
1224 - "+n" is a linear run of n nodes based on the current default parent
1225 - "." is a single node based on the current default parent
1225 - "." is a single node based on the current default parent
1226 - "$" resets the default parent to null (implied at the start);
1226 - "$" resets the default parent to null (implied at the start);
1227 otherwise the default parent is always the last node created
1227 otherwise the default parent is always the last node created
1228 - "<p" sets the default parent to the backref p
1228 - "<p" sets the default parent to the backref p
1229 - "*p" is a fork at parent p, which is a backref
1229 - "*p" is a fork at parent p, which is a backref
1230 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1230 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1231 - "/p2" is a merge of the preceding node and p2
1231 - "/p2" is a merge of the preceding node and p2
1232 - ":tag" defines a local tag for the preceding node
1232 - ":tag" defines a local tag for the preceding node
1233 - "@branch" sets the named branch for subsequent nodes
1233 - "@branch" sets the named branch for subsequent nodes
1234 - "#...\\n" is a comment up to the end of the line
1234 - "#...\\n" is a comment up to the end of the line
1235
1235
1236 Whitespace between the above elements is ignored.
1236 Whitespace between the above elements is ignored.
1237
1237
1238 A backref is either
1238 A backref is either
1239
1239
1240 - a number n, which references the node curr-n, where curr is the current
1240 - a number n, which references the node curr-n, where curr is the current
1241 node, or
1241 node, or
1242 - the name of a local tag you placed earlier using ":tag", or
1242 - the name of a local tag you placed earlier using ":tag", or
1243 - empty to denote the default parent.
1243 - empty to denote the default parent.
1244
1244
1245 All string valued-elements are either strictly alphanumeric, or must
1245 All string valued-elements are either strictly alphanumeric, or must
1246 be enclosed in double quotes ("..."), with "\\" as escape character.
1246 be enclosed in double quotes ("..."), with "\\" as escape character.
1247 """
1247 """
1248
1248
1249 if text is None:
1249 if text is None:
1250 ui.status(_("reading DAG from stdin\n"))
1250 ui.status(_("reading DAG from stdin\n"))
1251 text = ui.fin.read()
1251 text = ui.fin.read()
1252
1252
1253 cl = repo.changelog
1253 cl = repo.changelog
1254 if len(cl) > 0:
1254 if len(cl) > 0:
1255 raise util.Abort(_('repository is not empty'))
1255 raise util.Abort(_('repository is not empty'))
1256
1256
1257 # determine number of revs in DAG
1257 # determine number of revs in DAG
1258 total = 0
1258 total = 0
1259 for type, data in dagparser.parsedag(text):
1259 for type, data in dagparser.parsedag(text):
1260 if type == 'n':
1260 if type == 'n':
1261 total += 1
1261 total += 1
1262
1262
1263 if mergeable_file:
1263 if mergeable_file:
1264 linesperrev = 2
1264 linesperrev = 2
1265 # make a file with k lines per rev
1265 # make a file with k lines per rev
1266 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1266 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1267 initialmergedlines.append("")
1267 initialmergedlines.append("")
1268
1268
1269 tags = []
1269 tags = []
1270
1270
1271 tr = repo.transaction("builddag")
1271 tr = repo.transaction("builddag")
1272 try:
1272 try:
1273
1273
1274 at = -1
1274 at = -1
1275 atbranch = 'default'
1275 atbranch = 'default'
1276 nodeids = []
1276 nodeids = []
1277 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1277 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1278 for type, data in dagparser.parsedag(text):
1278 for type, data in dagparser.parsedag(text):
1279 if type == 'n':
1279 if type == 'n':
1280 ui.note('node %s\n' % str(data))
1280 ui.note('node %s\n' % str(data))
1281 id, ps = data
1281 id, ps = data
1282
1282
1283 files = []
1283 files = []
1284 fctxs = {}
1284 fctxs = {}
1285
1285
1286 p2 = None
1286 p2 = None
1287 if mergeable_file:
1287 if mergeable_file:
1288 fn = "mf"
1288 fn = "mf"
1289 p1 = repo[ps[0]]
1289 p1 = repo[ps[0]]
1290 if len(ps) > 1:
1290 if len(ps) > 1:
1291 p2 = repo[ps[1]]
1291 p2 = repo[ps[1]]
1292 pa = p1.ancestor(p2)
1292 pa = p1.ancestor(p2)
1293 base, local, other = [x[fn].data() for x in pa, p1, p2]
1293 base, local, other = [x[fn].data() for x in pa, p1, p2]
1294 m3 = simplemerge.Merge3Text(base, local, other)
1294 m3 = simplemerge.Merge3Text(base, local, other)
1295 ml = [l.strip() for l in m3.merge_lines()]
1295 ml = [l.strip() for l in m3.merge_lines()]
1296 ml.append("")
1296 ml.append("")
1297 elif at > 0:
1297 elif at > 0:
1298 ml = p1[fn].data().split("\n")
1298 ml = p1[fn].data().split("\n")
1299 else:
1299 else:
1300 ml = initialmergedlines
1300 ml = initialmergedlines
1301 ml[id * linesperrev] += " r%i" % id
1301 ml[id * linesperrev] += " r%i" % id
1302 mergedtext = "\n".join(ml)
1302 mergedtext = "\n".join(ml)
1303 files.append(fn)
1303 files.append(fn)
1304 fctxs[fn] = context.memfilectx(fn, mergedtext)
1304 fctxs[fn] = context.memfilectx(fn, mergedtext)
1305
1305
1306 if overwritten_file:
1306 if overwritten_file:
1307 fn = "of"
1307 fn = "of"
1308 files.append(fn)
1308 files.append(fn)
1309 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1309 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1310
1310
1311 if new_file:
1311 if new_file:
1312 fn = "nf%i" % id
1312 fn = "nf%i" % id
1313 files.append(fn)
1313 files.append(fn)
1314 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1314 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1315 if len(ps) > 1:
1315 if len(ps) > 1:
1316 if not p2:
1316 if not p2:
1317 p2 = repo[ps[1]]
1317 p2 = repo[ps[1]]
1318 for fn in p2:
1318 for fn in p2:
1319 if fn.startswith("nf"):
1319 if fn.startswith("nf"):
1320 files.append(fn)
1320 files.append(fn)
1321 fctxs[fn] = p2[fn]
1321 fctxs[fn] = p2[fn]
1322
1322
1323 def fctxfn(repo, cx, path):
1323 def fctxfn(repo, cx, path):
1324 return fctxs.get(path)
1324 return fctxs.get(path)
1325
1325
1326 if len(ps) == 0 or ps[0] < 0:
1326 if len(ps) == 0 or ps[0] < 0:
1327 pars = [None, None]
1327 pars = [None, None]
1328 elif len(ps) == 1:
1328 elif len(ps) == 1:
1329 pars = [nodeids[ps[0]], None]
1329 pars = [nodeids[ps[0]], None]
1330 else:
1330 else:
1331 pars = [nodeids[p] for p in ps]
1331 pars = [nodeids[p] for p in ps]
1332 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1332 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1333 date=(id, 0),
1333 date=(id, 0),
1334 user="debugbuilddag",
1334 user="debugbuilddag",
1335 extra={'branch': atbranch})
1335 extra={'branch': atbranch})
1336 nodeid = repo.commitctx(cx)
1336 nodeid = repo.commitctx(cx)
1337 nodeids.append(nodeid)
1337 nodeids.append(nodeid)
1338 at = id
1338 at = id
1339 elif type == 'l':
1339 elif type == 'l':
1340 id, name = data
1340 id, name = data
1341 ui.note('tag %s\n' % name)
1341 ui.note('tag %s\n' % name)
1342 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1342 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1343 elif type == 'a':
1343 elif type == 'a':
1344 ui.note('branch %s\n' % data)
1344 ui.note('branch %s\n' % data)
1345 atbranch = data
1345 atbranch = data
1346 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1346 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1347 tr.close()
1347 tr.close()
1348 finally:
1348 finally:
1349 ui.progress(_('building'), None)
1349 ui.progress(_('building'), None)
1350 tr.release()
1350 tr.release()
1351
1351
1352 if tags:
1352 if tags:
1353 repo.opener.write("localtags", "".join(tags))
1353 repo.opener.write("localtags", "".join(tags))
1354
1354
1355 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1355 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1356 def debugbundle(ui, bundlepath, all=None, **opts):
1356 def debugbundle(ui, bundlepath, all=None, **opts):
1357 """lists the contents of a bundle"""
1357 """lists the contents of a bundle"""
1358 f = url.open(ui, bundlepath)
1358 f = url.open(ui, bundlepath)
1359 try:
1359 try:
1360 gen = changegroup.readbundle(f, bundlepath)
1360 gen = changegroup.readbundle(f, bundlepath)
1361 if all:
1361 if all:
1362 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1362 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1363
1363
1364 def showchunks(named):
1364 def showchunks(named):
1365 ui.write("\n%s\n" % named)
1365 ui.write("\n%s\n" % named)
1366 chain = None
1366 chain = None
1367 while True:
1367 while True:
1368 chunkdata = gen.deltachunk(chain)
1368 chunkdata = gen.deltachunk(chain)
1369 if not chunkdata:
1369 if not chunkdata:
1370 break
1370 break
1371 node = chunkdata['node']
1371 node = chunkdata['node']
1372 p1 = chunkdata['p1']
1372 p1 = chunkdata['p1']
1373 p2 = chunkdata['p2']
1373 p2 = chunkdata['p2']
1374 cs = chunkdata['cs']
1374 cs = chunkdata['cs']
1375 deltabase = chunkdata['deltabase']
1375 deltabase = chunkdata['deltabase']
1376 delta = chunkdata['delta']
1376 delta = chunkdata['delta']
1377 ui.write("%s %s %s %s %s %s\n" %
1377 ui.write("%s %s %s %s %s %s\n" %
1378 (hex(node), hex(p1), hex(p2),
1378 (hex(node), hex(p1), hex(p2),
1379 hex(cs), hex(deltabase), len(delta)))
1379 hex(cs), hex(deltabase), len(delta)))
1380 chain = node
1380 chain = node
1381
1381
1382 chunkdata = gen.changelogheader()
1382 chunkdata = gen.changelogheader()
1383 showchunks("changelog")
1383 showchunks("changelog")
1384 chunkdata = gen.manifestheader()
1384 chunkdata = gen.manifestheader()
1385 showchunks("manifest")
1385 showchunks("manifest")
1386 while True:
1386 while True:
1387 chunkdata = gen.filelogheader()
1387 chunkdata = gen.filelogheader()
1388 if not chunkdata:
1388 if not chunkdata:
1389 break
1389 break
1390 fname = chunkdata['filename']
1390 fname = chunkdata['filename']
1391 showchunks(fname)
1391 showchunks(fname)
1392 else:
1392 else:
1393 chunkdata = gen.changelogheader()
1393 chunkdata = gen.changelogheader()
1394 chain = None
1394 chain = None
1395 while True:
1395 while True:
1396 chunkdata = gen.deltachunk(chain)
1396 chunkdata = gen.deltachunk(chain)
1397 if not chunkdata:
1397 if not chunkdata:
1398 break
1398 break
1399 node = chunkdata['node']
1399 node = chunkdata['node']
1400 ui.write("%s\n" % hex(node))
1400 ui.write("%s\n" % hex(node))
1401 chain = node
1401 chain = node
1402 finally:
1402 finally:
1403 f.close()
1403 f.close()
1404
1404
1405 @command('debugcheckstate', [], '')
1405 @command('debugcheckstate', [], '')
1406 def debugcheckstate(ui, repo):
1406 def debugcheckstate(ui, repo):
1407 """validate the correctness of the current dirstate"""
1407 """validate the correctness of the current dirstate"""
1408 parent1, parent2 = repo.dirstate.parents()
1408 parent1, parent2 = repo.dirstate.parents()
1409 m1 = repo[parent1].manifest()
1409 m1 = repo[parent1].manifest()
1410 m2 = repo[parent2].manifest()
1410 m2 = repo[parent2].manifest()
1411 errors = 0
1411 errors = 0
1412 for f in repo.dirstate:
1412 for f in repo.dirstate:
1413 state = repo.dirstate[f]
1413 state = repo.dirstate[f]
1414 if state in "nr" and f not in m1:
1414 if state in "nr" and f not in m1:
1415 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1415 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1416 errors += 1
1416 errors += 1
1417 if state in "a" and f in m1:
1417 if state in "a" and f in m1:
1418 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1418 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1419 errors += 1
1419 errors += 1
1420 if state in "m" and f not in m1 and f not in m2:
1420 if state in "m" and f not in m1 and f not in m2:
1421 ui.warn(_("%s in state %s, but not in either manifest\n") %
1421 ui.warn(_("%s in state %s, but not in either manifest\n") %
1422 (f, state))
1422 (f, state))
1423 errors += 1
1423 errors += 1
1424 for f in m1:
1424 for f in m1:
1425 state = repo.dirstate[f]
1425 state = repo.dirstate[f]
1426 if state not in "nrm":
1426 if state not in "nrm":
1427 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1427 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1428 errors += 1
1428 errors += 1
1429 if errors:
1429 if errors:
1430 error = _(".hg/dirstate inconsistent with current parent's manifest")
1430 error = _(".hg/dirstate inconsistent with current parent's manifest")
1431 raise util.Abort(error)
1431 raise util.Abort(error)
1432
1432
1433 @command('debugcommands', [], _('[COMMAND]'))
1433 @command('debugcommands', [], _('[COMMAND]'))
1434 def debugcommands(ui, cmd='', *args):
1434 def debugcommands(ui, cmd='', *args):
1435 """list all available commands and options"""
1435 """list all available commands and options"""
1436 for cmd, vals in sorted(table.iteritems()):
1436 for cmd, vals in sorted(table.iteritems()):
1437 cmd = cmd.split('|')[0].strip('^')
1437 cmd = cmd.split('|')[0].strip('^')
1438 opts = ', '.join([i[1] for i in vals[1]])
1438 opts = ', '.join([i[1] for i in vals[1]])
1439 ui.write('%s: %s\n' % (cmd, opts))
1439 ui.write('%s: %s\n' % (cmd, opts))
1440
1440
1441 @command('debugcomplete',
1441 @command('debugcomplete',
1442 [('o', 'options', None, _('show the command options'))],
1442 [('o', 'options', None, _('show the command options'))],
1443 _('[-o] CMD'))
1443 _('[-o] CMD'))
1444 def debugcomplete(ui, cmd='', **opts):
1444 def debugcomplete(ui, cmd='', **opts):
1445 """returns the completion list associated with the given command"""
1445 """returns the completion list associated with the given command"""
1446
1446
1447 if opts.get('options'):
1447 if opts.get('options'):
1448 options = []
1448 options = []
1449 otables = [globalopts]
1449 otables = [globalopts]
1450 if cmd:
1450 if cmd:
1451 aliases, entry = cmdutil.findcmd(cmd, table, False)
1451 aliases, entry = cmdutil.findcmd(cmd, table, False)
1452 otables.append(entry[1])
1452 otables.append(entry[1])
1453 for t in otables:
1453 for t in otables:
1454 for o in t:
1454 for o in t:
1455 if "(DEPRECATED)" in o[3]:
1455 if "(DEPRECATED)" in o[3]:
1456 continue
1456 continue
1457 if o[0]:
1457 if o[0]:
1458 options.append('-%s' % o[0])
1458 options.append('-%s' % o[0])
1459 options.append('--%s' % o[1])
1459 options.append('--%s' % o[1])
1460 ui.write("%s\n" % "\n".join(options))
1460 ui.write("%s\n" % "\n".join(options))
1461 return
1461 return
1462
1462
1463 cmdlist = cmdutil.findpossible(cmd, table)
1463 cmdlist = cmdutil.findpossible(cmd, table)
1464 if ui.verbose:
1464 if ui.verbose:
1465 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1465 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1466 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1466 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1467
1467
1468 @command('debugdag',
1468 @command('debugdag',
1469 [('t', 'tags', None, _('use tags as labels')),
1469 [('t', 'tags', None, _('use tags as labels')),
1470 ('b', 'branches', None, _('annotate with branch names')),
1470 ('b', 'branches', None, _('annotate with branch names')),
1471 ('', 'dots', None, _('use dots for runs')),
1471 ('', 'dots', None, _('use dots for runs')),
1472 ('s', 'spaces', None, _('separate elements by spaces'))],
1472 ('s', 'spaces', None, _('separate elements by spaces'))],
1473 _('[OPTION]... [FILE [REV]...]'))
1473 _('[OPTION]... [FILE [REV]...]'))
1474 def debugdag(ui, repo, file_=None, *revs, **opts):
1474 def debugdag(ui, repo, file_=None, *revs, **opts):
1475 """format the changelog or an index DAG as a concise textual description
1475 """format the changelog or an index DAG as a concise textual description
1476
1476
1477 If you pass a revlog index, the revlog's DAG is emitted. If you list
1477 If you pass a revlog index, the revlog's DAG is emitted. If you list
1478 revision numbers, they get labelled in the output as rN.
1478 revision numbers, they get labelled in the output as rN.
1479
1479
1480 Otherwise, the changelog DAG of the current repo is emitted.
1480 Otherwise, the changelog DAG of the current repo is emitted.
1481 """
1481 """
1482 spaces = opts.get('spaces')
1482 spaces = opts.get('spaces')
1483 dots = opts.get('dots')
1483 dots = opts.get('dots')
1484 if file_:
1484 if file_:
1485 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1485 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1486 revs = set((int(r) for r in revs))
1486 revs = set((int(r) for r in revs))
1487 def events():
1487 def events():
1488 for r in rlog:
1488 for r in rlog:
1489 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1489 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1490 if r in revs:
1490 if r in revs:
1491 yield 'l', (r, "r%i" % r)
1491 yield 'l', (r, "r%i" % r)
1492 elif repo:
1492 elif repo:
1493 cl = repo.changelog
1493 cl = repo.changelog
1494 tags = opts.get('tags')
1494 tags = opts.get('tags')
1495 branches = opts.get('branches')
1495 branches = opts.get('branches')
1496 if tags:
1496 if tags:
1497 labels = {}
1497 labels = {}
1498 for l, n in repo.tags().items():
1498 for l, n in repo.tags().items():
1499 labels.setdefault(cl.rev(n), []).append(l)
1499 labels.setdefault(cl.rev(n), []).append(l)
1500 def events():
1500 def events():
1501 b = "default"
1501 b = "default"
1502 for r in cl:
1502 for r in cl:
1503 if branches:
1503 if branches:
1504 newb = cl.read(cl.node(r))[5]['branch']
1504 newb = cl.read(cl.node(r))[5]['branch']
1505 if newb != b:
1505 if newb != b:
1506 yield 'a', newb
1506 yield 'a', newb
1507 b = newb
1507 b = newb
1508 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1508 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1509 if tags:
1509 if tags:
1510 ls = labels.get(r)
1510 ls = labels.get(r)
1511 if ls:
1511 if ls:
1512 for l in ls:
1512 for l in ls:
1513 yield 'l', (r, l)
1513 yield 'l', (r, l)
1514 else:
1514 else:
1515 raise util.Abort(_('need repo for changelog dag'))
1515 raise util.Abort(_('need repo for changelog dag'))
1516
1516
1517 for line in dagparser.dagtextlines(events(),
1517 for line in dagparser.dagtextlines(events(),
1518 addspaces=spaces,
1518 addspaces=spaces,
1519 wraplabels=True,
1519 wraplabels=True,
1520 wrapannotations=True,
1520 wrapannotations=True,
1521 wrapnonlinear=dots,
1521 wrapnonlinear=dots,
1522 usedots=dots,
1522 usedots=dots,
1523 maxlinewidth=70):
1523 maxlinewidth=70):
1524 ui.write(line)
1524 ui.write(line)
1525 ui.write("\n")
1525 ui.write("\n")
1526
1526
1527 @command('debugdata',
1527 @command('debugdata',
1528 [('c', 'changelog', False, _('open changelog')),
1528 [('c', 'changelog', False, _('open changelog')),
1529 ('m', 'manifest', False, _('open manifest'))],
1529 ('m', 'manifest', False, _('open manifest'))],
1530 _('-c|-m|FILE REV'))
1530 _('-c|-m|FILE REV'))
1531 def debugdata(ui, repo, file_, rev = None, **opts):
1531 def debugdata(ui, repo, file_, rev = None, **opts):
1532 """dump the contents of a data file revision"""
1532 """dump the contents of a data file revision"""
1533 if opts.get('changelog') or opts.get('manifest'):
1533 if opts.get('changelog') or opts.get('manifest'):
1534 file_, rev = None, file_
1534 file_, rev = None, file_
1535 elif rev is None:
1535 elif rev is None:
1536 raise error.CommandError('debugdata', _('invalid arguments'))
1536 raise error.CommandError('debugdata', _('invalid arguments'))
1537 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1537 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1538 try:
1538 try:
1539 ui.write(r.revision(r.lookup(rev)))
1539 ui.write(r.revision(r.lookup(rev)))
1540 except KeyError:
1540 except KeyError:
1541 raise util.Abort(_('invalid revision identifier %s') % rev)
1541 raise util.Abort(_('invalid revision identifier %s') % rev)
1542
1542
1543 @command('debugdate',
1543 @command('debugdate',
1544 [('e', 'extended', None, _('try extended date formats'))],
1544 [('e', 'extended', None, _('try extended date formats'))],
1545 _('[-e] DATE [RANGE]'))
1545 _('[-e] DATE [RANGE]'))
1546 def debugdate(ui, date, range=None, **opts):
1546 def debugdate(ui, date, range=None, **opts):
1547 """parse and display a date"""
1547 """parse and display a date"""
1548 if opts["extended"]:
1548 if opts["extended"]:
1549 d = util.parsedate(date, util.extendeddateformats)
1549 d = util.parsedate(date, util.extendeddateformats)
1550 else:
1550 else:
1551 d = util.parsedate(date)
1551 d = util.parsedate(date)
1552 ui.write("internal: %s %s\n" % d)
1552 ui.write("internal: %s %s\n" % d)
1553 ui.write("standard: %s\n" % util.datestr(d))
1553 ui.write("standard: %s\n" % util.datestr(d))
1554 if range:
1554 if range:
1555 m = util.matchdate(range)
1555 m = util.matchdate(range)
1556 ui.write("match: %s\n" % m(d[0]))
1556 ui.write("match: %s\n" % m(d[0]))
1557
1557
1558 @command('debugdiscovery',
1558 @command('debugdiscovery',
1559 [('', 'old', None, _('use old-style discovery')),
1559 [('', 'old', None, _('use old-style discovery')),
1560 ('', 'nonheads', None,
1560 ('', 'nonheads', None,
1561 _('use old-style discovery with non-heads included')),
1561 _('use old-style discovery with non-heads included')),
1562 ] + remoteopts,
1562 ] + remoteopts,
1563 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1563 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1564 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1564 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1565 """runs the changeset discovery protocol in isolation"""
1565 """runs the changeset discovery protocol in isolation"""
1566 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1566 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1567 remote = hg.peer(repo, opts, remoteurl)
1567 remote = hg.peer(repo, opts, remoteurl)
1568 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1568 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1569
1569
1570 # make sure tests are repeatable
1570 # make sure tests are repeatable
1571 random.seed(12323)
1571 random.seed(12323)
1572
1572
1573 def doit(localheads, remoteheads):
1573 def doit(localheads, remoteheads):
1574 if opts.get('old'):
1574 if opts.get('old'):
1575 if localheads:
1575 if localheads:
1576 raise util.Abort('cannot use localheads with old style discovery')
1576 raise util.Abort('cannot use localheads with old style discovery')
1577 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1577 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1578 force=True)
1578 force=True)
1579 common = set(common)
1579 common = set(common)
1580 if not opts.get('nonheads'):
1580 if not opts.get('nonheads'):
1581 ui.write("unpruned common: %s\n" % " ".join([short(n)
1581 ui.write("unpruned common: %s\n" % " ".join([short(n)
1582 for n in common]))
1582 for n in common]))
1583 dag = dagutil.revlogdag(repo.changelog)
1583 dag = dagutil.revlogdag(repo.changelog)
1584 all = dag.ancestorset(dag.internalizeall(common))
1584 all = dag.ancestorset(dag.internalizeall(common))
1585 common = dag.externalizeall(dag.headsetofconnecteds(all))
1585 common = dag.externalizeall(dag.headsetofconnecteds(all))
1586 else:
1586 else:
1587 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1587 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1588 common = set(common)
1588 common = set(common)
1589 rheads = set(hds)
1589 rheads = set(hds)
1590 lheads = set(repo.heads())
1590 lheads = set(repo.heads())
1591 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1591 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1592 if lheads <= common:
1592 if lheads <= common:
1593 ui.write("local is subset\n")
1593 ui.write("local is subset\n")
1594 elif rheads <= common:
1594 elif rheads <= common:
1595 ui.write("remote is subset\n")
1595 ui.write("remote is subset\n")
1596
1596
1597 serverlogs = opts.get('serverlog')
1597 serverlogs = opts.get('serverlog')
1598 if serverlogs:
1598 if serverlogs:
1599 for filename in serverlogs:
1599 for filename in serverlogs:
1600 logfile = open(filename, 'r')
1600 logfile = open(filename, 'r')
1601 try:
1601 try:
1602 line = logfile.readline()
1602 line = logfile.readline()
1603 while line:
1603 while line:
1604 parts = line.strip().split(';')
1604 parts = line.strip().split(';')
1605 op = parts[1]
1605 op = parts[1]
1606 if op == 'cg':
1606 if op == 'cg':
1607 pass
1607 pass
1608 elif op == 'cgss':
1608 elif op == 'cgss':
1609 doit(parts[2].split(' '), parts[3].split(' '))
1609 doit(parts[2].split(' '), parts[3].split(' '))
1610 elif op == 'unb':
1610 elif op == 'unb':
1611 doit(parts[3].split(' '), parts[2].split(' '))
1611 doit(parts[3].split(' '), parts[2].split(' '))
1612 line = logfile.readline()
1612 line = logfile.readline()
1613 finally:
1613 finally:
1614 logfile.close()
1614 logfile.close()
1615
1615
1616 else:
1616 else:
1617 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1617 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1618 opts.get('remote_head'))
1618 opts.get('remote_head'))
1619 localrevs = opts.get('local_head')
1619 localrevs = opts.get('local_head')
1620 doit(localrevs, remoterevs)
1620 doit(localrevs, remoterevs)
1621
1621
1622 @command('debugfileset', [], ('REVSPEC'))
1622 @command('debugfileset', [], ('REVSPEC'))
1623 def debugfileset(ui, repo, expr):
1623 def debugfileset(ui, repo, expr):
1624 '''parse and apply a fileset specification'''
1624 '''parse and apply a fileset specification'''
1625 if ui.verbose:
1625 if ui.verbose:
1626 tree = fileset.parse(expr)[0]
1626 tree = fileset.parse(expr)[0]
1627 ui.note(tree, "\n")
1627 ui.note(tree, "\n")
1628
1628
1629 for f in fileset.getfileset(repo[None], expr):
1629 for f in fileset.getfileset(repo[None], expr):
1630 ui.write("%s\n" % f)
1630 ui.write("%s\n" % f)
1631
1631
1632 @command('debugfsinfo', [], _('[PATH]'))
1632 @command('debugfsinfo', [], _('[PATH]'))
1633 def debugfsinfo(ui, path = "."):
1633 def debugfsinfo(ui, path = "."):
1634 """show information detected about current filesystem"""
1634 """show information detected about current filesystem"""
1635 util.writefile('.debugfsinfo', '')
1635 util.writefile('.debugfsinfo', '')
1636 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1636 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1637 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1637 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1638 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1638 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1639 and 'yes' or 'no'))
1639 and 'yes' or 'no'))
1640 os.unlink('.debugfsinfo')
1640 os.unlink('.debugfsinfo')
1641
1641
1642 @command('debuggetbundle',
1642 @command('debuggetbundle',
1643 [('H', 'head', [], _('id of head node'), _('ID')),
1643 [('H', 'head', [], _('id of head node'), _('ID')),
1644 ('C', 'common', [], _('id of common node'), _('ID')),
1644 ('C', 'common', [], _('id of common node'), _('ID')),
1645 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1645 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1646 _('REPO FILE [-H|-C ID]...'))
1646 _('REPO FILE [-H|-C ID]...'))
1647 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1647 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1648 """retrieves a bundle from a repo
1648 """retrieves a bundle from a repo
1649
1649
1650 Every ID must be a full-length hex node id string. Saves the bundle to the
1650 Every ID must be a full-length hex node id string. Saves the bundle to the
1651 given file.
1651 given file.
1652 """
1652 """
1653 repo = hg.peer(ui, opts, repopath)
1653 repo = hg.peer(ui, opts, repopath)
1654 if not repo.capable('getbundle'):
1654 if not repo.capable('getbundle'):
1655 raise util.Abort("getbundle() not supported by target repository")
1655 raise util.Abort("getbundle() not supported by target repository")
1656 args = {}
1656 args = {}
1657 if common:
1657 if common:
1658 args['common'] = [bin(s) for s in common]
1658 args['common'] = [bin(s) for s in common]
1659 if head:
1659 if head:
1660 args['heads'] = [bin(s) for s in head]
1660 args['heads'] = [bin(s) for s in head]
1661 bundle = repo.getbundle('debug', **args)
1661 bundle = repo.getbundle('debug', **args)
1662
1662
1663 bundletype = opts.get('type', 'bzip2').lower()
1663 bundletype = opts.get('type', 'bzip2').lower()
1664 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1664 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1665 bundletype = btypes.get(bundletype)
1665 bundletype = btypes.get(bundletype)
1666 if bundletype not in changegroup.bundletypes:
1666 if bundletype not in changegroup.bundletypes:
1667 raise util.Abort(_('unknown bundle type specified with --type'))
1667 raise util.Abort(_('unknown bundle type specified with --type'))
1668 changegroup.writebundle(bundle, bundlepath, bundletype)
1668 changegroup.writebundle(bundle, bundlepath, bundletype)
1669
1669
1670 @command('debugignore', [], '')
1670 @command('debugignore', [], '')
1671 def debugignore(ui, repo, *values, **opts):
1671 def debugignore(ui, repo, *values, **opts):
1672 """display the combined ignore pattern"""
1672 """display the combined ignore pattern"""
1673 ignore = repo.dirstate._ignore
1673 ignore = repo.dirstate._ignore
1674 includepat = getattr(ignore, 'includepat', None)
1674 includepat = getattr(ignore, 'includepat', None)
1675 if includepat is not None:
1675 if includepat is not None:
1676 ui.write("%s\n" % includepat)
1676 ui.write("%s\n" % includepat)
1677 else:
1677 else:
1678 raise util.Abort(_("no ignore patterns found"))
1678 raise util.Abort(_("no ignore patterns found"))
1679
1679
1680 @command('debugindex',
1680 @command('debugindex',
1681 [('c', 'changelog', False, _('open changelog')),
1681 [('c', 'changelog', False, _('open changelog')),
1682 ('m', 'manifest', False, _('open manifest')),
1682 ('m', 'manifest', False, _('open manifest')),
1683 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1683 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1684 _('[-f FORMAT] -c|-m|FILE'))
1684 _('[-f FORMAT] -c|-m|FILE'))
1685 def debugindex(ui, repo, file_ = None, **opts):
1685 def debugindex(ui, repo, file_ = None, **opts):
1686 """dump the contents of an index file"""
1686 """dump the contents of an index file"""
1687 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1687 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1688 format = opts.get('format', 0)
1688 format = opts.get('format', 0)
1689 if format not in (0, 1):
1689 if format not in (0, 1):
1690 raise util.Abort(_("unknown format %d") % format)
1690 raise util.Abort(_("unknown format %d") % format)
1691
1691
1692 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1692 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1693 if generaldelta:
1693 if generaldelta:
1694 basehdr = ' delta'
1694 basehdr = ' delta'
1695 else:
1695 else:
1696 basehdr = ' base'
1696 basehdr = ' base'
1697
1697
1698 if format == 0:
1698 if format == 0:
1699 ui.write(" rev offset length " + basehdr + " linkrev"
1699 ui.write(" rev offset length " + basehdr + " linkrev"
1700 " nodeid p1 p2\n")
1700 " nodeid p1 p2\n")
1701 elif format == 1:
1701 elif format == 1:
1702 ui.write(" rev flag offset length"
1702 ui.write(" rev flag offset length"
1703 " size " + basehdr + " link p1 p2 nodeid\n")
1703 " size " + basehdr + " link p1 p2 nodeid\n")
1704
1704
1705 for i in r:
1705 for i in r:
1706 node = r.node(i)
1706 node = r.node(i)
1707 if generaldelta:
1707 if generaldelta:
1708 base = r.deltaparent(i)
1708 base = r.deltaparent(i)
1709 else:
1709 else:
1710 base = r.chainbase(i)
1710 base = r.chainbase(i)
1711 if format == 0:
1711 if format == 0:
1712 try:
1712 try:
1713 pp = r.parents(node)
1713 pp = r.parents(node)
1714 except:
1714 except:
1715 pp = [nullid, nullid]
1715 pp = [nullid, nullid]
1716 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1716 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1717 i, r.start(i), r.length(i), base, r.linkrev(i),
1717 i, r.start(i), r.length(i), base, r.linkrev(i),
1718 short(node), short(pp[0]), short(pp[1])))
1718 short(node), short(pp[0]), short(pp[1])))
1719 elif format == 1:
1719 elif format == 1:
1720 pr = r.parentrevs(i)
1720 pr = r.parentrevs(i)
1721 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1721 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1722 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1722 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1723 base, r.linkrev(i), pr[0], pr[1], short(node)))
1723 base, r.linkrev(i), pr[0], pr[1], short(node)))
1724
1724
1725 @command('debugindexdot', [], _('FILE'))
1725 @command('debugindexdot', [], _('FILE'))
1726 def debugindexdot(ui, repo, file_):
1726 def debugindexdot(ui, repo, file_):
1727 """dump an index DAG as a graphviz dot file"""
1727 """dump an index DAG as a graphviz dot file"""
1728 r = None
1728 r = None
1729 if repo:
1729 if repo:
1730 filelog = repo.file(file_)
1730 filelog = repo.file(file_)
1731 if len(filelog):
1731 if len(filelog):
1732 r = filelog
1732 r = filelog
1733 if not r:
1733 if not r:
1734 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1734 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1735 ui.write("digraph G {\n")
1735 ui.write("digraph G {\n")
1736 for i in r:
1736 for i in r:
1737 node = r.node(i)
1737 node = r.node(i)
1738 pp = r.parents(node)
1738 pp = r.parents(node)
1739 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1739 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1740 if pp[1] != nullid:
1740 if pp[1] != nullid:
1741 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1741 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1742 ui.write("}\n")
1742 ui.write("}\n")
1743
1743
1744 @command('debuginstall', [], '')
1744 @command('debuginstall', [], '')
1745 def debuginstall(ui):
1745 def debuginstall(ui):
1746 '''test Mercurial installation
1746 '''test Mercurial installation
1747
1747
1748 Returns 0 on success.
1748 Returns 0 on success.
1749 '''
1749 '''
1750
1750
1751 def writetemp(contents):
1751 def writetemp(contents):
1752 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1752 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1753 f = os.fdopen(fd, "wb")
1753 f = os.fdopen(fd, "wb")
1754 f.write(contents)
1754 f.write(contents)
1755 f.close()
1755 f.close()
1756 return name
1756 return name
1757
1757
1758 problems = 0
1758 problems = 0
1759
1759
1760 # encoding
1760 # encoding
1761 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1761 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1762 try:
1762 try:
1763 encoding.fromlocal("test")
1763 encoding.fromlocal("test")
1764 except util.Abort, inst:
1764 except util.Abort, inst:
1765 ui.write(" %s\n" % inst)
1765 ui.write(" %s\n" % inst)
1766 ui.write(_(" (check that your locale is properly set)\n"))
1766 ui.write(_(" (check that your locale is properly set)\n"))
1767 problems += 1
1767 problems += 1
1768
1768
1769 # compiled modules
1769 # compiled modules
1770 ui.status(_("Checking installed modules (%s)...\n")
1770 ui.status(_("Checking installed modules (%s)...\n")
1771 % os.path.dirname(__file__))
1771 % os.path.dirname(__file__))
1772 try:
1772 try:
1773 import bdiff, mpatch, base85, osutil
1773 import bdiff, mpatch, base85, osutil
1774 except Exception, inst:
1774 except Exception, inst:
1775 ui.write(" %s\n" % inst)
1775 ui.write(" %s\n" % inst)
1776 ui.write(_(" One or more extensions could not be found"))
1776 ui.write(_(" One or more extensions could not be found"))
1777 ui.write(_(" (check that you compiled the extensions)\n"))
1777 ui.write(_(" (check that you compiled the extensions)\n"))
1778 problems += 1
1778 problems += 1
1779
1779
1780 # templates
1780 # templates
1781 ui.status(_("Checking templates...\n"))
1781 ui.status(_("Checking templates...\n"))
1782 try:
1782 try:
1783 import templater
1783 import templater
1784 templater.templater(templater.templatepath("map-cmdline.default"))
1784 templater.templater(templater.templatepath("map-cmdline.default"))
1785 except Exception, inst:
1785 except Exception, inst:
1786 ui.write(" %s\n" % inst)
1786 ui.write(" %s\n" % inst)
1787 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1787 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1788 problems += 1
1788 problems += 1
1789
1789
1790 # editor
1790 # editor
1791 ui.status(_("Checking commit editor...\n"))
1791 ui.status(_("Checking commit editor...\n"))
1792 editor = ui.geteditor()
1792 editor = ui.geteditor()
1793 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1793 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1794 if not cmdpath:
1794 if not cmdpath:
1795 if editor == 'vi':
1795 if editor == 'vi':
1796 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1796 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1797 ui.write(_(" (specify a commit editor in your configuration"
1797 ui.write(_(" (specify a commit editor in your configuration"
1798 " file)\n"))
1798 " file)\n"))
1799 else:
1799 else:
1800 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1800 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1801 ui.write(_(" (specify a commit editor in your configuration"
1801 ui.write(_(" (specify a commit editor in your configuration"
1802 " file)\n"))
1802 " file)\n"))
1803 problems += 1
1803 problems += 1
1804
1804
1805 # check username
1805 # check username
1806 ui.status(_("Checking username...\n"))
1806 ui.status(_("Checking username...\n"))
1807 try:
1807 try:
1808 ui.username()
1808 ui.username()
1809 except util.Abort, e:
1809 except util.Abort, e:
1810 ui.write(" %s\n" % e)
1810 ui.write(" %s\n" % e)
1811 ui.write(_(" (specify a username in your configuration file)\n"))
1811 ui.write(_(" (specify a username in your configuration file)\n"))
1812 problems += 1
1812 problems += 1
1813
1813
1814 if not problems:
1814 if not problems:
1815 ui.status(_("No problems detected\n"))
1815 ui.status(_("No problems detected\n"))
1816 else:
1816 else:
1817 ui.write(_("%s problems detected,"
1817 ui.write(_("%s problems detected,"
1818 " please check your install!\n") % problems)
1818 " please check your install!\n") % problems)
1819
1819
1820 return problems
1820 return problems
1821
1821
1822 @command('debugknown', [], _('REPO ID...'))
1822 @command('debugknown', [], _('REPO ID...'))
1823 def debugknown(ui, repopath, *ids, **opts):
1823 def debugknown(ui, repopath, *ids, **opts):
1824 """test whether node ids are known to a repo
1824 """test whether node ids are known to a repo
1825
1825
1826 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1826 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1827 indicating unknown/known.
1827 indicating unknown/known.
1828 """
1828 """
1829 repo = hg.peer(ui, opts, repopath)
1829 repo = hg.peer(ui, opts, repopath)
1830 if not repo.capable('known'):
1830 if not repo.capable('known'):
1831 raise util.Abort("known() not supported by target repository")
1831 raise util.Abort("known() not supported by target repository")
1832 flags = repo.known([bin(s) for s in ids])
1832 flags = repo.known([bin(s) for s in ids])
1833 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1833 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1834
1834
1835 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1835 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1836 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1836 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1837 '''access the pushkey key/value protocol
1837 '''access the pushkey key/value protocol
1838
1838
1839 With two args, list the keys in the given namespace.
1839 With two args, list the keys in the given namespace.
1840
1840
1841 With five args, set a key to new if it currently is set to old.
1841 With five args, set a key to new if it currently is set to old.
1842 Reports success or failure.
1842 Reports success or failure.
1843 '''
1843 '''
1844
1844
1845 target = hg.peer(ui, {}, repopath)
1845 target = hg.peer(ui, {}, repopath)
1846 if keyinfo:
1846 if keyinfo:
1847 key, old, new = keyinfo
1847 key, old, new = keyinfo
1848 r = target.pushkey(namespace, key, old, new)
1848 r = target.pushkey(namespace, key, old, new)
1849 ui.status(str(r) + '\n')
1849 ui.status(str(r) + '\n')
1850 return not r
1850 return not r
1851 else:
1851 else:
1852 for k, v in target.listkeys(namespace).iteritems():
1852 for k, v in target.listkeys(namespace).iteritems():
1853 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1853 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1854 v.encode('string-escape')))
1854 v.encode('string-escape')))
1855
1855
1856 @command('debugrebuildstate',
1856 @command('debugrebuildstate',
1857 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1857 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1858 _('[-r REV] [REV]'))
1858 _('[-r REV] [REV]'))
1859 def debugrebuildstate(ui, repo, rev="tip"):
1859 def debugrebuildstate(ui, repo, rev="tip"):
1860 """rebuild the dirstate as it would look like for the given revision"""
1860 """rebuild the dirstate as it would look like for the given revision"""
1861 ctx = scmutil.revsingle(repo, rev)
1861 ctx = scmutil.revsingle(repo, rev)
1862 wlock = repo.wlock()
1862 wlock = repo.wlock()
1863 try:
1863 try:
1864 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1864 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1865 finally:
1865 finally:
1866 wlock.release()
1866 wlock.release()
1867
1867
1868 @command('debugrename',
1868 @command('debugrename',
1869 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1869 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1870 _('[-r REV] FILE'))
1870 _('[-r REV] FILE'))
1871 def debugrename(ui, repo, file1, *pats, **opts):
1871 def debugrename(ui, repo, file1, *pats, **opts):
1872 """dump rename information"""
1872 """dump rename information"""
1873
1873
1874 ctx = scmutil.revsingle(repo, opts.get('rev'))
1874 ctx = scmutil.revsingle(repo, opts.get('rev'))
1875 m = scmutil.match(ctx, (file1,) + pats, opts)
1875 m = scmutil.match(ctx, (file1,) + pats, opts)
1876 for abs in ctx.walk(m):
1876 for abs in ctx.walk(m):
1877 fctx = ctx[abs]
1877 fctx = ctx[abs]
1878 o = fctx.filelog().renamed(fctx.filenode())
1878 o = fctx.filelog().renamed(fctx.filenode())
1879 rel = m.rel(abs)
1879 rel = m.rel(abs)
1880 if o:
1880 if o:
1881 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1881 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1882 else:
1882 else:
1883 ui.write(_("%s not renamed\n") % rel)
1883 ui.write(_("%s not renamed\n") % rel)
1884
1884
1885 @command('debugrevlog',
1885 @command('debugrevlog',
1886 [('c', 'changelog', False, _('open changelog')),
1886 [('c', 'changelog', False, _('open changelog')),
1887 ('m', 'manifest', False, _('open manifest')),
1887 ('m', 'manifest', False, _('open manifest')),
1888 ('d', 'dump', False, _('dump index data'))],
1888 ('d', 'dump', False, _('dump index data'))],
1889 _('-c|-m|FILE'))
1889 _('-c|-m|FILE'))
1890 def debugrevlog(ui, repo, file_ = None, **opts):
1890 def debugrevlog(ui, repo, file_ = None, **opts):
1891 """show data and statistics about a revlog"""
1891 """show data and statistics about a revlog"""
1892 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1892 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1893
1893
1894 if opts.get("dump"):
1894 if opts.get("dump"):
1895 numrevs = len(r)
1895 numrevs = len(r)
1896 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1896 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1897 " rawsize totalsize compression heads\n")
1897 " rawsize totalsize compression heads\n")
1898 ts = 0
1898 ts = 0
1899 heads = set()
1899 heads = set()
1900 for rev in xrange(numrevs):
1900 for rev in xrange(numrevs):
1901 dbase = r.deltaparent(rev)
1901 dbase = r.deltaparent(rev)
1902 if dbase == -1:
1902 if dbase == -1:
1903 dbase = rev
1903 dbase = rev
1904 cbase = r.chainbase(rev)
1904 cbase = r.chainbase(rev)
1905 p1, p2 = r.parentrevs(rev)
1905 p1, p2 = r.parentrevs(rev)
1906 rs = r.rawsize(rev)
1906 rs = r.rawsize(rev)
1907 ts = ts + rs
1907 ts = ts + rs
1908 heads -= set(r.parentrevs(rev))
1908 heads -= set(r.parentrevs(rev))
1909 heads.add(rev)
1909 heads.add(rev)
1910 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1910 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1911 (rev, p1, p2, r.start(rev), r.end(rev),
1911 (rev, p1, p2, r.start(rev), r.end(rev),
1912 r.start(dbase), r.start(cbase),
1912 r.start(dbase), r.start(cbase),
1913 r.start(p1), r.start(p2),
1913 r.start(p1), r.start(p2),
1914 rs, ts, ts / r.end(rev), len(heads)))
1914 rs, ts, ts / r.end(rev), len(heads)))
1915 return 0
1915 return 0
1916
1916
1917 v = r.version
1917 v = r.version
1918 format = v & 0xFFFF
1918 format = v & 0xFFFF
1919 flags = []
1919 flags = []
1920 gdelta = False
1920 gdelta = False
1921 if v & revlog.REVLOGNGINLINEDATA:
1921 if v & revlog.REVLOGNGINLINEDATA:
1922 flags.append('inline')
1922 flags.append('inline')
1923 if v & revlog.REVLOGGENERALDELTA:
1923 if v & revlog.REVLOGGENERALDELTA:
1924 gdelta = True
1924 gdelta = True
1925 flags.append('generaldelta')
1925 flags.append('generaldelta')
1926 if not flags:
1926 if not flags:
1927 flags = ['(none)']
1927 flags = ['(none)']
1928
1928
1929 nummerges = 0
1929 nummerges = 0
1930 numfull = 0
1930 numfull = 0
1931 numprev = 0
1931 numprev = 0
1932 nump1 = 0
1932 nump1 = 0
1933 nump2 = 0
1933 nump2 = 0
1934 numother = 0
1934 numother = 0
1935 nump1prev = 0
1935 nump1prev = 0
1936 nump2prev = 0
1936 nump2prev = 0
1937 chainlengths = []
1937 chainlengths = []
1938
1938
1939 datasize = [None, 0, 0L]
1939 datasize = [None, 0, 0L]
1940 fullsize = [None, 0, 0L]
1940 fullsize = [None, 0, 0L]
1941 deltasize = [None, 0, 0L]
1941 deltasize = [None, 0, 0L]
1942
1942
1943 def addsize(size, l):
1943 def addsize(size, l):
1944 if l[0] is None or size < l[0]:
1944 if l[0] is None or size < l[0]:
1945 l[0] = size
1945 l[0] = size
1946 if size > l[1]:
1946 if size > l[1]:
1947 l[1] = size
1947 l[1] = size
1948 l[2] += size
1948 l[2] += size
1949
1949
1950 numrevs = len(r)
1950 numrevs = len(r)
1951 for rev in xrange(numrevs):
1951 for rev in xrange(numrevs):
1952 p1, p2 = r.parentrevs(rev)
1952 p1, p2 = r.parentrevs(rev)
1953 delta = r.deltaparent(rev)
1953 delta = r.deltaparent(rev)
1954 if format > 0:
1954 if format > 0:
1955 addsize(r.rawsize(rev), datasize)
1955 addsize(r.rawsize(rev), datasize)
1956 if p2 != nullrev:
1956 if p2 != nullrev:
1957 nummerges += 1
1957 nummerges += 1
1958 size = r.length(rev)
1958 size = r.length(rev)
1959 if delta == nullrev:
1959 if delta == nullrev:
1960 chainlengths.append(0)
1960 chainlengths.append(0)
1961 numfull += 1
1961 numfull += 1
1962 addsize(size, fullsize)
1962 addsize(size, fullsize)
1963 else:
1963 else:
1964 chainlengths.append(chainlengths[delta] + 1)
1964 chainlengths.append(chainlengths[delta] + 1)
1965 addsize(size, deltasize)
1965 addsize(size, deltasize)
1966 if delta == rev - 1:
1966 if delta == rev - 1:
1967 numprev += 1
1967 numprev += 1
1968 if delta == p1:
1968 if delta == p1:
1969 nump1prev += 1
1969 nump1prev += 1
1970 elif delta == p2:
1970 elif delta == p2:
1971 nump2prev += 1
1971 nump2prev += 1
1972 elif delta == p1:
1972 elif delta == p1:
1973 nump1 += 1
1973 nump1 += 1
1974 elif delta == p2:
1974 elif delta == p2:
1975 nump2 += 1
1975 nump2 += 1
1976 elif delta != nullrev:
1976 elif delta != nullrev:
1977 numother += 1
1977 numother += 1
1978
1978
1979 numdeltas = numrevs - numfull
1979 numdeltas = numrevs - numfull
1980 numoprev = numprev - nump1prev - nump2prev
1980 numoprev = numprev - nump1prev - nump2prev
1981 totalrawsize = datasize[2]
1981 totalrawsize = datasize[2]
1982 datasize[2] /= numrevs
1982 datasize[2] /= numrevs
1983 fulltotal = fullsize[2]
1983 fulltotal = fullsize[2]
1984 fullsize[2] /= numfull
1984 fullsize[2] /= numfull
1985 deltatotal = deltasize[2]
1985 deltatotal = deltasize[2]
1986 deltasize[2] /= numrevs - numfull
1986 deltasize[2] /= numrevs - numfull
1987 totalsize = fulltotal + deltatotal
1987 totalsize = fulltotal + deltatotal
1988 avgchainlen = sum(chainlengths) / numrevs
1988 avgchainlen = sum(chainlengths) / numrevs
1989 compratio = totalrawsize / totalsize
1989 compratio = totalrawsize / totalsize
1990
1990
1991 basedfmtstr = '%%%dd\n'
1991 basedfmtstr = '%%%dd\n'
1992 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1992 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1993
1993
1994 def dfmtstr(max):
1994 def dfmtstr(max):
1995 return basedfmtstr % len(str(max))
1995 return basedfmtstr % len(str(max))
1996 def pcfmtstr(max, padding=0):
1996 def pcfmtstr(max, padding=0):
1997 return basepcfmtstr % (len(str(max)), ' ' * padding)
1997 return basepcfmtstr % (len(str(max)), ' ' * padding)
1998
1998
1999 def pcfmt(value, total):
1999 def pcfmt(value, total):
2000 return (value, 100 * float(value) / total)
2000 return (value, 100 * float(value) / total)
2001
2001
2002 ui.write('format : %d\n' % format)
2002 ui.write('format : %d\n' % format)
2003 ui.write('flags : %s\n' % ', '.join(flags))
2003 ui.write('flags : %s\n' % ', '.join(flags))
2004
2004
2005 ui.write('\n')
2005 ui.write('\n')
2006 fmt = pcfmtstr(totalsize)
2006 fmt = pcfmtstr(totalsize)
2007 fmt2 = dfmtstr(totalsize)
2007 fmt2 = dfmtstr(totalsize)
2008 ui.write('revisions : ' + fmt2 % numrevs)
2008 ui.write('revisions : ' + fmt2 % numrevs)
2009 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2009 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2010 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2010 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2011 ui.write('revisions : ' + fmt2 % numrevs)
2011 ui.write('revisions : ' + fmt2 % numrevs)
2012 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2012 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2013 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2013 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2014 ui.write('revision size : ' + fmt2 % totalsize)
2014 ui.write('revision size : ' + fmt2 % totalsize)
2015 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2015 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2016 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2016 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2017
2017
2018 ui.write('\n')
2018 ui.write('\n')
2019 fmt = dfmtstr(max(avgchainlen, compratio))
2019 fmt = dfmtstr(max(avgchainlen, compratio))
2020 ui.write('avg chain length : ' + fmt % avgchainlen)
2020 ui.write('avg chain length : ' + fmt % avgchainlen)
2021 ui.write('compression ratio : ' + fmt % compratio)
2021 ui.write('compression ratio : ' + fmt % compratio)
2022
2022
2023 if format > 0:
2023 if format > 0:
2024 ui.write('\n')
2024 ui.write('\n')
2025 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2025 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2026 % tuple(datasize))
2026 % tuple(datasize))
2027 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2027 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2028 % tuple(fullsize))
2028 % tuple(fullsize))
2029 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2029 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2030 % tuple(deltasize))
2030 % tuple(deltasize))
2031
2031
2032 if numdeltas > 0:
2032 if numdeltas > 0:
2033 ui.write('\n')
2033 ui.write('\n')
2034 fmt = pcfmtstr(numdeltas)
2034 fmt = pcfmtstr(numdeltas)
2035 fmt2 = pcfmtstr(numdeltas, 4)
2035 fmt2 = pcfmtstr(numdeltas, 4)
2036 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2036 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2037 if numprev > 0:
2037 if numprev > 0:
2038 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2038 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2039 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2039 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2040 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2040 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2041 if gdelta:
2041 if gdelta:
2042 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2042 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2043 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2043 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2044 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2044 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2045
2045
2046 @command('debugrevspec', [], ('REVSPEC'))
2046 @command('debugrevspec', [], ('REVSPEC'))
2047 def debugrevspec(ui, repo, expr):
2047 def debugrevspec(ui, repo, expr):
2048 '''parse and apply a revision specification'''
2048 '''parse and apply a revision specification'''
2049 if ui.verbose:
2049 if ui.verbose:
2050 tree = revset.parse(expr)[0]
2050 tree = revset.parse(expr)[0]
2051 ui.note(tree, "\n")
2051 ui.note(tree, "\n")
2052 newtree = revset.findaliases(ui, tree)
2052 newtree = revset.findaliases(ui, tree)
2053 if newtree != tree:
2053 if newtree != tree:
2054 ui.note(newtree, "\n")
2054 ui.note(newtree, "\n")
2055 func = revset.match(ui, expr)
2055 func = revset.match(ui, expr)
2056 for c in func(repo, range(len(repo))):
2056 for c in func(repo, range(len(repo))):
2057 ui.write("%s\n" % c)
2057 ui.write("%s\n" % c)
2058
2058
2059 @command('debugsetparents', [], _('REV1 [REV2]'))
2059 @command('debugsetparents', [], _('REV1 [REV2]'))
2060 def debugsetparents(ui, repo, rev1, rev2=None):
2060 def debugsetparents(ui, repo, rev1, rev2=None):
2061 """manually set the parents of the current working directory
2061 """manually set the parents of the current working directory
2062
2062
2063 This is useful for writing repository conversion tools, but should
2063 This is useful for writing repository conversion tools, but should
2064 be used with care.
2064 be used with care.
2065
2065
2066 Returns 0 on success.
2066 Returns 0 on success.
2067 """
2067 """
2068
2068
2069 r1 = scmutil.revsingle(repo, rev1).node()
2069 r1 = scmutil.revsingle(repo, rev1).node()
2070 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2070 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2071
2071
2072 wlock = repo.wlock()
2072 wlock = repo.wlock()
2073 try:
2073 try:
2074 repo.dirstate.setparents(r1, r2)
2074 repo.dirstate.setparents(r1, r2)
2075 finally:
2075 finally:
2076 wlock.release()
2076 wlock.release()
2077
2077
2078 @command('debugstate',
2078 @command('debugstate',
2079 [('', 'nodates', None, _('do not display the saved mtime')),
2079 [('', 'nodates', None, _('do not display the saved mtime')),
2080 ('', 'datesort', None, _('sort by saved mtime'))],
2080 ('', 'datesort', None, _('sort by saved mtime'))],
2081 _('[OPTION]...'))
2081 _('[OPTION]...'))
2082 def debugstate(ui, repo, nodates=None, datesort=None):
2082 def debugstate(ui, repo, nodates=None, datesort=None):
2083 """show the contents of the current dirstate"""
2083 """show the contents of the current dirstate"""
2084 timestr = ""
2084 timestr = ""
2085 showdate = not nodates
2085 showdate = not nodates
2086 if datesort:
2086 if datesort:
2087 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2087 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2088 else:
2088 else:
2089 keyfunc = None # sort by filename
2089 keyfunc = None # sort by filename
2090 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2090 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2091 if showdate:
2091 if showdate:
2092 if ent[3] == -1:
2092 if ent[3] == -1:
2093 # Pad or slice to locale representation
2093 # Pad or slice to locale representation
2094 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2094 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2095 time.localtime(0)))
2095 time.localtime(0)))
2096 timestr = 'unset'
2096 timestr = 'unset'
2097 timestr = (timestr[:locale_len] +
2097 timestr = (timestr[:locale_len] +
2098 ' ' * (locale_len - len(timestr)))
2098 ' ' * (locale_len - len(timestr)))
2099 else:
2099 else:
2100 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2100 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2101 time.localtime(ent[3]))
2101 time.localtime(ent[3]))
2102 if ent[1] & 020000:
2102 if ent[1] & 020000:
2103 mode = 'lnk'
2103 mode = 'lnk'
2104 else:
2104 else:
2105 mode = '%3o' % (ent[1] & 0777)
2105 mode = '%3o' % (ent[1] & 0777)
2106 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2106 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2107 for f in repo.dirstate.copies():
2107 for f in repo.dirstate.copies():
2108 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2108 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2109
2109
2110 @command('debugsub',
2110 @command('debugsub',
2111 [('r', 'rev', '',
2111 [('r', 'rev', '',
2112 _('revision to check'), _('REV'))],
2112 _('revision to check'), _('REV'))],
2113 _('[-r REV] [REV]'))
2113 _('[-r REV] [REV]'))
2114 def debugsub(ui, repo, rev=None):
2114 def debugsub(ui, repo, rev=None):
2115 ctx = scmutil.revsingle(repo, rev, None)
2115 ctx = scmutil.revsingle(repo, rev, None)
2116 for k, v in sorted(ctx.substate.items()):
2116 for k, v in sorted(ctx.substate.items()):
2117 ui.write('path %s\n' % k)
2117 ui.write('path %s\n' % k)
2118 ui.write(' source %s\n' % v[0])
2118 ui.write(' source %s\n' % v[0])
2119 ui.write(' revision %s\n' % v[1])
2119 ui.write(' revision %s\n' % v[1])
2120
2120
2121 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2121 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2122 def debugwalk(ui, repo, *pats, **opts):
2122 def debugwalk(ui, repo, *pats, **opts):
2123 """show how files match on given patterns"""
2123 """show how files match on given patterns"""
2124 m = scmutil.match(repo[None], pats, opts)
2124 m = scmutil.match(repo[None], pats, opts)
2125 items = list(repo.walk(m))
2125 items = list(repo.walk(m))
2126 if not items:
2126 if not items:
2127 return
2127 return
2128 fmt = 'f %%-%ds %%-%ds %%s' % (
2128 fmt = 'f %%-%ds %%-%ds %%s' % (
2129 max([len(abs) for abs in items]),
2129 max([len(abs) for abs in items]),
2130 max([len(m.rel(abs)) for abs in items]))
2130 max([len(m.rel(abs)) for abs in items]))
2131 for abs in items:
2131 for abs in items:
2132 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2132 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2133 ui.write("%s\n" % line.rstrip())
2133 ui.write("%s\n" % line.rstrip())
2134
2134
2135 @command('debugwireargs',
2135 @command('debugwireargs',
2136 [('', 'three', '', 'three'),
2136 [('', 'three', '', 'three'),
2137 ('', 'four', '', 'four'),
2137 ('', 'four', '', 'four'),
2138 ('', 'five', '', 'five'),
2138 ('', 'five', '', 'five'),
2139 ] + remoteopts,
2139 ] + remoteopts,
2140 _('REPO [OPTIONS]... [ONE [TWO]]'))
2140 _('REPO [OPTIONS]... [ONE [TWO]]'))
2141 def debugwireargs(ui, repopath, *vals, **opts):
2141 def debugwireargs(ui, repopath, *vals, **opts):
2142 repo = hg.peer(ui, opts, repopath)
2142 repo = hg.peer(ui, opts, repopath)
2143 for opt in remoteopts:
2143 for opt in remoteopts:
2144 del opts[opt[1]]
2144 del opts[opt[1]]
2145 args = {}
2145 args = {}
2146 for k, v in opts.iteritems():
2146 for k, v in opts.iteritems():
2147 if v:
2147 if v:
2148 args[k] = v
2148 args[k] = v
2149 # run twice to check that we don't mess up the stream for the next command
2149 # run twice to check that we don't mess up the stream for the next command
2150 res1 = repo.debugwireargs(*vals, **args)
2150 res1 = repo.debugwireargs(*vals, **args)
2151 res2 = repo.debugwireargs(*vals, **args)
2151 res2 = repo.debugwireargs(*vals, **args)
2152 ui.write("%s\n" % res1)
2152 ui.write("%s\n" % res1)
2153 if res1 != res2:
2153 if res1 != res2:
2154 ui.warn("%s\n" % res2)
2154 ui.warn("%s\n" % res2)
2155
2155
2156 @command('^diff',
2156 @command('^diff',
2157 [('r', 'rev', [], _('revision'), _('REV')),
2157 [('r', 'rev', [], _('revision'), _('REV')),
2158 ('c', 'change', '', _('change made by revision'), _('REV'))
2158 ('c', 'change', '', _('change made by revision'), _('REV'))
2159 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2159 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2160 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2160 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2161 def diff(ui, repo, *pats, **opts):
2161 def diff(ui, repo, *pats, **opts):
2162 """diff repository (or selected files)
2162 """diff repository (or selected files)
2163
2163
2164 Show differences between revisions for the specified files.
2164 Show differences between revisions for the specified files.
2165
2165
2166 Differences between files are shown using the unified diff format.
2166 Differences between files are shown using the unified diff format.
2167
2167
2168 .. note::
2168 .. note::
2169 diff may generate unexpected results for merges, as it will
2169 diff may generate unexpected results for merges, as it will
2170 default to comparing against the working directory's first
2170 default to comparing against the working directory's first
2171 parent changeset if no revisions are specified.
2171 parent changeset if no revisions are specified.
2172
2172
2173 When two revision arguments are given, then changes are shown
2173 When two revision arguments are given, then changes are shown
2174 between those revisions. If only one revision is specified then
2174 between those revisions. If only one revision is specified then
2175 that revision is compared to the working directory, and, when no
2175 that revision is compared to the working directory, and, when no
2176 revisions are specified, the working directory files are compared
2176 revisions are specified, the working directory files are compared
2177 to its parent.
2177 to its parent.
2178
2178
2179 Alternatively you can specify -c/--change with a revision to see
2179 Alternatively you can specify -c/--change with a revision to see
2180 the changes in that changeset relative to its first parent.
2180 the changes in that changeset relative to its first parent.
2181
2181
2182 Without the -a/--text option, diff will avoid generating diffs of
2182 Without the -a/--text option, diff will avoid generating diffs of
2183 files it detects as binary. With -a, diff will generate a diff
2183 files it detects as binary. With -a, diff will generate a diff
2184 anyway, probably with undesirable results.
2184 anyway, probably with undesirable results.
2185
2185
2186 Use the -g/--git option to generate diffs in the git extended diff
2186 Use the -g/--git option to generate diffs in the git extended diff
2187 format. For more information, read :hg:`help diffs`.
2187 format. For more information, read :hg:`help diffs`.
2188
2188
2189 .. container:: verbose
2189 .. container:: verbose
2190
2190
2191 Examples:
2191 Examples:
2192
2192
2193 - compare a file in the current working directory to its parent::
2193 - compare a file in the current working directory to its parent::
2194
2194
2195 hg diff foo.c
2195 hg diff foo.c
2196
2196
2197 - compare two historical versions of a directory, with rename info::
2197 - compare two historical versions of a directory, with rename info::
2198
2198
2199 hg diff --git -r 1.0:1.2 lib/
2199 hg diff --git -r 1.0:1.2 lib/
2200
2200
2201 - get change stats relative to the last change on some date::
2201 - get change stats relative to the last change on some date::
2202
2202
2203 hg diff --stat -r "date('may 2')"
2203 hg diff --stat -r "date('may 2')"
2204
2204
2205 - diff all newly-added files that contain a keyword::
2205 - diff all newly-added files that contain a keyword::
2206
2206
2207 hg diff "set:added() and grep(GNU)"
2207 hg diff "set:added() and grep(GNU)"
2208
2208
2209 - compare a revision and its parents::
2209 - compare a revision and its parents::
2210
2210
2211 hg diff -c 9353 # compare against first parent
2211 hg diff -c 9353 # compare against first parent
2212 hg diff -r 9353^:9353 # same using revset syntax
2212 hg diff -r 9353^:9353 # same using revset syntax
2213 hg diff -r 9353^2:9353 # compare against the second parent
2213 hg diff -r 9353^2:9353 # compare against the second parent
2214
2214
2215 Returns 0 on success.
2215 Returns 0 on success.
2216 """
2216 """
2217
2217
2218 revs = opts.get('rev')
2218 revs = opts.get('rev')
2219 change = opts.get('change')
2219 change = opts.get('change')
2220 stat = opts.get('stat')
2220 stat = opts.get('stat')
2221 reverse = opts.get('reverse')
2221 reverse = opts.get('reverse')
2222
2222
2223 if revs and change:
2223 if revs and change:
2224 msg = _('cannot specify --rev and --change at the same time')
2224 msg = _('cannot specify --rev and --change at the same time')
2225 raise util.Abort(msg)
2225 raise util.Abort(msg)
2226 elif change:
2226 elif change:
2227 node2 = scmutil.revsingle(repo, change, None).node()
2227 node2 = scmutil.revsingle(repo, change, None).node()
2228 node1 = repo[node2].p1().node()
2228 node1 = repo[node2].p1().node()
2229 else:
2229 else:
2230 node1, node2 = scmutil.revpair(repo, revs)
2230 node1, node2 = scmutil.revpair(repo, revs)
2231
2231
2232 if reverse:
2232 if reverse:
2233 node1, node2 = node2, node1
2233 node1, node2 = node2, node1
2234
2234
2235 diffopts = patch.diffopts(ui, opts)
2235 diffopts = patch.diffopts(ui, opts)
2236 m = scmutil.match(repo[node2], pats, opts)
2236 m = scmutil.match(repo[node2], pats, opts)
2237 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2237 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2238 listsubrepos=opts.get('subrepos'))
2238 listsubrepos=opts.get('subrepos'))
2239
2239
2240 @command('^export',
2240 @command('^export',
2241 [('o', 'output', '',
2241 [('o', 'output', '',
2242 _('print output to file with formatted name'), _('FORMAT')),
2242 _('print output to file with formatted name'), _('FORMAT')),
2243 ('', 'switch-parent', None, _('diff against the second parent')),
2243 ('', 'switch-parent', None, _('diff against the second parent')),
2244 ('r', 'rev', [], _('revisions to export'), _('REV')),
2244 ('r', 'rev', [], _('revisions to export'), _('REV')),
2245 ] + diffopts,
2245 ] + diffopts,
2246 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2246 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2247 def export(ui, repo, *changesets, **opts):
2247 def export(ui, repo, *changesets, **opts):
2248 """dump the header and diffs for one or more changesets
2248 """dump the header and diffs for one or more changesets
2249
2249
2250 Print the changeset header and diffs for one or more revisions.
2250 Print the changeset header and diffs for one or more revisions.
2251
2251
2252 The information shown in the changeset header is: author, date,
2252 The information shown in the changeset header is: author, date,
2253 branch name (if non-default), changeset hash, parent(s) and commit
2253 branch name (if non-default), changeset hash, parent(s) and commit
2254 comment.
2254 comment.
2255
2255
2256 .. note::
2256 .. note::
2257 export may generate unexpected diff output for merge
2257 export may generate unexpected diff output for merge
2258 changesets, as it will compare the merge changeset against its
2258 changesets, as it will compare the merge changeset against its
2259 first parent only.
2259 first parent only.
2260
2260
2261 Output may be to a file, in which case the name of the file is
2261 Output may be to a file, in which case the name of the file is
2262 given using a format string. The formatting rules are as follows:
2262 given using a format string. The formatting rules are as follows:
2263
2263
2264 :``%%``: literal "%" character
2264 :``%%``: literal "%" character
2265 :``%H``: changeset hash (40 hexadecimal digits)
2265 :``%H``: changeset hash (40 hexadecimal digits)
2266 :``%N``: number of patches being generated
2266 :``%N``: number of patches being generated
2267 :``%R``: changeset revision number
2267 :``%R``: changeset revision number
2268 :``%b``: basename of the exporting repository
2268 :``%b``: basename of the exporting repository
2269 :``%h``: short-form changeset hash (12 hexadecimal digits)
2269 :``%h``: short-form changeset hash (12 hexadecimal digits)
2270 :``%m``: first line of the commit message (only alphanumeric characters)
2270 :``%m``: first line of the commit message (only alphanumeric characters)
2271 :``%n``: zero-padded sequence number, starting at 1
2271 :``%n``: zero-padded sequence number, starting at 1
2272 :``%r``: zero-padded changeset revision number
2272 :``%r``: zero-padded changeset revision number
2273
2273
2274 Without the -a/--text option, export will avoid generating diffs
2274 Without the -a/--text option, export will avoid generating diffs
2275 of files it detects as binary. With -a, export will generate a
2275 of files it detects as binary. With -a, export will generate a
2276 diff anyway, probably with undesirable results.
2276 diff anyway, probably with undesirable results.
2277
2277
2278 Use the -g/--git option to generate diffs in the git extended diff
2278 Use the -g/--git option to generate diffs in the git extended diff
2279 format. See :hg:`help diffs` for more information.
2279 format. See :hg:`help diffs` for more information.
2280
2280
2281 With the --switch-parent option, the diff will be against the
2281 With the --switch-parent option, the diff will be against the
2282 second parent. It can be useful to review a merge.
2282 second parent. It can be useful to review a merge.
2283
2283
2284 .. container:: verbose
2284 .. container:: verbose
2285
2285
2286 Examples:
2286 Examples:
2287
2287
2288 - use export and import to transplant a bugfix to the current
2288 - use export and import to transplant a bugfix to the current
2289 branch::
2289 branch::
2290
2290
2291 hg export -r 9353 | hg import -
2291 hg export -r 9353 | hg import -
2292
2292
2293 - export all the changesets between two revisions to a file with
2293 - export all the changesets between two revisions to a file with
2294 rename information::
2294 rename information::
2295
2295
2296 hg export --git -r 123:150 > changes.txt
2296 hg export --git -r 123:150 > changes.txt
2297
2297
2298 - split outgoing changes into a series of patches with
2298 - split outgoing changes into a series of patches with
2299 descriptive names::
2299 descriptive names::
2300
2300
2301 hg export -r "outgoing()" -o "%n-%m.patch"
2301 hg export -r "outgoing()" -o "%n-%m.patch"
2302
2302
2303 Returns 0 on success.
2303 Returns 0 on success.
2304 """
2304 """
2305 changesets += tuple(opts.get('rev', []))
2305 changesets += tuple(opts.get('rev', []))
2306 if not changesets:
2306 if not changesets:
2307 raise util.Abort(_("export requires at least one changeset"))
2307 raise util.Abort(_("export requires at least one changeset"))
2308 revs = scmutil.revrange(repo, changesets)
2308 revs = scmutil.revrange(repo, changesets)
2309 if len(revs) > 1:
2309 if len(revs) > 1:
2310 ui.note(_('exporting patches:\n'))
2310 ui.note(_('exporting patches:\n'))
2311 else:
2311 else:
2312 ui.note(_('exporting patch:\n'))
2312 ui.note(_('exporting patch:\n'))
2313 cmdutil.export(repo, revs, template=opts.get('output'),
2313 cmdutil.export(repo, revs, template=opts.get('output'),
2314 switch_parent=opts.get('switch_parent'),
2314 switch_parent=opts.get('switch_parent'),
2315 opts=patch.diffopts(ui, opts))
2315 opts=patch.diffopts(ui, opts))
2316
2316
2317 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2317 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2318 def forget(ui, repo, *pats, **opts):
2318 def forget(ui, repo, *pats, **opts):
2319 """forget the specified files on the next commit
2319 """forget the specified files on the next commit
2320
2320
2321 Mark the specified files so they will no longer be tracked
2321 Mark the specified files so they will no longer be tracked
2322 after the next commit.
2322 after the next commit.
2323
2323
2324 This only removes files from the current branch, not from the
2324 This only removes files from the current branch, not from the
2325 entire project history, and it does not delete them from the
2325 entire project history, and it does not delete them from the
2326 working directory.
2326 working directory.
2327
2327
2328 To undo a forget before the next commit, see :hg:`add`.
2328 To undo a forget before the next commit, see :hg:`add`.
2329
2329
2330 .. container:: verbose
2330 .. container:: verbose
2331
2331
2332 Examples:
2332 Examples:
2333
2333
2334 - forget newly-added binary files::
2334 - forget newly-added binary files::
2335
2335
2336 hg forget "set:added() and binary()"
2336 hg forget "set:added() and binary()"
2337
2337
2338 - forget files that would be excluded by .hgignore::
2338 - forget files that would be excluded by .hgignore::
2339
2339
2340 hg forget "set:hgignore()"
2340 hg forget "set:hgignore()"
2341
2341
2342 Returns 0 on success.
2342 Returns 0 on success.
2343 """
2343 """
2344
2344
2345 if not pats:
2345 if not pats:
2346 raise util.Abort(_('no files specified'))
2346 raise util.Abort(_('no files specified'))
2347
2347
2348 m = scmutil.match(repo[None], pats, opts)
2348 m = scmutil.match(repo[None], pats, opts)
2349 s = repo.status(match=m, clean=True)
2349 s = repo.status(match=m, clean=True)
2350 forget = sorted(s[0] + s[1] + s[3] + s[6])
2350 forget = sorted(s[0] + s[1] + s[3] + s[6])
2351 errs = 0
2351 errs = 0
2352
2352
2353 for f in m.files():
2353 for f in m.files():
2354 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2354 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2355 if os.path.exists(m.rel(f)):
2355 if os.path.exists(m.rel(f)):
2356 ui.warn(_('not removing %s: file is already untracked\n')
2356 ui.warn(_('not removing %s: file is already untracked\n')
2357 % m.rel(f))
2357 % m.rel(f))
2358 errs = 1
2358 errs = 1
2359
2359
2360 for f in forget:
2360 for f in forget:
2361 if ui.verbose or not m.exact(f):
2361 if ui.verbose or not m.exact(f):
2362 ui.status(_('removing %s\n') % m.rel(f))
2362 ui.status(_('removing %s\n') % m.rel(f))
2363
2363
2364 repo[None].forget(forget)
2364 repo[None].forget(forget)
2365 return errs
2365 return errs
2366
2366
2367 @command('grep',
2367 @command('grep',
2368 [('0', 'print0', None, _('end fields with NUL')),
2368 [('0', 'print0', None, _('end fields with NUL')),
2369 ('', 'all', None, _('print all revisions that match')),
2369 ('', 'all', None, _('print all revisions that match')),
2370 ('a', 'text', None, _('treat all files as text')),
2370 ('a', 'text', None, _('treat all files as text')),
2371 ('f', 'follow', None,
2371 ('f', 'follow', None,
2372 _('follow changeset history,'
2372 _('follow changeset history,'
2373 ' or file history across copies and renames')),
2373 ' or file history across copies and renames')),
2374 ('i', 'ignore-case', None, _('ignore case when matching')),
2374 ('i', 'ignore-case', None, _('ignore case when matching')),
2375 ('l', 'files-with-matches', None,
2375 ('l', 'files-with-matches', None,
2376 _('print only filenames and revisions that match')),
2376 _('print only filenames and revisions that match')),
2377 ('n', 'line-number', None, _('print matching line numbers')),
2377 ('n', 'line-number', None, _('print matching line numbers')),
2378 ('r', 'rev', [],
2378 ('r', 'rev', [],
2379 _('only search files changed within revision range'), _('REV')),
2379 _('only search files changed within revision range'), _('REV')),
2380 ('u', 'user', None, _('list the author (long with -v)')),
2380 ('u', 'user', None, _('list the author (long with -v)')),
2381 ('d', 'date', None, _('list the date (short with -q)')),
2381 ('d', 'date', None, _('list the date (short with -q)')),
2382 ] + walkopts,
2382 ] + walkopts,
2383 _('[OPTION]... PATTERN [FILE]...'))
2383 _('[OPTION]... PATTERN [FILE]...'))
2384 def grep(ui, repo, pattern, *pats, **opts):
2384 def grep(ui, repo, pattern, *pats, **opts):
2385 """search for a pattern in specified files and revisions
2385 """search for a pattern in specified files and revisions
2386
2386
2387 Search revisions of files for a regular expression.
2387 Search revisions of files for a regular expression.
2388
2388
2389 This command behaves differently than Unix grep. It only accepts
2389 This command behaves differently than Unix grep. It only accepts
2390 Python/Perl regexps. It searches repository history, not the
2390 Python/Perl regexps. It searches repository history, not the
2391 working directory. It always prints the revision number in which a
2391 working directory. It always prints the revision number in which a
2392 match appears.
2392 match appears.
2393
2393
2394 By default, grep only prints output for the first revision of a
2394 By default, grep only prints output for the first revision of a
2395 file in which it finds a match. To get it to print every revision
2395 file in which it finds a match. To get it to print every revision
2396 that contains a change in match status ("-" for a match that
2396 that contains a change in match status ("-" for a match that
2397 becomes a non-match, or "+" for a non-match that becomes a match),
2397 becomes a non-match, or "+" for a non-match that becomes a match),
2398 use the --all flag.
2398 use the --all flag.
2399
2399
2400 Returns 0 if a match is found, 1 otherwise.
2400 Returns 0 if a match is found, 1 otherwise.
2401 """
2401 """
2402 reflags = 0
2402 reflags = 0
2403 if opts.get('ignore_case'):
2403 if opts.get('ignore_case'):
2404 reflags |= re.I
2404 reflags |= re.I
2405 try:
2405 try:
2406 regexp = re.compile(pattern, reflags)
2406 regexp = re.compile(pattern, reflags)
2407 except re.error, inst:
2407 except re.error, inst:
2408 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2408 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2409 return 1
2409 return 1
2410 sep, eol = ':', '\n'
2410 sep, eol = ':', '\n'
2411 if opts.get('print0'):
2411 if opts.get('print0'):
2412 sep = eol = '\0'
2412 sep = eol = '\0'
2413
2413
2414 getfile = util.lrucachefunc(repo.file)
2414 getfile = util.lrucachefunc(repo.file)
2415
2415
2416 def matchlines(body):
2416 def matchlines(body):
2417 begin = 0
2417 begin = 0
2418 linenum = 0
2418 linenum = 0
2419 while True:
2419 while True:
2420 match = regexp.search(body, begin)
2420 match = regexp.search(body, begin)
2421 if not match:
2421 if not match:
2422 break
2422 break
2423 mstart, mend = match.span()
2423 mstart, mend = match.span()
2424 linenum += body.count('\n', begin, mstart) + 1
2424 linenum += body.count('\n', begin, mstart) + 1
2425 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2425 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2426 begin = body.find('\n', mend) + 1 or len(body)
2426 begin = body.find('\n', mend) + 1 or len(body)
2427 lend = begin - 1
2427 lend = begin - 1
2428 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2428 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2429
2429
2430 class linestate(object):
2430 class linestate(object):
2431 def __init__(self, line, linenum, colstart, colend):
2431 def __init__(self, line, linenum, colstart, colend):
2432 self.line = line
2432 self.line = line
2433 self.linenum = linenum
2433 self.linenum = linenum
2434 self.colstart = colstart
2434 self.colstart = colstart
2435 self.colend = colend
2435 self.colend = colend
2436
2436
2437 def __hash__(self):
2437 def __hash__(self):
2438 return hash((self.linenum, self.line))
2438 return hash((self.linenum, self.line))
2439
2439
2440 def __eq__(self, other):
2440 def __eq__(self, other):
2441 return self.line == other.line
2441 return self.line == other.line
2442
2442
2443 matches = {}
2443 matches = {}
2444 copies = {}
2444 copies = {}
2445 def grepbody(fn, rev, body):
2445 def grepbody(fn, rev, body):
2446 matches[rev].setdefault(fn, [])
2446 matches[rev].setdefault(fn, [])
2447 m = matches[rev][fn]
2447 m = matches[rev][fn]
2448 for lnum, cstart, cend, line in matchlines(body):
2448 for lnum, cstart, cend, line in matchlines(body):
2449 s = linestate(line, lnum, cstart, cend)
2449 s = linestate(line, lnum, cstart, cend)
2450 m.append(s)
2450 m.append(s)
2451
2451
2452 def difflinestates(a, b):
2452 def difflinestates(a, b):
2453 sm = difflib.SequenceMatcher(None, a, b)
2453 sm = difflib.SequenceMatcher(None, a, b)
2454 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2454 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2455 if tag == 'insert':
2455 if tag == 'insert':
2456 for i in xrange(blo, bhi):
2456 for i in xrange(blo, bhi):
2457 yield ('+', b[i])
2457 yield ('+', b[i])
2458 elif tag == 'delete':
2458 elif tag == 'delete':
2459 for i in xrange(alo, ahi):
2459 for i in xrange(alo, ahi):
2460 yield ('-', a[i])
2460 yield ('-', a[i])
2461 elif tag == 'replace':
2461 elif tag == 'replace':
2462 for i in xrange(alo, ahi):
2462 for i in xrange(alo, ahi):
2463 yield ('-', a[i])
2463 yield ('-', a[i])
2464 for i in xrange(blo, bhi):
2464 for i in xrange(blo, bhi):
2465 yield ('+', b[i])
2465 yield ('+', b[i])
2466
2466
2467 def display(fn, ctx, pstates, states):
2467 def display(fn, ctx, pstates, states):
2468 rev = ctx.rev()
2468 rev = ctx.rev()
2469 datefunc = ui.quiet and util.shortdate or util.datestr
2469 datefunc = ui.quiet and util.shortdate or util.datestr
2470 found = False
2470 found = False
2471 filerevmatches = {}
2471 filerevmatches = {}
2472 def binary():
2472 def binary():
2473 flog = getfile(fn)
2473 flog = getfile(fn)
2474 return util.binary(flog.read(ctx.filenode(fn)))
2474 return util.binary(flog.read(ctx.filenode(fn)))
2475
2475
2476 if opts.get('all'):
2476 if opts.get('all'):
2477 iter = difflinestates(pstates, states)
2477 iter = difflinestates(pstates, states)
2478 else:
2478 else:
2479 iter = [('', l) for l in states]
2479 iter = [('', l) for l in states]
2480 for change, l in iter:
2480 for change, l in iter:
2481 cols = [fn, str(rev)]
2481 cols = [fn, str(rev)]
2482 before, match, after = None, None, None
2482 before, match, after = None, None, None
2483 if opts.get('line_number'):
2483 if opts.get('line_number'):
2484 cols.append(str(l.linenum))
2484 cols.append(str(l.linenum))
2485 if opts.get('all'):
2485 if opts.get('all'):
2486 cols.append(change)
2486 cols.append(change)
2487 if opts.get('user'):
2487 if opts.get('user'):
2488 cols.append(ui.shortuser(ctx.user()))
2488 cols.append(ui.shortuser(ctx.user()))
2489 if opts.get('date'):
2489 if opts.get('date'):
2490 cols.append(datefunc(ctx.date()))
2490 cols.append(datefunc(ctx.date()))
2491 if opts.get('files_with_matches'):
2491 if opts.get('files_with_matches'):
2492 c = (fn, rev)
2492 c = (fn, rev)
2493 if c in filerevmatches:
2493 if c in filerevmatches:
2494 continue
2494 continue
2495 filerevmatches[c] = 1
2495 filerevmatches[c] = 1
2496 else:
2496 else:
2497 before = l.line[:l.colstart]
2497 before = l.line[:l.colstart]
2498 match = l.line[l.colstart:l.colend]
2498 match = l.line[l.colstart:l.colend]
2499 after = l.line[l.colend:]
2499 after = l.line[l.colend:]
2500 ui.write(sep.join(cols))
2500 ui.write(sep.join(cols))
2501 if before is not None:
2501 if before is not None:
2502 if not opts.get('text') and binary():
2502 if not opts.get('text') and binary():
2503 ui.write(sep + " Binary file matches")
2503 ui.write(sep + " Binary file matches")
2504 else:
2504 else:
2505 ui.write(sep + before)
2505 ui.write(sep + before)
2506 ui.write(match, label='grep.match')
2506 ui.write(match, label='grep.match')
2507 ui.write(after)
2507 ui.write(after)
2508 ui.write(eol)
2508 ui.write(eol)
2509 found = True
2509 found = True
2510 return found
2510 return found
2511
2511
2512 skip = {}
2512 skip = {}
2513 revfiles = {}
2513 revfiles = {}
2514 matchfn = scmutil.match(repo[None], pats, opts)
2514 matchfn = scmutil.match(repo[None], pats, opts)
2515 found = False
2515 found = False
2516 follow = opts.get('follow')
2516 follow = opts.get('follow')
2517
2517
2518 def prep(ctx, fns):
2518 def prep(ctx, fns):
2519 rev = ctx.rev()
2519 rev = ctx.rev()
2520 pctx = ctx.p1()
2520 pctx = ctx.p1()
2521 parent = pctx.rev()
2521 parent = pctx.rev()
2522 matches.setdefault(rev, {})
2522 matches.setdefault(rev, {})
2523 matches.setdefault(parent, {})
2523 matches.setdefault(parent, {})
2524 files = revfiles.setdefault(rev, [])
2524 files = revfiles.setdefault(rev, [])
2525 for fn in fns:
2525 for fn in fns:
2526 flog = getfile(fn)
2526 flog = getfile(fn)
2527 try:
2527 try:
2528 fnode = ctx.filenode(fn)
2528 fnode = ctx.filenode(fn)
2529 except error.LookupError:
2529 except error.LookupError:
2530 continue
2530 continue
2531
2531
2532 copied = flog.renamed(fnode)
2532 copied = flog.renamed(fnode)
2533 copy = follow and copied and copied[0]
2533 copy = follow and copied and copied[0]
2534 if copy:
2534 if copy:
2535 copies.setdefault(rev, {})[fn] = copy
2535 copies.setdefault(rev, {})[fn] = copy
2536 if fn in skip:
2536 if fn in skip:
2537 if copy:
2537 if copy:
2538 skip[copy] = True
2538 skip[copy] = True
2539 continue
2539 continue
2540 files.append(fn)
2540 files.append(fn)
2541
2541
2542 if fn not in matches[rev]:
2542 if fn not in matches[rev]:
2543 grepbody(fn, rev, flog.read(fnode))
2543 grepbody(fn, rev, flog.read(fnode))
2544
2544
2545 pfn = copy or fn
2545 pfn = copy or fn
2546 if pfn not in matches[parent]:
2546 if pfn not in matches[parent]:
2547 try:
2547 try:
2548 fnode = pctx.filenode(pfn)
2548 fnode = pctx.filenode(pfn)
2549 grepbody(pfn, parent, flog.read(fnode))
2549 grepbody(pfn, parent, flog.read(fnode))
2550 except error.LookupError:
2550 except error.LookupError:
2551 pass
2551 pass
2552
2552
2553 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2553 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2554 rev = ctx.rev()
2554 rev = ctx.rev()
2555 parent = ctx.p1().rev()
2555 parent = ctx.p1().rev()
2556 for fn in sorted(revfiles.get(rev, [])):
2556 for fn in sorted(revfiles.get(rev, [])):
2557 states = matches[rev][fn]
2557 states = matches[rev][fn]
2558 copy = copies.get(rev, {}).get(fn)
2558 copy = copies.get(rev, {}).get(fn)
2559 if fn in skip:
2559 if fn in skip:
2560 if copy:
2560 if copy:
2561 skip[copy] = True
2561 skip[copy] = True
2562 continue
2562 continue
2563 pstates = matches.get(parent, {}).get(copy or fn, [])
2563 pstates = matches.get(parent, {}).get(copy or fn, [])
2564 if pstates or states:
2564 if pstates or states:
2565 r = display(fn, ctx, pstates, states)
2565 r = display(fn, ctx, pstates, states)
2566 found = found or r
2566 found = found or r
2567 if r and not opts.get('all'):
2567 if r and not opts.get('all'):
2568 skip[fn] = True
2568 skip[fn] = True
2569 if copy:
2569 if copy:
2570 skip[copy] = True
2570 skip[copy] = True
2571 del matches[rev]
2571 del matches[rev]
2572 del revfiles[rev]
2572 del revfiles[rev]
2573
2573
2574 return not found
2574 return not found
2575
2575
2576 @command('heads',
2576 @command('heads',
2577 [('r', 'rev', '',
2577 [('r', 'rev', '',
2578 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2578 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2579 ('t', 'topo', False, _('show topological heads only')),
2579 ('t', 'topo', False, _('show topological heads only')),
2580 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2580 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2581 ('c', 'closed', False, _('show normal and closed branch heads')),
2581 ('c', 'closed', False, _('show normal and closed branch heads')),
2582 ] + templateopts,
2582 ] + templateopts,
2583 _('[-ac] [-r STARTREV] [REV]...'))
2583 _('[-ac] [-r STARTREV] [REV]...'))
2584 def heads(ui, repo, *branchrevs, **opts):
2584 def heads(ui, repo, *branchrevs, **opts):
2585 """show current repository heads or show branch heads
2585 """show current repository heads or show branch heads
2586
2586
2587 With no arguments, show all repository branch heads.
2587 With no arguments, show all repository branch heads.
2588
2588
2589 Repository "heads" are changesets with no child changesets. They are
2589 Repository "heads" are changesets with no child changesets. They are
2590 where development generally takes place and are the usual targets
2590 where development generally takes place and are the usual targets
2591 for update and merge operations. Branch heads are changesets that have
2591 for update and merge operations. Branch heads are changesets that have
2592 no child changeset on the same branch.
2592 no child changeset on the same branch.
2593
2593
2594 If one or more REVs are given, only branch heads on the branches
2594 If one or more REVs are given, only branch heads on the branches
2595 associated with the specified changesets are shown. This means
2595 associated with the specified changesets are shown. This means
2596 that you can use :hg:`heads foo` to see the heads on a branch
2596 that you can use :hg:`heads foo` to see the heads on a branch
2597 named ``foo``.
2597 named ``foo``.
2598
2598
2599 If -c/--closed is specified, also show branch heads marked closed
2599 If -c/--closed is specified, also show branch heads marked closed
2600 (see :hg:`commit --close-branch`).
2600 (see :hg:`commit --close-branch`).
2601
2601
2602 If STARTREV is specified, only those heads that are descendants of
2602 If STARTREV is specified, only those heads that are descendants of
2603 STARTREV will be displayed.
2603 STARTREV will be displayed.
2604
2604
2605 If -t/--topo is specified, named branch mechanics will be ignored and only
2605 If -t/--topo is specified, named branch mechanics will be ignored and only
2606 changesets without children will be shown.
2606 changesets without children will be shown.
2607
2607
2608 Returns 0 if matching heads are found, 1 if not.
2608 Returns 0 if matching heads are found, 1 if not.
2609 """
2609 """
2610
2610
2611 start = None
2611 start = None
2612 if 'rev' in opts:
2612 if 'rev' in opts:
2613 start = scmutil.revsingle(repo, opts['rev'], None).node()
2613 start = scmutil.revsingle(repo, opts['rev'], None).node()
2614
2614
2615 if opts.get('topo'):
2615 if opts.get('topo'):
2616 heads = [repo[h] for h in repo.heads(start)]
2616 heads = [repo[h] for h in repo.heads(start)]
2617 else:
2617 else:
2618 heads = []
2618 heads = []
2619 for branch in repo.branchmap():
2619 for branch in repo.branchmap():
2620 heads += repo.branchheads(branch, start, opts.get('closed'))
2620 heads += repo.branchheads(branch, start, opts.get('closed'))
2621 heads = [repo[h] for h in heads]
2621 heads = [repo[h] for h in heads]
2622
2622
2623 if branchrevs:
2623 if branchrevs:
2624 branches = set(repo[br].branch() for br in branchrevs)
2624 branches = set(repo[br].branch() for br in branchrevs)
2625 heads = [h for h in heads if h.branch() in branches]
2625 heads = [h for h in heads if h.branch() in branches]
2626
2626
2627 if opts.get('active') and branchrevs:
2627 if opts.get('active') and branchrevs:
2628 dagheads = repo.heads(start)
2628 dagheads = repo.heads(start)
2629 heads = [h for h in heads if h.node() in dagheads]
2629 heads = [h for h in heads if h.node() in dagheads]
2630
2630
2631 if branchrevs:
2631 if branchrevs:
2632 haveheads = set(h.branch() for h in heads)
2632 haveheads = set(h.branch() for h in heads)
2633 if branches - haveheads:
2633 if branches - haveheads:
2634 headless = ', '.join(b for b in branches - haveheads)
2634 headless = ', '.join(b for b in branches - haveheads)
2635 msg = _('no open branch heads found on branches %s')
2635 msg = _('no open branch heads found on branches %s')
2636 if opts.get('rev'):
2636 if opts.get('rev'):
2637 msg += _(' (started at %s)' % opts['rev'])
2637 msg += _(' (started at %s)' % opts['rev'])
2638 ui.warn((msg + '\n') % headless)
2638 ui.warn((msg + '\n') % headless)
2639
2639
2640 if not heads:
2640 if not heads:
2641 return 1
2641 return 1
2642
2642
2643 heads = sorted(heads, key=lambda x: -x.rev())
2643 heads = sorted(heads, key=lambda x: -x.rev())
2644 displayer = cmdutil.show_changeset(ui, repo, opts)
2644 displayer = cmdutil.show_changeset(ui, repo, opts)
2645 for ctx in heads:
2645 for ctx in heads:
2646 displayer.show(ctx)
2646 displayer.show(ctx)
2647 displayer.close()
2647 displayer.close()
2648
2648
2649 @command('help',
2649 @command('help',
2650 [('e', 'extension', None, _('show only help for extensions')),
2650 [('e', 'extension', None, _('show only help for extensions')),
2651 ('c', 'command', None, _('show only help for commands'))],
2651 ('c', 'command', None, _('show only help for commands'))],
2652 _('[-ec] [TOPIC]'))
2652 _('[-ec] [TOPIC]'))
2653 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2653 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2654 """show help for a given topic or a help overview
2654 """show help for a given topic or a help overview
2655
2655
2656 With no arguments, print a list of commands with short help messages.
2656 With no arguments, print a list of commands with short help messages.
2657
2657
2658 Given a topic, extension, or command name, print help for that
2658 Given a topic, extension, or command name, print help for that
2659 topic.
2659 topic.
2660
2660
2661 Returns 0 if successful.
2661 Returns 0 if successful.
2662 """
2662 """
2663
2663
2664 optlist = []
2664 optlist = []
2665 textwidth = min(ui.termwidth(), 80) - 2
2665 textwidth = min(ui.termwidth(), 80) - 2
2666
2666
2667 # list all option lists
2667 # list all option lists
2668 def opttext(optlist, width):
2668 def opttext(optlist, width):
2669 out = []
2669 out = []
2670 multioccur = False
2670 multioccur = False
2671 for title, options in optlist:
2671 for title, options in optlist:
2672 out.append(("\n%s" % title, None))
2672 out.append(("\n%s" % title, None))
2673 for option in options:
2673 for option in options:
2674 if len(option) == 5:
2674 if len(option) == 5:
2675 shortopt, longopt, default, desc, optlabel = option
2675 shortopt, longopt, default, desc, optlabel = option
2676 else:
2676 else:
2677 shortopt, longopt, default, desc = option
2677 shortopt, longopt, default, desc = option
2678 optlabel = _("VALUE") # default label
2678 optlabel = _("VALUE") # default label
2679
2679
2680 if _("DEPRECATED") in desc and not ui.verbose:
2680 if _("DEPRECATED") in desc and not ui.verbose:
2681 continue
2681 continue
2682 if isinstance(default, list):
2682 if isinstance(default, list):
2683 numqualifier = " %s [+]" % optlabel
2683 numqualifier = " %s [+]" % optlabel
2684 multioccur = True
2684 multioccur = True
2685 elif (default is not None) and not isinstance(default, bool):
2685 elif (default is not None) and not isinstance(default, bool):
2686 numqualifier = " %s" % optlabel
2686 numqualifier = " %s" % optlabel
2687 else:
2687 else:
2688 numqualifier = ""
2688 numqualifier = ""
2689 out.append(("%2s%s" %
2689 out.append(("%2s%s" %
2690 (shortopt and "-%s" % shortopt,
2690 (shortopt and "-%s" % shortopt,
2691 longopt and " --%s%s" %
2691 longopt and " --%s%s" %
2692 (longopt, numqualifier)),
2692 (longopt, numqualifier)),
2693 "%s%s" % (desc,
2693 "%s%s" % (desc,
2694 default
2694 default
2695 and _(" (default: %s)") % default
2695 and _(" (default: %s)") % default
2696 or "")))
2696 or "")))
2697 if multioccur:
2697 if multioccur:
2698 msg = _("\n[+] marked option can be specified multiple times")
2698 msg = _("\n[+] marked option can be specified multiple times")
2699 if ui.verbose and name != 'shortlist':
2699 if ui.verbose and name != 'shortlist':
2700 out.append((msg, None))
2700 out.append((msg, None))
2701 else:
2701 else:
2702 out.insert(-1, (msg, None))
2702 out.insert(-1, (msg, None))
2703
2703
2704 text = ""
2704 text = ""
2705 if out:
2705 if out:
2706 colwidth = encoding.colwidth
2706 colwidth = encoding.colwidth
2707 # normalize: (opt or message, desc or None, width of opt)
2707 # normalize: (opt or message, desc or None, width of opt)
2708 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2708 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2709 for opt, desc in out]
2709 for opt, desc in out]
2710 hanging = max([e[2] for e in entries])
2710 hanging = max([e[2] for e in entries])
2711 for opt, desc, width in entries:
2711 for opt, desc, width in entries:
2712 if desc:
2712 if desc:
2713 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2713 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2714 hangindent = ' ' * (hanging + 3)
2714 hangindent = ' ' * (hanging + 3)
2715 text += '%s\n' % (util.wrap(desc, width,
2715 text += '%s\n' % (util.wrap(desc, width,
2716 initindent=initindent,
2716 initindent=initindent,
2717 hangindent=hangindent))
2717 hangindent=hangindent))
2718 else:
2718 else:
2719 text += "%s\n" % opt
2719 text += "%s\n" % opt
2720
2720
2721 return text
2721 return text
2722
2722
2723 def addglobalopts(aliases):
2723 def addglobalopts(aliases):
2724 if ui.verbose:
2724 if ui.verbose:
2725 optlist.append((_("global options:"), globalopts))
2725 optlist.append((_("global options:"), globalopts))
2726 if name == 'shortlist':
2726 if name == 'shortlist':
2727 optlist.append((_('use "hg help" for the full list '
2727 optlist.append((_('use "hg help" for the full list '
2728 'of commands'), ()))
2728 'of commands'), ()))
2729 else:
2729 else:
2730 if name == 'shortlist':
2730 if name == 'shortlist':
2731 msg = _('use "hg help" for the full list of commands '
2731 msg = _('use "hg help" for the full list of commands '
2732 'or "hg -v" for details')
2732 'or "hg -v" for details')
2733 elif name and not full:
2733 elif name and not full:
2734 msg = _('use "hg help %s" to show the full help text' % name)
2734 msg = _('use "hg help %s" to show the full help text' % name)
2735 elif aliases:
2735 elif aliases:
2736 msg = _('use "hg -v help%s" to show builtin aliases and '
2736 msg = _('use "hg -v help%s" to show builtin aliases and '
2737 'global options') % (name and " " + name or "")
2737 'global options') % (name and " " + name or "")
2738 else:
2738 else:
2739 msg = _('use "hg -v help %s" to show global options') % name
2739 msg = _('use "hg -v help %s" to show global options') % name
2740 optlist.append((msg, ()))
2740 optlist.append((msg, ()))
2741
2741
2742 def helpcmd(name):
2742 def helpcmd(name):
2743 try:
2743 try:
2744 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2744 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2745 except error.AmbiguousCommand, inst:
2745 except error.AmbiguousCommand, inst:
2746 # py3k fix: except vars can't be used outside the scope of the
2746 # py3k fix: except vars can't be used outside the scope of the
2747 # except block, nor can be used inside a lambda. python issue4617
2747 # except block, nor can be used inside a lambda. python issue4617
2748 prefix = inst.args[0]
2748 prefix = inst.args[0]
2749 select = lambda c: c.lstrip('^').startswith(prefix)
2749 select = lambda c: c.lstrip('^').startswith(prefix)
2750 helplist(_('list of commands:\n\n'), select)
2750 helplist(_('list of commands:\n\n'), select)
2751 return
2751 return
2752
2752
2753 # check if it's an invalid alias and display its error if it is
2753 # check if it's an invalid alias and display its error if it is
2754 if getattr(entry[0], 'badalias', False):
2754 if getattr(entry[0], 'badalias', False):
2755 if not unknowncmd:
2755 if not unknowncmd:
2756 entry[0](ui)
2756 entry[0](ui)
2757 return
2757 return
2758
2758
2759 # synopsis
2759 # synopsis
2760 if len(entry) > 2:
2760 if len(entry) > 2:
2761 if entry[2].startswith('hg'):
2761 if entry[2].startswith('hg'):
2762 ui.write("%s\n" % entry[2])
2762 ui.write("%s\n" % entry[2])
2763 else:
2763 else:
2764 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2764 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2765 else:
2765 else:
2766 ui.write('hg %s\n' % aliases[0])
2766 ui.write('hg %s\n' % aliases[0])
2767
2767
2768 # aliases
2768 # aliases
2769 if full and not ui.quiet and len(aliases) > 1:
2769 if full and not ui.quiet and len(aliases) > 1:
2770 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2770 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2771
2771
2772 # description
2772 # description
2773 doc = gettext(entry[0].__doc__)
2773 doc = gettext(entry[0].__doc__)
2774 if not doc:
2774 if not doc:
2775 doc = _("(no help text available)")
2775 doc = _("(no help text available)")
2776 if util.safehasattr(entry[0], 'definition'): # aliased command
2776 if util.safehasattr(entry[0], 'definition'): # aliased command
2777 if entry[0].definition.startswith('!'): # shell alias
2777 if entry[0].definition.startswith('!'): # shell alias
2778 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2778 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2779 else:
2779 else:
2780 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2780 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2781 if ui.quiet or not full:
2781 if ui.quiet or not full:
2782 doc = doc.splitlines()[0]
2782 doc = doc.splitlines()[0]
2783 keep = ui.verbose and ['verbose'] or []
2783 keep = ui.verbose and ['verbose'] or []
2784 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2784 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2785 ui.write("\n%s\n" % formatted)
2785 ui.write("\n%s" % formatted)
2786 if pruned:
2786 if pruned:
2787 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2787 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2788
2788
2789 if not ui.quiet:
2789 if not ui.quiet:
2790 # options
2790 # options
2791 if entry[1]:
2791 if entry[1]:
2792 optlist.append((_("options:\n"), entry[1]))
2792 optlist.append((_("options:\n"), entry[1]))
2793
2793
2794 addglobalopts(False)
2794 addglobalopts(False)
2795
2795
2796 # check if this command shadows a non-trivial (multi-line)
2796 # check if this command shadows a non-trivial (multi-line)
2797 # extension help text
2797 # extension help text
2798 try:
2798 try:
2799 mod = extensions.find(name)
2799 mod = extensions.find(name)
2800 doc = gettext(mod.__doc__) or ''
2800 doc = gettext(mod.__doc__) or ''
2801 if '\n' in doc.strip():
2801 if '\n' in doc.strip():
2802 msg = _('use "hg help -e %s" to show help for '
2802 msg = _('use "hg help -e %s" to show help for '
2803 'the %s extension') % (name, name)
2803 'the %s extension') % (name, name)
2804 ui.write('\n%s\n' % msg)
2804 ui.write('\n%s\n' % msg)
2805 except KeyError:
2805 except KeyError:
2806 pass
2806 pass
2807
2807
2808 def helplist(header, select=None):
2808 def helplist(header, select=None):
2809 h = {}
2809 h = {}
2810 cmds = {}
2810 cmds = {}
2811 for c, e in table.iteritems():
2811 for c, e in table.iteritems():
2812 f = c.split("|", 1)[0]
2812 f = c.split("|", 1)[0]
2813 if select and not select(f):
2813 if select and not select(f):
2814 continue
2814 continue
2815 if (not select and name != 'shortlist' and
2815 if (not select and name != 'shortlist' and
2816 e[0].__module__ != __name__):
2816 e[0].__module__ != __name__):
2817 continue
2817 continue
2818 if name == "shortlist" and not f.startswith("^"):
2818 if name == "shortlist" and not f.startswith("^"):
2819 continue
2819 continue
2820 f = f.lstrip("^")
2820 f = f.lstrip("^")
2821 if not ui.debugflag and f.startswith("debug"):
2821 if not ui.debugflag and f.startswith("debug"):
2822 continue
2822 continue
2823 doc = e[0].__doc__
2823 doc = e[0].__doc__
2824 if doc and 'DEPRECATED' in doc and not ui.verbose:
2824 if doc and 'DEPRECATED' in doc and not ui.verbose:
2825 continue
2825 continue
2826 doc = gettext(doc)
2826 doc = gettext(doc)
2827 if not doc:
2827 if not doc:
2828 doc = _("(no help text available)")
2828 doc = _("(no help text available)")
2829 h[f] = doc.splitlines()[0].rstrip()
2829 h[f] = doc.splitlines()[0].rstrip()
2830 cmds[f] = c.lstrip("^")
2830 cmds[f] = c.lstrip("^")
2831
2831
2832 if not h:
2832 if not h:
2833 ui.status(_('no commands defined\n'))
2833 ui.status(_('no commands defined\n'))
2834 return
2834 return
2835
2835
2836 ui.status(header)
2836 ui.status(header)
2837 fns = sorted(h)
2837 fns = sorted(h)
2838 m = max(map(len, fns))
2838 m = max(map(len, fns))
2839 for f in fns:
2839 for f in fns:
2840 if ui.verbose:
2840 if ui.verbose:
2841 commands = cmds[f].replace("|",", ")
2841 commands = cmds[f].replace("|",", ")
2842 ui.write(" %s:\n %s\n"%(commands, h[f]))
2842 ui.write(" %s:\n %s\n"%(commands, h[f]))
2843 else:
2843 else:
2844 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2844 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2845 initindent=' %-*s ' % (m, f),
2845 initindent=' %-*s ' % (m, f),
2846 hangindent=' ' * (m + 4))))
2846 hangindent=' ' * (m + 4))))
2847
2847
2848 if not ui.quiet:
2848 if not ui.quiet:
2849 addglobalopts(True)
2849 addglobalopts(True)
2850
2850
2851 def helptopic(name):
2851 def helptopic(name):
2852 for names, header, doc in help.helptable:
2852 for names, header, doc in help.helptable:
2853 if name in names:
2853 if name in names:
2854 break
2854 break
2855 else:
2855 else:
2856 raise error.UnknownCommand(name)
2856 raise error.UnknownCommand(name)
2857
2857
2858 # description
2858 # description
2859 if not doc:
2859 if not doc:
2860 doc = _("(no help text available)")
2860 doc = _("(no help text available)")
2861 if util.safehasattr(doc, '__call__'):
2861 if util.safehasattr(doc, '__call__'):
2862 doc = doc()
2862 doc = doc()
2863
2863
2864 ui.write("%s\n\n" % header)
2864 ui.write("%s\n\n" % header)
2865 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2865 ui.write("%s" % minirst.format(doc, textwidth, indent=4))
2866 try:
2866 try:
2867 cmdutil.findcmd(name, table)
2867 cmdutil.findcmd(name, table)
2868 ui.write(_('\nuse "hg help -c %s" to see help for '
2868 ui.write(_('\nuse "hg help -c %s" to see help for '
2869 'the %s command\n') % (name, name))
2869 'the %s command\n') % (name, name))
2870 except error.UnknownCommand:
2870 except error.UnknownCommand:
2871 pass
2871 pass
2872
2872
2873 def helpext(name):
2873 def helpext(name):
2874 try:
2874 try:
2875 mod = extensions.find(name)
2875 mod = extensions.find(name)
2876 doc = gettext(mod.__doc__) or _('no help text available')
2876 doc = gettext(mod.__doc__) or _('no help text available')
2877 except KeyError:
2877 except KeyError:
2878 mod = None
2878 mod = None
2879 doc = extensions.disabledext(name)
2879 doc = extensions.disabledext(name)
2880 if not doc:
2880 if not doc:
2881 raise error.UnknownCommand(name)
2881 raise error.UnknownCommand(name)
2882
2882
2883 if '\n' not in doc:
2883 if '\n' not in doc:
2884 head, tail = doc, ""
2884 head, tail = doc, ""
2885 else:
2885 else:
2886 head, tail = doc.split('\n', 1)
2886 head, tail = doc.split('\n', 1)
2887 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2887 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2888 if tail:
2888 if tail:
2889 ui.write(minirst.format(tail, textwidth))
2889 ui.write(minirst.format(tail, textwidth))
2890 ui.status('\n\n')
2890 ui.status('\n')
2891
2891
2892 if mod:
2892 if mod:
2893 try:
2893 try:
2894 ct = mod.cmdtable
2894 ct = mod.cmdtable
2895 except AttributeError:
2895 except AttributeError:
2896 ct = {}
2896 ct = {}
2897 modcmds = set([c.split('|', 1)[0] for c in ct])
2897 modcmds = set([c.split('|', 1)[0] for c in ct])
2898 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2898 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2899 else:
2899 else:
2900 ui.write(_('use "hg help extensions" for information on enabling '
2900 ui.write(_('use "hg help extensions" for information on enabling '
2901 'extensions\n'))
2901 'extensions\n'))
2902
2902
2903 def helpextcmd(name):
2903 def helpextcmd(name):
2904 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2904 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2905 doc = gettext(mod.__doc__).splitlines()[0]
2905 doc = gettext(mod.__doc__).splitlines()[0]
2906
2906
2907 msg = help.listexts(_("'%s' is provided by the following "
2907 msg = help.listexts(_("'%s' is provided by the following "
2908 "extension:") % cmd, {ext: doc}, indent=4)
2908 "extension:") % cmd, {ext: doc}, indent=4)
2909 ui.write(minirst.format(msg, textwidth))
2909 ui.write(minirst.format(msg, textwidth))
2910 ui.write('\n\n')
2910 ui.write('\n')
2911 ui.write(_('use "hg help extensions" for information on enabling '
2911 ui.write(_('use "hg help extensions" for information on enabling '
2912 'extensions\n'))
2912 'extensions\n'))
2913
2913
2914 if name and name != 'shortlist':
2914 if name and name != 'shortlist':
2915 i = None
2915 i = None
2916 if unknowncmd:
2916 if unknowncmd:
2917 queries = (helpextcmd,)
2917 queries = (helpextcmd,)
2918 elif opts.get('extension'):
2918 elif opts.get('extension'):
2919 queries = (helpext,)
2919 queries = (helpext,)
2920 elif opts.get('command'):
2920 elif opts.get('command'):
2921 queries = (helpcmd,)
2921 queries = (helpcmd,)
2922 else:
2922 else:
2923 queries = (helptopic, helpcmd, helpext, helpextcmd)
2923 queries = (helptopic, helpcmd, helpext, helpextcmd)
2924 for f in queries:
2924 for f in queries:
2925 try:
2925 try:
2926 f(name)
2926 f(name)
2927 i = None
2927 i = None
2928 break
2928 break
2929 except error.UnknownCommand, inst:
2929 except error.UnknownCommand, inst:
2930 i = inst
2930 i = inst
2931 if i:
2931 if i:
2932 raise i
2932 raise i
2933
2933
2934 else:
2934 else:
2935 # program name
2935 # program name
2936 ui.status(_("Mercurial Distributed SCM\n"))
2936 ui.status(_("Mercurial Distributed SCM\n"))
2937 ui.status('\n')
2937 ui.status('\n')
2938
2938
2939 # list of commands
2939 # list of commands
2940 if name == "shortlist":
2940 if name == "shortlist":
2941 header = _('basic commands:\n\n')
2941 header = _('basic commands:\n\n')
2942 else:
2942 else:
2943 header = _('list of commands:\n\n')
2943 header = _('list of commands:\n\n')
2944
2944
2945 helplist(header)
2945 helplist(header)
2946 if name != 'shortlist':
2946 if name != 'shortlist':
2947 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2947 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2948 if text:
2948 if text:
2949 ui.write("\n%s\n" % minirst.format(text, textwidth))
2949 ui.write("\n%s" % minirst.format(text, textwidth))
2950
2950
2951 if not name:
2951 if not name:
2952 ui.write(_("\nadditional help topics:\n\n"))
2952 ui.write(_("\nadditional help topics:\n\n"))
2953 topics = []
2953 topics = []
2954 for names, header, doc in help.helptable:
2954 for names, header, doc in help.helptable:
2955 topics.append((sorted(names, key=len, reverse=True)[0], header))
2955 topics.append((sorted(names, key=len, reverse=True)[0], header))
2956 topics_len = max([len(s[0]) for s in topics])
2956 topics_len = max([len(s[0]) for s in topics])
2957 for t, desc in topics:
2957 for t, desc in topics:
2958 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2958 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2959
2959
2960 ui.write(opttext(optlist, textwidth))
2960 ui.write(opttext(optlist, textwidth))
2961
2961
2962 @command('identify|id',
2962 @command('identify|id',
2963 [('r', 'rev', '',
2963 [('r', 'rev', '',
2964 _('identify the specified revision'), _('REV')),
2964 _('identify the specified revision'), _('REV')),
2965 ('n', 'num', None, _('show local revision number')),
2965 ('n', 'num', None, _('show local revision number')),
2966 ('i', 'id', None, _('show global revision id')),
2966 ('i', 'id', None, _('show global revision id')),
2967 ('b', 'branch', None, _('show branch')),
2967 ('b', 'branch', None, _('show branch')),
2968 ('t', 'tags', None, _('show tags')),
2968 ('t', 'tags', None, _('show tags')),
2969 ('B', 'bookmarks', None, _('show bookmarks'))],
2969 ('B', 'bookmarks', None, _('show bookmarks'))],
2970 _('[-nibtB] [-r REV] [SOURCE]'))
2970 _('[-nibtB] [-r REV] [SOURCE]'))
2971 def identify(ui, repo, source=None, rev=None,
2971 def identify(ui, repo, source=None, rev=None,
2972 num=None, id=None, branch=None, tags=None, bookmarks=None):
2972 num=None, id=None, branch=None, tags=None, bookmarks=None):
2973 """identify the working copy or specified revision
2973 """identify the working copy or specified revision
2974
2974
2975 Print a summary identifying the repository state at REV using one or
2975 Print a summary identifying the repository state at REV using one or
2976 two parent hash identifiers, followed by a "+" if the working
2976 two parent hash identifiers, followed by a "+" if the working
2977 directory has uncommitted changes, the branch name (if not default),
2977 directory has uncommitted changes, the branch name (if not default),
2978 a list of tags, and a list of bookmarks.
2978 a list of tags, and a list of bookmarks.
2979
2979
2980 When REV is not given, print a summary of the current state of the
2980 When REV is not given, print a summary of the current state of the
2981 repository.
2981 repository.
2982
2982
2983 Specifying a path to a repository root or Mercurial bundle will
2983 Specifying a path to a repository root or Mercurial bundle will
2984 cause lookup to operate on that repository/bundle.
2984 cause lookup to operate on that repository/bundle.
2985
2985
2986 .. container:: verbose
2986 .. container:: verbose
2987
2987
2988 Examples:
2988 Examples:
2989
2989
2990 - generate a build identifier for the working directory::
2990 - generate a build identifier for the working directory::
2991
2991
2992 hg id --id > build-id.dat
2992 hg id --id > build-id.dat
2993
2993
2994 - find the revision corresponding to a tag::
2994 - find the revision corresponding to a tag::
2995
2995
2996 hg id -n -r 1.3
2996 hg id -n -r 1.3
2997
2997
2998 - check the most recent revision of a remote repository::
2998 - check the most recent revision of a remote repository::
2999
2999
3000 hg id -r tip http://selenic.com/hg/
3000 hg id -r tip http://selenic.com/hg/
3001
3001
3002 Returns 0 if successful.
3002 Returns 0 if successful.
3003 """
3003 """
3004
3004
3005 if not repo and not source:
3005 if not repo and not source:
3006 raise util.Abort(_("there is no Mercurial repository here "
3006 raise util.Abort(_("there is no Mercurial repository here "
3007 "(.hg not found)"))
3007 "(.hg not found)"))
3008
3008
3009 hexfunc = ui.debugflag and hex or short
3009 hexfunc = ui.debugflag and hex or short
3010 default = not (num or id or branch or tags or bookmarks)
3010 default = not (num or id or branch or tags or bookmarks)
3011 output = []
3011 output = []
3012 revs = []
3012 revs = []
3013
3013
3014 if source:
3014 if source:
3015 source, branches = hg.parseurl(ui.expandpath(source))
3015 source, branches = hg.parseurl(ui.expandpath(source))
3016 repo = hg.peer(ui, {}, source)
3016 repo = hg.peer(ui, {}, source)
3017 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3017 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3018
3018
3019 if not repo.local():
3019 if not repo.local():
3020 if num or branch or tags:
3020 if num or branch or tags:
3021 raise util.Abort(
3021 raise util.Abort(
3022 _("can't query remote revision number, branch, or tags"))
3022 _("can't query remote revision number, branch, or tags"))
3023 if not rev and revs:
3023 if not rev and revs:
3024 rev = revs[0]
3024 rev = revs[0]
3025 if not rev:
3025 if not rev:
3026 rev = "tip"
3026 rev = "tip"
3027
3027
3028 remoterev = repo.lookup(rev)
3028 remoterev = repo.lookup(rev)
3029 if default or id:
3029 if default or id:
3030 output = [hexfunc(remoterev)]
3030 output = [hexfunc(remoterev)]
3031
3031
3032 def getbms():
3032 def getbms():
3033 bms = []
3033 bms = []
3034
3034
3035 if 'bookmarks' in repo.listkeys('namespaces'):
3035 if 'bookmarks' in repo.listkeys('namespaces'):
3036 hexremoterev = hex(remoterev)
3036 hexremoterev = hex(remoterev)
3037 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3037 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3038 if bmr == hexremoterev]
3038 if bmr == hexremoterev]
3039
3039
3040 return bms
3040 return bms
3041
3041
3042 if bookmarks:
3042 if bookmarks:
3043 output.extend(getbms())
3043 output.extend(getbms())
3044 elif default and not ui.quiet:
3044 elif default and not ui.quiet:
3045 # multiple bookmarks for a single parent separated by '/'
3045 # multiple bookmarks for a single parent separated by '/'
3046 bm = '/'.join(getbms())
3046 bm = '/'.join(getbms())
3047 if bm:
3047 if bm:
3048 output.append(bm)
3048 output.append(bm)
3049 else:
3049 else:
3050 if not rev:
3050 if not rev:
3051 ctx = repo[None]
3051 ctx = repo[None]
3052 parents = ctx.parents()
3052 parents = ctx.parents()
3053 changed = ""
3053 changed = ""
3054 if default or id or num:
3054 if default or id or num:
3055 changed = util.any(repo.status()) and "+" or ""
3055 changed = util.any(repo.status()) and "+" or ""
3056 if default or id:
3056 if default or id:
3057 output = ["%s%s" %
3057 output = ["%s%s" %
3058 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3058 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3059 if num:
3059 if num:
3060 output.append("%s%s" %
3060 output.append("%s%s" %
3061 ('+'.join([str(p.rev()) for p in parents]), changed))
3061 ('+'.join([str(p.rev()) for p in parents]), changed))
3062 else:
3062 else:
3063 ctx = scmutil.revsingle(repo, rev)
3063 ctx = scmutil.revsingle(repo, rev)
3064 if default or id:
3064 if default or id:
3065 output = [hexfunc(ctx.node())]
3065 output = [hexfunc(ctx.node())]
3066 if num:
3066 if num:
3067 output.append(str(ctx.rev()))
3067 output.append(str(ctx.rev()))
3068
3068
3069 if default and not ui.quiet:
3069 if default and not ui.quiet:
3070 b = ctx.branch()
3070 b = ctx.branch()
3071 if b != 'default':
3071 if b != 'default':
3072 output.append("(%s)" % b)
3072 output.append("(%s)" % b)
3073
3073
3074 # multiple tags for a single parent separated by '/'
3074 # multiple tags for a single parent separated by '/'
3075 t = '/'.join(ctx.tags())
3075 t = '/'.join(ctx.tags())
3076 if t:
3076 if t:
3077 output.append(t)
3077 output.append(t)
3078
3078
3079 # multiple bookmarks for a single parent separated by '/'
3079 # multiple bookmarks for a single parent separated by '/'
3080 bm = '/'.join(ctx.bookmarks())
3080 bm = '/'.join(ctx.bookmarks())
3081 if bm:
3081 if bm:
3082 output.append(bm)
3082 output.append(bm)
3083 else:
3083 else:
3084 if branch:
3084 if branch:
3085 output.append(ctx.branch())
3085 output.append(ctx.branch())
3086
3086
3087 if tags:
3087 if tags:
3088 output.extend(ctx.tags())
3088 output.extend(ctx.tags())
3089
3089
3090 if bookmarks:
3090 if bookmarks:
3091 output.extend(ctx.bookmarks())
3091 output.extend(ctx.bookmarks())
3092
3092
3093 ui.write("%s\n" % ' '.join(output))
3093 ui.write("%s\n" % ' '.join(output))
3094
3094
3095 @command('import|patch',
3095 @command('import|patch',
3096 [('p', 'strip', 1,
3096 [('p', 'strip', 1,
3097 _('directory strip option for patch. This has the same '
3097 _('directory strip option for patch. This has the same '
3098 'meaning as the corresponding patch option'), _('NUM')),
3098 'meaning as the corresponding patch option'), _('NUM')),
3099 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3099 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3100 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3100 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3101 ('', 'no-commit', None,
3101 ('', 'no-commit', None,
3102 _("don't commit, just update the working directory")),
3102 _("don't commit, just update the working directory")),
3103 ('', 'bypass', None,
3103 ('', 'bypass', None,
3104 _("apply patch without touching the working directory")),
3104 _("apply patch without touching the working directory")),
3105 ('', 'exact', None,
3105 ('', 'exact', None,
3106 _('apply patch to the nodes from which it was generated')),
3106 _('apply patch to the nodes from which it was generated')),
3107 ('', 'import-branch', None,
3107 ('', 'import-branch', None,
3108 _('use any branch information in patch (implied by --exact)'))] +
3108 _('use any branch information in patch (implied by --exact)'))] +
3109 commitopts + commitopts2 + similarityopts,
3109 commitopts + commitopts2 + similarityopts,
3110 _('[OPTION]... PATCH...'))
3110 _('[OPTION]... PATCH...'))
3111 def import_(ui, repo, patch1, *patches, **opts):
3111 def import_(ui, repo, patch1, *patches, **opts):
3112 """import an ordered set of patches
3112 """import an ordered set of patches
3113
3113
3114 Import a list of patches and commit them individually (unless
3114 Import a list of patches and commit them individually (unless
3115 --no-commit is specified).
3115 --no-commit is specified).
3116
3116
3117 If there are outstanding changes in the working directory, import
3117 If there are outstanding changes in the working directory, import
3118 will abort unless given the -f/--force flag.
3118 will abort unless given the -f/--force flag.
3119
3119
3120 You can import a patch straight from a mail message. Even patches
3120 You can import a patch straight from a mail message. Even patches
3121 as attachments work (to use the body part, it must have type
3121 as attachments work (to use the body part, it must have type
3122 text/plain or text/x-patch). From and Subject headers of email
3122 text/plain or text/x-patch). From and Subject headers of email
3123 message are used as default committer and commit message. All
3123 message are used as default committer and commit message. All
3124 text/plain body parts before first diff are added to commit
3124 text/plain body parts before first diff are added to commit
3125 message.
3125 message.
3126
3126
3127 If the imported patch was generated by :hg:`export`, user and
3127 If the imported patch was generated by :hg:`export`, user and
3128 description from patch override values from message headers and
3128 description from patch override values from message headers and
3129 body. Values given on command line with -m/--message and -u/--user
3129 body. Values given on command line with -m/--message and -u/--user
3130 override these.
3130 override these.
3131
3131
3132 If --exact is specified, import will set the working directory to
3132 If --exact is specified, import will set the working directory to
3133 the parent of each patch before applying it, and will abort if the
3133 the parent of each patch before applying it, and will abort if the
3134 resulting changeset has a different ID than the one recorded in
3134 resulting changeset has a different ID than the one recorded in
3135 the patch. This may happen due to character set problems or other
3135 the patch. This may happen due to character set problems or other
3136 deficiencies in the text patch format.
3136 deficiencies in the text patch format.
3137
3137
3138 Use --bypass to apply and commit patches directly to the
3138 Use --bypass to apply and commit patches directly to the
3139 repository, not touching the working directory. Without --exact,
3139 repository, not touching the working directory. Without --exact,
3140 patches will be applied on top of the working directory parent
3140 patches will be applied on top of the working directory parent
3141 revision.
3141 revision.
3142
3142
3143 With -s/--similarity, hg will attempt to discover renames and
3143 With -s/--similarity, hg will attempt to discover renames and
3144 copies in the patch in the same way as 'addremove'.
3144 copies in the patch in the same way as 'addremove'.
3145
3145
3146 To read a patch from standard input, use "-" as the patch name. If
3146 To read a patch from standard input, use "-" as the patch name. If
3147 a URL is specified, the patch will be downloaded from it.
3147 a URL is specified, the patch will be downloaded from it.
3148 See :hg:`help dates` for a list of formats valid for -d/--date.
3148 See :hg:`help dates` for a list of formats valid for -d/--date.
3149
3149
3150 .. container:: verbose
3150 .. container:: verbose
3151
3151
3152 Examples:
3152 Examples:
3153
3153
3154 - import a traditional patch from a website and detect renames::
3154 - import a traditional patch from a website and detect renames::
3155
3155
3156 hg import -s 80 http://example.com/bugfix.patch
3156 hg import -s 80 http://example.com/bugfix.patch
3157
3157
3158 - import a changeset from an hgweb server::
3158 - import a changeset from an hgweb server::
3159
3159
3160 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3160 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3161
3161
3162 - import all the patches in an Unix-style mbox::
3162 - import all the patches in an Unix-style mbox::
3163
3163
3164 hg import incoming-patches.mbox
3164 hg import incoming-patches.mbox
3165
3165
3166 - attempt to exactly restore an exported changeset (not always
3166 - attempt to exactly restore an exported changeset (not always
3167 possible)::
3167 possible)::
3168
3168
3169 hg import --exact proposed-fix.patch
3169 hg import --exact proposed-fix.patch
3170
3170
3171 Returns 0 on success.
3171 Returns 0 on success.
3172 """
3172 """
3173 patches = (patch1,) + patches
3173 patches = (patch1,) + patches
3174
3174
3175 date = opts.get('date')
3175 date = opts.get('date')
3176 if date:
3176 if date:
3177 opts['date'] = util.parsedate(date)
3177 opts['date'] = util.parsedate(date)
3178
3178
3179 update = not opts.get('bypass')
3179 update = not opts.get('bypass')
3180 if not update and opts.get('no_commit'):
3180 if not update and opts.get('no_commit'):
3181 raise util.Abort(_('cannot use --no-commit with --bypass'))
3181 raise util.Abort(_('cannot use --no-commit with --bypass'))
3182 try:
3182 try:
3183 sim = float(opts.get('similarity') or 0)
3183 sim = float(opts.get('similarity') or 0)
3184 except ValueError:
3184 except ValueError:
3185 raise util.Abort(_('similarity must be a number'))
3185 raise util.Abort(_('similarity must be a number'))
3186 if sim < 0 or sim > 100:
3186 if sim < 0 or sim > 100:
3187 raise util.Abort(_('similarity must be between 0 and 100'))
3187 raise util.Abort(_('similarity must be between 0 and 100'))
3188 if sim and not update:
3188 if sim and not update:
3189 raise util.Abort(_('cannot use --similarity with --bypass'))
3189 raise util.Abort(_('cannot use --similarity with --bypass'))
3190
3190
3191 if (opts.get('exact') or not opts.get('force')) and update:
3191 if (opts.get('exact') or not opts.get('force')) and update:
3192 cmdutil.bailifchanged(repo)
3192 cmdutil.bailifchanged(repo)
3193
3193
3194 d = opts["base"]
3194 d = opts["base"]
3195 strip = opts["strip"]
3195 strip = opts["strip"]
3196 wlock = lock = None
3196 wlock = lock = None
3197 msgs = []
3197 msgs = []
3198
3198
3199 def checkexact(repo, n, nodeid):
3199 def checkexact(repo, n, nodeid):
3200 if opts.get('exact') and hex(n) != nodeid:
3200 if opts.get('exact') and hex(n) != nodeid:
3201 repo.rollback()
3201 repo.rollback()
3202 raise util.Abort(_('patch is damaged or loses information'))
3202 raise util.Abort(_('patch is damaged or loses information'))
3203
3203
3204 def tryone(ui, hunk, parents):
3204 def tryone(ui, hunk, parents):
3205 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3205 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3206 patch.extract(ui, hunk)
3206 patch.extract(ui, hunk)
3207
3207
3208 if not tmpname:
3208 if not tmpname:
3209 return None
3209 return None
3210 commitid = _('to working directory')
3210 commitid = _('to working directory')
3211
3211
3212 try:
3212 try:
3213 cmdline_message = cmdutil.logmessage(ui, opts)
3213 cmdline_message = cmdutil.logmessage(ui, opts)
3214 if cmdline_message:
3214 if cmdline_message:
3215 # pickup the cmdline msg
3215 # pickup the cmdline msg
3216 message = cmdline_message
3216 message = cmdline_message
3217 elif message:
3217 elif message:
3218 # pickup the patch msg
3218 # pickup the patch msg
3219 message = message.strip()
3219 message = message.strip()
3220 else:
3220 else:
3221 # launch the editor
3221 # launch the editor
3222 message = None
3222 message = None
3223 ui.debug('message:\n%s\n' % message)
3223 ui.debug('message:\n%s\n' % message)
3224
3224
3225 if len(parents) == 1:
3225 if len(parents) == 1:
3226 parents.append(repo[nullid])
3226 parents.append(repo[nullid])
3227 if opts.get('exact'):
3227 if opts.get('exact'):
3228 if not nodeid or not p1:
3228 if not nodeid or not p1:
3229 raise util.Abort(_('not a Mercurial patch'))
3229 raise util.Abort(_('not a Mercurial patch'))
3230 p1 = repo[p1]
3230 p1 = repo[p1]
3231 p2 = repo[p2 or nullid]
3231 p2 = repo[p2 or nullid]
3232 elif p2:
3232 elif p2:
3233 try:
3233 try:
3234 p1 = repo[p1]
3234 p1 = repo[p1]
3235 p2 = repo[p2]
3235 p2 = repo[p2]
3236 except error.RepoError:
3236 except error.RepoError:
3237 p1, p2 = parents
3237 p1, p2 = parents
3238 else:
3238 else:
3239 p1, p2 = parents
3239 p1, p2 = parents
3240
3240
3241 n = None
3241 n = None
3242 if update:
3242 if update:
3243 if opts.get('exact') and p1 != parents[0]:
3243 if opts.get('exact') and p1 != parents[0]:
3244 hg.clean(repo, p1.node())
3244 hg.clean(repo, p1.node())
3245 if p1 != parents[0] and p2 != parents[1]:
3245 if p1 != parents[0] and p2 != parents[1]:
3246 repo.dirstate.setparents(p1.node(), p2.node())
3246 repo.dirstate.setparents(p1.node(), p2.node())
3247
3247
3248 if opts.get('exact') or opts.get('import_branch'):
3248 if opts.get('exact') or opts.get('import_branch'):
3249 repo.dirstate.setbranch(branch or 'default')
3249 repo.dirstate.setbranch(branch or 'default')
3250
3250
3251 files = set()
3251 files = set()
3252 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3252 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3253 eolmode=None, similarity=sim / 100.0)
3253 eolmode=None, similarity=sim / 100.0)
3254 files = list(files)
3254 files = list(files)
3255 if opts.get('no_commit'):
3255 if opts.get('no_commit'):
3256 if message:
3256 if message:
3257 msgs.append(message)
3257 msgs.append(message)
3258 else:
3258 else:
3259 if opts.get('exact'):
3259 if opts.get('exact'):
3260 m = None
3260 m = None
3261 else:
3261 else:
3262 m = scmutil.matchfiles(repo, files or [])
3262 m = scmutil.matchfiles(repo, files or [])
3263 n = repo.commit(message, opts.get('user') or user,
3263 n = repo.commit(message, opts.get('user') or user,
3264 opts.get('date') or date, match=m,
3264 opts.get('date') or date, match=m,
3265 editor=cmdutil.commiteditor)
3265 editor=cmdutil.commiteditor)
3266 checkexact(repo, n, nodeid)
3266 checkexact(repo, n, nodeid)
3267 # Force a dirstate write so that the next transaction
3267 # Force a dirstate write so that the next transaction
3268 # backups an up-to-date file.
3268 # backups an up-to-date file.
3269 repo.dirstate.write()
3269 repo.dirstate.write()
3270 else:
3270 else:
3271 if opts.get('exact') or opts.get('import_branch'):
3271 if opts.get('exact') or opts.get('import_branch'):
3272 branch = branch or 'default'
3272 branch = branch or 'default'
3273 else:
3273 else:
3274 branch = p1.branch()
3274 branch = p1.branch()
3275 store = patch.filestore()
3275 store = patch.filestore()
3276 try:
3276 try:
3277 files = set()
3277 files = set()
3278 try:
3278 try:
3279 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3279 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3280 files, eolmode=None)
3280 files, eolmode=None)
3281 except patch.PatchError, e:
3281 except patch.PatchError, e:
3282 raise util.Abort(str(e))
3282 raise util.Abort(str(e))
3283 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3283 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3284 message,
3284 message,
3285 opts.get('user') or user,
3285 opts.get('user') or user,
3286 opts.get('date') or date,
3286 opts.get('date') or date,
3287 branch, files, store,
3287 branch, files, store,
3288 editor=cmdutil.commiteditor)
3288 editor=cmdutil.commiteditor)
3289 repo.savecommitmessage(memctx.description())
3289 repo.savecommitmessage(memctx.description())
3290 n = memctx.commit()
3290 n = memctx.commit()
3291 checkexact(repo, n, nodeid)
3291 checkexact(repo, n, nodeid)
3292 finally:
3292 finally:
3293 store.close()
3293 store.close()
3294 if n:
3294 if n:
3295 commitid = short(n)
3295 commitid = short(n)
3296 return commitid
3296 return commitid
3297 finally:
3297 finally:
3298 os.unlink(tmpname)
3298 os.unlink(tmpname)
3299
3299
3300 try:
3300 try:
3301 wlock = repo.wlock()
3301 wlock = repo.wlock()
3302 lock = repo.lock()
3302 lock = repo.lock()
3303 parents = repo.parents()
3303 parents = repo.parents()
3304 lastcommit = None
3304 lastcommit = None
3305 for p in patches:
3305 for p in patches:
3306 pf = os.path.join(d, p)
3306 pf = os.path.join(d, p)
3307
3307
3308 if pf == '-':
3308 if pf == '-':
3309 ui.status(_("applying patch from stdin\n"))
3309 ui.status(_("applying patch from stdin\n"))
3310 pf = ui.fin
3310 pf = ui.fin
3311 else:
3311 else:
3312 ui.status(_("applying %s\n") % p)
3312 ui.status(_("applying %s\n") % p)
3313 pf = url.open(ui, pf)
3313 pf = url.open(ui, pf)
3314
3314
3315 haspatch = False
3315 haspatch = False
3316 for hunk in patch.split(pf):
3316 for hunk in patch.split(pf):
3317 commitid = tryone(ui, hunk, parents)
3317 commitid = tryone(ui, hunk, parents)
3318 if commitid:
3318 if commitid:
3319 haspatch = True
3319 haspatch = True
3320 if lastcommit:
3320 if lastcommit:
3321 ui.status(_('applied %s\n') % lastcommit)
3321 ui.status(_('applied %s\n') % lastcommit)
3322 lastcommit = commitid
3322 lastcommit = commitid
3323 if update or opts.get('exact'):
3323 if update or opts.get('exact'):
3324 parents = repo.parents()
3324 parents = repo.parents()
3325 else:
3325 else:
3326 parents = [repo[commitid]]
3326 parents = [repo[commitid]]
3327
3327
3328 if not haspatch:
3328 if not haspatch:
3329 raise util.Abort(_('no diffs found'))
3329 raise util.Abort(_('no diffs found'))
3330
3330
3331 if msgs:
3331 if msgs:
3332 repo.savecommitmessage('\n* * *\n'.join(msgs))
3332 repo.savecommitmessage('\n* * *\n'.join(msgs))
3333 finally:
3333 finally:
3334 release(lock, wlock)
3334 release(lock, wlock)
3335
3335
3336 @command('incoming|in',
3336 @command('incoming|in',
3337 [('f', 'force', None,
3337 [('f', 'force', None,
3338 _('run even if remote repository is unrelated')),
3338 _('run even if remote repository is unrelated')),
3339 ('n', 'newest-first', None, _('show newest record first')),
3339 ('n', 'newest-first', None, _('show newest record first')),
3340 ('', 'bundle', '',
3340 ('', 'bundle', '',
3341 _('file to store the bundles into'), _('FILE')),
3341 _('file to store the bundles into'), _('FILE')),
3342 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3342 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3343 ('B', 'bookmarks', False, _("compare bookmarks")),
3343 ('B', 'bookmarks', False, _("compare bookmarks")),
3344 ('b', 'branch', [],
3344 ('b', 'branch', [],
3345 _('a specific branch you would like to pull'), _('BRANCH')),
3345 _('a specific branch you would like to pull'), _('BRANCH')),
3346 ] + logopts + remoteopts + subrepoopts,
3346 ] + logopts + remoteopts + subrepoopts,
3347 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3347 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3348 def incoming(ui, repo, source="default", **opts):
3348 def incoming(ui, repo, source="default", **opts):
3349 """show new changesets found in source
3349 """show new changesets found in source
3350
3350
3351 Show new changesets found in the specified path/URL or the default
3351 Show new changesets found in the specified path/URL or the default
3352 pull location. These are the changesets that would have been pulled
3352 pull location. These are the changesets that would have been pulled
3353 if a pull at the time you issued this command.
3353 if a pull at the time you issued this command.
3354
3354
3355 For remote repository, using --bundle avoids downloading the
3355 For remote repository, using --bundle avoids downloading the
3356 changesets twice if the incoming is followed by a pull.
3356 changesets twice if the incoming is followed by a pull.
3357
3357
3358 See pull for valid source format details.
3358 See pull for valid source format details.
3359
3359
3360 Returns 0 if there are incoming changes, 1 otherwise.
3360 Returns 0 if there are incoming changes, 1 otherwise.
3361 """
3361 """
3362 if opts.get('bundle') and opts.get('subrepos'):
3362 if opts.get('bundle') and opts.get('subrepos'):
3363 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3363 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3364
3364
3365 if opts.get('bookmarks'):
3365 if opts.get('bookmarks'):
3366 source, branches = hg.parseurl(ui.expandpath(source),
3366 source, branches = hg.parseurl(ui.expandpath(source),
3367 opts.get('branch'))
3367 opts.get('branch'))
3368 other = hg.peer(repo, opts, source)
3368 other = hg.peer(repo, opts, source)
3369 if 'bookmarks' not in other.listkeys('namespaces'):
3369 if 'bookmarks' not in other.listkeys('namespaces'):
3370 ui.warn(_("remote doesn't support bookmarks\n"))
3370 ui.warn(_("remote doesn't support bookmarks\n"))
3371 return 0
3371 return 0
3372 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3372 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3373 return bookmarks.diff(ui, repo, other)
3373 return bookmarks.diff(ui, repo, other)
3374
3374
3375 repo._subtoppath = ui.expandpath(source)
3375 repo._subtoppath = ui.expandpath(source)
3376 try:
3376 try:
3377 return hg.incoming(ui, repo, source, opts)
3377 return hg.incoming(ui, repo, source, opts)
3378 finally:
3378 finally:
3379 del repo._subtoppath
3379 del repo._subtoppath
3380
3380
3381
3381
3382 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3382 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3383 def init(ui, dest=".", **opts):
3383 def init(ui, dest=".", **opts):
3384 """create a new repository in the given directory
3384 """create a new repository in the given directory
3385
3385
3386 Initialize a new repository in the given directory. If the given
3386 Initialize a new repository in the given directory. If the given
3387 directory does not exist, it will be created.
3387 directory does not exist, it will be created.
3388
3388
3389 If no directory is given, the current directory is used.
3389 If no directory is given, the current directory is used.
3390
3390
3391 It is possible to specify an ``ssh://`` URL as the destination.
3391 It is possible to specify an ``ssh://`` URL as the destination.
3392 See :hg:`help urls` for more information.
3392 See :hg:`help urls` for more information.
3393
3393
3394 Returns 0 on success.
3394 Returns 0 on success.
3395 """
3395 """
3396 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3396 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3397
3397
3398 @command('locate',
3398 @command('locate',
3399 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3399 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3400 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3400 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3401 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3401 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3402 ] + walkopts,
3402 ] + walkopts,
3403 _('[OPTION]... [PATTERN]...'))
3403 _('[OPTION]... [PATTERN]...'))
3404 def locate(ui, repo, *pats, **opts):
3404 def locate(ui, repo, *pats, **opts):
3405 """locate files matching specific patterns
3405 """locate files matching specific patterns
3406
3406
3407 Print files under Mercurial control in the working directory whose
3407 Print files under Mercurial control in the working directory whose
3408 names match the given patterns.
3408 names match the given patterns.
3409
3409
3410 By default, this command searches all directories in the working
3410 By default, this command searches all directories in the working
3411 directory. To search just the current directory and its
3411 directory. To search just the current directory and its
3412 subdirectories, use "--include .".
3412 subdirectories, use "--include .".
3413
3413
3414 If no patterns are given to match, this command prints the names
3414 If no patterns are given to match, this command prints the names
3415 of all files under Mercurial control in the working directory.
3415 of all files under Mercurial control in the working directory.
3416
3416
3417 If you want to feed the output of this command into the "xargs"
3417 If you want to feed the output of this command into the "xargs"
3418 command, use the -0 option to both this command and "xargs". This
3418 command, use the -0 option to both this command and "xargs". This
3419 will avoid the problem of "xargs" treating single filenames that
3419 will avoid the problem of "xargs" treating single filenames that
3420 contain whitespace as multiple filenames.
3420 contain whitespace as multiple filenames.
3421
3421
3422 Returns 0 if a match is found, 1 otherwise.
3422 Returns 0 if a match is found, 1 otherwise.
3423 """
3423 """
3424 end = opts.get('print0') and '\0' or '\n'
3424 end = opts.get('print0') and '\0' or '\n'
3425 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3425 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3426
3426
3427 ret = 1
3427 ret = 1
3428 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3428 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3429 m.bad = lambda x, y: False
3429 m.bad = lambda x, y: False
3430 for abs in repo[rev].walk(m):
3430 for abs in repo[rev].walk(m):
3431 if not rev and abs not in repo.dirstate:
3431 if not rev and abs not in repo.dirstate:
3432 continue
3432 continue
3433 if opts.get('fullpath'):
3433 if opts.get('fullpath'):
3434 ui.write(repo.wjoin(abs), end)
3434 ui.write(repo.wjoin(abs), end)
3435 else:
3435 else:
3436 ui.write(((pats and m.rel(abs)) or abs), end)
3436 ui.write(((pats and m.rel(abs)) or abs), end)
3437 ret = 0
3437 ret = 0
3438
3438
3439 return ret
3439 return ret
3440
3440
3441 @command('^log|history',
3441 @command('^log|history',
3442 [('f', 'follow', None,
3442 [('f', 'follow', None,
3443 _('follow changeset history, or file history across copies and renames')),
3443 _('follow changeset history, or file history across copies and renames')),
3444 ('', 'follow-first', None,
3444 ('', 'follow-first', None,
3445 _('only follow the first parent of merge changesets')),
3445 _('only follow the first parent of merge changesets')),
3446 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3446 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3447 ('C', 'copies', None, _('show copied files')),
3447 ('C', 'copies', None, _('show copied files')),
3448 ('k', 'keyword', [],
3448 ('k', 'keyword', [],
3449 _('do case-insensitive search for a given text'), _('TEXT')),
3449 _('do case-insensitive search for a given text'), _('TEXT')),
3450 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3450 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3451 ('', 'removed', None, _('include revisions where files were removed')),
3451 ('', 'removed', None, _('include revisions where files were removed')),
3452 ('m', 'only-merges', None, _('show only merges')),
3452 ('m', 'only-merges', None, _('show only merges')),
3453 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3453 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3454 ('', 'only-branch', [],
3454 ('', 'only-branch', [],
3455 _('show only changesets within the given named branch (DEPRECATED)'),
3455 _('show only changesets within the given named branch (DEPRECATED)'),
3456 _('BRANCH')),
3456 _('BRANCH')),
3457 ('b', 'branch', [],
3457 ('b', 'branch', [],
3458 _('show changesets within the given named branch'), _('BRANCH')),
3458 _('show changesets within the given named branch'), _('BRANCH')),
3459 ('P', 'prune', [],
3459 ('P', 'prune', [],
3460 _('do not display revision or any of its ancestors'), _('REV')),
3460 _('do not display revision or any of its ancestors'), _('REV')),
3461 ('', 'hidden', False, _('show hidden changesets')),
3461 ('', 'hidden', False, _('show hidden changesets')),
3462 ] + logopts + walkopts,
3462 ] + logopts + walkopts,
3463 _('[OPTION]... [FILE]'))
3463 _('[OPTION]... [FILE]'))
3464 def log(ui, repo, *pats, **opts):
3464 def log(ui, repo, *pats, **opts):
3465 """show revision history of entire repository or files
3465 """show revision history of entire repository or files
3466
3466
3467 Print the revision history of the specified files or the entire
3467 Print the revision history of the specified files or the entire
3468 project.
3468 project.
3469
3469
3470 If no revision range is specified, the default is ``tip:0`` unless
3470 If no revision range is specified, the default is ``tip:0`` unless
3471 --follow is set, in which case the working directory parent is
3471 --follow is set, in which case the working directory parent is
3472 used as the starting revision.
3472 used as the starting revision.
3473
3473
3474 File history is shown without following rename or copy history of
3474 File history is shown without following rename or copy history of
3475 files. Use -f/--follow with a filename to follow history across
3475 files. Use -f/--follow with a filename to follow history across
3476 renames and copies. --follow without a filename will only show
3476 renames and copies. --follow without a filename will only show
3477 ancestors or descendants of the starting revision.
3477 ancestors or descendants of the starting revision.
3478
3478
3479 By default this command prints revision number and changeset id,
3479 By default this command prints revision number and changeset id,
3480 tags, non-trivial parents, user, date and time, and a summary for
3480 tags, non-trivial parents, user, date and time, and a summary for
3481 each commit. When the -v/--verbose switch is used, the list of
3481 each commit. When the -v/--verbose switch is used, the list of
3482 changed files and full commit message are shown.
3482 changed files and full commit message are shown.
3483
3483
3484 .. note::
3484 .. note::
3485 log -p/--patch may generate unexpected diff output for merge
3485 log -p/--patch may generate unexpected diff output for merge
3486 changesets, as it will only compare the merge changeset against
3486 changesets, as it will only compare the merge changeset against
3487 its first parent. Also, only files different from BOTH parents
3487 its first parent. Also, only files different from BOTH parents
3488 will appear in files:.
3488 will appear in files:.
3489
3489
3490 .. note::
3490 .. note::
3491 for performance reasons, log FILE may omit duplicate changes
3491 for performance reasons, log FILE may omit duplicate changes
3492 made on branches and will not show deletions. To see all
3492 made on branches and will not show deletions. To see all
3493 changes including duplicates and deletions, use the --removed
3493 changes including duplicates and deletions, use the --removed
3494 switch.
3494 switch.
3495
3495
3496 .. container:: verbose
3496 .. container:: verbose
3497
3497
3498 Some examples:
3498 Some examples:
3499
3499
3500 - changesets with full descriptions and file lists::
3500 - changesets with full descriptions and file lists::
3501
3501
3502 hg log -v
3502 hg log -v
3503
3503
3504 - changesets ancestral to the working directory::
3504 - changesets ancestral to the working directory::
3505
3505
3506 hg log -f
3506 hg log -f
3507
3507
3508 - last 10 commits on the current branch::
3508 - last 10 commits on the current branch::
3509
3509
3510 hg log -l 10 -b .
3510 hg log -l 10 -b .
3511
3511
3512 - changesets showing all modifications of a file, including removals::
3512 - changesets showing all modifications of a file, including removals::
3513
3513
3514 hg log --removed file.c
3514 hg log --removed file.c
3515
3515
3516 - all changesets that touch a directory, with diffs, excluding merges::
3516 - all changesets that touch a directory, with diffs, excluding merges::
3517
3517
3518 hg log -Mp lib/
3518 hg log -Mp lib/
3519
3519
3520 - all revision numbers that match a keyword::
3520 - all revision numbers that match a keyword::
3521
3521
3522 hg log -k bug --template "{rev}\\n"
3522 hg log -k bug --template "{rev}\\n"
3523
3523
3524 - check if a given changeset is included is a tagged release::
3524 - check if a given changeset is included is a tagged release::
3525
3525
3526 hg log -r "a21ccf and ancestor(1.9)"
3526 hg log -r "a21ccf and ancestor(1.9)"
3527
3527
3528 - find all changesets by some user in a date range::
3528 - find all changesets by some user in a date range::
3529
3529
3530 hg log -k alice -d "may 2008 to jul 2008"
3530 hg log -k alice -d "may 2008 to jul 2008"
3531
3531
3532 - summary of all changesets after the last tag::
3532 - summary of all changesets after the last tag::
3533
3533
3534 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3534 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3535
3535
3536 See :hg:`help dates` for a list of formats valid for -d/--date.
3536 See :hg:`help dates` for a list of formats valid for -d/--date.
3537
3537
3538 See :hg:`help revisions` and :hg:`help revsets` for more about
3538 See :hg:`help revisions` and :hg:`help revsets` for more about
3539 specifying revisions.
3539 specifying revisions.
3540
3540
3541 Returns 0 on success.
3541 Returns 0 on success.
3542 """
3542 """
3543
3543
3544 matchfn = scmutil.match(repo[None], pats, opts)
3544 matchfn = scmutil.match(repo[None], pats, opts)
3545 limit = cmdutil.loglimit(opts)
3545 limit = cmdutil.loglimit(opts)
3546 count = 0
3546 count = 0
3547
3547
3548 endrev = None
3548 endrev = None
3549 if opts.get('copies') and opts.get('rev'):
3549 if opts.get('copies') and opts.get('rev'):
3550 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3550 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3551
3551
3552 df = False
3552 df = False
3553 if opts["date"]:
3553 if opts["date"]:
3554 df = util.matchdate(opts["date"])
3554 df = util.matchdate(opts["date"])
3555
3555
3556 branches = opts.get('branch', []) + opts.get('only_branch', [])
3556 branches = opts.get('branch', []) + opts.get('only_branch', [])
3557 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3557 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3558
3558
3559 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3559 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3560 def prep(ctx, fns):
3560 def prep(ctx, fns):
3561 rev = ctx.rev()
3561 rev = ctx.rev()
3562 parents = [p for p in repo.changelog.parentrevs(rev)
3562 parents = [p for p in repo.changelog.parentrevs(rev)
3563 if p != nullrev]
3563 if p != nullrev]
3564 if opts.get('no_merges') and len(parents) == 2:
3564 if opts.get('no_merges') and len(parents) == 2:
3565 return
3565 return
3566 if opts.get('only_merges') and len(parents) != 2:
3566 if opts.get('only_merges') and len(parents) != 2:
3567 return
3567 return
3568 if opts.get('branch') and ctx.branch() not in opts['branch']:
3568 if opts.get('branch') and ctx.branch() not in opts['branch']:
3569 return
3569 return
3570 if not opts.get('hidden') and ctx.hidden():
3570 if not opts.get('hidden') and ctx.hidden():
3571 return
3571 return
3572 if df and not df(ctx.date()[0]):
3572 if df and not df(ctx.date()[0]):
3573 return
3573 return
3574 if opts['user'] and not [k for k in opts['user']
3574 if opts['user'] and not [k for k in opts['user']
3575 if k.lower() in ctx.user().lower()]:
3575 if k.lower() in ctx.user().lower()]:
3576 return
3576 return
3577 if opts.get('keyword'):
3577 if opts.get('keyword'):
3578 for k in [kw.lower() for kw in opts['keyword']]:
3578 for k in [kw.lower() for kw in opts['keyword']]:
3579 if (k in ctx.user().lower() or
3579 if (k in ctx.user().lower() or
3580 k in ctx.description().lower() or
3580 k in ctx.description().lower() or
3581 k in " ".join(ctx.files()).lower()):
3581 k in " ".join(ctx.files()).lower()):
3582 break
3582 break
3583 else:
3583 else:
3584 return
3584 return
3585
3585
3586 copies = None
3586 copies = None
3587 if opts.get('copies') and rev:
3587 if opts.get('copies') and rev:
3588 copies = []
3588 copies = []
3589 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3589 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3590 for fn in ctx.files():
3590 for fn in ctx.files():
3591 rename = getrenamed(fn, rev)
3591 rename = getrenamed(fn, rev)
3592 if rename:
3592 if rename:
3593 copies.append((fn, rename[0]))
3593 copies.append((fn, rename[0]))
3594
3594
3595 revmatchfn = None
3595 revmatchfn = None
3596 if opts.get('patch') or opts.get('stat'):
3596 if opts.get('patch') or opts.get('stat'):
3597 if opts.get('follow') or opts.get('follow_first'):
3597 if opts.get('follow') or opts.get('follow_first'):
3598 # note: this might be wrong when following through merges
3598 # note: this might be wrong when following through merges
3599 revmatchfn = scmutil.match(repo[None], fns, default='path')
3599 revmatchfn = scmutil.match(repo[None], fns, default='path')
3600 else:
3600 else:
3601 revmatchfn = matchfn
3601 revmatchfn = matchfn
3602
3602
3603 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3603 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3604
3604
3605 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3605 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3606 if count == limit:
3606 if count == limit:
3607 break
3607 break
3608 if displayer.flush(ctx.rev()):
3608 if displayer.flush(ctx.rev()):
3609 count += 1
3609 count += 1
3610 displayer.close()
3610 displayer.close()
3611
3611
3612 @command('manifest',
3612 @command('manifest',
3613 [('r', 'rev', '', _('revision to display'), _('REV')),
3613 [('r', 'rev', '', _('revision to display'), _('REV')),
3614 ('', 'all', False, _("list files from all revisions"))],
3614 ('', 'all', False, _("list files from all revisions"))],
3615 _('[-r REV]'))
3615 _('[-r REV]'))
3616 def manifest(ui, repo, node=None, rev=None, **opts):
3616 def manifest(ui, repo, node=None, rev=None, **opts):
3617 """output the current or given revision of the project manifest
3617 """output the current or given revision of the project manifest
3618
3618
3619 Print a list of version controlled files for the given revision.
3619 Print a list of version controlled files for the given revision.
3620 If no revision is given, the first parent of the working directory
3620 If no revision is given, the first parent of the working directory
3621 is used, or the null revision if no revision is checked out.
3621 is used, or the null revision if no revision is checked out.
3622
3622
3623 With -v, print file permissions, symlink and executable bits.
3623 With -v, print file permissions, symlink and executable bits.
3624 With --debug, print file revision hashes.
3624 With --debug, print file revision hashes.
3625
3625
3626 If option --all is specified, the list of all files from all revisions
3626 If option --all is specified, the list of all files from all revisions
3627 is printed. This includes deleted and renamed files.
3627 is printed. This includes deleted and renamed files.
3628
3628
3629 Returns 0 on success.
3629 Returns 0 on success.
3630 """
3630 """
3631 if opts.get('all'):
3631 if opts.get('all'):
3632 if rev or node:
3632 if rev or node:
3633 raise util.Abort(_("can't specify a revision with --all"))
3633 raise util.Abort(_("can't specify a revision with --all"))
3634
3634
3635 res = []
3635 res = []
3636 prefix = "data/"
3636 prefix = "data/"
3637 suffix = ".i"
3637 suffix = ".i"
3638 plen = len(prefix)
3638 plen = len(prefix)
3639 slen = len(suffix)
3639 slen = len(suffix)
3640 lock = repo.lock()
3640 lock = repo.lock()
3641 try:
3641 try:
3642 for fn, b, size in repo.store.datafiles():
3642 for fn, b, size in repo.store.datafiles():
3643 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3643 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3644 res.append(fn[plen:-slen])
3644 res.append(fn[plen:-slen])
3645 finally:
3645 finally:
3646 lock.release()
3646 lock.release()
3647 for f in sorted(res):
3647 for f in sorted(res):
3648 ui.write("%s\n" % f)
3648 ui.write("%s\n" % f)
3649 return
3649 return
3650
3650
3651 if rev and node:
3651 if rev and node:
3652 raise util.Abort(_("please specify just one revision"))
3652 raise util.Abort(_("please specify just one revision"))
3653
3653
3654 if not node:
3654 if not node:
3655 node = rev
3655 node = rev
3656
3656
3657 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3657 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3658 ctx = scmutil.revsingle(repo, node)
3658 ctx = scmutil.revsingle(repo, node)
3659 for f in ctx:
3659 for f in ctx:
3660 if ui.debugflag:
3660 if ui.debugflag:
3661 ui.write("%40s " % hex(ctx.manifest()[f]))
3661 ui.write("%40s " % hex(ctx.manifest()[f]))
3662 if ui.verbose:
3662 if ui.verbose:
3663 ui.write(decor[ctx.flags(f)])
3663 ui.write(decor[ctx.flags(f)])
3664 ui.write("%s\n" % f)
3664 ui.write("%s\n" % f)
3665
3665
3666 @command('^merge',
3666 @command('^merge',
3667 [('f', 'force', None, _('force a merge with outstanding changes')),
3667 [('f', 'force', None, _('force a merge with outstanding changes')),
3668 ('r', 'rev', '', _('revision to merge'), _('REV')),
3668 ('r', 'rev', '', _('revision to merge'), _('REV')),
3669 ('P', 'preview', None,
3669 ('P', 'preview', None,
3670 _('review revisions to merge (no merge is performed)'))
3670 _('review revisions to merge (no merge is performed)'))
3671 ] + mergetoolopts,
3671 ] + mergetoolopts,
3672 _('[-P] [-f] [[-r] REV]'))
3672 _('[-P] [-f] [[-r] REV]'))
3673 def merge(ui, repo, node=None, **opts):
3673 def merge(ui, repo, node=None, **opts):
3674 """merge working directory with another revision
3674 """merge working directory with another revision
3675
3675
3676 The current working directory is updated with all changes made in
3676 The current working directory is updated with all changes made in
3677 the requested revision since the last common predecessor revision.
3677 the requested revision since the last common predecessor revision.
3678
3678
3679 Files that changed between either parent are marked as changed for
3679 Files that changed between either parent are marked as changed for
3680 the next commit and a commit must be performed before any further
3680 the next commit and a commit must be performed before any further
3681 updates to the repository are allowed. The next commit will have
3681 updates to the repository are allowed. The next commit will have
3682 two parents.
3682 two parents.
3683
3683
3684 ``--tool`` can be used to specify the merge tool used for file
3684 ``--tool`` can be used to specify the merge tool used for file
3685 merges. It overrides the HGMERGE environment variable and your
3685 merges. It overrides the HGMERGE environment variable and your
3686 configuration files. See :hg:`help merge-tools` for options.
3686 configuration files. See :hg:`help merge-tools` for options.
3687
3687
3688 If no revision is specified, the working directory's parent is a
3688 If no revision is specified, the working directory's parent is a
3689 head revision, and the current branch contains exactly one other
3689 head revision, and the current branch contains exactly one other
3690 head, the other head is merged with by default. Otherwise, an
3690 head, the other head is merged with by default. Otherwise, an
3691 explicit revision with which to merge with must be provided.
3691 explicit revision with which to merge with must be provided.
3692
3692
3693 :hg:`resolve` must be used to resolve unresolved files.
3693 :hg:`resolve` must be used to resolve unresolved files.
3694
3694
3695 To undo an uncommitted merge, use :hg:`update --clean .` which
3695 To undo an uncommitted merge, use :hg:`update --clean .` which
3696 will check out a clean copy of the original merge parent, losing
3696 will check out a clean copy of the original merge parent, losing
3697 all changes.
3697 all changes.
3698
3698
3699 Returns 0 on success, 1 if there are unresolved files.
3699 Returns 0 on success, 1 if there are unresolved files.
3700 """
3700 """
3701
3701
3702 if opts.get('rev') and node:
3702 if opts.get('rev') and node:
3703 raise util.Abort(_("please specify just one revision"))
3703 raise util.Abort(_("please specify just one revision"))
3704 if not node:
3704 if not node:
3705 node = opts.get('rev')
3705 node = opts.get('rev')
3706
3706
3707 if not node:
3707 if not node:
3708 branch = repo[None].branch()
3708 branch = repo[None].branch()
3709 bheads = repo.branchheads(branch)
3709 bheads = repo.branchheads(branch)
3710 if len(bheads) > 2:
3710 if len(bheads) > 2:
3711 raise util.Abort(_("branch '%s' has %d heads - "
3711 raise util.Abort(_("branch '%s' has %d heads - "
3712 "please merge with an explicit rev")
3712 "please merge with an explicit rev")
3713 % (branch, len(bheads)),
3713 % (branch, len(bheads)),
3714 hint=_("run 'hg heads .' to see heads"))
3714 hint=_("run 'hg heads .' to see heads"))
3715
3715
3716 parent = repo.dirstate.p1()
3716 parent = repo.dirstate.p1()
3717 if len(bheads) == 1:
3717 if len(bheads) == 1:
3718 if len(repo.heads()) > 1:
3718 if len(repo.heads()) > 1:
3719 raise util.Abort(_("branch '%s' has one head - "
3719 raise util.Abort(_("branch '%s' has one head - "
3720 "please merge with an explicit rev")
3720 "please merge with an explicit rev")
3721 % branch,
3721 % branch,
3722 hint=_("run 'hg heads' to see all heads"))
3722 hint=_("run 'hg heads' to see all heads"))
3723 msg = _('there is nothing to merge')
3723 msg = _('there is nothing to merge')
3724 if parent != repo.lookup(repo[None].branch()):
3724 if parent != repo.lookup(repo[None].branch()):
3725 msg = _('%s - use "hg update" instead') % msg
3725 msg = _('%s - use "hg update" instead') % msg
3726 raise util.Abort(msg)
3726 raise util.Abort(msg)
3727
3727
3728 if parent not in bheads:
3728 if parent not in bheads:
3729 raise util.Abort(_('working directory not at a head revision'),
3729 raise util.Abort(_('working directory not at a head revision'),
3730 hint=_("use 'hg update' or merge with an "
3730 hint=_("use 'hg update' or merge with an "
3731 "explicit revision"))
3731 "explicit revision"))
3732 node = parent == bheads[0] and bheads[-1] or bheads[0]
3732 node = parent == bheads[0] and bheads[-1] or bheads[0]
3733 else:
3733 else:
3734 node = scmutil.revsingle(repo, node).node()
3734 node = scmutil.revsingle(repo, node).node()
3735
3735
3736 if opts.get('preview'):
3736 if opts.get('preview'):
3737 # find nodes that are ancestors of p2 but not of p1
3737 # find nodes that are ancestors of p2 but not of p1
3738 p1 = repo.lookup('.')
3738 p1 = repo.lookup('.')
3739 p2 = repo.lookup(node)
3739 p2 = repo.lookup(node)
3740 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3740 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3741
3741
3742 displayer = cmdutil.show_changeset(ui, repo, opts)
3742 displayer = cmdutil.show_changeset(ui, repo, opts)
3743 for node in nodes:
3743 for node in nodes:
3744 displayer.show(repo[node])
3744 displayer.show(repo[node])
3745 displayer.close()
3745 displayer.close()
3746 return 0
3746 return 0
3747
3747
3748 try:
3748 try:
3749 # ui.forcemerge is an internal variable, do not document
3749 # ui.forcemerge is an internal variable, do not document
3750 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3750 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3751 return hg.merge(repo, node, force=opts.get('force'))
3751 return hg.merge(repo, node, force=opts.get('force'))
3752 finally:
3752 finally:
3753 ui.setconfig('ui', 'forcemerge', '')
3753 ui.setconfig('ui', 'forcemerge', '')
3754
3754
3755 @command('outgoing|out',
3755 @command('outgoing|out',
3756 [('f', 'force', None, _('run even when the destination is unrelated')),
3756 [('f', 'force', None, _('run even when the destination is unrelated')),
3757 ('r', 'rev', [],
3757 ('r', 'rev', [],
3758 _('a changeset intended to be included in the destination'), _('REV')),
3758 _('a changeset intended to be included in the destination'), _('REV')),
3759 ('n', 'newest-first', None, _('show newest record first')),
3759 ('n', 'newest-first', None, _('show newest record first')),
3760 ('B', 'bookmarks', False, _('compare bookmarks')),
3760 ('B', 'bookmarks', False, _('compare bookmarks')),
3761 ('b', 'branch', [], _('a specific branch you would like to push'),
3761 ('b', 'branch', [], _('a specific branch you would like to push'),
3762 _('BRANCH')),
3762 _('BRANCH')),
3763 ] + logopts + remoteopts + subrepoopts,
3763 ] + logopts + remoteopts + subrepoopts,
3764 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3764 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3765 def outgoing(ui, repo, dest=None, **opts):
3765 def outgoing(ui, repo, dest=None, **opts):
3766 """show changesets not found in the destination
3766 """show changesets not found in the destination
3767
3767
3768 Show changesets not found in the specified destination repository
3768 Show changesets not found in the specified destination repository
3769 or the default push location. These are the changesets that would
3769 or the default push location. These are the changesets that would
3770 be pushed if a push was requested.
3770 be pushed if a push was requested.
3771
3771
3772 See pull for details of valid destination formats.
3772 See pull for details of valid destination formats.
3773
3773
3774 Returns 0 if there are outgoing changes, 1 otherwise.
3774 Returns 0 if there are outgoing changes, 1 otherwise.
3775 """
3775 """
3776
3776
3777 if opts.get('bookmarks'):
3777 if opts.get('bookmarks'):
3778 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3778 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3779 dest, branches = hg.parseurl(dest, opts.get('branch'))
3779 dest, branches = hg.parseurl(dest, opts.get('branch'))
3780 other = hg.peer(repo, opts, dest)
3780 other = hg.peer(repo, opts, dest)
3781 if 'bookmarks' not in other.listkeys('namespaces'):
3781 if 'bookmarks' not in other.listkeys('namespaces'):
3782 ui.warn(_("remote doesn't support bookmarks\n"))
3782 ui.warn(_("remote doesn't support bookmarks\n"))
3783 return 0
3783 return 0
3784 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3784 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3785 return bookmarks.diff(ui, other, repo)
3785 return bookmarks.diff(ui, other, repo)
3786
3786
3787 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3787 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3788 try:
3788 try:
3789 return hg.outgoing(ui, repo, dest, opts)
3789 return hg.outgoing(ui, repo, dest, opts)
3790 finally:
3790 finally:
3791 del repo._subtoppath
3791 del repo._subtoppath
3792
3792
3793 @command('parents',
3793 @command('parents',
3794 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3794 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3795 ] + templateopts,
3795 ] + templateopts,
3796 _('[-r REV] [FILE]'))
3796 _('[-r REV] [FILE]'))
3797 def parents(ui, repo, file_=None, **opts):
3797 def parents(ui, repo, file_=None, **opts):
3798 """show the parents of the working directory or revision
3798 """show the parents of the working directory or revision
3799
3799
3800 Print the working directory's parent revisions. If a revision is
3800 Print the working directory's parent revisions. If a revision is
3801 given via -r/--rev, the parent of that revision will be printed.
3801 given via -r/--rev, the parent of that revision will be printed.
3802 If a file argument is given, the revision in which the file was
3802 If a file argument is given, the revision in which the file was
3803 last changed (before the working directory revision or the
3803 last changed (before the working directory revision or the
3804 argument to --rev if given) is printed.
3804 argument to --rev if given) is printed.
3805
3805
3806 Returns 0 on success.
3806 Returns 0 on success.
3807 """
3807 """
3808
3808
3809 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3809 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3810
3810
3811 if file_:
3811 if file_:
3812 m = scmutil.match(ctx, (file_,), opts)
3812 m = scmutil.match(ctx, (file_,), opts)
3813 if m.anypats() or len(m.files()) != 1:
3813 if m.anypats() or len(m.files()) != 1:
3814 raise util.Abort(_('can only specify an explicit filename'))
3814 raise util.Abort(_('can only specify an explicit filename'))
3815 file_ = m.files()[0]
3815 file_ = m.files()[0]
3816 filenodes = []
3816 filenodes = []
3817 for cp in ctx.parents():
3817 for cp in ctx.parents():
3818 if not cp:
3818 if not cp:
3819 continue
3819 continue
3820 try:
3820 try:
3821 filenodes.append(cp.filenode(file_))
3821 filenodes.append(cp.filenode(file_))
3822 except error.LookupError:
3822 except error.LookupError:
3823 pass
3823 pass
3824 if not filenodes:
3824 if not filenodes:
3825 raise util.Abort(_("'%s' not found in manifest!") % file_)
3825 raise util.Abort(_("'%s' not found in manifest!") % file_)
3826 fl = repo.file(file_)
3826 fl = repo.file(file_)
3827 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3827 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3828 else:
3828 else:
3829 p = [cp.node() for cp in ctx.parents()]
3829 p = [cp.node() for cp in ctx.parents()]
3830
3830
3831 displayer = cmdutil.show_changeset(ui, repo, opts)
3831 displayer = cmdutil.show_changeset(ui, repo, opts)
3832 for n in p:
3832 for n in p:
3833 if n != nullid:
3833 if n != nullid:
3834 displayer.show(repo[n])
3834 displayer.show(repo[n])
3835 displayer.close()
3835 displayer.close()
3836
3836
3837 @command('paths', [], _('[NAME]'))
3837 @command('paths', [], _('[NAME]'))
3838 def paths(ui, repo, search=None):
3838 def paths(ui, repo, search=None):
3839 """show aliases for remote repositories
3839 """show aliases for remote repositories
3840
3840
3841 Show definition of symbolic path name NAME. If no name is given,
3841 Show definition of symbolic path name NAME. If no name is given,
3842 show definition of all available names.
3842 show definition of all available names.
3843
3843
3844 Option -q/--quiet suppresses all output when searching for NAME
3844 Option -q/--quiet suppresses all output when searching for NAME
3845 and shows only the path names when listing all definitions.
3845 and shows only the path names when listing all definitions.
3846
3846
3847 Path names are defined in the [paths] section of your
3847 Path names are defined in the [paths] section of your
3848 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3848 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3849 repository, ``.hg/hgrc`` is used, too.
3849 repository, ``.hg/hgrc`` is used, too.
3850
3850
3851 The path names ``default`` and ``default-push`` have a special
3851 The path names ``default`` and ``default-push`` have a special
3852 meaning. When performing a push or pull operation, they are used
3852 meaning. When performing a push or pull operation, they are used
3853 as fallbacks if no location is specified on the command-line.
3853 as fallbacks if no location is specified on the command-line.
3854 When ``default-push`` is set, it will be used for push and
3854 When ``default-push`` is set, it will be used for push and
3855 ``default`` will be used for pull; otherwise ``default`` is used
3855 ``default`` will be used for pull; otherwise ``default`` is used
3856 as the fallback for both. When cloning a repository, the clone
3856 as the fallback for both. When cloning a repository, the clone
3857 source is written as ``default`` in ``.hg/hgrc``. Note that
3857 source is written as ``default`` in ``.hg/hgrc``. Note that
3858 ``default`` and ``default-push`` apply to all inbound (e.g.
3858 ``default`` and ``default-push`` apply to all inbound (e.g.
3859 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3859 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3860 :hg:`bundle`) operations.
3860 :hg:`bundle`) operations.
3861
3861
3862 See :hg:`help urls` for more information.
3862 See :hg:`help urls` for more information.
3863
3863
3864 Returns 0 on success.
3864 Returns 0 on success.
3865 """
3865 """
3866 if search:
3866 if search:
3867 for name, path in ui.configitems("paths"):
3867 for name, path in ui.configitems("paths"):
3868 if name == search:
3868 if name == search:
3869 ui.status("%s\n" % util.hidepassword(path))
3869 ui.status("%s\n" % util.hidepassword(path))
3870 return
3870 return
3871 if not ui.quiet:
3871 if not ui.quiet:
3872 ui.warn(_("not found!\n"))
3872 ui.warn(_("not found!\n"))
3873 return 1
3873 return 1
3874 else:
3874 else:
3875 for name, path in ui.configitems("paths"):
3875 for name, path in ui.configitems("paths"):
3876 if ui.quiet:
3876 if ui.quiet:
3877 ui.write("%s\n" % name)
3877 ui.write("%s\n" % name)
3878 else:
3878 else:
3879 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3879 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3880
3880
3881 def postincoming(ui, repo, modheads, optupdate, checkout):
3881 def postincoming(ui, repo, modheads, optupdate, checkout):
3882 if modheads == 0:
3882 if modheads == 0:
3883 return
3883 return
3884 if optupdate:
3884 if optupdate:
3885 try:
3885 try:
3886 return hg.update(repo, checkout)
3886 return hg.update(repo, checkout)
3887 except util.Abort, inst:
3887 except util.Abort, inst:
3888 ui.warn(_("not updating: %s\n" % str(inst)))
3888 ui.warn(_("not updating: %s\n" % str(inst)))
3889 return 0
3889 return 0
3890 if modheads > 1:
3890 if modheads > 1:
3891 currentbranchheads = len(repo.branchheads())
3891 currentbranchheads = len(repo.branchheads())
3892 if currentbranchheads == modheads:
3892 if currentbranchheads == modheads:
3893 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3893 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3894 elif currentbranchheads > 1:
3894 elif currentbranchheads > 1:
3895 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3895 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3896 else:
3896 else:
3897 ui.status(_("(run 'hg heads' to see heads)\n"))
3897 ui.status(_("(run 'hg heads' to see heads)\n"))
3898 else:
3898 else:
3899 ui.status(_("(run 'hg update' to get a working copy)\n"))
3899 ui.status(_("(run 'hg update' to get a working copy)\n"))
3900
3900
3901 @command('^pull',
3901 @command('^pull',
3902 [('u', 'update', None,
3902 [('u', 'update', None,
3903 _('update to new branch head if changesets were pulled')),
3903 _('update to new branch head if changesets were pulled')),
3904 ('f', 'force', None, _('run even when remote repository is unrelated')),
3904 ('f', 'force', None, _('run even when remote repository is unrelated')),
3905 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3905 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3906 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3906 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3907 ('b', 'branch', [], _('a specific branch you would like to pull'),
3907 ('b', 'branch', [], _('a specific branch you would like to pull'),
3908 _('BRANCH')),
3908 _('BRANCH')),
3909 ] + remoteopts,
3909 ] + remoteopts,
3910 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3910 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3911 def pull(ui, repo, source="default", **opts):
3911 def pull(ui, repo, source="default", **opts):
3912 """pull changes from the specified source
3912 """pull changes from the specified source
3913
3913
3914 Pull changes from a remote repository to a local one.
3914 Pull changes from a remote repository to a local one.
3915
3915
3916 This finds all changes from the repository at the specified path
3916 This finds all changes from the repository at the specified path
3917 or URL and adds them to a local repository (the current one unless
3917 or URL and adds them to a local repository (the current one unless
3918 -R is specified). By default, this does not update the copy of the
3918 -R is specified). By default, this does not update the copy of the
3919 project in the working directory.
3919 project in the working directory.
3920
3920
3921 Use :hg:`incoming` if you want to see what would have been added
3921 Use :hg:`incoming` if you want to see what would have been added
3922 by a pull at the time you issued this command. If you then decide
3922 by a pull at the time you issued this command. If you then decide
3923 to add those changes to the repository, you should use :hg:`pull
3923 to add those changes to the repository, you should use :hg:`pull
3924 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3924 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3925
3925
3926 If SOURCE is omitted, the 'default' path will be used.
3926 If SOURCE is omitted, the 'default' path will be used.
3927 See :hg:`help urls` for more information.
3927 See :hg:`help urls` for more information.
3928
3928
3929 Returns 0 on success, 1 if an update had unresolved files.
3929 Returns 0 on success, 1 if an update had unresolved files.
3930 """
3930 """
3931 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3931 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3932 other = hg.peer(repo, opts, source)
3932 other = hg.peer(repo, opts, source)
3933 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3933 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3934 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3934 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3935
3935
3936 if opts.get('bookmark'):
3936 if opts.get('bookmark'):
3937 if not revs:
3937 if not revs:
3938 revs = []
3938 revs = []
3939 rb = other.listkeys('bookmarks')
3939 rb = other.listkeys('bookmarks')
3940 for b in opts['bookmark']:
3940 for b in opts['bookmark']:
3941 if b not in rb:
3941 if b not in rb:
3942 raise util.Abort(_('remote bookmark %s not found!') % b)
3942 raise util.Abort(_('remote bookmark %s not found!') % b)
3943 revs.append(rb[b])
3943 revs.append(rb[b])
3944
3944
3945 if revs:
3945 if revs:
3946 try:
3946 try:
3947 revs = [other.lookup(rev) for rev in revs]
3947 revs = [other.lookup(rev) for rev in revs]
3948 except error.CapabilityError:
3948 except error.CapabilityError:
3949 err = _("other repository doesn't support revision lookup, "
3949 err = _("other repository doesn't support revision lookup, "
3950 "so a rev cannot be specified.")
3950 "so a rev cannot be specified.")
3951 raise util.Abort(err)
3951 raise util.Abort(err)
3952
3952
3953 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3953 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3954 bookmarks.updatefromremote(ui, repo, other)
3954 bookmarks.updatefromremote(ui, repo, other)
3955 if checkout:
3955 if checkout:
3956 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3956 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3957 repo._subtoppath = source
3957 repo._subtoppath = source
3958 try:
3958 try:
3959 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3959 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3960
3960
3961 finally:
3961 finally:
3962 del repo._subtoppath
3962 del repo._subtoppath
3963
3963
3964 # update specified bookmarks
3964 # update specified bookmarks
3965 if opts.get('bookmark'):
3965 if opts.get('bookmark'):
3966 for b in opts['bookmark']:
3966 for b in opts['bookmark']:
3967 # explicit pull overrides local bookmark if any
3967 # explicit pull overrides local bookmark if any
3968 ui.status(_("importing bookmark %s\n") % b)
3968 ui.status(_("importing bookmark %s\n") % b)
3969 repo._bookmarks[b] = repo[rb[b]].node()
3969 repo._bookmarks[b] = repo[rb[b]].node()
3970 bookmarks.write(repo)
3970 bookmarks.write(repo)
3971
3971
3972 return ret
3972 return ret
3973
3973
3974 @command('^push',
3974 @command('^push',
3975 [('f', 'force', None, _('force push')),
3975 [('f', 'force', None, _('force push')),
3976 ('r', 'rev', [],
3976 ('r', 'rev', [],
3977 _('a changeset intended to be included in the destination'),
3977 _('a changeset intended to be included in the destination'),
3978 _('REV')),
3978 _('REV')),
3979 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3979 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3980 ('b', 'branch', [],
3980 ('b', 'branch', [],
3981 _('a specific branch you would like to push'), _('BRANCH')),
3981 _('a specific branch you would like to push'), _('BRANCH')),
3982 ('', 'new-branch', False, _('allow pushing a new branch')),
3982 ('', 'new-branch', False, _('allow pushing a new branch')),
3983 ] + remoteopts,
3983 ] + remoteopts,
3984 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3984 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3985 def push(ui, repo, dest=None, **opts):
3985 def push(ui, repo, dest=None, **opts):
3986 """push changes to the specified destination
3986 """push changes to the specified destination
3987
3987
3988 Push changesets from the local repository to the specified
3988 Push changesets from the local repository to the specified
3989 destination.
3989 destination.
3990
3990
3991 This operation is symmetrical to pull: it is identical to a pull
3991 This operation is symmetrical to pull: it is identical to a pull
3992 in the destination repository from the current one.
3992 in the destination repository from the current one.
3993
3993
3994 By default, push will not allow creation of new heads at the
3994 By default, push will not allow creation of new heads at the
3995 destination, since multiple heads would make it unclear which head
3995 destination, since multiple heads would make it unclear which head
3996 to use. In this situation, it is recommended to pull and merge
3996 to use. In this situation, it is recommended to pull and merge
3997 before pushing.
3997 before pushing.
3998
3998
3999 Use --new-branch if you want to allow push to create a new named
3999 Use --new-branch if you want to allow push to create a new named
4000 branch that is not present at the destination. This allows you to
4000 branch that is not present at the destination. This allows you to
4001 only create a new branch without forcing other changes.
4001 only create a new branch without forcing other changes.
4002
4002
4003 Use -f/--force to override the default behavior and push all
4003 Use -f/--force to override the default behavior and push all
4004 changesets on all branches.
4004 changesets on all branches.
4005
4005
4006 If -r/--rev is used, the specified revision and all its ancestors
4006 If -r/--rev is used, the specified revision and all its ancestors
4007 will be pushed to the remote repository.
4007 will be pushed to the remote repository.
4008
4008
4009 Please see :hg:`help urls` for important details about ``ssh://``
4009 Please see :hg:`help urls` for important details about ``ssh://``
4010 URLs. If DESTINATION is omitted, a default path will be used.
4010 URLs. If DESTINATION is omitted, a default path will be used.
4011
4011
4012 Returns 0 if push was successful, 1 if nothing to push.
4012 Returns 0 if push was successful, 1 if nothing to push.
4013 """
4013 """
4014
4014
4015 if opts.get('bookmark'):
4015 if opts.get('bookmark'):
4016 for b in opts['bookmark']:
4016 for b in opts['bookmark']:
4017 # translate -B options to -r so changesets get pushed
4017 # translate -B options to -r so changesets get pushed
4018 if b in repo._bookmarks:
4018 if b in repo._bookmarks:
4019 opts.setdefault('rev', []).append(b)
4019 opts.setdefault('rev', []).append(b)
4020 else:
4020 else:
4021 # if we try to push a deleted bookmark, translate it to null
4021 # if we try to push a deleted bookmark, translate it to null
4022 # this lets simultaneous -r, -b options continue working
4022 # this lets simultaneous -r, -b options continue working
4023 opts.setdefault('rev', []).append("null")
4023 opts.setdefault('rev', []).append("null")
4024
4024
4025 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4025 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4026 dest, branches = hg.parseurl(dest, opts.get('branch'))
4026 dest, branches = hg.parseurl(dest, opts.get('branch'))
4027 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4027 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4028 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4028 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4029 other = hg.peer(repo, opts, dest)
4029 other = hg.peer(repo, opts, dest)
4030 if revs:
4030 if revs:
4031 revs = [repo.lookup(rev) for rev in revs]
4031 revs = [repo.lookup(rev) for rev in revs]
4032
4032
4033 repo._subtoppath = dest
4033 repo._subtoppath = dest
4034 try:
4034 try:
4035 # push subrepos depth-first for coherent ordering
4035 # push subrepos depth-first for coherent ordering
4036 c = repo['']
4036 c = repo['']
4037 subs = c.substate # only repos that are committed
4037 subs = c.substate # only repos that are committed
4038 for s in sorted(subs):
4038 for s in sorted(subs):
4039 if not c.sub(s).push(opts.get('force')):
4039 if not c.sub(s).push(opts.get('force')):
4040 return False
4040 return False
4041 finally:
4041 finally:
4042 del repo._subtoppath
4042 del repo._subtoppath
4043 result = repo.push(other, opts.get('force'), revs=revs,
4043 result = repo.push(other, opts.get('force'), revs=revs,
4044 newbranch=opts.get('new_branch'))
4044 newbranch=opts.get('new_branch'))
4045
4045
4046 result = (result == 0)
4046 result = (result == 0)
4047
4047
4048 if opts.get('bookmark'):
4048 if opts.get('bookmark'):
4049 rb = other.listkeys('bookmarks')
4049 rb = other.listkeys('bookmarks')
4050 for b in opts['bookmark']:
4050 for b in opts['bookmark']:
4051 # explicit push overrides remote bookmark if any
4051 # explicit push overrides remote bookmark if any
4052 if b in repo._bookmarks:
4052 if b in repo._bookmarks:
4053 ui.status(_("exporting bookmark %s\n") % b)
4053 ui.status(_("exporting bookmark %s\n") % b)
4054 new = repo[b].hex()
4054 new = repo[b].hex()
4055 elif b in rb:
4055 elif b in rb:
4056 ui.status(_("deleting remote bookmark %s\n") % b)
4056 ui.status(_("deleting remote bookmark %s\n") % b)
4057 new = '' # delete
4057 new = '' # delete
4058 else:
4058 else:
4059 ui.warn(_('bookmark %s does not exist on the local '
4059 ui.warn(_('bookmark %s does not exist on the local '
4060 'or remote repository!\n') % b)
4060 'or remote repository!\n') % b)
4061 return 2
4061 return 2
4062 old = rb.get(b, '')
4062 old = rb.get(b, '')
4063 r = other.pushkey('bookmarks', b, old, new)
4063 r = other.pushkey('bookmarks', b, old, new)
4064 if not r:
4064 if not r:
4065 ui.warn(_('updating bookmark %s failed!\n') % b)
4065 ui.warn(_('updating bookmark %s failed!\n') % b)
4066 if not result:
4066 if not result:
4067 result = 2
4067 result = 2
4068
4068
4069 return result
4069 return result
4070
4070
4071 @command('recover', [])
4071 @command('recover', [])
4072 def recover(ui, repo):
4072 def recover(ui, repo):
4073 """roll back an interrupted transaction
4073 """roll back an interrupted transaction
4074
4074
4075 Recover from an interrupted commit or pull.
4075 Recover from an interrupted commit or pull.
4076
4076
4077 This command tries to fix the repository status after an
4077 This command tries to fix the repository status after an
4078 interrupted operation. It should only be necessary when Mercurial
4078 interrupted operation. It should only be necessary when Mercurial
4079 suggests it.
4079 suggests it.
4080
4080
4081 Returns 0 if successful, 1 if nothing to recover or verify fails.
4081 Returns 0 if successful, 1 if nothing to recover or verify fails.
4082 """
4082 """
4083 if repo.recover():
4083 if repo.recover():
4084 return hg.verify(repo)
4084 return hg.verify(repo)
4085 return 1
4085 return 1
4086
4086
4087 @command('^remove|rm',
4087 @command('^remove|rm',
4088 [('A', 'after', None, _('record delete for missing files')),
4088 [('A', 'after', None, _('record delete for missing files')),
4089 ('f', 'force', None,
4089 ('f', 'force', None,
4090 _('remove (and delete) file even if added or modified')),
4090 _('remove (and delete) file even if added or modified')),
4091 ] + walkopts,
4091 ] + walkopts,
4092 _('[OPTION]... FILE...'))
4092 _('[OPTION]... FILE...'))
4093 def remove(ui, repo, *pats, **opts):
4093 def remove(ui, repo, *pats, **opts):
4094 """remove the specified files on the next commit
4094 """remove the specified files on the next commit
4095
4095
4096 Schedule the indicated files for removal from the current branch.
4096 Schedule the indicated files for removal from the current branch.
4097
4097
4098 This command schedules the files to be removed at the next commit.
4098 This command schedules the files to be removed at the next commit.
4099 To undo a remove before that, see :hg:`revert`. To undo added
4099 To undo a remove before that, see :hg:`revert`. To undo added
4100 files, see :hg:`forget`.
4100 files, see :hg:`forget`.
4101
4101
4102 .. container:: verbose
4102 .. container:: verbose
4103
4103
4104 -A/--after can be used to remove only files that have already
4104 -A/--after can be used to remove only files that have already
4105 been deleted, -f/--force can be used to force deletion, and -Af
4105 been deleted, -f/--force can be used to force deletion, and -Af
4106 can be used to remove files from the next revision without
4106 can be used to remove files from the next revision without
4107 deleting them from the working directory.
4107 deleting them from the working directory.
4108
4108
4109 The following table details the behavior of remove for different
4109 The following table details the behavior of remove for different
4110 file states (columns) and option combinations (rows). The file
4110 file states (columns) and option combinations (rows). The file
4111 states are Added [A], Clean [C], Modified [M] and Missing [!]
4111 states are Added [A], Clean [C], Modified [M] and Missing [!]
4112 (as reported by :hg:`status`). The actions are Warn, Remove
4112 (as reported by :hg:`status`). The actions are Warn, Remove
4113 (from branch) and Delete (from disk):
4113 (from branch) and Delete (from disk):
4114
4114
4115 ======= == == == ==
4115 ======= == == == ==
4116 A C M !
4116 A C M !
4117 ======= == == == ==
4117 ======= == == == ==
4118 none W RD W R
4118 none W RD W R
4119 -f R RD RD R
4119 -f R RD RD R
4120 -A W W W R
4120 -A W W W R
4121 -Af R R R R
4121 -Af R R R R
4122 ======= == == == ==
4122 ======= == == == ==
4123
4123
4124 Note that remove never deletes files in Added [A] state from the
4124 Note that remove never deletes files in Added [A] state from the
4125 working directory, not even if option --force is specified.
4125 working directory, not even if option --force is specified.
4126
4126
4127 Returns 0 on success, 1 if any warnings encountered.
4127 Returns 0 on success, 1 if any warnings encountered.
4128 """
4128 """
4129
4129
4130 ret = 0
4130 ret = 0
4131 after, force = opts.get('after'), opts.get('force')
4131 after, force = opts.get('after'), opts.get('force')
4132 if not pats and not after:
4132 if not pats and not after:
4133 raise util.Abort(_('no files specified'))
4133 raise util.Abort(_('no files specified'))
4134
4134
4135 m = scmutil.match(repo[None], pats, opts)
4135 m = scmutil.match(repo[None], pats, opts)
4136 s = repo.status(match=m, clean=True)
4136 s = repo.status(match=m, clean=True)
4137 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4137 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4138
4138
4139 for f in m.files():
4139 for f in m.files():
4140 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4140 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4141 if os.path.exists(m.rel(f)):
4141 if os.path.exists(m.rel(f)):
4142 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4142 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4143 ret = 1
4143 ret = 1
4144
4144
4145 if force:
4145 if force:
4146 list = modified + deleted + clean + added
4146 list = modified + deleted + clean + added
4147 elif after:
4147 elif after:
4148 list = deleted
4148 list = deleted
4149 for f in modified + added + clean:
4149 for f in modified + added + clean:
4150 ui.warn(_('not removing %s: file still exists (use -f'
4150 ui.warn(_('not removing %s: file still exists (use -f'
4151 ' to force removal)\n') % m.rel(f))
4151 ' to force removal)\n') % m.rel(f))
4152 ret = 1
4152 ret = 1
4153 else:
4153 else:
4154 list = deleted + clean
4154 list = deleted + clean
4155 for f in modified:
4155 for f in modified:
4156 ui.warn(_('not removing %s: file is modified (use -f'
4156 ui.warn(_('not removing %s: file is modified (use -f'
4157 ' to force removal)\n') % m.rel(f))
4157 ' to force removal)\n') % m.rel(f))
4158 ret = 1
4158 ret = 1
4159 for f in added:
4159 for f in added:
4160 ui.warn(_('not removing %s: file has been marked for add'
4160 ui.warn(_('not removing %s: file has been marked for add'
4161 ' (use forget to undo)\n') % m.rel(f))
4161 ' (use forget to undo)\n') % m.rel(f))
4162 ret = 1
4162 ret = 1
4163
4163
4164 for f in sorted(list):
4164 for f in sorted(list):
4165 if ui.verbose or not m.exact(f):
4165 if ui.verbose or not m.exact(f):
4166 ui.status(_('removing %s\n') % m.rel(f))
4166 ui.status(_('removing %s\n') % m.rel(f))
4167
4167
4168 wlock = repo.wlock()
4168 wlock = repo.wlock()
4169 try:
4169 try:
4170 if not after:
4170 if not after:
4171 for f in list:
4171 for f in list:
4172 if f in added:
4172 if f in added:
4173 continue # we never unlink added files on remove
4173 continue # we never unlink added files on remove
4174 try:
4174 try:
4175 util.unlinkpath(repo.wjoin(f))
4175 util.unlinkpath(repo.wjoin(f))
4176 except OSError, inst:
4176 except OSError, inst:
4177 if inst.errno != errno.ENOENT:
4177 if inst.errno != errno.ENOENT:
4178 raise
4178 raise
4179 repo[None].forget(list)
4179 repo[None].forget(list)
4180 finally:
4180 finally:
4181 wlock.release()
4181 wlock.release()
4182
4182
4183 return ret
4183 return ret
4184
4184
4185 @command('rename|move|mv',
4185 @command('rename|move|mv',
4186 [('A', 'after', None, _('record a rename that has already occurred')),
4186 [('A', 'after', None, _('record a rename that has already occurred')),
4187 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4187 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4188 ] + walkopts + dryrunopts,
4188 ] + walkopts + dryrunopts,
4189 _('[OPTION]... SOURCE... DEST'))
4189 _('[OPTION]... SOURCE... DEST'))
4190 def rename(ui, repo, *pats, **opts):
4190 def rename(ui, repo, *pats, **opts):
4191 """rename files; equivalent of copy + remove
4191 """rename files; equivalent of copy + remove
4192
4192
4193 Mark dest as copies of sources; mark sources for deletion. If dest
4193 Mark dest as copies of sources; mark sources for deletion. If dest
4194 is a directory, copies are put in that directory. If dest is a
4194 is a directory, copies are put in that directory. If dest is a
4195 file, there can only be one source.
4195 file, there can only be one source.
4196
4196
4197 By default, this command copies the contents of files as they
4197 By default, this command copies the contents of files as they
4198 exist in the working directory. If invoked with -A/--after, the
4198 exist in the working directory. If invoked with -A/--after, the
4199 operation is recorded, but no copying is performed.
4199 operation is recorded, but no copying is performed.
4200
4200
4201 This command takes effect at the next commit. To undo a rename
4201 This command takes effect at the next commit. To undo a rename
4202 before that, see :hg:`revert`.
4202 before that, see :hg:`revert`.
4203
4203
4204 Returns 0 on success, 1 if errors are encountered.
4204 Returns 0 on success, 1 if errors are encountered.
4205 """
4205 """
4206 wlock = repo.wlock(False)
4206 wlock = repo.wlock(False)
4207 try:
4207 try:
4208 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4208 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4209 finally:
4209 finally:
4210 wlock.release()
4210 wlock.release()
4211
4211
4212 @command('resolve',
4212 @command('resolve',
4213 [('a', 'all', None, _('select all unresolved files')),
4213 [('a', 'all', None, _('select all unresolved files')),
4214 ('l', 'list', None, _('list state of files needing merge')),
4214 ('l', 'list', None, _('list state of files needing merge')),
4215 ('m', 'mark', None, _('mark files as resolved')),
4215 ('m', 'mark', None, _('mark files as resolved')),
4216 ('u', 'unmark', None, _('mark files as unresolved')),
4216 ('u', 'unmark', None, _('mark files as unresolved')),
4217 ('n', 'no-status', None, _('hide status prefix'))]
4217 ('n', 'no-status', None, _('hide status prefix'))]
4218 + mergetoolopts + walkopts,
4218 + mergetoolopts + walkopts,
4219 _('[OPTION]... [FILE]...'))
4219 _('[OPTION]... [FILE]...'))
4220 def resolve(ui, repo, *pats, **opts):
4220 def resolve(ui, repo, *pats, **opts):
4221 """redo merges or set/view the merge status of files
4221 """redo merges or set/view the merge status of files
4222
4222
4223 Merges with unresolved conflicts are often the result of
4223 Merges with unresolved conflicts are often the result of
4224 non-interactive merging using the ``internal:merge`` configuration
4224 non-interactive merging using the ``internal:merge`` configuration
4225 setting, or a command-line merge tool like ``diff3``. The resolve
4225 setting, or a command-line merge tool like ``diff3``. The resolve
4226 command is used to manage the files involved in a merge, after
4226 command is used to manage the files involved in a merge, after
4227 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4227 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4228 working directory must have two parents).
4228 working directory must have two parents).
4229
4229
4230 The resolve command can be used in the following ways:
4230 The resolve command can be used in the following ways:
4231
4231
4232 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4232 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4233 files, discarding any previous merge attempts. Re-merging is not
4233 files, discarding any previous merge attempts. Re-merging is not
4234 performed for files already marked as resolved. Use ``--all/-a``
4234 performed for files already marked as resolved. Use ``--all/-a``
4235 to select all unresolved files. ``--tool`` can be used to specify
4235 to select all unresolved files. ``--tool`` can be used to specify
4236 the merge tool used for the given files. It overrides the HGMERGE
4236 the merge tool used for the given files. It overrides the HGMERGE
4237 environment variable and your configuration files.
4237 environment variable and your configuration files.
4238
4238
4239 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4239 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4240 (e.g. after having manually fixed-up the files). The default is
4240 (e.g. after having manually fixed-up the files). The default is
4241 to mark all unresolved files.
4241 to mark all unresolved files.
4242
4242
4243 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4243 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4244 default is to mark all resolved files.
4244 default is to mark all resolved files.
4245
4245
4246 - :hg:`resolve -l`: list files which had or still have conflicts.
4246 - :hg:`resolve -l`: list files which had or still have conflicts.
4247 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4247 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4248
4248
4249 Note that Mercurial will not let you commit files with unresolved
4249 Note that Mercurial will not let you commit files with unresolved
4250 merge conflicts. You must use :hg:`resolve -m ...` before you can
4250 merge conflicts. You must use :hg:`resolve -m ...` before you can
4251 commit after a conflicting merge.
4251 commit after a conflicting merge.
4252
4252
4253 Returns 0 on success, 1 if any files fail a resolve attempt.
4253 Returns 0 on success, 1 if any files fail a resolve attempt.
4254 """
4254 """
4255
4255
4256 all, mark, unmark, show, nostatus = \
4256 all, mark, unmark, show, nostatus = \
4257 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4257 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4258
4258
4259 if (show and (mark or unmark)) or (mark and unmark):
4259 if (show and (mark or unmark)) or (mark and unmark):
4260 raise util.Abort(_("too many options specified"))
4260 raise util.Abort(_("too many options specified"))
4261 if pats and all:
4261 if pats and all:
4262 raise util.Abort(_("can't specify --all and patterns"))
4262 raise util.Abort(_("can't specify --all and patterns"))
4263 if not (all or pats or show or mark or unmark):
4263 if not (all or pats or show or mark or unmark):
4264 raise util.Abort(_('no files or directories specified; '
4264 raise util.Abort(_('no files or directories specified; '
4265 'use --all to remerge all files'))
4265 'use --all to remerge all files'))
4266
4266
4267 ms = mergemod.mergestate(repo)
4267 ms = mergemod.mergestate(repo)
4268 m = scmutil.match(repo[None], pats, opts)
4268 m = scmutil.match(repo[None], pats, opts)
4269 ret = 0
4269 ret = 0
4270
4270
4271 for f in ms:
4271 for f in ms:
4272 if m(f):
4272 if m(f):
4273 if show:
4273 if show:
4274 if nostatus:
4274 if nostatus:
4275 ui.write("%s\n" % f)
4275 ui.write("%s\n" % f)
4276 else:
4276 else:
4277 ui.write("%s %s\n" % (ms[f].upper(), f),
4277 ui.write("%s %s\n" % (ms[f].upper(), f),
4278 label='resolve.' +
4278 label='resolve.' +
4279 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4279 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4280 elif mark:
4280 elif mark:
4281 ms.mark(f, "r")
4281 ms.mark(f, "r")
4282 elif unmark:
4282 elif unmark:
4283 ms.mark(f, "u")
4283 ms.mark(f, "u")
4284 else:
4284 else:
4285 wctx = repo[None]
4285 wctx = repo[None]
4286 mctx = wctx.parents()[-1]
4286 mctx = wctx.parents()[-1]
4287
4287
4288 # backup pre-resolve (merge uses .orig for its own purposes)
4288 # backup pre-resolve (merge uses .orig for its own purposes)
4289 a = repo.wjoin(f)
4289 a = repo.wjoin(f)
4290 util.copyfile(a, a + ".resolve")
4290 util.copyfile(a, a + ".resolve")
4291
4291
4292 try:
4292 try:
4293 # resolve file
4293 # resolve file
4294 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4294 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4295 if ms.resolve(f, wctx, mctx):
4295 if ms.resolve(f, wctx, mctx):
4296 ret = 1
4296 ret = 1
4297 finally:
4297 finally:
4298 ui.setconfig('ui', 'forcemerge', '')
4298 ui.setconfig('ui', 'forcemerge', '')
4299
4299
4300 # replace filemerge's .orig file with our resolve file
4300 # replace filemerge's .orig file with our resolve file
4301 util.rename(a + ".resolve", a + ".orig")
4301 util.rename(a + ".resolve", a + ".orig")
4302
4302
4303 ms.commit()
4303 ms.commit()
4304 return ret
4304 return ret
4305
4305
4306 @command('revert',
4306 @command('revert',
4307 [('a', 'all', None, _('revert all changes when no arguments given')),
4307 [('a', 'all', None, _('revert all changes when no arguments given')),
4308 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4308 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4309 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4309 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4310 ('C', 'no-backup', None, _('do not save backup copies of files')),
4310 ('C', 'no-backup', None, _('do not save backup copies of files')),
4311 ] + walkopts + dryrunopts,
4311 ] + walkopts + dryrunopts,
4312 _('[OPTION]... [-r REV] [NAME]...'))
4312 _('[OPTION]... [-r REV] [NAME]...'))
4313 def revert(ui, repo, *pats, **opts):
4313 def revert(ui, repo, *pats, **opts):
4314 """restore files to their checkout state
4314 """restore files to their checkout state
4315
4315
4316 .. note::
4316 .. note::
4317 To check out earlier revisions, you should use :hg:`update REV`.
4317 To check out earlier revisions, you should use :hg:`update REV`.
4318 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4318 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4319
4319
4320 With no revision specified, revert the specified files or directories
4320 With no revision specified, revert the specified files or directories
4321 to the contents they had in the parent of the working directory.
4321 to the contents they had in the parent of the working directory.
4322 This restores the contents of files to an unmodified
4322 This restores the contents of files to an unmodified
4323 state and unschedules adds, removes, copies, and renames. If the
4323 state and unschedules adds, removes, copies, and renames. If the
4324 working directory has two parents, you must explicitly specify a
4324 working directory has two parents, you must explicitly specify a
4325 revision.
4325 revision.
4326
4326
4327 Using the -r/--rev or -d/--date options, revert the given files or
4327 Using the -r/--rev or -d/--date options, revert the given files or
4328 directories to their states as of a specific revision. Because
4328 directories to their states as of a specific revision. Because
4329 revert does not change the working directory parents, this will
4329 revert does not change the working directory parents, this will
4330 cause these files to appear modified. This can be helpful to "back
4330 cause these files to appear modified. This can be helpful to "back
4331 out" some or all of an earlier change. See :hg:`backout` for a
4331 out" some or all of an earlier change. See :hg:`backout` for a
4332 related method.
4332 related method.
4333
4333
4334 Modified files are saved with a .orig suffix before reverting.
4334 Modified files are saved with a .orig suffix before reverting.
4335 To disable these backups, use --no-backup.
4335 To disable these backups, use --no-backup.
4336
4336
4337 See :hg:`help dates` for a list of formats valid for -d/--date.
4337 See :hg:`help dates` for a list of formats valid for -d/--date.
4338
4338
4339 Returns 0 on success.
4339 Returns 0 on success.
4340 """
4340 """
4341
4341
4342 if opts.get("date"):
4342 if opts.get("date"):
4343 if opts.get("rev"):
4343 if opts.get("rev"):
4344 raise util.Abort(_("you can't specify a revision and a date"))
4344 raise util.Abort(_("you can't specify a revision and a date"))
4345 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4345 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4346
4346
4347 parent, p2 = repo.dirstate.parents()
4347 parent, p2 = repo.dirstate.parents()
4348 if not opts.get('rev') and p2 != nullid:
4348 if not opts.get('rev') and p2 != nullid:
4349 # revert after merge is a trap for new users (issue2915)
4349 # revert after merge is a trap for new users (issue2915)
4350 raise util.Abort(_('uncommitted merge with no revision specified'),
4350 raise util.Abort(_('uncommitted merge with no revision specified'),
4351 hint=_('use "hg update" or see "hg help revert"'))
4351 hint=_('use "hg update" or see "hg help revert"'))
4352
4352
4353 ctx = scmutil.revsingle(repo, opts.get('rev'))
4353 ctx = scmutil.revsingle(repo, opts.get('rev'))
4354 node = ctx.node()
4354 node = ctx.node()
4355
4355
4356 if not pats and not opts.get('all'):
4356 if not pats and not opts.get('all'):
4357 msg = _("no files or directories specified")
4357 msg = _("no files or directories specified")
4358 if p2 != nullid:
4358 if p2 != nullid:
4359 hint = _("uncommitted merge, use --all to discard all changes,"
4359 hint = _("uncommitted merge, use --all to discard all changes,"
4360 " or 'hg update -C .' to abort the merge")
4360 " or 'hg update -C .' to abort the merge")
4361 raise util.Abort(msg, hint=hint)
4361 raise util.Abort(msg, hint=hint)
4362 dirty = util.any(repo.status())
4362 dirty = util.any(repo.status())
4363 if node != parent:
4363 if node != parent:
4364 if dirty:
4364 if dirty:
4365 hint = _("uncommitted changes, use --all to discard all"
4365 hint = _("uncommitted changes, use --all to discard all"
4366 " changes, or 'hg update %s' to update") % ctx.rev()
4366 " changes, or 'hg update %s' to update") % ctx.rev()
4367 else:
4367 else:
4368 hint = _("use --all to revert all files,"
4368 hint = _("use --all to revert all files,"
4369 " or 'hg update %s' to update") % ctx.rev()
4369 " or 'hg update %s' to update") % ctx.rev()
4370 elif dirty:
4370 elif dirty:
4371 hint = _("uncommitted changes, use --all to discard all changes")
4371 hint = _("uncommitted changes, use --all to discard all changes")
4372 else:
4372 else:
4373 hint = _("use --all to revert all files")
4373 hint = _("use --all to revert all files")
4374 raise util.Abort(msg, hint=hint)
4374 raise util.Abort(msg, hint=hint)
4375
4375
4376 mf = ctx.manifest()
4376 mf = ctx.manifest()
4377 if node == parent:
4377 if node == parent:
4378 pmf = mf
4378 pmf = mf
4379 else:
4379 else:
4380 pmf = None
4380 pmf = None
4381
4381
4382 # need all matching names in dirstate and manifest of target rev,
4382 # need all matching names in dirstate and manifest of target rev,
4383 # so have to walk both. do not print errors if files exist in one
4383 # so have to walk both. do not print errors if files exist in one
4384 # but not other.
4384 # but not other.
4385
4385
4386 names = {}
4386 names = {}
4387
4387
4388 wlock = repo.wlock()
4388 wlock = repo.wlock()
4389 try:
4389 try:
4390 # walk dirstate.
4390 # walk dirstate.
4391
4391
4392 m = scmutil.match(repo[None], pats, opts)
4392 m = scmutil.match(repo[None], pats, opts)
4393 m.bad = lambda x, y: False
4393 m.bad = lambda x, y: False
4394 for abs in repo.walk(m):
4394 for abs in repo.walk(m):
4395 names[abs] = m.rel(abs), m.exact(abs)
4395 names[abs] = m.rel(abs), m.exact(abs)
4396
4396
4397 # walk target manifest.
4397 # walk target manifest.
4398
4398
4399 def badfn(path, msg):
4399 def badfn(path, msg):
4400 if path in names:
4400 if path in names:
4401 return
4401 return
4402 path_ = path + '/'
4402 path_ = path + '/'
4403 for f in names:
4403 for f in names:
4404 if f.startswith(path_):
4404 if f.startswith(path_):
4405 return
4405 return
4406 ui.warn("%s: %s\n" % (m.rel(path), msg))
4406 ui.warn("%s: %s\n" % (m.rel(path), msg))
4407
4407
4408 m = scmutil.match(repo[node], pats, opts)
4408 m = scmutil.match(repo[node], pats, opts)
4409 m.bad = badfn
4409 m.bad = badfn
4410 for abs in repo[node].walk(m):
4410 for abs in repo[node].walk(m):
4411 if abs not in names:
4411 if abs not in names:
4412 names[abs] = m.rel(abs), m.exact(abs)
4412 names[abs] = m.rel(abs), m.exact(abs)
4413
4413
4414 m = scmutil.matchfiles(repo, names)
4414 m = scmutil.matchfiles(repo, names)
4415 changes = repo.status(match=m)[:4]
4415 changes = repo.status(match=m)[:4]
4416 modified, added, removed, deleted = map(set, changes)
4416 modified, added, removed, deleted = map(set, changes)
4417
4417
4418 # if f is a rename, also revert the source
4418 # if f is a rename, also revert the source
4419 cwd = repo.getcwd()
4419 cwd = repo.getcwd()
4420 for f in added:
4420 for f in added:
4421 src = repo.dirstate.copied(f)
4421 src = repo.dirstate.copied(f)
4422 if src and src not in names and repo.dirstate[src] == 'r':
4422 if src and src not in names and repo.dirstate[src] == 'r':
4423 removed.add(src)
4423 removed.add(src)
4424 names[src] = (repo.pathto(src, cwd), True)
4424 names[src] = (repo.pathto(src, cwd), True)
4425
4425
4426 def removeforget(abs):
4426 def removeforget(abs):
4427 if repo.dirstate[abs] == 'a':
4427 if repo.dirstate[abs] == 'a':
4428 return _('forgetting %s\n')
4428 return _('forgetting %s\n')
4429 return _('removing %s\n')
4429 return _('removing %s\n')
4430
4430
4431 revert = ([], _('reverting %s\n'))
4431 revert = ([], _('reverting %s\n'))
4432 add = ([], _('adding %s\n'))
4432 add = ([], _('adding %s\n'))
4433 remove = ([], removeforget)
4433 remove = ([], removeforget)
4434 undelete = ([], _('undeleting %s\n'))
4434 undelete = ([], _('undeleting %s\n'))
4435
4435
4436 disptable = (
4436 disptable = (
4437 # dispatch table:
4437 # dispatch table:
4438 # file state
4438 # file state
4439 # action if in target manifest
4439 # action if in target manifest
4440 # action if not in target manifest
4440 # action if not in target manifest
4441 # make backup if in target manifest
4441 # make backup if in target manifest
4442 # make backup if not in target manifest
4442 # make backup if not in target manifest
4443 (modified, revert, remove, True, True),
4443 (modified, revert, remove, True, True),
4444 (added, revert, remove, True, False),
4444 (added, revert, remove, True, False),
4445 (removed, undelete, None, False, False),
4445 (removed, undelete, None, False, False),
4446 (deleted, revert, remove, False, False),
4446 (deleted, revert, remove, False, False),
4447 )
4447 )
4448
4448
4449 for abs, (rel, exact) in sorted(names.items()):
4449 for abs, (rel, exact) in sorted(names.items()):
4450 mfentry = mf.get(abs)
4450 mfentry = mf.get(abs)
4451 target = repo.wjoin(abs)
4451 target = repo.wjoin(abs)
4452 def handle(xlist, dobackup):
4452 def handle(xlist, dobackup):
4453 xlist[0].append(abs)
4453 xlist[0].append(abs)
4454 if (dobackup and not opts.get('no_backup') and
4454 if (dobackup and not opts.get('no_backup') and
4455 os.path.lexists(target)):
4455 os.path.lexists(target)):
4456 bakname = "%s.orig" % rel
4456 bakname = "%s.orig" % rel
4457 ui.note(_('saving current version of %s as %s\n') %
4457 ui.note(_('saving current version of %s as %s\n') %
4458 (rel, bakname))
4458 (rel, bakname))
4459 if not opts.get('dry_run'):
4459 if not opts.get('dry_run'):
4460 util.rename(target, bakname)
4460 util.rename(target, bakname)
4461 if ui.verbose or not exact:
4461 if ui.verbose or not exact:
4462 msg = xlist[1]
4462 msg = xlist[1]
4463 if not isinstance(msg, basestring):
4463 if not isinstance(msg, basestring):
4464 msg = msg(abs)
4464 msg = msg(abs)
4465 ui.status(msg % rel)
4465 ui.status(msg % rel)
4466 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4466 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4467 if abs not in table:
4467 if abs not in table:
4468 continue
4468 continue
4469 # file has changed in dirstate
4469 # file has changed in dirstate
4470 if mfentry:
4470 if mfentry:
4471 handle(hitlist, backuphit)
4471 handle(hitlist, backuphit)
4472 elif misslist is not None:
4472 elif misslist is not None:
4473 handle(misslist, backupmiss)
4473 handle(misslist, backupmiss)
4474 break
4474 break
4475 else:
4475 else:
4476 if abs not in repo.dirstate:
4476 if abs not in repo.dirstate:
4477 if mfentry:
4477 if mfentry:
4478 handle(add, True)
4478 handle(add, True)
4479 elif exact:
4479 elif exact:
4480 ui.warn(_('file not managed: %s\n') % rel)
4480 ui.warn(_('file not managed: %s\n') % rel)
4481 continue
4481 continue
4482 # file has not changed in dirstate
4482 # file has not changed in dirstate
4483 if node == parent:
4483 if node == parent:
4484 if exact:
4484 if exact:
4485 ui.warn(_('no changes needed to %s\n') % rel)
4485 ui.warn(_('no changes needed to %s\n') % rel)
4486 continue
4486 continue
4487 if pmf is None:
4487 if pmf is None:
4488 # only need parent manifest in this unlikely case,
4488 # only need parent manifest in this unlikely case,
4489 # so do not read by default
4489 # so do not read by default
4490 pmf = repo[parent].manifest()
4490 pmf = repo[parent].manifest()
4491 if abs in pmf:
4491 if abs in pmf:
4492 if mfentry:
4492 if mfentry:
4493 # if version of file is same in parent and target
4493 # if version of file is same in parent and target
4494 # manifests, do nothing
4494 # manifests, do nothing
4495 if (pmf[abs] != mfentry or
4495 if (pmf[abs] != mfentry or
4496 pmf.flags(abs) != mf.flags(abs)):
4496 pmf.flags(abs) != mf.flags(abs)):
4497 handle(revert, False)
4497 handle(revert, False)
4498 else:
4498 else:
4499 handle(remove, False)
4499 handle(remove, False)
4500
4500
4501 if not opts.get('dry_run'):
4501 if not opts.get('dry_run'):
4502 def checkout(f):
4502 def checkout(f):
4503 fc = ctx[f]
4503 fc = ctx[f]
4504 repo.wwrite(f, fc.data(), fc.flags())
4504 repo.wwrite(f, fc.data(), fc.flags())
4505
4505
4506 audit_path = scmutil.pathauditor(repo.root)
4506 audit_path = scmutil.pathauditor(repo.root)
4507 for f in remove[0]:
4507 for f in remove[0]:
4508 if repo.dirstate[f] == 'a':
4508 if repo.dirstate[f] == 'a':
4509 repo.dirstate.drop(f)
4509 repo.dirstate.drop(f)
4510 continue
4510 continue
4511 audit_path(f)
4511 audit_path(f)
4512 try:
4512 try:
4513 util.unlinkpath(repo.wjoin(f))
4513 util.unlinkpath(repo.wjoin(f))
4514 except OSError:
4514 except OSError:
4515 pass
4515 pass
4516 repo.dirstate.remove(f)
4516 repo.dirstate.remove(f)
4517
4517
4518 normal = None
4518 normal = None
4519 if node == parent:
4519 if node == parent:
4520 # We're reverting to our parent. If possible, we'd like status
4520 # We're reverting to our parent. If possible, we'd like status
4521 # to report the file as clean. We have to use normallookup for
4521 # to report the file as clean. We have to use normallookup for
4522 # merges to avoid losing information about merged/dirty files.
4522 # merges to avoid losing information about merged/dirty files.
4523 if p2 != nullid:
4523 if p2 != nullid:
4524 normal = repo.dirstate.normallookup
4524 normal = repo.dirstate.normallookup
4525 else:
4525 else:
4526 normal = repo.dirstate.normal
4526 normal = repo.dirstate.normal
4527 for f in revert[0]:
4527 for f in revert[0]:
4528 checkout(f)
4528 checkout(f)
4529 if normal:
4529 if normal:
4530 normal(f)
4530 normal(f)
4531
4531
4532 for f in add[0]:
4532 for f in add[0]:
4533 checkout(f)
4533 checkout(f)
4534 repo.dirstate.add(f)
4534 repo.dirstate.add(f)
4535
4535
4536 normal = repo.dirstate.normallookup
4536 normal = repo.dirstate.normallookup
4537 if node == parent and p2 == nullid:
4537 if node == parent and p2 == nullid:
4538 normal = repo.dirstate.normal
4538 normal = repo.dirstate.normal
4539 for f in undelete[0]:
4539 for f in undelete[0]:
4540 checkout(f)
4540 checkout(f)
4541 normal(f)
4541 normal(f)
4542
4542
4543 finally:
4543 finally:
4544 wlock.release()
4544 wlock.release()
4545
4545
4546 @command('rollback', dryrunopts)
4546 @command('rollback', dryrunopts)
4547 def rollback(ui, repo, **opts):
4547 def rollback(ui, repo, **opts):
4548 """roll back the last transaction (dangerous)
4548 """roll back the last transaction (dangerous)
4549
4549
4550 This command should be used with care. There is only one level of
4550 This command should be used with care. There is only one level of
4551 rollback, and there is no way to undo a rollback. It will also
4551 rollback, and there is no way to undo a rollback. It will also
4552 restore the dirstate at the time of the last transaction, losing
4552 restore the dirstate at the time of the last transaction, losing
4553 any dirstate changes since that time. This command does not alter
4553 any dirstate changes since that time. This command does not alter
4554 the working directory.
4554 the working directory.
4555
4555
4556 Transactions are used to encapsulate the effects of all commands
4556 Transactions are used to encapsulate the effects of all commands
4557 that create new changesets or propagate existing changesets into a
4557 that create new changesets or propagate existing changesets into a
4558 repository. For example, the following commands are transactional,
4558 repository. For example, the following commands are transactional,
4559 and their effects can be rolled back:
4559 and their effects can be rolled back:
4560
4560
4561 - commit
4561 - commit
4562 - import
4562 - import
4563 - pull
4563 - pull
4564 - push (with this repository as the destination)
4564 - push (with this repository as the destination)
4565 - unbundle
4565 - unbundle
4566
4566
4567 This command is not intended for use on public repositories. Once
4567 This command is not intended for use on public repositories. Once
4568 changes are visible for pull by other users, rolling a transaction
4568 changes are visible for pull by other users, rolling a transaction
4569 back locally is ineffective (someone else may already have pulled
4569 back locally is ineffective (someone else may already have pulled
4570 the changes). Furthermore, a race is possible with readers of the
4570 the changes). Furthermore, a race is possible with readers of the
4571 repository; for example an in-progress pull from the repository
4571 repository; for example an in-progress pull from the repository
4572 may fail if a rollback is performed.
4572 may fail if a rollback is performed.
4573
4573
4574 Returns 0 on success, 1 if no rollback data is available.
4574 Returns 0 on success, 1 if no rollback data is available.
4575 """
4575 """
4576 return repo.rollback(opts.get('dry_run'))
4576 return repo.rollback(opts.get('dry_run'))
4577
4577
4578 @command('root', [])
4578 @command('root', [])
4579 def root(ui, repo):
4579 def root(ui, repo):
4580 """print the root (top) of the current working directory
4580 """print the root (top) of the current working directory
4581
4581
4582 Print the root directory of the current repository.
4582 Print the root directory of the current repository.
4583
4583
4584 Returns 0 on success.
4584 Returns 0 on success.
4585 """
4585 """
4586 ui.write(repo.root + "\n")
4586 ui.write(repo.root + "\n")
4587
4587
4588 @command('^serve',
4588 @command('^serve',
4589 [('A', 'accesslog', '', _('name of access log file to write to'),
4589 [('A', 'accesslog', '', _('name of access log file to write to'),
4590 _('FILE')),
4590 _('FILE')),
4591 ('d', 'daemon', None, _('run server in background')),
4591 ('d', 'daemon', None, _('run server in background')),
4592 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4592 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4593 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4593 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4594 # use string type, then we can check if something was passed
4594 # use string type, then we can check if something was passed
4595 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4595 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4596 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4596 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4597 _('ADDR')),
4597 _('ADDR')),
4598 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4598 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4599 _('PREFIX')),
4599 _('PREFIX')),
4600 ('n', 'name', '',
4600 ('n', 'name', '',
4601 _('name to show in web pages (default: working directory)'), _('NAME')),
4601 _('name to show in web pages (default: working directory)'), _('NAME')),
4602 ('', 'web-conf', '',
4602 ('', 'web-conf', '',
4603 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4603 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4604 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4604 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4605 _('FILE')),
4605 _('FILE')),
4606 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4606 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4607 ('', 'stdio', None, _('for remote clients')),
4607 ('', 'stdio', None, _('for remote clients')),
4608 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4608 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4609 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4609 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4610 ('', 'style', '', _('template style to use'), _('STYLE')),
4610 ('', 'style', '', _('template style to use'), _('STYLE')),
4611 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4611 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4612 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4612 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4613 _('[OPTION]...'))
4613 _('[OPTION]...'))
4614 def serve(ui, repo, **opts):
4614 def serve(ui, repo, **opts):
4615 """start stand-alone webserver
4615 """start stand-alone webserver
4616
4616
4617 Start a local HTTP repository browser and pull server. You can use
4617 Start a local HTTP repository browser and pull server. You can use
4618 this for ad-hoc sharing and browsing of repositories. It is
4618 this for ad-hoc sharing and browsing of repositories. It is
4619 recommended to use a real web server to serve a repository for
4619 recommended to use a real web server to serve a repository for
4620 longer periods of time.
4620 longer periods of time.
4621
4621
4622 Please note that the server does not implement access control.
4622 Please note that the server does not implement access control.
4623 This means that, by default, anybody can read from the server and
4623 This means that, by default, anybody can read from the server and
4624 nobody can write to it by default. Set the ``web.allow_push``
4624 nobody can write to it by default. Set the ``web.allow_push``
4625 option to ``*`` to allow everybody to push to the server. You
4625 option to ``*`` to allow everybody to push to the server. You
4626 should use a real web server if you need to authenticate users.
4626 should use a real web server if you need to authenticate users.
4627
4627
4628 By default, the server logs accesses to stdout and errors to
4628 By default, the server logs accesses to stdout and errors to
4629 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4629 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4630 files.
4630 files.
4631
4631
4632 To have the server choose a free port number to listen on, specify
4632 To have the server choose a free port number to listen on, specify
4633 a port number of 0; in this case, the server will print the port
4633 a port number of 0; in this case, the server will print the port
4634 number it uses.
4634 number it uses.
4635
4635
4636 Returns 0 on success.
4636 Returns 0 on success.
4637 """
4637 """
4638
4638
4639 if opts["stdio"] and opts["cmdserver"]:
4639 if opts["stdio"] and opts["cmdserver"]:
4640 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4640 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4641
4641
4642 def checkrepo():
4642 def checkrepo():
4643 if repo is None:
4643 if repo is None:
4644 raise error.RepoError(_("There is no Mercurial repository here"
4644 raise error.RepoError(_("There is no Mercurial repository here"
4645 " (.hg not found)"))
4645 " (.hg not found)"))
4646
4646
4647 if opts["stdio"]:
4647 if opts["stdio"]:
4648 checkrepo()
4648 checkrepo()
4649 s = sshserver.sshserver(ui, repo)
4649 s = sshserver.sshserver(ui, repo)
4650 s.serve_forever()
4650 s.serve_forever()
4651
4651
4652 if opts["cmdserver"]:
4652 if opts["cmdserver"]:
4653 checkrepo()
4653 checkrepo()
4654 s = commandserver.server(ui, repo, opts["cmdserver"])
4654 s = commandserver.server(ui, repo, opts["cmdserver"])
4655 return s.serve()
4655 return s.serve()
4656
4656
4657 # this way we can check if something was given in the command-line
4657 # this way we can check if something was given in the command-line
4658 if opts.get('port'):
4658 if opts.get('port'):
4659 opts['port'] = util.getport(opts.get('port'))
4659 opts['port'] = util.getport(opts.get('port'))
4660
4660
4661 baseui = repo and repo.baseui or ui
4661 baseui = repo and repo.baseui or ui
4662 optlist = ("name templates style address port prefix ipv6"
4662 optlist = ("name templates style address port prefix ipv6"
4663 " accesslog errorlog certificate encoding")
4663 " accesslog errorlog certificate encoding")
4664 for o in optlist.split():
4664 for o in optlist.split():
4665 val = opts.get(o, '')
4665 val = opts.get(o, '')
4666 if val in (None, ''): # should check against default options instead
4666 if val in (None, ''): # should check against default options instead
4667 continue
4667 continue
4668 baseui.setconfig("web", o, val)
4668 baseui.setconfig("web", o, val)
4669 if repo and repo.ui != baseui:
4669 if repo and repo.ui != baseui:
4670 repo.ui.setconfig("web", o, val)
4670 repo.ui.setconfig("web", o, val)
4671
4671
4672 o = opts.get('web_conf') or opts.get('webdir_conf')
4672 o = opts.get('web_conf') or opts.get('webdir_conf')
4673 if not o:
4673 if not o:
4674 if not repo:
4674 if not repo:
4675 raise error.RepoError(_("There is no Mercurial repository"
4675 raise error.RepoError(_("There is no Mercurial repository"
4676 " here (.hg not found)"))
4676 " here (.hg not found)"))
4677 o = repo.root
4677 o = repo.root
4678
4678
4679 app = hgweb.hgweb(o, baseui=ui)
4679 app = hgweb.hgweb(o, baseui=ui)
4680
4680
4681 class service(object):
4681 class service(object):
4682 def init(self):
4682 def init(self):
4683 util.setsignalhandler()
4683 util.setsignalhandler()
4684 self.httpd = hgweb.server.create_server(ui, app)
4684 self.httpd = hgweb.server.create_server(ui, app)
4685
4685
4686 if opts['port'] and not ui.verbose:
4686 if opts['port'] and not ui.verbose:
4687 return
4687 return
4688
4688
4689 if self.httpd.prefix:
4689 if self.httpd.prefix:
4690 prefix = self.httpd.prefix.strip('/') + '/'
4690 prefix = self.httpd.prefix.strip('/') + '/'
4691 else:
4691 else:
4692 prefix = ''
4692 prefix = ''
4693
4693
4694 port = ':%d' % self.httpd.port
4694 port = ':%d' % self.httpd.port
4695 if port == ':80':
4695 if port == ':80':
4696 port = ''
4696 port = ''
4697
4697
4698 bindaddr = self.httpd.addr
4698 bindaddr = self.httpd.addr
4699 if bindaddr == '0.0.0.0':
4699 if bindaddr == '0.0.0.0':
4700 bindaddr = '*'
4700 bindaddr = '*'
4701 elif ':' in bindaddr: # IPv6
4701 elif ':' in bindaddr: # IPv6
4702 bindaddr = '[%s]' % bindaddr
4702 bindaddr = '[%s]' % bindaddr
4703
4703
4704 fqaddr = self.httpd.fqaddr
4704 fqaddr = self.httpd.fqaddr
4705 if ':' in fqaddr:
4705 if ':' in fqaddr:
4706 fqaddr = '[%s]' % fqaddr
4706 fqaddr = '[%s]' % fqaddr
4707 if opts['port']:
4707 if opts['port']:
4708 write = ui.status
4708 write = ui.status
4709 else:
4709 else:
4710 write = ui.write
4710 write = ui.write
4711 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4711 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4712 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4712 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4713
4713
4714 def run(self):
4714 def run(self):
4715 self.httpd.serve_forever()
4715 self.httpd.serve_forever()
4716
4716
4717 service = service()
4717 service = service()
4718
4718
4719 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4719 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4720
4720
4721 @command('showconfig|debugconfig',
4721 @command('showconfig|debugconfig',
4722 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4722 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4723 _('[-u] [NAME]...'))
4723 _('[-u] [NAME]...'))
4724 def showconfig(ui, repo, *values, **opts):
4724 def showconfig(ui, repo, *values, **opts):
4725 """show combined config settings from all hgrc files
4725 """show combined config settings from all hgrc files
4726
4726
4727 With no arguments, print names and values of all config items.
4727 With no arguments, print names and values of all config items.
4728
4728
4729 With one argument of the form section.name, print just the value
4729 With one argument of the form section.name, print just the value
4730 of that config item.
4730 of that config item.
4731
4731
4732 With multiple arguments, print names and values of all config
4732 With multiple arguments, print names and values of all config
4733 items with matching section names.
4733 items with matching section names.
4734
4734
4735 With --debug, the source (filename and line number) is printed
4735 With --debug, the source (filename and line number) is printed
4736 for each config item.
4736 for each config item.
4737
4737
4738 Returns 0 on success.
4738 Returns 0 on success.
4739 """
4739 """
4740
4740
4741 for f in scmutil.rcpath():
4741 for f in scmutil.rcpath():
4742 ui.debug('read config from: %s\n' % f)
4742 ui.debug('read config from: %s\n' % f)
4743 untrusted = bool(opts.get('untrusted'))
4743 untrusted = bool(opts.get('untrusted'))
4744 if values:
4744 if values:
4745 sections = [v for v in values if '.' not in v]
4745 sections = [v for v in values if '.' not in v]
4746 items = [v for v in values if '.' in v]
4746 items = [v for v in values if '.' in v]
4747 if len(items) > 1 or items and sections:
4747 if len(items) > 1 or items and sections:
4748 raise util.Abort(_('only one config item permitted'))
4748 raise util.Abort(_('only one config item permitted'))
4749 for section, name, value in ui.walkconfig(untrusted=untrusted):
4749 for section, name, value in ui.walkconfig(untrusted=untrusted):
4750 value = str(value).replace('\n', '\\n')
4750 value = str(value).replace('\n', '\\n')
4751 sectname = section + '.' + name
4751 sectname = section + '.' + name
4752 if values:
4752 if values:
4753 for v in values:
4753 for v in values:
4754 if v == section:
4754 if v == section:
4755 ui.debug('%s: ' %
4755 ui.debug('%s: ' %
4756 ui.configsource(section, name, untrusted))
4756 ui.configsource(section, name, untrusted))
4757 ui.write('%s=%s\n' % (sectname, value))
4757 ui.write('%s=%s\n' % (sectname, value))
4758 elif v == sectname:
4758 elif v == sectname:
4759 ui.debug('%s: ' %
4759 ui.debug('%s: ' %
4760 ui.configsource(section, name, untrusted))
4760 ui.configsource(section, name, untrusted))
4761 ui.write(value, '\n')
4761 ui.write(value, '\n')
4762 else:
4762 else:
4763 ui.debug('%s: ' %
4763 ui.debug('%s: ' %
4764 ui.configsource(section, name, untrusted))
4764 ui.configsource(section, name, untrusted))
4765 ui.write('%s=%s\n' % (sectname, value))
4765 ui.write('%s=%s\n' % (sectname, value))
4766
4766
4767 @command('^status|st',
4767 @command('^status|st',
4768 [('A', 'all', None, _('show status of all files')),
4768 [('A', 'all', None, _('show status of all files')),
4769 ('m', 'modified', None, _('show only modified files')),
4769 ('m', 'modified', None, _('show only modified files')),
4770 ('a', 'added', None, _('show only added files')),
4770 ('a', 'added', None, _('show only added files')),
4771 ('r', 'removed', None, _('show only removed files')),
4771 ('r', 'removed', None, _('show only removed files')),
4772 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4772 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4773 ('c', 'clean', None, _('show only files without changes')),
4773 ('c', 'clean', None, _('show only files without changes')),
4774 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4774 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4775 ('i', 'ignored', None, _('show only ignored files')),
4775 ('i', 'ignored', None, _('show only ignored files')),
4776 ('n', 'no-status', None, _('hide status prefix')),
4776 ('n', 'no-status', None, _('hide status prefix')),
4777 ('C', 'copies', None, _('show source of copied files')),
4777 ('C', 'copies', None, _('show source of copied files')),
4778 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4778 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4779 ('', 'rev', [], _('show difference from revision'), _('REV')),
4779 ('', 'rev', [], _('show difference from revision'), _('REV')),
4780 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4780 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4781 ] + walkopts + subrepoopts,
4781 ] + walkopts + subrepoopts,
4782 _('[OPTION]... [FILE]...'))
4782 _('[OPTION]... [FILE]...'))
4783 def status(ui, repo, *pats, **opts):
4783 def status(ui, repo, *pats, **opts):
4784 """show changed files in the working directory
4784 """show changed files in the working directory
4785
4785
4786 Show status of files in the repository. If names are given, only
4786 Show status of files in the repository. If names are given, only
4787 files that match are shown. Files that are clean or ignored or
4787 files that match are shown. Files that are clean or ignored or
4788 the source of a copy/move operation, are not listed unless
4788 the source of a copy/move operation, are not listed unless
4789 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4789 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4790 Unless options described with "show only ..." are given, the
4790 Unless options described with "show only ..." are given, the
4791 options -mardu are used.
4791 options -mardu are used.
4792
4792
4793 Option -q/--quiet hides untracked (unknown and ignored) files
4793 Option -q/--quiet hides untracked (unknown and ignored) files
4794 unless explicitly requested with -u/--unknown or -i/--ignored.
4794 unless explicitly requested with -u/--unknown or -i/--ignored.
4795
4795
4796 .. note::
4796 .. note::
4797 status may appear to disagree with diff if permissions have
4797 status may appear to disagree with diff if permissions have
4798 changed or a merge has occurred. The standard diff format does
4798 changed or a merge has occurred. The standard diff format does
4799 not report permission changes and diff only reports changes
4799 not report permission changes and diff only reports changes
4800 relative to one merge parent.
4800 relative to one merge parent.
4801
4801
4802 If one revision is given, it is used as the base revision.
4802 If one revision is given, it is used as the base revision.
4803 If two revisions are given, the differences between them are
4803 If two revisions are given, the differences between them are
4804 shown. The --change option can also be used as a shortcut to list
4804 shown. The --change option can also be used as a shortcut to list
4805 the changed files of a revision from its first parent.
4805 the changed files of a revision from its first parent.
4806
4806
4807 The codes used to show the status of files are::
4807 The codes used to show the status of files are::
4808
4808
4809 M = modified
4809 M = modified
4810 A = added
4810 A = added
4811 R = removed
4811 R = removed
4812 C = clean
4812 C = clean
4813 ! = missing (deleted by non-hg command, but still tracked)
4813 ! = missing (deleted by non-hg command, but still tracked)
4814 ? = not tracked
4814 ? = not tracked
4815 I = ignored
4815 I = ignored
4816 = origin of the previous file listed as A (added)
4816 = origin of the previous file listed as A (added)
4817
4817
4818 .. container:: verbose
4818 .. container:: verbose
4819
4819
4820 Examples:
4820 Examples:
4821
4821
4822 - show changes in the working directory relative to a changeset:
4822 - show changes in the working directory relative to a changeset:
4823
4823
4824 hg status --rev 9353
4824 hg status --rev 9353
4825
4825
4826 - show all changes including copies in an existing changeset::
4826 - show all changes including copies in an existing changeset::
4827
4827
4828 hg status --copies --change 9353
4828 hg status --copies --change 9353
4829
4829
4830 - get a NUL separated list of added files, suitable for xargs::
4830 - get a NUL separated list of added files, suitable for xargs::
4831
4831
4832 hg status -an0
4832 hg status -an0
4833
4833
4834 Returns 0 on success.
4834 Returns 0 on success.
4835 """
4835 """
4836
4836
4837 revs = opts.get('rev')
4837 revs = opts.get('rev')
4838 change = opts.get('change')
4838 change = opts.get('change')
4839
4839
4840 if revs and change:
4840 if revs and change:
4841 msg = _('cannot specify --rev and --change at the same time')
4841 msg = _('cannot specify --rev and --change at the same time')
4842 raise util.Abort(msg)
4842 raise util.Abort(msg)
4843 elif change:
4843 elif change:
4844 node2 = repo.lookup(change)
4844 node2 = repo.lookup(change)
4845 node1 = repo[node2].p1().node()
4845 node1 = repo[node2].p1().node()
4846 else:
4846 else:
4847 node1, node2 = scmutil.revpair(repo, revs)
4847 node1, node2 = scmutil.revpair(repo, revs)
4848
4848
4849 cwd = (pats and repo.getcwd()) or ''
4849 cwd = (pats and repo.getcwd()) or ''
4850 end = opts.get('print0') and '\0' or '\n'
4850 end = opts.get('print0') and '\0' or '\n'
4851 copy = {}
4851 copy = {}
4852 states = 'modified added removed deleted unknown ignored clean'.split()
4852 states = 'modified added removed deleted unknown ignored clean'.split()
4853 show = [k for k in states if opts.get(k)]
4853 show = [k for k in states if opts.get(k)]
4854 if opts.get('all'):
4854 if opts.get('all'):
4855 show += ui.quiet and (states[:4] + ['clean']) or states
4855 show += ui.quiet and (states[:4] + ['clean']) or states
4856 if not show:
4856 if not show:
4857 show = ui.quiet and states[:4] or states[:5]
4857 show = ui.quiet and states[:4] or states[:5]
4858
4858
4859 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
4859 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
4860 'ignored' in show, 'clean' in show, 'unknown' in show,
4860 'ignored' in show, 'clean' in show, 'unknown' in show,
4861 opts.get('subrepos'))
4861 opts.get('subrepos'))
4862 changestates = zip(states, 'MAR!?IC', stat)
4862 changestates = zip(states, 'MAR!?IC', stat)
4863
4863
4864 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4864 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4865 ctxn = repo[nullid]
4865 ctxn = repo[nullid]
4866 ctx1 = repo[node1]
4866 ctx1 = repo[node1]
4867 ctx2 = repo[node2]
4867 ctx2 = repo[node2]
4868 added = stat[1]
4868 added = stat[1]
4869 if node2 is None:
4869 if node2 is None:
4870 added = stat[0] + stat[1] # merged?
4870 added = stat[0] + stat[1] # merged?
4871
4871
4872 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4872 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4873 if k in added:
4873 if k in added:
4874 copy[k] = v
4874 copy[k] = v
4875 elif v in added:
4875 elif v in added:
4876 copy[v] = k
4876 copy[v] = k
4877
4877
4878 for state, char, files in changestates:
4878 for state, char, files in changestates:
4879 if state in show:
4879 if state in show:
4880 format = "%s %%s%s" % (char, end)
4880 format = "%s %%s%s" % (char, end)
4881 if opts.get('no_status'):
4881 if opts.get('no_status'):
4882 format = "%%s%s" % end
4882 format = "%%s%s" % end
4883
4883
4884 for f in files:
4884 for f in files:
4885 ui.write(format % repo.pathto(f, cwd),
4885 ui.write(format % repo.pathto(f, cwd),
4886 label='status.' + state)
4886 label='status.' + state)
4887 if f in copy:
4887 if f in copy:
4888 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4888 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4889 label='status.copied')
4889 label='status.copied')
4890
4890
4891 @command('^summary|sum',
4891 @command('^summary|sum',
4892 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4892 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4893 def summary(ui, repo, **opts):
4893 def summary(ui, repo, **opts):
4894 """summarize working directory state
4894 """summarize working directory state
4895
4895
4896 This generates a brief summary of the working directory state,
4896 This generates a brief summary of the working directory state,
4897 including parents, branch, commit status, and available updates.
4897 including parents, branch, commit status, and available updates.
4898
4898
4899 With the --remote option, this will check the default paths for
4899 With the --remote option, this will check the default paths for
4900 incoming and outgoing changes. This can be time-consuming.
4900 incoming and outgoing changes. This can be time-consuming.
4901
4901
4902 Returns 0 on success.
4902 Returns 0 on success.
4903 """
4903 """
4904
4904
4905 ctx = repo[None]
4905 ctx = repo[None]
4906 parents = ctx.parents()
4906 parents = ctx.parents()
4907 pnode = parents[0].node()
4907 pnode = parents[0].node()
4908 marks = []
4908 marks = []
4909
4909
4910 for p in parents:
4910 for p in parents:
4911 # label with log.changeset (instead of log.parent) since this
4911 # label with log.changeset (instead of log.parent) since this
4912 # shows a working directory parent *changeset*:
4912 # shows a working directory parent *changeset*:
4913 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4913 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4914 label='log.changeset')
4914 label='log.changeset')
4915 ui.write(' '.join(p.tags()), label='log.tag')
4915 ui.write(' '.join(p.tags()), label='log.tag')
4916 if p.bookmarks():
4916 if p.bookmarks():
4917 marks.extend(p.bookmarks())
4917 marks.extend(p.bookmarks())
4918 if p.rev() == -1:
4918 if p.rev() == -1:
4919 if not len(repo):
4919 if not len(repo):
4920 ui.write(_(' (empty repository)'))
4920 ui.write(_(' (empty repository)'))
4921 else:
4921 else:
4922 ui.write(_(' (no revision checked out)'))
4922 ui.write(_(' (no revision checked out)'))
4923 ui.write('\n')
4923 ui.write('\n')
4924 if p.description():
4924 if p.description():
4925 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4925 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4926 label='log.summary')
4926 label='log.summary')
4927
4927
4928 branch = ctx.branch()
4928 branch = ctx.branch()
4929 bheads = repo.branchheads(branch)
4929 bheads = repo.branchheads(branch)
4930 m = _('branch: %s\n') % branch
4930 m = _('branch: %s\n') % branch
4931 if branch != 'default':
4931 if branch != 'default':
4932 ui.write(m, label='log.branch')
4932 ui.write(m, label='log.branch')
4933 else:
4933 else:
4934 ui.status(m, label='log.branch')
4934 ui.status(m, label='log.branch')
4935
4935
4936 if marks:
4936 if marks:
4937 current = repo._bookmarkcurrent
4937 current = repo._bookmarkcurrent
4938 ui.write(_('bookmarks:'), label='log.bookmark')
4938 ui.write(_('bookmarks:'), label='log.bookmark')
4939 if current is not None:
4939 if current is not None:
4940 try:
4940 try:
4941 marks.remove(current)
4941 marks.remove(current)
4942 ui.write(' *' + current, label='bookmarks.current')
4942 ui.write(' *' + current, label='bookmarks.current')
4943 except ValueError:
4943 except ValueError:
4944 # current bookmark not in parent ctx marks
4944 # current bookmark not in parent ctx marks
4945 pass
4945 pass
4946 for m in marks:
4946 for m in marks:
4947 ui.write(' ' + m, label='log.bookmark')
4947 ui.write(' ' + m, label='log.bookmark')
4948 ui.write('\n', label='log.bookmark')
4948 ui.write('\n', label='log.bookmark')
4949
4949
4950 st = list(repo.status(unknown=True))[:6]
4950 st = list(repo.status(unknown=True))[:6]
4951
4951
4952 c = repo.dirstate.copies()
4952 c = repo.dirstate.copies()
4953 copied, renamed = [], []
4953 copied, renamed = [], []
4954 for d, s in c.iteritems():
4954 for d, s in c.iteritems():
4955 if s in st[2]:
4955 if s in st[2]:
4956 st[2].remove(s)
4956 st[2].remove(s)
4957 renamed.append(d)
4957 renamed.append(d)
4958 else:
4958 else:
4959 copied.append(d)
4959 copied.append(d)
4960 if d in st[1]:
4960 if d in st[1]:
4961 st[1].remove(d)
4961 st[1].remove(d)
4962 st.insert(3, renamed)
4962 st.insert(3, renamed)
4963 st.insert(4, copied)
4963 st.insert(4, copied)
4964
4964
4965 ms = mergemod.mergestate(repo)
4965 ms = mergemod.mergestate(repo)
4966 st.append([f for f in ms if ms[f] == 'u'])
4966 st.append([f for f in ms if ms[f] == 'u'])
4967
4967
4968 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4968 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4969 st.append(subs)
4969 st.append(subs)
4970
4970
4971 labels = [ui.label(_('%d modified'), 'status.modified'),
4971 labels = [ui.label(_('%d modified'), 'status.modified'),
4972 ui.label(_('%d added'), 'status.added'),
4972 ui.label(_('%d added'), 'status.added'),
4973 ui.label(_('%d removed'), 'status.removed'),
4973 ui.label(_('%d removed'), 'status.removed'),
4974 ui.label(_('%d renamed'), 'status.copied'),
4974 ui.label(_('%d renamed'), 'status.copied'),
4975 ui.label(_('%d copied'), 'status.copied'),
4975 ui.label(_('%d copied'), 'status.copied'),
4976 ui.label(_('%d deleted'), 'status.deleted'),
4976 ui.label(_('%d deleted'), 'status.deleted'),
4977 ui.label(_('%d unknown'), 'status.unknown'),
4977 ui.label(_('%d unknown'), 'status.unknown'),
4978 ui.label(_('%d ignored'), 'status.ignored'),
4978 ui.label(_('%d ignored'), 'status.ignored'),
4979 ui.label(_('%d unresolved'), 'resolve.unresolved'),
4979 ui.label(_('%d unresolved'), 'resolve.unresolved'),
4980 ui.label(_('%d subrepos'), 'status.modified')]
4980 ui.label(_('%d subrepos'), 'status.modified')]
4981 t = []
4981 t = []
4982 for s, l in zip(st, labels):
4982 for s, l in zip(st, labels):
4983 if s:
4983 if s:
4984 t.append(l % len(s))
4984 t.append(l % len(s))
4985
4985
4986 t = ', '.join(t)
4986 t = ', '.join(t)
4987 cleanworkdir = False
4987 cleanworkdir = False
4988
4988
4989 if len(parents) > 1:
4989 if len(parents) > 1:
4990 t += _(' (merge)')
4990 t += _(' (merge)')
4991 elif branch != parents[0].branch():
4991 elif branch != parents[0].branch():
4992 t += _(' (new branch)')
4992 t += _(' (new branch)')
4993 elif (parents[0].extra().get('close') and
4993 elif (parents[0].extra().get('close') and
4994 pnode in repo.branchheads(branch, closed=True)):
4994 pnode in repo.branchheads(branch, closed=True)):
4995 t += _(' (head closed)')
4995 t += _(' (head closed)')
4996 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4996 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4997 t += _(' (clean)')
4997 t += _(' (clean)')
4998 cleanworkdir = True
4998 cleanworkdir = True
4999 elif pnode not in bheads:
4999 elif pnode not in bheads:
5000 t += _(' (new branch head)')
5000 t += _(' (new branch head)')
5001
5001
5002 if cleanworkdir:
5002 if cleanworkdir:
5003 ui.status(_('commit: %s\n') % t.strip())
5003 ui.status(_('commit: %s\n') % t.strip())
5004 else:
5004 else:
5005 ui.write(_('commit: %s\n') % t.strip())
5005 ui.write(_('commit: %s\n') % t.strip())
5006
5006
5007 # all ancestors of branch heads - all ancestors of parent = new csets
5007 # all ancestors of branch heads - all ancestors of parent = new csets
5008 new = [0] * len(repo)
5008 new = [0] * len(repo)
5009 cl = repo.changelog
5009 cl = repo.changelog
5010 for a in [cl.rev(n) for n in bheads]:
5010 for a in [cl.rev(n) for n in bheads]:
5011 new[a] = 1
5011 new[a] = 1
5012 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
5012 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
5013 new[a] = 1
5013 new[a] = 1
5014 for a in [p.rev() for p in parents]:
5014 for a in [p.rev() for p in parents]:
5015 if a >= 0:
5015 if a >= 0:
5016 new[a] = 0
5016 new[a] = 0
5017 for a in cl.ancestors(*[p.rev() for p in parents]):
5017 for a in cl.ancestors(*[p.rev() for p in parents]):
5018 new[a] = 0
5018 new[a] = 0
5019 new = sum(new)
5019 new = sum(new)
5020
5020
5021 if new == 0:
5021 if new == 0:
5022 ui.status(_('update: (current)\n'))
5022 ui.status(_('update: (current)\n'))
5023 elif pnode not in bheads:
5023 elif pnode not in bheads:
5024 ui.write(_('update: %d new changesets (update)\n') % new)
5024 ui.write(_('update: %d new changesets (update)\n') % new)
5025 else:
5025 else:
5026 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5026 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5027 (new, len(bheads)))
5027 (new, len(bheads)))
5028
5028
5029 if opts.get('remote'):
5029 if opts.get('remote'):
5030 t = []
5030 t = []
5031 source, branches = hg.parseurl(ui.expandpath('default'))
5031 source, branches = hg.parseurl(ui.expandpath('default'))
5032 other = hg.peer(repo, {}, source)
5032 other = hg.peer(repo, {}, source)
5033 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5033 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5034 ui.debug('comparing with %s\n' % util.hidepassword(source))
5034 ui.debug('comparing with %s\n' % util.hidepassword(source))
5035 repo.ui.pushbuffer()
5035 repo.ui.pushbuffer()
5036 commoninc = discovery.findcommonincoming(repo, other)
5036 commoninc = discovery.findcommonincoming(repo, other)
5037 _common, incoming, _rheads = commoninc
5037 _common, incoming, _rheads = commoninc
5038 repo.ui.popbuffer()
5038 repo.ui.popbuffer()
5039 if incoming:
5039 if incoming:
5040 t.append(_('1 or more incoming'))
5040 t.append(_('1 or more incoming'))
5041
5041
5042 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5042 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5043 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5043 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5044 if source != dest:
5044 if source != dest:
5045 other = hg.peer(repo, {}, dest)
5045 other = hg.peer(repo, {}, dest)
5046 commoninc = None
5046 commoninc = None
5047 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5047 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5048 repo.ui.pushbuffer()
5048 repo.ui.pushbuffer()
5049 common, outheads = discovery.findcommonoutgoing(repo, other,
5049 common, outheads = discovery.findcommonoutgoing(repo, other,
5050 commoninc=commoninc)
5050 commoninc=commoninc)
5051 repo.ui.popbuffer()
5051 repo.ui.popbuffer()
5052 o = repo.changelog.findmissing(common=common, heads=outheads)
5052 o = repo.changelog.findmissing(common=common, heads=outheads)
5053 if o:
5053 if o:
5054 t.append(_('%d outgoing') % len(o))
5054 t.append(_('%d outgoing') % len(o))
5055 if 'bookmarks' in other.listkeys('namespaces'):
5055 if 'bookmarks' in other.listkeys('namespaces'):
5056 lmarks = repo.listkeys('bookmarks')
5056 lmarks = repo.listkeys('bookmarks')
5057 rmarks = other.listkeys('bookmarks')
5057 rmarks = other.listkeys('bookmarks')
5058 diff = set(rmarks) - set(lmarks)
5058 diff = set(rmarks) - set(lmarks)
5059 if len(diff) > 0:
5059 if len(diff) > 0:
5060 t.append(_('%d incoming bookmarks') % len(diff))
5060 t.append(_('%d incoming bookmarks') % len(diff))
5061 diff = set(lmarks) - set(rmarks)
5061 diff = set(lmarks) - set(rmarks)
5062 if len(diff) > 0:
5062 if len(diff) > 0:
5063 t.append(_('%d outgoing bookmarks') % len(diff))
5063 t.append(_('%d outgoing bookmarks') % len(diff))
5064
5064
5065 if t:
5065 if t:
5066 ui.write(_('remote: %s\n') % (', '.join(t)))
5066 ui.write(_('remote: %s\n') % (', '.join(t)))
5067 else:
5067 else:
5068 ui.status(_('remote: (synced)\n'))
5068 ui.status(_('remote: (synced)\n'))
5069
5069
5070 @command('tag',
5070 @command('tag',
5071 [('f', 'force', None, _('force tag')),
5071 [('f', 'force', None, _('force tag')),
5072 ('l', 'local', None, _('make the tag local')),
5072 ('l', 'local', None, _('make the tag local')),
5073 ('r', 'rev', '', _('revision to tag'), _('REV')),
5073 ('r', 'rev', '', _('revision to tag'), _('REV')),
5074 ('', 'remove', None, _('remove a tag')),
5074 ('', 'remove', None, _('remove a tag')),
5075 # -l/--local is already there, commitopts cannot be used
5075 # -l/--local is already there, commitopts cannot be used
5076 ('e', 'edit', None, _('edit commit message')),
5076 ('e', 'edit', None, _('edit commit message')),
5077 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5077 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5078 ] + commitopts2,
5078 ] + commitopts2,
5079 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5079 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5080 def tag(ui, repo, name1, *names, **opts):
5080 def tag(ui, repo, name1, *names, **opts):
5081 """add one or more tags for the current or given revision
5081 """add one or more tags for the current or given revision
5082
5082
5083 Name a particular revision using <name>.
5083 Name a particular revision using <name>.
5084
5084
5085 Tags are used to name particular revisions of the repository and are
5085 Tags are used to name particular revisions of the repository and are
5086 very useful to compare different revisions, to go back to significant
5086 very useful to compare different revisions, to go back to significant
5087 earlier versions or to mark branch points as releases, etc. Changing
5087 earlier versions or to mark branch points as releases, etc. Changing
5088 an existing tag is normally disallowed; use -f/--force to override.
5088 an existing tag is normally disallowed; use -f/--force to override.
5089
5089
5090 If no revision is given, the parent of the working directory is
5090 If no revision is given, the parent of the working directory is
5091 used, or tip if no revision is checked out.
5091 used, or tip if no revision is checked out.
5092
5092
5093 To facilitate version control, distribution, and merging of tags,
5093 To facilitate version control, distribution, and merging of tags,
5094 they are stored as a file named ".hgtags" which is managed similarly
5094 they are stored as a file named ".hgtags" which is managed similarly
5095 to other project files and can be hand-edited if necessary. This
5095 to other project files and can be hand-edited if necessary. This
5096 also means that tagging creates a new commit. The file
5096 also means that tagging creates a new commit. The file
5097 ".hg/localtags" is used for local tags (not shared among
5097 ".hg/localtags" is used for local tags (not shared among
5098 repositories).
5098 repositories).
5099
5099
5100 Tag commits are usually made at the head of a branch. If the parent
5100 Tag commits are usually made at the head of a branch. If the parent
5101 of the working directory is not a branch head, :hg:`tag` aborts; use
5101 of the working directory is not a branch head, :hg:`tag` aborts; use
5102 -f/--force to force the tag commit to be based on a non-head
5102 -f/--force to force the tag commit to be based on a non-head
5103 changeset.
5103 changeset.
5104
5104
5105 See :hg:`help dates` for a list of formats valid for -d/--date.
5105 See :hg:`help dates` for a list of formats valid for -d/--date.
5106
5106
5107 Since tag names have priority over branch names during revision
5107 Since tag names have priority over branch names during revision
5108 lookup, using an existing branch name as a tag name is discouraged.
5108 lookup, using an existing branch name as a tag name is discouraged.
5109
5109
5110 Returns 0 on success.
5110 Returns 0 on success.
5111 """
5111 """
5112
5112
5113 rev_ = "."
5113 rev_ = "."
5114 names = [t.strip() for t in (name1,) + names]
5114 names = [t.strip() for t in (name1,) + names]
5115 if len(names) != len(set(names)):
5115 if len(names) != len(set(names)):
5116 raise util.Abort(_('tag names must be unique'))
5116 raise util.Abort(_('tag names must be unique'))
5117 for n in names:
5117 for n in names:
5118 if n in ['tip', '.', 'null']:
5118 if n in ['tip', '.', 'null']:
5119 raise util.Abort(_("the name '%s' is reserved") % n)
5119 raise util.Abort(_("the name '%s' is reserved") % n)
5120 if not n:
5120 if not n:
5121 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
5121 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
5122 if opts.get('rev') and opts.get('remove'):
5122 if opts.get('rev') and opts.get('remove'):
5123 raise util.Abort(_("--rev and --remove are incompatible"))
5123 raise util.Abort(_("--rev and --remove are incompatible"))
5124 if opts.get('rev'):
5124 if opts.get('rev'):
5125 rev_ = opts['rev']
5125 rev_ = opts['rev']
5126 message = opts.get('message')
5126 message = opts.get('message')
5127 if opts.get('remove'):
5127 if opts.get('remove'):
5128 expectedtype = opts.get('local') and 'local' or 'global'
5128 expectedtype = opts.get('local') and 'local' or 'global'
5129 for n in names:
5129 for n in names:
5130 if not repo.tagtype(n):
5130 if not repo.tagtype(n):
5131 raise util.Abort(_("tag '%s' does not exist") % n)
5131 raise util.Abort(_("tag '%s' does not exist") % n)
5132 if repo.tagtype(n) != expectedtype:
5132 if repo.tagtype(n) != expectedtype:
5133 if expectedtype == 'global':
5133 if expectedtype == 'global':
5134 raise util.Abort(_("tag '%s' is not a global tag") % n)
5134 raise util.Abort(_("tag '%s' is not a global tag") % n)
5135 else:
5135 else:
5136 raise util.Abort(_("tag '%s' is not a local tag") % n)
5136 raise util.Abort(_("tag '%s' is not a local tag") % n)
5137 rev_ = nullid
5137 rev_ = nullid
5138 if not message:
5138 if not message:
5139 # we don't translate commit messages
5139 # we don't translate commit messages
5140 message = 'Removed tag %s' % ', '.join(names)
5140 message = 'Removed tag %s' % ', '.join(names)
5141 elif not opts.get('force'):
5141 elif not opts.get('force'):
5142 for n in names:
5142 for n in names:
5143 if n in repo.tags():
5143 if n in repo.tags():
5144 raise util.Abort(_("tag '%s' already exists "
5144 raise util.Abort(_("tag '%s' already exists "
5145 "(use -f to force)") % n)
5145 "(use -f to force)") % n)
5146 if not opts.get('local'):
5146 if not opts.get('local'):
5147 p1, p2 = repo.dirstate.parents()
5147 p1, p2 = repo.dirstate.parents()
5148 if p2 != nullid:
5148 if p2 != nullid:
5149 raise util.Abort(_('uncommitted merge'))
5149 raise util.Abort(_('uncommitted merge'))
5150 bheads = repo.branchheads()
5150 bheads = repo.branchheads()
5151 if not opts.get('force') and bheads and p1 not in bheads:
5151 if not opts.get('force') and bheads and p1 not in bheads:
5152 raise util.Abort(_('not at a branch head (use -f to force)'))
5152 raise util.Abort(_('not at a branch head (use -f to force)'))
5153 r = scmutil.revsingle(repo, rev_).node()
5153 r = scmutil.revsingle(repo, rev_).node()
5154
5154
5155 if not message:
5155 if not message:
5156 # we don't translate commit messages
5156 # we don't translate commit messages
5157 message = ('Added tag %s for changeset %s' %
5157 message = ('Added tag %s for changeset %s' %
5158 (', '.join(names), short(r)))
5158 (', '.join(names), short(r)))
5159
5159
5160 date = opts.get('date')
5160 date = opts.get('date')
5161 if date:
5161 if date:
5162 date = util.parsedate(date)
5162 date = util.parsedate(date)
5163
5163
5164 if opts.get('edit'):
5164 if opts.get('edit'):
5165 message = ui.edit(message, ui.username())
5165 message = ui.edit(message, ui.username())
5166
5166
5167 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5167 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5168
5168
5169 @command('tags', [], '')
5169 @command('tags', [], '')
5170 def tags(ui, repo):
5170 def tags(ui, repo):
5171 """list repository tags
5171 """list repository tags
5172
5172
5173 This lists both regular and local tags. When the -v/--verbose
5173 This lists both regular and local tags. When the -v/--verbose
5174 switch is used, a third column "local" is printed for local tags.
5174 switch is used, a third column "local" is printed for local tags.
5175
5175
5176 Returns 0 on success.
5176 Returns 0 on success.
5177 """
5177 """
5178
5178
5179 hexfunc = ui.debugflag and hex or short
5179 hexfunc = ui.debugflag and hex or short
5180 tagtype = ""
5180 tagtype = ""
5181
5181
5182 for t, n in reversed(repo.tagslist()):
5182 for t, n in reversed(repo.tagslist()):
5183 if ui.quiet:
5183 if ui.quiet:
5184 ui.write("%s\n" % t, label='tags.normal')
5184 ui.write("%s\n" % t, label='tags.normal')
5185 continue
5185 continue
5186
5186
5187 hn = hexfunc(n)
5187 hn = hexfunc(n)
5188 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5188 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5189 rev = ui.label(r, 'log.changeset')
5189 rev = ui.label(r, 'log.changeset')
5190 spaces = " " * (30 - encoding.colwidth(t))
5190 spaces = " " * (30 - encoding.colwidth(t))
5191
5191
5192 tag = ui.label(t, 'tags.normal')
5192 tag = ui.label(t, 'tags.normal')
5193 if ui.verbose:
5193 if ui.verbose:
5194 if repo.tagtype(t) == 'local':
5194 if repo.tagtype(t) == 'local':
5195 tagtype = " local"
5195 tagtype = " local"
5196 tag = ui.label(t, 'tags.local')
5196 tag = ui.label(t, 'tags.local')
5197 else:
5197 else:
5198 tagtype = ""
5198 tagtype = ""
5199 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5199 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5200
5200
5201 @command('tip',
5201 @command('tip',
5202 [('p', 'patch', None, _('show patch')),
5202 [('p', 'patch', None, _('show patch')),
5203 ('g', 'git', None, _('use git extended diff format')),
5203 ('g', 'git', None, _('use git extended diff format')),
5204 ] + templateopts,
5204 ] + templateopts,
5205 _('[-p] [-g]'))
5205 _('[-p] [-g]'))
5206 def tip(ui, repo, **opts):
5206 def tip(ui, repo, **opts):
5207 """show the tip revision
5207 """show the tip revision
5208
5208
5209 The tip revision (usually just called the tip) is the changeset
5209 The tip revision (usually just called the tip) is the changeset
5210 most recently added to the repository (and therefore the most
5210 most recently added to the repository (and therefore the most
5211 recently changed head).
5211 recently changed head).
5212
5212
5213 If you have just made a commit, that commit will be the tip. If
5213 If you have just made a commit, that commit will be the tip. If
5214 you have just pulled changes from another repository, the tip of
5214 you have just pulled changes from another repository, the tip of
5215 that repository becomes the current tip. The "tip" tag is special
5215 that repository becomes the current tip. The "tip" tag is special
5216 and cannot be renamed or assigned to a different changeset.
5216 and cannot be renamed or assigned to a different changeset.
5217
5217
5218 Returns 0 on success.
5218 Returns 0 on success.
5219 """
5219 """
5220 displayer = cmdutil.show_changeset(ui, repo, opts)
5220 displayer = cmdutil.show_changeset(ui, repo, opts)
5221 displayer.show(repo[len(repo) - 1])
5221 displayer.show(repo[len(repo) - 1])
5222 displayer.close()
5222 displayer.close()
5223
5223
5224 @command('unbundle',
5224 @command('unbundle',
5225 [('u', 'update', None,
5225 [('u', 'update', None,
5226 _('update to new branch head if changesets were unbundled'))],
5226 _('update to new branch head if changesets were unbundled'))],
5227 _('[-u] FILE...'))
5227 _('[-u] FILE...'))
5228 def unbundle(ui, repo, fname1, *fnames, **opts):
5228 def unbundle(ui, repo, fname1, *fnames, **opts):
5229 """apply one or more changegroup files
5229 """apply one or more changegroup files
5230
5230
5231 Apply one or more compressed changegroup files generated by the
5231 Apply one or more compressed changegroup files generated by the
5232 bundle command.
5232 bundle command.
5233
5233
5234 Returns 0 on success, 1 if an update has unresolved files.
5234 Returns 0 on success, 1 if an update has unresolved files.
5235 """
5235 """
5236 fnames = (fname1,) + fnames
5236 fnames = (fname1,) + fnames
5237
5237
5238 lock = repo.lock()
5238 lock = repo.lock()
5239 wc = repo['.']
5239 wc = repo['.']
5240 try:
5240 try:
5241 for fname in fnames:
5241 for fname in fnames:
5242 f = url.open(ui, fname)
5242 f = url.open(ui, fname)
5243 gen = changegroup.readbundle(f, fname)
5243 gen = changegroup.readbundle(f, fname)
5244 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5244 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5245 lock=lock)
5245 lock=lock)
5246 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5246 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5247 finally:
5247 finally:
5248 lock.release()
5248 lock.release()
5249 return postincoming(ui, repo, modheads, opts.get('update'), None)
5249 return postincoming(ui, repo, modheads, opts.get('update'), None)
5250
5250
5251 @command('^update|up|checkout|co',
5251 @command('^update|up|checkout|co',
5252 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5252 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5253 ('c', 'check', None,
5253 ('c', 'check', None,
5254 _('update across branches if no uncommitted changes')),
5254 _('update across branches if no uncommitted changes')),
5255 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5255 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5256 ('r', 'rev', '', _('revision'), _('REV'))],
5256 ('r', 'rev', '', _('revision'), _('REV'))],
5257 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5257 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5258 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5258 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5259 """update working directory (or switch revisions)
5259 """update working directory (or switch revisions)
5260
5260
5261 Update the repository's working directory to the specified
5261 Update the repository's working directory to the specified
5262 changeset. If no changeset is specified, update to the tip of the
5262 changeset. If no changeset is specified, update to the tip of the
5263 current named branch.
5263 current named branch.
5264
5264
5265 If the changeset is not a descendant of the working directory's
5265 If the changeset is not a descendant of the working directory's
5266 parent, the update is aborted. With the -c/--check option, the
5266 parent, the update is aborted. With the -c/--check option, the
5267 working directory is checked for uncommitted changes; if none are
5267 working directory is checked for uncommitted changes; if none are
5268 found, the working directory is updated to the specified
5268 found, the working directory is updated to the specified
5269 changeset.
5269 changeset.
5270
5270
5271 Update sets the working directory's parent revison to the specified
5271 Update sets the working directory's parent revison to the specified
5272 changeset (see :hg:`help parents`).
5272 changeset (see :hg:`help parents`).
5273
5273
5274 The following rules apply when the working directory contains
5274 The following rules apply when the working directory contains
5275 uncommitted changes:
5275 uncommitted changes:
5276
5276
5277 1. If neither -c/--check nor -C/--clean is specified, and if
5277 1. If neither -c/--check nor -C/--clean is specified, and if
5278 the requested changeset is an ancestor or descendant of
5278 the requested changeset is an ancestor or descendant of
5279 the working directory's parent, the uncommitted changes
5279 the working directory's parent, the uncommitted changes
5280 are merged into the requested changeset and the merged
5280 are merged into the requested changeset and the merged
5281 result is left uncommitted. If the requested changeset is
5281 result is left uncommitted. If the requested changeset is
5282 not an ancestor or descendant (that is, it is on another
5282 not an ancestor or descendant (that is, it is on another
5283 branch), the update is aborted and the uncommitted changes
5283 branch), the update is aborted and the uncommitted changes
5284 are preserved.
5284 are preserved.
5285
5285
5286 2. With the -c/--check option, the update is aborted and the
5286 2. With the -c/--check option, the update is aborted and the
5287 uncommitted changes are preserved.
5287 uncommitted changes are preserved.
5288
5288
5289 3. With the -C/--clean option, uncommitted changes are discarded and
5289 3. With the -C/--clean option, uncommitted changes are discarded and
5290 the working directory is updated to the requested changeset.
5290 the working directory is updated to the requested changeset.
5291
5291
5292 Use null as the changeset to remove the working directory (like
5292 Use null as the changeset to remove the working directory (like
5293 :hg:`clone -U`).
5293 :hg:`clone -U`).
5294
5294
5295 If you want to revert just one file to an older revision, use
5295 If you want to revert just one file to an older revision, use
5296 :hg:`revert [-r REV] NAME`.
5296 :hg:`revert [-r REV] NAME`.
5297
5297
5298 See :hg:`help dates` for a list of formats valid for -d/--date.
5298 See :hg:`help dates` for a list of formats valid for -d/--date.
5299
5299
5300 Returns 0 on success, 1 if there are unresolved files.
5300 Returns 0 on success, 1 if there are unresolved files.
5301 """
5301 """
5302 if rev and node:
5302 if rev and node:
5303 raise util.Abort(_("please specify just one revision"))
5303 raise util.Abort(_("please specify just one revision"))
5304
5304
5305 if rev is None or rev == '':
5305 if rev is None or rev == '':
5306 rev = node
5306 rev = node
5307
5307
5308 # if we defined a bookmark, we have to remember the original bookmark name
5308 # if we defined a bookmark, we have to remember the original bookmark name
5309 brev = rev
5309 brev = rev
5310 rev = scmutil.revsingle(repo, rev, rev).rev()
5310 rev = scmutil.revsingle(repo, rev, rev).rev()
5311
5311
5312 if check and clean:
5312 if check and clean:
5313 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5313 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5314
5314
5315 if check:
5315 if check:
5316 # we could use dirty() but we can ignore merge and branch trivia
5316 # we could use dirty() but we can ignore merge and branch trivia
5317 c = repo[None]
5317 c = repo[None]
5318 if c.modified() or c.added() or c.removed():
5318 if c.modified() or c.added() or c.removed():
5319 raise util.Abort(_("uncommitted local changes"))
5319 raise util.Abort(_("uncommitted local changes"))
5320
5320
5321 if date:
5321 if date:
5322 if rev is not None:
5322 if rev is not None:
5323 raise util.Abort(_("you can't specify a revision and a date"))
5323 raise util.Abort(_("you can't specify a revision and a date"))
5324 rev = cmdutil.finddate(ui, repo, date)
5324 rev = cmdutil.finddate(ui, repo, date)
5325
5325
5326 if clean or check:
5326 if clean or check:
5327 ret = hg.clean(repo, rev)
5327 ret = hg.clean(repo, rev)
5328 else:
5328 else:
5329 ret = hg.update(repo, rev)
5329 ret = hg.update(repo, rev)
5330
5330
5331 if brev in repo._bookmarks:
5331 if brev in repo._bookmarks:
5332 bookmarks.setcurrent(repo, brev)
5332 bookmarks.setcurrent(repo, brev)
5333
5333
5334 return ret
5334 return ret
5335
5335
5336 @command('verify', [])
5336 @command('verify', [])
5337 def verify(ui, repo):
5337 def verify(ui, repo):
5338 """verify the integrity of the repository
5338 """verify the integrity of the repository
5339
5339
5340 Verify the integrity of the current repository.
5340 Verify the integrity of the current repository.
5341
5341
5342 This will perform an extensive check of the repository's
5342 This will perform an extensive check of the repository's
5343 integrity, validating the hashes and checksums of each entry in
5343 integrity, validating the hashes and checksums of each entry in
5344 the changelog, manifest, and tracked files, as well as the
5344 the changelog, manifest, and tracked files, as well as the
5345 integrity of their crosslinks and indices.
5345 integrity of their crosslinks and indices.
5346
5346
5347 Returns 0 on success, 1 if errors are encountered.
5347 Returns 0 on success, 1 if errors are encountered.
5348 """
5348 """
5349 return hg.verify(repo)
5349 return hg.verify(repo)
5350
5350
5351 @command('version', [])
5351 @command('version', [])
5352 def version_(ui):
5352 def version_(ui):
5353 """output version and copyright information"""
5353 """output version and copyright information"""
5354 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5354 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5355 % util.version())
5355 % util.version())
5356 ui.status(_(
5356 ui.status(_(
5357 "(see http://mercurial.selenic.com for more information)\n"
5357 "(see http://mercurial.selenic.com for more information)\n"
5358 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5358 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5359 "This is free software; see the source for copying conditions. "
5359 "This is free software; see the source for copying conditions. "
5360 "There is NO\nwarranty; "
5360 "There is NO\nwarranty; "
5361 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5361 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5362 ))
5362 ))
5363
5363
5364 norepo = ("clone init version help debugcommands debugcomplete"
5364 norepo = ("clone init version help debugcommands debugcomplete"
5365 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5365 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5366 " debugknown debuggetbundle debugbundle")
5366 " debugknown debuggetbundle debugbundle")
5367 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5367 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5368 " debugdata debugindex debugindexdot debugrevlog")
5368 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,562 +1,563 b''
1 # minirst.py - minimal reStructuredText parser
1 # minirst.py - minimal reStructuredText parser
2 #
2 #
3 # Copyright 2009, 2010 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2009, 2010 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 """simplified reStructuredText parser.
8 """simplified reStructuredText parser.
9
9
10 This parser knows just enough about reStructuredText to parse the
10 This parser knows just enough about reStructuredText to parse the
11 Mercurial docstrings.
11 Mercurial docstrings.
12
12
13 It cheats in a major way: nested blocks are not really nested. They
13 It cheats in a major way: nested blocks are not really nested. They
14 are just indented blocks that look like they are nested. This relies
14 are just indented blocks that look like they are nested. This relies
15 on the user to keep the right indentation for the blocks.
15 on the user to keep the right indentation for the blocks.
16
16
17 Remember to update http://mercurial.selenic.com/wiki/HelpStyleGuide
17 Remember to update http://mercurial.selenic.com/wiki/HelpStyleGuide
18 when adding support for new constructs.
18 when adding support for new constructs.
19 """
19 """
20
20
21 import re
21 import re
22 import util, encoding
22 import util, encoding
23 from i18n import _
23 from i18n import _
24
24
25 def replace(text, substs):
25 def replace(text, substs):
26 for f, t in substs:
26 for f, t in substs:
27 text = text.replace(f, t)
27 text = text.replace(f, t)
28 return text
28 return text
29
29
30 _blockre = re.compile(r"\n(?:\s*\n)+")
30 _blockre = re.compile(r"\n(?:\s*\n)+")
31
31
32 def findblocks(text):
32 def findblocks(text):
33 """Find continuous blocks of lines in text.
33 """Find continuous blocks of lines in text.
34
34
35 Returns a list of dictionaries representing the blocks. Each block
35 Returns a list of dictionaries representing the blocks. Each block
36 has an 'indent' field and a 'lines' field.
36 has an 'indent' field and a 'lines' field.
37 """
37 """
38 blocks = []
38 blocks = []
39 for b in _blockre.split(text.lstrip('\n').rstrip()):
39 for b in _blockre.split(text.lstrip('\n').rstrip()):
40 lines = b.splitlines()
40 lines = b.splitlines()
41 if lines:
41 if lines:
42 indent = min((len(l) - len(l.lstrip())) for l in lines)
42 indent = min((len(l) - len(l.lstrip())) for l in lines)
43 lines = [l[indent:] for l in lines]
43 lines = [l[indent:] for l in lines]
44 blocks.append(dict(indent=indent, lines=lines))
44 blocks.append(dict(indent=indent, lines=lines))
45 return blocks
45 return blocks
46
46
47 def findliteralblocks(blocks):
47 def findliteralblocks(blocks):
48 """Finds literal blocks and adds a 'type' field to the blocks.
48 """Finds literal blocks and adds a 'type' field to the blocks.
49
49
50 Literal blocks are given the type 'literal', all other blocks are
50 Literal blocks are given the type 'literal', all other blocks are
51 given type the 'paragraph'.
51 given type the 'paragraph'.
52 """
52 """
53 i = 0
53 i = 0
54 while i < len(blocks):
54 while i < len(blocks):
55 # Searching for a block that looks like this:
55 # Searching for a block that looks like this:
56 #
56 #
57 # +------------------------------+
57 # +------------------------------+
58 # | paragraph |
58 # | paragraph |
59 # | (ends with "::") |
59 # | (ends with "::") |
60 # +------------------------------+
60 # +------------------------------+
61 # +---------------------------+
61 # +---------------------------+
62 # | indented literal block |
62 # | indented literal block |
63 # +---------------------------+
63 # +---------------------------+
64 blocks[i]['type'] = 'paragraph'
64 blocks[i]['type'] = 'paragraph'
65 if blocks[i]['lines'][-1].endswith('::') and i + 1 < len(blocks):
65 if blocks[i]['lines'][-1].endswith('::') and i + 1 < len(blocks):
66 indent = blocks[i]['indent']
66 indent = blocks[i]['indent']
67 adjustment = blocks[i + 1]['indent'] - indent
67 adjustment = blocks[i + 1]['indent'] - indent
68
68
69 if blocks[i]['lines'] == ['::']:
69 if blocks[i]['lines'] == ['::']:
70 # Expanded form: remove block
70 # Expanded form: remove block
71 del blocks[i]
71 del blocks[i]
72 i -= 1
72 i -= 1
73 elif blocks[i]['lines'][-1].endswith(' ::'):
73 elif blocks[i]['lines'][-1].endswith(' ::'):
74 # Partially minimized form: remove space and both
74 # Partially minimized form: remove space and both
75 # colons.
75 # colons.
76 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-3]
76 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-3]
77 else:
77 else:
78 # Fully minimized form: remove just one colon.
78 # Fully minimized form: remove just one colon.
79 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-1]
79 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-1]
80
80
81 # List items are formatted with a hanging indent. We must
81 # List items are formatted with a hanging indent. We must
82 # correct for this here while we still have the original
82 # correct for this here while we still have the original
83 # information on the indentation of the subsequent literal
83 # information on the indentation of the subsequent literal
84 # blocks available.
84 # blocks available.
85 m = _bulletre.match(blocks[i]['lines'][0])
85 m = _bulletre.match(blocks[i]['lines'][0])
86 if m:
86 if m:
87 indent += m.end()
87 indent += m.end()
88 adjustment -= m.end()
88 adjustment -= m.end()
89
89
90 # Mark the following indented blocks.
90 # Mark the following indented blocks.
91 while i + 1 < len(blocks) and blocks[i + 1]['indent'] > indent:
91 while i + 1 < len(blocks) and blocks[i + 1]['indent'] > indent:
92 blocks[i + 1]['type'] = 'literal'
92 blocks[i + 1]['type'] = 'literal'
93 blocks[i + 1]['indent'] -= adjustment
93 blocks[i + 1]['indent'] -= adjustment
94 i += 1
94 i += 1
95 i += 1
95 i += 1
96 return blocks
96 return blocks
97
97
98 _bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)|\|) ')
98 _bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)|\|) ')
99 _optionre = re.compile(r'^(-([a-zA-Z0-9]), )?(--[a-z0-9-]+)'
99 _optionre = re.compile(r'^(-([a-zA-Z0-9]), )?(--[a-z0-9-]+)'
100 r'((.*) +)(.*)$')
100 r'((.*) +)(.*)$')
101 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):[ ]+(.*)')
101 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):[ ]+(.*)')
102 _definitionre = re.compile(r'[^ ]')
102 _definitionre = re.compile(r'[^ ]')
103 _tablere = re.compile(r'(=+\s+)*=+')
103 _tablere = re.compile(r'(=+\s+)*=+')
104
104
105 def splitparagraphs(blocks):
105 def splitparagraphs(blocks):
106 """Split paragraphs into lists."""
106 """Split paragraphs into lists."""
107 # Tuples with (list type, item regexp, single line items?). Order
107 # Tuples with (list type, item regexp, single line items?). Order
108 # matters: definition lists has the least specific regexp and must
108 # matters: definition lists has the least specific regexp and must
109 # come last.
109 # come last.
110 listtypes = [('bullet', _bulletre, True),
110 listtypes = [('bullet', _bulletre, True),
111 ('option', _optionre, True),
111 ('option', _optionre, True),
112 ('field', _fieldre, True),
112 ('field', _fieldre, True),
113 ('definition', _definitionre, False)]
113 ('definition', _definitionre, False)]
114
114
115 def match(lines, i, itemre, singleline):
115 def match(lines, i, itemre, singleline):
116 """Does itemre match an item at line i?
116 """Does itemre match an item at line i?
117
117
118 A list item can be followed by an idented line or another list
118 A list item can be followed by an idented line or another list
119 item (but only if singleline is True).
119 item (but only if singleline is True).
120 """
120 """
121 line1 = lines[i]
121 line1 = lines[i]
122 line2 = i + 1 < len(lines) and lines[i + 1] or ''
122 line2 = i + 1 < len(lines) and lines[i + 1] or ''
123 if not itemre.match(line1):
123 if not itemre.match(line1):
124 return False
124 return False
125 if singleline:
125 if singleline:
126 return line2 == '' or line2[0] == ' ' or itemre.match(line2)
126 return line2 == '' or line2[0] == ' ' or itemre.match(line2)
127 else:
127 else:
128 return line2.startswith(' ')
128 return line2.startswith(' ')
129
129
130 i = 0
130 i = 0
131 while i < len(blocks):
131 while i < len(blocks):
132 if blocks[i]['type'] == 'paragraph':
132 if blocks[i]['type'] == 'paragraph':
133 lines = blocks[i]['lines']
133 lines = blocks[i]['lines']
134 for type, itemre, singleline in listtypes:
134 for type, itemre, singleline in listtypes:
135 if match(lines, 0, itemre, singleline):
135 if match(lines, 0, itemre, singleline):
136 items = []
136 items = []
137 for j, line in enumerate(lines):
137 for j, line in enumerate(lines):
138 if match(lines, j, itemre, singleline):
138 if match(lines, j, itemre, singleline):
139 items.append(dict(type=type, lines=[],
139 items.append(dict(type=type, lines=[],
140 indent=blocks[i]['indent']))
140 indent=blocks[i]['indent']))
141 items[-1]['lines'].append(line)
141 items[-1]['lines'].append(line)
142 blocks[i:i + 1] = items
142 blocks[i:i + 1] = items
143 break
143 break
144 i += 1
144 i += 1
145 return blocks
145 return blocks
146
146
147 _fieldwidth = 12
147 _fieldwidth = 12
148
148
149 def updatefieldlists(blocks):
149 def updatefieldlists(blocks):
150 """Find key and maximum key width for field lists."""
150 """Find key and maximum key width for field lists."""
151 i = 0
151 i = 0
152 while i < len(blocks):
152 while i < len(blocks):
153 if blocks[i]['type'] != 'field':
153 if blocks[i]['type'] != 'field':
154 i += 1
154 i += 1
155 continue
155 continue
156
156
157 keywidth = 0
157 keywidth = 0
158 j = i
158 j = i
159 while j < len(blocks) and blocks[j]['type'] == 'field':
159 while j < len(blocks) and blocks[j]['type'] == 'field':
160 m = _fieldre.match(blocks[j]['lines'][0])
160 m = _fieldre.match(blocks[j]['lines'][0])
161 key, rest = m.groups()
161 key, rest = m.groups()
162 blocks[j]['lines'][0] = rest
162 blocks[j]['lines'][0] = rest
163 blocks[j]['key'] = key
163 blocks[j]['key'] = key
164 keywidth = max(keywidth, len(key))
164 keywidth = max(keywidth, len(key))
165 j += 1
165 j += 1
166
166
167 for block in blocks[i:j]:
167 for block in blocks[i:j]:
168 block['keywidth'] = keywidth
168 block['keywidth'] = keywidth
169 i = j + 1
169 i = j + 1
170
170
171 return blocks
171 return blocks
172
172
173 def updateoptionlists(blocks):
173 def updateoptionlists(blocks):
174 i = 0
174 i = 0
175 while i < len(blocks):
175 while i < len(blocks):
176 if blocks[i]['type'] != 'option':
176 if blocks[i]['type'] != 'option':
177 i += 1
177 i += 1
178 continue
178 continue
179
179
180 optstrwidth = 0
180 optstrwidth = 0
181 j = i
181 j = i
182 while j < len(blocks) and blocks[j]['type'] == 'option':
182 while j < len(blocks) and blocks[j]['type'] == 'option':
183 m = _optionre.match(blocks[j]['lines'][0])
183 m = _optionre.match(blocks[j]['lines'][0])
184
184
185 shortoption = m.group(2)
185 shortoption = m.group(2)
186 group3 = m.group(3)
186 group3 = m.group(3)
187 longoption = group3[2:].strip()
187 longoption = group3[2:].strip()
188 desc = m.group(6).strip()
188 desc = m.group(6).strip()
189 longoptionarg = m.group(5).strip()
189 longoptionarg = m.group(5).strip()
190 blocks[j]['lines'][0] = desc
190 blocks[j]['lines'][0] = desc
191
191
192 noshortop = ''
192 noshortop = ''
193 if not shortoption:
193 if not shortoption:
194 noshortop = ' '
194 noshortop = ' '
195
195
196 opt = "%s%s" % (shortoption and "-%s " % shortoption or '',
196 opt = "%s%s" % (shortoption and "-%s " % shortoption or '',
197 ("%s--%s %s") % (noshortop, longoption,
197 ("%s--%s %s") % (noshortop, longoption,
198 longoptionarg))
198 longoptionarg))
199 opt = opt.rstrip()
199 opt = opt.rstrip()
200 blocks[j]['optstr'] = opt
200 blocks[j]['optstr'] = opt
201 optstrwidth = max(optstrwidth, encoding.colwidth(opt))
201 optstrwidth = max(optstrwidth, encoding.colwidth(opt))
202 j += 1
202 j += 1
203
203
204 for block in blocks[i:j]:
204 for block in blocks[i:j]:
205 block['optstrwidth'] = optstrwidth
205 block['optstrwidth'] = optstrwidth
206 i = j + 1
206 i = j + 1
207 return blocks
207 return blocks
208
208
209 def prunecontainers(blocks, keep):
209 def prunecontainers(blocks, keep):
210 """Prune unwanted containers.
210 """Prune unwanted containers.
211
211
212 The blocks must have a 'type' field, i.e., they should have been
212 The blocks must have a 'type' field, i.e., they should have been
213 run through findliteralblocks first.
213 run through findliteralblocks first.
214 """
214 """
215 pruned = []
215 pruned = []
216 i = 0
216 i = 0
217 while i + 1 < len(blocks):
217 while i + 1 < len(blocks):
218 # Searching for a block that looks like this:
218 # Searching for a block that looks like this:
219 #
219 #
220 # +-------+---------------------------+
220 # +-------+---------------------------+
221 # | ".. container ::" type |
221 # | ".. container ::" type |
222 # +---+ |
222 # +---+ |
223 # | blocks |
223 # | blocks |
224 # +-------------------------------+
224 # +-------------------------------+
225 if (blocks[i]['type'] == 'paragraph' and
225 if (blocks[i]['type'] == 'paragraph' and
226 blocks[i]['lines'][0].startswith('.. container::')):
226 blocks[i]['lines'][0].startswith('.. container::')):
227 indent = blocks[i]['indent']
227 indent = blocks[i]['indent']
228 adjustment = blocks[i + 1]['indent'] - indent
228 adjustment = blocks[i + 1]['indent'] - indent
229 containertype = blocks[i]['lines'][0][15:]
229 containertype = blocks[i]['lines'][0][15:]
230 prune = containertype not in keep
230 prune = containertype not in keep
231 if prune:
231 if prune:
232 pruned.append(containertype)
232 pruned.append(containertype)
233
233
234 # Always delete "..container:: type" block
234 # Always delete "..container:: type" block
235 del blocks[i]
235 del blocks[i]
236 j = i
236 j = i
237 i -= 1
237 i -= 1
238 while j < len(blocks) and blocks[j]['indent'] > indent:
238 while j < len(blocks) and blocks[j]['indent'] > indent:
239 if prune:
239 if prune:
240 del blocks[j]
240 del blocks[j]
241 else:
241 else:
242 blocks[j]['indent'] -= adjustment
242 blocks[j]['indent'] -= adjustment
243 j += 1
243 j += 1
244 i += 1
244 i += 1
245 return blocks, pruned
245 return blocks, pruned
246
246
247 _sectionre = re.compile(r"""^([-=`:.'"~^_*+#])\1+$""")
247 _sectionre = re.compile(r"""^([-=`:.'"~^_*+#])\1+$""")
248
248
249 def findtables(blocks):
249 def findtables(blocks):
250 '''Find simple tables
250 '''Find simple tables
251
251
252 Only simple one-line table elements are supported
252 Only simple one-line table elements are supported
253 '''
253 '''
254
254
255 for block in blocks:
255 for block in blocks:
256 # Searching for a block that looks like this:
256 # Searching for a block that looks like this:
257 #
257 #
258 # === ==== ===
258 # === ==== ===
259 # A B C
259 # A B C
260 # === ==== === <- optional
260 # === ==== === <- optional
261 # 1 2 3
261 # 1 2 3
262 # x y z
262 # x y z
263 # === ==== ===
263 # === ==== ===
264 if (block['type'] == 'paragraph' and
264 if (block['type'] == 'paragraph' and
265 len(block['lines']) > 4 and
265 len(block['lines']) > 4 and
266 _tablere.match(block['lines'][0]) and
266 _tablere.match(block['lines'][0]) and
267 block['lines'][0] == block['lines'][-1]):
267 block['lines'][0] == block['lines'][-1]):
268 block['type'] = 'table'
268 block['type'] = 'table'
269 block['header'] = False
269 block['header'] = False
270 div = block['lines'][0]
270 div = block['lines'][0]
271 columns = [x for x in xrange(len(div))
271 columns = [x for x in xrange(len(div))
272 if div[x] == '=' and (x == 0 or div[x - 1] == ' ')]
272 if div[x] == '=' and (x == 0 or div[x - 1] == ' ')]
273 rows = []
273 rows = []
274 for l in block['lines'][1:-1]:
274 for l in block['lines'][1:-1]:
275 if l == div:
275 if l == div:
276 block['header'] = True
276 block['header'] = True
277 continue
277 continue
278 row = []
278 row = []
279 for n, start in enumerate(columns):
279 for n, start in enumerate(columns):
280 if n + 1 < len(columns):
280 if n + 1 < len(columns):
281 row.append(l[start:columns[n + 1]].strip())
281 row.append(l[start:columns[n + 1]].strip())
282 else:
282 else:
283 row.append(l[start:].strip())
283 row.append(l[start:].strip())
284 rows.append(row)
284 rows.append(row)
285 block['table'] = rows
285 block['table'] = rows
286
286
287 return blocks
287 return blocks
288
288
289 def findsections(blocks):
289 def findsections(blocks):
290 """Finds sections.
290 """Finds sections.
291
291
292 The blocks must have a 'type' field, i.e., they should have been
292 The blocks must have a 'type' field, i.e., they should have been
293 run through findliteralblocks first.
293 run through findliteralblocks first.
294 """
294 """
295 for block in blocks:
295 for block in blocks:
296 # Searching for a block that looks like this:
296 # Searching for a block that looks like this:
297 #
297 #
298 # +------------------------------+
298 # +------------------------------+
299 # | Section title |
299 # | Section title |
300 # | ------------- |
300 # | ------------- |
301 # +------------------------------+
301 # +------------------------------+
302 if (block['type'] == 'paragraph' and
302 if (block['type'] == 'paragraph' and
303 len(block['lines']) == 2 and
303 len(block['lines']) == 2 and
304 encoding.colwidth(block['lines'][0]) == len(block['lines'][1]) and
304 encoding.colwidth(block['lines'][0]) == len(block['lines'][1]) and
305 _sectionre.match(block['lines'][1])):
305 _sectionre.match(block['lines'][1])):
306 block['underline'] = block['lines'][1][0]
306 block['underline'] = block['lines'][1][0]
307 block['type'] = 'section'
307 block['type'] = 'section'
308 del block['lines'][1]
308 del block['lines'][1]
309 return blocks
309 return blocks
310
310
311 def inlineliterals(blocks):
311 def inlineliterals(blocks):
312 substs = [('``', '"')]
312 substs = [('``', '"')]
313 for b in blocks:
313 for b in blocks:
314 if b['type'] in ('paragraph', 'section'):
314 if b['type'] in ('paragraph', 'section'):
315 b['lines'] = [replace(l, substs) for l in b['lines']]
315 b['lines'] = [replace(l, substs) for l in b['lines']]
316 return blocks
316 return blocks
317
317
318 def hgrole(blocks):
318 def hgrole(blocks):
319 substs = [(':hg:`', '"hg '), ('`', '"')]
319 substs = [(':hg:`', '"hg '), ('`', '"')]
320 for b in blocks:
320 for b in blocks:
321 if b['type'] in ('paragraph', 'section'):
321 if b['type'] in ('paragraph', 'section'):
322 # Turn :hg:`command` into "hg command". This also works
322 # Turn :hg:`command` into "hg command". This also works
323 # when there is a line break in the command and relies on
323 # when there is a line break in the command and relies on
324 # the fact that we have no stray back-quotes in the input
324 # the fact that we have no stray back-quotes in the input
325 # (run the blocks through inlineliterals first).
325 # (run the blocks through inlineliterals first).
326 b['lines'] = [replace(l, substs) for l in b['lines']]
326 b['lines'] = [replace(l, substs) for l in b['lines']]
327 return blocks
327 return blocks
328
328
329 def addmargins(blocks):
329 def addmargins(blocks):
330 """Adds empty blocks for vertical spacing.
330 """Adds empty blocks for vertical spacing.
331
331
332 This groups bullets, options, and definitions together with no vertical
332 This groups bullets, options, and definitions together with no vertical
333 space between them, and adds an empty block between all other blocks.
333 space between them, and adds an empty block between all other blocks.
334 """
334 """
335 i = 1
335 i = 1
336 while i < len(blocks):
336 while i < len(blocks):
337 if (blocks[i]['type'] == blocks[i - 1]['type'] and
337 if (blocks[i]['type'] == blocks[i - 1]['type'] and
338 blocks[i]['type'] in ('bullet', 'option', 'field')):
338 blocks[i]['type'] in ('bullet', 'option', 'field')):
339 i += 1
339 i += 1
340 else:
340 else:
341 blocks.insert(i, dict(lines=[''], indent=0, type='margin'))
341 blocks.insert(i, dict(lines=[''], indent=0, type='margin'))
342 i += 2
342 i += 2
343 return blocks
343 return blocks
344
344
345 def prunecomments(blocks):
345 def prunecomments(blocks):
346 """Remove comments."""
346 """Remove comments."""
347 i = 0
347 i = 0
348 while i < len(blocks):
348 while i < len(blocks):
349 b = blocks[i]
349 b = blocks[i]
350 if b['type'] == 'paragraph' and (b['lines'][0].startswith('.. ') or
350 if b['type'] == 'paragraph' and (b['lines'][0].startswith('.. ') or
351 b['lines'] == ['..']):
351 b['lines'] == ['..']):
352 del blocks[i]
352 del blocks[i]
353 if i < len(blocks) and blocks[i]['type'] == 'margin':
353 if i < len(blocks) and blocks[i]['type'] == 'margin':
354 del blocks[i]
354 del blocks[i]
355 else:
355 else:
356 i += 1
356 i += 1
357 return blocks
357 return blocks
358
358
359 _admonitionre = re.compile(r"\.\. (admonition|attention|caution|danger|"
359 _admonitionre = re.compile(r"\.\. (admonition|attention|caution|danger|"
360 r"error|hint|important|note|tip|warning)::",
360 r"error|hint|important|note|tip|warning)::",
361 flags=re.IGNORECASE)
361 flags=re.IGNORECASE)
362
362
363 def findadmonitions(blocks):
363 def findadmonitions(blocks):
364 """
364 """
365 Makes the type of the block an admonition block if
365 Makes the type of the block an admonition block if
366 the first line is an admonition directive
366 the first line is an admonition directive
367 """
367 """
368 i = 0
368 i = 0
369 while i < len(blocks):
369 while i < len(blocks):
370 m = _admonitionre.match(blocks[i]['lines'][0])
370 m = _admonitionre.match(blocks[i]['lines'][0])
371 if m:
371 if m:
372 blocks[i]['type'] = 'admonition'
372 blocks[i]['type'] = 'admonition'
373 admonitiontitle = blocks[i]['lines'][0][3:m.end() - 2].lower()
373 admonitiontitle = blocks[i]['lines'][0][3:m.end() - 2].lower()
374
374
375 firstline = blocks[i]['lines'][0][m.end() + 1:]
375 firstline = blocks[i]['lines'][0][m.end() + 1:]
376 if firstline:
376 if firstline:
377 blocks[i]['lines'].insert(1, ' ' + firstline)
377 blocks[i]['lines'].insert(1, ' ' + firstline)
378
378
379 blocks[i]['admonitiontitle'] = admonitiontitle
379 blocks[i]['admonitiontitle'] = admonitiontitle
380 del blocks[i]['lines'][0]
380 del blocks[i]['lines'][0]
381 i = i + 1
381 i = i + 1
382 return blocks
382 return blocks
383
383
384 _admonitiontitles = {'attention': _('Attention:'),
384 _admonitiontitles = {'attention': _('Attention:'),
385 'caution': _('Caution:'),
385 'caution': _('Caution:'),
386 'danger': _('!Danger!') ,
386 'danger': _('!Danger!') ,
387 'error': _('Error:'),
387 'error': _('Error:'),
388 'hint': _('Hint:'),
388 'hint': _('Hint:'),
389 'important': _('Important:'),
389 'important': _('Important:'),
390 'note': _('Note:'),
390 'note': _('Note:'),
391 'tip': _('Tip:'),
391 'tip': _('Tip:'),
392 'warning': _('Warning!')}
392 'warning': _('Warning!')}
393
393
394 def formatoption(block, width):
394 def formatoption(block, width):
395 desc = ' '.join(map(str.strip, block['lines']))
395 desc = ' '.join(map(str.strip, block['lines']))
396 colwidth = encoding.colwidth(block['optstr'])
396 colwidth = encoding.colwidth(block['optstr'])
397 usablewidth = width - 1
397 usablewidth = width - 1
398 hanging = block['optstrwidth']
398 hanging = block['optstrwidth']
399 initindent = '%s%s ' % (block['optstr'], ' ' * ((hanging - colwidth)))
399 initindent = '%s%s ' % (block['optstr'], ' ' * ((hanging - colwidth)))
400 hangindent = ' ' * (encoding.colwidth(initindent) + 1)
400 hangindent = ' ' * (encoding.colwidth(initindent) + 1)
401 return ' %s' % (util.wrap(desc, usablewidth,
401 return ' %s\n' % (util.wrap(desc, usablewidth,
402 initindent=initindent,
402 initindent=initindent,
403 hangindent=hangindent))
403 hangindent=hangindent))
404
404
405 def formatblock(block, width):
405 def formatblock(block, width):
406 """Format a block according to width."""
406 """Format a block according to width."""
407 if width <= 0:
407 if width <= 0:
408 width = 78
408 width = 78
409 indent = ' ' * block['indent']
409 indent = ' ' * block['indent']
410 if block['type'] == 'admonition':
410 if block['type'] == 'admonition':
411 admonition = _admonitiontitles[block['admonitiontitle']]
411 admonition = _admonitiontitles[block['admonitiontitle']]
412 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
412 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
413
413
414 defindent = indent + hang * ' '
414 defindent = indent + hang * ' '
415 text = ' '.join(map(str.strip, block['lines']))
415 text = ' '.join(map(str.strip, block['lines']))
416 return '%s\n%s' % (indent + admonition, util.wrap(text, width=width,
416 return '%s\n%s\n' % (indent + admonition,
417 initindent=defindent,
417 util.wrap(text, width=width,
418 hangindent=defindent))
418 initindent=defindent,
419 hangindent=defindent))
419 if block['type'] == 'margin':
420 if block['type'] == 'margin':
420 return ''
421 return '\n'
421 if block['type'] == 'literal':
422 if block['type'] == 'literal':
422 indent += ' '
423 indent += ' '
423 return indent + ('\n' + indent).join(block['lines'])
424 return indent + ('\n' + indent).join(block['lines']) + '\n'
424 if block['type'] == 'section':
425 if block['type'] == 'section':
425 underline = encoding.colwidth(block['lines'][0]) * block['underline']
426 underline = encoding.colwidth(block['lines'][0]) * block['underline']
426 return "%s%s\n%s%s" % (indent, block['lines'][0],indent, underline)
427 return "%s%s\n%s%s\n" % (indent, block['lines'][0],indent, underline)
427 if block['type'] == 'table':
428 if block['type'] == 'table':
428 table = block['table']
429 table = block['table']
429 # compute column widths
430 # compute column widths
430 widths = [max([encoding.colwidth(e) for e in c]) for c in zip(*table)]
431 widths = [max([encoding.colwidth(e) for e in c]) for c in zip(*table)]
431 text = ''
432 text = ''
432 span = sum(widths) + len(widths) - 1
433 span = sum(widths) + len(widths) - 1
433 indent = ' ' * block['indent']
434 indent = ' ' * block['indent']
434 hang = ' ' * (len(indent) + span - widths[-1])
435 hang = ' ' * (len(indent) + span - widths[-1])
435 f = ' '.join('%%-%ds' % n for n in widths)
436 f = ' '.join('%%-%ds' % n for n in widths)
436
437
437 for row in table:
438 for row in table:
438 l = f % tuple(row)
439 l = f % tuple(row)
439 l = util.wrap(l, width=width, initindent=indent, hangindent=hang)
440 l = util.wrap(l, width=width, initindent=indent, hangindent=hang)
440 if not text and block['header']:
441 if not text and block['header']:
441 text = l + '\n' + indent + '-' * (min(width, span)) + '\n'
442 text = l + '\n' + indent + '-' * (min(width, span)) + '\n'
442 else:
443 else:
443 text += l + "\n"
444 text += l + "\n"
444 return text
445 return text
445 if block['type'] == 'definition':
446 if block['type'] == 'definition':
446 term = indent + block['lines'][0]
447 term = indent + block['lines'][0]
447 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
448 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
448 defindent = indent + hang * ' '
449 defindent = indent + hang * ' '
449 text = ' '.join(map(str.strip, block['lines'][1:]))
450 text = ' '.join(map(str.strip, block['lines'][1:]))
450 return '%s\n%s' % (term, util.wrap(text, width=width,
451 return '%s\n%s\n' % (term, util.wrap(text, width=width,
451 initindent=defindent,
452 initindent=defindent,
452 hangindent=defindent))
453 hangindent=defindent))
453 subindent = indent
454 subindent = indent
454 if block['type'] == 'bullet':
455 if block['type'] == 'bullet':
455 if block['lines'][0].startswith('| '):
456 if block['lines'][0].startswith('| '):
456 # Remove bullet for line blocks and add no extra
457 # Remove bullet for line blocks and add no extra
457 # indention.
458 # indention.
458 block['lines'][0] = block['lines'][0][2:]
459 block['lines'][0] = block['lines'][0][2:]
459 else:
460 else:
460 m = _bulletre.match(block['lines'][0])
461 m = _bulletre.match(block['lines'][0])
461 subindent = indent + m.end() * ' '
462 subindent = indent + m.end() * ' '
462 elif block['type'] == 'field':
463 elif block['type'] == 'field':
463 keywidth = block['keywidth']
464 keywidth = block['keywidth']
464 key = block['key']
465 key = block['key']
465
466
466 subindent = indent + _fieldwidth * ' '
467 subindent = indent + _fieldwidth * ' '
467 if len(key) + 2 > _fieldwidth:
468 if len(key) + 2 > _fieldwidth:
468 # key too large, use full line width
469 # key too large, use full line width
469 key = key.ljust(width)
470 key = key.ljust(width)
470 elif keywidth + 2 < _fieldwidth:
471 elif keywidth + 2 < _fieldwidth:
471 # all keys are small, add only two spaces
472 # all keys are small, add only two spaces
472 key = key.ljust(keywidth + 2)
473 key = key.ljust(keywidth + 2)
473 subindent = indent + (keywidth + 2) * ' '
474 subindent = indent + (keywidth + 2) * ' '
474 else:
475 else:
475 # mixed sizes, use fieldwidth for this one
476 # mixed sizes, use fieldwidth for this one
476 key = key.ljust(_fieldwidth)
477 key = key.ljust(_fieldwidth)
477 block['lines'][0] = key + block['lines'][0]
478 block['lines'][0] = key + block['lines'][0]
478 elif block['type'] == 'option':
479 elif block['type'] == 'option':
479 return formatoption(block, width)
480 return formatoption(block, width)
480
481
481 text = ' '.join(map(str.strip, block['lines']))
482 text = ' '.join(map(str.strip, block['lines']))
482 return util.wrap(text, width=width,
483 return util.wrap(text, width=width,
483 initindent=indent,
484 initindent=indent,
484 hangindent=subindent)
485 hangindent=subindent) + '\n'
485
486
486 def parse(text, indent=0, keep=None):
487 def parse(text, indent=0, keep=None):
487 """Parse text into a list of blocks"""
488 """Parse text into a list of blocks"""
488 pruned = []
489 pruned = []
489 blocks = findblocks(text)
490 blocks = findblocks(text)
490 for b in blocks:
491 for b in blocks:
491 b['indent'] += indent
492 b['indent'] += indent
492 blocks = findliteralblocks(blocks)
493 blocks = findliteralblocks(blocks)
493 blocks = findtables(blocks)
494 blocks = findtables(blocks)
494 blocks, pruned = prunecontainers(blocks, keep or [])
495 blocks, pruned = prunecontainers(blocks, keep or [])
495 blocks = findsections(blocks)
496 blocks = findsections(blocks)
496 blocks = inlineliterals(blocks)
497 blocks = inlineliterals(blocks)
497 blocks = hgrole(blocks)
498 blocks = hgrole(blocks)
498 blocks = splitparagraphs(blocks)
499 blocks = splitparagraphs(blocks)
499 blocks = updatefieldlists(blocks)
500 blocks = updatefieldlists(blocks)
500 blocks = updateoptionlists(blocks)
501 blocks = updateoptionlists(blocks)
501 blocks = addmargins(blocks)
502 blocks = addmargins(blocks)
502 blocks = prunecomments(blocks)
503 blocks = prunecomments(blocks)
503 blocks = findadmonitions(blocks)
504 blocks = findadmonitions(blocks)
504 return blocks, pruned
505 return blocks, pruned
505
506
506 def formatblocks(blocks, width):
507 def formatblocks(blocks, width):
507 text = '\n'.join(formatblock(b, width) for b in blocks)
508 text = ''.join(formatblock(b, width) for b in blocks)
508 return text
509 return text
509
510
510 def format(text, width, indent=0, keep=None):
511 def format(text, width, indent=0, keep=None):
511 """Parse and format the text according to width."""
512 """Parse and format the text according to width."""
512 blocks, pruned = parse(text, indent, keep or [])
513 blocks, pruned = parse(text, indent, keep or [])
513 text = '\n'.join(formatblock(b, width) for b in blocks)
514 text = ''.join(formatblock(b, width) for b in blocks)
514 if keep is None:
515 if keep is None:
515 return text
516 return text
516 else:
517 else:
517 return text, pruned
518 return text, pruned
518
519
519 def getsections(blocks):
520 def getsections(blocks):
520 '''return a list of (section name, nesting level, blocks) tuples'''
521 '''return a list of (section name, nesting level, blocks) tuples'''
521 nest = ""
522 nest = ""
522 level = 0
523 level = 0
523 secs = []
524 secs = []
524 for b in blocks:
525 for b in blocks:
525 if b['type'] == 'section':
526 if b['type'] == 'section':
526 i = b['underline']
527 i = b['underline']
527 if i not in nest:
528 if i not in nest:
528 nest += i
529 nest += i
529 level = nest.index(i) + 1
530 level = nest.index(i) + 1
530 nest = nest[:level]
531 nest = nest[:level]
531 secs.append((b['lines'][0], level, [b]))
532 secs.append((b['lines'][0], level, [b]))
532 else:
533 else:
533 if not secs:
534 if not secs:
534 # add an initial empty section
535 # add an initial empty section
535 secs = [('', 0, [])]
536 secs = [('', 0, [])]
536 secs[-1][2].append(b)
537 secs[-1][2].append(b)
537 return secs
538 return secs
538
539
539 def decorateblocks(blocks, width):
540 def decorateblocks(blocks, width):
540 '''generate a list of (section name, line text) pairs for search'''
541 '''generate a list of (section name, line text) pairs for search'''
541 lines = []
542 lines = []
542 for s in getsections(blocks):
543 for s in getsections(blocks):
543 section = s[0]
544 section = s[0]
544 text = formatblocks(s[2], width)
545 text = formatblocks(s[2], width)
545 lines.append([(section, l) for l in text.splitlines(True)])
546 lines.append([(section, l) for l in text.splitlines(True)])
546 return lines
547 return lines
547
548
548 def maketable(data, indent=0, header=False):
549 def maketable(data, indent=0, header=False):
549 '''Generate an RST table for the given table data'''
550 '''Generate an RST table for the given table data'''
550
551
551 widths = [max(encoding.colwidth(e) for e in c) for c in zip(*data)]
552 widths = [max(encoding.colwidth(e) for e in c) for c in zip(*data)]
552 indent = ' ' * indent
553 indent = ' ' * indent
553 f = indent + ' '.join('%%-%ds' % w for w in widths) + '\n'
554 f = indent + ' '.join('%%-%ds' % w for w in widths) + '\n'
554 div = indent + ' '.join('=' * w for w in widths) + '\n'
555 div = indent + ' '.join('=' * w for w in widths) + '\n'
555
556
556 out = [div]
557 out = [div]
557 for row in data:
558 for row in data:
558 out.append(f % tuple(row))
559 out.append(f % tuple(row))
559 if header and len(data) > 1:
560 if header and len(data) > 1:
560 out.insert(2, div)
561 out.insert(2, div)
561 out.append(div)
562 out.append(div)
562 return ''.join(out)
563 return ''.join(out)
@@ -1,408 +1,428 b''
1 paragraphs formatted to fit within 60 characters:
1 paragraphs formatted to fit within 60 characters:
2 ----------------------------------------------------------------------
2 ----------------------------------------------------------------------
3 This is some text in the first paragraph.
3 This is some text in the first paragraph.
4
4
5 A small indented paragraph. It is followed by some lines
5 A small indented paragraph. It is followed by some lines
6 containing random whitespace.
6 containing random whitespace.
7
7
8 The third and final paragraph.
8 The third and final paragraph.
9
9 ----------------------------------------------------------------------
10 ----------------------------------------------------------------------
10
11
11 paragraphs formatted to fit within 30 characters:
12 paragraphs formatted to fit within 30 characters:
12 ----------------------------------------------------------------------
13 ----------------------------------------------------------------------
13 This is some text in the first
14 This is some text in the first
14 paragraph.
15 paragraph.
15
16
16 A small indented paragraph.
17 A small indented paragraph.
17 It is followed by some lines
18 It is followed by some lines
18 containing random
19 containing random
19 whitespace.
20 whitespace.
20
21
21 The third and final paragraph.
22 The third and final paragraph.
23
22 ----------------------------------------------------------------------
24 ----------------------------------------------------------------------
23
25
24 definitions formatted to fit within 60 characters:
26 definitions formatted to fit within 60 characters:
25 ----------------------------------------------------------------------
27 ----------------------------------------------------------------------
26 A Term
28 A Term
27 Definition. The indented lines make up the definition.
29 Definition. The indented lines make up the definition.
28
30
29 Another Term
31 Another Term
30 Another definition. The final line in the definition
32 Another definition. The final line in the definition
31 determines the indentation, so this will be indented
33 determines the indentation, so this will be indented
32 with four spaces.
34 with four spaces.
33
35
34 A Nested/Indented Term
36 A Nested/Indented Term
35 Definition.
37 Definition.
38
36 ----------------------------------------------------------------------
39 ----------------------------------------------------------------------
37
40
38 definitions formatted to fit within 30 characters:
41 definitions formatted to fit within 30 characters:
39 ----------------------------------------------------------------------
42 ----------------------------------------------------------------------
40 A Term
43 A Term
41 Definition. The indented
44 Definition. The indented
42 lines make up the
45 lines make up the
43 definition.
46 definition.
44
47
45 Another Term
48 Another Term
46 Another definition. The
49 Another definition. The
47 final line in the
50 final line in the
48 definition determines the
51 definition determines the
49 indentation, so this will
52 indentation, so this will
50 be indented with four
53 be indented with four
51 spaces.
54 spaces.
52
55
53 A Nested/Indented Term
56 A Nested/Indented Term
54 Definition.
57 Definition.
58
55 ----------------------------------------------------------------------
59 ----------------------------------------------------------------------
56
60
57 literals formatted to fit within 60 characters:
61 literals formatted to fit within 60 characters:
58 ----------------------------------------------------------------------
62 ----------------------------------------------------------------------
59 The fully minimized form is the most convenient form:
63 The fully minimized form is the most convenient form:
60
64
61 Hello
65 Hello
62 literal
66 literal
63 world
67 world
64
68
65 In the partially minimized form a paragraph simply ends with
69 In the partially minimized form a paragraph simply ends with
66 space-double-colon.
70 space-double-colon.
67
71
68 ////////////////////////////////////////
72 ////////////////////////////////////////
69 long un-wrapped line in a literal block
73 long un-wrapped line in a literal block
70 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
74 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
71
75
72 This literal block is started with '::',
76 This literal block is started with '::',
73 the so-called expanded form. The paragraph
77 the so-called expanded form. The paragraph
74 with '::' disappears in the final output.
78 with '::' disappears in the final output.
79
75 ----------------------------------------------------------------------
80 ----------------------------------------------------------------------
76
81
77 literals formatted to fit within 30 characters:
82 literals formatted to fit within 30 characters:
78 ----------------------------------------------------------------------
83 ----------------------------------------------------------------------
79 The fully minimized form is
84 The fully minimized form is
80 the most convenient form:
85 the most convenient form:
81
86
82 Hello
87 Hello
83 literal
88 literal
84 world
89 world
85
90
86 In the partially minimized
91 In the partially minimized
87 form a paragraph simply ends
92 form a paragraph simply ends
88 with space-double-colon.
93 with space-double-colon.
89
94
90 ////////////////////////////////////////
95 ////////////////////////////////////////
91 long un-wrapped line in a literal block
96 long un-wrapped line in a literal block
92 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
97 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
93
98
94 This literal block is started with '::',
99 This literal block is started with '::',
95 the so-called expanded form. The paragraph
100 the so-called expanded form. The paragraph
96 with '::' disappears in the final output.
101 with '::' disappears in the final output.
102
97 ----------------------------------------------------------------------
103 ----------------------------------------------------------------------
98
104
99 lists formatted to fit within 60 characters:
105 lists formatted to fit within 60 characters:
100 ----------------------------------------------------------------------
106 ----------------------------------------------------------------------
101 - This is the first list item.
107 - This is the first list item.
102
108
103 Second paragraph in the first list item.
109 Second paragraph in the first list item.
104
110
105 - List items need not be separated by a blank line.
111 - List items need not be separated by a blank line.
106 - And will be rendered without one in any case.
112 - And will be rendered without one in any case.
107
113
108 We can have indented lists:
114 We can have indented lists:
109
115
110 - This is an indented list item
116 - This is an indented list item
111 - Another indented list item:
117 - Another indented list item:
112
118
113 - A literal block in the middle
119 - A literal block in the middle
114 of an indented list.
120 of an indented list.
115
121
116 (The above is not a list item since we are in the literal block.)
122 (The above is not a list item since we are in the literal block.)
117
123
118 Literal block with no indentation (apart from
124 Literal block with no indentation (apart from
119 the two spaces added to all literal blocks).
125 the two spaces added to all literal blocks).
120
126
121 1. This is an enumerated list (first item).
127 1. This is an enumerated list (first item).
122 2. Continuing with the second item.
128 2. Continuing with the second item.
123 (1) foo
129 (1) foo
124 (2) bar
130 (2) bar
125 1) Another
131 1) Another
126 2) List
132 2) List
127
133
128 Line blocks are also a form of list:
134 Line blocks are also a form of list:
129
135
130 This is the first line. The line continues here.
136 This is the first line. The line continues here.
131 This is the second line.
137 This is the second line.
138
132 ----------------------------------------------------------------------
139 ----------------------------------------------------------------------
133
140
134 lists formatted to fit within 30 characters:
141 lists formatted to fit within 30 characters:
135 ----------------------------------------------------------------------
142 ----------------------------------------------------------------------
136 - This is the first list item.
143 - This is the first list item.
137
144
138 Second paragraph in the
145 Second paragraph in the
139 first list item.
146 first list item.
140
147
141 - List items need not be
148 - List items need not be
142 separated by a blank line.
149 separated by a blank line.
143 - And will be rendered without
150 - And will be rendered without
144 one in any case.
151 one in any case.
145
152
146 We can have indented lists:
153 We can have indented lists:
147
154
148 - This is an indented list
155 - This is an indented list
149 item
156 item
150 - Another indented list
157 - Another indented list
151 item:
158 item:
152
159
153 - A literal block in the middle
160 - A literal block in the middle
154 of an indented list.
161 of an indented list.
155
162
156 (The above is not a list item since we are in the literal block.)
163 (The above is not a list item since we are in the literal block.)
157
164
158 Literal block with no indentation (apart from
165 Literal block with no indentation (apart from
159 the two spaces added to all literal blocks).
166 the two spaces added to all literal blocks).
160
167
161 1. This is an enumerated list
168 1. This is an enumerated list
162 (first item).
169 (first item).
163 2. Continuing with the second
170 2. Continuing with the second
164 item.
171 item.
165 (1) foo
172 (1) foo
166 (2) bar
173 (2) bar
167 1) Another
174 1) Another
168 2) List
175 2) List
169
176
170 Line blocks are also a form of
177 Line blocks are also a form of
171 list:
178 list:
172
179
173 This is the first line. The
180 This is the first line. The
174 line continues here.
181 line continues here.
175 This is the second line.
182 This is the second line.
183
176 ----------------------------------------------------------------------
184 ----------------------------------------------------------------------
177
185
178 options formatted to fit within 60 characters:
186 options formatted to fit within 60 characters:
179 ----------------------------------------------------------------------
187 ----------------------------------------------------------------------
180 There is support for simple option lists, but only with long
188 There is support for simple option lists, but only with long
181 options:
189 options:
182
190
183 -X --exclude filter an option with a short and long option
191 -X --exclude filter an option with a short and long option
184 with an argument
192 with an argument
185 -I --include an option with both a short option and
193 -I --include an option with both a short option and
186 a long option
194 a long option
187 --all Output all.
195 --all Output all.
188 --both Output both (this description is quite
196 --both Output both (this description is quite
189 long).
197 long).
190 --long Output all day long.
198 --long Output all day long.
191 --par This option has two paragraphs in its
199 --par This option has two paragraphs in its
192 description. This is the first.
200 description. This is the first.
193
201
194 This is the second. Blank lines may
202 This is the second. Blank lines may
195 be omitted between options (as above)
203 be omitted between options (as above)
196 or left in (as here).
204 or left in (as here).
197
205
198 The next paragraph looks like an option list, but lacks the
206 The next paragraph looks like an option list, but lacks the
199 two-space marker after the option. It is treated as a normal
207 two-space marker after the option. It is treated as a normal
200 paragraph:
208 paragraph:
201
209
202 --foo bar baz
210 --foo bar baz
211
203 ----------------------------------------------------------------------
212 ----------------------------------------------------------------------
204
213
205 options formatted to fit within 30 characters:
214 options formatted to fit within 30 characters:
206 ----------------------------------------------------------------------
215 ----------------------------------------------------------------------
207 There is support for simple
216 There is support for simple
208 option lists, but only with
217 option lists, but only with
209 long options:
218 long options:
210
219
211 -X --exclude filter an
220 -X --exclude filter an
212 option
221 option
213 with a
222 with a
214 short
223 short
215 and
224 and
216 long
225 long
217 option
226 option
218 with an
227 with an
219 argumen
228 argumen
220 t
229 t
221 -I --include an
230 -I --include an
222 option
231 option
223 with
232 with
224 both a
233 both a
225 short
234 short
226 option
235 option
227 and a
236 and a
228 long
237 long
229 option
238 option
230 --all Output
239 --all Output
231 all.
240 all.
232 --both Output
241 --both Output
233 both
242 both
234 (this d
243 (this d
235 escript
244 escript
236 ion is
245 ion is
237 quite
246 quite
238 long).
247 long).
239 --long Output
248 --long Output
240 all day
249 all day
241 long.
250 long.
242 --par This
251 --par This
243 option
252 option
244 has two
253 has two
245 paragra
254 paragra
246 phs in
255 phs in
247 its des
256 its des
248 criptio
257 criptio
249 n. This
258 n. This
250 is the
259 is the
251 first.
260 first.
252
261
253 This is
262 This is
254 the
263 the
255 second.
264 second.
256 Blank
265 Blank
257 lines
266 lines
258 may be
267 may be
259 omitted
268 omitted
260 between
269 between
261 options
270 options
262 (as
271 (as
263 above)
272 above)
264 or left
273 or left
265 in (as
274 in (as
266 here).
275 here).
267
276
268 The next paragraph looks like
277 The next paragraph looks like
269 an option list, but lacks the
278 an option list, but lacks the
270 two-space marker after the
279 two-space marker after the
271 option. It is treated as a
280 option. It is treated as a
272 normal paragraph:
281 normal paragraph:
273
282
274 --foo bar baz
283 --foo bar baz
284
275 ----------------------------------------------------------------------
285 ----------------------------------------------------------------------
276
286
277 fields formatted to fit within 60 characters:
287 fields formatted to fit within 60 characters:
278 ----------------------------------------------------------------------
288 ----------------------------------------------------------------------
279 a First item.
289 a First item.
280 ab Second item. Indentation and wrapping is handled
290 ab Second item. Indentation and wrapping is handled
281 automatically.
291 automatically.
282
292
283 Next list:
293 Next list:
284
294
285 small The larger key below triggers full indentation
295 small The larger key below triggers full indentation
286 here.
296 here.
287 much too large
297 much too large
288 This key is big enough to get its own line.
298 This key is big enough to get its own line.
299
289 ----------------------------------------------------------------------
300 ----------------------------------------------------------------------
290
301
291 fields formatted to fit within 30 characters:
302 fields formatted to fit within 30 characters:
292 ----------------------------------------------------------------------
303 ----------------------------------------------------------------------
293 a First item.
304 a First item.
294 ab Second item. Indentation
305 ab Second item. Indentation
295 and wrapping is handled
306 and wrapping is handled
296 automatically.
307 automatically.
297
308
298 Next list:
309 Next list:
299
310
300 small The larger key
311 small The larger key
301 below triggers
312 below triggers
302 full indentation
313 full indentation
303 here.
314 here.
304 much too large
315 much too large
305 This key is big
316 This key is big
306 enough to get its
317 enough to get its
307 own line.
318 own line.
319
308 ----------------------------------------------------------------------
320 ----------------------------------------------------------------------
309
321
310 containers (normal) formatted to fit within 60 characters:
322 containers (normal) formatted to fit within 60 characters:
311 ----------------------------------------------------------------------
323 ----------------------------------------------------------------------
312 Normal output.
324 Normal output.
325
313 ----------------------------------------------------------------------
326 ----------------------------------------------------------------------
314
327
315 containers (verbose) formatted to fit within 60 characters:
328 containers (verbose) formatted to fit within 60 characters:
316 ----------------------------------------------------------------------
329 ----------------------------------------------------------------------
317 Normal output.
330 Normal output.
318
331
319 Verbose output.
332 Verbose output.
333
320 ----------------------------------------------------------------------
334 ----------------------------------------------------------------------
321 ['debug', 'debug']
335 ['debug', 'debug']
322 ----------------------------------------------------------------------
336 ----------------------------------------------------------------------
323
337
324 containers (debug) formatted to fit within 60 characters:
338 containers (debug) formatted to fit within 60 characters:
325 ----------------------------------------------------------------------
339 ----------------------------------------------------------------------
326 Normal output.
340 Normal output.
327
341
328 Initial debug output.
342 Initial debug output.
343
329 ----------------------------------------------------------------------
344 ----------------------------------------------------------------------
330 ['verbose']
345 ['verbose']
331 ----------------------------------------------------------------------
346 ----------------------------------------------------------------------
332
347
333 containers (verbose debug) formatted to fit within 60 characters:
348 containers (verbose debug) formatted to fit within 60 characters:
334 ----------------------------------------------------------------------
349 ----------------------------------------------------------------------
335 Normal output.
350 Normal output.
336
351
337 Initial debug output.
352 Initial debug output.
338
353
339 Verbose output.
354 Verbose output.
340
355
341 Debug output.
356 Debug output.
357
342 ----------------------------------------------------------------------
358 ----------------------------------------------------------------------
343 []
359 []
344 ----------------------------------------------------------------------
360 ----------------------------------------------------------------------
345
361
346 roles formatted to fit within 60 characters:
362 roles formatted to fit within 60 characters:
347 ----------------------------------------------------------------------
363 ----------------------------------------------------------------------
348 Please see "hg add".
364 Please see "hg add".
365
349 ----------------------------------------------------------------------
366 ----------------------------------------------------------------------
350
367
351 sections formatted to fit within 20 characters:
368 sections formatted to fit within 20 characters:
352 ----------------------------------------------------------------------
369 ----------------------------------------------------------------------
353 Title
370 Title
354 =====
371 =====
355
372
356 Section
373 Section
357 -------
374 -------
358
375
359 Subsection
376 Subsection
360 ''''''''''
377 ''''''''''
361
378
362 Markup: "foo" and "hg help"
379 Markup: "foo" and "hg help"
363 ---------------------------
380 ---------------------------
381
364 ----------------------------------------------------------------------
382 ----------------------------------------------------------------------
365
383
366 admonitions formatted to fit within 30 characters:
384 admonitions formatted to fit within 30 characters:
367 ----------------------------------------------------------------------
385 ----------------------------------------------------------------------
368 Note:
386 Note:
369 This is a note
387 This is a note
370
388
371 - Bullet 1
389 - Bullet 1
372 - Bullet 2
390 - Bullet 2
373
391
374 Warning!
392 Warning!
375 This is a warning Second
393 This is a warning Second
376 input line of warning
394 input line of warning
377
395
378 !Danger!
396 !Danger!
379 This is danger
397 This is danger
398
380 ----------------------------------------------------------------------
399 ----------------------------------------------------------------------
381
400
382 comments formatted to fit within 30 characters:
401 comments formatted to fit within 30 characters:
383 ----------------------------------------------------------------------
402 ----------------------------------------------------------------------
384 Some text.
403 Some text.
385
404
386 Some indented text.
405 Some indented text.
387
406
388 Empty comment above
407 Empty comment above
408
389 ----------------------------------------------------------------------
409 ----------------------------------------------------------------------
390
410
391 === === ========================================
411 === === ========================================
392 a b c
412 a b c
393 === === ========================================
413 === === ========================================
394 1 2 3
414 1 2 3
395 foo bar baz this list is very very very long man
415 foo bar baz this list is very very very long man
396 === === ========================================
416 === === ========================================
397
417
398 table formatted to fit within 30 characters:
418 table formatted to fit within 30 characters:
399 ----------------------------------------------------------------------
419 ----------------------------------------------------------------------
400 a b c
420 a b c
401 ------------------------------
421 ------------------------------
402 1 2 3
422 1 2 3
403 foo bar baz this list is
423 foo bar baz this list is
404 very very very long
424 very very very long
405 man
425 man
406
426
407 ----------------------------------------------------------------------
427 ----------------------------------------------------------------------
408
428
General Comments 0
You need to be logged in to leave comments. Login now