##// END OF EJS Templates
minirst: add simple table support...
Matt Mackall -
r15037:df47381b default
parent child Browse files
Show More
@@ -1,5189 +1,5192 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 Valid types are:
310 Valid types are:
311
311
312 :``files``: a directory full of files (default)
312 :``files``: a directory full of files (default)
313 :``tar``: tar archive, uncompressed
313 :``tar``: tar archive, uncompressed
314 :``tbz2``: tar archive, compressed using bzip2
314 :``tbz2``: tar archive, compressed using bzip2
315 :``tgz``: tar archive, compressed using gzip
315 :``tgz``: tar archive, compressed using gzip
316 :``uzip``: zip archive, uncompressed
316 :``uzip``: zip archive, uncompressed
317 :``zip``: zip archive, compressed using deflate
317 :``zip``: zip archive, compressed using deflate
318
318
319 The exact name of the destination archive or directory is given
319 The exact name of the destination archive or directory is given
320 using a format string; see :hg:`help export` for details.
320 using a format string; see :hg:`help export` for details.
321
321
322 Each member added to an archive file has a directory prefix
322 Each member added to an archive file has a directory prefix
323 prepended. Use -p/--prefix to specify a format string for the
323 prepended. Use -p/--prefix to specify a format string for the
324 prefix. The default is the basename of the archive, with suffixes
324 prefix. The default is the basename of the archive, with suffixes
325 removed.
325 removed.
326
326
327 Returns 0 on success.
327 Returns 0 on success.
328 '''
328 '''
329
329
330 ctx = scmutil.revsingle(repo, opts.get('rev'))
330 ctx = scmutil.revsingle(repo, opts.get('rev'))
331 if not ctx:
331 if not ctx:
332 raise util.Abort(_('no working directory: please specify a revision'))
332 raise util.Abort(_('no working directory: please specify a revision'))
333 node = ctx.node()
333 node = ctx.node()
334 dest = cmdutil.makefilename(repo, dest, node)
334 dest = cmdutil.makefilename(repo, dest, node)
335 if os.path.realpath(dest) == repo.root:
335 if os.path.realpath(dest) == repo.root:
336 raise util.Abort(_('repository root cannot be destination'))
336 raise util.Abort(_('repository root cannot be destination'))
337
337
338 kind = opts.get('type') or archival.guesskind(dest) or 'files'
338 kind = opts.get('type') or archival.guesskind(dest) or 'files'
339 prefix = opts.get('prefix')
339 prefix = opts.get('prefix')
340
340
341 if dest == '-':
341 if dest == '-':
342 if kind == 'files':
342 if kind == 'files':
343 raise util.Abort(_('cannot archive plain files to stdout'))
343 raise util.Abort(_('cannot archive plain files to stdout'))
344 dest = cmdutil.makefileobj(repo, dest)
344 dest = cmdutil.makefileobj(repo, dest)
345 if not prefix:
345 if not prefix:
346 prefix = os.path.basename(repo.root) + '-%h'
346 prefix = os.path.basename(repo.root) + '-%h'
347
347
348 prefix = cmdutil.makefilename(repo, prefix, node)
348 prefix = cmdutil.makefilename(repo, prefix, node)
349 matchfn = scmutil.match(ctx, [], opts)
349 matchfn = scmutil.match(ctx, [], opts)
350 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
350 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
351 matchfn, prefix, subrepos=opts.get('subrepos'))
351 matchfn, prefix, subrepos=opts.get('subrepos'))
352
352
353 @command('backout',
353 @command('backout',
354 [('', 'merge', None, _('merge with old dirstate parent after backout')),
354 [('', 'merge', None, _('merge with old dirstate parent after backout')),
355 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
355 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
356 ('r', 'rev', '', _('revision to backout'), _('REV')),
356 ('r', 'rev', '', _('revision to backout'), _('REV')),
357 ] + mergetoolopts + walkopts + commitopts + commitopts2,
357 ] + mergetoolopts + walkopts + commitopts + commitopts2,
358 _('[OPTION]... [-r] REV'))
358 _('[OPTION]... [-r] REV'))
359 def backout(ui, repo, node=None, rev=None, **opts):
359 def backout(ui, repo, node=None, rev=None, **opts):
360 '''reverse effect of earlier changeset
360 '''reverse effect of earlier changeset
361
361
362 Prepare a new changeset with the effect of REV undone in the
362 Prepare a new changeset with the effect of REV undone in the
363 current working directory.
363 current working directory.
364
364
365 If REV is the parent of the working directory, then this new changeset
365 If REV is the parent of the working directory, then this new changeset
366 is committed automatically. Otherwise, hg needs to merge the
366 is committed automatically. Otherwise, hg needs to merge the
367 changes and the merged result is left uncommitted.
367 changes and the merged result is left uncommitted.
368
368
369 By default, the pending changeset will have one parent,
369 By default, the pending changeset will have one parent,
370 maintaining a linear history. With --merge, the pending changeset
370 maintaining a linear history. With --merge, the pending changeset
371 will instead have two parents: the old parent of the working
371 will instead have two parents: the old parent of the working
372 directory and a new child of REV that simply undoes REV.
372 directory and a new child of REV that simply undoes REV.
373
373
374 Before version 1.7, the behavior without --merge was equivalent to
374 Before version 1.7, the behavior without --merge was equivalent to
375 specifying --merge followed by :hg:`update --clean .` to cancel
375 specifying --merge followed by :hg:`update --clean .` to cancel
376 the merge and leave the child of REV as a head to be merged
376 the merge and leave the child of REV as a head to be merged
377 separately.
377 separately.
378
378
379 See :hg:`help dates` for a list of formats valid for -d/--date.
379 See :hg:`help dates` for a list of formats valid for -d/--date.
380
380
381 Returns 0 on success.
381 Returns 0 on success.
382 '''
382 '''
383 if rev and node:
383 if rev and node:
384 raise util.Abort(_("please specify just one revision"))
384 raise util.Abort(_("please specify just one revision"))
385
385
386 if not rev:
386 if not rev:
387 rev = node
387 rev = node
388
388
389 if not rev:
389 if not rev:
390 raise util.Abort(_("please specify a revision to backout"))
390 raise util.Abort(_("please specify a revision to backout"))
391
391
392 date = opts.get('date')
392 date = opts.get('date')
393 if date:
393 if date:
394 opts['date'] = util.parsedate(date)
394 opts['date'] = util.parsedate(date)
395
395
396 cmdutil.bailifchanged(repo)
396 cmdutil.bailifchanged(repo)
397 node = scmutil.revsingle(repo, rev).node()
397 node = scmutil.revsingle(repo, rev).node()
398
398
399 op1, op2 = repo.dirstate.parents()
399 op1, op2 = repo.dirstate.parents()
400 a = repo.changelog.ancestor(op1, node)
400 a = repo.changelog.ancestor(op1, node)
401 if a != node:
401 if a != node:
402 raise util.Abort(_('cannot backout change on a different branch'))
402 raise util.Abort(_('cannot backout change on a different branch'))
403
403
404 p1, p2 = repo.changelog.parents(node)
404 p1, p2 = repo.changelog.parents(node)
405 if p1 == nullid:
405 if p1 == nullid:
406 raise util.Abort(_('cannot backout a change with no parents'))
406 raise util.Abort(_('cannot backout a change with no parents'))
407 if p2 != nullid:
407 if p2 != nullid:
408 if not opts.get('parent'):
408 if not opts.get('parent'):
409 raise util.Abort(_('cannot backout a merge changeset without '
409 raise util.Abort(_('cannot backout a merge changeset without '
410 '--parent'))
410 '--parent'))
411 p = repo.lookup(opts['parent'])
411 p = repo.lookup(opts['parent'])
412 if p not in (p1, p2):
412 if p not in (p1, p2):
413 raise util.Abort(_('%s is not a parent of %s') %
413 raise util.Abort(_('%s is not a parent of %s') %
414 (short(p), short(node)))
414 (short(p), short(node)))
415 parent = p
415 parent = p
416 else:
416 else:
417 if opts.get('parent'):
417 if opts.get('parent'):
418 raise util.Abort(_('cannot use --parent on non-merge changeset'))
418 raise util.Abort(_('cannot use --parent on non-merge changeset'))
419 parent = p1
419 parent = p1
420
420
421 # the backout should appear on the same branch
421 # the backout should appear on the same branch
422 branch = repo.dirstate.branch()
422 branch = repo.dirstate.branch()
423 hg.clean(repo, node, show_stats=False)
423 hg.clean(repo, node, show_stats=False)
424 repo.dirstate.setbranch(branch)
424 repo.dirstate.setbranch(branch)
425 revert_opts = opts.copy()
425 revert_opts = opts.copy()
426 revert_opts['date'] = None
426 revert_opts['date'] = None
427 revert_opts['all'] = True
427 revert_opts['all'] = True
428 revert_opts['rev'] = hex(parent)
428 revert_opts['rev'] = hex(parent)
429 revert_opts['no_backup'] = None
429 revert_opts['no_backup'] = None
430 revert(ui, repo, **revert_opts)
430 revert(ui, repo, **revert_opts)
431 if not opts.get('merge') and op1 != node:
431 if not opts.get('merge') and op1 != node:
432 try:
432 try:
433 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
433 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
434 return hg.update(repo, op1)
434 return hg.update(repo, op1)
435 finally:
435 finally:
436 ui.setconfig('ui', 'forcemerge', '')
436 ui.setconfig('ui', 'forcemerge', '')
437
437
438 commit_opts = opts.copy()
438 commit_opts = opts.copy()
439 commit_opts['addremove'] = False
439 commit_opts['addremove'] = False
440 if not commit_opts['message'] and not commit_opts['logfile']:
440 if not commit_opts['message'] and not commit_opts['logfile']:
441 # we don't translate commit messages
441 # we don't translate commit messages
442 commit_opts['message'] = "Backed out changeset %s" % short(node)
442 commit_opts['message'] = "Backed out changeset %s" % short(node)
443 commit_opts['force_editor'] = True
443 commit_opts['force_editor'] = True
444 commit(ui, repo, **commit_opts)
444 commit(ui, repo, **commit_opts)
445 def nice(node):
445 def nice(node):
446 return '%d:%s' % (repo.changelog.rev(node), short(node))
446 return '%d:%s' % (repo.changelog.rev(node), short(node))
447 ui.status(_('changeset %s backs out changeset %s\n') %
447 ui.status(_('changeset %s backs out changeset %s\n') %
448 (nice(repo.changelog.tip()), nice(node)))
448 (nice(repo.changelog.tip()), nice(node)))
449 if opts.get('merge') and op1 != node:
449 if opts.get('merge') and op1 != node:
450 hg.clean(repo, op1, show_stats=False)
450 hg.clean(repo, op1, show_stats=False)
451 ui.status(_('merging with changeset %s\n')
451 ui.status(_('merging with changeset %s\n')
452 % nice(repo.changelog.tip()))
452 % nice(repo.changelog.tip()))
453 try:
453 try:
454 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
454 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
455 return hg.merge(repo, hex(repo.changelog.tip()))
455 return hg.merge(repo, hex(repo.changelog.tip()))
456 finally:
456 finally:
457 ui.setconfig('ui', 'forcemerge', '')
457 ui.setconfig('ui', 'forcemerge', '')
458 return 0
458 return 0
459
459
460 @command('bisect',
460 @command('bisect',
461 [('r', 'reset', False, _('reset bisect state')),
461 [('r', 'reset', False, _('reset bisect state')),
462 ('g', 'good', False, _('mark changeset good')),
462 ('g', 'good', False, _('mark changeset good')),
463 ('b', 'bad', False, _('mark changeset bad')),
463 ('b', 'bad', False, _('mark changeset bad')),
464 ('s', 'skip', False, _('skip testing changeset')),
464 ('s', 'skip', False, _('skip testing changeset')),
465 ('e', 'extend', False, _('extend the bisect range')),
465 ('e', 'extend', False, _('extend the bisect range')),
466 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
466 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
467 ('U', 'noupdate', False, _('do not update to target'))],
467 ('U', 'noupdate', False, _('do not update to target'))],
468 _("[-gbsr] [-U] [-c CMD] [REV]"))
468 _("[-gbsr] [-U] [-c CMD] [REV]"))
469 def bisect(ui, repo, rev=None, extra=None, command=None,
469 def bisect(ui, repo, rev=None, extra=None, command=None,
470 reset=None, good=None, bad=None, skip=None, extend=None,
470 reset=None, good=None, bad=None, skip=None, extend=None,
471 noupdate=None):
471 noupdate=None):
472 """subdivision search of changesets
472 """subdivision search of changesets
473
473
474 This command helps to find changesets which introduce problems. To
474 This command helps to find changesets which introduce problems. To
475 use, mark the earliest changeset you know exhibits the problem as
475 use, mark the earliest changeset you know exhibits the problem as
476 bad, then mark the latest changeset which is free from the problem
476 bad, then mark the latest changeset which is free from the problem
477 as good. Bisect will update your working directory to a revision
477 as good. Bisect will update your working directory to a revision
478 for testing (unless the -U/--noupdate option is specified). Once
478 for testing (unless the -U/--noupdate option is specified). Once
479 you have performed tests, mark the working directory as good or
479 you have performed tests, mark the working directory as good or
480 bad, and bisect will either update to another candidate changeset
480 bad, and bisect will either update to another candidate changeset
481 or announce that it has found the bad revision.
481 or announce that it has found the bad revision.
482
482
483 As a shortcut, you can also use the revision argument to mark a
483 As a shortcut, you can also use the revision argument to mark a
484 revision as good or bad without checking it out first.
484 revision as good or bad without checking it out first.
485
485
486 If you supply a command, it will be used for automatic bisection.
486 If you supply a command, it will be used for automatic bisection.
487 Its exit status will be used to mark revisions as good or bad:
487 Its exit status will be used to mark revisions as good or bad:
488 status 0 means good, 125 means to skip the revision, 127
488 status 0 means good, 125 means to skip the revision, 127
489 (command not found) will abort the bisection, and any other
489 (command not found) will abort the bisection, and any other
490 non-zero exit status means the revision is bad.
490 non-zero exit status means the revision is bad.
491
491
492 Returns 0 on success.
492 Returns 0 on success.
493 """
493 """
494 def extendbisectrange(nodes, good):
494 def extendbisectrange(nodes, good):
495 # bisect is incomplete when it ends on a merge node and
495 # bisect is incomplete when it ends on a merge node and
496 # one of the parent was not checked.
496 # one of the parent was not checked.
497 parents = repo[nodes[0]].parents()
497 parents = repo[nodes[0]].parents()
498 if len(parents) > 1:
498 if len(parents) > 1:
499 side = good and state['bad'] or state['good']
499 side = good and state['bad'] or state['good']
500 num = len(set(i.node() for i in parents) & set(side))
500 num = len(set(i.node() for i in parents) & set(side))
501 if num == 1:
501 if num == 1:
502 return parents[0].ancestor(parents[1])
502 return parents[0].ancestor(parents[1])
503 return None
503 return None
504
504
505 def print_result(nodes, good):
505 def print_result(nodes, good):
506 displayer = cmdutil.show_changeset(ui, repo, {})
506 displayer = cmdutil.show_changeset(ui, repo, {})
507 if len(nodes) == 1:
507 if len(nodes) == 1:
508 # narrowed it down to a single revision
508 # narrowed it down to a single revision
509 if good:
509 if good:
510 ui.write(_("The first good revision is:\n"))
510 ui.write(_("The first good revision is:\n"))
511 else:
511 else:
512 ui.write(_("The first bad revision is:\n"))
512 ui.write(_("The first bad revision is:\n"))
513 displayer.show(repo[nodes[0]])
513 displayer.show(repo[nodes[0]])
514 extendnode = extendbisectrange(nodes, good)
514 extendnode = extendbisectrange(nodes, good)
515 if extendnode is not None:
515 if extendnode is not None:
516 ui.write(_('Not all ancestors of this changeset have been'
516 ui.write(_('Not all ancestors of this changeset have been'
517 ' checked.\nUse bisect --extend to continue the '
517 ' checked.\nUse bisect --extend to continue the '
518 'bisection from\nthe common ancestor, %s.\n')
518 'bisection from\nthe common ancestor, %s.\n')
519 % extendnode)
519 % extendnode)
520 else:
520 else:
521 # multiple possible revisions
521 # multiple possible revisions
522 if good:
522 if good:
523 ui.write(_("Due to skipped revisions, the first "
523 ui.write(_("Due to skipped revisions, the first "
524 "good revision could be any of:\n"))
524 "good revision could be any of:\n"))
525 else:
525 else:
526 ui.write(_("Due to skipped revisions, the first "
526 ui.write(_("Due to skipped revisions, the first "
527 "bad revision could be any of:\n"))
527 "bad revision could be any of:\n"))
528 for n in nodes:
528 for n in nodes:
529 displayer.show(repo[n])
529 displayer.show(repo[n])
530 displayer.close()
530 displayer.close()
531
531
532 def check_state(state, interactive=True):
532 def check_state(state, interactive=True):
533 if not state['good'] or not state['bad']:
533 if not state['good'] or not state['bad']:
534 if (good or bad or skip or reset) and interactive:
534 if (good or bad or skip or reset) and interactive:
535 return
535 return
536 if not state['good']:
536 if not state['good']:
537 raise util.Abort(_('cannot bisect (no known good revisions)'))
537 raise util.Abort(_('cannot bisect (no known good revisions)'))
538 else:
538 else:
539 raise util.Abort(_('cannot bisect (no known bad revisions)'))
539 raise util.Abort(_('cannot bisect (no known bad revisions)'))
540 return True
540 return True
541
541
542 # backward compatibility
542 # backward compatibility
543 if rev in "good bad reset init".split():
543 if rev in "good bad reset init".split():
544 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
544 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
545 cmd, rev, extra = rev, extra, None
545 cmd, rev, extra = rev, extra, None
546 if cmd == "good":
546 if cmd == "good":
547 good = True
547 good = True
548 elif cmd == "bad":
548 elif cmd == "bad":
549 bad = True
549 bad = True
550 else:
550 else:
551 reset = True
551 reset = True
552 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
552 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
553 raise util.Abort(_('incompatible arguments'))
553 raise util.Abort(_('incompatible arguments'))
554
554
555 if reset:
555 if reset:
556 p = repo.join("bisect.state")
556 p = repo.join("bisect.state")
557 if os.path.exists(p):
557 if os.path.exists(p):
558 os.unlink(p)
558 os.unlink(p)
559 return
559 return
560
560
561 state = hbisect.load_state(repo)
561 state = hbisect.load_state(repo)
562
562
563 if command:
563 if command:
564 changesets = 1
564 changesets = 1
565 try:
565 try:
566 while changesets:
566 while changesets:
567 # update state
567 # update state
568 status = util.system(command, out=ui.fout)
568 status = util.system(command, out=ui.fout)
569 if status == 125:
569 if status == 125:
570 transition = "skip"
570 transition = "skip"
571 elif status == 0:
571 elif status == 0:
572 transition = "good"
572 transition = "good"
573 # status < 0 means process was killed
573 # status < 0 means process was killed
574 elif status == 127:
574 elif status == 127:
575 raise util.Abort(_("failed to execute %s") % command)
575 raise util.Abort(_("failed to execute %s") % command)
576 elif status < 0:
576 elif status < 0:
577 raise util.Abort(_("%s killed") % command)
577 raise util.Abort(_("%s killed") % command)
578 else:
578 else:
579 transition = "bad"
579 transition = "bad"
580 ctx = scmutil.revsingle(repo, rev)
580 ctx = scmutil.revsingle(repo, rev)
581 rev = None # clear for future iterations
581 rev = None # clear for future iterations
582 state[transition].append(ctx.node())
582 state[transition].append(ctx.node())
583 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
583 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
584 check_state(state, interactive=False)
584 check_state(state, interactive=False)
585 # bisect
585 # bisect
586 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
586 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
587 # update to next check
587 # update to next check
588 cmdutil.bailifchanged(repo)
588 cmdutil.bailifchanged(repo)
589 hg.clean(repo, nodes[0], show_stats=False)
589 hg.clean(repo, nodes[0], show_stats=False)
590 finally:
590 finally:
591 hbisect.save_state(repo, state)
591 hbisect.save_state(repo, state)
592 print_result(nodes, good)
592 print_result(nodes, good)
593 return
593 return
594
594
595 # update state
595 # update state
596
596
597 if rev:
597 if rev:
598 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
598 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
599 else:
599 else:
600 nodes = [repo.lookup('.')]
600 nodes = [repo.lookup('.')]
601
601
602 if good or bad or skip:
602 if good or bad or skip:
603 if good:
603 if good:
604 state['good'] += nodes
604 state['good'] += nodes
605 elif bad:
605 elif bad:
606 state['bad'] += nodes
606 state['bad'] += nodes
607 elif skip:
607 elif skip:
608 state['skip'] += nodes
608 state['skip'] += nodes
609 hbisect.save_state(repo, state)
609 hbisect.save_state(repo, state)
610
610
611 if not check_state(state):
611 if not check_state(state):
612 return
612 return
613
613
614 # actually bisect
614 # actually bisect
615 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
615 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
616 if extend:
616 if extend:
617 if not changesets:
617 if not changesets:
618 extendnode = extendbisectrange(nodes, good)
618 extendnode = extendbisectrange(nodes, good)
619 if extendnode is not None:
619 if extendnode is not None:
620 ui.write(_("Extending search to changeset %d:%s\n"
620 ui.write(_("Extending search to changeset %d:%s\n"
621 % (extendnode.rev(), extendnode)))
621 % (extendnode.rev(), extendnode)))
622 if noupdate:
622 if noupdate:
623 return
623 return
624 cmdutil.bailifchanged(repo)
624 cmdutil.bailifchanged(repo)
625 return hg.clean(repo, extendnode.node())
625 return hg.clean(repo, extendnode.node())
626 raise util.Abort(_("nothing to extend"))
626 raise util.Abort(_("nothing to extend"))
627
627
628 if changesets == 0:
628 if changesets == 0:
629 print_result(nodes, good)
629 print_result(nodes, good)
630 else:
630 else:
631 assert len(nodes) == 1 # only a single node can be tested next
631 assert len(nodes) == 1 # only a single node can be tested next
632 node = nodes[0]
632 node = nodes[0]
633 # compute the approximate number of remaining tests
633 # compute the approximate number of remaining tests
634 tests, size = 0, 2
634 tests, size = 0, 2
635 while size <= changesets:
635 while size <= changesets:
636 tests, size = tests + 1, size * 2
636 tests, size = tests + 1, size * 2
637 rev = repo.changelog.rev(node)
637 rev = repo.changelog.rev(node)
638 ui.write(_("Testing changeset %d:%s "
638 ui.write(_("Testing changeset %d:%s "
639 "(%d changesets remaining, ~%d tests)\n")
639 "(%d changesets remaining, ~%d tests)\n")
640 % (rev, short(node), changesets, tests))
640 % (rev, short(node), changesets, tests))
641 if not noupdate:
641 if not noupdate:
642 cmdutil.bailifchanged(repo)
642 cmdutil.bailifchanged(repo)
643 return hg.clean(repo, node)
643 return hg.clean(repo, node)
644
644
645 @command('bookmarks',
645 @command('bookmarks',
646 [('f', 'force', False, _('force')),
646 [('f', 'force', False, _('force')),
647 ('r', 'rev', '', _('revision'), _('REV')),
647 ('r', 'rev', '', _('revision'), _('REV')),
648 ('d', 'delete', False, _('delete a given bookmark')),
648 ('d', 'delete', False, _('delete a given bookmark')),
649 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
649 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
650 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
650 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
651 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
651 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
652 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
652 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
653 rename=None, inactive=False):
653 rename=None, inactive=False):
654 '''track a line of development with movable markers
654 '''track a line of development with movable markers
655
655
656 Bookmarks are pointers to certain commits that move when
656 Bookmarks are pointers to certain commits that move when
657 committing. Bookmarks are local. They can be renamed, copied and
657 committing. Bookmarks are local. They can be renamed, copied and
658 deleted. It is possible to use bookmark names in :hg:`merge` and
658 deleted. It is possible to use bookmark names in :hg:`merge` and
659 :hg:`update` to merge and update respectively to a given bookmark.
659 :hg:`update` to merge and update respectively to a given bookmark.
660
660
661 You can use :hg:`bookmark NAME` to set a bookmark on the working
661 You can use :hg:`bookmark NAME` to set a bookmark on the working
662 directory's parent revision with the given name. If you specify
662 directory's parent revision with the given name. If you specify
663 a revision using -r REV (where REV may be an existing bookmark),
663 a revision using -r REV (where REV may be an existing bookmark),
664 the bookmark is assigned to that revision.
664 the bookmark is assigned to that revision.
665
665
666 Bookmarks can be pushed and pulled between repositories (see :hg:`help
666 Bookmarks can be pushed and pulled between repositories (see :hg:`help
667 push` and :hg:`help pull`). This requires both the local and remote
667 push` and :hg:`help pull`). This requires both the local and remote
668 repositories to support bookmarks. For versions prior to 1.8, this means
668 repositories to support bookmarks. For versions prior to 1.8, this means
669 the bookmarks extension must be enabled.
669 the bookmarks extension must be enabled.
670 '''
670 '''
671 hexfn = ui.debugflag and hex or short
671 hexfn = ui.debugflag and hex or short
672 marks = repo._bookmarks
672 marks = repo._bookmarks
673 cur = repo.changectx('.').node()
673 cur = repo.changectx('.').node()
674
674
675 if rename:
675 if rename:
676 if rename not in marks:
676 if rename not in marks:
677 raise util.Abort(_("bookmark '%s' does not exist") % rename)
677 raise util.Abort(_("bookmark '%s' does not exist") % rename)
678 if mark in marks and not force:
678 if mark in marks and not force:
679 raise util.Abort(_("bookmark '%s' already exists "
679 raise util.Abort(_("bookmark '%s' already exists "
680 "(use -f to force)") % mark)
680 "(use -f to force)") % mark)
681 if mark is None:
681 if mark is None:
682 raise util.Abort(_("new bookmark name required"))
682 raise util.Abort(_("new bookmark name required"))
683 marks[mark] = marks[rename]
683 marks[mark] = marks[rename]
684 if repo._bookmarkcurrent == rename and not inactive:
684 if repo._bookmarkcurrent == rename and not inactive:
685 bookmarks.setcurrent(repo, mark)
685 bookmarks.setcurrent(repo, mark)
686 del marks[rename]
686 del marks[rename]
687 bookmarks.write(repo)
687 bookmarks.write(repo)
688 return
688 return
689
689
690 if delete:
690 if delete:
691 if mark is None:
691 if mark is None:
692 raise util.Abort(_("bookmark name required"))
692 raise util.Abort(_("bookmark name required"))
693 if mark not in marks:
693 if mark not in marks:
694 raise util.Abort(_("bookmark '%s' does not exist") % mark)
694 raise util.Abort(_("bookmark '%s' does not exist") % mark)
695 if mark == repo._bookmarkcurrent:
695 if mark == repo._bookmarkcurrent:
696 bookmarks.setcurrent(repo, None)
696 bookmarks.setcurrent(repo, None)
697 del marks[mark]
697 del marks[mark]
698 bookmarks.write(repo)
698 bookmarks.write(repo)
699 return
699 return
700
700
701 if mark is not None:
701 if mark is not None:
702 if "\n" in mark:
702 if "\n" in mark:
703 raise util.Abort(_("bookmark name cannot contain newlines"))
703 raise util.Abort(_("bookmark name cannot contain newlines"))
704 mark = mark.strip()
704 mark = mark.strip()
705 if not mark:
705 if not mark:
706 raise util.Abort(_("bookmark names cannot consist entirely of "
706 raise util.Abort(_("bookmark names cannot consist entirely of "
707 "whitespace"))
707 "whitespace"))
708 if inactive and mark == repo._bookmarkcurrent:
708 if inactive and mark == repo._bookmarkcurrent:
709 bookmarks.setcurrent(repo, None)
709 bookmarks.setcurrent(repo, None)
710 return
710 return
711 if mark in marks and not force:
711 if mark in marks and not force:
712 raise util.Abort(_("bookmark '%s' already exists "
712 raise util.Abort(_("bookmark '%s' already exists "
713 "(use -f to force)") % mark)
713 "(use -f to force)") % mark)
714 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
714 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
715 and not force):
715 and not force):
716 raise util.Abort(
716 raise util.Abort(
717 _("a bookmark cannot have the name of an existing branch"))
717 _("a bookmark cannot have the name of an existing branch"))
718 if rev:
718 if rev:
719 marks[mark] = repo.lookup(rev)
719 marks[mark] = repo.lookup(rev)
720 else:
720 else:
721 marks[mark] = repo.changectx('.').node()
721 marks[mark] = repo.changectx('.').node()
722 if not inactive and repo.changectx('.').node() == marks[mark]:
722 if not inactive and repo.changectx('.').node() == marks[mark]:
723 bookmarks.setcurrent(repo, mark)
723 bookmarks.setcurrent(repo, mark)
724 bookmarks.write(repo)
724 bookmarks.write(repo)
725 return
725 return
726
726
727 if mark is None:
727 if mark is None:
728 if rev:
728 if rev:
729 raise util.Abort(_("bookmark name required"))
729 raise util.Abort(_("bookmark name required"))
730 if len(marks) == 0:
730 if len(marks) == 0:
731 ui.status(_("no bookmarks set\n"))
731 ui.status(_("no bookmarks set\n"))
732 else:
732 else:
733 for bmark, n in sorted(marks.iteritems()):
733 for bmark, n in sorted(marks.iteritems()):
734 current = repo._bookmarkcurrent
734 current = repo._bookmarkcurrent
735 if bmark == current and n == cur:
735 if bmark == current and n == cur:
736 prefix, label = '*', 'bookmarks.current'
736 prefix, label = '*', 'bookmarks.current'
737 else:
737 else:
738 prefix, label = ' ', ''
738 prefix, label = ' ', ''
739
739
740 if ui.quiet:
740 if ui.quiet:
741 ui.write("%s\n" % bmark, label=label)
741 ui.write("%s\n" % bmark, label=label)
742 else:
742 else:
743 ui.write(" %s %-25s %d:%s\n" % (
743 ui.write(" %s %-25s %d:%s\n" % (
744 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
744 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
745 label=label)
745 label=label)
746 return
746 return
747
747
748 @command('branch',
748 @command('branch',
749 [('f', 'force', None,
749 [('f', 'force', None,
750 _('set branch name even if it shadows an existing branch')),
750 _('set branch name even if it shadows an existing branch')),
751 ('C', 'clean', None, _('reset branch name to parent branch name'))],
751 ('C', 'clean', None, _('reset branch name to parent branch name'))],
752 _('[-fC] [NAME]'))
752 _('[-fC] [NAME]'))
753 def branch(ui, repo, label=None, **opts):
753 def branch(ui, repo, label=None, **opts):
754 """set or show the current branch name
754 """set or show the current branch name
755
755
756 With no argument, show the current branch name. With one argument,
756 With no argument, show the current branch name. With one argument,
757 set the working directory branch name (the branch will not exist
757 set the working directory branch name (the branch will not exist
758 in the repository until the next commit). Standard practice
758 in the repository until the next commit). Standard practice
759 recommends that primary development take place on the 'default'
759 recommends that primary development take place on the 'default'
760 branch.
760 branch.
761
761
762 Unless -f/--force is specified, branch will not let you set a
762 Unless -f/--force is specified, branch will not let you set a
763 branch name that already exists, even if it's inactive.
763 branch name that already exists, even if it's inactive.
764
764
765 Use -C/--clean to reset the working directory branch to that of
765 Use -C/--clean to reset the working directory branch to that of
766 the parent of the working directory, negating a previous branch
766 the parent of the working directory, negating a previous branch
767 change.
767 change.
768
768
769 Use the command :hg:`update` to switch to an existing branch. Use
769 Use the command :hg:`update` to switch to an existing branch. Use
770 :hg:`commit --close-branch` to mark this branch as closed.
770 :hg:`commit --close-branch` to mark this branch as closed.
771
771
772 .. note::
772 .. note::
773
773
774 Branch names are permanent. Use :hg:`bookmark` to create a
774 Branch names are permanent. Use :hg:`bookmark` to create a
775 light-weight bookmark instead. See :hg:`help glossary` for more
775 light-weight bookmark instead. See :hg:`help glossary` for more
776 information about named branches and bookmarks.
776 information about named branches and bookmarks.
777
777
778 Returns 0 on success.
778 Returns 0 on success.
779 """
779 """
780
780
781 if opts.get('clean'):
781 if opts.get('clean'):
782 label = repo[None].p1().branch()
782 label = repo[None].p1().branch()
783 repo.dirstate.setbranch(label)
783 repo.dirstate.setbranch(label)
784 ui.status(_('reset working directory to branch %s\n') % label)
784 ui.status(_('reset working directory to branch %s\n') % label)
785 elif label:
785 elif label:
786 if not opts.get('force') and label in repo.branchtags():
786 if not opts.get('force') and label in repo.branchtags():
787 if label not in [p.branch() for p in repo.parents()]:
787 if label not in [p.branch() for p in repo.parents()]:
788 raise util.Abort(_('a branch of the same name already exists'),
788 raise util.Abort(_('a branch of the same name already exists'),
789 # i18n: "it" refers to an existing branch
789 # i18n: "it" refers to an existing branch
790 hint=_("use 'hg update' to switch to it"))
790 hint=_("use 'hg update' to switch to it"))
791 repo.dirstate.setbranch(label)
791 repo.dirstate.setbranch(label)
792 ui.status(_('marked working directory as branch %s\n') % label)
792 ui.status(_('marked working directory as branch %s\n') % label)
793 else:
793 else:
794 ui.write("%s\n" % repo.dirstate.branch())
794 ui.write("%s\n" % repo.dirstate.branch())
795
795
796 @command('branches',
796 @command('branches',
797 [('a', 'active', False, _('show only branches that have unmerged heads')),
797 [('a', 'active', False, _('show only branches that have unmerged heads')),
798 ('c', 'closed', False, _('show normal and closed branches'))],
798 ('c', 'closed', False, _('show normal and closed branches'))],
799 _('[-ac]'))
799 _('[-ac]'))
800 def branches(ui, repo, active=False, closed=False):
800 def branches(ui, repo, active=False, closed=False):
801 """list repository named branches
801 """list repository named branches
802
802
803 List the repository's named branches, indicating which ones are
803 List the repository's named branches, indicating which ones are
804 inactive. If -c/--closed is specified, also list branches which have
804 inactive. If -c/--closed is specified, also list branches which have
805 been marked closed (see :hg:`commit --close-branch`).
805 been marked closed (see :hg:`commit --close-branch`).
806
806
807 If -a/--active is specified, only show active branches. A branch
807 If -a/--active is specified, only show active branches. A branch
808 is considered active if it contains repository heads.
808 is considered active if it contains repository heads.
809
809
810 Use the command :hg:`update` to switch to an existing branch.
810 Use the command :hg:`update` to switch to an existing branch.
811
811
812 Returns 0.
812 Returns 0.
813 """
813 """
814
814
815 hexfunc = ui.debugflag and hex or short
815 hexfunc = ui.debugflag and hex or short
816 activebranches = [repo[n].branch() for n in repo.heads()]
816 activebranches = [repo[n].branch() for n in repo.heads()]
817 def testactive(tag, node):
817 def testactive(tag, node):
818 realhead = tag in activebranches
818 realhead = tag in activebranches
819 open = node in repo.branchheads(tag, closed=False)
819 open = node in repo.branchheads(tag, closed=False)
820 return realhead and open
820 return realhead and open
821 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
821 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
822 for tag, node in repo.branchtags().items()],
822 for tag, node in repo.branchtags().items()],
823 reverse=True)
823 reverse=True)
824
824
825 for isactive, node, tag in branches:
825 for isactive, node, tag in branches:
826 if (not active) or isactive:
826 if (not active) or isactive:
827 if ui.quiet:
827 if ui.quiet:
828 ui.write("%s\n" % tag)
828 ui.write("%s\n" % tag)
829 else:
829 else:
830 hn = repo.lookup(node)
830 hn = repo.lookup(node)
831 if isactive:
831 if isactive:
832 label = 'branches.active'
832 label = 'branches.active'
833 notice = ''
833 notice = ''
834 elif hn not in repo.branchheads(tag, closed=False):
834 elif hn not in repo.branchheads(tag, closed=False):
835 if not closed:
835 if not closed:
836 continue
836 continue
837 label = 'branches.closed'
837 label = 'branches.closed'
838 notice = _(' (closed)')
838 notice = _(' (closed)')
839 else:
839 else:
840 label = 'branches.inactive'
840 label = 'branches.inactive'
841 notice = _(' (inactive)')
841 notice = _(' (inactive)')
842 if tag == repo.dirstate.branch():
842 if tag == repo.dirstate.branch():
843 label = 'branches.current'
843 label = 'branches.current'
844 rev = str(node).rjust(31 - encoding.colwidth(tag))
844 rev = str(node).rjust(31 - encoding.colwidth(tag))
845 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
845 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
846 tag = ui.label(tag, label)
846 tag = ui.label(tag, label)
847 ui.write("%s %s%s\n" % (tag, rev, notice))
847 ui.write("%s %s%s\n" % (tag, rev, notice))
848
848
849 @command('bundle',
849 @command('bundle',
850 [('f', 'force', None, _('run even when the destination is unrelated')),
850 [('f', 'force', None, _('run even when the destination is unrelated')),
851 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
851 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
852 _('REV')),
852 _('REV')),
853 ('b', 'branch', [], _('a specific branch you would like to bundle'),
853 ('b', 'branch', [], _('a specific branch you would like to bundle'),
854 _('BRANCH')),
854 _('BRANCH')),
855 ('', 'base', [],
855 ('', 'base', [],
856 _('a base changeset assumed to be available at the destination'),
856 _('a base changeset assumed to be available at the destination'),
857 _('REV')),
857 _('REV')),
858 ('a', 'all', None, _('bundle all changesets in the repository')),
858 ('a', 'all', None, _('bundle all changesets in the repository')),
859 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
859 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
860 ] + remoteopts,
860 ] + remoteopts,
861 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
861 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
862 def bundle(ui, repo, fname, dest=None, **opts):
862 def bundle(ui, repo, fname, dest=None, **opts):
863 """create a changegroup file
863 """create a changegroup file
864
864
865 Generate a compressed changegroup file collecting changesets not
865 Generate a compressed changegroup file collecting changesets not
866 known to be in another repository.
866 known to be in another repository.
867
867
868 If you omit the destination repository, then hg assumes the
868 If you omit the destination repository, then hg assumes the
869 destination will have all the nodes you specify with --base
869 destination will have all the nodes you specify with --base
870 parameters. To create a bundle containing all changesets, use
870 parameters. To create a bundle containing all changesets, use
871 -a/--all (or --base null).
871 -a/--all (or --base null).
872
872
873 You can change compression method with the -t/--type option.
873 You can change compression method with the -t/--type option.
874 The available compression methods are: none, bzip2, and
874 The available compression methods are: none, bzip2, and
875 gzip (by default, bundles are compressed using bzip2).
875 gzip (by default, bundles are compressed using bzip2).
876
876
877 The bundle file can then be transferred using conventional means
877 The bundle file can then be transferred using conventional means
878 and applied to another repository with the unbundle or pull
878 and applied to another repository with the unbundle or pull
879 command. This is useful when direct push and pull are not
879 command. This is useful when direct push and pull are not
880 available or when exporting an entire repository is undesirable.
880 available or when exporting an entire repository is undesirable.
881
881
882 Applying bundles preserves all changeset contents including
882 Applying bundles preserves all changeset contents including
883 permissions, copy/rename information, and revision history.
883 permissions, copy/rename information, and revision history.
884
884
885 Returns 0 on success, 1 if no changes found.
885 Returns 0 on success, 1 if no changes found.
886 """
886 """
887 revs = None
887 revs = None
888 if 'rev' in opts:
888 if 'rev' in opts:
889 revs = scmutil.revrange(repo, opts['rev'])
889 revs = scmutil.revrange(repo, opts['rev'])
890
890
891 if opts.get('all'):
891 if opts.get('all'):
892 base = ['null']
892 base = ['null']
893 else:
893 else:
894 base = scmutil.revrange(repo, opts.get('base'))
894 base = scmutil.revrange(repo, opts.get('base'))
895 if base:
895 if base:
896 if dest:
896 if dest:
897 raise util.Abort(_("--base is incompatible with specifying "
897 raise util.Abort(_("--base is incompatible with specifying "
898 "a destination"))
898 "a destination"))
899 common = [repo.lookup(rev) for rev in base]
899 common = [repo.lookup(rev) for rev in base]
900 heads = revs and map(repo.lookup, revs) or revs
900 heads = revs and map(repo.lookup, revs) or revs
901 else:
901 else:
902 dest = ui.expandpath(dest or 'default-push', dest or 'default')
902 dest = ui.expandpath(dest or 'default-push', dest or 'default')
903 dest, branches = hg.parseurl(dest, opts.get('branch'))
903 dest, branches = hg.parseurl(dest, opts.get('branch'))
904 other = hg.peer(repo, opts, dest)
904 other = hg.peer(repo, opts, dest)
905 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
905 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
906 heads = revs and map(repo.lookup, revs) or revs
906 heads = revs and map(repo.lookup, revs) or revs
907 common, outheads = discovery.findcommonoutgoing(repo, other,
907 common, outheads = discovery.findcommonoutgoing(repo, other,
908 onlyheads=heads,
908 onlyheads=heads,
909 force=opts.get('force'))
909 force=opts.get('force'))
910
910
911 cg = repo.getbundle('bundle', common=common, heads=heads)
911 cg = repo.getbundle('bundle', common=common, heads=heads)
912 if not cg:
912 if not cg:
913 ui.status(_("no changes found\n"))
913 ui.status(_("no changes found\n"))
914 return 1
914 return 1
915
915
916 bundletype = opts.get('type', 'bzip2').lower()
916 bundletype = opts.get('type', 'bzip2').lower()
917 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
917 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
918 bundletype = btypes.get(bundletype)
918 bundletype = btypes.get(bundletype)
919 if bundletype not in changegroup.bundletypes:
919 if bundletype not in changegroup.bundletypes:
920 raise util.Abort(_('unknown bundle type specified with --type'))
920 raise util.Abort(_('unknown bundle type specified with --type'))
921
921
922 changegroup.writebundle(cg, fname, bundletype)
922 changegroup.writebundle(cg, fname, bundletype)
923
923
924 @command('cat',
924 @command('cat',
925 [('o', 'output', '',
925 [('o', 'output', '',
926 _('print output to file with formatted name'), _('FORMAT')),
926 _('print output to file with formatted name'), _('FORMAT')),
927 ('r', 'rev', '', _('print the given revision'), _('REV')),
927 ('r', 'rev', '', _('print the given revision'), _('REV')),
928 ('', 'decode', None, _('apply any matching decode filter')),
928 ('', 'decode', None, _('apply any matching decode filter')),
929 ] + walkopts,
929 ] + walkopts,
930 _('[OPTION]... FILE...'))
930 _('[OPTION]... FILE...'))
931 def cat(ui, repo, file1, *pats, **opts):
931 def cat(ui, repo, file1, *pats, **opts):
932 """output the current or given revision of files
932 """output the current or given revision of files
933
933
934 Print the specified files as they were at the given revision. If
934 Print the specified files as they were at the given revision. If
935 no revision is given, the parent of the working directory is used,
935 no revision is given, the parent of the working directory is used,
936 or tip if no revision is checked out.
936 or tip if no revision is checked out.
937
937
938 Output may be to a file, in which case the name of the file is
938 Output may be to a file, in which case the name of the file is
939 given using a format string. The formatting rules are the same as
939 given using a format string. The formatting rules are the same as
940 for the export command, with the following additions:
940 for the export command, with the following additions:
941
941
942 :``%s``: basename of file being printed
942 :``%s``: basename of file being printed
943 :``%d``: dirname of file being printed, or '.' if in repository root
943 :``%d``: dirname of file being printed, or '.' if in repository root
944 :``%p``: root-relative path name of file being printed
944 :``%p``: root-relative path name of file being printed
945
945
946 Returns 0 on success.
946 Returns 0 on success.
947 """
947 """
948 ctx = scmutil.revsingle(repo, opts.get('rev'))
948 ctx = scmutil.revsingle(repo, opts.get('rev'))
949 err = 1
949 err = 1
950 m = scmutil.match(ctx, (file1,) + pats, opts)
950 m = scmutil.match(ctx, (file1,) + pats, opts)
951 for abs in ctx.walk(m):
951 for abs in ctx.walk(m):
952 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
952 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
953 pathname=abs)
953 pathname=abs)
954 data = ctx[abs].data()
954 data = ctx[abs].data()
955 if opts.get('decode'):
955 if opts.get('decode'):
956 data = repo.wwritedata(abs, data)
956 data = repo.wwritedata(abs, data)
957 fp.write(data)
957 fp.write(data)
958 fp.close()
958 fp.close()
959 err = 0
959 err = 0
960 return err
960 return err
961
961
962 @command('^clone',
962 @command('^clone',
963 [('U', 'noupdate', None,
963 [('U', 'noupdate', None,
964 _('the clone will include an empty working copy (only a repository)')),
964 _('the clone will include an empty working copy (only a repository)')),
965 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
965 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
966 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
966 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
967 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
967 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
968 ('', 'pull', None, _('use pull protocol to copy metadata')),
968 ('', 'pull', None, _('use pull protocol to copy metadata')),
969 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
969 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
970 ] + remoteopts,
970 ] + remoteopts,
971 _('[OPTION]... SOURCE [DEST]'))
971 _('[OPTION]... SOURCE [DEST]'))
972 def clone(ui, source, dest=None, **opts):
972 def clone(ui, source, dest=None, **opts):
973 """make a copy of an existing repository
973 """make a copy of an existing repository
974
974
975 Create a copy of an existing repository in a new directory.
975 Create a copy of an existing repository in a new directory.
976
976
977 If no destination directory name is specified, it defaults to the
977 If no destination directory name is specified, it defaults to the
978 basename of the source.
978 basename of the source.
979
979
980 The location of the source is added to the new repository's
980 The location of the source is added to the new repository's
981 ``.hg/hgrc`` file, as the default to be used for future pulls.
981 ``.hg/hgrc`` file, as the default to be used for future pulls.
982
982
983 See :hg:`help urls` for valid source format details.
983 See :hg:`help urls` for valid source format details.
984
984
985 It is possible to specify an ``ssh://`` URL as the destination, but no
985 It is possible to specify an ``ssh://`` URL as the destination, but no
986 ``.hg/hgrc`` and working directory will be created on the remote side.
986 ``.hg/hgrc`` and working directory will be created on the remote side.
987 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
987 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
988
988
989 A set of changesets (tags, or branch names) to pull may be specified
989 A set of changesets (tags, or branch names) to pull may be specified
990 by listing each changeset (tag, or branch name) with -r/--rev.
990 by listing each changeset (tag, or branch name) with -r/--rev.
991 If -r/--rev is used, the cloned repository will contain only a subset
991 If -r/--rev is used, the cloned repository will contain only a subset
992 of the changesets of the source repository. Only the set of changesets
992 of the changesets of the source repository. Only the set of changesets
993 defined by all -r/--rev options (including all their ancestors)
993 defined by all -r/--rev options (including all their ancestors)
994 will be pulled into the destination repository.
994 will be pulled into the destination repository.
995 No subsequent changesets (including subsequent tags) will be present
995 No subsequent changesets (including subsequent tags) will be present
996 in the destination.
996 in the destination.
997
997
998 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
998 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
999 local source repositories.
999 local source repositories.
1000
1000
1001 For efficiency, hardlinks are used for cloning whenever the source
1001 For efficiency, hardlinks are used for cloning whenever the source
1002 and destination are on the same filesystem (note this applies only
1002 and destination are on the same filesystem (note this applies only
1003 to the repository data, not to the working directory). Some
1003 to the repository data, not to the working directory). Some
1004 filesystems, such as AFS, implement hardlinking incorrectly, but
1004 filesystems, such as AFS, implement hardlinking incorrectly, but
1005 do not report errors. In these cases, use the --pull option to
1005 do not report errors. In these cases, use the --pull option to
1006 avoid hardlinking.
1006 avoid hardlinking.
1007
1007
1008 In some cases, you can clone repositories and the working directory
1008 In some cases, you can clone repositories and the working directory
1009 using full hardlinks with ::
1009 using full hardlinks with ::
1010
1010
1011 $ cp -al REPO REPOCLONE
1011 $ cp -al REPO REPOCLONE
1012
1012
1013 This is the fastest way to clone, but it is not always safe. The
1013 This is the fastest way to clone, but it is not always safe. The
1014 operation is not atomic (making sure REPO is not modified during
1014 operation is not atomic (making sure REPO is not modified during
1015 the operation is up to you) and you have to make sure your editor
1015 the operation is up to you) and you have to make sure your editor
1016 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
1016 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
1017 this is not compatible with certain extensions that place their
1017 this is not compatible with certain extensions that place their
1018 metadata under the .hg directory, such as mq.
1018 metadata under the .hg directory, such as mq.
1019
1019
1020 Mercurial will update the working directory to the first applicable
1020 Mercurial will update the working directory to the first applicable
1021 revision from this list:
1021 revision from this list:
1022
1022
1023 a) null if -U or the source repository has no changesets
1023 a) null if -U or the source repository has no changesets
1024 b) if -u . and the source repository is local, the first parent of
1024 b) if -u . and the source repository is local, the first parent of
1025 the source repository's working directory
1025 the source repository's working directory
1026 c) the changeset specified with -u (if a branch name, this means the
1026 c) the changeset specified with -u (if a branch name, this means the
1027 latest head of that branch)
1027 latest head of that branch)
1028 d) the changeset specified with -r
1028 d) the changeset specified with -r
1029 e) the tipmost head specified with -b
1029 e) the tipmost head specified with -b
1030 f) the tipmost head specified with the url#branch source syntax
1030 f) the tipmost head specified with the url#branch source syntax
1031 g) the tipmost head of the default branch
1031 g) the tipmost head of the default branch
1032 h) tip
1032 h) tip
1033
1033
1034 Returns 0 on success.
1034 Returns 0 on success.
1035 """
1035 """
1036 if opts.get('noupdate') and opts.get('updaterev'):
1036 if opts.get('noupdate') and opts.get('updaterev'):
1037 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1037 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1038
1038
1039 r = hg.clone(ui, opts, source, dest,
1039 r = hg.clone(ui, opts, source, dest,
1040 pull=opts.get('pull'),
1040 pull=opts.get('pull'),
1041 stream=opts.get('uncompressed'),
1041 stream=opts.get('uncompressed'),
1042 rev=opts.get('rev'),
1042 rev=opts.get('rev'),
1043 update=opts.get('updaterev') or not opts.get('noupdate'),
1043 update=opts.get('updaterev') or not opts.get('noupdate'),
1044 branch=opts.get('branch'))
1044 branch=opts.get('branch'))
1045
1045
1046 return r is None
1046 return r is None
1047
1047
1048 @command('^commit|ci',
1048 @command('^commit|ci',
1049 [('A', 'addremove', None,
1049 [('A', 'addremove', None,
1050 _('mark new/missing files as added/removed before committing')),
1050 _('mark new/missing files as added/removed before committing')),
1051 ('', 'close-branch', None,
1051 ('', 'close-branch', None,
1052 _('mark a branch as closed, hiding it from the branch list')),
1052 _('mark a branch as closed, hiding it from the branch list')),
1053 ] + walkopts + commitopts + commitopts2,
1053 ] + walkopts + commitopts + commitopts2,
1054 _('[OPTION]... [FILE]...'))
1054 _('[OPTION]... [FILE]...'))
1055 def commit(ui, repo, *pats, **opts):
1055 def commit(ui, repo, *pats, **opts):
1056 """commit the specified files or all outstanding changes
1056 """commit the specified files or all outstanding changes
1057
1057
1058 Commit changes to the given files into the repository. Unlike a
1058 Commit changes to the given files into the repository. Unlike a
1059 centralized SCM, this operation is a local operation. See
1059 centralized SCM, this operation is a local operation. See
1060 :hg:`push` for a way to actively distribute your changes.
1060 :hg:`push` for a way to actively distribute your changes.
1061
1061
1062 If a list of files is omitted, all changes reported by :hg:`status`
1062 If a list of files is omitted, all changes reported by :hg:`status`
1063 will be committed.
1063 will be committed.
1064
1064
1065 If you are committing the result of a merge, do not provide any
1065 If you are committing the result of a merge, do not provide any
1066 filenames or -I/-X filters.
1066 filenames or -I/-X filters.
1067
1067
1068 If no commit message is specified, Mercurial starts your
1068 If no commit message is specified, Mercurial starts your
1069 configured editor where you can enter a message. In case your
1069 configured editor where you can enter a message. In case your
1070 commit fails, you will find a backup of your message in
1070 commit fails, you will find a backup of your message in
1071 ``.hg/last-message.txt``.
1071 ``.hg/last-message.txt``.
1072
1072
1073 See :hg:`help dates` for a list of formats valid for -d/--date.
1073 See :hg:`help dates` for a list of formats valid for -d/--date.
1074
1074
1075 Returns 0 on success, 1 if nothing changed.
1075 Returns 0 on success, 1 if nothing changed.
1076 """
1076 """
1077 extra = {}
1077 extra = {}
1078 if opts.get('close_branch'):
1078 if opts.get('close_branch'):
1079 if repo['.'].node() not in repo.branchheads():
1079 if repo['.'].node() not in repo.branchheads():
1080 # The topo heads set is included in the branch heads set of the
1080 # The topo heads set is included in the branch heads set of the
1081 # current branch, so it's sufficient to test branchheads
1081 # current branch, so it's sufficient to test branchheads
1082 raise util.Abort(_('can only close branch heads'))
1082 raise util.Abort(_('can only close branch heads'))
1083 extra['close'] = 1
1083 extra['close'] = 1
1084 e = cmdutil.commiteditor
1084 e = cmdutil.commiteditor
1085 if opts.get('force_editor'):
1085 if opts.get('force_editor'):
1086 e = cmdutil.commitforceeditor
1086 e = cmdutil.commitforceeditor
1087
1087
1088 def commitfunc(ui, repo, message, match, opts):
1088 def commitfunc(ui, repo, message, match, opts):
1089 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1089 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1090 editor=e, extra=extra)
1090 editor=e, extra=extra)
1091
1091
1092 branch = repo[None].branch()
1092 branch = repo[None].branch()
1093 bheads = repo.branchheads(branch)
1093 bheads = repo.branchheads(branch)
1094
1094
1095 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1095 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1096 if not node:
1096 if not node:
1097 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1097 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1098 if stat[3]:
1098 if stat[3]:
1099 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1099 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1100 % len(stat[3]))
1100 % len(stat[3]))
1101 else:
1101 else:
1102 ui.status(_("nothing changed\n"))
1102 ui.status(_("nothing changed\n"))
1103 return 1
1103 return 1
1104
1104
1105 ctx = repo[node]
1105 ctx = repo[node]
1106 parents = ctx.parents()
1106 parents = ctx.parents()
1107
1107
1108 if (bheads and node not in bheads and not
1108 if (bheads and node not in bheads and not
1109 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1109 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1110 ui.status(_('created new head\n'))
1110 ui.status(_('created new head\n'))
1111 # The message is not printed for initial roots. For the other
1111 # The message is not printed for initial roots. For the other
1112 # changesets, it is printed in the following situations:
1112 # changesets, it is printed in the following situations:
1113 #
1113 #
1114 # Par column: for the 2 parents with ...
1114 # Par column: for the 2 parents with ...
1115 # N: null or no parent
1115 # N: null or no parent
1116 # B: parent is on another named branch
1116 # B: parent is on another named branch
1117 # C: parent is a regular non head changeset
1117 # C: parent is a regular non head changeset
1118 # H: parent was a branch head of the current branch
1118 # H: parent was a branch head of the current branch
1119 # Msg column: whether we print "created new head" message
1119 # Msg column: whether we print "created new head" message
1120 # In the following, it is assumed that there already exists some
1120 # In the following, it is assumed that there already exists some
1121 # initial branch heads of the current branch, otherwise nothing is
1121 # initial branch heads of the current branch, otherwise nothing is
1122 # printed anyway.
1122 # printed anyway.
1123 #
1123 #
1124 # Par Msg Comment
1124 # Par Msg Comment
1125 # NN y additional topo root
1125 # NN y additional topo root
1126 #
1126 #
1127 # BN y additional branch root
1127 # BN y additional branch root
1128 # CN y additional topo head
1128 # CN y additional topo head
1129 # HN n usual case
1129 # HN n usual case
1130 #
1130 #
1131 # BB y weird additional branch root
1131 # BB y weird additional branch root
1132 # CB y branch merge
1132 # CB y branch merge
1133 # HB n merge with named branch
1133 # HB n merge with named branch
1134 #
1134 #
1135 # CC y additional head from merge
1135 # CC y additional head from merge
1136 # CH n merge with a head
1136 # CH n merge with a head
1137 #
1137 #
1138 # HH n head merge: head count decreases
1138 # HH n head merge: head count decreases
1139
1139
1140 if not opts.get('close_branch'):
1140 if not opts.get('close_branch'):
1141 for r in parents:
1141 for r in parents:
1142 if r.extra().get('close') and r.branch() == branch:
1142 if r.extra().get('close') and r.branch() == branch:
1143 ui.status(_('reopening closed branch head %d\n') % r)
1143 ui.status(_('reopening closed branch head %d\n') % r)
1144
1144
1145 if ui.debugflag:
1145 if ui.debugflag:
1146 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1146 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1147 elif ui.verbose:
1147 elif ui.verbose:
1148 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1148 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1149
1149
1150 @command('copy|cp',
1150 @command('copy|cp',
1151 [('A', 'after', None, _('record a copy that has already occurred')),
1151 [('A', 'after', None, _('record a copy that has already occurred')),
1152 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1152 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1153 ] + walkopts + dryrunopts,
1153 ] + walkopts + dryrunopts,
1154 _('[OPTION]... [SOURCE]... DEST'))
1154 _('[OPTION]... [SOURCE]... DEST'))
1155 def copy(ui, repo, *pats, **opts):
1155 def copy(ui, repo, *pats, **opts):
1156 """mark files as copied for the next commit
1156 """mark files as copied for the next commit
1157
1157
1158 Mark dest as having copies of source files. If dest is a
1158 Mark dest as having copies of source files. If dest is a
1159 directory, copies are put in that directory. If dest is a file,
1159 directory, copies are put in that directory. If dest is a file,
1160 the source must be a single file.
1160 the source must be a single file.
1161
1161
1162 By default, this command copies the contents of files as they
1162 By default, this command copies the contents of files as they
1163 exist in the working directory. If invoked with -A/--after, the
1163 exist in the working directory. If invoked with -A/--after, the
1164 operation is recorded, but no copying is performed.
1164 operation is recorded, but no copying is performed.
1165
1165
1166 This command takes effect with the next commit. To undo a copy
1166 This command takes effect with the next commit. To undo a copy
1167 before that, see :hg:`revert`.
1167 before that, see :hg:`revert`.
1168
1168
1169 Returns 0 on success, 1 if errors are encountered.
1169 Returns 0 on success, 1 if errors are encountered.
1170 """
1170 """
1171 wlock = repo.wlock(False)
1171 wlock = repo.wlock(False)
1172 try:
1172 try:
1173 return cmdutil.copy(ui, repo, pats, opts)
1173 return cmdutil.copy(ui, repo, pats, opts)
1174 finally:
1174 finally:
1175 wlock.release()
1175 wlock.release()
1176
1176
1177 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1177 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1178 def debugancestor(ui, repo, *args):
1178 def debugancestor(ui, repo, *args):
1179 """find the ancestor revision of two revisions in a given index"""
1179 """find the ancestor revision of two revisions in a given index"""
1180 if len(args) == 3:
1180 if len(args) == 3:
1181 index, rev1, rev2 = args
1181 index, rev1, rev2 = args
1182 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1182 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1183 lookup = r.lookup
1183 lookup = r.lookup
1184 elif len(args) == 2:
1184 elif len(args) == 2:
1185 if not repo:
1185 if not repo:
1186 raise util.Abort(_("there is no Mercurial repository here "
1186 raise util.Abort(_("there is no Mercurial repository here "
1187 "(.hg not found)"))
1187 "(.hg not found)"))
1188 rev1, rev2 = args
1188 rev1, rev2 = args
1189 r = repo.changelog
1189 r = repo.changelog
1190 lookup = repo.lookup
1190 lookup = repo.lookup
1191 else:
1191 else:
1192 raise util.Abort(_('either two or three arguments required'))
1192 raise util.Abort(_('either two or three arguments required'))
1193 a = r.ancestor(lookup(rev1), lookup(rev2))
1193 a = r.ancestor(lookup(rev1), lookup(rev2))
1194 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1194 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1195
1195
1196 @command('debugbuilddag',
1196 @command('debugbuilddag',
1197 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1197 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1198 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1198 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1199 ('n', 'new-file', None, _('add new file at each rev'))],
1199 ('n', 'new-file', None, _('add new file at each rev'))],
1200 _('[OPTION]... [TEXT]'))
1200 _('[OPTION]... [TEXT]'))
1201 def debugbuilddag(ui, repo, text=None,
1201 def debugbuilddag(ui, repo, text=None,
1202 mergeable_file=False,
1202 mergeable_file=False,
1203 overwritten_file=False,
1203 overwritten_file=False,
1204 new_file=False):
1204 new_file=False):
1205 """builds a repo with a given DAG from scratch in the current empty repo
1205 """builds a repo with a given DAG from scratch in the current empty repo
1206
1206
1207 The description of the DAG is read from stdin if not given on the
1207 The description of the DAG is read from stdin if not given on the
1208 command line.
1208 command line.
1209
1209
1210 Elements:
1210 Elements:
1211
1211
1212 - "+n" is a linear run of n nodes based on the current default parent
1212 - "+n" is a linear run of n nodes based on the current default parent
1213 - "." is a single node based on the current default parent
1213 - "." is a single node based on the current default parent
1214 - "$" resets the default parent to null (implied at the start);
1214 - "$" resets the default parent to null (implied at the start);
1215 otherwise the default parent is always the last node created
1215 otherwise the default parent is always the last node created
1216 - "<p" sets the default parent to the backref p
1216 - "<p" sets the default parent to the backref p
1217 - "*p" is a fork at parent p, which is a backref
1217 - "*p" is a fork at parent p, which is a backref
1218 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1218 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1219 - "/p2" is a merge of the preceding node and p2
1219 - "/p2" is a merge of the preceding node and p2
1220 - ":tag" defines a local tag for the preceding node
1220 - ":tag" defines a local tag for the preceding node
1221 - "@branch" sets the named branch for subsequent nodes
1221 - "@branch" sets the named branch for subsequent nodes
1222 - "#...\\n" is a comment up to the end of the line
1222 - "#...\\n" is a comment up to the end of the line
1223
1223
1224 Whitespace between the above elements is ignored.
1224 Whitespace between the above elements is ignored.
1225
1225
1226 A backref is either
1226 A backref is either
1227
1227
1228 - a number n, which references the node curr-n, where curr is the current
1228 - a number n, which references the node curr-n, where curr is the current
1229 node, or
1229 node, or
1230 - the name of a local tag you placed earlier using ":tag", or
1230 - the name of a local tag you placed earlier using ":tag", or
1231 - empty to denote the default parent.
1231 - empty to denote the default parent.
1232
1232
1233 All string valued-elements are either strictly alphanumeric, or must
1233 All string valued-elements are either strictly alphanumeric, or must
1234 be enclosed in double quotes ("..."), with "\\" as escape character.
1234 be enclosed in double quotes ("..."), with "\\" as escape character.
1235 """
1235 """
1236
1236
1237 if text is None:
1237 if text is None:
1238 ui.status(_("reading DAG from stdin\n"))
1238 ui.status(_("reading DAG from stdin\n"))
1239 text = ui.fin.read()
1239 text = ui.fin.read()
1240
1240
1241 cl = repo.changelog
1241 cl = repo.changelog
1242 if len(cl) > 0:
1242 if len(cl) > 0:
1243 raise util.Abort(_('repository is not empty'))
1243 raise util.Abort(_('repository is not empty'))
1244
1244
1245 # determine number of revs in DAG
1245 # determine number of revs in DAG
1246 total = 0
1246 total = 0
1247 for type, data in dagparser.parsedag(text):
1247 for type, data in dagparser.parsedag(text):
1248 if type == 'n':
1248 if type == 'n':
1249 total += 1
1249 total += 1
1250
1250
1251 if mergeable_file:
1251 if mergeable_file:
1252 linesperrev = 2
1252 linesperrev = 2
1253 # make a file with k lines per rev
1253 # make a file with k lines per rev
1254 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1254 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1255 initialmergedlines.append("")
1255 initialmergedlines.append("")
1256
1256
1257 tags = []
1257 tags = []
1258
1258
1259 tr = repo.transaction("builddag")
1259 tr = repo.transaction("builddag")
1260 try:
1260 try:
1261
1261
1262 at = -1
1262 at = -1
1263 atbranch = 'default'
1263 atbranch = 'default'
1264 nodeids = []
1264 nodeids = []
1265 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1265 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1266 for type, data in dagparser.parsedag(text):
1266 for type, data in dagparser.parsedag(text):
1267 if type == 'n':
1267 if type == 'n':
1268 ui.note('node %s\n' % str(data))
1268 ui.note('node %s\n' % str(data))
1269 id, ps = data
1269 id, ps = data
1270
1270
1271 files = []
1271 files = []
1272 fctxs = {}
1272 fctxs = {}
1273
1273
1274 p2 = None
1274 p2 = None
1275 if mergeable_file:
1275 if mergeable_file:
1276 fn = "mf"
1276 fn = "mf"
1277 p1 = repo[ps[0]]
1277 p1 = repo[ps[0]]
1278 if len(ps) > 1:
1278 if len(ps) > 1:
1279 p2 = repo[ps[1]]
1279 p2 = repo[ps[1]]
1280 pa = p1.ancestor(p2)
1280 pa = p1.ancestor(p2)
1281 base, local, other = [x[fn].data() for x in pa, p1, p2]
1281 base, local, other = [x[fn].data() for x in pa, p1, p2]
1282 m3 = simplemerge.Merge3Text(base, local, other)
1282 m3 = simplemerge.Merge3Text(base, local, other)
1283 ml = [l.strip() for l in m3.merge_lines()]
1283 ml = [l.strip() for l in m3.merge_lines()]
1284 ml.append("")
1284 ml.append("")
1285 elif at > 0:
1285 elif at > 0:
1286 ml = p1[fn].data().split("\n")
1286 ml = p1[fn].data().split("\n")
1287 else:
1287 else:
1288 ml = initialmergedlines
1288 ml = initialmergedlines
1289 ml[id * linesperrev] += " r%i" % id
1289 ml[id * linesperrev] += " r%i" % id
1290 mergedtext = "\n".join(ml)
1290 mergedtext = "\n".join(ml)
1291 files.append(fn)
1291 files.append(fn)
1292 fctxs[fn] = context.memfilectx(fn, mergedtext)
1292 fctxs[fn] = context.memfilectx(fn, mergedtext)
1293
1293
1294 if overwritten_file:
1294 if overwritten_file:
1295 fn = "of"
1295 fn = "of"
1296 files.append(fn)
1296 files.append(fn)
1297 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1297 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1298
1298
1299 if new_file:
1299 if new_file:
1300 fn = "nf%i" % id
1300 fn = "nf%i" % id
1301 files.append(fn)
1301 files.append(fn)
1302 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1302 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1303 if len(ps) > 1:
1303 if len(ps) > 1:
1304 if not p2:
1304 if not p2:
1305 p2 = repo[ps[1]]
1305 p2 = repo[ps[1]]
1306 for fn in p2:
1306 for fn in p2:
1307 if fn.startswith("nf"):
1307 if fn.startswith("nf"):
1308 files.append(fn)
1308 files.append(fn)
1309 fctxs[fn] = p2[fn]
1309 fctxs[fn] = p2[fn]
1310
1310
1311 def fctxfn(repo, cx, path):
1311 def fctxfn(repo, cx, path):
1312 return fctxs.get(path)
1312 return fctxs.get(path)
1313
1313
1314 if len(ps) == 0 or ps[0] < 0:
1314 if len(ps) == 0 or ps[0] < 0:
1315 pars = [None, None]
1315 pars = [None, None]
1316 elif len(ps) == 1:
1316 elif len(ps) == 1:
1317 pars = [nodeids[ps[0]], None]
1317 pars = [nodeids[ps[0]], None]
1318 else:
1318 else:
1319 pars = [nodeids[p] for p in ps]
1319 pars = [nodeids[p] for p in ps]
1320 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1320 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1321 date=(id, 0),
1321 date=(id, 0),
1322 user="debugbuilddag",
1322 user="debugbuilddag",
1323 extra={'branch': atbranch})
1323 extra={'branch': atbranch})
1324 nodeid = repo.commitctx(cx)
1324 nodeid = repo.commitctx(cx)
1325 nodeids.append(nodeid)
1325 nodeids.append(nodeid)
1326 at = id
1326 at = id
1327 elif type == 'l':
1327 elif type == 'l':
1328 id, name = data
1328 id, name = data
1329 ui.note('tag %s\n' % name)
1329 ui.note('tag %s\n' % name)
1330 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1330 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1331 elif type == 'a':
1331 elif type == 'a':
1332 ui.note('branch %s\n' % data)
1332 ui.note('branch %s\n' % data)
1333 atbranch = data
1333 atbranch = data
1334 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1334 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1335 tr.close()
1335 tr.close()
1336 finally:
1336 finally:
1337 ui.progress(_('building'), None)
1337 ui.progress(_('building'), None)
1338 tr.release()
1338 tr.release()
1339
1339
1340 if tags:
1340 if tags:
1341 repo.opener.write("localtags", "".join(tags))
1341 repo.opener.write("localtags", "".join(tags))
1342
1342
1343 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1343 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1344 def debugbundle(ui, bundlepath, all=None, **opts):
1344 def debugbundle(ui, bundlepath, all=None, **opts):
1345 """lists the contents of a bundle"""
1345 """lists the contents of a bundle"""
1346 f = url.open(ui, bundlepath)
1346 f = url.open(ui, bundlepath)
1347 try:
1347 try:
1348 gen = changegroup.readbundle(f, bundlepath)
1348 gen = changegroup.readbundle(f, bundlepath)
1349 if all:
1349 if all:
1350 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1350 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1351
1351
1352 def showchunks(named):
1352 def showchunks(named):
1353 ui.write("\n%s\n" % named)
1353 ui.write("\n%s\n" % named)
1354 chain = None
1354 chain = None
1355 while True:
1355 while True:
1356 chunkdata = gen.deltachunk(chain)
1356 chunkdata = gen.deltachunk(chain)
1357 if not chunkdata:
1357 if not chunkdata:
1358 break
1358 break
1359 node = chunkdata['node']
1359 node = chunkdata['node']
1360 p1 = chunkdata['p1']
1360 p1 = chunkdata['p1']
1361 p2 = chunkdata['p2']
1361 p2 = chunkdata['p2']
1362 cs = chunkdata['cs']
1362 cs = chunkdata['cs']
1363 deltabase = chunkdata['deltabase']
1363 deltabase = chunkdata['deltabase']
1364 delta = chunkdata['delta']
1364 delta = chunkdata['delta']
1365 ui.write("%s %s %s %s %s %s\n" %
1365 ui.write("%s %s %s %s %s %s\n" %
1366 (hex(node), hex(p1), hex(p2),
1366 (hex(node), hex(p1), hex(p2),
1367 hex(cs), hex(deltabase), len(delta)))
1367 hex(cs), hex(deltabase), len(delta)))
1368 chain = node
1368 chain = node
1369
1369
1370 chunkdata = gen.changelogheader()
1370 chunkdata = gen.changelogheader()
1371 showchunks("changelog")
1371 showchunks("changelog")
1372 chunkdata = gen.manifestheader()
1372 chunkdata = gen.manifestheader()
1373 showchunks("manifest")
1373 showchunks("manifest")
1374 while True:
1374 while True:
1375 chunkdata = gen.filelogheader()
1375 chunkdata = gen.filelogheader()
1376 if not chunkdata:
1376 if not chunkdata:
1377 break
1377 break
1378 fname = chunkdata['filename']
1378 fname = chunkdata['filename']
1379 showchunks(fname)
1379 showchunks(fname)
1380 else:
1380 else:
1381 chunkdata = gen.changelogheader()
1381 chunkdata = gen.changelogheader()
1382 chain = None
1382 chain = None
1383 while True:
1383 while True:
1384 chunkdata = gen.deltachunk(chain)
1384 chunkdata = gen.deltachunk(chain)
1385 if not chunkdata:
1385 if not chunkdata:
1386 break
1386 break
1387 node = chunkdata['node']
1387 node = chunkdata['node']
1388 ui.write("%s\n" % hex(node))
1388 ui.write("%s\n" % hex(node))
1389 chain = node
1389 chain = node
1390 finally:
1390 finally:
1391 f.close()
1391 f.close()
1392
1392
1393 @command('debugcheckstate', [], '')
1393 @command('debugcheckstate', [], '')
1394 def debugcheckstate(ui, repo):
1394 def debugcheckstate(ui, repo):
1395 """validate the correctness of the current dirstate"""
1395 """validate the correctness of the current dirstate"""
1396 parent1, parent2 = repo.dirstate.parents()
1396 parent1, parent2 = repo.dirstate.parents()
1397 m1 = repo[parent1].manifest()
1397 m1 = repo[parent1].manifest()
1398 m2 = repo[parent2].manifest()
1398 m2 = repo[parent2].manifest()
1399 errors = 0
1399 errors = 0
1400 for f in repo.dirstate:
1400 for f in repo.dirstate:
1401 state = repo.dirstate[f]
1401 state = repo.dirstate[f]
1402 if state in "nr" and f not in m1:
1402 if state in "nr" and f not in m1:
1403 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1403 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1404 errors += 1
1404 errors += 1
1405 if state in "a" and f in m1:
1405 if state in "a" and f in m1:
1406 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1406 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1407 errors += 1
1407 errors += 1
1408 if state in "m" and f not in m1 and f not in m2:
1408 if state in "m" and f not in m1 and f not in m2:
1409 ui.warn(_("%s in state %s, but not in either manifest\n") %
1409 ui.warn(_("%s in state %s, but not in either manifest\n") %
1410 (f, state))
1410 (f, state))
1411 errors += 1
1411 errors += 1
1412 for f in m1:
1412 for f in m1:
1413 state = repo.dirstate[f]
1413 state = repo.dirstate[f]
1414 if state not in "nrm":
1414 if state not in "nrm":
1415 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1415 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1416 errors += 1
1416 errors += 1
1417 if errors:
1417 if errors:
1418 error = _(".hg/dirstate inconsistent with current parent's manifest")
1418 error = _(".hg/dirstate inconsistent with current parent's manifest")
1419 raise util.Abort(error)
1419 raise util.Abort(error)
1420
1420
1421 @command('debugcommands', [], _('[COMMAND]'))
1421 @command('debugcommands', [], _('[COMMAND]'))
1422 def debugcommands(ui, cmd='', *args):
1422 def debugcommands(ui, cmd='', *args):
1423 """list all available commands and options"""
1423 """list all available commands and options"""
1424 for cmd, vals in sorted(table.iteritems()):
1424 for cmd, vals in sorted(table.iteritems()):
1425 cmd = cmd.split('|')[0].strip('^')
1425 cmd = cmd.split('|')[0].strip('^')
1426 opts = ', '.join([i[1] for i in vals[1]])
1426 opts = ', '.join([i[1] for i in vals[1]])
1427 ui.write('%s: %s\n' % (cmd, opts))
1427 ui.write('%s: %s\n' % (cmd, opts))
1428
1428
1429 @command('debugcomplete',
1429 @command('debugcomplete',
1430 [('o', 'options', None, _('show the command options'))],
1430 [('o', 'options', None, _('show the command options'))],
1431 _('[-o] CMD'))
1431 _('[-o] CMD'))
1432 def debugcomplete(ui, cmd='', **opts):
1432 def debugcomplete(ui, cmd='', **opts):
1433 """returns the completion list associated with the given command"""
1433 """returns the completion list associated with the given command"""
1434
1434
1435 if opts.get('options'):
1435 if opts.get('options'):
1436 options = []
1436 options = []
1437 otables = [globalopts]
1437 otables = [globalopts]
1438 if cmd:
1438 if cmd:
1439 aliases, entry = cmdutil.findcmd(cmd, table, False)
1439 aliases, entry = cmdutil.findcmd(cmd, table, False)
1440 otables.append(entry[1])
1440 otables.append(entry[1])
1441 for t in otables:
1441 for t in otables:
1442 for o in t:
1442 for o in t:
1443 if "(DEPRECATED)" in o[3]:
1443 if "(DEPRECATED)" in o[3]:
1444 continue
1444 continue
1445 if o[0]:
1445 if o[0]:
1446 options.append('-%s' % o[0])
1446 options.append('-%s' % o[0])
1447 options.append('--%s' % o[1])
1447 options.append('--%s' % o[1])
1448 ui.write("%s\n" % "\n".join(options))
1448 ui.write("%s\n" % "\n".join(options))
1449 return
1449 return
1450
1450
1451 cmdlist = cmdutil.findpossible(cmd, table)
1451 cmdlist = cmdutil.findpossible(cmd, table)
1452 if ui.verbose:
1452 if ui.verbose:
1453 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1453 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1454 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1454 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1455
1455
1456 @command('debugdag',
1456 @command('debugdag',
1457 [('t', 'tags', None, _('use tags as labels')),
1457 [('t', 'tags', None, _('use tags as labels')),
1458 ('b', 'branches', None, _('annotate with branch names')),
1458 ('b', 'branches', None, _('annotate with branch names')),
1459 ('', 'dots', None, _('use dots for runs')),
1459 ('', 'dots', None, _('use dots for runs')),
1460 ('s', 'spaces', None, _('separate elements by spaces'))],
1460 ('s', 'spaces', None, _('separate elements by spaces'))],
1461 _('[OPTION]... [FILE [REV]...]'))
1461 _('[OPTION]... [FILE [REV]...]'))
1462 def debugdag(ui, repo, file_=None, *revs, **opts):
1462 def debugdag(ui, repo, file_=None, *revs, **opts):
1463 """format the changelog or an index DAG as a concise textual description
1463 """format the changelog or an index DAG as a concise textual description
1464
1464
1465 If you pass a revlog index, the revlog's DAG is emitted. If you list
1465 If you pass a revlog index, the revlog's DAG is emitted. If you list
1466 revision numbers, they get labelled in the output as rN.
1466 revision numbers, they get labelled in the output as rN.
1467
1467
1468 Otherwise, the changelog DAG of the current repo is emitted.
1468 Otherwise, the changelog DAG of the current repo is emitted.
1469 """
1469 """
1470 spaces = opts.get('spaces')
1470 spaces = opts.get('spaces')
1471 dots = opts.get('dots')
1471 dots = opts.get('dots')
1472 if file_:
1472 if file_:
1473 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1473 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1474 revs = set((int(r) for r in revs))
1474 revs = set((int(r) for r in revs))
1475 def events():
1475 def events():
1476 for r in rlog:
1476 for r in rlog:
1477 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1477 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1478 if r in revs:
1478 if r in revs:
1479 yield 'l', (r, "r%i" % r)
1479 yield 'l', (r, "r%i" % r)
1480 elif repo:
1480 elif repo:
1481 cl = repo.changelog
1481 cl = repo.changelog
1482 tags = opts.get('tags')
1482 tags = opts.get('tags')
1483 branches = opts.get('branches')
1483 branches = opts.get('branches')
1484 if tags:
1484 if tags:
1485 labels = {}
1485 labels = {}
1486 for l, n in repo.tags().items():
1486 for l, n in repo.tags().items():
1487 labels.setdefault(cl.rev(n), []).append(l)
1487 labels.setdefault(cl.rev(n), []).append(l)
1488 def events():
1488 def events():
1489 b = "default"
1489 b = "default"
1490 for r in cl:
1490 for r in cl:
1491 if branches:
1491 if branches:
1492 newb = cl.read(cl.node(r))[5]['branch']
1492 newb = cl.read(cl.node(r))[5]['branch']
1493 if newb != b:
1493 if newb != b:
1494 yield 'a', newb
1494 yield 'a', newb
1495 b = newb
1495 b = newb
1496 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1496 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1497 if tags:
1497 if tags:
1498 ls = labels.get(r)
1498 ls = labels.get(r)
1499 if ls:
1499 if ls:
1500 for l in ls:
1500 for l in ls:
1501 yield 'l', (r, l)
1501 yield 'l', (r, l)
1502 else:
1502 else:
1503 raise util.Abort(_('need repo for changelog dag'))
1503 raise util.Abort(_('need repo for changelog dag'))
1504
1504
1505 for line in dagparser.dagtextlines(events(),
1505 for line in dagparser.dagtextlines(events(),
1506 addspaces=spaces,
1506 addspaces=spaces,
1507 wraplabels=True,
1507 wraplabels=True,
1508 wrapannotations=True,
1508 wrapannotations=True,
1509 wrapnonlinear=dots,
1509 wrapnonlinear=dots,
1510 usedots=dots,
1510 usedots=dots,
1511 maxlinewidth=70):
1511 maxlinewidth=70):
1512 ui.write(line)
1512 ui.write(line)
1513 ui.write("\n")
1513 ui.write("\n")
1514
1514
1515 @command('debugdata',
1515 @command('debugdata',
1516 [('c', 'changelog', False, _('open changelog')),
1516 [('c', 'changelog', False, _('open changelog')),
1517 ('m', 'manifest', False, _('open manifest'))],
1517 ('m', 'manifest', False, _('open manifest'))],
1518 _('-c|-m|FILE REV'))
1518 _('-c|-m|FILE REV'))
1519 def debugdata(ui, repo, file_, rev = None, **opts):
1519 def debugdata(ui, repo, file_, rev = None, **opts):
1520 """dump the contents of a data file revision"""
1520 """dump the contents of a data file revision"""
1521 if opts.get('changelog') or opts.get('manifest'):
1521 if opts.get('changelog') or opts.get('manifest'):
1522 file_, rev = None, file_
1522 file_, rev = None, file_
1523 elif rev is None:
1523 elif rev is None:
1524 raise error.CommandError('debugdata', _('invalid arguments'))
1524 raise error.CommandError('debugdata', _('invalid arguments'))
1525 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1525 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1526 try:
1526 try:
1527 ui.write(r.revision(r.lookup(rev)))
1527 ui.write(r.revision(r.lookup(rev)))
1528 except KeyError:
1528 except KeyError:
1529 raise util.Abort(_('invalid revision identifier %s') % rev)
1529 raise util.Abort(_('invalid revision identifier %s') % rev)
1530
1530
1531 @command('debugdate',
1531 @command('debugdate',
1532 [('e', 'extended', None, _('try extended date formats'))],
1532 [('e', 'extended', None, _('try extended date formats'))],
1533 _('[-e] DATE [RANGE]'))
1533 _('[-e] DATE [RANGE]'))
1534 def debugdate(ui, date, range=None, **opts):
1534 def debugdate(ui, date, range=None, **opts):
1535 """parse and display a date"""
1535 """parse and display a date"""
1536 if opts["extended"]:
1536 if opts["extended"]:
1537 d = util.parsedate(date, util.extendeddateformats)
1537 d = util.parsedate(date, util.extendeddateformats)
1538 else:
1538 else:
1539 d = util.parsedate(date)
1539 d = util.parsedate(date)
1540 ui.write("internal: %s %s\n" % d)
1540 ui.write("internal: %s %s\n" % d)
1541 ui.write("standard: %s\n" % util.datestr(d))
1541 ui.write("standard: %s\n" % util.datestr(d))
1542 if range:
1542 if range:
1543 m = util.matchdate(range)
1543 m = util.matchdate(range)
1544 ui.write("match: %s\n" % m(d[0]))
1544 ui.write("match: %s\n" % m(d[0]))
1545
1545
1546 @command('debugdiscovery',
1546 @command('debugdiscovery',
1547 [('', 'old', None, _('use old-style discovery')),
1547 [('', 'old', None, _('use old-style discovery')),
1548 ('', 'nonheads', None,
1548 ('', 'nonheads', None,
1549 _('use old-style discovery with non-heads included')),
1549 _('use old-style discovery with non-heads included')),
1550 ] + remoteopts,
1550 ] + remoteopts,
1551 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1551 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1552 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1552 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1553 """runs the changeset discovery protocol in isolation"""
1553 """runs the changeset discovery protocol in isolation"""
1554 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1554 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1555 remote = hg.peer(repo, opts, remoteurl)
1555 remote = hg.peer(repo, opts, remoteurl)
1556 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1556 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1557
1557
1558 # make sure tests are repeatable
1558 # make sure tests are repeatable
1559 random.seed(12323)
1559 random.seed(12323)
1560
1560
1561 def doit(localheads, remoteheads):
1561 def doit(localheads, remoteheads):
1562 if opts.get('old'):
1562 if opts.get('old'):
1563 if localheads:
1563 if localheads:
1564 raise util.Abort('cannot use localheads with old style discovery')
1564 raise util.Abort('cannot use localheads with old style discovery')
1565 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1565 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1566 force=True)
1566 force=True)
1567 common = set(common)
1567 common = set(common)
1568 if not opts.get('nonheads'):
1568 if not opts.get('nonheads'):
1569 ui.write("unpruned common: %s\n" % " ".join([short(n)
1569 ui.write("unpruned common: %s\n" % " ".join([short(n)
1570 for n in common]))
1570 for n in common]))
1571 dag = dagutil.revlogdag(repo.changelog)
1571 dag = dagutil.revlogdag(repo.changelog)
1572 all = dag.ancestorset(dag.internalizeall(common))
1572 all = dag.ancestorset(dag.internalizeall(common))
1573 common = dag.externalizeall(dag.headsetofconnecteds(all))
1573 common = dag.externalizeall(dag.headsetofconnecteds(all))
1574 else:
1574 else:
1575 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1575 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1576 common = set(common)
1576 common = set(common)
1577 rheads = set(hds)
1577 rheads = set(hds)
1578 lheads = set(repo.heads())
1578 lheads = set(repo.heads())
1579 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1579 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1580 if lheads <= common:
1580 if lheads <= common:
1581 ui.write("local is subset\n")
1581 ui.write("local is subset\n")
1582 elif rheads <= common:
1582 elif rheads <= common:
1583 ui.write("remote is subset\n")
1583 ui.write("remote is subset\n")
1584
1584
1585 serverlogs = opts.get('serverlog')
1585 serverlogs = opts.get('serverlog')
1586 if serverlogs:
1586 if serverlogs:
1587 for filename in serverlogs:
1587 for filename in serverlogs:
1588 logfile = open(filename, 'r')
1588 logfile = open(filename, 'r')
1589 try:
1589 try:
1590 line = logfile.readline()
1590 line = logfile.readline()
1591 while line:
1591 while line:
1592 parts = line.strip().split(';')
1592 parts = line.strip().split(';')
1593 op = parts[1]
1593 op = parts[1]
1594 if op == 'cg':
1594 if op == 'cg':
1595 pass
1595 pass
1596 elif op == 'cgss':
1596 elif op == 'cgss':
1597 doit(parts[2].split(' '), parts[3].split(' '))
1597 doit(parts[2].split(' '), parts[3].split(' '))
1598 elif op == 'unb':
1598 elif op == 'unb':
1599 doit(parts[3].split(' '), parts[2].split(' '))
1599 doit(parts[3].split(' '), parts[2].split(' '))
1600 line = logfile.readline()
1600 line = logfile.readline()
1601 finally:
1601 finally:
1602 logfile.close()
1602 logfile.close()
1603
1603
1604 else:
1604 else:
1605 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1605 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1606 opts.get('remote_head'))
1606 opts.get('remote_head'))
1607 localrevs = opts.get('local_head')
1607 localrevs = opts.get('local_head')
1608 doit(localrevs, remoterevs)
1608 doit(localrevs, remoterevs)
1609
1609
1610 @command('debugfileset', [], ('REVSPEC'))
1610 @command('debugfileset', [], ('REVSPEC'))
1611 def debugfileset(ui, repo, expr):
1611 def debugfileset(ui, repo, expr):
1612 '''parse and apply a fileset specification'''
1612 '''parse and apply a fileset specification'''
1613 if ui.verbose:
1613 if ui.verbose:
1614 tree = fileset.parse(expr)[0]
1614 tree = fileset.parse(expr)[0]
1615 ui.note(tree, "\n")
1615 ui.note(tree, "\n")
1616
1616
1617 for f in fileset.getfileset(repo[None], expr):
1617 for f in fileset.getfileset(repo[None], expr):
1618 ui.write("%s\n" % f)
1618 ui.write("%s\n" % f)
1619
1619
1620 @command('debugfsinfo', [], _('[PATH]'))
1620 @command('debugfsinfo', [], _('[PATH]'))
1621 def debugfsinfo(ui, path = "."):
1621 def debugfsinfo(ui, path = "."):
1622 """show information detected about current filesystem"""
1622 """show information detected about current filesystem"""
1623 util.writefile('.debugfsinfo', '')
1623 util.writefile('.debugfsinfo', '')
1624 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1624 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1625 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1625 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1626 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1626 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1627 and 'yes' or 'no'))
1627 and 'yes' or 'no'))
1628 os.unlink('.debugfsinfo')
1628 os.unlink('.debugfsinfo')
1629
1629
1630 @command('debuggetbundle',
1630 @command('debuggetbundle',
1631 [('H', 'head', [], _('id of head node'), _('ID')),
1631 [('H', 'head', [], _('id of head node'), _('ID')),
1632 ('C', 'common', [], _('id of common node'), _('ID')),
1632 ('C', 'common', [], _('id of common node'), _('ID')),
1633 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1633 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1634 _('REPO FILE [-H|-C ID]...'))
1634 _('REPO FILE [-H|-C ID]...'))
1635 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1635 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1636 """retrieves a bundle from a repo
1636 """retrieves a bundle from a repo
1637
1637
1638 Every ID must be a full-length hex node id string. Saves the bundle to the
1638 Every ID must be a full-length hex node id string. Saves the bundle to the
1639 given file.
1639 given file.
1640 """
1640 """
1641 repo = hg.peer(ui, opts, repopath)
1641 repo = hg.peer(ui, opts, repopath)
1642 if not repo.capable('getbundle'):
1642 if not repo.capable('getbundle'):
1643 raise util.Abort("getbundle() not supported by target repository")
1643 raise util.Abort("getbundle() not supported by target repository")
1644 args = {}
1644 args = {}
1645 if common:
1645 if common:
1646 args['common'] = [bin(s) for s in common]
1646 args['common'] = [bin(s) for s in common]
1647 if head:
1647 if head:
1648 args['heads'] = [bin(s) for s in head]
1648 args['heads'] = [bin(s) for s in head]
1649 bundle = repo.getbundle('debug', **args)
1649 bundle = repo.getbundle('debug', **args)
1650
1650
1651 bundletype = opts.get('type', 'bzip2').lower()
1651 bundletype = opts.get('type', 'bzip2').lower()
1652 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1652 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1653 bundletype = btypes.get(bundletype)
1653 bundletype = btypes.get(bundletype)
1654 if bundletype not in changegroup.bundletypes:
1654 if bundletype not in changegroup.bundletypes:
1655 raise util.Abort(_('unknown bundle type specified with --type'))
1655 raise util.Abort(_('unknown bundle type specified with --type'))
1656 changegroup.writebundle(bundle, bundlepath, bundletype)
1656 changegroup.writebundle(bundle, bundlepath, bundletype)
1657
1657
1658 @command('debugignore', [], '')
1658 @command('debugignore', [], '')
1659 def debugignore(ui, repo, *values, **opts):
1659 def debugignore(ui, repo, *values, **opts):
1660 """display the combined ignore pattern"""
1660 """display the combined ignore pattern"""
1661 ignore = repo.dirstate._ignore
1661 ignore = repo.dirstate._ignore
1662 includepat = getattr(ignore, 'includepat', None)
1662 includepat = getattr(ignore, 'includepat', None)
1663 if includepat is not None:
1663 if includepat is not None:
1664 ui.write("%s\n" % includepat)
1664 ui.write("%s\n" % includepat)
1665 else:
1665 else:
1666 raise util.Abort(_("no ignore patterns found"))
1666 raise util.Abort(_("no ignore patterns found"))
1667
1667
1668 @command('debugindex',
1668 @command('debugindex',
1669 [('c', 'changelog', False, _('open changelog')),
1669 [('c', 'changelog', False, _('open changelog')),
1670 ('m', 'manifest', False, _('open manifest')),
1670 ('m', 'manifest', False, _('open manifest')),
1671 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1671 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1672 _('[-f FORMAT] -c|-m|FILE'))
1672 _('[-f FORMAT] -c|-m|FILE'))
1673 def debugindex(ui, repo, file_ = None, **opts):
1673 def debugindex(ui, repo, file_ = None, **opts):
1674 """dump the contents of an index file"""
1674 """dump the contents of an index file"""
1675 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1675 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1676 format = opts.get('format', 0)
1676 format = opts.get('format', 0)
1677 if format not in (0, 1):
1677 if format not in (0, 1):
1678 raise util.Abort(_("unknown format %d") % format)
1678 raise util.Abort(_("unknown format %d") % format)
1679
1679
1680 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1680 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1681 if generaldelta:
1681 if generaldelta:
1682 basehdr = ' delta'
1682 basehdr = ' delta'
1683 else:
1683 else:
1684 basehdr = ' base'
1684 basehdr = ' base'
1685
1685
1686 if format == 0:
1686 if format == 0:
1687 ui.write(" rev offset length " + basehdr + " linkrev"
1687 ui.write(" rev offset length " + basehdr + " linkrev"
1688 " nodeid p1 p2\n")
1688 " nodeid p1 p2\n")
1689 elif format == 1:
1689 elif format == 1:
1690 ui.write(" rev flag offset length"
1690 ui.write(" rev flag offset length"
1691 " size " + basehdr + " link p1 p2 nodeid\n")
1691 " size " + basehdr + " link p1 p2 nodeid\n")
1692
1692
1693 for i in r:
1693 for i in r:
1694 node = r.node(i)
1694 node = r.node(i)
1695 if generaldelta:
1695 if generaldelta:
1696 base = r.deltaparent(i)
1696 base = r.deltaparent(i)
1697 else:
1697 else:
1698 base = r.chainbase(i)
1698 base = r.chainbase(i)
1699 if format == 0:
1699 if format == 0:
1700 try:
1700 try:
1701 pp = r.parents(node)
1701 pp = r.parents(node)
1702 except:
1702 except:
1703 pp = [nullid, nullid]
1703 pp = [nullid, nullid]
1704 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1704 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1705 i, r.start(i), r.length(i), base, r.linkrev(i),
1705 i, r.start(i), r.length(i), base, r.linkrev(i),
1706 short(node), short(pp[0]), short(pp[1])))
1706 short(node), short(pp[0]), short(pp[1])))
1707 elif format == 1:
1707 elif format == 1:
1708 pr = r.parentrevs(i)
1708 pr = r.parentrevs(i)
1709 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1709 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1710 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1710 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1711 base, r.linkrev(i), pr[0], pr[1], short(node)))
1711 base, r.linkrev(i), pr[0], pr[1], short(node)))
1712
1712
1713 @command('debugindexdot', [], _('FILE'))
1713 @command('debugindexdot', [], _('FILE'))
1714 def debugindexdot(ui, repo, file_):
1714 def debugindexdot(ui, repo, file_):
1715 """dump an index DAG as a graphviz dot file"""
1715 """dump an index DAG as a graphviz dot file"""
1716 r = None
1716 r = None
1717 if repo:
1717 if repo:
1718 filelog = repo.file(file_)
1718 filelog = repo.file(file_)
1719 if len(filelog):
1719 if len(filelog):
1720 r = filelog
1720 r = filelog
1721 if not r:
1721 if not r:
1722 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1722 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1723 ui.write("digraph G {\n")
1723 ui.write("digraph G {\n")
1724 for i in r:
1724 for i in r:
1725 node = r.node(i)
1725 node = r.node(i)
1726 pp = r.parents(node)
1726 pp = r.parents(node)
1727 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1727 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1728 if pp[1] != nullid:
1728 if pp[1] != nullid:
1729 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1729 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1730 ui.write("}\n")
1730 ui.write("}\n")
1731
1731
1732 @command('debuginstall', [], '')
1732 @command('debuginstall', [], '')
1733 def debuginstall(ui):
1733 def debuginstall(ui):
1734 '''test Mercurial installation
1734 '''test Mercurial installation
1735
1735
1736 Returns 0 on success.
1736 Returns 0 on success.
1737 '''
1737 '''
1738
1738
1739 def writetemp(contents):
1739 def writetemp(contents):
1740 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1740 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1741 f = os.fdopen(fd, "wb")
1741 f = os.fdopen(fd, "wb")
1742 f.write(contents)
1742 f.write(contents)
1743 f.close()
1743 f.close()
1744 return name
1744 return name
1745
1745
1746 problems = 0
1746 problems = 0
1747
1747
1748 # encoding
1748 # encoding
1749 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1749 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1750 try:
1750 try:
1751 encoding.fromlocal("test")
1751 encoding.fromlocal("test")
1752 except util.Abort, inst:
1752 except util.Abort, inst:
1753 ui.write(" %s\n" % inst)
1753 ui.write(" %s\n" % inst)
1754 ui.write(_(" (check that your locale is properly set)\n"))
1754 ui.write(_(" (check that your locale is properly set)\n"))
1755 problems += 1
1755 problems += 1
1756
1756
1757 # compiled modules
1757 # compiled modules
1758 ui.status(_("Checking installed modules (%s)...\n")
1758 ui.status(_("Checking installed modules (%s)...\n")
1759 % os.path.dirname(__file__))
1759 % os.path.dirname(__file__))
1760 try:
1760 try:
1761 import bdiff, mpatch, base85, osutil
1761 import bdiff, mpatch, base85, osutil
1762 except Exception, inst:
1762 except Exception, inst:
1763 ui.write(" %s\n" % inst)
1763 ui.write(" %s\n" % inst)
1764 ui.write(_(" One or more extensions could not be found"))
1764 ui.write(_(" One or more extensions could not be found"))
1765 ui.write(_(" (check that you compiled the extensions)\n"))
1765 ui.write(_(" (check that you compiled the extensions)\n"))
1766 problems += 1
1766 problems += 1
1767
1767
1768 # templates
1768 # templates
1769 ui.status(_("Checking templates...\n"))
1769 ui.status(_("Checking templates...\n"))
1770 try:
1770 try:
1771 import templater
1771 import templater
1772 templater.templater(templater.templatepath("map-cmdline.default"))
1772 templater.templater(templater.templatepath("map-cmdline.default"))
1773 except Exception, inst:
1773 except Exception, inst:
1774 ui.write(" %s\n" % inst)
1774 ui.write(" %s\n" % inst)
1775 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1775 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1776 problems += 1
1776 problems += 1
1777
1777
1778 # editor
1778 # editor
1779 ui.status(_("Checking commit editor...\n"))
1779 ui.status(_("Checking commit editor...\n"))
1780 editor = ui.geteditor()
1780 editor = ui.geteditor()
1781 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1781 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1782 if not cmdpath:
1782 if not cmdpath:
1783 if editor == 'vi':
1783 if editor == 'vi':
1784 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1784 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1785 ui.write(_(" (specify a commit editor in your configuration"
1785 ui.write(_(" (specify a commit editor in your configuration"
1786 " file)\n"))
1786 " file)\n"))
1787 else:
1787 else:
1788 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1788 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1789 ui.write(_(" (specify a commit editor in your configuration"
1789 ui.write(_(" (specify a commit editor in your configuration"
1790 " file)\n"))
1790 " file)\n"))
1791 problems += 1
1791 problems += 1
1792
1792
1793 # check username
1793 # check username
1794 ui.status(_("Checking username...\n"))
1794 ui.status(_("Checking username...\n"))
1795 try:
1795 try:
1796 ui.username()
1796 ui.username()
1797 except util.Abort, e:
1797 except util.Abort, e:
1798 ui.write(" %s\n" % e)
1798 ui.write(" %s\n" % e)
1799 ui.write(_(" (specify a username in your configuration file)\n"))
1799 ui.write(_(" (specify a username in your configuration file)\n"))
1800 problems += 1
1800 problems += 1
1801
1801
1802 if not problems:
1802 if not problems:
1803 ui.status(_("No problems detected\n"))
1803 ui.status(_("No problems detected\n"))
1804 else:
1804 else:
1805 ui.write(_("%s problems detected,"
1805 ui.write(_("%s problems detected,"
1806 " please check your install!\n") % problems)
1806 " please check your install!\n") % problems)
1807
1807
1808 return problems
1808 return problems
1809
1809
1810 @command('debugknown', [], _('REPO ID...'))
1810 @command('debugknown', [], _('REPO ID...'))
1811 def debugknown(ui, repopath, *ids, **opts):
1811 def debugknown(ui, repopath, *ids, **opts):
1812 """test whether node ids are known to a repo
1812 """test whether node ids are known to a repo
1813
1813
1814 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1814 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1815 indicating unknown/known.
1815 indicating unknown/known.
1816 """
1816 """
1817 repo = hg.peer(ui, opts, repopath)
1817 repo = hg.peer(ui, opts, repopath)
1818 if not repo.capable('known'):
1818 if not repo.capable('known'):
1819 raise util.Abort("known() not supported by target repository")
1819 raise util.Abort("known() not supported by target repository")
1820 flags = repo.known([bin(s) for s in ids])
1820 flags = repo.known([bin(s) for s in ids])
1821 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1821 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1822
1822
1823 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1823 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1824 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1824 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1825 '''access the pushkey key/value protocol
1825 '''access the pushkey key/value protocol
1826
1826
1827 With two args, list the keys in the given namespace.
1827 With two args, list the keys in the given namespace.
1828
1828
1829 With five args, set a key to new if it currently is set to old.
1829 With five args, set a key to new if it currently is set to old.
1830 Reports success or failure.
1830 Reports success or failure.
1831 '''
1831 '''
1832
1832
1833 target = hg.peer(ui, {}, repopath)
1833 target = hg.peer(ui, {}, repopath)
1834 if keyinfo:
1834 if keyinfo:
1835 key, old, new = keyinfo
1835 key, old, new = keyinfo
1836 r = target.pushkey(namespace, key, old, new)
1836 r = target.pushkey(namespace, key, old, new)
1837 ui.status(str(r) + '\n')
1837 ui.status(str(r) + '\n')
1838 return not r
1838 return not r
1839 else:
1839 else:
1840 for k, v in target.listkeys(namespace).iteritems():
1840 for k, v in target.listkeys(namespace).iteritems():
1841 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1841 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1842 v.encode('string-escape')))
1842 v.encode('string-escape')))
1843
1843
1844 @command('debugrebuildstate',
1844 @command('debugrebuildstate',
1845 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1845 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1846 _('[-r REV] [REV]'))
1846 _('[-r REV] [REV]'))
1847 def debugrebuildstate(ui, repo, rev="tip"):
1847 def debugrebuildstate(ui, repo, rev="tip"):
1848 """rebuild the dirstate as it would look like for the given revision"""
1848 """rebuild the dirstate as it would look like for the given revision"""
1849 ctx = scmutil.revsingle(repo, rev)
1849 ctx = scmutil.revsingle(repo, rev)
1850 wlock = repo.wlock()
1850 wlock = repo.wlock()
1851 try:
1851 try:
1852 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1852 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1853 finally:
1853 finally:
1854 wlock.release()
1854 wlock.release()
1855
1855
1856 @command('debugrename',
1856 @command('debugrename',
1857 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1857 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1858 _('[-r REV] FILE'))
1858 _('[-r REV] FILE'))
1859 def debugrename(ui, repo, file1, *pats, **opts):
1859 def debugrename(ui, repo, file1, *pats, **opts):
1860 """dump rename information"""
1860 """dump rename information"""
1861
1861
1862 ctx = scmutil.revsingle(repo, opts.get('rev'))
1862 ctx = scmutil.revsingle(repo, opts.get('rev'))
1863 m = scmutil.match(ctx, (file1,) + pats, opts)
1863 m = scmutil.match(ctx, (file1,) + pats, opts)
1864 for abs in ctx.walk(m):
1864 for abs in ctx.walk(m):
1865 fctx = ctx[abs]
1865 fctx = ctx[abs]
1866 o = fctx.filelog().renamed(fctx.filenode())
1866 o = fctx.filelog().renamed(fctx.filenode())
1867 rel = m.rel(abs)
1867 rel = m.rel(abs)
1868 if o:
1868 if o:
1869 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1869 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1870 else:
1870 else:
1871 ui.write(_("%s not renamed\n") % rel)
1871 ui.write(_("%s not renamed\n") % rel)
1872
1872
1873 @command('debugrevlog',
1873 @command('debugrevlog',
1874 [('c', 'changelog', False, _('open changelog')),
1874 [('c', 'changelog', False, _('open changelog')),
1875 ('m', 'manifest', False, _('open manifest')),
1875 ('m', 'manifest', False, _('open manifest')),
1876 ('d', 'dump', False, _('dump index data'))],
1876 ('d', 'dump', False, _('dump index data'))],
1877 _('-c|-m|FILE'))
1877 _('-c|-m|FILE'))
1878 def debugrevlog(ui, repo, file_ = None, **opts):
1878 def debugrevlog(ui, repo, file_ = None, **opts):
1879 """show data and statistics about a revlog"""
1879 """show data and statistics about a revlog"""
1880 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1880 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1881
1881
1882 if opts.get("dump"):
1882 if opts.get("dump"):
1883 numrevs = len(r)
1883 numrevs = len(r)
1884 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1884 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1885 " rawsize totalsize compression heads\n")
1885 " rawsize totalsize compression heads\n")
1886 ts = 0
1886 ts = 0
1887 heads = set()
1887 heads = set()
1888 for rev in xrange(numrevs):
1888 for rev in xrange(numrevs):
1889 dbase = r.deltaparent(rev)
1889 dbase = r.deltaparent(rev)
1890 if dbase == -1:
1890 if dbase == -1:
1891 dbase = rev
1891 dbase = rev
1892 cbase = r.chainbase(rev)
1892 cbase = r.chainbase(rev)
1893 p1, p2 = r.parentrevs(rev)
1893 p1, p2 = r.parentrevs(rev)
1894 rs = r.rawsize(rev)
1894 rs = r.rawsize(rev)
1895 ts = ts + rs
1895 ts = ts + rs
1896 heads -= set(r.parentrevs(rev))
1896 heads -= set(r.parentrevs(rev))
1897 heads.add(rev)
1897 heads.add(rev)
1898 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1898 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1899 (rev, p1, p2, r.start(rev), r.end(rev),
1899 (rev, p1, p2, r.start(rev), r.end(rev),
1900 r.start(dbase), r.start(cbase),
1900 r.start(dbase), r.start(cbase),
1901 r.start(p1), r.start(p2),
1901 r.start(p1), r.start(p2),
1902 rs, ts, ts / r.end(rev), len(heads)))
1902 rs, ts, ts / r.end(rev), len(heads)))
1903 return 0
1903 return 0
1904
1904
1905 v = r.version
1905 v = r.version
1906 format = v & 0xFFFF
1906 format = v & 0xFFFF
1907 flags = []
1907 flags = []
1908 gdelta = False
1908 gdelta = False
1909 if v & revlog.REVLOGNGINLINEDATA:
1909 if v & revlog.REVLOGNGINLINEDATA:
1910 flags.append('inline')
1910 flags.append('inline')
1911 if v & revlog.REVLOGGENERALDELTA:
1911 if v & revlog.REVLOGGENERALDELTA:
1912 gdelta = True
1912 gdelta = True
1913 flags.append('generaldelta')
1913 flags.append('generaldelta')
1914 if not flags:
1914 if not flags:
1915 flags = ['(none)']
1915 flags = ['(none)']
1916
1916
1917 nummerges = 0
1917 nummerges = 0
1918 numfull = 0
1918 numfull = 0
1919 numprev = 0
1919 numprev = 0
1920 nump1 = 0
1920 nump1 = 0
1921 nump2 = 0
1921 nump2 = 0
1922 numother = 0
1922 numother = 0
1923 nump1prev = 0
1923 nump1prev = 0
1924 nump2prev = 0
1924 nump2prev = 0
1925 chainlengths = []
1925 chainlengths = []
1926
1926
1927 datasize = [None, 0, 0L]
1927 datasize = [None, 0, 0L]
1928 fullsize = [None, 0, 0L]
1928 fullsize = [None, 0, 0L]
1929 deltasize = [None, 0, 0L]
1929 deltasize = [None, 0, 0L]
1930
1930
1931 def addsize(size, l):
1931 def addsize(size, l):
1932 if l[0] is None or size < l[0]:
1932 if l[0] is None or size < l[0]:
1933 l[0] = size
1933 l[0] = size
1934 if size > l[1]:
1934 if size > l[1]:
1935 l[1] = size
1935 l[1] = size
1936 l[2] += size
1936 l[2] += size
1937
1937
1938 numrevs = len(r)
1938 numrevs = len(r)
1939 for rev in xrange(numrevs):
1939 for rev in xrange(numrevs):
1940 p1, p2 = r.parentrevs(rev)
1940 p1, p2 = r.parentrevs(rev)
1941 delta = r.deltaparent(rev)
1941 delta = r.deltaparent(rev)
1942 if format > 0:
1942 if format > 0:
1943 addsize(r.rawsize(rev), datasize)
1943 addsize(r.rawsize(rev), datasize)
1944 if p2 != nullrev:
1944 if p2 != nullrev:
1945 nummerges += 1
1945 nummerges += 1
1946 size = r.length(rev)
1946 size = r.length(rev)
1947 if delta == nullrev:
1947 if delta == nullrev:
1948 chainlengths.append(0)
1948 chainlengths.append(0)
1949 numfull += 1
1949 numfull += 1
1950 addsize(size, fullsize)
1950 addsize(size, fullsize)
1951 else:
1951 else:
1952 chainlengths.append(chainlengths[delta] + 1)
1952 chainlengths.append(chainlengths[delta] + 1)
1953 addsize(size, deltasize)
1953 addsize(size, deltasize)
1954 if delta == rev - 1:
1954 if delta == rev - 1:
1955 numprev += 1
1955 numprev += 1
1956 if delta == p1:
1956 if delta == p1:
1957 nump1prev += 1
1957 nump1prev += 1
1958 elif delta == p2:
1958 elif delta == p2:
1959 nump2prev += 1
1959 nump2prev += 1
1960 elif delta == p1:
1960 elif delta == p1:
1961 nump1 += 1
1961 nump1 += 1
1962 elif delta == p2:
1962 elif delta == p2:
1963 nump2 += 1
1963 nump2 += 1
1964 elif delta != nullrev:
1964 elif delta != nullrev:
1965 numother += 1
1965 numother += 1
1966
1966
1967 numdeltas = numrevs - numfull
1967 numdeltas = numrevs - numfull
1968 numoprev = numprev - nump1prev - nump2prev
1968 numoprev = numprev - nump1prev - nump2prev
1969 totalrawsize = datasize[2]
1969 totalrawsize = datasize[2]
1970 datasize[2] /= numrevs
1970 datasize[2] /= numrevs
1971 fulltotal = fullsize[2]
1971 fulltotal = fullsize[2]
1972 fullsize[2] /= numfull
1972 fullsize[2] /= numfull
1973 deltatotal = deltasize[2]
1973 deltatotal = deltasize[2]
1974 deltasize[2] /= numrevs - numfull
1974 deltasize[2] /= numrevs - numfull
1975 totalsize = fulltotal + deltatotal
1975 totalsize = fulltotal + deltatotal
1976 avgchainlen = sum(chainlengths) / numrevs
1976 avgchainlen = sum(chainlengths) / numrevs
1977 compratio = totalrawsize / totalsize
1977 compratio = totalrawsize / totalsize
1978
1978
1979 basedfmtstr = '%%%dd\n'
1979 basedfmtstr = '%%%dd\n'
1980 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1980 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1981
1981
1982 def dfmtstr(max):
1982 def dfmtstr(max):
1983 return basedfmtstr % len(str(max))
1983 return basedfmtstr % len(str(max))
1984 def pcfmtstr(max, padding=0):
1984 def pcfmtstr(max, padding=0):
1985 return basepcfmtstr % (len(str(max)), ' ' * padding)
1985 return basepcfmtstr % (len(str(max)), ' ' * padding)
1986
1986
1987 def pcfmt(value, total):
1987 def pcfmt(value, total):
1988 return (value, 100 * float(value) / total)
1988 return (value, 100 * float(value) / total)
1989
1989
1990 ui.write('format : %d\n' % format)
1990 ui.write('format : %d\n' % format)
1991 ui.write('flags : %s\n' % ', '.join(flags))
1991 ui.write('flags : %s\n' % ', '.join(flags))
1992
1992
1993 ui.write('\n')
1993 ui.write('\n')
1994 fmt = pcfmtstr(totalsize)
1994 fmt = pcfmtstr(totalsize)
1995 fmt2 = dfmtstr(totalsize)
1995 fmt2 = dfmtstr(totalsize)
1996 ui.write('revisions : ' + fmt2 % numrevs)
1996 ui.write('revisions : ' + fmt2 % numrevs)
1997 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
1997 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
1998 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
1998 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
1999 ui.write('revisions : ' + fmt2 % numrevs)
1999 ui.write('revisions : ' + fmt2 % numrevs)
2000 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2000 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2001 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2001 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2002 ui.write('revision size : ' + fmt2 % totalsize)
2002 ui.write('revision size : ' + fmt2 % totalsize)
2003 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2003 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2004 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2004 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2005
2005
2006 ui.write('\n')
2006 ui.write('\n')
2007 fmt = dfmtstr(max(avgchainlen, compratio))
2007 fmt = dfmtstr(max(avgchainlen, compratio))
2008 ui.write('avg chain length : ' + fmt % avgchainlen)
2008 ui.write('avg chain length : ' + fmt % avgchainlen)
2009 ui.write('compression ratio : ' + fmt % compratio)
2009 ui.write('compression ratio : ' + fmt % compratio)
2010
2010
2011 if format > 0:
2011 if format > 0:
2012 ui.write('\n')
2012 ui.write('\n')
2013 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2013 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2014 % tuple(datasize))
2014 % tuple(datasize))
2015 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2015 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2016 % tuple(fullsize))
2016 % tuple(fullsize))
2017 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2017 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2018 % tuple(deltasize))
2018 % tuple(deltasize))
2019
2019
2020 if numdeltas > 0:
2020 if numdeltas > 0:
2021 ui.write('\n')
2021 ui.write('\n')
2022 fmt = pcfmtstr(numdeltas)
2022 fmt = pcfmtstr(numdeltas)
2023 fmt2 = pcfmtstr(numdeltas, 4)
2023 fmt2 = pcfmtstr(numdeltas, 4)
2024 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2024 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2025 if numprev > 0:
2025 if numprev > 0:
2026 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2026 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2027 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2027 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2028 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2028 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2029 if gdelta:
2029 if gdelta:
2030 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2030 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2031 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2031 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2032 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2032 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2033
2033
2034 @command('debugrevspec', [], ('REVSPEC'))
2034 @command('debugrevspec', [], ('REVSPEC'))
2035 def debugrevspec(ui, repo, expr):
2035 def debugrevspec(ui, repo, expr):
2036 '''parse and apply a revision specification'''
2036 '''parse and apply a revision specification'''
2037 if ui.verbose:
2037 if ui.verbose:
2038 tree = revset.parse(expr)[0]
2038 tree = revset.parse(expr)[0]
2039 ui.note(tree, "\n")
2039 ui.note(tree, "\n")
2040 newtree = revset.findaliases(ui, tree)
2040 newtree = revset.findaliases(ui, tree)
2041 if newtree != tree:
2041 if newtree != tree:
2042 ui.note(newtree, "\n")
2042 ui.note(newtree, "\n")
2043 func = revset.match(ui, expr)
2043 func = revset.match(ui, expr)
2044 for c in func(repo, range(len(repo))):
2044 for c in func(repo, range(len(repo))):
2045 ui.write("%s\n" % c)
2045 ui.write("%s\n" % c)
2046
2046
2047 @command('debugsetparents', [], _('REV1 [REV2]'))
2047 @command('debugsetparents', [], _('REV1 [REV2]'))
2048 def debugsetparents(ui, repo, rev1, rev2=None):
2048 def debugsetparents(ui, repo, rev1, rev2=None):
2049 """manually set the parents of the current working directory
2049 """manually set the parents of the current working directory
2050
2050
2051 This is useful for writing repository conversion tools, but should
2051 This is useful for writing repository conversion tools, but should
2052 be used with care.
2052 be used with care.
2053
2053
2054 Returns 0 on success.
2054 Returns 0 on success.
2055 """
2055 """
2056
2056
2057 r1 = scmutil.revsingle(repo, rev1).node()
2057 r1 = scmutil.revsingle(repo, rev1).node()
2058 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2058 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2059
2059
2060 wlock = repo.wlock()
2060 wlock = repo.wlock()
2061 try:
2061 try:
2062 repo.dirstate.setparents(r1, r2)
2062 repo.dirstate.setparents(r1, r2)
2063 finally:
2063 finally:
2064 wlock.release()
2064 wlock.release()
2065
2065
2066 @command('debugstate',
2066 @command('debugstate',
2067 [('', 'nodates', None, _('do not display the saved mtime')),
2067 [('', 'nodates', None, _('do not display the saved mtime')),
2068 ('', 'datesort', None, _('sort by saved mtime'))],
2068 ('', 'datesort', None, _('sort by saved mtime'))],
2069 _('[OPTION]...'))
2069 _('[OPTION]...'))
2070 def debugstate(ui, repo, nodates=None, datesort=None):
2070 def debugstate(ui, repo, nodates=None, datesort=None):
2071 """show the contents of the current dirstate"""
2071 """show the contents of the current dirstate"""
2072 timestr = ""
2072 timestr = ""
2073 showdate = not nodates
2073 showdate = not nodates
2074 if datesort:
2074 if datesort:
2075 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2075 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2076 else:
2076 else:
2077 keyfunc = None # sort by filename
2077 keyfunc = None # sort by filename
2078 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2078 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2079 if showdate:
2079 if showdate:
2080 if ent[3] == -1:
2080 if ent[3] == -1:
2081 # Pad or slice to locale representation
2081 # Pad or slice to locale representation
2082 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2082 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2083 time.localtime(0)))
2083 time.localtime(0)))
2084 timestr = 'unset'
2084 timestr = 'unset'
2085 timestr = (timestr[:locale_len] +
2085 timestr = (timestr[:locale_len] +
2086 ' ' * (locale_len - len(timestr)))
2086 ' ' * (locale_len - len(timestr)))
2087 else:
2087 else:
2088 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2088 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2089 time.localtime(ent[3]))
2089 time.localtime(ent[3]))
2090 if ent[1] & 020000:
2090 if ent[1] & 020000:
2091 mode = 'lnk'
2091 mode = 'lnk'
2092 else:
2092 else:
2093 mode = '%3o' % (ent[1] & 0777)
2093 mode = '%3o' % (ent[1] & 0777)
2094 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2094 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2095 for f in repo.dirstate.copies():
2095 for f in repo.dirstate.copies():
2096 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2096 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2097
2097
2098 @command('debugsub',
2098 @command('debugsub',
2099 [('r', 'rev', '',
2099 [('r', 'rev', '',
2100 _('revision to check'), _('REV'))],
2100 _('revision to check'), _('REV'))],
2101 _('[-r REV] [REV]'))
2101 _('[-r REV] [REV]'))
2102 def debugsub(ui, repo, rev=None):
2102 def debugsub(ui, repo, rev=None):
2103 ctx = scmutil.revsingle(repo, rev, None)
2103 ctx = scmutil.revsingle(repo, rev, None)
2104 for k, v in sorted(ctx.substate.items()):
2104 for k, v in sorted(ctx.substate.items()):
2105 ui.write('path %s\n' % k)
2105 ui.write('path %s\n' % k)
2106 ui.write(' source %s\n' % v[0])
2106 ui.write(' source %s\n' % v[0])
2107 ui.write(' revision %s\n' % v[1])
2107 ui.write(' revision %s\n' % v[1])
2108
2108
2109 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2109 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2110 def debugwalk(ui, repo, *pats, **opts):
2110 def debugwalk(ui, repo, *pats, **opts):
2111 """show how files match on given patterns"""
2111 """show how files match on given patterns"""
2112 m = scmutil.match(repo[None], pats, opts)
2112 m = scmutil.match(repo[None], pats, opts)
2113 items = list(repo.walk(m))
2113 items = list(repo.walk(m))
2114 if not items:
2114 if not items:
2115 return
2115 return
2116 fmt = 'f %%-%ds %%-%ds %%s' % (
2116 fmt = 'f %%-%ds %%-%ds %%s' % (
2117 max([len(abs) for abs in items]),
2117 max([len(abs) for abs in items]),
2118 max([len(m.rel(abs)) for abs in items]))
2118 max([len(m.rel(abs)) for abs in items]))
2119 for abs in items:
2119 for abs in items:
2120 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2120 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2121 ui.write("%s\n" % line.rstrip())
2121 ui.write("%s\n" % line.rstrip())
2122
2122
2123 @command('debugwireargs',
2123 @command('debugwireargs',
2124 [('', 'three', '', 'three'),
2124 [('', 'three', '', 'three'),
2125 ('', 'four', '', 'four'),
2125 ('', 'four', '', 'four'),
2126 ('', 'five', '', 'five'),
2126 ('', 'five', '', 'five'),
2127 ] + remoteopts,
2127 ] + remoteopts,
2128 _('REPO [OPTIONS]... [ONE [TWO]]'))
2128 _('REPO [OPTIONS]... [ONE [TWO]]'))
2129 def debugwireargs(ui, repopath, *vals, **opts):
2129 def debugwireargs(ui, repopath, *vals, **opts):
2130 repo = hg.peer(ui, opts, repopath)
2130 repo = hg.peer(ui, opts, repopath)
2131 for opt in remoteopts:
2131 for opt in remoteopts:
2132 del opts[opt[1]]
2132 del opts[opt[1]]
2133 args = {}
2133 args = {}
2134 for k, v in opts.iteritems():
2134 for k, v in opts.iteritems():
2135 if v:
2135 if v:
2136 args[k] = v
2136 args[k] = v
2137 # run twice to check that we don't mess up the stream for the next command
2137 # run twice to check that we don't mess up the stream for the next command
2138 res1 = repo.debugwireargs(*vals, **args)
2138 res1 = repo.debugwireargs(*vals, **args)
2139 res2 = repo.debugwireargs(*vals, **args)
2139 res2 = repo.debugwireargs(*vals, **args)
2140 ui.write("%s\n" % res1)
2140 ui.write("%s\n" % res1)
2141 if res1 != res2:
2141 if res1 != res2:
2142 ui.warn("%s\n" % res2)
2142 ui.warn("%s\n" % res2)
2143
2143
2144 @command('^diff',
2144 @command('^diff',
2145 [('r', 'rev', [], _('revision'), _('REV')),
2145 [('r', 'rev', [], _('revision'), _('REV')),
2146 ('c', 'change', '', _('change made by revision'), _('REV'))
2146 ('c', 'change', '', _('change made by revision'), _('REV'))
2147 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2147 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2148 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2148 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2149 def diff(ui, repo, *pats, **opts):
2149 def diff(ui, repo, *pats, **opts):
2150 """diff repository (or selected files)
2150 """diff repository (or selected files)
2151
2151
2152 Show differences between revisions for the specified files.
2152 Show differences between revisions for the specified files.
2153
2153
2154 Differences between files are shown using the unified diff format.
2154 Differences between files are shown using the unified diff format.
2155
2155
2156 .. note::
2156 .. note::
2157 diff may generate unexpected results for merges, as it will
2157 diff may generate unexpected results for merges, as it will
2158 default to comparing against the working directory's first
2158 default to comparing against the working directory's first
2159 parent changeset if no revisions are specified.
2159 parent changeset if no revisions are specified.
2160
2160
2161 When two revision arguments are given, then changes are shown
2161 When two revision arguments are given, then changes are shown
2162 between those revisions. If only one revision is specified then
2162 between those revisions. If only one revision is specified then
2163 that revision is compared to the working directory, and, when no
2163 that revision is compared to the working directory, and, when no
2164 revisions are specified, the working directory files are compared
2164 revisions are specified, the working directory files are compared
2165 to its parent.
2165 to its parent.
2166
2166
2167 Alternatively you can specify -c/--change with a revision to see
2167 Alternatively you can specify -c/--change with a revision to see
2168 the changes in that changeset relative to its first parent.
2168 the changes in that changeset relative to its first parent.
2169
2169
2170 Without the -a/--text option, diff will avoid generating diffs of
2170 Without the -a/--text option, diff will avoid generating diffs of
2171 files it detects as binary. With -a, diff will generate a diff
2171 files it detects as binary. With -a, diff will generate a diff
2172 anyway, probably with undesirable results.
2172 anyway, probably with undesirable results.
2173
2173
2174 Use the -g/--git option to generate diffs in the git extended diff
2174 Use the -g/--git option to generate diffs in the git extended diff
2175 format. For more information, read :hg:`help diffs`.
2175 format. For more information, read :hg:`help diffs`.
2176
2176
2177 Returns 0 on success.
2177 Returns 0 on success.
2178 """
2178 """
2179
2179
2180 revs = opts.get('rev')
2180 revs = opts.get('rev')
2181 change = opts.get('change')
2181 change = opts.get('change')
2182 stat = opts.get('stat')
2182 stat = opts.get('stat')
2183 reverse = opts.get('reverse')
2183 reverse = opts.get('reverse')
2184
2184
2185 if revs and change:
2185 if revs and change:
2186 msg = _('cannot specify --rev and --change at the same time')
2186 msg = _('cannot specify --rev and --change at the same time')
2187 raise util.Abort(msg)
2187 raise util.Abort(msg)
2188 elif change:
2188 elif change:
2189 node2 = scmutil.revsingle(repo, change, None).node()
2189 node2 = scmutil.revsingle(repo, change, None).node()
2190 node1 = repo[node2].p1().node()
2190 node1 = repo[node2].p1().node()
2191 else:
2191 else:
2192 node1, node2 = scmutil.revpair(repo, revs)
2192 node1, node2 = scmutil.revpair(repo, revs)
2193
2193
2194 if reverse:
2194 if reverse:
2195 node1, node2 = node2, node1
2195 node1, node2 = node2, node1
2196
2196
2197 diffopts = patch.diffopts(ui, opts)
2197 diffopts = patch.diffopts(ui, opts)
2198 m = scmutil.match(repo[node2], pats, opts)
2198 m = scmutil.match(repo[node2], pats, opts)
2199 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2199 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2200 listsubrepos=opts.get('subrepos'))
2200 listsubrepos=opts.get('subrepos'))
2201
2201
2202 @command('^export',
2202 @command('^export',
2203 [('o', 'output', '',
2203 [('o', 'output', '',
2204 _('print output to file with formatted name'), _('FORMAT')),
2204 _('print output to file with formatted name'), _('FORMAT')),
2205 ('', 'switch-parent', None, _('diff against the second parent')),
2205 ('', 'switch-parent', None, _('diff against the second parent')),
2206 ('r', 'rev', [], _('revisions to export'), _('REV')),
2206 ('r', 'rev', [], _('revisions to export'), _('REV')),
2207 ] + diffopts,
2207 ] + diffopts,
2208 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2208 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2209 def export(ui, repo, *changesets, **opts):
2209 def export(ui, repo, *changesets, **opts):
2210 """dump the header and diffs for one or more changesets
2210 """dump the header and diffs for one or more changesets
2211
2211
2212 Print the changeset header and diffs for one or more revisions.
2212 Print the changeset header and diffs for one or more revisions.
2213
2213
2214 The information shown in the changeset header is: author, date,
2214 The information shown in the changeset header is: author, date,
2215 branch name (if non-default), changeset hash, parent(s) and commit
2215 branch name (if non-default), changeset hash, parent(s) and commit
2216 comment.
2216 comment.
2217
2217
2218 .. note::
2218 .. note::
2219 export may generate unexpected diff output for merge
2219 export may generate unexpected diff output for merge
2220 changesets, as it will compare the merge changeset against its
2220 changesets, as it will compare the merge changeset against its
2221 first parent only.
2221 first parent only.
2222
2222
2223 Output may be to a file, in which case the name of the file is
2223 Output may be to a file, in which case the name of the file is
2224 given using a format string. The formatting rules are as follows:
2224 given using a format string. The formatting rules are as follows:
2225
2225
2226 :``%%``: literal "%" character
2226 :``%%``: literal "%" character
2227 :``%H``: changeset hash (40 hexadecimal digits)
2227 :``%H``: changeset hash (40 hexadecimal digits)
2228 :``%N``: number of patches being generated
2228 :``%N``: number of patches being generated
2229 :``%R``: changeset revision number
2229 :``%R``: changeset revision number
2230 :``%b``: basename of the exporting repository
2230 :``%b``: basename of the exporting repository
2231 :``%h``: short-form changeset hash (12 hexadecimal digits)
2231 :``%h``: short-form changeset hash (12 hexadecimal digits)
2232 :``%m``: first line of the commit message (only alphanumeric characters)
2232 :``%m``: first line of the commit message (only alphanumeric characters)
2233 :``%n``: zero-padded sequence number, starting at 1
2233 :``%n``: zero-padded sequence number, starting at 1
2234 :``%r``: zero-padded changeset revision number
2234 :``%r``: zero-padded changeset revision number
2235
2235
2236 Without the -a/--text option, export will avoid generating diffs
2236 Without the -a/--text option, export will avoid generating diffs
2237 of files it detects as binary. With -a, export will generate a
2237 of files it detects as binary. With -a, export will generate a
2238 diff anyway, probably with undesirable results.
2238 diff anyway, probably with undesirable results.
2239
2239
2240 Use the -g/--git option to generate diffs in the git extended diff
2240 Use the -g/--git option to generate diffs in the git extended diff
2241 format. See :hg:`help diffs` for more information.
2241 format. See :hg:`help diffs` for more information.
2242
2242
2243 With the --switch-parent option, the diff will be against the
2243 With the --switch-parent option, the diff will be against the
2244 second parent. It can be useful to review a merge.
2244 second parent. It can be useful to review a merge.
2245
2245
2246 Returns 0 on success.
2246 Returns 0 on success.
2247 """
2247 """
2248 changesets += tuple(opts.get('rev', []))
2248 changesets += tuple(opts.get('rev', []))
2249 if not changesets:
2249 if not changesets:
2250 raise util.Abort(_("export requires at least one changeset"))
2250 raise util.Abort(_("export requires at least one changeset"))
2251 revs = scmutil.revrange(repo, changesets)
2251 revs = scmutil.revrange(repo, changesets)
2252 if len(revs) > 1:
2252 if len(revs) > 1:
2253 ui.note(_('exporting patches:\n'))
2253 ui.note(_('exporting patches:\n'))
2254 else:
2254 else:
2255 ui.note(_('exporting patch:\n'))
2255 ui.note(_('exporting patch:\n'))
2256 cmdutil.export(repo, revs, template=opts.get('output'),
2256 cmdutil.export(repo, revs, template=opts.get('output'),
2257 switch_parent=opts.get('switch_parent'),
2257 switch_parent=opts.get('switch_parent'),
2258 opts=patch.diffopts(ui, opts))
2258 opts=patch.diffopts(ui, opts))
2259
2259
2260 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2260 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2261 def forget(ui, repo, *pats, **opts):
2261 def forget(ui, repo, *pats, **opts):
2262 """forget the specified files on the next commit
2262 """forget the specified files on the next commit
2263
2263
2264 Mark the specified files so they will no longer be tracked
2264 Mark the specified files so they will no longer be tracked
2265 after the next commit.
2265 after the next commit.
2266
2266
2267 This only removes files from the current branch, not from the
2267 This only removes files from the current branch, not from the
2268 entire project history, and it does not delete them from the
2268 entire project history, and it does not delete them from the
2269 working directory.
2269 working directory.
2270
2270
2271 To undo a forget before the next commit, see :hg:`add`.
2271 To undo a forget before the next commit, see :hg:`add`.
2272
2272
2273 Returns 0 on success.
2273 Returns 0 on success.
2274 """
2274 """
2275
2275
2276 if not pats:
2276 if not pats:
2277 raise util.Abort(_('no files specified'))
2277 raise util.Abort(_('no files specified'))
2278
2278
2279 m = scmutil.match(repo[None], pats, opts)
2279 m = scmutil.match(repo[None], pats, opts)
2280 s = repo.status(match=m, clean=True)
2280 s = repo.status(match=m, clean=True)
2281 forget = sorted(s[0] + s[1] + s[3] + s[6])
2281 forget = sorted(s[0] + s[1] + s[3] + s[6])
2282 errs = 0
2282 errs = 0
2283
2283
2284 for f in m.files():
2284 for f in m.files():
2285 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2285 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2286 if os.path.exists(m.rel(f)):
2286 if os.path.exists(m.rel(f)):
2287 ui.warn(_('not removing %s: file is already untracked\n')
2287 ui.warn(_('not removing %s: file is already untracked\n')
2288 % m.rel(f))
2288 % m.rel(f))
2289 errs = 1
2289 errs = 1
2290
2290
2291 for f in forget:
2291 for f in forget:
2292 if ui.verbose or not m.exact(f):
2292 if ui.verbose or not m.exact(f):
2293 ui.status(_('removing %s\n') % m.rel(f))
2293 ui.status(_('removing %s\n') % m.rel(f))
2294
2294
2295 repo[None].forget(forget)
2295 repo[None].forget(forget)
2296 return errs
2296 return errs
2297
2297
2298 @command('grep',
2298 @command('grep',
2299 [('0', 'print0', None, _('end fields with NUL')),
2299 [('0', 'print0', None, _('end fields with NUL')),
2300 ('', 'all', None, _('print all revisions that match')),
2300 ('', 'all', None, _('print all revisions that match')),
2301 ('a', 'text', None, _('treat all files as text')),
2301 ('a', 'text', None, _('treat all files as text')),
2302 ('f', 'follow', None,
2302 ('f', 'follow', None,
2303 _('follow changeset history,'
2303 _('follow changeset history,'
2304 ' or file history across copies and renames')),
2304 ' or file history across copies and renames')),
2305 ('i', 'ignore-case', None, _('ignore case when matching')),
2305 ('i', 'ignore-case', None, _('ignore case when matching')),
2306 ('l', 'files-with-matches', None,
2306 ('l', 'files-with-matches', None,
2307 _('print only filenames and revisions that match')),
2307 _('print only filenames and revisions that match')),
2308 ('n', 'line-number', None, _('print matching line numbers')),
2308 ('n', 'line-number', None, _('print matching line numbers')),
2309 ('r', 'rev', [],
2309 ('r', 'rev', [],
2310 _('only search files changed within revision range'), _('REV')),
2310 _('only search files changed within revision range'), _('REV')),
2311 ('u', 'user', None, _('list the author (long with -v)')),
2311 ('u', 'user', None, _('list the author (long with -v)')),
2312 ('d', 'date', None, _('list the date (short with -q)')),
2312 ('d', 'date', None, _('list the date (short with -q)')),
2313 ] + walkopts,
2313 ] + walkopts,
2314 _('[OPTION]... PATTERN [FILE]...'))
2314 _('[OPTION]... PATTERN [FILE]...'))
2315 def grep(ui, repo, pattern, *pats, **opts):
2315 def grep(ui, repo, pattern, *pats, **opts):
2316 """search for a pattern in specified files and revisions
2316 """search for a pattern in specified files and revisions
2317
2317
2318 Search revisions of files for a regular expression.
2318 Search revisions of files for a regular expression.
2319
2319
2320 This command behaves differently than Unix grep. It only accepts
2320 This command behaves differently than Unix grep. It only accepts
2321 Python/Perl regexps. It searches repository history, not the
2321 Python/Perl regexps. It searches repository history, not the
2322 working directory. It always prints the revision number in which a
2322 working directory. It always prints the revision number in which a
2323 match appears.
2323 match appears.
2324
2324
2325 By default, grep only prints output for the first revision of a
2325 By default, grep only prints output for the first revision of a
2326 file in which it finds a match. To get it to print every revision
2326 file in which it finds a match. To get it to print every revision
2327 that contains a change in match status ("-" for a match that
2327 that contains a change in match status ("-" for a match that
2328 becomes a non-match, or "+" for a non-match that becomes a match),
2328 becomes a non-match, or "+" for a non-match that becomes a match),
2329 use the --all flag.
2329 use the --all flag.
2330
2330
2331 Returns 0 if a match is found, 1 otherwise.
2331 Returns 0 if a match is found, 1 otherwise.
2332 """
2332 """
2333 reflags = 0
2333 reflags = 0
2334 if opts.get('ignore_case'):
2334 if opts.get('ignore_case'):
2335 reflags |= re.I
2335 reflags |= re.I
2336 try:
2336 try:
2337 regexp = re.compile(pattern, reflags)
2337 regexp = re.compile(pattern, reflags)
2338 except re.error, inst:
2338 except re.error, inst:
2339 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2339 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2340 return 1
2340 return 1
2341 sep, eol = ':', '\n'
2341 sep, eol = ':', '\n'
2342 if opts.get('print0'):
2342 if opts.get('print0'):
2343 sep = eol = '\0'
2343 sep = eol = '\0'
2344
2344
2345 getfile = util.lrucachefunc(repo.file)
2345 getfile = util.lrucachefunc(repo.file)
2346
2346
2347 def matchlines(body):
2347 def matchlines(body):
2348 begin = 0
2348 begin = 0
2349 linenum = 0
2349 linenum = 0
2350 while True:
2350 while True:
2351 match = regexp.search(body, begin)
2351 match = regexp.search(body, begin)
2352 if not match:
2352 if not match:
2353 break
2353 break
2354 mstart, mend = match.span()
2354 mstart, mend = match.span()
2355 linenum += body.count('\n', begin, mstart) + 1
2355 linenum += body.count('\n', begin, mstart) + 1
2356 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2356 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2357 begin = body.find('\n', mend) + 1 or len(body)
2357 begin = body.find('\n', mend) + 1 or len(body)
2358 lend = begin - 1
2358 lend = begin - 1
2359 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2359 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2360
2360
2361 class linestate(object):
2361 class linestate(object):
2362 def __init__(self, line, linenum, colstart, colend):
2362 def __init__(self, line, linenum, colstart, colend):
2363 self.line = line
2363 self.line = line
2364 self.linenum = linenum
2364 self.linenum = linenum
2365 self.colstart = colstart
2365 self.colstart = colstart
2366 self.colend = colend
2366 self.colend = colend
2367
2367
2368 def __hash__(self):
2368 def __hash__(self):
2369 return hash((self.linenum, self.line))
2369 return hash((self.linenum, self.line))
2370
2370
2371 def __eq__(self, other):
2371 def __eq__(self, other):
2372 return self.line == other.line
2372 return self.line == other.line
2373
2373
2374 matches = {}
2374 matches = {}
2375 copies = {}
2375 copies = {}
2376 def grepbody(fn, rev, body):
2376 def grepbody(fn, rev, body):
2377 matches[rev].setdefault(fn, [])
2377 matches[rev].setdefault(fn, [])
2378 m = matches[rev][fn]
2378 m = matches[rev][fn]
2379 for lnum, cstart, cend, line in matchlines(body):
2379 for lnum, cstart, cend, line in matchlines(body):
2380 s = linestate(line, lnum, cstart, cend)
2380 s = linestate(line, lnum, cstart, cend)
2381 m.append(s)
2381 m.append(s)
2382
2382
2383 def difflinestates(a, b):
2383 def difflinestates(a, b):
2384 sm = difflib.SequenceMatcher(None, a, b)
2384 sm = difflib.SequenceMatcher(None, a, b)
2385 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2385 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2386 if tag == 'insert':
2386 if tag == 'insert':
2387 for i in xrange(blo, bhi):
2387 for i in xrange(blo, bhi):
2388 yield ('+', b[i])
2388 yield ('+', b[i])
2389 elif tag == 'delete':
2389 elif tag == 'delete':
2390 for i in xrange(alo, ahi):
2390 for i in xrange(alo, ahi):
2391 yield ('-', a[i])
2391 yield ('-', a[i])
2392 elif tag == 'replace':
2392 elif tag == 'replace':
2393 for i in xrange(alo, ahi):
2393 for i in xrange(alo, ahi):
2394 yield ('-', a[i])
2394 yield ('-', a[i])
2395 for i in xrange(blo, bhi):
2395 for i in xrange(blo, bhi):
2396 yield ('+', b[i])
2396 yield ('+', b[i])
2397
2397
2398 def display(fn, ctx, pstates, states):
2398 def display(fn, ctx, pstates, states):
2399 rev = ctx.rev()
2399 rev = ctx.rev()
2400 datefunc = ui.quiet and util.shortdate or util.datestr
2400 datefunc = ui.quiet and util.shortdate or util.datestr
2401 found = False
2401 found = False
2402 filerevmatches = {}
2402 filerevmatches = {}
2403 def binary():
2403 def binary():
2404 flog = getfile(fn)
2404 flog = getfile(fn)
2405 return util.binary(flog.read(ctx.filenode(fn)))
2405 return util.binary(flog.read(ctx.filenode(fn)))
2406
2406
2407 if opts.get('all'):
2407 if opts.get('all'):
2408 iter = difflinestates(pstates, states)
2408 iter = difflinestates(pstates, states)
2409 else:
2409 else:
2410 iter = [('', l) for l in states]
2410 iter = [('', l) for l in states]
2411 for change, l in iter:
2411 for change, l in iter:
2412 cols = [fn, str(rev)]
2412 cols = [fn, str(rev)]
2413 before, match, after = None, None, None
2413 before, match, after = None, None, None
2414 if opts.get('line_number'):
2414 if opts.get('line_number'):
2415 cols.append(str(l.linenum))
2415 cols.append(str(l.linenum))
2416 if opts.get('all'):
2416 if opts.get('all'):
2417 cols.append(change)
2417 cols.append(change)
2418 if opts.get('user'):
2418 if opts.get('user'):
2419 cols.append(ui.shortuser(ctx.user()))
2419 cols.append(ui.shortuser(ctx.user()))
2420 if opts.get('date'):
2420 if opts.get('date'):
2421 cols.append(datefunc(ctx.date()))
2421 cols.append(datefunc(ctx.date()))
2422 if opts.get('files_with_matches'):
2422 if opts.get('files_with_matches'):
2423 c = (fn, rev)
2423 c = (fn, rev)
2424 if c in filerevmatches:
2424 if c in filerevmatches:
2425 continue
2425 continue
2426 filerevmatches[c] = 1
2426 filerevmatches[c] = 1
2427 else:
2427 else:
2428 before = l.line[:l.colstart]
2428 before = l.line[:l.colstart]
2429 match = l.line[l.colstart:l.colend]
2429 match = l.line[l.colstart:l.colend]
2430 after = l.line[l.colend:]
2430 after = l.line[l.colend:]
2431 ui.write(sep.join(cols))
2431 ui.write(sep.join(cols))
2432 if before is not None:
2432 if before is not None:
2433 if not opts.get('text') and binary():
2433 if not opts.get('text') and binary():
2434 ui.write(sep + " Binary file matches")
2434 ui.write(sep + " Binary file matches")
2435 else:
2435 else:
2436 ui.write(sep + before)
2436 ui.write(sep + before)
2437 ui.write(match, label='grep.match')
2437 ui.write(match, label='grep.match')
2438 ui.write(after)
2438 ui.write(after)
2439 ui.write(eol)
2439 ui.write(eol)
2440 found = True
2440 found = True
2441 return found
2441 return found
2442
2442
2443 skip = {}
2443 skip = {}
2444 revfiles = {}
2444 revfiles = {}
2445 matchfn = scmutil.match(repo[None], pats, opts)
2445 matchfn = scmutil.match(repo[None], pats, opts)
2446 found = False
2446 found = False
2447 follow = opts.get('follow')
2447 follow = opts.get('follow')
2448
2448
2449 def prep(ctx, fns):
2449 def prep(ctx, fns):
2450 rev = ctx.rev()
2450 rev = ctx.rev()
2451 pctx = ctx.p1()
2451 pctx = ctx.p1()
2452 parent = pctx.rev()
2452 parent = pctx.rev()
2453 matches.setdefault(rev, {})
2453 matches.setdefault(rev, {})
2454 matches.setdefault(parent, {})
2454 matches.setdefault(parent, {})
2455 files = revfiles.setdefault(rev, [])
2455 files = revfiles.setdefault(rev, [])
2456 for fn in fns:
2456 for fn in fns:
2457 flog = getfile(fn)
2457 flog = getfile(fn)
2458 try:
2458 try:
2459 fnode = ctx.filenode(fn)
2459 fnode = ctx.filenode(fn)
2460 except error.LookupError:
2460 except error.LookupError:
2461 continue
2461 continue
2462
2462
2463 copied = flog.renamed(fnode)
2463 copied = flog.renamed(fnode)
2464 copy = follow and copied and copied[0]
2464 copy = follow and copied and copied[0]
2465 if copy:
2465 if copy:
2466 copies.setdefault(rev, {})[fn] = copy
2466 copies.setdefault(rev, {})[fn] = copy
2467 if fn in skip:
2467 if fn in skip:
2468 if copy:
2468 if copy:
2469 skip[copy] = True
2469 skip[copy] = True
2470 continue
2470 continue
2471 files.append(fn)
2471 files.append(fn)
2472
2472
2473 if fn not in matches[rev]:
2473 if fn not in matches[rev]:
2474 grepbody(fn, rev, flog.read(fnode))
2474 grepbody(fn, rev, flog.read(fnode))
2475
2475
2476 pfn = copy or fn
2476 pfn = copy or fn
2477 if pfn not in matches[parent]:
2477 if pfn not in matches[parent]:
2478 try:
2478 try:
2479 fnode = pctx.filenode(pfn)
2479 fnode = pctx.filenode(pfn)
2480 grepbody(pfn, parent, flog.read(fnode))
2480 grepbody(pfn, parent, flog.read(fnode))
2481 except error.LookupError:
2481 except error.LookupError:
2482 pass
2482 pass
2483
2483
2484 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2484 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2485 rev = ctx.rev()
2485 rev = ctx.rev()
2486 parent = ctx.p1().rev()
2486 parent = ctx.p1().rev()
2487 for fn in sorted(revfiles.get(rev, [])):
2487 for fn in sorted(revfiles.get(rev, [])):
2488 states = matches[rev][fn]
2488 states = matches[rev][fn]
2489 copy = copies.get(rev, {}).get(fn)
2489 copy = copies.get(rev, {}).get(fn)
2490 if fn in skip:
2490 if fn in skip:
2491 if copy:
2491 if copy:
2492 skip[copy] = True
2492 skip[copy] = True
2493 continue
2493 continue
2494 pstates = matches.get(parent, {}).get(copy or fn, [])
2494 pstates = matches.get(parent, {}).get(copy or fn, [])
2495 if pstates or states:
2495 if pstates or states:
2496 r = display(fn, ctx, pstates, states)
2496 r = display(fn, ctx, pstates, states)
2497 found = found or r
2497 found = found or r
2498 if r and not opts.get('all'):
2498 if r and not opts.get('all'):
2499 skip[fn] = True
2499 skip[fn] = True
2500 if copy:
2500 if copy:
2501 skip[copy] = True
2501 skip[copy] = True
2502 del matches[rev]
2502 del matches[rev]
2503 del revfiles[rev]
2503 del revfiles[rev]
2504
2504
2505 return not found
2505 return not found
2506
2506
2507 @command('heads',
2507 @command('heads',
2508 [('r', 'rev', '',
2508 [('r', 'rev', '',
2509 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2509 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2510 ('t', 'topo', False, _('show topological heads only')),
2510 ('t', 'topo', False, _('show topological heads only')),
2511 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2511 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2512 ('c', 'closed', False, _('show normal and closed branch heads')),
2512 ('c', 'closed', False, _('show normal and closed branch heads')),
2513 ] + templateopts,
2513 ] + templateopts,
2514 _('[-ac] [-r STARTREV] [REV]...'))
2514 _('[-ac] [-r STARTREV] [REV]...'))
2515 def heads(ui, repo, *branchrevs, **opts):
2515 def heads(ui, repo, *branchrevs, **opts):
2516 """show current repository heads or show branch heads
2516 """show current repository heads or show branch heads
2517
2517
2518 With no arguments, show all repository branch heads.
2518 With no arguments, show all repository branch heads.
2519
2519
2520 Repository "heads" are changesets with no child changesets. They are
2520 Repository "heads" are changesets with no child changesets. They are
2521 where development generally takes place and are the usual targets
2521 where development generally takes place and are the usual targets
2522 for update and merge operations. Branch heads are changesets that have
2522 for update and merge operations. Branch heads are changesets that have
2523 no child changeset on the same branch.
2523 no child changeset on the same branch.
2524
2524
2525 If one or more REVs are given, only branch heads on the branches
2525 If one or more REVs are given, only branch heads on the branches
2526 associated with the specified changesets are shown.
2526 associated with the specified changesets are shown.
2527
2527
2528 If -c/--closed is specified, also show branch heads marked closed
2528 If -c/--closed is specified, also show branch heads marked closed
2529 (see :hg:`commit --close-branch`).
2529 (see :hg:`commit --close-branch`).
2530
2530
2531 If STARTREV is specified, only those heads that are descendants of
2531 If STARTREV is specified, only those heads that are descendants of
2532 STARTREV will be displayed.
2532 STARTREV will be displayed.
2533
2533
2534 If -t/--topo is specified, named branch mechanics will be ignored and only
2534 If -t/--topo is specified, named branch mechanics will be ignored and only
2535 changesets without children will be shown.
2535 changesets without children will be shown.
2536
2536
2537 Returns 0 if matching heads are found, 1 if not.
2537 Returns 0 if matching heads are found, 1 if not.
2538 """
2538 """
2539
2539
2540 start = None
2540 start = None
2541 if 'rev' in opts:
2541 if 'rev' in opts:
2542 start = scmutil.revsingle(repo, opts['rev'], None).node()
2542 start = scmutil.revsingle(repo, opts['rev'], None).node()
2543
2543
2544 if opts.get('topo'):
2544 if opts.get('topo'):
2545 heads = [repo[h] for h in repo.heads(start)]
2545 heads = [repo[h] for h in repo.heads(start)]
2546 else:
2546 else:
2547 heads = []
2547 heads = []
2548 for branch in repo.branchmap():
2548 for branch in repo.branchmap():
2549 heads += repo.branchheads(branch, start, opts.get('closed'))
2549 heads += repo.branchheads(branch, start, opts.get('closed'))
2550 heads = [repo[h] for h in heads]
2550 heads = [repo[h] for h in heads]
2551
2551
2552 if branchrevs:
2552 if branchrevs:
2553 branches = set(repo[br].branch() for br in branchrevs)
2553 branches = set(repo[br].branch() for br in branchrevs)
2554 heads = [h for h in heads if h.branch() in branches]
2554 heads = [h for h in heads if h.branch() in branches]
2555
2555
2556 if opts.get('active') and branchrevs:
2556 if opts.get('active') and branchrevs:
2557 dagheads = repo.heads(start)
2557 dagheads = repo.heads(start)
2558 heads = [h for h in heads if h.node() in dagheads]
2558 heads = [h for h in heads if h.node() in dagheads]
2559
2559
2560 if branchrevs:
2560 if branchrevs:
2561 haveheads = set(h.branch() for h in heads)
2561 haveheads = set(h.branch() for h in heads)
2562 if branches - haveheads:
2562 if branches - haveheads:
2563 headless = ', '.join(b for b in branches - haveheads)
2563 headless = ', '.join(b for b in branches - haveheads)
2564 msg = _('no open branch heads found on branches %s')
2564 msg = _('no open branch heads found on branches %s')
2565 if opts.get('rev'):
2565 if opts.get('rev'):
2566 msg += _(' (started at %s)' % opts['rev'])
2566 msg += _(' (started at %s)' % opts['rev'])
2567 ui.warn((msg + '\n') % headless)
2567 ui.warn((msg + '\n') % headless)
2568
2568
2569 if not heads:
2569 if not heads:
2570 return 1
2570 return 1
2571
2571
2572 heads = sorted(heads, key=lambda x: -x.rev())
2572 heads = sorted(heads, key=lambda x: -x.rev())
2573 displayer = cmdutil.show_changeset(ui, repo, opts)
2573 displayer = cmdutil.show_changeset(ui, repo, opts)
2574 for ctx in heads:
2574 for ctx in heads:
2575 displayer.show(ctx)
2575 displayer.show(ctx)
2576 displayer.close()
2576 displayer.close()
2577
2577
2578 @command('help',
2578 @command('help',
2579 [('e', 'extension', None, _('show only help for extensions')),
2579 [('e', 'extension', None, _('show only help for extensions')),
2580 ('c', 'command', None, _('show only help for commands'))],
2580 ('c', 'command', None, _('show only help for commands'))],
2581 _('[-ec] [TOPIC]'))
2581 _('[-ec] [TOPIC]'))
2582 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2582 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2583 """show help for a given topic or a help overview
2583 """show help for a given topic or a help overview
2584
2584
2585 With no arguments, print a list of commands with short help messages.
2585 With no arguments, print a list of commands with short help messages.
2586
2586
2587 Given a topic, extension, or command name, print help for that
2587 Given a topic, extension, or command name, print help for that
2588 topic.
2588 topic.
2589
2589
2590 Returns 0 if successful.
2590 Returns 0 if successful.
2591 """
2591 """
2592
2592
2593 optlist = []
2593 optlist = []
2594 textwidth = min(ui.termwidth(), 80) - 2
2594 textwidth = min(ui.termwidth(), 80) - 2
2595
2595
2596 # list all option lists
2596 # list all option lists
2597 def opttext(optlist, width):
2597 def opttext(optlist, width):
2598 out = []
2598 out = []
2599 multioccur = False
2599 multioccur = False
2600 for title, options in optlist:
2600 for title, options in optlist:
2601 out.append(("\n%s" % title, None))
2601 out.append(("\n%s" % title, None))
2602 for option in options:
2602 for option in options:
2603 if len(option) == 5:
2603 if len(option) == 5:
2604 shortopt, longopt, default, desc, optlabel = option
2604 shortopt, longopt, default, desc, optlabel = option
2605 else:
2605 else:
2606 shortopt, longopt, default, desc = option
2606 shortopt, longopt, default, desc = option
2607 optlabel = _("VALUE") # default label
2607 optlabel = _("VALUE") # default label
2608
2608
2609 if _("DEPRECATED") in desc and not ui.verbose:
2609 if _("DEPRECATED") in desc and not ui.verbose:
2610 continue
2610 continue
2611 if isinstance(default, list):
2611 if isinstance(default, list):
2612 numqualifier = " %s [+]" % optlabel
2612 numqualifier = " %s [+]" % optlabel
2613 multioccur = True
2613 multioccur = True
2614 elif (default is not None) and not isinstance(default, bool):
2614 elif (default is not None) and not isinstance(default, bool):
2615 numqualifier = " %s" % optlabel
2615 numqualifier = " %s" % optlabel
2616 else:
2616 else:
2617 numqualifier = ""
2617 numqualifier = ""
2618 out.append(("%2s%s" %
2618 out.append(("%2s%s" %
2619 (shortopt and "-%s" % shortopt,
2619 (shortopt and "-%s" % shortopt,
2620 longopt and " --%s%s" %
2620 longopt and " --%s%s" %
2621 (longopt, numqualifier)),
2621 (longopt, numqualifier)),
2622 "%s%s" % (desc,
2622 "%s%s" % (desc,
2623 default
2623 default
2624 and _(" (default: %s)") % default
2624 and _(" (default: %s)") % default
2625 or "")))
2625 or "")))
2626 if multioccur:
2626 if multioccur:
2627 msg = _("\n[+] marked option can be specified multiple times")
2627 msg = _("\n[+] marked option can be specified multiple times")
2628 if ui.verbose and name != 'shortlist':
2628 if ui.verbose and name != 'shortlist':
2629 out.append((msg, None))
2629 out.append((msg, None))
2630 else:
2630 else:
2631 out.insert(-1, (msg, None))
2631 out.insert(-1, (msg, None))
2632
2632
2633 text = ""
2633 text = ""
2634 if out:
2634 if out:
2635 colwidth = encoding.colwidth
2635 colwidth = encoding.colwidth
2636 # normalize: (opt or message, desc or None, width of opt)
2636 # normalize: (opt or message, desc or None, width of opt)
2637 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2637 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2638 for opt, desc in out]
2638 for opt, desc in out]
2639 hanging = max([e[2] for e in entries])
2639 hanging = max([e[2] for e in entries])
2640 for opt, desc, width in entries:
2640 for opt, desc, width in entries:
2641 if desc:
2641 if desc:
2642 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2642 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2643 hangindent = ' ' * (hanging + 3)
2643 hangindent = ' ' * (hanging + 3)
2644 text += '%s\n' % (util.wrap(desc, width,
2644 text += '%s\n' % (util.wrap(desc, width,
2645 initindent=initindent,
2645 initindent=initindent,
2646 hangindent=hangindent))
2646 hangindent=hangindent))
2647 else:
2647 else:
2648 text += "%s\n" % opt
2648 text += "%s\n" % opt
2649
2649
2650 return text
2650 return text
2651
2651
2652 def addglobalopts(aliases):
2652 def addglobalopts(aliases):
2653 if ui.verbose:
2653 if ui.verbose:
2654 optlist.append((_("global options:"), globalopts))
2654 optlist.append((_("global options:"), globalopts))
2655 if name == 'shortlist':
2655 if name == 'shortlist':
2656 optlist.append((_('use "hg help" for the full list '
2656 optlist.append((_('use "hg help" for the full list '
2657 'of commands'), ()))
2657 'of commands'), ()))
2658 else:
2658 else:
2659 if name == 'shortlist':
2659 if name == 'shortlist':
2660 msg = _('use "hg help" for the full list of commands '
2660 msg = _('use "hg help" for the full list of commands '
2661 'or "hg -v" for details')
2661 'or "hg -v" for details')
2662 elif name and not full:
2662 elif name and not full:
2663 msg = _('use "hg help %s" to show the full help text' % name)
2663 msg = _('use "hg help %s" to show the full help text' % name)
2664 elif aliases:
2664 elif aliases:
2665 msg = _('use "hg -v help%s" to show builtin aliases and '
2665 msg = _('use "hg -v help%s" to show builtin aliases and '
2666 'global options') % (name and " " + name or "")
2666 'global options') % (name and " " + name or "")
2667 else:
2667 else:
2668 msg = _('use "hg -v help %s" to show global options') % name
2668 msg = _('use "hg -v help %s" to show global options') % name
2669 optlist.append((msg, ()))
2669 optlist.append((msg, ()))
2670
2670
2671 def helpcmd(name):
2671 def helpcmd(name):
2672 try:
2672 try:
2673 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2673 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2674 except error.AmbiguousCommand, inst:
2674 except error.AmbiguousCommand, inst:
2675 # py3k fix: except vars can't be used outside the scope of the
2675 # py3k fix: except vars can't be used outside the scope of the
2676 # except block, nor can be used inside a lambda. python issue4617
2676 # except block, nor can be used inside a lambda. python issue4617
2677 prefix = inst.args[0]
2677 prefix = inst.args[0]
2678 select = lambda c: c.lstrip('^').startswith(prefix)
2678 select = lambda c: c.lstrip('^').startswith(prefix)
2679 helplist(_('list of commands:\n\n'), select)
2679 helplist(_('list of commands:\n\n'), select)
2680 return
2680 return
2681
2681
2682 # check if it's an invalid alias and display its error if it is
2682 # check if it's an invalid alias and display its error if it is
2683 if getattr(entry[0], 'badalias', False):
2683 if getattr(entry[0], 'badalias', False):
2684 if not unknowncmd:
2684 if not unknowncmd:
2685 entry[0](ui)
2685 entry[0](ui)
2686 return
2686 return
2687
2687
2688 # synopsis
2688 # synopsis
2689 if len(entry) > 2:
2689 if len(entry) > 2:
2690 if entry[2].startswith('hg'):
2690 if entry[2].startswith('hg'):
2691 ui.write("%s\n" % entry[2])
2691 ui.write("%s\n" % entry[2])
2692 else:
2692 else:
2693 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2693 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2694 else:
2694 else:
2695 ui.write('hg %s\n' % aliases[0])
2695 ui.write('hg %s\n' % aliases[0])
2696
2696
2697 # aliases
2697 # aliases
2698 if full and not ui.quiet and len(aliases) > 1:
2698 if full and not ui.quiet and len(aliases) > 1:
2699 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2699 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2700
2700
2701 # description
2701 # description
2702 doc = gettext(entry[0].__doc__)
2702 doc = gettext(entry[0].__doc__)
2703 if not doc:
2703 if not doc:
2704 doc = _("(no help text available)")
2704 doc = _("(no help text available)")
2705 if util.safehasattr(entry[0], 'definition'): # aliased command
2705 if util.safehasattr(entry[0], 'definition'): # aliased command
2706 if entry[0].definition.startswith('!'): # shell alias
2706 if entry[0].definition.startswith('!'): # shell alias
2707 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2707 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2708 else:
2708 else:
2709 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2709 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2710 if ui.quiet or not full:
2710 if ui.quiet or not full:
2711 doc = doc.splitlines()[0]
2711 doc = doc.splitlines()[0]
2712 keep = ui.verbose and ['verbose'] or []
2712 keep = ui.verbose and ['verbose'] or []
2713 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2713 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2714 ui.write("\n%s\n" % formatted)
2714 ui.write("\n%s\n" % formatted)
2715 if pruned:
2715 if pruned:
2716 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2716 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2717
2717
2718 if not ui.quiet:
2718 if not ui.quiet:
2719 # options
2719 # options
2720 if entry[1]:
2720 if entry[1]:
2721 optlist.append((_("options:\n"), entry[1]))
2721 optlist.append((_("options:\n"), entry[1]))
2722
2722
2723 addglobalopts(False)
2723 addglobalopts(False)
2724
2724
2725 # check if this command shadows a non-trivial (multi-line)
2725 # check if this command shadows a non-trivial (multi-line)
2726 # extension help text
2726 # extension help text
2727 try:
2727 try:
2728 mod = extensions.find(name)
2728 mod = extensions.find(name)
2729 doc = gettext(mod.__doc__) or ''
2729 doc = gettext(mod.__doc__) or ''
2730 if '\n' in doc.strip():
2730 if '\n' in doc.strip():
2731 msg = _('use "hg help -e %s" to show help for '
2731 msg = _('use "hg help -e %s" to show help for '
2732 'the %s extension') % (name, name)
2732 'the %s extension') % (name, name)
2733 ui.write('\n%s\n' % msg)
2733 ui.write('\n%s\n' % msg)
2734 except KeyError:
2734 except KeyError:
2735 pass
2735 pass
2736
2736
2737 def helplist(header, select=None):
2737 def helplist(header, select=None):
2738 h = {}
2738 h = {}
2739 cmds = {}
2739 cmds = {}
2740 for c, e in table.iteritems():
2740 for c, e in table.iteritems():
2741 f = c.split("|", 1)[0]
2741 f = c.split("|", 1)[0]
2742 if select and not select(f):
2742 if select and not select(f):
2743 continue
2743 continue
2744 if (not select and name != 'shortlist' and
2744 if (not select and name != 'shortlist' and
2745 e[0].__module__ != __name__):
2745 e[0].__module__ != __name__):
2746 continue
2746 continue
2747 if name == "shortlist" and not f.startswith("^"):
2747 if name == "shortlist" and not f.startswith("^"):
2748 continue
2748 continue
2749 f = f.lstrip("^")
2749 f = f.lstrip("^")
2750 if not ui.debugflag and f.startswith("debug"):
2750 if not ui.debugflag and f.startswith("debug"):
2751 continue
2751 continue
2752 doc = e[0].__doc__
2752 doc = e[0].__doc__
2753 if doc and 'DEPRECATED' in doc and not ui.verbose:
2753 if doc and 'DEPRECATED' in doc and not ui.verbose:
2754 continue
2754 continue
2755 doc = gettext(doc)
2755 doc = gettext(doc)
2756 if not doc:
2756 if not doc:
2757 doc = _("(no help text available)")
2757 doc = _("(no help text available)")
2758 h[f] = doc.splitlines()[0].rstrip()
2758 h[f] = doc.splitlines()[0].rstrip()
2759 cmds[f] = c.lstrip("^")
2759 cmds[f] = c.lstrip("^")
2760
2760
2761 if not h:
2761 if not h:
2762 ui.status(_('no commands defined\n'))
2762 ui.status(_('no commands defined\n'))
2763 return
2763 return
2764
2764
2765 ui.status(header)
2765 ui.status(header)
2766 fns = sorted(h)
2766 fns = sorted(h)
2767 m = max(map(len, fns))
2767 m = max(map(len, fns))
2768 for f in fns:
2768 for f in fns:
2769 if ui.verbose:
2769 if ui.verbose:
2770 commands = cmds[f].replace("|",", ")
2770 commands = cmds[f].replace("|",", ")
2771 ui.write(" %s:\n %s\n"%(commands, h[f]))
2771 ui.write(" %s:\n %s\n"%(commands, h[f]))
2772 else:
2772 else:
2773 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2773 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2774 initindent=' %-*s ' % (m, f),
2774 initindent=' %-*s ' % (m, f),
2775 hangindent=' ' * (m + 4))))
2775 hangindent=' ' * (m + 4))))
2776
2776
2777 if not ui.quiet:
2777 if not ui.quiet:
2778 addglobalopts(True)
2778 addglobalopts(True)
2779
2779
2780 def helptopic(name):
2780 def helptopic(name):
2781 for names, header, doc in help.helptable:
2781 for names, header, doc in help.helptable:
2782 if name in names:
2782 if name in names:
2783 break
2783 break
2784 else:
2784 else:
2785 raise error.UnknownCommand(name)
2785 raise error.UnknownCommand(name)
2786
2786
2787 # description
2787 # description
2788 if not doc:
2788 if not doc:
2789 doc = _("(no help text available)")
2789 doc = _("(no help text available)")
2790 if util.safehasattr(doc, '__call__'):
2790 if util.safehasattr(doc, '__call__'):
2791 doc = doc()
2791 doc = doc()
2792
2792
2793 ui.write("%s\n\n" % header)
2793 ui.write("%s\n\n" % header)
2794 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2794 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2795 try:
2795 try:
2796 cmdutil.findcmd(name, table)
2796 cmdutil.findcmd(name, table)
2797 ui.write(_('\nuse "hg help -c %s" to see help for '
2797 ui.write(_('\nuse "hg help -c %s" to see help for '
2798 'the %s command\n') % (name, name))
2798 'the %s command\n') % (name, name))
2799 except error.UnknownCommand:
2799 except error.UnknownCommand:
2800 pass
2800 pass
2801
2801
2802 def helpext(name):
2802 def helpext(name):
2803 try:
2803 try:
2804 mod = extensions.find(name)
2804 mod = extensions.find(name)
2805 doc = gettext(mod.__doc__) or _('no help text available')
2805 doc = gettext(mod.__doc__) or _('no help text available')
2806 except KeyError:
2806 except KeyError:
2807 mod = None
2807 mod = None
2808 doc = extensions.disabledext(name)
2808 doc = extensions.disabledext(name)
2809 if not doc:
2809 if not doc:
2810 raise error.UnknownCommand(name)
2810 raise error.UnknownCommand(name)
2811
2811
2812 if '\n' not in doc:
2812 if '\n' not in doc:
2813 head, tail = doc, ""
2813 head, tail = doc, ""
2814 else:
2814 else:
2815 head, tail = doc.split('\n', 1)
2815 head, tail = doc.split('\n', 1)
2816 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2816 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2817 if tail:
2817 if tail:
2818 ui.write(minirst.format(tail, textwidth))
2818 ui.write(minirst.format(tail, textwidth))
2819 ui.status('\n\n')
2819 ui.status('\n\n')
2820
2820
2821 if mod:
2821 if mod:
2822 try:
2822 try:
2823 ct = mod.cmdtable
2823 ct = mod.cmdtable
2824 except AttributeError:
2824 except AttributeError:
2825 ct = {}
2825 ct = {}
2826 modcmds = set([c.split('|', 1)[0] for c in ct])
2826 modcmds = set([c.split('|', 1)[0] for c in ct])
2827 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2827 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2828 else:
2828 else:
2829 ui.write(_('use "hg help extensions" for information on enabling '
2829 ui.write(_('use "hg help extensions" for information on enabling '
2830 'extensions\n'))
2830 'extensions\n'))
2831
2831
2832 def helpextcmd(name):
2832 def helpextcmd(name):
2833 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2833 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2834 doc = gettext(mod.__doc__).splitlines()[0]
2834 doc = gettext(mod.__doc__).splitlines()[0]
2835
2835
2836 msg = help.listexts(_("'%s' is provided by the following "
2836 msg = help.listexts(_("'%s' is provided by the following "
2837 "extension:") % cmd, {ext: doc}, indent=4)
2837 "extension:") % cmd, {ext: doc}, indent=4)
2838 ui.write(minirst.format(msg, textwidth))
2838 ui.write(minirst.format(msg, textwidth))
2839 ui.write('\n\n')
2839 ui.write('\n\n')
2840 ui.write(_('use "hg help extensions" for information on enabling '
2840 ui.write(_('use "hg help extensions" for information on enabling '
2841 'extensions\n'))
2841 'extensions\n'))
2842
2842
2843 if name and name != 'shortlist':
2843 if name and name != 'shortlist':
2844 i = None
2844 i = None
2845 if unknowncmd:
2845 if unknowncmd:
2846 queries = (helpextcmd,)
2846 queries = (helpextcmd,)
2847 elif opts.get('extension'):
2847 elif opts.get('extension'):
2848 queries = (helpext,)
2848 queries = (helpext,)
2849 elif opts.get('command'):
2849 elif opts.get('command'):
2850 queries = (helpcmd,)
2850 queries = (helpcmd,)
2851 else:
2851 else:
2852 queries = (helptopic, helpcmd, helpext, helpextcmd)
2852 queries = (helptopic, helpcmd, helpext, helpextcmd)
2853 for f in queries:
2853 for f in queries:
2854 try:
2854 try:
2855 f(name)
2855 f(name)
2856 i = None
2856 i = None
2857 break
2857 break
2858 except error.UnknownCommand, inst:
2858 except error.UnknownCommand, inst:
2859 i = inst
2859 i = inst
2860 if i:
2860 if i:
2861 raise i
2861 raise i
2862
2862
2863 else:
2863 else:
2864 # program name
2864 # program name
2865 ui.status(_("Mercurial Distributed SCM\n"))
2865 ui.status(_("Mercurial Distributed SCM\n"))
2866 ui.status('\n')
2866 ui.status('\n')
2867
2867
2868 # list of commands
2868 # list of commands
2869 if name == "shortlist":
2869 if name == "shortlist":
2870 header = _('basic commands:\n\n')
2870 header = _('basic commands:\n\n')
2871 else:
2871 else:
2872 header = _('list of commands:\n\n')
2872 header = _('list of commands:\n\n')
2873
2873
2874 helplist(header)
2874 helplist(header)
2875 if name != 'shortlist':
2875 if name != 'shortlist':
2876 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2876 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2877 if text:
2877 if text:
2878 ui.write("\n%s\n" % minirst.format(text, textwidth))
2878 ui.write("\n%s\n" % minirst.format(text, textwidth))
2879
2879
2880 if not name:
2880 if not name:
2881 ui.write(_("\nadditional help topics:\n\n"))
2881 ui.write(_("\nadditional help topics:\n\n"))
2882 topics = []
2882 topics = []
2883 for names, header, doc in help.helptable:
2883 for names, header, doc in help.helptable:
2884 topics.append((sorted(names, key=len, reverse=True)[0], header))
2884 topics.append((sorted(names, key=len, reverse=True)[0], header))
2885 topics_len = max([len(s[0]) for s in topics])
2885 topics_len = max([len(s[0]) for s in topics])
2886 for t, desc in topics:
2886 for t, desc in topics:
2887 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2887 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2888
2888
2889 ui.write(opttext(optlist, textwidth))
2889 ui.write(opttext(optlist, textwidth))
2890
2890
2891 @command('identify|id',
2891 @command('identify|id',
2892 [('r', 'rev', '',
2892 [('r', 'rev', '',
2893 _('identify the specified revision'), _('REV')),
2893 _('identify the specified revision'), _('REV')),
2894 ('n', 'num', None, _('show local revision number')),
2894 ('n', 'num', None, _('show local revision number')),
2895 ('i', 'id', None, _('show global revision id')),
2895 ('i', 'id', None, _('show global revision id')),
2896 ('b', 'branch', None, _('show branch')),
2896 ('b', 'branch', None, _('show branch')),
2897 ('t', 'tags', None, _('show tags')),
2897 ('t', 'tags', None, _('show tags')),
2898 ('B', 'bookmarks', None, _('show bookmarks'))],
2898 ('B', 'bookmarks', None, _('show bookmarks'))],
2899 _('[-nibtB] [-r REV] [SOURCE]'))
2899 _('[-nibtB] [-r REV] [SOURCE]'))
2900 def identify(ui, repo, source=None, rev=None,
2900 def identify(ui, repo, source=None, rev=None,
2901 num=None, id=None, branch=None, tags=None, bookmarks=None):
2901 num=None, id=None, branch=None, tags=None, bookmarks=None):
2902 """identify the working copy or specified revision
2902 """identify the working copy or specified revision
2903
2903
2904 Print a summary identifying the repository state at REV using one or
2904 Print a summary identifying the repository state at REV using one or
2905 two parent hash identifiers, followed by a "+" if the working
2905 two parent hash identifiers, followed by a "+" if the working
2906 directory has uncommitted changes, the branch name (if not default),
2906 directory has uncommitted changes, the branch name (if not default),
2907 a list of tags, and a list of bookmarks.
2907 a list of tags, and a list of bookmarks.
2908
2908
2909 When REV is not given, print a summary of the current state of the
2909 When REV is not given, print a summary of the current state of the
2910 repository.
2910 repository.
2911
2911
2912 Specifying a path to a repository root or Mercurial bundle will
2912 Specifying a path to a repository root or Mercurial bundle will
2913 cause lookup to operate on that repository/bundle.
2913 cause lookup to operate on that repository/bundle.
2914
2914
2915 Returns 0 if successful.
2915 Returns 0 if successful.
2916 """
2916 """
2917
2917
2918 if not repo and not source:
2918 if not repo and not source:
2919 raise util.Abort(_("there is no Mercurial repository here "
2919 raise util.Abort(_("there is no Mercurial repository here "
2920 "(.hg not found)"))
2920 "(.hg not found)"))
2921
2921
2922 hexfunc = ui.debugflag and hex or short
2922 hexfunc = ui.debugflag and hex or short
2923 default = not (num or id or branch or tags or bookmarks)
2923 default = not (num or id or branch or tags or bookmarks)
2924 output = []
2924 output = []
2925 revs = []
2925 revs = []
2926
2926
2927 if source:
2927 if source:
2928 source, branches = hg.parseurl(ui.expandpath(source))
2928 source, branches = hg.parseurl(ui.expandpath(source))
2929 repo = hg.peer(ui, {}, source)
2929 repo = hg.peer(ui, {}, source)
2930 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2930 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2931
2931
2932 if not repo.local():
2932 if not repo.local():
2933 if num or branch or tags:
2933 if num or branch or tags:
2934 raise util.Abort(
2934 raise util.Abort(
2935 _("can't query remote revision number, branch, or tags"))
2935 _("can't query remote revision number, branch, or tags"))
2936 if not rev and revs:
2936 if not rev and revs:
2937 rev = revs[0]
2937 rev = revs[0]
2938 if not rev:
2938 if not rev:
2939 rev = "tip"
2939 rev = "tip"
2940
2940
2941 remoterev = repo.lookup(rev)
2941 remoterev = repo.lookup(rev)
2942 if default or id:
2942 if default or id:
2943 output = [hexfunc(remoterev)]
2943 output = [hexfunc(remoterev)]
2944
2944
2945 def getbms():
2945 def getbms():
2946 bms = []
2946 bms = []
2947
2947
2948 if 'bookmarks' in repo.listkeys('namespaces'):
2948 if 'bookmarks' in repo.listkeys('namespaces'):
2949 hexremoterev = hex(remoterev)
2949 hexremoterev = hex(remoterev)
2950 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2950 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2951 if bmr == hexremoterev]
2951 if bmr == hexremoterev]
2952
2952
2953 return bms
2953 return bms
2954
2954
2955 if bookmarks:
2955 if bookmarks:
2956 output.extend(getbms())
2956 output.extend(getbms())
2957 elif default and not ui.quiet:
2957 elif default and not ui.quiet:
2958 # multiple bookmarks for a single parent separated by '/'
2958 # multiple bookmarks for a single parent separated by '/'
2959 bm = '/'.join(getbms())
2959 bm = '/'.join(getbms())
2960 if bm:
2960 if bm:
2961 output.append(bm)
2961 output.append(bm)
2962 else:
2962 else:
2963 if not rev:
2963 if not rev:
2964 ctx = repo[None]
2964 ctx = repo[None]
2965 parents = ctx.parents()
2965 parents = ctx.parents()
2966 changed = ""
2966 changed = ""
2967 if default or id or num:
2967 if default or id or num:
2968 changed = util.any(repo.status()) and "+" or ""
2968 changed = util.any(repo.status()) and "+" or ""
2969 if default or id:
2969 if default or id:
2970 output = ["%s%s" %
2970 output = ["%s%s" %
2971 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2971 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2972 if num:
2972 if num:
2973 output.append("%s%s" %
2973 output.append("%s%s" %
2974 ('+'.join([str(p.rev()) for p in parents]), changed))
2974 ('+'.join([str(p.rev()) for p in parents]), changed))
2975 else:
2975 else:
2976 ctx = scmutil.revsingle(repo, rev)
2976 ctx = scmutil.revsingle(repo, rev)
2977 if default or id:
2977 if default or id:
2978 output = [hexfunc(ctx.node())]
2978 output = [hexfunc(ctx.node())]
2979 if num:
2979 if num:
2980 output.append(str(ctx.rev()))
2980 output.append(str(ctx.rev()))
2981
2981
2982 if default and not ui.quiet:
2982 if default and not ui.quiet:
2983 b = ctx.branch()
2983 b = ctx.branch()
2984 if b != 'default':
2984 if b != 'default':
2985 output.append("(%s)" % b)
2985 output.append("(%s)" % b)
2986
2986
2987 # multiple tags for a single parent separated by '/'
2987 # multiple tags for a single parent separated by '/'
2988 t = '/'.join(ctx.tags())
2988 t = '/'.join(ctx.tags())
2989 if t:
2989 if t:
2990 output.append(t)
2990 output.append(t)
2991
2991
2992 # multiple bookmarks for a single parent separated by '/'
2992 # multiple bookmarks for a single parent separated by '/'
2993 bm = '/'.join(ctx.bookmarks())
2993 bm = '/'.join(ctx.bookmarks())
2994 if bm:
2994 if bm:
2995 output.append(bm)
2995 output.append(bm)
2996 else:
2996 else:
2997 if branch:
2997 if branch:
2998 output.append(ctx.branch())
2998 output.append(ctx.branch())
2999
2999
3000 if tags:
3000 if tags:
3001 output.extend(ctx.tags())
3001 output.extend(ctx.tags())
3002
3002
3003 if bookmarks:
3003 if bookmarks:
3004 output.extend(ctx.bookmarks())
3004 output.extend(ctx.bookmarks())
3005
3005
3006 ui.write("%s\n" % ' '.join(output))
3006 ui.write("%s\n" % ' '.join(output))
3007
3007
3008 @command('import|patch',
3008 @command('import|patch',
3009 [('p', 'strip', 1,
3009 [('p', 'strip', 1,
3010 _('directory strip option for patch. This has the same '
3010 _('directory strip option for patch. This has the same '
3011 'meaning as the corresponding patch option'), _('NUM')),
3011 'meaning as the corresponding patch option'), _('NUM')),
3012 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3012 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3013 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3013 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3014 ('', 'no-commit', None,
3014 ('', 'no-commit', None,
3015 _("don't commit, just update the working directory")),
3015 _("don't commit, just update the working directory")),
3016 ('', 'bypass', None,
3016 ('', 'bypass', None,
3017 _("apply patch without touching the working directory")),
3017 _("apply patch without touching the working directory")),
3018 ('', 'exact', None,
3018 ('', 'exact', None,
3019 _('apply patch to the nodes from which it was generated')),
3019 _('apply patch to the nodes from which it was generated')),
3020 ('', 'import-branch', None,
3020 ('', 'import-branch', None,
3021 _('use any branch information in patch (implied by --exact)'))] +
3021 _('use any branch information in patch (implied by --exact)'))] +
3022 commitopts + commitopts2 + similarityopts,
3022 commitopts + commitopts2 + similarityopts,
3023 _('[OPTION]... PATCH...'))
3023 _('[OPTION]... PATCH...'))
3024 def import_(ui, repo, patch1, *patches, **opts):
3024 def import_(ui, repo, patch1, *patches, **opts):
3025 """import an ordered set of patches
3025 """import an ordered set of patches
3026
3026
3027 Import a list of patches and commit them individually (unless
3027 Import a list of patches and commit them individually (unless
3028 --no-commit is specified).
3028 --no-commit is specified).
3029
3029
3030 If there are outstanding changes in the working directory, import
3030 If there are outstanding changes in the working directory, import
3031 will abort unless given the -f/--force flag.
3031 will abort unless given the -f/--force flag.
3032
3032
3033 You can import a patch straight from a mail message. Even patches
3033 You can import a patch straight from a mail message. Even patches
3034 as attachments work (to use the body part, it must have type
3034 as attachments work (to use the body part, it must have type
3035 text/plain or text/x-patch). From and Subject headers of email
3035 text/plain or text/x-patch). From and Subject headers of email
3036 message are used as default committer and commit message. All
3036 message are used as default committer and commit message. All
3037 text/plain body parts before first diff are added to commit
3037 text/plain body parts before first diff are added to commit
3038 message.
3038 message.
3039
3039
3040 If the imported patch was generated by :hg:`export`, user and
3040 If the imported patch was generated by :hg:`export`, user and
3041 description from patch override values from message headers and
3041 description from patch override values from message headers and
3042 body. Values given on command line with -m/--message and -u/--user
3042 body. Values given on command line with -m/--message and -u/--user
3043 override these.
3043 override these.
3044
3044
3045 If --exact is specified, import will set the working directory to
3045 If --exact is specified, import will set the working directory to
3046 the parent of each patch before applying it, and will abort if the
3046 the parent of each patch before applying it, and will abort if the
3047 resulting changeset has a different ID than the one recorded in
3047 resulting changeset has a different ID than the one recorded in
3048 the patch. This may happen due to character set problems or other
3048 the patch. This may happen due to character set problems or other
3049 deficiencies in the text patch format.
3049 deficiencies in the text patch format.
3050
3050
3051 Use --bypass to apply and commit patches directly to the
3051 Use --bypass to apply and commit patches directly to the
3052 repository, not touching the working directory. Without --exact,
3052 repository, not touching the working directory. Without --exact,
3053 patches will be applied on top of the working directory parent
3053 patches will be applied on top of the working directory parent
3054 revision.
3054 revision.
3055
3055
3056 With -s/--similarity, hg will attempt to discover renames and
3056 With -s/--similarity, hg will attempt to discover renames and
3057 copies in the patch in the same way as 'addremove'.
3057 copies in the patch in the same way as 'addremove'.
3058
3058
3059 To read a patch from standard input, use "-" as the patch name. If
3059 To read a patch from standard input, use "-" as the patch name. If
3060 a URL is specified, the patch will be downloaded from it.
3060 a URL is specified, the patch will be downloaded from it.
3061 See :hg:`help dates` for a list of formats valid for -d/--date.
3061 See :hg:`help dates` for a list of formats valid for -d/--date.
3062
3062
3063 Returns 0 on success.
3063 Returns 0 on success.
3064 """
3064 """
3065 patches = (patch1,) + patches
3065 patches = (patch1,) + patches
3066
3066
3067 date = opts.get('date')
3067 date = opts.get('date')
3068 if date:
3068 if date:
3069 opts['date'] = util.parsedate(date)
3069 opts['date'] = util.parsedate(date)
3070
3070
3071 update = not opts.get('bypass')
3071 update = not opts.get('bypass')
3072 if not update and opts.get('no_commit'):
3072 if not update and opts.get('no_commit'):
3073 raise util.Abort(_('cannot use --no-commit with --bypass'))
3073 raise util.Abort(_('cannot use --no-commit with --bypass'))
3074 try:
3074 try:
3075 sim = float(opts.get('similarity') or 0)
3075 sim = float(opts.get('similarity') or 0)
3076 except ValueError:
3076 except ValueError:
3077 raise util.Abort(_('similarity must be a number'))
3077 raise util.Abort(_('similarity must be a number'))
3078 if sim < 0 or sim > 100:
3078 if sim < 0 or sim > 100:
3079 raise util.Abort(_('similarity must be between 0 and 100'))
3079 raise util.Abort(_('similarity must be between 0 and 100'))
3080 if sim and not update:
3080 if sim and not update:
3081 raise util.Abort(_('cannot use --similarity with --bypass'))
3081 raise util.Abort(_('cannot use --similarity with --bypass'))
3082
3082
3083 if (opts.get('exact') or not opts.get('force')) and update:
3083 if (opts.get('exact') or not opts.get('force')) and update:
3084 cmdutil.bailifchanged(repo)
3084 cmdutil.bailifchanged(repo)
3085
3085
3086 d = opts["base"]
3086 d = opts["base"]
3087 strip = opts["strip"]
3087 strip = opts["strip"]
3088 wlock = lock = None
3088 wlock = lock = None
3089 msgs = []
3089 msgs = []
3090
3090
3091 def checkexact(repo, n, nodeid):
3091 def checkexact(repo, n, nodeid):
3092 if opts.get('exact') and hex(n) != nodeid:
3092 if opts.get('exact') and hex(n) != nodeid:
3093 repo.rollback()
3093 repo.rollback()
3094 raise util.Abort(_('patch is damaged or loses information'))
3094 raise util.Abort(_('patch is damaged or loses information'))
3095
3095
3096 def tryone(ui, hunk, parents):
3096 def tryone(ui, hunk, parents):
3097 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3097 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3098 patch.extract(ui, hunk)
3098 patch.extract(ui, hunk)
3099
3099
3100 if not tmpname:
3100 if not tmpname:
3101 return None
3101 return None
3102 commitid = _('to working directory')
3102 commitid = _('to working directory')
3103
3103
3104 try:
3104 try:
3105 cmdline_message = cmdutil.logmessage(ui, opts)
3105 cmdline_message = cmdutil.logmessage(ui, opts)
3106 if cmdline_message:
3106 if cmdline_message:
3107 # pickup the cmdline msg
3107 # pickup the cmdline msg
3108 message = cmdline_message
3108 message = cmdline_message
3109 elif message:
3109 elif message:
3110 # pickup the patch msg
3110 # pickup the patch msg
3111 message = message.strip()
3111 message = message.strip()
3112 else:
3112 else:
3113 # launch the editor
3113 # launch the editor
3114 message = None
3114 message = None
3115 ui.debug('message:\n%s\n' % message)
3115 ui.debug('message:\n%s\n' % message)
3116
3116
3117 if len(parents) == 1:
3117 if len(parents) == 1:
3118 parents.append(repo[nullid])
3118 parents.append(repo[nullid])
3119 if opts.get('exact'):
3119 if opts.get('exact'):
3120 if not nodeid or not p1:
3120 if not nodeid or not p1:
3121 raise util.Abort(_('not a Mercurial patch'))
3121 raise util.Abort(_('not a Mercurial patch'))
3122 p1 = repo[p1]
3122 p1 = repo[p1]
3123 p2 = repo[p2 or nullid]
3123 p2 = repo[p2 or nullid]
3124 elif p2:
3124 elif p2:
3125 try:
3125 try:
3126 p1 = repo[p1]
3126 p1 = repo[p1]
3127 p2 = repo[p2]
3127 p2 = repo[p2]
3128 except error.RepoError:
3128 except error.RepoError:
3129 p1, p2 = parents
3129 p1, p2 = parents
3130 else:
3130 else:
3131 p1, p2 = parents
3131 p1, p2 = parents
3132
3132
3133 n = None
3133 n = None
3134 if update:
3134 if update:
3135 if opts.get('exact') and p1 != parents[0]:
3135 if opts.get('exact') and p1 != parents[0]:
3136 hg.clean(repo, p1.node())
3136 hg.clean(repo, p1.node())
3137 if p1 != parents[0] and p2 != parents[1]:
3137 if p1 != parents[0] and p2 != parents[1]:
3138 repo.dirstate.setparents(p1.node(), p2.node())
3138 repo.dirstate.setparents(p1.node(), p2.node())
3139
3139
3140 if opts.get('exact') or opts.get('import_branch'):
3140 if opts.get('exact') or opts.get('import_branch'):
3141 repo.dirstate.setbranch(branch or 'default')
3141 repo.dirstate.setbranch(branch or 'default')
3142
3142
3143 files = set()
3143 files = set()
3144 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3144 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3145 eolmode=None, similarity=sim / 100.0)
3145 eolmode=None, similarity=sim / 100.0)
3146 files = list(files)
3146 files = list(files)
3147 if opts.get('no_commit'):
3147 if opts.get('no_commit'):
3148 if message:
3148 if message:
3149 msgs.append(message)
3149 msgs.append(message)
3150 else:
3150 else:
3151 if opts.get('exact'):
3151 if opts.get('exact'):
3152 m = None
3152 m = None
3153 else:
3153 else:
3154 m = scmutil.matchfiles(repo, files or [])
3154 m = scmutil.matchfiles(repo, files or [])
3155 n = repo.commit(message, opts.get('user') or user,
3155 n = repo.commit(message, opts.get('user') or user,
3156 opts.get('date') or date, match=m,
3156 opts.get('date') or date, match=m,
3157 editor=cmdutil.commiteditor)
3157 editor=cmdutil.commiteditor)
3158 checkexact(repo, n, nodeid)
3158 checkexact(repo, n, nodeid)
3159 # Force a dirstate write so that the next transaction
3159 # Force a dirstate write so that the next transaction
3160 # backups an up-to-date file.
3160 # backups an up-to-date file.
3161 repo.dirstate.write()
3161 repo.dirstate.write()
3162 else:
3162 else:
3163 if opts.get('exact') or opts.get('import_branch'):
3163 if opts.get('exact') or opts.get('import_branch'):
3164 branch = branch or 'default'
3164 branch = branch or 'default'
3165 else:
3165 else:
3166 branch = p1.branch()
3166 branch = p1.branch()
3167 store = patch.filestore()
3167 store = patch.filestore()
3168 try:
3168 try:
3169 files = set()
3169 files = set()
3170 try:
3170 try:
3171 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3171 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3172 files, eolmode=None)
3172 files, eolmode=None)
3173 except patch.PatchError, e:
3173 except patch.PatchError, e:
3174 raise util.Abort(str(e))
3174 raise util.Abort(str(e))
3175 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3175 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3176 message,
3176 message,
3177 opts.get('user') or user,
3177 opts.get('user') or user,
3178 opts.get('date') or date,
3178 opts.get('date') or date,
3179 branch, files, store,
3179 branch, files, store,
3180 editor=cmdutil.commiteditor)
3180 editor=cmdutil.commiteditor)
3181 repo.savecommitmessage(memctx.description())
3181 repo.savecommitmessage(memctx.description())
3182 n = memctx.commit()
3182 n = memctx.commit()
3183 checkexact(repo, n, nodeid)
3183 checkexact(repo, n, nodeid)
3184 finally:
3184 finally:
3185 store.close()
3185 store.close()
3186 if n:
3186 if n:
3187 commitid = short(n)
3187 commitid = short(n)
3188 return commitid
3188 return commitid
3189 finally:
3189 finally:
3190 os.unlink(tmpname)
3190 os.unlink(tmpname)
3191
3191
3192 try:
3192 try:
3193 wlock = repo.wlock()
3193 wlock = repo.wlock()
3194 lock = repo.lock()
3194 lock = repo.lock()
3195 parents = repo.parents()
3195 parents = repo.parents()
3196 lastcommit = None
3196 lastcommit = None
3197 for p in patches:
3197 for p in patches:
3198 pf = os.path.join(d, p)
3198 pf = os.path.join(d, p)
3199
3199
3200 if pf == '-':
3200 if pf == '-':
3201 ui.status(_("applying patch from stdin\n"))
3201 ui.status(_("applying patch from stdin\n"))
3202 pf = ui.fin
3202 pf = ui.fin
3203 else:
3203 else:
3204 ui.status(_("applying %s\n") % p)
3204 ui.status(_("applying %s\n") % p)
3205 pf = url.open(ui, pf)
3205 pf = url.open(ui, pf)
3206
3206
3207 haspatch = False
3207 haspatch = False
3208 for hunk in patch.split(pf):
3208 for hunk in patch.split(pf):
3209 commitid = tryone(ui, hunk, parents)
3209 commitid = tryone(ui, hunk, parents)
3210 if commitid:
3210 if commitid:
3211 haspatch = True
3211 haspatch = True
3212 if lastcommit:
3212 if lastcommit:
3213 ui.status(_('applied %s\n') % lastcommit)
3213 ui.status(_('applied %s\n') % lastcommit)
3214 lastcommit = commitid
3214 lastcommit = commitid
3215 if update or opts.get('exact'):
3215 if update or opts.get('exact'):
3216 parents = repo.parents()
3216 parents = repo.parents()
3217 else:
3217 else:
3218 parents = [repo[commitid]]
3218 parents = [repo[commitid]]
3219
3219
3220 if not haspatch:
3220 if not haspatch:
3221 raise util.Abort(_('no diffs found'))
3221 raise util.Abort(_('no diffs found'))
3222
3222
3223 if msgs:
3223 if msgs:
3224 repo.savecommitmessage('\n* * *\n'.join(msgs))
3224 repo.savecommitmessage('\n* * *\n'.join(msgs))
3225 finally:
3225 finally:
3226 release(lock, wlock)
3226 release(lock, wlock)
3227
3227
3228 @command('incoming|in',
3228 @command('incoming|in',
3229 [('f', 'force', None,
3229 [('f', 'force', None,
3230 _('run even if remote repository is unrelated')),
3230 _('run even if remote repository is unrelated')),
3231 ('n', 'newest-first', None, _('show newest record first')),
3231 ('n', 'newest-first', None, _('show newest record first')),
3232 ('', 'bundle', '',
3232 ('', 'bundle', '',
3233 _('file to store the bundles into'), _('FILE')),
3233 _('file to store the bundles into'), _('FILE')),
3234 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3234 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3235 ('B', 'bookmarks', False, _("compare bookmarks")),
3235 ('B', 'bookmarks', False, _("compare bookmarks")),
3236 ('b', 'branch', [],
3236 ('b', 'branch', [],
3237 _('a specific branch you would like to pull'), _('BRANCH')),
3237 _('a specific branch you would like to pull'), _('BRANCH')),
3238 ] + logopts + remoteopts + subrepoopts,
3238 ] + logopts + remoteopts + subrepoopts,
3239 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3239 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3240 def incoming(ui, repo, source="default", **opts):
3240 def incoming(ui, repo, source="default", **opts):
3241 """show new changesets found in source
3241 """show new changesets found in source
3242
3242
3243 Show new changesets found in the specified path/URL or the default
3243 Show new changesets found in the specified path/URL or the default
3244 pull location. These are the changesets that would have been pulled
3244 pull location. These are the changesets that would have been pulled
3245 if a pull at the time you issued this command.
3245 if a pull at the time you issued this command.
3246
3246
3247 For remote repository, using --bundle avoids downloading the
3247 For remote repository, using --bundle avoids downloading the
3248 changesets twice if the incoming is followed by a pull.
3248 changesets twice if the incoming is followed by a pull.
3249
3249
3250 See pull for valid source format details.
3250 See pull for valid source format details.
3251
3251
3252 Returns 0 if there are incoming changes, 1 otherwise.
3252 Returns 0 if there are incoming changes, 1 otherwise.
3253 """
3253 """
3254 if opts.get('bundle') and opts.get('subrepos'):
3254 if opts.get('bundle') and opts.get('subrepos'):
3255 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3255 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3256
3256
3257 if opts.get('bookmarks'):
3257 if opts.get('bookmarks'):
3258 source, branches = hg.parseurl(ui.expandpath(source),
3258 source, branches = hg.parseurl(ui.expandpath(source),
3259 opts.get('branch'))
3259 opts.get('branch'))
3260 other = hg.peer(repo, opts, source)
3260 other = hg.peer(repo, opts, source)
3261 if 'bookmarks' not in other.listkeys('namespaces'):
3261 if 'bookmarks' not in other.listkeys('namespaces'):
3262 ui.warn(_("remote doesn't support bookmarks\n"))
3262 ui.warn(_("remote doesn't support bookmarks\n"))
3263 return 0
3263 return 0
3264 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3264 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3265 return bookmarks.diff(ui, repo, other)
3265 return bookmarks.diff(ui, repo, other)
3266
3266
3267 repo._subtoppath = ui.expandpath(source)
3267 repo._subtoppath = ui.expandpath(source)
3268 try:
3268 try:
3269 return hg.incoming(ui, repo, source, opts)
3269 return hg.incoming(ui, repo, source, opts)
3270 finally:
3270 finally:
3271 del repo._subtoppath
3271 del repo._subtoppath
3272
3272
3273
3273
3274 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3274 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3275 def init(ui, dest=".", **opts):
3275 def init(ui, dest=".", **opts):
3276 """create a new repository in the given directory
3276 """create a new repository in the given directory
3277
3277
3278 Initialize a new repository in the given directory. If the given
3278 Initialize a new repository in the given directory. If the given
3279 directory does not exist, it will be created.
3279 directory does not exist, it will be created.
3280
3280
3281 If no directory is given, the current directory is used.
3281 If no directory is given, the current directory is used.
3282
3282
3283 It is possible to specify an ``ssh://`` URL as the destination.
3283 It is possible to specify an ``ssh://`` URL as the destination.
3284 See :hg:`help urls` for more information.
3284 See :hg:`help urls` for more information.
3285
3285
3286 Returns 0 on success.
3286 Returns 0 on success.
3287 """
3287 """
3288 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3288 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3289
3289
3290 @command('locate',
3290 @command('locate',
3291 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3291 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3292 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3292 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3293 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3293 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3294 ] + walkopts,
3294 ] + walkopts,
3295 _('[OPTION]... [PATTERN]...'))
3295 _('[OPTION]... [PATTERN]...'))
3296 def locate(ui, repo, *pats, **opts):
3296 def locate(ui, repo, *pats, **opts):
3297 """locate files matching specific patterns
3297 """locate files matching specific patterns
3298
3298
3299 Print files under Mercurial control in the working directory whose
3299 Print files under Mercurial control in the working directory whose
3300 names match the given patterns.
3300 names match the given patterns.
3301
3301
3302 By default, this command searches all directories in the working
3302 By default, this command searches all directories in the working
3303 directory. To search just the current directory and its
3303 directory. To search just the current directory and its
3304 subdirectories, use "--include .".
3304 subdirectories, use "--include .".
3305
3305
3306 If no patterns are given to match, this command prints the names
3306 If no patterns are given to match, this command prints the names
3307 of all files under Mercurial control in the working directory.
3307 of all files under Mercurial control in the working directory.
3308
3308
3309 If you want to feed the output of this command into the "xargs"
3309 If you want to feed the output of this command into the "xargs"
3310 command, use the -0 option to both this command and "xargs". This
3310 command, use the -0 option to both this command and "xargs". This
3311 will avoid the problem of "xargs" treating single filenames that
3311 will avoid the problem of "xargs" treating single filenames that
3312 contain whitespace as multiple filenames.
3312 contain whitespace as multiple filenames.
3313
3313
3314 Returns 0 if a match is found, 1 otherwise.
3314 Returns 0 if a match is found, 1 otherwise.
3315 """
3315 """
3316 end = opts.get('print0') and '\0' or '\n'
3316 end = opts.get('print0') and '\0' or '\n'
3317 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3317 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3318
3318
3319 ret = 1
3319 ret = 1
3320 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3320 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3321 m.bad = lambda x, y: False
3321 m.bad = lambda x, y: False
3322 for abs in repo[rev].walk(m):
3322 for abs in repo[rev].walk(m):
3323 if not rev and abs not in repo.dirstate:
3323 if not rev and abs not in repo.dirstate:
3324 continue
3324 continue
3325 if opts.get('fullpath'):
3325 if opts.get('fullpath'):
3326 ui.write(repo.wjoin(abs), end)
3326 ui.write(repo.wjoin(abs), end)
3327 else:
3327 else:
3328 ui.write(((pats and m.rel(abs)) or abs), end)
3328 ui.write(((pats and m.rel(abs)) or abs), end)
3329 ret = 0
3329 ret = 0
3330
3330
3331 return ret
3331 return ret
3332
3332
3333 @command('^log|history',
3333 @command('^log|history',
3334 [('f', 'follow', None,
3334 [('f', 'follow', None,
3335 _('follow changeset history, or file history across copies and renames')),
3335 _('follow changeset history, or file history across copies and renames')),
3336 ('', 'follow-first', None,
3336 ('', 'follow-first', None,
3337 _('only follow the first parent of merge changesets')),
3337 _('only follow the first parent of merge changesets')),
3338 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3338 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3339 ('C', 'copies', None, _('show copied files')),
3339 ('C', 'copies', None, _('show copied files')),
3340 ('k', 'keyword', [],
3340 ('k', 'keyword', [],
3341 _('do case-insensitive search for a given text'), _('TEXT')),
3341 _('do case-insensitive search for a given text'), _('TEXT')),
3342 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3342 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3343 ('', 'removed', None, _('include revisions where files were removed')),
3343 ('', 'removed', None, _('include revisions where files were removed')),
3344 ('m', 'only-merges', None, _('show only merges')),
3344 ('m', 'only-merges', None, _('show only merges')),
3345 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3345 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3346 ('', 'only-branch', [],
3346 ('', 'only-branch', [],
3347 _('show only changesets within the given named branch (DEPRECATED)'),
3347 _('show only changesets within the given named branch (DEPRECATED)'),
3348 _('BRANCH')),
3348 _('BRANCH')),
3349 ('b', 'branch', [],
3349 ('b', 'branch', [],
3350 _('show changesets within the given named branch'), _('BRANCH')),
3350 _('show changesets within the given named branch'), _('BRANCH')),
3351 ('P', 'prune', [],
3351 ('P', 'prune', [],
3352 _('do not display revision or any of its ancestors'), _('REV')),
3352 _('do not display revision or any of its ancestors'), _('REV')),
3353 ('h', 'hidden', False, _('show hidden changesets')),
3353 ('h', 'hidden', False, _('show hidden changesets')),
3354 ] + logopts + walkopts,
3354 ] + logopts + walkopts,
3355 _('[OPTION]... [FILE]'))
3355 _('[OPTION]... [FILE]'))
3356 def log(ui, repo, *pats, **opts):
3356 def log(ui, repo, *pats, **opts):
3357 """show revision history of entire repository or files
3357 """show revision history of entire repository or files
3358
3358
3359 Print the revision history of the specified files or the entire
3359 Print the revision history of the specified files or the entire
3360 project.
3360 project.
3361
3361
3362 File history is shown without following rename or copy history of
3362 File history is shown without following rename or copy history of
3363 files. Use -f/--follow with a filename to follow history across
3363 files. Use -f/--follow with a filename to follow history across
3364 renames and copies. --follow without a filename will only show
3364 renames and copies. --follow without a filename will only show
3365 ancestors or descendants of the starting revision. --follow-first
3365 ancestors or descendants of the starting revision. --follow-first
3366 only follows the first parent of merge revisions.
3366 only follows the first parent of merge revisions.
3367
3367
3368 If no revision range is specified, the default is ``tip:0`` unless
3368 If no revision range is specified, the default is ``tip:0`` unless
3369 --follow is set, in which case the working directory parent is
3369 --follow is set, in which case the working directory parent is
3370 used as the starting revision. You can specify a revision set for
3370 used as the starting revision. You can specify a revision set for
3371 log, see :hg:`help revsets` for more information.
3371 log, see :hg:`help revsets` for more information.
3372
3372
3373 See :hg:`help dates` for a list of formats valid for -d/--date.
3373 See :hg:`help dates` for a list of formats valid for -d/--date.
3374
3374
3375 By default this command prints revision number and changeset id,
3375 By default this command prints revision number and changeset id,
3376 tags, non-trivial parents, user, date and time, and a summary for
3376 tags, non-trivial parents, user, date and time, and a summary for
3377 each commit. When the -v/--verbose switch is used, the list of
3377 each commit. When the -v/--verbose switch is used, the list of
3378 changed files and full commit message are shown.
3378 changed files and full commit message are shown.
3379
3379
3380 .. note::
3380 .. note::
3381 log -p/--patch may generate unexpected diff output for merge
3381 log -p/--patch may generate unexpected diff output for merge
3382 changesets, as it will only compare the merge changeset against
3382 changesets, as it will only compare the merge changeset against
3383 its first parent. Also, only files different from BOTH parents
3383 its first parent. Also, only files different from BOTH parents
3384 will appear in files:.
3384 will appear in files:.
3385
3385
3386 Returns 0 on success.
3386 Returns 0 on success.
3387 """
3387 """
3388
3388
3389 matchfn = scmutil.match(repo[None], pats, opts)
3389 matchfn = scmutil.match(repo[None], pats, opts)
3390 limit = cmdutil.loglimit(opts)
3390 limit = cmdutil.loglimit(opts)
3391 count = 0
3391 count = 0
3392
3392
3393 endrev = None
3393 endrev = None
3394 if opts.get('copies') and opts.get('rev'):
3394 if opts.get('copies') and opts.get('rev'):
3395 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3395 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3396
3396
3397 df = False
3397 df = False
3398 if opts["date"]:
3398 if opts["date"]:
3399 df = util.matchdate(opts["date"])
3399 df = util.matchdate(opts["date"])
3400
3400
3401 branches = opts.get('branch', []) + opts.get('only_branch', [])
3401 branches = opts.get('branch', []) + opts.get('only_branch', [])
3402 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3402 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3403
3403
3404 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3404 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3405 def prep(ctx, fns):
3405 def prep(ctx, fns):
3406 rev = ctx.rev()
3406 rev = ctx.rev()
3407 parents = [p for p in repo.changelog.parentrevs(rev)
3407 parents = [p for p in repo.changelog.parentrevs(rev)
3408 if p != nullrev]
3408 if p != nullrev]
3409 if opts.get('no_merges') and len(parents) == 2:
3409 if opts.get('no_merges') and len(parents) == 2:
3410 return
3410 return
3411 if opts.get('only_merges') and len(parents) != 2:
3411 if opts.get('only_merges') and len(parents) != 2:
3412 return
3412 return
3413 if opts.get('branch') and ctx.branch() not in opts['branch']:
3413 if opts.get('branch') and ctx.branch() not in opts['branch']:
3414 return
3414 return
3415 if not opts.get('hidden') and ctx.hidden():
3415 if not opts.get('hidden') and ctx.hidden():
3416 return
3416 return
3417 if df and not df(ctx.date()[0]):
3417 if df and not df(ctx.date()[0]):
3418 return
3418 return
3419 if opts['user'] and not [k for k in opts['user']
3419 if opts['user'] and not [k for k in opts['user']
3420 if k.lower() in ctx.user().lower()]:
3420 if k.lower() in ctx.user().lower()]:
3421 return
3421 return
3422 if opts.get('keyword'):
3422 if opts.get('keyword'):
3423 for k in [kw.lower() for kw in opts['keyword']]:
3423 for k in [kw.lower() for kw in opts['keyword']]:
3424 if (k in ctx.user().lower() or
3424 if (k in ctx.user().lower() or
3425 k in ctx.description().lower() or
3425 k in ctx.description().lower() or
3426 k in " ".join(ctx.files()).lower()):
3426 k in " ".join(ctx.files()).lower()):
3427 break
3427 break
3428 else:
3428 else:
3429 return
3429 return
3430
3430
3431 copies = None
3431 copies = None
3432 if opts.get('copies') and rev:
3432 if opts.get('copies') and rev:
3433 copies = []
3433 copies = []
3434 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3434 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3435 for fn in ctx.files():
3435 for fn in ctx.files():
3436 rename = getrenamed(fn, rev)
3436 rename = getrenamed(fn, rev)
3437 if rename:
3437 if rename:
3438 copies.append((fn, rename[0]))
3438 copies.append((fn, rename[0]))
3439
3439
3440 revmatchfn = None
3440 revmatchfn = None
3441 if opts.get('patch') or opts.get('stat'):
3441 if opts.get('patch') or opts.get('stat'):
3442 if opts.get('follow') or opts.get('follow_first'):
3442 if opts.get('follow') or opts.get('follow_first'):
3443 # note: this might be wrong when following through merges
3443 # note: this might be wrong when following through merges
3444 revmatchfn = scmutil.match(repo[None], fns, default='path')
3444 revmatchfn = scmutil.match(repo[None], fns, default='path')
3445 else:
3445 else:
3446 revmatchfn = matchfn
3446 revmatchfn = matchfn
3447
3447
3448 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3448 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3449
3449
3450 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3450 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3451 if count == limit:
3451 if count == limit:
3452 break
3452 break
3453 if displayer.flush(ctx.rev()):
3453 if displayer.flush(ctx.rev()):
3454 count += 1
3454 count += 1
3455 displayer.close()
3455 displayer.close()
3456
3456
3457 @command('manifest',
3457 @command('manifest',
3458 [('r', 'rev', '', _('revision to display'), _('REV')),
3458 [('r', 'rev', '', _('revision to display'), _('REV')),
3459 ('', 'all', False, _("list files from all revisions"))],
3459 ('', 'all', False, _("list files from all revisions"))],
3460 _('[-r REV]'))
3460 _('[-r REV]'))
3461 def manifest(ui, repo, node=None, rev=None, **opts):
3461 def manifest(ui, repo, node=None, rev=None, **opts):
3462 """output the current or given revision of the project manifest
3462 """output the current or given revision of the project manifest
3463
3463
3464 Print a list of version controlled files for the given revision.
3464 Print a list of version controlled files for the given revision.
3465 If no revision is given, the first parent of the working directory
3465 If no revision is given, the first parent of the working directory
3466 is used, or the null revision if no revision is checked out.
3466 is used, or the null revision if no revision is checked out.
3467
3467
3468 With -v, print file permissions, symlink and executable bits.
3468 With -v, print file permissions, symlink and executable bits.
3469 With --debug, print file revision hashes.
3469 With --debug, print file revision hashes.
3470
3470
3471 If option --all is specified, the list of all files from all revisions
3471 If option --all is specified, the list of all files from all revisions
3472 is printed. This includes deleted and renamed files.
3472 is printed. This includes deleted and renamed files.
3473
3473
3474 Returns 0 on success.
3474 Returns 0 on success.
3475 """
3475 """
3476 if opts.get('all'):
3476 if opts.get('all'):
3477 if rev or node:
3477 if rev or node:
3478 raise util.Abort(_("can't specify a revision with --all"))
3478 raise util.Abort(_("can't specify a revision with --all"))
3479
3479
3480 res = []
3480 res = []
3481 prefix = "data/"
3481 prefix = "data/"
3482 suffix = ".i"
3482 suffix = ".i"
3483 plen = len(prefix)
3483 plen = len(prefix)
3484 slen = len(suffix)
3484 slen = len(suffix)
3485 lock = repo.lock()
3485 lock = repo.lock()
3486 try:
3486 try:
3487 for fn, b, size in repo.store.datafiles():
3487 for fn, b, size in repo.store.datafiles():
3488 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3488 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3489 res.append(fn[plen:-slen])
3489 res.append(fn[plen:-slen])
3490 finally:
3490 finally:
3491 lock.release()
3491 lock.release()
3492 for f in sorted(res):
3492 for f in sorted(res):
3493 ui.write("%s\n" % f)
3493 ui.write("%s\n" % f)
3494 return
3494 return
3495
3495
3496 if rev and node:
3496 if rev and node:
3497 raise util.Abort(_("please specify just one revision"))
3497 raise util.Abort(_("please specify just one revision"))
3498
3498
3499 if not node:
3499 if not node:
3500 node = rev
3500 node = rev
3501
3501
3502 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3502 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3503 ctx = scmutil.revsingle(repo, node)
3503 ctx = scmutil.revsingle(repo, node)
3504 for f in ctx:
3504 for f in ctx:
3505 if ui.debugflag:
3505 if ui.debugflag:
3506 ui.write("%40s " % hex(ctx.manifest()[f]))
3506 ui.write("%40s " % hex(ctx.manifest()[f]))
3507 if ui.verbose:
3507 if ui.verbose:
3508 ui.write(decor[ctx.flags(f)])
3508 ui.write(decor[ctx.flags(f)])
3509 ui.write("%s\n" % f)
3509 ui.write("%s\n" % f)
3510
3510
3511 @command('^merge',
3511 @command('^merge',
3512 [('f', 'force', None, _('force a merge with outstanding changes')),
3512 [('f', 'force', None, _('force a merge with outstanding changes')),
3513 ('r', 'rev', '', _('revision to merge'), _('REV')),
3513 ('r', 'rev', '', _('revision to merge'), _('REV')),
3514 ('P', 'preview', None,
3514 ('P', 'preview', None,
3515 _('review revisions to merge (no merge is performed)'))
3515 _('review revisions to merge (no merge is performed)'))
3516 ] + mergetoolopts,
3516 ] + mergetoolopts,
3517 _('[-P] [-f] [[-r] REV]'))
3517 _('[-P] [-f] [[-r] REV]'))
3518 def merge(ui, repo, node=None, **opts):
3518 def merge(ui, repo, node=None, **opts):
3519 """merge working directory with another revision
3519 """merge working directory with another revision
3520
3520
3521 The current working directory is updated with all changes made in
3521 The current working directory is updated with all changes made in
3522 the requested revision since the last common predecessor revision.
3522 the requested revision since the last common predecessor revision.
3523
3523
3524 Files that changed between either parent are marked as changed for
3524 Files that changed between either parent are marked as changed for
3525 the next commit and a commit must be performed before any further
3525 the next commit and a commit must be performed before any further
3526 updates to the repository are allowed. The next commit will have
3526 updates to the repository are allowed. The next commit will have
3527 two parents.
3527 two parents.
3528
3528
3529 ``--tool`` can be used to specify the merge tool used for file
3529 ``--tool`` can be used to specify the merge tool used for file
3530 merges. It overrides the HGMERGE environment variable and your
3530 merges. It overrides the HGMERGE environment variable and your
3531 configuration files. See :hg:`help merge-tools` for options.
3531 configuration files. See :hg:`help merge-tools` for options.
3532
3532
3533 If no revision is specified, the working directory's parent is a
3533 If no revision is specified, the working directory's parent is a
3534 head revision, and the current branch contains exactly one other
3534 head revision, and the current branch contains exactly one other
3535 head, the other head is merged with by default. Otherwise, an
3535 head, the other head is merged with by default. Otherwise, an
3536 explicit revision with which to merge with must be provided.
3536 explicit revision with which to merge with must be provided.
3537
3537
3538 :hg:`resolve` must be used to resolve unresolved files.
3538 :hg:`resolve` must be used to resolve unresolved files.
3539
3539
3540 To undo an uncommitted merge, use :hg:`update --clean .` which
3540 To undo an uncommitted merge, use :hg:`update --clean .` which
3541 will check out a clean copy of the original merge parent, losing
3541 will check out a clean copy of the original merge parent, losing
3542 all changes.
3542 all changes.
3543
3543
3544 Returns 0 on success, 1 if there are unresolved files.
3544 Returns 0 on success, 1 if there are unresolved files.
3545 """
3545 """
3546
3546
3547 if opts.get('rev') and node:
3547 if opts.get('rev') and node:
3548 raise util.Abort(_("please specify just one revision"))
3548 raise util.Abort(_("please specify just one revision"))
3549 if not node:
3549 if not node:
3550 node = opts.get('rev')
3550 node = opts.get('rev')
3551
3551
3552 if not node:
3552 if not node:
3553 branch = repo[None].branch()
3553 branch = repo[None].branch()
3554 bheads = repo.branchheads(branch)
3554 bheads = repo.branchheads(branch)
3555 if len(bheads) > 2:
3555 if len(bheads) > 2:
3556 raise util.Abort(_("branch '%s' has %d heads - "
3556 raise util.Abort(_("branch '%s' has %d heads - "
3557 "please merge with an explicit rev")
3557 "please merge with an explicit rev")
3558 % (branch, len(bheads)),
3558 % (branch, len(bheads)),
3559 hint=_("run 'hg heads .' to see heads"))
3559 hint=_("run 'hg heads .' to see heads"))
3560
3560
3561 parent = repo.dirstate.p1()
3561 parent = repo.dirstate.p1()
3562 if len(bheads) == 1:
3562 if len(bheads) == 1:
3563 if len(repo.heads()) > 1:
3563 if len(repo.heads()) > 1:
3564 raise util.Abort(_("branch '%s' has one head - "
3564 raise util.Abort(_("branch '%s' has one head - "
3565 "please merge with an explicit rev")
3565 "please merge with an explicit rev")
3566 % branch,
3566 % branch,
3567 hint=_("run 'hg heads' to see all heads"))
3567 hint=_("run 'hg heads' to see all heads"))
3568 msg = _('there is nothing to merge')
3568 msg = _('there is nothing to merge')
3569 if parent != repo.lookup(repo[None].branch()):
3569 if parent != repo.lookup(repo[None].branch()):
3570 msg = _('%s - use "hg update" instead') % msg
3570 msg = _('%s - use "hg update" instead') % msg
3571 raise util.Abort(msg)
3571 raise util.Abort(msg)
3572
3572
3573 if parent not in bheads:
3573 if parent not in bheads:
3574 raise util.Abort(_('working directory not at a head revision'),
3574 raise util.Abort(_('working directory not at a head revision'),
3575 hint=_("use 'hg update' or merge with an "
3575 hint=_("use 'hg update' or merge with an "
3576 "explicit revision"))
3576 "explicit revision"))
3577 node = parent == bheads[0] and bheads[-1] or bheads[0]
3577 node = parent == bheads[0] and bheads[-1] or bheads[0]
3578 else:
3578 else:
3579 node = scmutil.revsingle(repo, node).node()
3579 node = scmutil.revsingle(repo, node).node()
3580
3580
3581 if opts.get('preview'):
3581 if opts.get('preview'):
3582 # find nodes that are ancestors of p2 but not of p1
3582 # find nodes that are ancestors of p2 but not of p1
3583 p1 = repo.lookup('.')
3583 p1 = repo.lookup('.')
3584 p2 = repo.lookup(node)
3584 p2 = repo.lookup(node)
3585 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3585 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3586
3586
3587 displayer = cmdutil.show_changeset(ui, repo, opts)
3587 displayer = cmdutil.show_changeset(ui, repo, opts)
3588 for node in nodes:
3588 for node in nodes:
3589 displayer.show(repo[node])
3589 displayer.show(repo[node])
3590 displayer.close()
3590 displayer.close()
3591 return 0
3591 return 0
3592
3592
3593 try:
3593 try:
3594 # ui.forcemerge is an internal variable, do not document
3594 # ui.forcemerge is an internal variable, do not document
3595 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3595 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3596 return hg.merge(repo, node, force=opts.get('force'))
3596 return hg.merge(repo, node, force=opts.get('force'))
3597 finally:
3597 finally:
3598 ui.setconfig('ui', 'forcemerge', '')
3598 ui.setconfig('ui', 'forcemerge', '')
3599
3599
3600 @command('outgoing|out',
3600 @command('outgoing|out',
3601 [('f', 'force', None, _('run even when the destination is unrelated')),
3601 [('f', 'force', None, _('run even when the destination is unrelated')),
3602 ('r', 'rev', [],
3602 ('r', 'rev', [],
3603 _('a changeset intended to be included in the destination'), _('REV')),
3603 _('a changeset intended to be included in the destination'), _('REV')),
3604 ('n', 'newest-first', None, _('show newest record first')),
3604 ('n', 'newest-first', None, _('show newest record first')),
3605 ('B', 'bookmarks', False, _('compare bookmarks')),
3605 ('B', 'bookmarks', False, _('compare bookmarks')),
3606 ('b', 'branch', [], _('a specific branch you would like to push'),
3606 ('b', 'branch', [], _('a specific branch you would like to push'),
3607 _('BRANCH')),
3607 _('BRANCH')),
3608 ] + logopts + remoteopts + subrepoopts,
3608 ] + logopts + remoteopts + subrepoopts,
3609 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3609 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3610 def outgoing(ui, repo, dest=None, **opts):
3610 def outgoing(ui, repo, dest=None, **opts):
3611 """show changesets not found in the destination
3611 """show changesets not found in the destination
3612
3612
3613 Show changesets not found in the specified destination repository
3613 Show changesets not found in the specified destination repository
3614 or the default push location. These are the changesets that would
3614 or the default push location. These are the changesets that would
3615 be pushed if a push was requested.
3615 be pushed if a push was requested.
3616
3616
3617 See pull for details of valid destination formats.
3617 See pull for details of valid destination formats.
3618
3618
3619 Returns 0 if there are outgoing changes, 1 otherwise.
3619 Returns 0 if there are outgoing changes, 1 otherwise.
3620 """
3620 """
3621
3621
3622 if opts.get('bookmarks'):
3622 if opts.get('bookmarks'):
3623 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3623 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3624 dest, branches = hg.parseurl(dest, opts.get('branch'))
3624 dest, branches = hg.parseurl(dest, opts.get('branch'))
3625 other = hg.peer(repo, opts, dest)
3625 other = hg.peer(repo, opts, dest)
3626 if 'bookmarks' not in other.listkeys('namespaces'):
3626 if 'bookmarks' not in other.listkeys('namespaces'):
3627 ui.warn(_("remote doesn't support bookmarks\n"))
3627 ui.warn(_("remote doesn't support bookmarks\n"))
3628 return 0
3628 return 0
3629 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3629 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3630 return bookmarks.diff(ui, other, repo)
3630 return bookmarks.diff(ui, other, repo)
3631
3631
3632 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3632 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3633 try:
3633 try:
3634 return hg.outgoing(ui, repo, dest, opts)
3634 return hg.outgoing(ui, repo, dest, opts)
3635 finally:
3635 finally:
3636 del repo._subtoppath
3636 del repo._subtoppath
3637
3637
3638 @command('parents',
3638 @command('parents',
3639 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3639 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3640 ] + templateopts,
3640 ] + templateopts,
3641 _('[-r REV] [FILE]'))
3641 _('[-r REV] [FILE]'))
3642 def parents(ui, repo, file_=None, **opts):
3642 def parents(ui, repo, file_=None, **opts):
3643 """show the parents of the working directory or revision
3643 """show the parents of the working directory or revision
3644
3644
3645 Print the working directory's parent revisions. If a revision is
3645 Print the working directory's parent revisions. If a revision is
3646 given via -r/--rev, the parent of that revision will be printed.
3646 given via -r/--rev, the parent of that revision will be printed.
3647 If a file argument is given, the revision in which the file was
3647 If a file argument is given, the revision in which the file was
3648 last changed (before the working directory revision or the
3648 last changed (before the working directory revision or the
3649 argument to --rev if given) is printed.
3649 argument to --rev if given) is printed.
3650
3650
3651 Returns 0 on success.
3651 Returns 0 on success.
3652 """
3652 """
3653
3653
3654 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3654 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3655
3655
3656 if file_:
3656 if file_:
3657 m = scmutil.match(ctx, (file_,), opts)
3657 m = scmutil.match(ctx, (file_,), opts)
3658 if m.anypats() or len(m.files()) != 1:
3658 if m.anypats() or len(m.files()) != 1:
3659 raise util.Abort(_('can only specify an explicit filename'))
3659 raise util.Abort(_('can only specify an explicit filename'))
3660 file_ = m.files()[0]
3660 file_ = m.files()[0]
3661 filenodes = []
3661 filenodes = []
3662 for cp in ctx.parents():
3662 for cp in ctx.parents():
3663 if not cp:
3663 if not cp:
3664 continue
3664 continue
3665 try:
3665 try:
3666 filenodes.append(cp.filenode(file_))
3666 filenodes.append(cp.filenode(file_))
3667 except error.LookupError:
3667 except error.LookupError:
3668 pass
3668 pass
3669 if not filenodes:
3669 if not filenodes:
3670 raise util.Abort(_("'%s' not found in manifest!") % file_)
3670 raise util.Abort(_("'%s' not found in manifest!") % file_)
3671 fl = repo.file(file_)
3671 fl = repo.file(file_)
3672 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3672 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3673 else:
3673 else:
3674 p = [cp.node() for cp in ctx.parents()]
3674 p = [cp.node() for cp in ctx.parents()]
3675
3675
3676 displayer = cmdutil.show_changeset(ui, repo, opts)
3676 displayer = cmdutil.show_changeset(ui, repo, opts)
3677 for n in p:
3677 for n in p:
3678 if n != nullid:
3678 if n != nullid:
3679 displayer.show(repo[n])
3679 displayer.show(repo[n])
3680 displayer.close()
3680 displayer.close()
3681
3681
3682 @command('paths', [], _('[NAME]'))
3682 @command('paths', [], _('[NAME]'))
3683 def paths(ui, repo, search=None):
3683 def paths(ui, repo, search=None):
3684 """show aliases for remote repositories
3684 """show aliases for remote repositories
3685
3685
3686 Show definition of symbolic path name NAME. If no name is given,
3686 Show definition of symbolic path name NAME. If no name is given,
3687 show definition of all available names.
3687 show definition of all available names.
3688
3688
3689 Option -q/--quiet suppresses all output when searching for NAME
3689 Option -q/--quiet suppresses all output when searching for NAME
3690 and shows only the path names when listing all definitions.
3690 and shows only the path names when listing all definitions.
3691
3691
3692 Path names are defined in the [paths] section of your
3692 Path names are defined in the [paths] section of your
3693 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3693 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3694 repository, ``.hg/hgrc`` is used, too.
3694 repository, ``.hg/hgrc`` is used, too.
3695
3695
3696 The path names ``default`` and ``default-push`` have a special
3696 The path names ``default`` and ``default-push`` have a special
3697 meaning. When performing a push or pull operation, they are used
3697 meaning. When performing a push or pull operation, they are used
3698 as fallbacks if no location is specified on the command-line.
3698 as fallbacks if no location is specified on the command-line.
3699 When ``default-push`` is set, it will be used for push and
3699 When ``default-push`` is set, it will be used for push and
3700 ``default`` will be used for pull; otherwise ``default`` is used
3700 ``default`` will be used for pull; otherwise ``default`` is used
3701 as the fallback for both. When cloning a repository, the clone
3701 as the fallback for both. When cloning a repository, the clone
3702 source is written as ``default`` in ``.hg/hgrc``. Note that
3702 source is written as ``default`` in ``.hg/hgrc``. Note that
3703 ``default`` and ``default-push`` apply to all inbound (e.g.
3703 ``default`` and ``default-push`` apply to all inbound (e.g.
3704 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3704 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3705 :hg:`bundle`) operations.
3705 :hg:`bundle`) operations.
3706
3706
3707 See :hg:`help urls` for more information.
3707 See :hg:`help urls` for more information.
3708
3708
3709 Returns 0 on success.
3709 Returns 0 on success.
3710 """
3710 """
3711 if search:
3711 if search:
3712 for name, path in ui.configitems("paths"):
3712 for name, path in ui.configitems("paths"):
3713 if name == search:
3713 if name == search:
3714 ui.status("%s\n" % util.hidepassword(path))
3714 ui.status("%s\n" % util.hidepassword(path))
3715 return
3715 return
3716 if not ui.quiet:
3716 if not ui.quiet:
3717 ui.warn(_("not found!\n"))
3717 ui.warn(_("not found!\n"))
3718 return 1
3718 return 1
3719 else:
3719 else:
3720 for name, path in ui.configitems("paths"):
3720 for name, path in ui.configitems("paths"):
3721 if ui.quiet:
3721 if ui.quiet:
3722 ui.write("%s\n" % name)
3722 ui.write("%s\n" % name)
3723 else:
3723 else:
3724 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3724 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3725
3725
3726 def postincoming(ui, repo, modheads, optupdate, checkout):
3726 def postincoming(ui, repo, modheads, optupdate, checkout):
3727 if modheads == 0:
3727 if modheads == 0:
3728 return
3728 return
3729 if optupdate:
3729 if optupdate:
3730 try:
3730 try:
3731 return hg.update(repo, checkout)
3731 return hg.update(repo, checkout)
3732 except util.Abort, inst:
3732 except util.Abort, inst:
3733 ui.warn(_("not updating: %s\n" % str(inst)))
3733 ui.warn(_("not updating: %s\n" % str(inst)))
3734 return 0
3734 return 0
3735 if modheads > 1:
3735 if modheads > 1:
3736 currentbranchheads = len(repo.branchheads())
3736 currentbranchheads = len(repo.branchheads())
3737 if currentbranchheads == modheads:
3737 if currentbranchheads == modheads:
3738 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3738 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3739 elif currentbranchheads > 1:
3739 elif currentbranchheads > 1:
3740 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3740 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3741 else:
3741 else:
3742 ui.status(_("(run 'hg heads' to see heads)\n"))
3742 ui.status(_("(run 'hg heads' to see heads)\n"))
3743 else:
3743 else:
3744 ui.status(_("(run 'hg update' to get a working copy)\n"))
3744 ui.status(_("(run 'hg update' to get a working copy)\n"))
3745
3745
3746 @command('^pull',
3746 @command('^pull',
3747 [('u', 'update', None,
3747 [('u', 'update', None,
3748 _('update to new branch head if changesets were pulled')),
3748 _('update to new branch head if changesets were pulled')),
3749 ('f', 'force', None, _('run even when remote repository is unrelated')),
3749 ('f', 'force', None, _('run even when remote repository is unrelated')),
3750 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3750 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3751 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3751 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3752 ('b', 'branch', [], _('a specific branch you would like to pull'),
3752 ('b', 'branch', [], _('a specific branch you would like to pull'),
3753 _('BRANCH')),
3753 _('BRANCH')),
3754 ] + remoteopts,
3754 ] + remoteopts,
3755 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3755 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3756 def pull(ui, repo, source="default", **opts):
3756 def pull(ui, repo, source="default", **opts):
3757 """pull changes from the specified source
3757 """pull changes from the specified source
3758
3758
3759 Pull changes from a remote repository to a local one.
3759 Pull changes from a remote repository to a local one.
3760
3760
3761 This finds all changes from the repository at the specified path
3761 This finds all changes from the repository at the specified path
3762 or URL and adds them to a local repository (the current one unless
3762 or URL and adds them to a local repository (the current one unless
3763 -R is specified). By default, this does not update the copy of the
3763 -R is specified). By default, this does not update the copy of the
3764 project in the working directory.
3764 project in the working directory.
3765
3765
3766 Use :hg:`incoming` if you want to see what would have been added
3766 Use :hg:`incoming` if you want to see what would have been added
3767 by a pull at the time you issued this command. If you then decide
3767 by a pull at the time you issued this command. If you then decide
3768 to add those changes to the repository, you should use :hg:`pull
3768 to add those changes to the repository, you should use :hg:`pull
3769 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3769 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3770
3770
3771 If SOURCE is omitted, the 'default' path will be used.
3771 If SOURCE is omitted, the 'default' path will be used.
3772 See :hg:`help urls` for more information.
3772 See :hg:`help urls` for more information.
3773
3773
3774 Returns 0 on success, 1 if an update had unresolved files.
3774 Returns 0 on success, 1 if an update had unresolved files.
3775 """
3775 """
3776 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3776 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3777 other = hg.peer(repo, opts, source)
3777 other = hg.peer(repo, opts, source)
3778 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3778 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3779 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3779 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3780
3780
3781 if opts.get('bookmark'):
3781 if opts.get('bookmark'):
3782 if not revs:
3782 if not revs:
3783 revs = []
3783 revs = []
3784 rb = other.listkeys('bookmarks')
3784 rb = other.listkeys('bookmarks')
3785 for b in opts['bookmark']:
3785 for b in opts['bookmark']:
3786 if b not in rb:
3786 if b not in rb:
3787 raise util.Abort(_('remote bookmark %s not found!') % b)
3787 raise util.Abort(_('remote bookmark %s not found!') % b)
3788 revs.append(rb[b])
3788 revs.append(rb[b])
3789
3789
3790 if revs:
3790 if revs:
3791 try:
3791 try:
3792 revs = [other.lookup(rev) for rev in revs]
3792 revs = [other.lookup(rev) for rev in revs]
3793 except error.CapabilityError:
3793 except error.CapabilityError:
3794 err = _("other repository doesn't support revision lookup, "
3794 err = _("other repository doesn't support revision lookup, "
3795 "so a rev cannot be specified.")
3795 "so a rev cannot be specified.")
3796 raise util.Abort(err)
3796 raise util.Abort(err)
3797
3797
3798 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3798 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3799 bookmarks.updatefromremote(ui, repo, other)
3799 bookmarks.updatefromremote(ui, repo, other)
3800 if checkout:
3800 if checkout:
3801 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3801 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3802 repo._subtoppath = source
3802 repo._subtoppath = source
3803 try:
3803 try:
3804 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3804 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3805
3805
3806 finally:
3806 finally:
3807 del repo._subtoppath
3807 del repo._subtoppath
3808
3808
3809 # update specified bookmarks
3809 # update specified bookmarks
3810 if opts.get('bookmark'):
3810 if opts.get('bookmark'):
3811 for b in opts['bookmark']:
3811 for b in opts['bookmark']:
3812 # explicit pull overrides local bookmark if any
3812 # explicit pull overrides local bookmark if any
3813 ui.status(_("importing bookmark %s\n") % b)
3813 ui.status(_("importing bookmark %s\n") % b)
3814 repo._bookmarks[b] = repo[rb[b]].node()
3814 repo._bookmarks[b] = repo[rb[b]].node()
3815 bookmarks.write(repo)
3815 bookmarks.write(repo)
3816
3816
3817 return ret
3817 return ret
3818
3818
3819 @command('^push',
3819 @command('^push',
3820 [('f', 'force', None, _('force push')),
3820 [('f', 'force', None, _('force push')),
3821 ('r', 'rev', [],
3821 ('r', 'rev', [],
3822 _('a changeset intended to be included in the destination'),
3822 _('a changeset intended to be included in the destination'),
3823 _('REV')),
3823 _('REV')),
3824 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3824 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
3825 ('b', 'branch', [],
3825 ('b', 'branch', [],
3826 _('a specific branch you would like to push'), _('BRANCH')),
3826 _('a specific branch you would like to push'), _('BRANCH')),
3827 ('', 'new-branch', False, _('allow pushing a new branch')),
3827 ('', 'new-branch', False, _('allow pushing a new branch')),
3828 ] + remoteopts,
3828 ] + remoteopts,
3829 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3829 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
3830 def push(ui, repo, dest=None, **opts):
3830 def push(ui, repo, dest=None, **opts):
3831 """push changes to the specified destination
3831 """push changes to the specified destination
3832
3832
3833 Push changesets from the local repository to the specified
3833 Push changesets from the local repository to the specified
3834 destination.
3834 destination.
3835
3835
3836 This operation is symmetrical to pull: it is identical to a pull
3836 This operation is symmetrical to pull: it is identical to a pull
3837 in the destination repository from the current one.
3837 in the destination repository from the current one.
3838
3838
3839 By default, push will not allow creation of new heads at the
3839 By default, push will not allow creation of new heads at the
3840 destination, since multiple heads would make it unclear which head
3840 destination, since multiple heads would make it unclear which head
3841 to use. In this situation, it is recommended to pull and merge
3841 to use. In this situation, it is recommended to pull and merge
3842 before pushing.
3842 before pushing.
3843
3843
3844 Use --new-branch if you want to allow push to create a new named
3844 Use --new-branch if you want to allow push to create a new named
3845 branch that is not present at the destination. This allows you to
3845 branch that is not present at the destination. This allows you to
3846 only create a new branch without forcing other changes.
3846 only create a new branch without forcing other changes.
3847
3847
3848 Use -f/--force to override the default behavior and push all
3848 Use -f/--force to override the default behavior and push all
3849 changesets on all branches.
3849 changesets on all branches.
3850
3850
3851 If -r/--rev is used, the specified revision and all its ancestors
3851 If -r/--rev is used, the specified revision and all its ancestors
3852 will be pushed to the remote repository.
3852 will be pushed to the remote repository.
3853
3853
3854 Please see :hg:`help urls` for important details about ``ssh://``
3854 Please see :hg:`help urls` for important details about ``ssh://``
3855 URLs. If DESTINATION is omitted, a default path will be used.
3855 URLs. If DESTINATION is omitted, a default path will be used.
3856
3856
3857 Returns 0 if push was successful, 1 if nothing to push.
3857 Returns 0 if push was successful, 1 if nothing to push.
3858 """
3858 """
3859
3859
3860 if opts.get('bookmark'):
3860 if opts.get('bookmark'):
3861 for b in opts['bookmark']:
3861 for b in opts['bookmark']:
3862 # translate -B options to -r so changesets get pushed
3862 # translate -B options to -r so changesets get pushed
3863 if b in repo._bookmarks:
3863 if b in repo._bookmarks:
3864 opts.setdefault('rev', []).append(b)
3864 opts.setdefault('rev', []).append(b)
3865 else:
3865 else:
3866 # if we try to push a deleted bookmark, translate it to null
3866 # if we try to push a deleted bookmark, translate it to null
3867 # this lets simultaneous -r, -b options continue working
3867 # this lets simultaneous -r, -b options continue working
3868 opts.setdefault('rev', []).append("null")
3868 opts.setdefault('rev', []).append("null")
3869
3869
3870 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3870 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3871 dest, branches = hg.parseurl(dest, opts.get('branch'))
3871 dest, branches = hg.parseurl(dest, opts.get('branch'))
3872 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3872 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3873 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3873 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3874 other = hg.peer(repo, opts, dest)
3874 other = hg.peer(repo, opts, dest)
3875 if revs:
3875 if revs:
3876 revs = [repo.lookup(rev) for rev in revs]
3876 revs = [repo.lookup(rev) for rev in revs]
3877
3877
3878 repo._subtoppath = dest
3878 repo._subtoppath = dest
3879 try:
3879 try:
3880 # push subrepos depth-first for coherent ordering
3880 # push subrepos depth-first for coherent ordering
3881 c = repo['']
3881 c = repo['']
3882 subs = c.substate # only repos that are committed
3882 subs = c.substate # only repos that are committed
3883 for s in sorted(subs):
3883 for s in sorted(subs):
3884 if not c.sub(s).push(opts.get('force')):
3884 if not c.sub(s).push(opts.get('force')):
3885 return False
3885 return False
3886 finally:
3886 finally:
3887 del repo._subtoppath
3887 del repo._subtoppath
3888 result = repo.push(other, opts.get('force'), revs=revs,
3888 result = repo.push(other, opts.get('force'), revs=revs,
3889 newbranch=opts.get('new_branch'))
3889 newbranch=opts.get('new_branch'))
3890
3890
3891 result = (result == 0)
3891 result = (result == 0)
3892
3892
3893 if opts.get('bookmark'):
3893 if opts.get('bookmark'):
3894 rb = other.listkeys('bookmarks')
3894 rb = other.listkeys('bookmarks')
3895 for b in opts['bookmark']:
3895 for b in opts['bookmark']:
3896 # explicit push overrides remote bookmark if any
3896 # explicit push overrides remote bookmark if any
3897 if b in repo._bookmarks:
3897 if b in repo._bookmarks:
3898 ui.status(_("exporting bookmark %s\n") % b)
3898 ui.status(_("exporting bookmark %s\n") % b)
3899 new = repo[b].hex()
3899 new = repo[b].hex()
3900 elif b in rb:
3900 elif b in rb:
3901 ui.status(_("deleting remote bookmark %s\n") % b)
3901 ui.status(_("deleting remote bookmark %s\n") % b)
3902 new = '' # delete
3902 new = '' # delete
3903 else:
3903 else:
3904 ui.warn(_('bookmark %s does not exist on the local '
3904 ui.warn(_('bookmark %s does not exist on the local '
3905 'or remote repository!\n') % b)
3905 'or remote repository!\n') % b)
3906 return 2
3906 return 2
3907 old = rb.get(b, '')
3907 old = rb.get(b, '')
3908 r = other.pushkey('bookmarks', b, old, new)
3908 r = other.pushkey('bookmarks', b, old, new)
3909 if not r:
3909 if not r:
3910 ui.warn(_('updating bookmark %s failed!\n') % b)
3910 ui.warn(_('updating bookmark %s failed!\n') % b)
3911 if not result:
3911 if not result:
3912 result = 2
3912 result = 2
3913
3913
3914 return result
3914 return result
3915
3915
3916 @command('recover', [])
3916 @command('recover', [])
3917 def recover(ui, repo):
3917 def recover(ui, repo):
3918 """roll back an interrupted transaction
3918 """roll back an interrupted transaction
3919
3919
3920 Recover from an interrupted commit or pull.
3920 Recover from an interrupted commit or pull.
3921
3921
3922 This command tries to fix the repository status after an
3922 This command tries to fix the repository status after an
3923 interrupted operation. It should only be necessary when Mercurial
3923 interrupted operation. It should only be necessary when Mercurial
3924 suggests it.
3924 suggests it.
3925
3925
3926 Returns 0 if successful, 1 if nothing to recover or verify fails.
3926 Returns 0 if successful, 1 if nothing to recover or verify fails.
3927 """
3927 """
3928 if repo.recover():
3928 if repo.recover():
3929 return hg.verify(repo)
3929 return hg.verify(repo)
3930 return 1
3930 return 1
3931
3931
3932 @command('^remove|rm',
3932 @command('^remove|rm',
3933 [('A', 'after', None, _('record delete for missing files')),
3933 [('A', 'after', None, _('record delete for missing files')),
3934 ('f', 'force', None,
3934 ('f', 'force', None,
3935 _('remove (and delete) file even if added or modified')),
3935 _('remove (and delete) file even if added or modified')),
3936 ] + walkopts,
3936 ] + walkopts,
3937 _('[OPTION]... FILE...'))
3937 _('[OPTION]... FILE...'))
3938 def remove(ui, repo, *pats, **opts):
3938 def remove(ui, repo, *pats, **opts):
3939 """remove the specified files on the next commit
3939 """remove the specified files on the next commit
3940
3940
3941 Schedule the indicated files for removal from the repository.
3941 Schedule the indicated files for removal from the repository.
3942
3942
3943 This only removes files from the current branch, not from the
3943 This only removes files from the current branch, not from the
3944 entire project history. -A/--after can be used to remove only
3944 entire project history. -A/--after can be used to remove only
3945 files that have already been deleted, -f/--force can be used to
3945 files that have already been deleted, -f/--force can be used to
3946 force deletion, and -Af can be used to remove files from the next
3946 force deletion, and -Af can be used to remove files from the next
3947 revision without deleting them from the working directory.
3947 revision without deleting them from the working directory.
3948
3948
3949 The following table details the behavior of remove for different
3949 The following table details the behavior of remove for different
3950 file states (columns) and option combinations (rows). The file
3950 file states (columns) and option combinations (rows). The file
3951 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3951 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3952 reported by :hg:`status`). The actions are Warn, Remove (from
3952 reported by :hg:`status`). The actions are Warn, Remove (from
3953 branch) and Delete (from disk)::
3953 branch) and Delete (from disk):
3954
3954
3955 A C M !
3955 ======= == == == ==
3956 none W RD W R
3956 A C M !
3957 -f R RD RD R
3957 ======= == == == ==
3958 -A W W W R
3958 none W RD W R
3959 -Af R R R R
3959 -f R RD RD R
3960 -A W W W R
3961 -Af R R R R
3962 ======= == == == ==
3960
3963
3961 Note that remove never deletes files in Added [A] state from the
3964 Note that remove never deletes files in Added [A] state from the
3962 working directory, not even if option --force is specified.
3965 working directory, not even if option --force is specified.
3963
3966
3964 This command schedules the files to be removed at the next commit.
3967 This command schedules the files to be removed at the next commit.
3965 To undo a remove before that, see :hg:`revert`.
3968 To undo a remove before that, see :hg:`revert`.
3966
3969
3967 Returns 0 on success, 1 if any warnings encountered.
3970 Returns 0 on success, 1 if any warnings encountered.
3968 """
3971 """
3969
3972
3970 ret = 0
3973 ret = 0
3971 after, force = opts.get('after'), opts.get('force')
3974 after, force = opts.get('after'), opts.get('force')
3972 if not pats and not after:
3975 if not pats and not after:
3973 raise util.Abort(_('no files specified'))
3976 raise util.Abort(_('no files specified'))
3974
3977
3975 m = scmutil.match(repo[None], pats, opts)
3978 m = scmutil.match(repo[None], pats, opts)
3976 s = repo.status(match=m, clean=True)
3979 s = repo.status(match=m, clean=True)
3977 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3980 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3978
3981
3979 for f in m.files():
3982 for f in m.files():
3980 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3983 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3981 if os.path.exists(m.rel(f)):
3984 if os.path.exists(m.rel(f)):
3982 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3985 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3983 ret = 1
3986 ret = 1
3984
3987
3985 if force:
3988 if force:
3986 list = modified + deleted + clean + added
3989 list = modified + deleted + clean + added
3987 elif after:
3990 elif after:
3988 list = deleted
3991 list = deleted
3989 for f in modified + added + clean:
3992 for f in modified + added + clean:
3990 ui.warn(_('not removing %s: file still exists (use -f'
3993 ui.warn(_('not removing %s: file still exists (use -f'
3991 ' to force removal)\n') % m.rel(f))
3994 ' to force removal)\n') % m.rel(f))
3992 ret = 1
3995 ret = 1
3993 else:
3996 else:
3994 list = deleted + clean
3997 list = deleted + clean
3995 for f in modified:
3998 for f in modified:
3996 ui.warn(_('not removing %s: file is modified (use -f'
3999 ui.warn(_('not removing %s: file is modified (use -f'
3997 ' to force removal)\n') % m.rel(f))
4000 ' to force removal)\n') % m.rel(f))
3998 ret = 1
4001 ret = 1
3999 for f in added:
4002 for f in added:
4000 ui.warn(_('not removing %s: file has been marked for add (use -f'
4003 ui.warn(_('not removing %s: file has been marked for add (use -f'
4001 ' to force removal)\n') % m.rel(f))
4004 ' to force removal)\n') % m.rel(f))
4002 ret = 1
4005 ret = 1
4003
4006
4004 for f in sorted(list):
4007 for f in sorted(list):
4005 if ui.verbose or not m.exact(f):
4008 if ui.verbose or not m.exact(f):
4006 ui.status(_('removing %s\n') % m.rel(f))
4009 ui.status(_('removing %s\n') % m.rel(f))
4007
4010
4008 wlock = repo.wlock()
4011 wlock = repo.wlock()
4009 try:
4012 try:
4010 if not after:
4013 if not after:
4011 for f in list:
4014 for f in list:
4012 if f in added:
4015 if f in added:
4013 continue # we never unlink added files on remove
4016 continue # we never unlink added files on remove
4014 try:
4017 try:
4015 util.unlinkpath(repo.wjoin(f))
4018 util.unlinkpath(repo.wjoin(f))
4016 except OSError, inst:
4019 except OSError, inst:
4017 if inst.errno != errno.ENOENT:
4020 if inst.errno != errno.ENOENT:
4018 raise
4021 raise
4019 repo[None].forget(list)
4022 repo[None].forget(list)
4020 finally:
4023 finally:
4021 wlock.release()
4024 wlock.release()
4022
4025
4023 return ret
4026 return ret
4024
4027
4025 @command('rename|move|mv',
4028 @command('rename|move|mv',
4026 [('A', 'after', None, _('record a rename that has already occurred')),
4029 [('A', 'after', None, _('record a rename that has already occurred')),
4027 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4030 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4028 ] + walkopts + dryrunopts,
4031 ] + walkopts + dryrunopts,
4029 _('[OPTION]... SOURCE... DEST'))
4032 _('[OPTION]... SOURCE... DEST'))
4030 def rename(ui, repo, *pats, **opts):
4033 def rename(ui, repo, *pats, **opts):
4031 """rename files; equivalent of copy + remove
4034 """rename files; equivalent of copy + remove
4032
4035
4033 Mark dest as copies of sources; mark sources for deletion. If dest
4036 Mark dest as copies of sources; mark sources for deletion. If dest
4034 is a directory, copies are put in that directory. If dest is a
4037 is a directory, copies are put in that directory. If dest is a
4035 file, there can only be one source.
4038 file, there can only be one source.
4036
4039
4037 By default, this command copies the contents of files as they
4040 By default, this command copies the contents of files as they
4038 exist in the working directory. If invoked with -A/--after, the
4041 exist in the working directory. If invoked with -A/--after, the
4039 operation is recorded, but no copying is performed.
4042 operation is recorded, but no copying is performed.
4040
4043
4041 This command takes effect at the next commit. To undo a rename
4044 This command takes effect at the next commit. To undo a rename
4042 before that, see :hg:`revert`.
4045 before that, see :hg:`revert`.
4043
4046
4044 Returns 0 on success, 1 if errors are encountered.
4047 Returns 0 on success, 1 if errors are encountered.
4045 """
4048 """
4046 wlock = repo.wlock(False)
4049 wlock = repo.wlock(False)
4047 try:
4050 try:
4048 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4051 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4049 finally:
4052 finally:
4050 wlock.release()
4053 wlock.release()
4051
4054
4052 @command('resolve',
4055 @command('resolve',
4053 [('a', 'all', None, _('select all unresolved files')),
4056 [('a', 'all', None, _('select all unresolved files')),
4054 ('l', 'list', None, _('list state of files needing merge')),
4057 ('l', 'list', None, _('list state of files needing merge')),
4055 ('m', 'mark', None, _('mark files as resolved')),
4058 ('m', 'mark', None, _('mark files as resolved')),
4056 ('u', 'unmark', None, _('mark files as unresolved')),
4059 ('u', 'unmark', None, _('mark files as unresolved')),
4057 ('n', 'no-status', None, _('hide status prefix'))]
4060 ('n', 'no-status', None, _('hide status prefix'))]
4058 + mergetoolopts + walkopts,
4061 + mergetoolopts + walkopts,
4059 _('[OPTION]... [FILE]...'))
4062 _('[OPTION]... [FILE]...'))
4060 def resolve(ui, repo, *pats, **opts):
4063 def resolve(ui, repo, *pats, **opts):
4061 """redo merges or set/view the merge status of files
4064 """redo merges or set/view the merge status of files
4062
4065
4063 Merges with unresolved conflicts are often the result of
4066 Merges with unresolved conflicts are often the result of
4064 non-interactive merging using the ``internal:merge`` configuration
4067 non-interactive merging using the ``internal:merge`` configuration
4065 setting, or a command-line merge tool like ``diff3``. The resolve
4068 setting, or a command-line merge tool like ``diff3``. The resolve
4066 command is used to manage the files involved in a merge, after
4069 command is used to manage the files involved in a merge, after
4067 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4070 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4068 working directory must have two parents).
4071 working directory must have two parents).
4069
4072
4070 The resolve command can be used in the following ways:
4073 The resolve command can be used in the following ways:
4071
4074
4072 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4075 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4073 files, discarding any previous merge attempts. Re-merging is not
4076 files, discarding any previous merge attempts. Re-merging is not
4074 performed for files already marked as resolved. Use ``--all/-a``
4077 performed for files already marked as resolved. Use ``--all/-a``
4075 to selects all unresolved files. ``--tool`` can be used to specify
4078 to selects all unresolved files. ``--tool`` can be used to specify
4076 the merge tool used for the given files. It overrides the HGMERGE
4079 the merge tool used for the given files. It overrides the HGMERGE
4077 environment variable and your configuration files.
4080 environment variable and your configuration files.
4078
4081
4079 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4082 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4080 (e.g. after having manually fixed-up the files). The default is
4083 (e.g. after having manually fixed-up the files). The default is
4081 to mark all unresolved files.
4084 to mark all unresolved files.
4082
4085
4083 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4086 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4084 default is to mark all resolved files.
4087 default is to mark all resolved files.
4085
4088
4086 - :hg:`resolve -l`: list files which had or still have conflicts.
4089 - :hg:`resolve -l`: list files which had or still have conflicts.
4087 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4090 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4088
4091
4089 Note that Mercurial will not let you commit files with unresolved
4092 Note that Mercurial will not let you commit files with unresolved
4090 merge conflicts. You must use :hg:`resolve -m ...` before you can
4093 merge conflicts. You must use :hg:`resolve -m ...` before you can
4091 commit after a conflicting merge.
4094 commit after a conflicting merge.
4092
4095
4093 Returns 0 on success, 1 if any files fail a resolve attempt.
4096 Returns 0 on success, 1 if any files fail a resolve attempt.
4094 """
4097 """
4095
4098
4096 all, mark, unmark, show, nostatus = \
4099 all, mark, unmark, show, nostatus = \
4097 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4100 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4098
4101
4099 if (show and (mark or unmark)) or (mark and unmark):
4102 if (show and (mark or unmark)) or (mark and unmark):
4100 raise util.Abort(_("too many options specified"))
4103 raise util.Abort(_("too many options specified"))
4101 if pats and all:
4104 if pats and all:
4102 raise util.Abort(_("can't specify --all and patterns"))
4105 raise util.Abort(_("can't specify --all and patterns"))
4103 if not (all or pats or show or mark or unmark):
4106 if not (all or pats or show or mark or unmark):
4104 raise util.Abort(_('no files or directories specified; '
4107 raise util.Abort(_('no files or directories specified; '
4105 'use --all to remerge all files'))
4108 'use --all to remerge all files'))
4106
4109
4107 ms = mergemod.mergestate(repo)
4110 ms = mergemod.mergestate(repo)
4108 m = scmutil.match(repo[None], pats, opts)
4111 m = scmutil.match(repo[None], pats, opts)
4109 ret = 0
4112 ret = 0
4110
4113
4111 for f in ms:
4114 for f in ms:
4112 if m(f):
4115 if m(f):
4113 if show:
4116 if show:
4114 if nostatus:
4117 if nostatus:
4115 ui.write("%s\n" % f)
4118 ui.write("%s\n" % f)
4116 else:
4119 else:
4117 ui.write("%s %s\n" % (ms[f].upper(), f),
4120 ui.write("%s %s\n" % (ms[f].upper(), f),
4118 label='resolve.' +
4121 label='resolve.' +
4119 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4122 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4120 elif mark:
4123 elif mark:
4121 ms.mark(f, "r")
4124 ms.mark(f, "r")
4122 elif unmark:
4125 elif unmark:
4123 ms.mark(f, "u")
4126 ms.mark(f, "u")
4124 else:
4127 else:
4125 wctx = repo[None]
4128 wctx = repo[None]
4126 mctx = wctx.parents()[-1]
4129 mctx = wctx.parents()[-1]
4127
4130
4128 # backup pre-resolve (merge uses .orig for its own purposes)
4131 # backup pre-resolve (merge uses .orig for its own purposes)
4129 a = repo.wjoin(f)
4132 a = repo.wjoin(f)
4130 util.copyfile(a, a + ".resolve")
4133 util.copyfile(a, a + ".resolve")
4131
4134
4132 try:
4135 try:
4133 # resolve file
4136 # resolve file
4134 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4137 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4135 if ms.resolve(f, wctx, mctx):
4138 if ms.resolve(f, wctx, mctx):
4136 ret = 1
4139 ret = 1
4137 finally:
4140 finally:
4138 ui.setconfig('ui', 'forcemerge', '')
4141 ui.setconfig('ui', 'forcemerge', '')
4139
4142
4140 # replace filemerge's .orig file with our resolve file
4143 # replace filemerge's .orig file with our resolve file
4141 util.rename(a + ".resolve", a + ".orig")
4144 util.rename(a + ".resolve", a + ".orig")
4142
4145
4143 ms.commit()
4146 ms.commit()
4144 return ret
4147 return ret
4145
4148
4146 @command('revert',
4149 @command('revert',
4147 [('a', 'all', None, _('revert all changes when no arguments given')),
4150 [('a', 'all', None, _('revert all changes when no arguments given')),
4148 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4151 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4149 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4152 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4150 ('C', 'no-backup', None, _('do not save backup copies of files')),
4153 ('C', 'no-backup', None, _('do not save backup copies of files')),
4151 ] + walkopts + dryrunopts,
4154 ] + walkopts + dryrunopts,
4152 _('[OPTION]... [-r REV] [NAME]...'))
4155 _('[OPTION]... [-r REV] [NAME]...'))
4153 def revert(ui, repo, *pats, **opts):
4156 def revert(ui, repo, *pats, **opts):
4154 """restore files to their checkout state
4157 """restore files to their checkout state
4155
4158
4156 .. note::
4159 .. note::
4157 To check out earlier revisions, you should use :hg:`update REV`.
4160 To check out earlier revisions, you should use :hg:`update REV`.
4158 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4161 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4159
4162
4160 With no revision specified, revert the specified files or directories
4163 With no revision specified, revert the specified files or directories
4161 to the contents they had in the parent of the working directory.
4164 to the contents they had in the parent of the working directory.
4162 This restores the contents of files to an unmodified
4165 This restores the contents of files to an unmodified
4163 state and unschedules adds, removes, copies, and renames. If the
4166 state and unschedules adds, removes, copies, and renames. If the
4164 working directory has two parents, you must explicitly specify a
4167 working directory has two parents, you must explicitly specify a
4165 revision.
4168 revision.
4166
4169
4167 Using the -r/--rev or -d/--date options, revert the given files or
4170 Using the -r/--rev or -d/--date options, revert the given files or
4168 directories to their states as of a specific revision. Because
4171 directories to their states as of a specific revision. Because
4169 revert does not change the working directory parents, this will
4172 revert does not change the working directory parents, this will
4170 cause these files to appear modified. This can be helpful to "back
4173 cause these files to appear modified. This can be helpful to "back
4171 out" some or all of an earlier change. See :hg:`backout` for a
4174 out" some or all of an earlier change. See :hg:`backout` for a
4172 related method.
4175 related method.
4173
4176
4174 Modified files are saved with a .orig suffix before reverting.
4177 Modified files are saved with a .orig suffix before reverting.
4175 To disable these backups, use --no-backup.
4178 To disable these backups, use --no-backup.
4176
4179
4177 See :hg:`help dates` for a list of formats valid for -d/--date.
4180 See :hg:`help dates` for a list of formats valid for -d/--date.
4178
4181
4179 Returns 0 on success.
4182 Returns 0 on success.
4180 """
4183 """
4181
4184
4182 if opts.get("date"):
4185 if opts.get("date"):
4183 if opts.get("rev"):
4186 if opts.get("rev"):
4184 raise util.Abort(_("you can't specify a revision and a date"))
4187 raise util.Abort(_("you can't specify a revision and a date"))
4185 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4188 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4186
4189
4187 parent, p2 = repo.dirstate.parents()
4190 parent, p2 = repo.dirstate.parents()
4188 if not opts.get('rev') and p2 != nullid:
4191 if not opts.get('rev') and p2 != nullid:
4189 # revert after merge is a trap for new users (issue2915)
4192 # revert after merge is a trap for new users (issue2915)
4190 raise util.Abort(_('uncommitted merge with no revision specified'),
4193 raise util.Abort(_('uncommitted merge with no revision specified'),
4191 hint=_('use "hg update" or see "hg help revert"'))
4194 hint=_('use "hg update" or see "hg help revert"'))
4192
4195
4193 ctx = scmutil.revsingle(repo, opts.get('rev'))
4196 ctx = scmutil.revsingle(repo, opts.get('rev'))
4194 node = ctx.node()
4197 node = ctx.node()
4195
4198
4196 if not pats and not opts.get('all'):
4199 if not pats and not opts.get('all'):
4197 msg = _("no files or directories specified")
4200 msg = _("no files or directories specified")
4198 if p2 != nullid:
4201 if p2 != nullid:
4199 hint = _("uncommitted merge, use --all to discard all changes,"
4202 hint = _("uncommitted merge, use --all to discard all changes,"
4200 " or 'hg update -C .' to abort the merge")
4203 " or 'hg update -C .' to abort the merge")
4201 raise util.Abort(msg, hint=hint)
4204 raise util.Abort(msg, hint=hint)
4202 dirty = util.any(repo.status())
4205 dirty = util.any(repo.status())
4203 if node != parent:
4206 if node != parent:
4204 if dirty:
4207 if dirty:
4205 hint = _("uncommitted changes, use --all to discard all"
4208 hint = _("uncommitted changes, use --all to discard all"
4206 " changes, or 'hg update %s' to update") % ctx.rev()
4209 " changes, or 'hg update %s' to update") % ctx.rev()
4207 else:
4210 else:
4208 hint = _("use --all to revert all files,"
4211 hint = _("use --all to revert all files,"
4209 " or 'hg update %s' to update") % ctx.rev()
4212 " or 'hg update %s' to update") % ctx.rev()
4210 elif dirty:
4213 elif dirty:
4211 hint = _("uncommitted changes, use --all to discard all changes")
4214 hint = _("uncommitted changes, use --all to discard all changes")
4212 else:
4215 else:
4213 hint = _("use --all to revert all files")
4216 hint = _("use --all to revert all files")
4214 raise util.Abort(msg, hint=hint)
4217 raise util.Abort(msg, hint=hint)
4215
4218
4216 mf = ctx.manifest()
4219 mf = ctx.manifest()
4217 if node == parent:
4220 if node == parent:
4218 pmf = mf
4221 pmf = mf
4219 else:
4222 else:
4220 pmf = None
4223 pmf = None
4221
4224
4222 # need all matching names in dirstate and manifest of target rev,
4225 # need all matching names in dirstate and manifest of target rev,
4223 # so have to walk both. do not print errors if files exist in one
4226 # so have to walk both. do not print errors if files exist in one
4224 # but not other.
4227 # but not other.
4225
4228
4226 names = {}
4229 names = {}
4227
4230
4228 wlock = repo.wlock()
4231 wlock = repo.wlock()
4229 try:
4232 try:
4230 # walk dirstate.
4233 # walk dirstate.
4231
4234
4232 m = scmutil.match(repo[None], pats, opts)
4235 m = scmutil.match(repo[None], pats, opts)
4233 m.bad = lambda x, y: False
4236 m.bad = lambda x, y: False
4234 for abs in repo.walk(m):
4237 for abs in repo.walk(m):
4235 names[abs] = m.rel(abs), m.exact(abs)
4238 names[abs] = m.rel(abs), m.exact(abs)
4236
4239
4237 # walk target manifest.
4240 # walk target manifest.
4238
4241
4239 def badfn(path, msg):
4242 def badfn(path, msg):
4240 if path in names:
4243 if path in names:
4241 return
4244 return
4242 path_ = path + '/'
4245 path_ = path + '/'
4243 for f in names:
4246 for f in names:
4244 if f.startswith(path_):
4247 if f.startswith(path_):
4245 return
4248 return
4246 ui.warn("%s: %s\n" % (m.rel(path), msg))
4249 ui.warn("%s: %s\n" % (m.rel(path), msg))
4247
4250
4248 m = scmutil.match(repo[node], pats, opts)
4251 m = scmutil.match(repo[node], pats, opts)
4249 m.bad = badfn
4252 m.bad = badfn
4250 for abs in repo[node].walk(m):
4253 for abs in repo[node].walk(m):
4251 if abs not in names:
4254 if abs not in names:
4252 names[abs] = m.rel(abs), m.exact(abs)
4255 names[abs] = m.rel(abs), m.exact(abs)
4253
4256
4254 m = scmutil.matchfiles(repo, names)
4257 m = scmutil.matchfiles(repo, names)
4255 changes = repo.status(match=m)[:4]
4258 changes = repo.status(match=m)[:4]
4256 modified, added, removed, deleted = map(set, changes)
4259 modified, added, removed, deleted = map(set, changes)
4257
4260
4258 # if f is a rename, also revert the source
4261 # if f is a rename, also revert the source
4259 cwd = repo.getcwd()
4262 cwd = repo.getcwd()
4260 for f in added:
4263 for f in added:
4261 src = repo.dirstate.copied(f)
4264 src = repo.dirstate.copied(f)
4262 if src and src not in names and repo.dirstate[src] == 'r':
4265 if src and src not in names and repo.dirstate[src] == 'r':
4263 removed.add(src)
4266 removed.add(src)
4264 names[src] = (repo.pathto(src, cwd), True)
4267 names[src] = (repo.pathto(src, cwd), True)
4265
4268
4266 def removeforget(abs):
4269 def removeforget(abs):
4267 if repo.dirstate[abs] == 'a':
4270 if repo.dirstate[abs] == 'a':
4268 return _('forgetting %s\n')
4271 return _('forgetting %s\n')
4269 return _('removing %s\n')
4272 return _('removing %s\n')
4270
4273
4271 revert = ([], _('reverting %s\n'))
4274 revert = ([], _('reverting %s\n'))
4272 add = ([], _('adding %s\n'))
4275 add = ([], _('adding %s\n'))
4273 remove = ([], removeforget)
4276 remove = ([], removeforget)
4274 undelete = ([], _('undeleting %s\n'))
4277 undelete = ([], _('undeleting %s\n'))
4275
4278
4276 disptable = (
4279 disptable = (
4277 # dispatch table:
4280 # dispatch table:
4278 # file state
4281 # file state
4279 # action if in target manifest
4282 # action if in target manifest
4280 # action if not in target manifest
4283 # action if not in target manifest
4281 # make backup if in target manifest
4284 # make backup if in target manifest
4282 # make backup if not in target manifest
4285 # make backup if not in target manifest
4283 (modified, revert, remove, True, True),
4286 (modified, revert, remove, True, True),
4284 (added, revert, remove, True, False),
4287 (added, revert, remove, True, False),
4285 (removed, undelete, None, False, False),
4288 (removed, undelete, None, False, False),
4286 (deleted, revert, remove, False, False),
4289 (deleted, revert, remove, False, False),
4287 )
4290 )
4288
4291
4289 for abs, (rel, exact) in sorted(names.items()):
4292 for abs, (rel, exact) in sorted(names.items()):
4290 mfentry = mf.get(abs)
4293 mfentry = mf.get(abs)
4291 target = repo.wjoin(abs)
4294 target = repo.wjoin(abs)
4292 def handle(xlist, dobackup):
4295 def handle(xlist, dobackup):
4293 xlist[0].append(abs)
4296 xlist[0].append(abs)
4294 if (dobackup and not opts.get('no_backup') and
4297 if (dobackup and not opts.get('no_backup') and
4295 os.path.lexists(target)):
4298 os.path.lexists(target)):
4296 bakname = "%s.orig" % rel
4299 bakname = "%s.orig" % rel
4297 ui.note(_('saving current version of %s as %s\n') %
4300 ui.note(_('saving current version of %s as %s\n') %
4298 (rel, bakname))
4301 (rel, bakname))
4299 if not opts.get('dry_run'):
4302 if not opts.get('dry_run'):
4300 util.rename(target, bakname)
4303 util.rename(target, bakname)
4301 if ui.verbose or not exact:
4304 if ui.verbose or not exact:
4302 msg = xlist[1]
4305 msg = xlist[1]
4303 if not isinstance(msg, basestring):
4306 if not isinstance(msg, basestring):
4304 msg = msg(abs)
4307 msg = msg(abs)
4305 ui.status(msg % rel)
4308 ui.status(msg % rel)
4306 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4309 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4307 if abs not in table:
4310 if abs not in table:
4308 continue
4311 continue
4309 # file has changed in dirstate
4312 # file has changed in dirstate
4310 if mfentry:
4313 if mfentry:
4311 handle(hitlist, backuphit)
4314 handle(hitlist, backuphit)
4312 elif misslist is not None:
4315 elif misslist is not None:
4313 handle(misslist, backupmiss)
4316 handle(misslist, backupmiss)
4314 break
4317 break
4315 else:
4318 else:
4316 if abs not in repo.dirstate:
4319 if abs not in repo.dirstate:
4317 if mfentry:
4320 if mfentry:
4318 handle(add, True)
4321 handle(add, True)
4319 elif exact:
4322 elif exact:
4320 ui.warn(_('file not managed: %s\n') % rel)
4323 ui.warn(_('file not managed: %s\n') % rel)
4321 continue
4324 continue
4322 # file has not changed in dirstate
4325 # file has not changed in dirstate
4323 if node == parent:
4326 if node == parent:
4324 if exact:
4327 if exact:
4325 ui.warn(_('no changes needed to %s\n') % rel)
4328 ui.warn(_('no changes needed to %s\n') % rel)
4326 continue
4329 continue
4327 if pmf is None:
4330 if pmf is None:
4328 # only need parent manifest in this unlikely case,
4331 # only need parent manifest in this unlikely case,
4329 # so do not read by default
4332 # so do not read by default
4330 pmf = repo[parent].manifest()
4333 pmf = repo[parent].manifest()
4331 if abs in pmf:
4334 if abs in pmf:
4332 if mfentry:
4335 if mfentry:
4333 # if version of file is same in parent and target
4336 # if version of file is same in parent and target
4334 # manifests, do nothing
4337 # manifests, do nothing
4335 if (pmf[abs] != mfentry or
4338 if (pmf[abs] != mfentry or
4336 pmf.flags(abs) != mf.flags(abs)):
4339 pmf.flags(abs) != mf.flags(abs)):
4337 handle(revert, False)
4340 handle(revert, False)
4338 else:
4341 else:
4339 handle(remove, False)
4342 handle(remove, False)
4340
4343
4341 if not opts.get('dry_run'):
4344 if not opts.get('dry_run'):
4342 def checkout(f):
4345 def checkout(f):
4343 fc = ctx[f]
4346 fc = ctx[f]
4344 repo.wwrite(f, fc.data(), fc.flags())
4347 repo.wwrite(f, fc.data(), fc.flags())
4345
4348
4346 audit_path = scmutil.pathauditor(repo.root)
4349 audit_path = scmutil.pathauditor(repo.root)
4347 for f in remove[0]:
4350 for f in remove[0]:
4348 if repo.dirstate[f] == 'a':
4351 if repo.dirstate[f] == 'a':
4349 repo.dirstate.drop(f)
4352 repo.dirstate.drop(f)
4350 continue
4353 continue
4351 audit_path(f)
4354 audit_path(f)
4352 try:
4355 try:
4353 util.unlinkpath(repo.wjoin(f))
4356 util.unlinkpath(repo.wjoin(f))
4354 except OSError:
4357 except OSError:
4355 pass
4358 pass
4356 repo.dirstate.remove(f)
4359 repo.dirstate.remove(f)
4357
4360
4358 normal = None
4361 normal = None
4359 if node == parent:
4362 if node == parent:
4360 # We're reverting to our parent. If possible, we'd like status
4363 # We're reverting to our parent. If possible, we'd like status
4361 # to report the file as clean. We have to use normallookup for
4364 # to report the file as clean. We have to use normallookup for
4362 # merges to avoid losing information about merged/dirty files.
4365 # merges to avoid losing information about merged/dirty files.
4363 if p2 != nullid:
4366 if p2 != nullid:
4364 normal = repo.dirstate.normallookup
4367 normal = repo.dirstate.normallookup
4365 else:
4368 else:
4366 normal = repo.dirstate.normal
4369 normal = repo.dirstate.normal
4367 for f in revert[0]:
4370 for f in revert[0]:
4368 checkout(f)
4371 checkout(f)
4369 if normal:
4372 if normal:
4370 normal(f)
4373 normal(f)
4371
4374
4372 for f in add[0]:
4375 for f in add[0]:
4373 checkout(f)
4376 checkout(f)
4374 repo.dirstate.add(f)
4377 repo.dirstate.add(f)
4375
4378
4376 normal = repo.dirstate.normallookup
4379 normal = repo.dirstate.normallookup
4377 if node == parent and p2 == nullid:
4380 if node == parent and p2 == nullid:
4378 normal = repo.dirstate.normal
4381 normal = repo.dirstate.normal
4379 for f in undelete[0]:
4382 for f in undelete[0]:
4380 checkout(f)
4383 checkout(f)
4381 normal(f)
4384 normal(f)
4382
4385
4383 finally:
4386 finally:
4384 wlock.release()
4387 wlock.release()
4385
4388
4386 @command('rollback', dryrunopts)
4389 @command('rollback', dryrunopts)
4387 def rollback(ui, repo, **opts):
4390 def rollback(ui, repo, **opts):
4388 """roll back the last transaction (dangerous)
4391 """roll back the last transaction (dangerous)
4389
4392
4390 This command should be used with care. There is only one level of
4393 This command should be used with care. There is only one level of
4391 rollback, and there is no way to undo a rollback. It will also
4394 rollback, and there is no way to undo a rollback. It will also
4392 restore the dirstate at the time of the last transaction, losing
4395 restore the dirstate at the time of the last transaction, losing
4393 any dirstate changes since that time. This command does not alter
4396 any dirstate changes since that time. This command does not alter
4394 the working directory.
4397 the working directory.
4395
4398
4396 Transactions are used to encapsulate the effects of all commands
4399 Transactions are used to encapsulate the effects of all commands
4397 that create new changesets or propagate existing changesets into a
4400 that create new changesets or propagate existing changesets into a
4398 repository. For example, the following commands are transactional,
4401 repository. For example, the following commands are transactional,
4399 and their effects can be rolled back:
4402 and their effects can be rolled back:
4400
4403
4401 - commit
4404 - commit
4402 - import
4405 - import
4403 - pull
4406 - pull
4404 - push (with this repository as the destination)
4407 - push (with this repository as the destination)
4405 - unbundle
4408 - unbundle
4406
4409
4407 This command is not intended for use on public repositories. Once
4410 This command is not intended for use on public repositories. Once
4408 changes are visible for pull by other users, rolling a transaction
4411 changes are visible for pull by other users, rolling a transaction
4409 back locally is ineffective (someone else may already have pulled
4412 back locally is ineffective (someone else may already have pulled
4410 the changes). Furthermore, a race is possible with readers of the
4413 the changes). Furthermore, a race is possible with readers of the
4411 repository; for example an in-progress pull from the repository
4414 repository; for example an in-progress pull from the repository
4412 may fail if a rollback is performed.
4415 may fail if a rollback is performed.
4413
4416
4414 Returns 0 on success, 1 if no rollback data is available.
4417 Returns 0 on success, 1 if no rollback data is available.
4415 """
4418 """
4416 return repo.rollback(opts.get('dry_run'))
4419 return repo.rollback(opts.get('dry_run'))
4417
4420
4418 @command('root', [])
4421 @command('root', [])
4419 def root(ui, repo):
4422 def root(ui, repo):
4420 """print the root (top) of the current working directory
4423 """print the root (top) of the current working directory
4421
4424
4422 Print the root directory of the current repository.
4425 Print the root directory of the current repository.
4423
4426
4424 Returns 0 on success.
4427 Returns 0 on success.
4425 """
4428 """
4426 ui.write(repo.root + "\n")
4429 ui.write(repo.root + "\n")
4427
4430
4428 @command('^serve',
4431 @command('^serve',
4429 [('A', 'accesslog', '', _('name of access log file to write to'),
4432 [('A', 'accesslog', '', _('name of access log file to write to'),
4430 _('FILE')),
4433 _('FILE')),
4431 ('d', 'daemon', None, _('run server in background')),
4434 ('d', 'daemon', None, _('run server in background')),
4432 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4435 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4433 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4436 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4434 # use string type, then we can check if something was passed
4437 # use string type, then we can check if something was passed
4435 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4438 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4436 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4439 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4437 _('ADDR')),
4440 _('ADDR')),
4438 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4441 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4439 _('PREFIX')),
4442 _('PREFIX')),
4440 ('n', 'name', '',
4443 ('n', 'name', '',
4441 _('name to show in web pages (default: working directory)'), _('NAME')),
4444 _('name to show in web pages (default: working directory)'), _('NAME')),
4442 ('', 'web-conf', '',
4445 ('', 'web-conf', '',
4443 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4446 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4444 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4447 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4445 _('FILE')),
4448 _('FILE')),
4446 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4449 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4447 ('', 'stdio', None, _('for remote clients')),
4450 ('', 'stdio', None, _('for remote clients')),
4448 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4451 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4449 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4452 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4450 ('', 'style', '', _('template style to use'), _('STYLE')),
4453 ('', 'style', '', _('template style to use'), _('STYLE')),
4451 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4454 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4452 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4455 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4453 _('[OPTION]...'))
4456 _('[OPTION]...'))
4454 def serve(ui, repo, **opts):
4457 def serve(ui, repo, **opts):
4455 """start stand-alone webserver
4458 """start stand-alone webserver
4456
4459
4457 Start a local HTTP repository browser and pull server. You can use
4460 Start a local HTTP repository browser and pull server. You can use
4458 this for ad-hoc sharing and browsing of repositories. It is
4461 this for ad-hoc sharing and browsing of repositories. It is
4459 recommended to use a real web server to serve a repository for
4462 recommended to use a real web server to serve a repository for
4460 longer periods of time.
4463 longer periods of time.
4461
4464
4462 Please note that the server does not implement access control.
4465 Please note that the server does not implement access control.
4463 This means that, by default, anybody can read from the server and
4466 This means that, by default, anybody can read from the server and
4464 nobody can write to it by default. Set the ``web.allow_push``
4467 nobody can write to it by default. Set the ``web.allow_push``
4465 option to ``*`` to allow everybody to push to the server. You
4468 option to ``*`` to allow everybody to push to the server. You
4466 should use a real web server if you need to authenticate users.
4469 should use a real web server if you need to authenticate users.
4467
4470
4468 By default, the server logs accesses to stdout and errors to
4471 By default, the server logs accesses to stdout and errors to
4469 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4472 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4470 files.
4473 files.
4471
4474
4472 To have the server choose a free port number to listen on, specify
4475 To have the server choose a free port number to listen on, specify
4473 a port number of 0; in this case, the server will print the port
4476 a port number of 0; in this case, the server will print the port
4474 number it uses.
4477 number it uses.
4475
4478
4476 Returns 0 on success.
4479 Returns 0 on success.
4477 """
4480 """
4478
4481
4479 if opts["stdio"] and opts["cmdserver"]:
4482 if opts["stdio"] and opts["cmdserver"]:
4480 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4483 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4481
4484
4482 def checkrepo():
4485 def checkrepo():
4483 if repo is None:
4486 if repo is None:
4484 raise error.RepoError(_("There is no Mercurial repository here"
4487 raise error.RepoError(_("There is no Mercurial repository here"
4485 " (.hg not found)"))
4488 " (.hg not found)"))
4486
4489
4487 if opts["stdio"]:
4490 if opts["stdio"]:
4488 checkrepo()
4491 checkrepo()
4489 s = sshserver.sshserver(ui, repo)
4492 s = sshserver.sshserver(ui, repo)
4490 s.serve_forever()
4493 s.serve_forever()
4491
4494
4492 if opts["cmdserver"]:
4495 if opts["cmdserver"]:
4493 checkrepo()
4496 checkrepo()
4494 s = commandserver.server(ui, repo, opts["cmdserver"])
4497 s = commandserver.server(ui, repo, opts["cmdserver"])
4495 return s.serve()
4498 return s.serve()
4496
4499
4497 # this way we can check if something was given in the command-line
4500 # this way we can check if something was given in the command-line
4498 if opts.get('port'):
4501 if opts.get('port'):
4499 opts['port'] = util.getport(opts.get('port'))
4502 opts['port'] = util.getport(opts.get('port'))
4500
4503
4501 baseui = repo and repo.baseui or ui
4504 baseui = repo and repo.baseui or ui
4502 optlist = ("name templates style address port prefix ipv6"
4505 optlist = ("name templates style address port prefix ipv6"
4503 " accesslog errorlog certificate encoding")
4506 " accesslog errorlog certificate encoding")
4504 for o in optlist.split():
4507 for o in optlist.split():
4505 val = opts.get(o, '')
4508 val = opts.get(o, '')
4506 if val in (None, ''): # should check against default options instead
4509 if val in (None, ''): # should check against default options instead
4507 continue
4510 continue
4508 baseui.setconfig("web", o, val)
4511 baseui.setconfig("web", o, val)
4509 if repo and repo.ui != baseui:
4512 if repo and repo.ui != baseui:
4510 repo.ui.setconfig("web", o, val)
4513 repo.ui.setconfig("web", o, val)
4511
4514
4512 o = opts.get('web_conf') or opts.get('webdir_conf')
4515 o = opts.get('web_conf') or opts.get('webdir_conf')
4513 if not o:
4516 if not o:
4514 if not repo:
4517 if not repo:
4515 raise error.RepoError(_("There is no Mercurial repository"
4518 raise error.RepoError(_("There is no Mercurial repository"
4516 " here (.hg not found)"))
4519 " here (.hg not found)"))
4517 o = repo.root
4520 o = repo.root
4518
4521
4519 app = hgweb.hgweb(o, baseui=ui)
4522 app = hgweb.hgweb(o, baseui=ui)
4520
4523
4521 class service(object):
4524 class service(object):
4522 def init(self):
4525 def init(self):
4523 util.setsignalhandler()
4526 util.setsignalhandler()
4524 self.httpd = hgweb.server.create_server(ui, app)
4527 self.httpd = hgweb.server.create_server(ui, app)
4525
4528
4526 if opts['port'] and not ui.verbose:
4529 if opts['port'] and not ui.verbose:
4527 return
4530 return
4528
4531
4529 if self.httpd.prefix:
4532 if self.httpd.prefix:
4530 prefix = self.httpd.prefix.strip('/') + '/'
4533 prefix = self.httpd.prefix.strip('/') + '/'
4531 else:
4534 else:
4532 prefix = ''
4535 prefix = ''
4533
4536
4534 port = ':%d' % self.httpd.port
4537 port = ':%d' % self.httpd.port
4535 if port == ':80':
4538 if port == ':80':
4536 port = ''
4539 port = ''
4537
4540
4538 bindaddr = self.httpd.addr
4541 bindaddr = self.httpd.addr
4539 if bindaddr == '0.0.0.0':
4542 if bindaddr == '0.0.0.0':
4540 bindaddr = '*'
4543 bindaddr = '*'
4541 elif ':' in bindaddr: # IPv6
4544 elif ':' in bindaddr: # IPv6
4542 bindaddr = '[%s]' % bindaddr
4545 bindaddr = '[%s]' % bindaddr
4543
4546
4544 fqaddr = self.httpd.fqaddr
4547 fqaddr = self.httpd.fqaddr
4545 if ':' in fqaddr:
4548 if ':' in fqaddr:
4546 fqaddr = '[%s]' % fqaddr
4549 fqaddr = '[%s]' % fqaddr
4547 if opts['port']:
4550 if opts['port']:
4548 write = ui.status
4551 write = ui.status
4549 else:
4552 else:
4550 write = ui.write
4553 write = ui.write
4551 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4554 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4552 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4555 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4553
4556
4554 def run(self):
4557 def run(self):
4555 self.httpd.serve_forever()
4558 self.httpd.serve_forever()
4556
4559
4557 service = service()
4560 service = service()
4558
4561
4559 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4562 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4560
4563
4561 @command('showconfig|debugconfig',
4564 @command('showconfig|debugconfig',
4562 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4565 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4563 _('[-u] [NAME]...'))
4566 _('[-u] [NAME]...'))
4564 def showconfig(ui, repo, *values, **opts):
4567 def showconfig(ui, repo, *values, **opts):
4565 """show combined config settings from all hgrc files
4568 """show combined config settings from all hgrc files
4566
4569
4567 With no arguments, print names and values of all config items.
4570 With no arguments, print names and values of all config items.
4568
4571
4569 With one argument of the form section.name, print just the value
4572 With one argument of the form section.name, print just the value
4570 of that config item.
4573 of that config item.
4571
4574
4572 With multiple arguments, print names and values of all config
4575 With multiple arguments, print names and values of all config
4573 items with matching section names.
4576 items with matching section names.
4574
4577
4575 With --debug, the source (filename and line number) is printed
4578 With --debug, the source (filename and line number) is printed
4576 for each config item.
4579 for each config item.
4577
4580
4578 Returns 0 on success.
4581 Returns 0 on success.
4579 """
4582 """
4580
4583
4581 for f in scmutil.rcpath():
4584 for f in scmutil.rcpath():
4582 ui.debug('read config from: %s\n' % f)
4585 ui.debug('read config from: %s\n' % f)
4583 untrusted = bool(opts.get('untrusted'))
4586 untrusted = bool(opts.get('untrusted'))
4584 if values:
4587 if values:
4585 sections = [v for v in values if '.' not in v]
4588 sections = [v for v in values if '.' not in v]
4586 items = [v for v in values if '.' in v]
4589 items = [v for v in values if '.' in v]
4587 if len(items) > 1 or items and sections:
4590 if len(items) > 1 or items and sections:
4588 raise util.Abort(_('only one config item permitted'))
4591 raise util.Abort(_('only one config item permitted'))
4589 for section, name, value in ui.walkconfig(untrusted=untrusted):
4592 for section, name, value in ui.walkconfig(untrusted=untrusted):
4590 value = str(value).replace('\n', '\\n')
4593 value = str(value).replace('\n', '\\n')
4591 sectname = section + '.' + name
4594 sectname = section + '.' + name
4592 if values:
4595 if values:
4593 for v in values:
4596 for v in values:
4594 if v == section:
4597 if v == section:
4595 ui.debug('%s: ' %
4598 ui.debug('%s: ' %
4596 ui.configsource(section, name, untrusted))
4599 ui.configsource(section, name, untrusted))
4597 ui.write('%s=%s\n' % (sectname, value))
4600 ui.write('%s=%s\n' % (sectname, value))
4598 elif v == sectname:
4601 elif v == sectname:
4599 ui.debug('%s: ' %
4602 ui.debug('%s: ' %
4600 ui.configsource(section, name, untrusted))
4603 ui.configsource(section, name, untrusted))
4601 ui.write(value, '\n')
4604 ui.write(value, '\n')
4602 else:
4605 else:
4603 ui.debug('%s: ' %
4606 ui.debug('%s: ' %
4604 ui.configsource(section, name, untrusted))
4607 ui.configsource(section, name, untrusted))
4605 ui.write('%s=%s\n' % (sectname, value))
4608 ui.write('%s=%s\n' % (sectname, value))
4606
4609
4607 @command('^status|st',
4610 @command('^status|st',
4608 [('A', 'all', None, _('show status of all files')),
4611 [('A', 'all', None, _('show status of all files')),
4609 ('m', 'modified', None, _('show only modified files')),
4612 ('m', 'modified', None, _('show only modified files')),
4610 ('a', 'added', None, _('show only added files')),
4613 ('a', 'added', None, _('show only added files')),
4611 ('r', 'removed', None, _('show only removed files')),
4614 ('r', 'removed', None, _('show only removed files')),
4612 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4615 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4613 ('c', 'clean', None, _('show only files without changes')),
4616 ('c', 'clean', None, _('show only files without changes')),
4614 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4617 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4615 ('i', 'ignored', None, _('show only ignored files')),
4618 ('i', 'ignored', None, _('show only ignored files')),
4616 ('n', 'no-status', None, _('hide status prefix')),
4619 ('n', 'no-status', None, _('hide status prefix')),
4617 ('C', 'copies', None, _('show source of copied files')),
4620 ('C', 'copies', None, _('show source of copied files')),
4618 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4621 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4619 ('', 'rev', [], _('show difference from revision'), _('REV')),
4622 ('', 'rev', [], _('show difference from revision'), _('REV')),
4620 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4623 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4621 ] + walkopts + subrepoopts,
4624 ] + walkopts + subrepoopts,
4622 _('[OPTION]... [FILE]...'))
4625 _('[OPTION]... [FILE]...'))
4623 def status(ui, repo, *pats, **opts):
4626 def status(ui, repo, *pats, **opts):
4624 """show changed files in the working directory
4627 """show changed files in the working directory
4625
4628
4626 Show status of files in the repository. If names are given, only
4629 Show status of files in the repository. If names are given, only
4627 files that match are shown. Files that are clean or ignored or
4630 files that match are shown. Files that are clean or ignored or
4628 the source of a copy/move operation, are not listed unless
4631 the source of a copy/move operation, are not listed unless
4629 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4632 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4630 Unless options described with "show only ..." are given, the
4633 Unless options described with "show only ..." are given, the
4631 options -mardu are used.
4634 options -mardu are used.
4632
4635
4633 Option -q/--quiet hides untracked (unknown and ignored) files
4636 Option -q/--quiet hides untracked (unknown and ignored) files
4634 unless explicitly requested with -u/--unknown or -i/--ignored.
4637 unless explicitly requested with -u/--unknown or -i/--ignored.
4635
4638
4636 .. note::
4639 .. note::
4637 status may appear to disagree with diff if permissions have
4640 status may appear to disagree with diff if permissions have
4638 changed or a merge has occurred. The standard diff format does
4641 changed or a merge has occurred. The standard diff format does
4639 not report permission changes and diff only reports changes
4642 not report permission changes and diff only reports changes
4640 relative to one merge parent.
4643 relative to one merge parent.
4641
4644
4642 If one revision is given, it is used as the base revision.
4645 If one revision is given, it is used as the base revision.
4643 If two revisions are given, the differences between them are
4646 If two revisions are given, the differences between them are
4644 shown. The --change option can also be used as a shortcut to list
4647 shown. The --change option can also be used as a shortcut to list
4645 the changed files of a revision from its first parent.
4648 the changed files of a revision from its first parent.
4646
4649
4647 The codes used to show the status of files are::
4650 The codes used to show the status of files are::
4648
4651
4649 M = modified
4652 M = modified
4650 A = added
4653 A = added
4651 R = removed
4654 R = removed
4652 C = clean
4655 C = clean
4653 ! = missing (deleted by non-hg command, but still tracked)
4656 ! = missing (deleted by non-hg command, but still tracked)
4654 ? = not tracked
4657 ? = not tracked
4655 I = ignored
4658 I = ignored
4656 = origin of the previous file listed as A (added)
4659 = origin of the previous file listed as A (added)
4657
4660
4658 Returns 0 on success.
4661 Returns 0 on success.
4659 """
4662 """
4660
4663
4661 revs = opts.get('rev')
4664 revs = opts.get('rev')
4662 change = opts.get('change')
4665 change = opts.get('change')
4663
4666
4664 if revs and change:
4667 if revs and change:
4665 msg = _('cannot specify --rev and --change at the same time')
4668 msg = _('cannot specify --rev and --change at the same time')
4666 raise util.Abort(msg)
4669 raise util.Abort(msg)
4667 elif change:
4670 elif change:
4668 node2 = repo.lookup(change)
4671 node2 = repo.lookup(change)
4669 node1 = repo[node2].p1().node()
4672 node1 = repo[node2].p1().node()
4670 else:
4673 else:
4671 node1, node2 = scmutil.revpair(repo, revs)
4674 node1, node2 = scmutil.revpair(repo, revs)
4672
4675
4673 cwd = (pats and repo.getcwd()) or ''
4676 cwd = (pats and repo.getcwd()) or ''
4674 end = opts.get('print0') and '\0' or '\n'
4677 end = opts.get('print0') and '\0' or '\n'
4675 copy = {}
4678 copy = {}
4676 states = 'modified added removed deleted unknown ignored clean'.split()
4679 states = 'modified added removed deleted unknown ignored clean'.split()
4677 show = [k for k in states if opts.get(k)]
4680 show = [k for k in states if opts.get(k)]
4678 if opts.get('all'):
4681 if opts.get('all'):
4679 show += ui.quiet and (states[:4] + ['clean']) or states
4682 show += ui.quiet and (states[:4] + ['clean']) or states
4680 if not show:
4683 if not show:
4681 show = ui.quiet and states[:4] or states[:5]
4684 show = ui.quiet and states[:4] or states[:5]
4682
4685
4683 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
4686 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
4684 'ignored' in show, 'clean' in show, 'unknown' in show,
4687 'ignored' in show, 'clean' in show, 'unknown' in show,
4685 opts.get('subrepos'))
4688 opts.get('subrepos'))
4686 changestates = zip(states, 'MAR!?IC', stat)
4689 changestates = zip(states, 'MAR!?IC', stat)
4687
4690
4688 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4691 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4689 ctxn = repo[nullid]
4692 ctxn = repo[nullid]
4690 ctx1 = repo[node1]
4693 ctx1 = repo[node1]
4691 ctx2 = repo[node2]
4694 ctx2 = repo[node2]
4692 added = stat[1]
4695 added = stat[1]
4693 if node2 is None:
4696 if node2 is None:
4694 added = stat[0] + stat[1] # merged?
4697 added = stat[0] + stat[1] # merged?
4695
4698
4696 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4699 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4697 if k in added:
4700 if k in added:
4698 copy[k] = v
4701 copy[k] = v
4699 elif v in added:
4702 elif v in added:
4700 copy[v] = k
4703 copy[v] = k
4701
4704
4702 for state, char, files in changestates:
4705 for state, char, files in changestates:
4703 if state in show:
4706 if state in show:
4704 format = "%s %%s%s" % (char, end)
4707 format = "%s %%s%s" % (char, end)
4705 if opts.get('no_status'):
4708 if opts.get('no_status'):
4706 format = "%%s%s" % end
4709 format = "%%s%s" % end
4707
4710
4708 for f in files:
4711 for f in files:
4709 ui.write(format % repo.pathto(f, cwd),
4712 ui.write(format % repo.pathto(f, cwd),
4710 label='status.' + state)
4713 label='status.' + state)
4711 if f in copy:
4714 if f in copy:
4712 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4715 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4713 label='status.copied')
4716 label='status.copied')
4714
4717
4715 @command('^summary|sum',
4718 @command('^summary|sum',
4716 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4719 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4717 def summary(ui, repo, **opts):
4720 def summary(ui, repo, **opts):
4718 """summarize working directory state
4721 """summarize working directory state
4719
4722
4720 This generates a brief summary of the working directory state,
4723 This generates a brief summary of the working directory state,
4721 including parents, branch, commit status, and available updates.
4724 including parents, branch, commit status, and available updates.
4722
4725
4723 With the --remote option, this will check the default paths for
4726 With the --remote option, this will check the default paths for
4724 incoming and outgoing changes. This can be time-consuming.
4727 incoming and outgoing changes. This can be time-consuming.
4725
4728
4726 Returns 0 on success.
4729 Returns 0 on success.
4727 """
4730 """
4728
4731
4729 ctx = repo[None]
4732 ctx = repo[None]
4730 parents = ctx.parents()
4733 parents = ctx.parents()
4731 pnode = parents[0].node()
4734 pnode = parents[0].node()
4732 marks = []
4735 marks = []
4733
4736
4734 for p in parents:
4737 for p in parents:
4735 # label with log.changeset (instead of log.parent) since this
4738 # label with log.changeset (instead of log.parent) since this
4736 # shows a working directory parent *changeset*:
4739 # shows a working directory parent *changeset*:
4737 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4740 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4738 label='log.changeset')
4741 label='log.changeset')
4739 ui.write(' '.join(p.tags()), label='log.tag')
4742 ui.write(' '.join(p.tags()), label='log.tag')
4740 if p.bookmarks():
4743 if p.bookmarks():
4741 marks.extend(p.bookmarks())
4744 marks.extend(p.bookmarks())
4742 if p.rev() == -1:
4745 if p.rev() == -1:
4743 if not len(repo):
4746 if not len(repo):
4744 ui.write(_(' (empty repository)'))
4747 ui.write(_(' (empty repository)'))
4745 else:
4748 else:
4746 ui.write(_(' (no revision checked out)'))
4749 ui.write(_(' (no revision checked out)'))
4747 ui.write('\n')
4750 ui.write('\n')
4748 if p.description():
4751 if p.description():
4749 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4752 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4750 label='log.summary')
4753 label='log.summary')
4751
4754
4752 branch = ctx.branch()
4755 branch = ctx.branch()
4753 bheads = repo.branchheads(branch)
4756 bheads = repo.branchheads(branch)
4754 m = _('branch: %s\n') % branch
4757 m = _('branch: %s\n') % branch
4755 if branch != 'default':
4758 if branch != 'default':
4756 ui.write(m, label='log.branch')
4759 ui.write(m, label='log.branch')
4757 else:
4760 else:
4758 ui.status(m, label='log.branch')
4761 ui.status(m, label='log.branch')
4759
4762
4760 if marks:
4763 if marks:
4761 current = repo._bookmarkcurrent
4764 current = repo._bookmarkcurrent
4762 ui.write(_('bookmarks:'), label='log.bookmark')
4765 ui.write(_('bookmarks:'), label='log.bookmark')
4763 if current is not None:
4766 if current is not None:
4764 try:
4767 try:
4765 marks.remove(current)
4768 marks.remove(current)
4766 ui.write(' *' + current, label='bookmarks.current')
4769 ui.write(' *' + current, label='bookmarks.current')
4767 except ValueError:
4770 except ValueError:
4768 # current bookmark not in parent ctx marks
4771 # current bookmark not in parent ctx marks
4769 pass
4772 pass
4770 for m in marks:
4773 for m in marks:
4771 ui.write(' ' + m, label='log.bookmark')
4774 ui.write(' ' + m, label='log.bookmark')
4772 ui.write('\n', label='log.bookmark')
4775 ui.write('\n', label='log.bookmark')
4773
4776
4774 st = list(repo.status(unknown=True))[:6]
4777 st = list(repo.status(unknown=True))[:6]
4775
4778
4776 c = repo.dirstate.copies()
4779 c = repo.dirstate.copies()
4777 copied, renamed = [], []
4780 copied, renamed = [], []
4778 for d, s in c.iteritems():
4781 for d, s in c.iteritems():
4779 if s in st[2]:
4782 if s in st[2]:
4780 st[2].remove(s)
4783 st[2].remove(s)
4781 renamed.append(d)
4784 renamed.append(d)
4782 else:
4785 else:
4783 copied.append(d)
4786 copied.append(d)
4784 if d in st[1]:
4787 if d in st[1]:
4785 st[1].remove(d)
4788 st[1].remove(d)
4786 st.insert(3, renamed)
4789 st.insert(3, renamed)
4787 st.insert(4, copied)
4790 st.insert(4, copied)
4788
4791
4789 ms = mergemod.mergestate(repo)
4792 ms = mergemod.mergestate(repo)
4790 st.append([f for f in ms if ms[f] == 'u'])
4793 st.append([f for f in ms if ms[f] == 'u'])
4791
4794
4792 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4795 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4793 st.append(subs)
4796 st.append(subs)
4794
4797
4795 labels = [ui.label(_('%d modified'), 'status.modified'),
4798 labels = [ui.label(_('%d modified'), 'status.modified'),
4796 ui.label(_('%d added'), 'status.added'),
4799 ui.label(_('%d added'), 'status.added'),
4797 ui.label(_('%d removed'), 'status.removed'),
4800 ui.label(_('%d removed'), 'status.removed'),
4798 ui.label(_('%d renamed'), 'status.copied'),
4801 ui.label(_('%d renamed'), 'status.copied'),
4799 ui.label(_('%d copied'), 'status.copied'),
4802 ui.label(_('%d copied'), 'status.copied'),
4800 ui.label(_('%d deleted'), 'status.deleted'),
4803 ui.label(_('%d deleted'), 'status.deleted'),
4801 ui.label(_('%d unknown'), 'status.unknown'),
4804 ui.label(_('%d unknown'), 'status.unknown'),
4802 ui.label(_('%d ignored'), 'status.ignored'),
4805 ui.label(_('%d ignored'), 'status.ignored'),
4803 ui.label(_('%d unresolved'), 'resolve.unresolved'),
4806 ui.label(_('%d unresolved'), 'resolve.unresolved'),
4804 ui.label(_('%d subrepos'), 'status.modified')]
4807 ui.label(_('%d subrepos'), 'status.modified')]
4805 t = []
4808 t = []
4806 for s, l in zip(st, labels):
4809 for s, l in zip(st, labels):
4807 if s:
4810 if s:
4808 t.append(l % len(s))
4811 t.append(l % len(s))
4809
4812
4810 t = ', '.join(t)
4813 t = ', '.join(t)
4811 cleanworkdir = False
4814 cleanworkdir = False
4812
4815
4813 if len(parents) > 1:
4816 if len(parents) > 1:
4814 t += _(' (merge)')
4817 t += _(' (merge)')
4815 elif branch != parents[0].branch():
4818 elif branch != parents[0].branch():
4816 t += _(' (new branch)')
4819 t += _(' (new branch)')
4817 elif (parents[0].extra().get('close') and
4820 elif (parents[0].extra().get('close') and
4818 pnode in repo.branchheads(branch, closed=True)):
4821 pnode in repo.branchheads(branch, closed=True)):
4819 t += _(' (head closed)')
4822 t += _(' (head closed)')
4820 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4823 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
4821 t += _(' (clean)')
4824 t += _(' (clean)')
4822 cleanworkdir = True
4825 cleanworkdir = True
4823 elif pnode not in bheads:
4826 elif pnode not in bheads:
4824 t += _(' (new branch head)')
4827 t += _(' (new branch head)')
4825
4828
4826 if cleanworkdir:
4829 if cleanworkdir:
4827 ui.status(_('commit: %s\n') % t.strip())
4830 ui.status(_('commit: %s\n') % t.strip())
4828 else:
4831 else:
4829 ui.write(_('commit: %s\n') % t.strip())
4832 ui.write(_('commit: %s\n') % t.strip())
4830
4833
4831 # all ancestors of branch heads - all ancestors of parent = new csets
4834 # all ancestors of branch heads - all ancestors of parent = new csets
4832 new = [0] * len(repo)
4835 new = [0] * len(repo)
4833 cl = repo.changelog
4836 cl = repo.changelog
4834 for a in [cl.rev(n) for n in bheads]:
4837 for a in [cl.rev(n) for n in bheads]:
4835 new[a] = 1
4838 new[a] = 1
4836 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
4839 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
4837 new[a] = 1
4840 new[a] = 1
4838 for a in [p.rev() for p in parents]:
4841 for a in [p.rev() for p in parents]:
4839 if a >= 0:
4842 if a >= 0:
4840 new[a] = 0
4843 new[a] = 0
4841 for a in cl.ancestors(*[p.rev() for p in parents]):
4844 for a in cl.ancestors(*[p.rev() for p in parents]):
4842 new[a] = 0
4845 new[a] = 0
4843 new = sum(new)
4846 new = sum(new)
4844
4847
4845 if new == 0:
4848 if new == 0:
4846 ui.status(_('update: (current)\n'))
4849 ui.status(_('update: (current)\n'))
4847 elif pnode not in bheads:
4850 elif pnode not in bheads:
4848 ui.write(_('update: %d new changesets (update)\n') % new)
4851 ui.write(_('update: %d new changesets (update)\n') % new)
4849 else:
4852 else:
4850 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4853 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4851 (new, len(bheads)))
4854 (new, len(bheads)))
4852
4855
4853 if opts.get('remote'):
4856 if opts.get('remote'):
4854 t = []
4857 t = []
4855 source, branches = hg.parseurl(ui.expandpath('default'))
4858 source, branches = hg.parseurl(ui.expandpath('default'))
4856 other = hg.peer(repo, {}, source)
4859 other = hg.peer(repo, {}, source)
4857 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4860 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4858 ui.debug('comparing with %s\n' % util.hidepassword(source))
4861 ui.debug('comparing with %s\n' % util.hidepassword(source))
4859 repo.ui.pushbuffer()
4862 repo.ui.pushbuffer()
4860 commoninc = discovery.findcommonincoming(repo, other)
4863 commoninc = discovery.findcommonincoming(repo, other)
4861 _common, incoming, _rheads = commoninc
4864 _common, incoming, _rheads = commoninc
4862 repo.ui.popbuffer()
4865 repo.ui.popbuffer()
4863 if incoming:
4866 if incoming:
4864 t.append(_('1 or more incoming'))
4867 t.append(_('1 or more incoming'))
4865
4868
4866 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4869 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4867 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4870 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4868 if source != dest:
4871 if source != dest:
4869 other = hg.peer(repo, {}, dest)
4872 other = hg.peer(repo, {}, dest)
4870 commoninc = None
4873 commoninc = None
4871 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4874 ui.debug('comparing with %s\n' % util.hidepassword(dest))
4872 repo.ui.pushbuffer()
4875 repo.ui.pushbuffer()
4873 common, outheads = discovery.findcommonoutgoing(repo, other,
4876 common, outheads = discovery.findcommonoutgoing(repo, other,
4874 commoninc=commoninc)
4877 commoninc=commoninc)
4875 repo.ui.popbuffer()
4878 repo.ui.popbuffer()
4876 o = repo.changelog.findmissing(common=common, heads=outheads)
4879 o = repo.changelog.findmissing(common=common, heads=outheads)
4877 if o:
4880 if o:
4878 t.append(_('%d outgoing') % len(o))
4881 t.append(_('%d outgoing') % len(o))
4879 if 'bookmarks' in other.listkeys('namespaces'):
4882 if 'bookmarks' in other.listkeys('namespaces'):
4880 lmarks = repo.listkeys('bookmarks')
4883 lmarks = repo.listkeys('bookmarks')
4881 rmarks = other.listkeys('bookmarks')
4884 rmarks = other.listkeys('bookmarks')
4882 diff = set(rmarks) - set(lmarks)
4885 diff = set(rmarks) - set(lmarks)
4883 if len(diff) > 0:
4886 if len(diff) > 0:
4884 t.append(_('%d incoming bookmarks') % len(diff))
4887 t.append(_('%d incoming bookmarks') % len(diff))
4885 diff = set(lmarks) - set(rmarks)
4888 diff = set(lmarks) - set(rmarks)
4886 if len(diff) > 0:
4889 if len(diff) > 0:
4887 t.append(_('%d outgoing bookmarks') % len(diff))
4890 t.append(_('%d outgoing bookmarks') % len(diff))
4888
4891
4889 if t:
4892 if t:
4890 ui.write(_('remote: %s\n') % (', '.join(t)))
4893 ui.write(_('remote: %s\n') % (', '.join(t)))
4891 else:
4894 else:
4892 ui.status(_('remote: (synced)\n'))
4895 ui.status(_('remote: (synced)\n'))
4893
4896
4894 @command('tag',
4897 @command('tag',
4895 [('f', 'force', None, _('force tag')),
4898 [('f', 'force', None, _('force tag')),
4896 ('l', 'local', None, _('make the tag local')),
4899 ('l', 'local', None, _('make the tag local')),
4897 ('r', 'rev', '', _('revision to tag'), _('REV')),
4900 ('r', 'rev', '', _('revision to tag'), _('REV')),
4898 ('', 'remove', None, _('remove a tag')),
4901 ('', 'remove', None, _('remove a tag')),
4899 # -l/--local is already there, commitopts cannot be used
4902 # -l/--local is already there, commitopts cannot be used
4900 ('e', 'edit', None, _('edit commit message')),
4903 ('e', 'edit', None, _('edit commit message')),
4901 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
4904 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
4902 ] + commitopts2,
4905 ] + commitopts2,
4903 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
4906 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
4904 def tag(ui, repo, name1, *names, **opts):
4907 def tag(ui, repo, name1, *names, **opts):
4905 """add one or more tags for the current or given revision
4908 """add one or more tags for the current or given revision
4906
4909
4907 Name a particular revision using <name>.
4910 Name a particular revision using <name>.
4908
4911
4909 Tags are used to name particular revisions of the repository and are
4912 Tags are used to name particular revisions of the repository and are
4910 very useful to compare different revisions, to go back to significant
4913 very useful to compare different revisions, to go back to significant
4911 earlier versions or to mark branch points as releases, etc. Changing
4914 earlier versions or to mark branch points as releases, etc. Changing
4912 an existing tag is normally disallowed; use -f/--force to override.
4915 an existing tag is normally disallowed; use -f/--force to override.
4913
4916
4914 If no revision is given, the parent of the working directory is
4917 If no revision is given, the parent of the working directory is
4915 used, or tip if no revision is checked out.
4918 used, or tip if no revision is checked out.
4916
4919
4917 To facilitate version control, distribution, and merging of tags,
4920 To facilitate version control, distribution, and merging of tags,
4918 they are stored as a file named ".hgtags" which is managed similarly
4921 they are stored as a file named ".hgtags" which is managed similarly
4919 to other project files and can be hand-edited if necessary. This
4922 to other project files and can be hand-edited if necessary. This
4920 also means that tagging creates a new commit. The file
4923 also means that tagging creates a new commit. The file
4921 ".hg/localtags" is used for local tags (not shared among
4924 ".hg/localtags" is used for local tags (not shared among
4922 repositories).
4925 repositories).
4923
4926
4924 Tag commits are usually made at the head of a branch. If the parent
4927 Tag commits are usually made at the head of a branch. If the parent
4925 of the working directory is not a branch head, :hg:`tag` aborts; use
4928 of the working directory is not a branch head, :hg:`tag` aborts; use
4926 -f/--force to force the tag commit to be based on a non-head
4929 -f/--force to force the tag commit to be based on a non-head
4927 changeset.
4930 changeset.
4928
4931
4929 See :hg:`help dates` for a list of formats valid for -d/--date.
4932 See :hg:`help dates` for a list of formats valid for -d/--date.
4930
4933
4931 Since tag names have priority over branch names during revision
4934 Since tag names have priority over branch names during revision
4932 lookup, using an existing branch name as a tag name is discouraged.
4935 lookup, using an existing branch name as a tag name is discouraged.
4933
4936
4934 Returns 0 on success.
4937 Returns 0 on success.
4935 """
4938 """
4936
4939
4937 rev_ = "."
4940 rev_ = "."
4938 names = [t.strip() for t in (name1,) + names]
4941 names = [t.strip() for t in (name1,) + names]
4939 if len(names) != len(set(names)):
4942 if len(names) != len(set(names)):
4940 raise util.Abort(_('tag names must be unique'))
4943 raise util.Abort(_('tag names must be unique'))
4941 for n in names:
4944 for n in names:
4942 if n in ['tip', '.', 'null']:
4945 if n in ['tip', '.', 'null']:
4943 raise util.Abort(_("the name '%s' is reserved") % n)
4946 raise util.Abort(_("the name '%s' is reserved") % n)
4944 if not n:
4947 if not n:
4945 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4948 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4946 if opts.get('rev') and opts.get('remove'):
4949 if opts.get('rev') and opts.get('remove'):
4947 raise util.Abort(_("--rev and --remove are incompatible"))
4950 raise util.Abort(_("--rev and --remove are incompatible"))
4948 if opts.get('rev'):
4951 if opts.get('rev'):
4949 rev_ = opts['rev']
4952 rev_ = opts['rev']
4950 message = opts.get('message')
4953 message = opts.get('message')
4951 if opts.get('remove'):
4954 if opts.get('remove'):
4952 expectedtype = opts.get('local') and 'local' or 'global'
4955 expectedtype = opts.get('local') and 'local' or 'global'
4953 for n in names:
4956 for n in names:
4954 if not repo.tagtype(n):
4957 if not repo.tagtype(n):
4955 raise util.Abort(_("tag '%s' does not exist") % n)
4958 raise util.Abort(_("tag '%s' does not exist") % n)
4956 if repo.tagtype(n) != expectedtype:
4959 if repo.tagtype(n) != expectedtype:
4957 if expectedtype == 'global':
4960 if expectedtype == 'global':
4958 raise util.Abort(_("tag '%s' is not a global tag") % n)
4961 raise util.Abort(_("tag '%s' is not a global tag") % n)
4959 else:
4962 else:
4960 raise util.Abort(_("tag '%s' is not a local tag") % n)
4963 raise util.Abort(_("tag '%s' is not a local tag") % n)
4961 rev_ = nullid
4964 rev_ = nullid
4962 if not message:
4965 if not message:
4963 # we don't translate commit messages
4966 # we don't translate commit messages
4964 message = 'Removed tag %s' % ', '.join(names)
4967 message = 'Removed tag %s' % ', '.join(names)
4965 elif not opts.get('force'):
4968 elif not opts.get('force'):
4966 for n in names:
4969 for n in names:
4967 if n in repo.tags():
4970 if n in repo.tags():
4968 raise util.Abort(_("tag '%s' already exists "
4971 raise util.Abort(_("tag '%s' already exists "
4969 "(use -f to force)") % n)
4972 "(use -f to force)") % n)
4970 if not opts.get('local'):
4973 if not opts.get('local'):
4971 p1, p2 = repo.dirstate.parents()
4974 p1, p2 = repo.dirstate.parents()
4972 if p2 != nullid:
4975 if p2 != nullid:
4973 raise util.Abort(_('uncommitted merge'))
4976 raise util.Abort(_('uncommitted merge'))
4974 bheads = repo.branchheads()
4977 bheads = repo.branchheads()
4975 if not opts.get('force') and bheads and p1 not in bheads:
4978 if not opts.get('force') and bheads and p1 not in bheads:
4976 raise util.Abort(_('not at a branch head (use -f to force)'))
4979 raise util.Abort(_('not at a branch head (use -f to force)'))
4977 r = scmutil.revsingle(repo, rev_).node()
4980 r = scmutil.revsingle(repo, rev_).node()
4978
4981
4979 if not message:
4982 if not message:
4980 # we don't translate commit messages
4983 # we don't translate commit messages
4981 message = ('Added tag %s for changeset %s' %
4984 message = ('Added tag %s for changeset %s' %
4982 (', '.join(names), short(r)))
4985 (', '.join(names), short(r)))
4983
4986
4984 date = opts.get('date')
4987 date = opts.get('date')
4985 if date:
4988 if date:
4986 date = util.parsedate(date)
4989 date = util.parsedate(date)
4987
4990
4988 if opts.get('edit'):
4991 if opts.get('edit'):
4989 message = ui.edit(message, ui.username())
4992 message = ui.edit(message, ui.username())
4990
4993
4991 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4994 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4992
4995
4993 @command('tags', [], '')
4996 @command('tags', [], '')
4994 def tags(ui, repo):
4997 def tags(ui, repo):
4995 """list repository tags
4998 """list repository tags
4996
4999
4997 This lists both regular and local tags. When the -v/--verbose
5000 This lists both regular and local tags. When the -v/--verbose
4998 switch is used, a third column "local" is printed for local tags.
5001 switch is used, a third column "local" is printed for local tags.
4999
5002
5000 Returns 0 on success.
5003 Returns 0 on success.
5001 """
5004 """
5002
5005
5003 hexfunc = ui.debugflag and hex or short
5006 hexfunc = ui.debugflag and hex or short
5004 tagtype = ""
5007 tagtype = ""
5005
5008
5006 for t, n in reversed(repo.tagslist()):
5009 for t, n in reversed(repo.tagslist()):
5007 if ui.quiet:
5010 if ui.quiet:
5008 ui.write("%s\n" % t)
5011 ui.write("%s\n" % t)
5009 continue
5012 continue
5010
5013
5011 hn = hexfunc(n)
5014 hn = hexfunc(n)
5012 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5015 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5013 spaces = " " * (30 - encoding.colwidth(t))
5016 spaces = " " * (30 - encoding.colwidth(t))
5014
5017
5015 if ui.verbose:
5018 if ui.verbose:
5016 if repo.tagtype(t) == 'local':
5019 if repo.tagtype(t) == 'local':
5017 tagtype = " local"
5020 tagtype = " local"
5018 else:
5021 else:
5019 tagtype = ""
5022 tagtype = ""
5020 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
5023 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
5021
5024
5022 @command('tip',
5025 @command('tip',
5023 [('p', 'patch', None, _('show patch')),
5026 [('p', 'patch', None, _('show patch')),
5024 ('g', 'git', None, _('use git extended diff format')),
5027 ('g', 'git', None, _('use git extended diff format')),
5025 ] + templateopts,
5028 ] + templateopts,
5026 _('[-p] [-g]'))
5029 _('[-p] [-g]'))
5027 def tip(ui, repo, **opts):
5030 def tip(ui, repo, **opts):
5028 """show the tip revision
5031 """show the tip revision
5029
5032
5030 The tip revision (usually just called the tip) is the changeset
5033 The tip revision (usually just called the tip) is the changeset
5031 most recently added to the repository (and therefore the most
5034 most recently added to the repository (and therefore the most
5032 recently changed head).
5035 recently changed head).
5033
5036
5034 If you have just made a commit, that commit will be the tip. If
5037 If you have just made a commit, that commit will be the tip. If
5035 you have just pulled changes from another repository, the tip of
5038 you have just pulled changes from another repository, the tip of
5036 that repository becomes the current tip. The "tip" tag is special
5039 that repository becomes the current tip. The "tip" tag is special
5037 and cannot be renamed or assigned to a different changeset.
5040 and cannot be renamed or assigned to a different changeset.
5038
5041
5039 Returns 0 on success.
5042 Returns 0 on success.
5040 """
5043 """
5041 displayer = cmdutil.show_changeset(ui, repo, opts)
5044 displayer = cmdutil.show_changeset(ui, repo, opts)
5042 displayer.show(repo[len(repo) - 1])
5045 displayer.show(repo[len(repo) - 1])
5043 displayer.close()
5046 displayer.close()
5044
5047
5045 @command('unbundle',
5048 @command('unbundle',
5046 [('u', 'update', None,
5049 [('u', 'update', None,
5047 _('update to new branch head if changesets were unbundled'))],
5050 _('update to new branch head if changesets were unbundled'))],
5048 _('[-u] FILE...'))
5051 _('[-u] FILE...'))
5049 def unbundle(ui, repo, fname1, *fnames, **opts):
5052 def unbundle(ui, repo, fname1, *fnames, **opts):
5050 """apply one or more changegroup files
5053 """apply one or more changegroup files
5051
5054
5052 Apply one or more compressed changegroup files generated by the
5055 Apply one or more compressed changegroup files generated by the
5053 bundle command.
5056 bundle command.
5054
5057
5055 Returns 0 on success, 1 if an update has unresolved files.
5058 Returns 0 on success, 1 if an update has unresolved files.
5056 """
5059 """
5057 fnames = (fname1,) + fnames
5060 fnames = (fname1,) + fnames
5058
5061
5059 lock = repo.lock()
5062 lock = repo.lock()
5060 wc = repo['.']
5063 wc = repo['.']
5061 try:
5064 try:
5062 for fname in fnames:
5065 for fname in fnames:
5063 f = url.open(ui, fname)
5066 f = url.open(ui, fname)
5064 gen = changegroup.readbundle(f, fname)
5067 gen = changegroup.readbundle(f, fname)
5065 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5068 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5066 lock=lock)
5069 lock=lock)
5067 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5070 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5068 finally:
5071 finally:
5069 lock.release()
5072 lock.release()
5070 return postincoming(ui, repo, modheads, opts.get('update'), None)
5073 return postincoming(ui, repo, modheads, opts.get('update'), None)
5071
5074
5072 @command('^update|up|checkout|co',
5075 @command('^update|up|checkout|co',
5073 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5076 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5074 ('c', 'check', None,
5077 ('c', 'check', None,
5075 _('update across branches if no uncommitted changes')),
5078 _('update across branches if no uncommitted changes')),
5076 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5079 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5077 ('r', 'rev', '', _('revision'), _('REV'))],
5080 ('r', 'rev', '', _('revision'), _('REV'))],
5078 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5081 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5079 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5082 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5080 """update working directory (or switch revisions)
5083 """update working directory (or switch revisions)
5081
5084
5082 Update the repository's working directory to the specified
5085 Update the repository's working directory to the specified
5083 changeset. If no changeset is specified, update to the tip of the
5086 changeset. If no changeset is specified, update to the tip of the
5084 current named branch.
5087 current named branch.
5085
5088
5086 If the changeset is not a descendant of the working directory's
5089 If the changeset is not a descendant of the working directory's
5087 parent, the update is aborted. With the -c/--check option, the
5090 parent, the update is aborted. With the -c/--check option, the
5088 working directory is checked for uncommitted changes; if none are
5091 working directory is checked for uncommitted changes; if none are
5089 found, the working directory is updated to the specified
5092 found, the working directory is updated to the specified
5090 changeset.
5093 changeset.
5091
5094
5092 Update sets the working directory's parent revison to the specified
5095 Update sets the working directory's parent revison to the specified
5093 changeset (see :hg:`help parents`).
5096 changeset (see :hg:`help parents`).
5094
5097
5095 The following rules apply when the working directory contains
5098 The following rules apply when the working directory contains
5096 uncommitted changes:
5099 uncommitted changes:
5097
5100
5098 1. If neither -c/--check nor -C/--clean is specified, and if
5101 1. If neither -c/--check nor -C/--clean is specified, and if
5099 the requested changeset is an ancestor or descendant of
5102 the requested changeset is an ancestor or descendant of
5100 the working directory's parent, the uncommitted changes
5103 the working directory's parent, the uncommitted changes
5101 are merged into the requested changeset and the merged
5104 are merged into the requested changeset and the merged
5102 result is left uncommitted. If the requested changeset is
5105 result is left uncommitted. If the requested changeset is
5103 not an ancestor or descendant (that is, it is on another
5106 not an ancestor or descendant (that is, it is on another
5104 branch), the update is aborted and the uncommitted changes
5107 branch), the update is aborted and the uncommitted changes
5105 are preserved.
5108 are preserved.
5106
5109
5107 2. With the -c/--check option, the update is aborted and the
5110 2. With the -c/--check option, the update is aborted and the
5108 uncommitted changes are preserved.
5111 uncommitted changes are preserved.
5109
5112
5110 3. With the -C/--clean option, uncommitted changes are discarded and
5113 3. With the -C/--clean option, uncommitted changes are discarded and
5111 the working directory is updated to the requested changeset.
5114 the working directory is updated to the requested changeset.
5112
5115
5113 Use null as the changeset to remove the working directory (like
5116 Use null as the changeset to remove the working directory (like
5114 :hg:`clone -U`).
5117 :hg:`clone -U`).
5115
5118
5116 If you want to revert just one file to an older revision, use
5119 If you want to revert just one file to an older revision, use
5117 :hg:`revert [-r REV] NAME`.
5120 :hg:`revert [-r REV] NAME`.
5118
5121
5119 See :hg:`help dates` for a list of formats valid for -d/--date.
5122 See :hg:`help dates` for a list of formats valid for -d/--date.
5120
5123
5121 Returns 0 on success, 1 if there are unresolved files.
5124 Returns 0 on success, 1 if there are unresolved files.
5122 """
5125 """
5123 if rev and node:
5126 if rev and node:
5124 raise util.Abort(_("please specify just one revision"))
5127 raise util.Abort(_("please specify just one revision"))
5125
5128
5126 if rev is None or rev == '':
5129 if rev is None or rev == '':
5127 rev = node
5130 rev = node
5128
5131
5129 # if we defined a bookmark, we have to remember the original bookmark name
5132 # if we defined a bookmark, we have to remember the original bookmark name
5130 brev = rev
5133 brev = rev
5131 rev = scmutil.revsingle(repo, rev, rev).rev()
5134 rev = scmutil.revsingle(repo, rev, rev).rev()
5132
5135
5133 if check and clean:
5136 if check and clean:
5134 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5137 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5135
5138
5136 if check:
5139 if check:
5137 # we could use dirty() but we can ignore merge and branch trivia
5140 # we could use dirty() but we can ignore merge and branch trivia
5138 c = repo[None]
5141 c = repo[None]
5139 if c.modified() or c.added() or c.removed():
5142 if c.modified() or c.added() or c.removed():
5140 raise util.Abort(_("uncommitted local changes"))
5143 raise util.Abort(_("uncommitted local changes"))
5141
5144
5142 if date:
5145 if date:
5143 if rev is not None:
5146 if rev is not None:
5144 raise util.Abort(_("you can't specify a revision and a date"))
5147 raise util.Abort(_("you can't specify a revision and a date"))
5145 rev = cmdutil.finddate(ui, repo, date)
5148 rev = cmdutil.finddate(ui, repo, date)
5146
5149
5147 if clean or check:
5150 if clean or check:
5148 ret = hg.clean(repo, rev)
5151 ret = hg.clean(repo, rev)
5149 else:
5152 else:
5150 ret = hg.update(repo, rev)
5153 ret = hg.update(repo, rev)
5151
5154
5152 if brev in repo._bookmarks:
5155 if brev in repo._bookmarks:
5153 bookmarks.setcurrent(repo, brev)
5156 bookmarks.setcurrent(repo, brev)
5154
5157
5155 return ret
5158 return ret
5156
5159
5157 @command('verify', [])
5160 @command('verify', [])
5158 def verify(ui, repo):
5161 def verify(ui, repo):
5159 """verify the integrity of the repository
5162 """verify the integrity of the repository
5160
5163
5161 Verify the integrity of the current repository.
5164 Verify the integrity of the current repository.
5162
5165
5163 This will perform an extensive check of the repository's
5166 This will perform an extensive check of the repository's
5164 integrity, validating the hashes and checksums of each entry in
5167 integrity, validating the hashes and checksums of each entry in
5165 the changelog, manifest, and tracked files, as well as the
5168 the changelog, manifest, and tracked files, as well as the
5166 integrity of their crosslinks and indices.
5169 integrity of their crosslinks and indices.
5167
5170
5168 Returns 0 on success, 1 if errors are encountered.
5171 Returns 0 on success, 1 if errors are encountered.
5169 """
5172 """
5170 return hg.verify(repo)
5173 return hg.verify(repo)
5171
5174
5172 @command('version', [])
5175 @command('version', [])
5173 def version_(ui):
5176 def version_(ui):
5174 """output version and copyright information"""
5177 """output version and copyright information"""
5175 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5178 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5176 % util.version())
5179 % util.version())
5177 ui.status(_(
5180 ui.status(_(
5178 "(see http://mercurial.selenic.com for more information)\n"
5181 "(see http://mercurial.selenic.com for more information)\n"
5179 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5182 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5180 "This is free software; see the source for copying conditions. "
5183 "This is free software; see the source for copying conditions. "
5181 "There is NO\nwarranty; "
5184 "There is NO\nwarranty; "
5182 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5185 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5183 ))
5186 ))
5184
5187
5185 norepo = ("clone init version help debugcommands debugcomplete"
5188 norepo = ("clone init version help debugcommands debugcomplete"
5186 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5189 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5187 " debugknown debuggetbundle debugbundle")
5190 " debugknown debuggetbundle debugbundle")
5188 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5191 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5189 " debugdata debugindex debugindexdot debugrevlog")
5192 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,519 +1,579 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, sys
21 import re, sys
22 import util, encoding
22 import util, encoding
23 from i18n import _
23 from i18n import _
24
24
25
25
26 def replace(text, substs):
26 def replace(text, substs):
27 utext = text.decode(encoding.encoding)
27 utext = text.decode(encoding.encoding)
28 for f, t in substs:
28 for f, t in substs:
29 utext = utext.replace(f, t)
29 utext = utext.replace(f, t)
30 return utext.encode(encoding.encoding)
30 return utext.encode(encoding.encoding)
31
31
32
32
33 _blockre = re.compile(r"\n(?:\s*\n)+")
33 _blockre = re.compile(r"\n(?:\s*\n)+")
34
34
35 def findblocks(text):
35 def findblocks(text):
36 """Find continuous blocks of lines in text.
36 """Find continuous blocks of lines in text.
37
37
38 Returns a list of dictionaries representing the blocks. Each block
38 Returns a list of dictionaries representing the blocks. Each block
39 has an 'indent' field and a 'lines' field.
39 has an 'indent' field and a 'lines' field.
40 """
40 """
41 blocks = []
41 blocks = []
42 for b in _blockre.split(text.lstrip('\n').rstrip()):
42 for b in _blockre.split(text.lstrip('\n').rstrip()):
43 lines = b.splitlines()
43 lines = b.splitlines()
44 indent = min((len(l) - len(l.lstrip())) for l in lines)
44 indent = min((len(l) - len(l.lstrip())) for l in lines)
45 lines = [l[indent:] for l in lines]
45 lines = [l[indent:] for l in lines]
46 blocks.append(dict(indent=indent, lines=lines))
46 blocks.append(dict(indent=indent, lines=lines))
47 return blocks
47 return blocks
48
48
49
49
50 def findliteralblocks(blocks):
50 def findliteralblocks(blocks):
51 """Finds literal blocks and adds a 'type' field to the blocks.
51 """Finds literal blocks and adds a 'type' field to the blocks.
52
52
53 Literal blocks are given the type 'literal', all other blocks are
53 Literal blocks are given the type 'literal', all other blocks are
54 given type the 'paragraph'.
54 given type the 'paragraph'.
55 """
55 """
56 i = 0
56 i = 0
57 while i < len(blocks):
57 while i < len(blocks):
58 # Searching for a block that looks like this:
58 # Searching for a block that looks like this:
59 #
59 #
60 # +------------------------------+
60 # +------------------------------+
61 # | paragraph |
61 # | paragraph |
62 # | (ends with "::") |
62 # | (ends with "::") |
63 # +------------------------------+
63 # +------------------------------+
64 # +---------------------------+
64 # +---------------------------+
65 # | indented literal block |
65 # | indented literal block |
66 # +---------------------------+
66 # +---------------------------+
67 blocks[i]['type'] = 'paragraph'
67 blocks[i]['type'] = 'paragraph'
68 if blocks[i]['lines'][-1].endswith('::') and i + 1 < len(blocks):
68 if blocks[i]['lines'][-1].endswith('::') and i + 1 < len(blocks):
69 indent = blocks[i]['indent']
69 indent = blocks[i]['indent']
70 adjustment = blocks[i + 1]['indent'] - indent
70 adjustment = blocks[i + 1]['indent'] - indent
71
71
72 if blocks[i]['lines'] == ['::']:
72 if blocks[i]['lines'] == ['::']:
73 # Expanded form: remove block
73 # Expanded form: remove block
74 del blocks[i]
74 del blocks[i]
75 i -= 1
75 i -= 1
76 elif blocks[i]['lines'][-1].endswith(' ::'):
76 elif blocks[i]['lines'][-1].endswith(' ::'):
77 # Partially minimized form: remove space and both
77 # Partially minimized form: remove space and both
78 # colons.
78 # colons.
79 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-3]
79 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-3]
80 else:
80 else:
81 # Fully minimized form: remove just one colon.
81 # Fully minimized form: remove just one colon.
82 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-1]
82 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-1]
83
83
84 # List items are formatted with a hanging indent. We must
84 # List items are formatted with a hanging indent. We must
85 # correct for this here while we still have the original
85 # correct for this here while we still have the original
86 # information on the indentation of the subsequent literal
86 # information on the indentation of the subsequent literal
87 # blocks available.
87 # blocks available.
88 m = _bulletre.match(blocks[i]['lines'][0])
88 m = _bulletre.match(blocks[i]['lines'][0])
89 if m:
89 if m:
90 indent += m.end()
90 indent += m.end()
91 adjustment -= m.end()
91 adjustment -= m.end()
92
92
93 # Mark the following indented blocks.
93 # Mark the following indented blocks.
94 while i + 1 < len(blocks) and blocks[i + 1]['indent'] > indent:
94 while i + 1 < len(blocks) and blocks[i + 1]['indent'] > indent:
95 blocks[i + 1]['type'] = 'literal'
95 blocks[i + 1]['type'] = 'literal'
96 blocks[i + 1]['indent'] -= adjustment
96 blocks[i + 1]['indent'] -= adjustment
97 i += 1
97 i += 1
98 i += 1
98 i += 1
99 return blocks
99 return blocks
100
100
101 _bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)|\|) ')
101 _bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)|\|) ')
102 _optionre = re.compile(r'^(-([a-zA-Z0-9]), )?(--[a-z0-9-]+)'
102 _optionre = re.compile(r'^(-([a-zA-Z0-9]), )?(--[a-z0-9-]+)'
103 r'((.*) +)(.*)$')
103 r'((.*) +)(.*)$')
104 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):[ ]+(.*)')
104 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):[ ]+(.*)')
105 _definitionre = re.compile(r'[^ ]')
105 _definitionre = re.compile(r'[^ ]')
106 _tablere = re.compile(r'(=+\s+)*=+')
106
107
107 def splitparagraphs(blocks):
108 def splitparagraphs(blocks):
108 """Split paragraphs into lists."""
109 """Split paragraphs into lists."""
109 # Tuples with (list type, item regexp, single line items?). Order
110 # Tuples with (list type, item regexp, single line items?). Order
110 # matters: definition lists has the least specific regexp and must
111 # matters: definition lists has the least specific regexp and must
111 # come last.
112 # come last.
112 listtypes = [('bullet', _bulletre, True),
113 listtypes = [('bullet', _bulletre, True),
113 ('option', _optionre, True),
114 ('option', _optionre, True),
114 ('field', _fieldre, True),
115 ('field', _fieldre, True),
115 ('definition', _definitionre, False)]
116 ('definition', _definitionre, False)]
116
117
117 def match(lines, i, itemre, singleline):
118 def match(lines, i, itemre, singleline):
118 """Does itemre match an item at line i?
119 """Does itemre match an item at line i?
119
120
120 A list item can be followed by an idented line or another list
121 A list item can be followed by an idented line or another list
121 item (but only if singleline is True).
122 item (but only if singleline is True).
122 """
123 """
123 line1 = lines[i]
124 line1 = lines[i]
124 line2 = i + 1 < len(lines) and lines[i + 1] or ''
125 line2 = i + 1 < len(lines) and lines[i + 1] or ''
125 if not itemre.match(line1):
126 if not itemre.match(line1):
126 return False
127 return False
127 if singleline:
128 if singleline:
128 return line2 == '' or line2[0] == ' ' or itemre.match(line2)
129 return line2 == '' or line2[0] == ' ' or itemre.match(line2)
129 else:
130 else:
130 return line2.startswith(' ')
131 return line2.startswith(' ')
131
132
132 i = 0
133 i = 0
133 while i < len(blocks):
134 while i < len(blocks):
134 if blocks[i]['type'] == 'paragraph':
135 if blocks[i]['type'] == 'paragraph':
135 lines = blocks[i]['lines']
136 lines = blocks[i]['lines']
136 for type, itemre, singleline in listtypes:
137 for type, itemre, singleline in listtypes:
137 if match(lines, 0, itemre, singleline):
138 if match(lines, 0, itemre, singleline):
138 items = []
139 items = []
139 for j, line in enumerate(lines):
140 for j, line in enumerate(lines):
140 if match(lines, j, itemre, singleline):
141 if match(lines, j, itemre, singleline):
141 items.append(dict(type=type, lines=[],
142 items.append(dict(type=type, lines=[],
142 indent=blocks[i]['indent']))
143 indent=blocks[i]['indent']))
143 items[-1]['lines'].append(line)
144 items[-1]['lines'].append(line)
144 blocks[i:i + 1] = items
145 blocks[i:i + 1] = items
145 break
146 break
146 i += 1
147 i += 1
147 return blocks
148 return blocks
148
149
149
150
150 _fieldwidth = 12
151 _fieldwidth = 12
151
152
152 def updatefieldlists(blocks):
153 def updatefieldlists(blocks):
153 """Find key and maximum key width for field lists."""
154 """Find key and maximum key width for field lists."""
154 i = 0
155 i = 0
155 while i < len(blocks):
156 while i < len(blocks):
156 if blocks[i]['type'] != 'field':
157 if blocks[i]['type'] != 'field':
157 i += 1
158 i += 1
158 continue
159 continue
159
160
160 keywidth = 0
161 keywidth = 0
161 j = i
162 j = i
162 while j < len(blocks) and blocks[j]['type'] == 'field':
163 while j < len(blocks) and blocks[j]['type'] == 'field':
163 m = _fieldre.match(blocks[j]['lines'][0])
164 m = _fieldre.match(blocks[j]['lines'][0])
164 key, rest = m.groups()
165 key, rest = m.groups()
165 blocks[j]['lines'][0] = rest
166 blocks[j]['lines'][0] = rest
166 blocks[j]['key'] = key
167 blocks[j]['key'] = key
167 keywidth = max(keywidth, len(key))
168 keywidth = max(keywidth, len(key))
168 j += 1
169 j += 1
169
170
170 for block in blocks[i:j]:
171 for block in blocks[i:j]:
171 block['keywidth'] = keywidth
172 block['keywidth'] = keywidth
172 i = j + 1
173 i = j + 1
173
174
174 return blocks
175 return blocks
175
176
176
177
177 def updateoptionlists(blocks):
178 def updateoptionlists(blocks):
178 i = 0
179 i = 0
179 while i < len(blocks):
180 while i < len(blocks):
180 if blocks[i]['type'] != 'option':
181 if blocks[i]['type'] != 'option':
181 i += 1
182 i += 1
182 continue
183 continue
183
184
184 optstrwidth = 0
185 optstrwidth = 0
185 j = i
186 j = i
186 while j < len(blocks) and blocks[j]['type'] == 'option':
187 while j < len(blocks) and blocks[j]['type'] == 'option':
187 m = _optionre.match(blocks[j]['lines'][0])
188 m = _optionre.match(blocks[j]['lines'][0])
188
189
189 shortoption = m.group(2)
190 shortoption = m.group(2)
190 group3 = m.group(3)
191 group3 = m.group(3)
191 longoption = group3[2:].strip()
192 longoption = group3[2:].strip()
192 desc = m.group(6).strip()
193 desc = m.group(6).strip()
193 longoptionarg = m.group(5).strip()
194 longoptionarg = m.group(5).strip()
194 blocks[j]['lines'][0] = desc
195 blocks[j]['lines'][0] = desc
195
196
196 noshortop = ''
197 noshortop = ''
197 if not shortoption:
198 if not shortoption:
198 noshortop = ' '
199 noshortop = ' '
199
200
200 opt = "%s%s" % (shortoption and "-%s " % shortoption or '',
201 opt = "%s%s" % (shortoption and "-%s " % shortoption or '',
201 ("%s--%s %s") % (noshortop, longoption,
202 ("%s--%s %s") % (noshortop, longoption,
202 longoptionarg))
203 longoptionarg))
203 opt = opt.rstrip()
204 opt = opt.rstrip()
204 blocks[j]['optstr'] = opt
205 blocks[j]['optstr'] = opt
205 optstrwidth = max(optstrwidth, encoding.colwidth(opt))
206 optstrwidth = max(optstrwidth, encoding.colwidth(opt))
206 j += 1
207 j += 1
207
208
208 for block in blocks[i:j]:
209 for block in blocks[i:j]:
209 block['optstrwidth'] = optstrwidth
210 block['optstrwidth'] = optstrwidth
210 i = j + 1
211 i = j + 1
211 return blocks
212 return blocks
212
213
213 def prunecontainers(blocks, keep):
214 def prunecontainers(blocks, keep):
214 """Prune unwanted containers.
215 """Prune unwanted containers.
215
216
216 The blocks must have a 'type' field, i.e., they should have been
217 The blocks must have a 'type' field, i.e., they should have been
217 run through findliteralblocks first.
218 run through findliteralblocks first.
218 """
219 """
219 pruned = []
220 pruned = []
220 i = 0
221 i = 0
221 while i + 1 < len(blocks):
222 while i + 1 < len(blocks):
222 # Searching for a block that looks like this:
223 # Searching for a block that looks like this:
223 #
224 #
224 # +-------+---------------------------+
225 # +-------+---------------------------+
225 # | ".. container ::" type |
226 # | ".. container ::" type |
226 # +---+ |
227 # +---+ |
227 # | blocks |
228 # | blocks |
228 # +-------------------------------+
229 # +-------------------------------+
229 if (blocks[i]['type'] == 'paragraph' and
230 if (blocks[i]['type'] == 'paragraph' and
230 blocks[i]['lines'][0].startswith('.. container::')):
231 blocks[i]['lines'][0].startswith('.. container::')):
231 indent = blocks[i]['indent']
232 indent = blocks[i]['indent']
232 adjustment = blocks[i + 1]['indent'] - indent
233 adjustment = blocks[i + 1]['indent'] - indent
233 containertype = blocks[i]['lines'][0][15:]
234 containertype = blocks[i]['lines'][0][15:]
234 prune = containertype not in keep
235 prune = containertype not in keep
235 if prune:
236 if prune:
236 pruned.append(containertype)
237 pruned.append(containertype)
237
238
238 # Always delete "..container:: type" block
239 # Always delete "..container:: type" block
239 del blocks[i]
240 del blocks[i]
240 j = i
241 j = i
241 while j < len(blocks) and blocks[j]['indent'] > indent:
242 while j < len(blocks) and blocks[j]['indent'] > indent:
242 if prune:
243 if prune:
243 del blocks[j]
244 del blocks[j]
244 i -= 1 # adjust outer index
245 i -= 1 # adjust outer index
245 else:
246 else:
246 blocks[j]['indent'] -= adjustment
247 blocks[j]['indent'] -= adjustment
247 j += 1
248 j += 1
248 i += 1
249 i += 1
249 return blocks, pruned
250 return blocks, pruned
250
251
251
252
252 _sectionre = re.compile(r"""^([-=`:.'"~^_*+#])\1+$""")
253 _sectionre = re.compile(r"""^([-=`:.'"~^_*+#])\1+$""")
253
254
255 def findtables(blocks):
256 '''Find simple tables
257
258 Only simple one-line table elements are supported
259 '''
260
261 for block in blocks:
262 # Searching for a block that looks like this:
263 #
264 # === ==== ===
265 # A B C
266 # === ==== === <- optional
267 # 1 2 3
268 # x y z
269 # === ==== ===
270 if (block['type'] == 'paragraph' and
271 len(block['lines']) > 4 and
272 _tablere.match(block['lines'][0]) and
273 block['lines'][0] == block['lines'][-1]):
274 block['type'] = 'table'
275 block['header'] = False
276 div = block['lines'][0]
277 columns = [x for x in xrange(len(div))
278 if div[x] == '=' and (x == 0 or div[x - 1] == ' ')]
279 rows = []
280 for l in block['lines'][1:-1]:
281 if l == div:
282 block['header'] = True
283 continue
284 row = []
285 for n, start in enumerate(columns):
286 if n + 1 < len(columns):
287 row.append(l[start:columns[n + 1]].strip())
288 else:
289 row.append(l[start:].strip())
290 rows.append(row)
291 block['table'] = rows
292
293 return blocks
294
254 def findsections(blocks):
295 def findsections(blocks):
255 """Finds sections.
296 """Finds sections.
256
297
257 The blocks must have a 'type' field, i.e., they should have been
298 The blocks must have a 'type' field, i.e., they should have been
258 run through findliteralblocks first.
299 run through findliteralblocks first.
259 """
300 """
260 for block in blocks:
301 for block in blocks:
261 # Searching for a block that looks like this:
302 # Searching for a block that looks like this:
262 #
303 #
263 # +------------------------------+
304 # +------------------------------+
264 # | Section title |
305 # | Section title |
265 # | ------------- |
306 # | ------------- |
266 # +------------------------------+
307 # +------------------------------+
267 if (block['type'] == 'paragraph' and
308 if (block['type'] == 'paragraph' and
268 len(block['lines']) == 2 and
309 len(block['lines']) == 2 and
269 encoding.colwidth(block['lines'][0]) == len(block['lines'][1]) and
310 encoding.colwidth(block['lines'][0]) == len(block['lines'][1]) and
270 _sectionre.match(block['lines'][1])):
311 _sectionre.match(block['lines'][1])):
271 block['underline'] = block['lines'][1][0]
312 block['underline'] = block['lines'][1][0]
272 block['type'] = 'section'
313 block['type'] = 'section'
273 del block['lines'][1]
314 del block['lines'][1]
274 return blocks
315 return blocks
275
316
276
317
277 def inlineliterals(blocks):
318 def inlineliterals(blocks):
278 substs = [('``', '"')]
319 substs = [('``', '"')]
279 for b in blocks:
320 for b in blocks:
280 if b['type'] in ('paragraph', 'section'):
321 if b['type'] in ('paragraph', 'section'):
281 b['lines'] = [replace(l, substs) for l in b['lines']]
322 b['lines'] = [replace(l, substs) for l in b['lines']]
282 return blocks
323 return blocks
283
324
284
325
285 def hgrole(blocks):
326 def hgrole(blocks):
286 substs = [(':hg:`', '"hg '), ('`', '"')]
327 substs = [(':hg:`', '"hg '), ('`', '"')]
287 for b in blocks:
328 for b in blocks:
288 if b['type'] in ('paragraph', 'section'):
329 if b['type'] in ('paragraph', 'section'):
289 # Turn :hg:`command` into "hg command". This also works
330 # Turn :hg:`command` into "hg command". This also works
290 # when there is a line break in the command and relies on
331 # when there is a line break in the command and relies on
291 # the fact that we have no stray back-quotes in the input
332 # the fact that we have no stray back-quotes in the input
292 # (run the blocks through inlineliterals first).
333 # (run the blocks through inlineliterals first).
293 b['lines'] = [replace(l, substs) for l in b['lines']]
334 b['lines'] = [replace(l, substs) for l in b['lines']]
294 return blocks
335 return blocks
295
336
296
337
297 def addmargins(blocks):
338 def addmargins(blocks):
298 """Adds empty blocks for vertical spacing.
339 """Adds empty blocks for vertical spacing.
299
340
300 This groups bullets, options, and definitions together with no vertical
341 This groups bullets, options, and definitions together with no vertical
301 space between them, and adds an empty block between all other blocks.
342 space between them, and adds an empty block between all other blocks.
302 """
343 """
303 i = 1
344 i = 1
304 while i < len(blocks):
345 while i < len(blocks):
305 if (blocks[i]['type'] == blocks[i - 1]['type'] and
346 if (blocks[i]['type'] == blocks[i - 1]['type'] and
306 blocks[i]['type'] in ('bullet', 'option', 'field')):
347 blocks[i]['type'] in ('bullet', 'option', 'field')):
307 i += 1
348 i += 1
308 else:
349 else:
309 blocks.insert(i, dict(lines=[''], indent=0, type='margin'))
350 blocks.insert(i, dict(lines=[''], indent=0, type='margin'))
310 i += 2
351 i += 2
311 return blocks
352 return blocks
312
353
313 def prunecomments(blocks):
354 def prunecomments(blocks):
314 """Remove comments."""
355 """Remove comments."""
315 i = 0
356 i = 0
316 while i < len(blocks):
357 while i < len(blocks):
317 b = blocks[i]
358 b = blocks[i]
318 if b['type'] == 'paragraph' and (b['lines'][0].startswith('.. ') or
359 if b['type'] == 'paragraph' and (b['lines'][0].startswith('.. ') or
319 b['lines'] == ['..']):
360 b['lines'] == ['..']):
320 del blocks[i]
361 del blocks[i]
321 if i < len(blocks) and blocks[i]['type'] == 'margin':
362 if i < len(blocks) and blocks[i]['type'] == 'margin':
322 del blocks[i]
363 del blocks[i]
323 else:
364 else:
324 i += 1
365 i += 1
325 return blocks
366 return blocks
326
367
327 _admonitionre = re.compile(r"\.\. (admonition|attention|caution|danger|"
368 _admonitionre = re.compile(r"\.\. (admonition|attention|caution|danger|"
328 r"error|hint|important|note|tip|warning)::",
369 r"error|hint|important|note|tip|warning)::",
329 flags=re.IGNORECASE)
370 flags=re.IGNORECASE)
330
371
331 def findadmonitions(blocks):
372 def findadmonitions(blocks):
332 """
373 """
333 Makes the type of the block an admonition block if
374 Makes the type of the block an admonition block if
334 the first line is an admonition directive
375 the first line is an admonition directive
335 """
376 """
336 i = 0
377 i = 0
337 while i < len(blocks):
378 while i < len(blocks):
338 m = _admonitionre.match(blocks[i]['lines'][0])
379 m = _admonitionre.match(blocks[i]['lines'][0])
339 if m:
380 if m:
340 blocks[i]['type'] = 'admonition'
381 blocks[i]['type'] = 'admonition'
341 admonitiontitle = blocks[i]['lines'][0][3:m.end() - 2].lower()
382 admonitiontitle = blocks[i]['lines'][0][3:m.end() - 2].lower()
342
383
343 firstline = blocks[i]['lines'][0][m.end() + 1:]
384 firstline = blocks[i]['lines'][0][m.end() + 1:]
344 if firstline:
385 if firstline:
345 blocks[i]['lines'].insert(1, ' ' + firstline)
386 blocks[i]['lines'].insert(1, ' ' + firstline)
346
387
347 blocks[i]['admonitiontitle'] = admonitiontitle
388 blocks[i]['admonitiontitle'] = admonitiontitle
348 del blocks[i]['lines'][0]
389 del blocks[i]['lines'][0]
349 i = i + 1
390 i = i + 1
350 return blocks
391 return blocks
351
392
352 _admonitiontitles = {'attention': _('Attention:'),
393 _admonitiontitles = {'attention': _('Attention:'),
353 'caution': _('Caution:'),
394 'caution': _('Caution:'),
354 'danger': _('!Danger!') ,
395 'danger': _('!Danger!') ,
355 'error': _('Error:'),
396 'error': _('Error:'),
356 'hint': _('Hint:'),
397 'hint': _('Hint:'),
357 'important': _('Important:'),
398 'important': _('Important:'),
358 'note': _('Note:'),
399 'note': _('Note:'),
359 'tip': _('Tip:'),
400 'tip': _('Tip:'),
360 'warning': _('Warning!')}
401 'warning': _('Warning!')}
361
402
362 def formatoption(block, width):
403 def formatoption(block, width):
363 desc = ' '.join(map(str.strip, block['lines']))
404 desc = ' '.join(map(str.strip, block['lines']))
364 colwidth = encoding.colwidth(block['optstr'])
405 colwidth = encoding.colwidth(block['optstr'])
365 usablewidth = width - 1
406 usablewidth = width - 1
366 hanging = block['optstrwidth']
407 hanging = block['optstrwidth']
367 initindent = '%s%s ' % (block['optstr'], ' ' * ((hanging - colwidth)))
408 initindent = '%s%s ' % (block['optstr'], ' ' * ((hanging - colwidth)))
368 hangindent = ' ' * (encoding.colwidth(initindent) + 1)
409 hangindent = ' ' * (encoding.colwidth(initindent) + 1)
369 return ' %s' % (util.wrap(desc, usablewidth,
410 return ' %s' % (util.wrap(desc, usablewidth,
370 initindent=initindent,
411 initindent=initindent,
371 hangindent=hangindent))
412 hangindent=hangindent))
372
413
373 def formatblock(block, width):
414 def formatblock(block, width):
374 """Format a block according to width."""
415 """Format a block according to width."""
375 if width <= 0:
416 if width <= 0:
376 width = 78
417 width = 78
377 indent = ' ' * block['indent']
418 indent = ' ' * block['indent']
378 if block['type'] == 'admonition':
419 if block['type'] == 'admonition':
379 admonition = _admonitiontitles[block['admonitiontitle']]
420 admonition = _admonitiontitles[block['admonitiontitle']]
380 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
421 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
381
422
382 defindent = indent + hang * ' '
423 defindent = indent + hang * ' '
383 text = ' '.join(map(str.strip, block['lines']))
424 text = ' '.join(map(str.strip, block['lines']))
384 return '%s\n%s' % (indent + admonition, util.wrap(text, width=width,
425 return '%s\n%s' % (indent + admonition, util.wrap(text, width=width,
385 initindent=defindent,
426 initindent=defindent,
386 hangindent=defindent))
427 hangindent=defindent))
387 if block['type'] == 'margin':
428 if block['type'] == 'margin':
388 return ''
429 return ''
389 if block['type'] == 'literal':
430 if block['type'] == 'literal':
390 indent += ' '
431 indent += ' '
391 return indent + ('\n' + indent).join(block['lines'])
432 return indent + ('\n' + indent).join(block['lines'])
392 if block['type'] == 'section':
433 if block['type'] == 'section':
393 underline = encoding.colwidth(block['lines'][0]) * block['underline']
434 underline = encoding.colwidth(block['lines'][0]) * block['underline']
394 return "%s%s\n%s%s" % (indent, block['lines'][0],indent, underline)
435 return "%s%s\n%s%s" % (indent, block['lines'][0],indent, underline)
436 if block['type'] == 'table':
437 table = block['table']
438 # compute column widths
439 widths = [max([encoding.colwidth(e) for e in c]) for c in zip(*table)]
440 text = ''
441 span = sum(widths) + len(widths) - 1
442 indent = ' ' * block['indent']
443 hang = ' ' * (len(indent) + span - widths[-1])
444 f = ' '.join('%%-%ds' % n for n in widths)
445
446 for row in table:
447 l = f % tuple(row)
448 l = util.wrap(l, width=width, initindent=indent, hangindent=hang)
449 if not text and block['header']:
450 text = l + '\n' + indent + '-' * (min(width, span)) + '\n'
451 else:
452 text += l + "\n"
453 return text
395 if block['type'] == 'definition':
454 if block['type'] == 'definition':
396 term = indent + block['lines'][0]
455 term = indent + block['lines'][0]
397 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
456 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
398 defindent = indent + hang * ' '
457 defindent = indent + hang * ' '
399 text = ' '.join(map(str.strip, block['lines'][1:]))
458 text = ' '.join(map(str.strip, block['lines'][1:]))
400 return '%s\n%s' % (term, util.wrap(text, width=width,
459 return '%s\n%s' % (term, util.wrap(text, width=width,
401 initindent=defindent,
460 initindent=defindent,
402 hangindent=defindent))
461 hangindent=defindent))
403 subindent = indent
462 subindent = indent
404 if block['type'] == 'bullet':
463 if block['type'] == 'bullet':
405 if block['lines'][0].startswith('| '):
464 if block['lines'][0].startswith('| '):
406 # Remove bullet for line blocks and add no extra
465 # Remove bullet for line blocks and add no extra
407 # indention.
466 # indention.
408 block['lines'][0] = block['lines'][0][2:]
467 block['lines'][0] = block['lines'][0][2:]
409 else:
468 else:
410 m = _bulletre.match(block['lines'][0])
469 m = _bulletre.match(block['lines'][0])
411 subindent = indent + m.end() * ' '
470 subindent = indent + m.end() * ' '
412 elif block['type'] == 'field':
471 elif block['type'] == 'field':
413 keywidth = block['keywidth']
472 keywidth = block['keywidth']
414 key = block['key']
473 key = block['key']
415
474
416 subindent = indent + _fieldwidth * ' '
475 subindent = indent + _fieldwidth * ' '
417 if len(key) + 2 > _fieldwidth:
476 if len(key) + 2 > _fieldwidth:
418 # key too large, use full line width
477 # key too large, use full line width
419 key = key.ljust(width)
478 key = key.ljust(width)
420 elif keywidth + 2 < _fieldwidth:
479 elif keywidth + 2 < _fieldwidth:
421 # all keys are small, add only two spaces
480 # all keys are small, add only two spaces
422 key = key.ljust(keywidth + 2)
481 key = key.ljust(keywidth + 2)
423 subindent = indent + (keywidth + 2) * ' '
482 subindent = indent + (keywidth + 2) * ' '
424 else:
483 else:
425 # mixed sizes, use fieldwidth for this one
484 # mixed sizes, use fieldwidth for this one
426 key = key.ljust(_fieldwidth)
485 key = key.ljust(_fieldwidth)
427 block['lines'][0] = key + block['lines'][0]
486 block['lines'][0] = key + block['lines'][0]
428 elif block['type'] == 'option':
487 elif block['type'] == 'option':
429 return formatoption(block, width)
488 return formatoption(block, width)
430
489
431 text = ' '.join(map(str.strip, block['lines']))
490 text = ' '.join(map(str.strip, block['lines']))
432 return util.wrap(text, width=width,
491 return util.wrap(text, width=width,
433 initindent=indent,
492 initindent=indent,
434 hangindent=subindent)
493 hangindent=subindent)
435
494
436 def parse(text, indent=0, keep=None):
495 def parse(text, indent=0, keep=None):
437 """Parse text into a list of blocks"""
496 """Parse text into a list of blocks"""
438 pruned = []
497 pruned = []
439 blocks = findblocks(text)
498 blocks = findblocks(text)
440 for b in blocks:
499 for b in blocks:
441 b['indent'] += indent
500 b['indent'] += indent
442 blocks = findliteralblocks(blocks)
501 blocks = findliteralblocks(blocks)
502 blocks = findtables(blocks)
443 blocks, pruned = prunecontainers(blocks, keep or [])
503 blocks, pruned = prunecontainers(blocks, keep or [])
444 blocks = findsections(blocks)
504 blocks = findsections(blocks)
445 blocks = inlineliterals(blocks)
505 blocks = inlineliterals(blocks)
446 blocks = hgrole(blocks)
506 blocks = hgrole(blocks)
447 blocks = splitparagraphs(blocks)
507 blocks = splitparagraphs(blocks)
448 blocks = updatefieldlists(blocks)
508 blocks = updatefieldlists(blocks)
449 blocks = updateoptionlists(blocks)
509 blocks = updateoptionlists(blocks)
450 blocks = addmargins(blocks)
510 blocks = addmargins(blocks)
451 blocks = prunecomments(blocks)
511 blocks = prunecomments(blocks)
452 blocks = findadmonitions(blocks)
512 blocks = findadmonitions(blocks)
453 return blocks, pruned
513 return blocks, pruned
454
514
455 def formatblocks(blocks, width):
515 def formatblocks(blocks, width):
456 text = '\n'.join(formatblock(b, width) for b in blocks)
516 text = '\n'.join(formatblock(b, width) for b in blocks)
457 return text
517 return text
458
518
459 def format(text, width, indent=0, keep=None):
519 def format(text, width, indent=0, keep=None):
460 """Parse and format the text according to width."""
520 """Parse and format the text according to width."""
461 blocks, pruned = parse(text, indent, keep or [])
521 blocks, pruned = parse(text, indent, keep or [])
462 text = '\n'.join(formatblock(b, width) for b in blocks)
522 text = '\n'.join(formatblock(b, width) for b in blocks)
463 if keep is None:
523 if keep is None:
464 return text
524 return text
465 else:
525 else:
466 return text, pruned
526 return text, pruned
467
527
468 def getsections(blocks):
528 def getsections(blocks):
469 '''return a list of (section name, nesting level, blocks) tuples'''
529 '''return a list of (section name, nesting level, blocks) tuples'''
470 nest = ""
530 nest = ""
471 level = 0
531 level = 0
472 secs = []
532 secs = []
473 for b in blocks:
533 for b in blocks:
474 if b['type'] == 'section':
534 if b['type'] == 'section':
475 i = b['underline']
535 i = b['underline']
476 if i not in nest:
536 if i not in nest:
477 nest += i
537 nest += i
478 level = nest.index(i) + 1
538 level = nest.index(i) + 1
479 nest = nest[:level]
539 nest = nest[:level]
480 secs.append((b['lines'][0], level, [b]))
540 secs.append((b['lines'][0], level, [b]))
481 else:
541 else:
482 if not secs:
542 if not secs:
483 # add an initial empty section
543 # add an initial empty section
484 secs = [('', 0, [])]
544 secs = [('', 0, [])]
485 secs[-1][2].append(b)
545 secs[-1][2].append(b)
486 return secs
546 return secs
487
547
488 def decorateblocks(blocks, width):
548 def decorateblocks(blocks, width):
489 '''generate a list of (section name, line text) pairs for search'''
549 '''generate a list of (section name, line text) pairs for search'''
490 lines = []
550 lines = []
491 for s in getsections(blocks):
551 for s in getsections(blocks):
492 section = s[0]
552 section = s[0]
493 text = formatblocks(s[2], width)
553 text = formatblocks(s[2], width)
494 lines.append([(section, l) for l in text.splitlines(True)])
554 lines.append([(section, l) for l in text.splitlines(True)])
495 return lines
555 return lines
496
556
497 if __name__ == "__main__":
557 if __name__ == "__main__":
498 from pprint import pprint
558 from pprint import pprint
499
559
500 def debug(func, *args):
560 def debug(func, *args):
501 blocks = func(*args)
561 blocks = func(*args)
502 print "*** after %s:" % func.__name__
562 print "*** after %s:" % func.__name__
503 pprint(blocks)
563 pprint(blocks)
504 print
564 print
505 return blocks
565 return blocks
506
566
507 text = sys.stdin.read()
567 text = sys.stdin.read()
508 blocks = debug(findblocks, text)
568 blocks = debug(findblocks, text)
509 blocks = debug(findliteralblocks, blocks)
569 blocks = debug(findliteralblocks, blocks)
510 blocks, pruned = debug(prunecontainers, blocks, sys.argv[1:])
570 blocks, pruned = debug(prunecontainers, blocks, sys.argv[1:])
511 blocks = debug(inlineliterals, blocks)
571 blocks = debug(inlineliterals, blocks)
512 blocks = debug(splitparagraphs, blocks)
572 blocks = debug(splitparagraphs, blocks)
513 blocks = debug(updatefieldlists, blocks)
573 blocks = debug(updatefieldlists, blocks)
514 blocks = debug(updateoptionlists, blocks)
574 blocks = debug(updateoptionlists, blocks)
515 blocks = debug(findsections, blocks)
575 blocks = debug(findsections, blocks)
516 blocks = debug(addmargins, blocks)
576 blocks = debug(addmargins, blocks)
517 blocks = debug(prunecomments, blocks)
577 blocks = debug(prunecomments, blocks)
518 blocks = debug(findadmonitions, blocks)
578 blocks = debug(findadmonitions, blocks)
519 print '\n'.join(formatblock(b, 30) for b in blocks)
579 print '\n'.join(formatblock(b, 30) for b in blocks)
@@ -1,233 +1,245 b''
1 from pprint import pprint
1 from pprint import pprint
2 from mercurial import minirst
2 from mercurial import minirst
3
3
4 def debugformat(title, text, width, **kwargs):
4 def debugformat(title, text, width, **kwargs):
5 print "%s formatted to fit within %d characters:" % (title, width)
5 print "%s formatted to fit within %d characters:" % (title, width)
6 print "-" * 70
6 print "-" * 70
7 formatted = minirst.format(text, width, **kwargs)
7 formatted = minirst.format(text, width, **kwargs)
8 if type(formatted) == tuple:
8 if type(formatted) == tuple:
9 print formatted[0]
9 print formatted[0]
10 print "-" * 70
10 print "-" * 70
11 pprint(formatted[1])
11 pprint(formatted[1])
12 else:
12 else:
13 print formatted
13 print formatted
14 print "-" * 70
14 print "-" * 70
15 print
15 print
16
16
17 paragraphs = """
17 paragraphs = """
18 This is some text in the first paragraph.
18 This is some text in the first paragraph.
19
19
20 A small indented paragraph.
20 A small indented paragraph.
21 It is followed by some lines
21 It is followed by some lines
22 containing random whitespace.
22 containing random whitespace.
23 \n \n \nThe third and final paragraph.
23 \n \n \nThe third and final paragraph.
24 """
24 """
25
25
26 debugformat('paragraphs', paragraphs, 60)
26 debugformat('paragraphs', paragraphs, 60)
27 debugformat('paragraphs', paragraphs, 30)
27 debugformat('paragraphs', paragraphs, 30)
28
28
29
29
30 definitions = """
30 definitions = """
31 A Term
31 A Term
32 Definition. The indented
32 Definition. The indented
33 lines make up the definition.
33 lines make up the definition.
34 Another Term
34 Another Term
35 Another definition. The final line in the
35 Another definition. The final line in the
36 definition determines the indentation, so
36 definition determines the indentation, so
37 this will be indented with four spaces.
37 this will be indented with four spaces.
38
38
39 A Nested/Indented Term
39 A Nested/Indented Term
40 Definition.
40 Definition.
41 """
41 """
42
42
43 debugformat('definitions', definitions, 60)
43 debugformat('definitions', definitions, 60)
44 debugformat('definitions', definitions, 30)
44 debugformat('definitions', definitions, 30)
45
45
46
46
47 literals = r"""
47 literals = r"""
48 The fully minimized form is the most
48 The fully minimized form is the most
49 convenient form::
49 convenient form::
50
50
51 Hello
51 Hello
52 literal
52 literal
53 world
53 world
54
54
55 In the partially minimized form a paragraph
55 In the partially minimized form a paragraph
56 simply ends with space-double-colon. ::
56 simply ends with space-double-colon. ::
57
57
58 ////////////////////////////////////////
58 ////////////////////////////////////////
59 long un-wrapped line in a literal block
59 long un-wrapped line in a literal block
60 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
60 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
61
61
62 ::
62 ::
63
63
64 This literal block is started with '::',
64 This literal block is started with '::',
65 the so-called expanded form. The paragraph
65 the so-called expanded form. The paragraph
66 with '::' disappears in the final output.
66 with '::' disappears in the final output.
67 """
67 """
68
68
69 debugformat('literals', literals, 60)
69 debugformat('literals', literals, 60)
70 debugformat('literals', literals, 30)
70 debugformat('literals', literals, 30)
71
71
72
72
73 lists = """
73 lists = """
74 - This is the first list item.
74 - This is the first list item.
75
75
76 Second paragraph in the first list item.
76 Second paragraph in the first list item.
77
77
78 - List items need not be separated
78 - List items need not be separated
79 by a blank line.
79 by a blank line.
80 - And will be rendered without
80 - And will be rendered without
81 one in any case.
81 one in any case.
82
82
83 We can have indented lists:
83 We can have indented lists:
84
84
85 - This is an indented list item
85 - This is an indented list item
86
86
87 - Another indented list item::
87 - Another indented list item::
88
88
89 - A literal block in the middle
89 - A literal block in the middle
90 of an indented list.
90 of an indented list.
91
91
92 (The above is not a list item since we are in the literal block.)
92 (The above is not a list item since we are in the literal block.)
93
93
94 ::
94 ::
95
95
96 Literal block with no indentation (apart from
96 Literal block with no indentation (apart from
97 the two spaces added to all literal blocks).
97 the two spaces added to all literal blocks).
98
98
99 1. This is an enumerated list (first item).
99 1. This is an enumerated list (first item).
100 2. Continuing with the second item.
100 2. Continuing with the second item.
101
101
102 (1) foo
102 (1) foo
103 (2) bar
103 (2) bar
104
104
105 1) Another
105 1) Another
106 2) List
106 2) List
107
107
108 Line blocks are also a form of list:
108 Line blocks are also a form of list:
109
109
110 | This is the first line.
110 | This is the first line.
111 The line continues here.
111 The line continues here.
112 | This is the second line.
112 | This is the second line.
113 """
113 """
114
114
115 debugformat('lists', lists, 60)
115 debugformat('lists', lists, 60)
116 debugformat('lists', lists, 30)
116 debugformat('lists', lists, 30)
117
117
118
118
119 options = """
119 options = """
120 There is support for simple option lists,
120 There is support for simple option lists,
121 but only with long options:
121 but only with long options:
122
122
123 -X, --exclude filter an option with a short and long option with an argument
123 -X, --exclude filter an option with a short and long option with an argument
124 -I, --include an option with both a short option and a long option
124 -I, --include an option with both a short option and a long option
125 --all Output all.
125 --all Output all.
126 --both Output both (this description is
126 --both Output both (this description is
127 quite long).
127 quite long).
128 --long Output all day long.
128 --long Output all day long.
129
129
130 --par This option has two paragraphs in its description.
130 --par This option has two paragraphs in its description.
131 This is the first.
131 This is the first.
132
132
133 This is the second. Blank lines may be omitted between
133 This is the second. Blank lines may be omitted between
134 options (as above) or left in (as here).
134 options (as above) or left in (as here).
135
135
136
136
137 The next paragraph looks like an option list, but lacks the two-space
137 The next paragraph looks like an option list, but lacks the two-space
138 marker after the option. It is treated as a normal paragraph:
138 marker after the option. It is treated as a normal paragraph:
139
139
140 --foo bar baz
140 --foo bar baz
141 """
141 """
142
142
143 debugformat('options', options, 60)
143 debugformat('options', options, 60)
144 debugformat('options', options, 30)
144 debugformat('options', options, 30)
145
145
146
146
147 fields = """
147 fields = """
148 :a: First item.
148 :a: First item.
149 :ab: Second item. Indentation and wrapping
149 :ab: Second item. Indentation and wrapping
150 is handled automatically.
150 is handled automatically.
151
151
152 Next list:
152 Next list:
153
153
154 :small: The larger key below triggers full indentation here.
154 :small: The larger key below triggers full indentation here.
155 :much too large: This key is big enough to get its own line.
155 :much too large: This key is big enough to get its own line.
156 """
156 """
157
157
158 debugformat('fields', fields, 60)
158 debugformat('fields', fields, 60)
159 debugformat('fields', fields, 30)
159 debugformat('fields', fields, 30)
160
160
161 containers = """
161 containers = """
162 Normal output.
162 Normal output.
163
163
164 .. container:: debug
164 .. container:: debug
165
165
166 Initial debug output.
166 Initial debug output.
167
167
168 .. container:: verbose
168 .. container:: verbose
169
169
170 Verbose output.
170 Verbose output.
171
171
172 .. container:: debug
172 .. container:: debug
173
173
174 Debug output.
174 Debug output.
175 """
175 """
176
176
177 debugformat('containers (normal)', containers, 60)
177 debugformat('containers (normal)', containers, 60)
178 debugformat('containers (verbose)', containers, 60, keep=['verbose'])
178 debugformat('containers (verbose)', containers, 60, keep=['verbose'])
179 debugformat('containers (debug)', containers, 60, keep=['debug'])
179 debugformat('containers (debug)', containers, 60, keep=['debug'])
180 debugformat('containers (verbose debug)', containers, 60,
180 debugformat('containers (verbose debug)', containers, 60,
181 keep=['verbose', 'debug'])
181 keep=['verbose', 'debug'])
182
182
183 roles = """Please see :hg:`add`."""
183 roles = """Please see :hg:`add`."""
184 debugformat('roles', roles, 60)
184 debugformat('roles', roles, 60)
185
185
186
186
187 sections = """
187 sections = """
188 Title
188 Title
189 =====
189 =====
190
190
191 Section
191 Section
192 -------
192 -------
193
193
194 Subsection
194 Subsection
195 ''''''''''
195 ''''''''''
196
196
197 Markup: ``foo`` and :hg:`help`
197 Markup: ``foo`` and :hg:`help`
198 ------------------------------
198 ------------------------------
199 """
199 """
200 debugformat('sections', sections, 20)
200 debugformat('sections', sections, 20)
201
201
202
202
203 admonitions = """
203 admonitions = """
204 .. note::
204 .. note::
205 This is a note
205 This is a note
206
206
207 - Bullet 1
207 - Bullet 1
208 - Bullet 2
208 - Bullet 2
209
209
210 .. warning:: This is a warning Second
210 .. warning:: This is a warning Second
211 input line of warning
211 input line of warning
212
212
213 .. danger::
213 .. danger::
214 This is danger
214 This is danger
215 """
215 """
216
216
217 debugformat('admonitions', admonitions, 30)
217 debugformat('admonitions', admonitions, 30)
218
218
219 comments = """
219 comments = """
220 Some text.
220 Some text.
221
221
222 .. A comment
222 .. A comment
223
223
224 .. An indented comment
224 .. An indented comment
225
225
226 Some indented text.
226 Some indented text.
227
227
228 ..
228 ..
229
229
230 Empty comment above
230 Empty comment above
231 """
231 """
232
232
233 debugformat('comments', comments, 30)
233 debugformat('comments', comments, 30)
234
235 table = """
236 === === ===
237 a b c
238 === === ===
239 1 2 3
240 foo bar baz
241 aa bb sdfsdfsdf this line is way too long for this cell.
242 === === ===
243 """
244
245 debugformat('table', table, 30)
@@ -1,390 +1,402 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 paragraphs formatted to fit within 30 characters:
11 paragraphs formatted to fit within 30 characters:
12 ----------------------------------------------------------------------
12 ----------------------------------------------------------------------
13 This is some text in the first
13 This is some text in the first
14 paragraph.
14 paragraph.
15
15
16 A small indented paragraph.
16 A small indented paragraph.
17 It is followed by some lines
17 It is followed by some lines
18 containing random
18 containing random
19 whitespace.
19 whitespace.
20
20
21 The third and final paragraph.
21 The third and final paragraph.
22 ----------------------------------------------------------------------
22 ----------------------------------------------------------------------
23
23
24 definitions formatted to fit within 60 characters:
24 definitions formatted to fit within 60 characters:
25 ----------------------------------------------------------------------
25 ----------------------------------------------------------------------
26 A Term
26 A Term
27 Definition. The indented lines make up the definition.
27 Definition. The indented lines make up the definition.
28
28
29 Another Term
29 Another Term
30 Another definition. The final line in the definition
30 Another definition. The final line in the definition
31 determines the indentation, so this will be indented
31 determines the indentation, so this will be indented
32 with four spaces.
32 with four spaces.
33
33
34 A Nested/Indented Term
34 A Nested/Indented Term
35 Definition.
35 Definition.
36 ----------------------------------------------------------------------
36 ----------------------------------------------------------------------
37
37
38 definitions formatted to fit within 30 characters:
38 definitions formatted to fit within 30 characters:
39 ----------------------------------------------------------------------
39 ----------------------------------------------------------------------
40 A Term
40 A Term
41 Definition. The indented
41 Definition. The indented
42 lines make up the
42 lines make up the
43 definition.
43 definition.
44
44
45 Another Term
45 Another Term
46 Another definition. The
46 Another definition. The
47 final line in the
47 final line in the
48 definition determines the
48 definition determines the
49 indentation, so this will
49 indentation, so this will
50 be indented with four
50 be indented with four
51 spaces.
51 spaces.
52
52
53 A Nested/Indented Term
53 A Nested/Indented Term
54 Definition.
54 Definition.
55 ----------------------------------------------------------------------
55 ----------------------------------------------------------------------
56
56
57 literals formatted to fit within 60 characters:
57 literals formatted to fit within 60 characters:
58 ----------------------------------------------------------------------
58 ----------------------------------------------------------------------
59 The fully minimized form is the most convenient form:
59 The fully minimized form is the most convenient form:
60
60
61 Hello
61 Hello
62 literal
62 literal
63 world
63 world
64
64
65 In the partially minimized form a paragraph simply ends with
65 In the partially minimized form a paragraph simply ends with
66 space-double-colon.
66 space-double-colon.
67
67
68 ////////////////////////////////////////
68 ////////////////////////////////////////
69 long un-wrapped line in a literal block
69 long un-wrapped line in a literal block
70 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
70 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
71
71
72 This literal block is started with '::',
72 This literal block is started with '::',
73 the so-called expanded form. The paragraph
73 the so-called expanded form. The paragraph
74 with '::' disappears in the final output.
74 with '::' disappears in the final output.
75 ----------------------------------------------------------------------
75 ----------------------------------------------------------------------
76
76
77 literals formatted to fit within 30 characters:
77 literals formatted to fit within 30 characters:
78 ----------------------------------------------------------------------
78 ----------------------------------------------------------------------
79 The fully minimized form is
79 The fully minimized form is
80 the most convenient form:
80 the most convenient form:
81
81
82 Hello
82 Hello
83 literal
83 literal
84 world
84 world
85
85
86 In the partially minimized
86 In the partially minimized
87 form a paragraph simply ends
87 form a paragraph simply ends
88 with space-double-colon.
88 with space-double-colon.
89
89
90 ////////////////////////////////////////
90 ////////////////////////////////////////
91 long un-wrapped line in a literal block
91 long un-wrapped line in a literal block
92 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
92 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
93
93
94 This literal block is started with '::',
94 This literal block is started with '::',
95 the so-called expanded form. The paragraph
95 the so-called expanded form. The paragraph
96 with '::' disappears in the final output.
96 with '::' disappears in the final output.
97 ----------------------------------------------------------------------
97 ----------------------------------------------------------------------
98
98
99 lists formatted to fit within 60 characters:
99 lists formatted to fit within 60 characters:
100 ----------------------------------------------------------------------
100 ----------------------------------------------------------------------
101 - This is the first list item.
101 - This is the first list item.
102
102
103 Second paragraph in the first list item.
103 Second paragraph in the first list item.
104
104
105 - List items need not be separated by a blank line.
105 - List items need not be separated by a blank line.
106 - And will be rendered without one in any case.
106 - And will be rendered without one in any case.
107
107
108 We can have indented lists:
108 We can have indented lists:
109
109
110 - This is an indented list item
110 - This is an indented list item
111 - Another indented list item:
111 - Another indented list item:
112
112
113 - A literal block in the middle
113 - A literal block in the middle
114 of an indented list.
114 of an indented list.
115
115
116 (The above is not a list item since we are in the literal block.)
116 (The above is not a list item since we are in the literal block.)
117
117
118 Literal block with no indentation (apart from
118 Literal block with no indentation (apart from
119 the two spaces added to all literal blocks).
119 the two spaces added to all literal blocks).
120
120
121 1. This is an enumerated list (first item).
121 1. This is an enumerated list (first item).
122 2. Continuing with the second item.
122 2. Continuing with the second item.
123 (1) foo
123 (1) foo
124 (2) bar
124 (2) bar
125 1) Another
125 1) Another
126 2) List
126 2) List
127
127
128 Line blocks are also a form of list:
128 Line blocks are also a form of list:
129
129
130 This is the first line. The line continues here.
130 This is the first line. The line continues here.
131 This is the second line.
131 This is the second line.
132 ----------------------------------------------------------------------
132 ----------------------------------------------------------------------
133
133
134 lists formatted to fit within 30 characters:
134 lists formatted to fit within 30 characters:
135 ----------------------------------------------------------------------
135 ----------------------------------------------------------------------
136 - This is the first list item.
136 - This is the first list item.
137
137
138 Second paragraph in the
138 Second paragraph in the
139 first list item.
139 first list item.
140
140
141 - List items need not be
141 - List items need not be
142 separated by a blank line.
142 separated by a blank line.
143 - And will be rendered without
143 - And will be rendered without
144 one in any case.
144 one in any case.
145
145
146 We can have indented lists:
146 We can have indented lists:
147
147
148 - This is an indented list
148 - This is an indented list
149 item
149 item
150 - Another indented list
150 - Another indented list
151 item:
151 item:
152
152
153 - A literal block in the middle
153 - A literal block in the middle
154 of an indented list.
154 of an indented list.
155
155
156 (The above is not a list item since we are in the literal block.)
156 (The above is not a list item since we are in the literal block.)
157
157
158 Literal block with no indentation (apart from
158 Literal block with no indentation (apart from
159 the two spaces added to all literal blocks).
159 the two spaces added to all literal blocks).
160
160
161 1. This is an enumerated list
161 1. This is an enumerated list
162 (first item).
162 (first item).
163 2. Continuing with the second
163 2. Continuing with the second
164 item.
164 item.
165 (1) foo
165 (1) foo
166 (2) bar
166 (2) bar
167 1) Another
167 1) Another
168 2) List
168 2) List
169
169
170 Line blocks are also a form of
170 Line blocks are also a form of
171 list:
171 list:
172
172
173 This is the first line. The
173 This is the first line. The
174 line continues here.
174 line continues here.
175 This is the second line.
175 This is the second line.
176 ----------------------------------------------------------------------
176 ----------------------------------------------------------------------
177
177
178 options formatted to fit within 60 characters:
178 options formatted to fit within 60 characters:
179 ----------------------------------------------------------------------
179 ----------------------------------------------------------------------
180 There is support for simple option lists, but only with long
180 There is support for simple option lists, but only with long
181 options:
181 options:
182
182
183 -X --exclude filter an option with a short and long option
183 -X --exclude filter an option with a short and long option
184 with an argument
184 with an argument
185 -I --include an option with both a short option and
185 -I --include an option with both a short option and
186 a long option
186 a long option
187 --all Output all.
187 --all Output all.
188 --both Output both (this description is quite
188 --both Output both (this description is quite
189 long).
189 long).
190 --long Output all day long.
190 --long Output all day long.
191 --par This option has two paragraphs in its
191 --par This option has two paragraphs in its
192 description. This is the first.
192 description. This is the first.
193
193
194 This is the second. Blank lines may
194 This is the second. Blank lines may
195 be omitted between options (as above)
195 be omitted between options (as above)
196 or left in (as here).
196 or left in (as here).
197
197
198 The next paragraph looks like an option list, but lacks the
198 The next paragraph looks like an option list, but lacks the
199 two-space marker after the option. It is treated as a normal
199 two-space marker after the option. It is treated as a normal
200 paragraph:
200 paragraph:
201
201
202 --foo bar baz
202 --foo bar baz
203 ----------------------------------------------------------------------
203 ----------------------------------------------------------------------
204
204
205 options formatted to fit within 30 characters:
205 options formatted to fit within 30 characters:
206 ----------------------------------------------------------------------
206 ----------------------------------------------------------------------
207 There is support for simple
207 There is support for simple
208 option lists, but only with
208 option lists, but only with
209 long options:
209 long options:
210
210
211 -X --exclude filter an
211 -X --exclude filter an
212 option
212 option
213 with a
213 with a
214 short
214 short
215 and
215 and
216 long
216 long
217 option
217 option
218 with an
218 with an
219 argumen
219 argumen
220 t
220 t
221 -I --include an
221 -I --include an
222 option
222 option
223 with
223 with
224 both a
224 both a
225 short
225 short
226 option
226 option
227 and a
227 and a
228 long
228 long
229 option
229 option
230 --all Output
230 --all Output
231 all.
231 all.
232 --both Output
232 --both Output
233 both
233 both
234 (this d
234 (this d
235 escript
235 escript
236 ion is
236 ion is
237 quite
237 quite
238 long).
238 long).
239 --long Output
239 --long Output
240 all day
240 all day
241 long.
241 long.
242 --par This
242 --par This
243 option
243 option
244 has two
244 has two
245 paragra
245 paragra
246 phs in
246 phs in
247 its des
247 its des
248 criptio
248 criptio
249 n. This
249 n. This
250 is the
250 is the
251 first.
251 first.
252
252
253 This is
253 This is
254 the
254 the
255 second.
255 second.
256 Blank
256 Blank
257 lines
257 lines
258 may be
258 may be
259 omitted
259 omitted
260 between
260 between
261 options
261 options
262 (as
262 (as
263 above)
263 above)
264 or left
264 or left
265 in (as
265 in (as
266 here).
266 here).
267
267
268 The next paragraph looks like
268 The next paragraph looks like
269 an option list, but lacks the
269 an option list, but lacks the
270 two-space marker after the
270 two-space marker after the
271 option. It is treated as a
271 option. It is treated as a
272 normal paragraph:
272 normal paragraph:
273
273
274 --foo bar baz
274 --foo bar baz
275 ----------------------------------------------------------------------
275 ----------------------------------------------------------------------
276
276
277 fields formatted to fit within 60 characters:
277 fields formatted to fit within 60 characters:
278 ----------------------------------------------------------------------
278 ----------------------------------------------------------------------
279 a First item.
279 a First item.
280 ab Second item. Indentation and wrapping is handled
280 ab Second item. Indentation and wrapping is handled
281 automatically.
281 automatically.
282
282
283 Next list:
283 Next list:
284
284
285 small The larger key below triggers full indentation
285 small The larger key below triggers full indentation
286 here.
286 here.
287 much too large
287 much too large
288 This key is big enough to get its own line.
288 This key is big enough to get its own line.
289 ----------------------------------------------------------------------
289 ----------------------------------------------------------------------
290
290
291 fields formatted to fit within 30 characters:
291 fields formatted to fit within 30 characters:
292 ----------------------------------------------------------------------
292 ----------------------------------------------------------------------
293 a First item.
293 a First item.
294 ab Second item. Indentation
294 ab Second item. Indentation
295 and wrapping is handled
295 and wrapping is handled
296 automatically.
296 automatically.
297
297
298 Next list:
298 Next list:
299
299
300 small The larger key
300 small The larger key
301 below triggers
301 below triggers
302 full indentation
302 full indentation
303 here.
303 here.
304 much too large
304 much too large
305 This key is big
305 This key is big
306 enough to get its
306 enough to get its
307 own line.
307 own line.
308 ----------------------------------------------------------------------
308 ----------------------------------------------------------------------
309
309
310 containers (normal) formatted to fit within 60 characters:
310 containers (normal) formatted to fit within 60 characters:
311 ----------------------------------------------------------------------
311 ----------------------------------------------------------------------
312 Normal output.
312 Normal output.
313 ----------------------------------------------------------------------
313 ----------------------------------------------------------------------
314
314
315 containers (verbose) formatted to fit within 60 characters:
315 containers (verbose) formatted to fit within 60 characters:
316 ----------------------------------------------------------------------
316 ----------------------------------------------------------------------
317 Normal output.
317 Normal output.
318
318
319 Verbose output.
319 Verbose output.
320 ----------------------------------------------------------------------
320 ----------------------------------------------------------------------
321 ['debug', 'debug']
321 ['debug', 'debug']
322 ----------------------------------------------------------------------
322 ----------------------------------------------------------------------
323
323
324 containers (debug) formatted to fit within 60 characters:
324 containers (debug) formatted to fit within 60 characters:
325 ----------------------------------------------------------------------
325 ----------------------------------------------------------------------
326 Normal output.
326 Normal output.
327
327
328 Initial debug output.
328 Initial debug output.
329 ----------------------------------------------------------------------
329 ----------------------------------------------------------------------
330 ['verbose']
330 ['verbose']
331 ----------------------------------------------------------------------
331 ----------------------------------------------------------------------
332
332
333 containers (verbose debug) formatted to fit within 60 characters:
333 containers (verbose debug) formatted to fit within 60 characters:
334 ----------------------------------------------------------------------
334 ----------------------------------------------------------------------
335 Normal output.
335 Normal output.
336
336
337 Initial debug output.
337 Initial debug output.
338
338
339 Verbose output.
339 Verbose output.
340
340
341 Debug output.
341 Debug output.
342 ----------------------------------------------------------------------
342 ----------------------------------------------------------------------
343 []
343 []
344 ----------------------------------------------------------------------
344 ----------------------------------------------------------------------
345
345
346 roles formatted to fit within 60 characters:
346 roles formatted to fit within 60 characters:
347 ----------------------------------------------------------------------
347 ----------------------------------------------------------------------
348 Please see "hg add".
348 Please see "hg add".
349 ----------------------------------------------------------------------
349 ----------------------------------------------------------------------
350
350
351 sections formatted to fit within 20 characters:
351 sections formatted to fit within 20 characters:
352 ----------------------------------------------------------------------
352 ----------------------------------------------------------------------
353 Title
353 Title
354 =====
354 =====
355
355
356 Section
356 Section
357 -------
357 -------
358
358
359 Subsection
359 Subsection
360 ''''''''''
360 ''''''''''
361
361
362 Markup: "foo" and "hg help"
362 Markup: "foo" and "hg help"
363 ---------------------------
363 ---------------------------
364 ----------------------------------------------------------------------
364 ----------------------------------------------------------------------
365
365
366 admonitions formatted to fit within 30 characters:
366 admonitions formatted to fit within 30 characters:
367 ----------------------------------------------------------------------
367 ----------------------------------------------------------------------
368 Note:
368 Note:
369 This is a note
369 This is a note
370
370
371 - Bullet 1
371 - Bullet 1
372 - Bullet 2
372 - Bullet 2
373
373
374 Warning!
374 Warning!
375 This is a warning Second
375 This is a warning Second
376 input line of warning
376 input line of warning
377
377
378 !Danger!
378 !Danger!
379 This is danger
379 This is danger
380 ----------------------------------------------------------------------
380 ----------------------------------------------------------------------
381
381
382 comments formatted to fit within 30 characters:
382 comments formatted to fit within 30 characters:
383 ----------------------------------------------------------------------
383 ----------------------------------------------------------------------
384 Some text.
384 Some text.
385
385
386 Some indented text.
386 Some indented text.
387
387
388 Empty comment above
388 Empty comment above
389 ----------------------------------------------------------------------
389 ----------------------------------------------------------------------
390
390
391 table formatted to fit within 30 characters:
392 ----------------------------------------------------------------------
393 a b c
394 ------------------------------
395 1 2 3
396 foo bar baz
397 aa bb sdfsdfsdf this line
398 is way too long for
399 this cell.
400
401 ----------------------------------------------------------------------
402
General Comments 0
You need to be logged in to leave comments. Login now