##// END OF EJS Templates
rst: fix detection of single-row tables...
Matt Mackall -
r15192:3834ca04 default
parent child Browse files
Show More
@@ -1,5445 +1,5446 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge
18 import dagparser, context, simplemerge
19 import random, setdiscovery, treediscovery, dagutil
19 import random, setdiscovery, treediscovery, dagutil
20
20
21 table = {}
21 table = {}
22
22
23 command = cmdutil.command(table)
23 command = cmdutil.command(table)
24
24
25 # common command options
25 # common command options
26
26
27 globalopts = [
27 globalopts = [
28 ('R', 'repository', '',
28 ('R', 'repository', '',
29 _('repository root directory or name of overlay bundle file'),
29 _('repository root directory or name of overlay bundle file'),
30 _('REPO')),
30 _('REPO')),
31 ('', 'cwd', '',
31 ('', 'cwd', '',
32 _('change working directory'), _('DIR')),
32 _('change working directory'), _('DIR')),
33 ('y', 'noninteractive', None,
33 ('y', 'noninteractive', None,
34 _('do not prompt, automatically pick the first choice for all prompts')),
34 _('do not prompt, automatically pick the first choice for all prompts')),
35 ('q', 'quiet', None, _('suppress output')),
35 ('q', 'quiet', None, _('suppress output')),
36 ('v', 'verbose', None, _('enable additional output')),
36 ('v', 'verbose', None, _('enable additional output')),
37 ('', 'config', [],
37 ('', 'config', [],
38 _('set/override config option (use \'section.name=value\')'),
38 _('set/override config option (use \'section.name=value\')'),
39 _('CONFIG')),
39 _('CONFIG')),
40 ('', 'debug', None, _('enable debugging output')),
40 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debugger', None, _('start debugger')),
41 ('', 'debugger', None, _('start debugger')),
42 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
42 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 _('ENCODE')),
43 _('ENCODE')),
44 ('', 'encodingmode', encoding.encodingmode,
44 ('', 'encodingmode', encoding.encodingmode,
45 _('set the charset encoding mode'), _('MODE')),
45 _('set the charset encoding mode'), _('MODE')),
46 ('', 'traceback', None, _('always print a traceback on exception')),
46 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'time', None, _('time how long the command takes')),
47 ('', 'time', None, _('time how long the command takes')),
48 ('', 'profile', None, _('print command execution profile')),
48 ('', 'profile', None, _('print command execution profile')),
49 ('', 'version', None, _('output version information and exit')),
49 ('', 'version', None, _('output version information and exit')),
50 ('h', 'help', None, _('display help and exit')),
50 ('h', 'help', None, _('display help and exit')),
51 ]
51 ]
52
52
53 dryrunopts = [('n', 'dry-run', None,
53 dryrunopts = [('n', 'dry-run', None,
54 _('do not perform actions, just print output'))]
54 _('do not perform actions, just print output'))]
55
55
56 remoteopts = [
56 remoteopts = [
57 ('e', 'ssh', '',
57 ('e', 'ssh', '',
58 _('specify ssh command to use'), _('CMD')),
58 _('specify ssh command to use'), _('CMD')),
59 ('', 'remotecmd', '',
59 ('', 'remotecmd', '',
60 _('specify hg command to run on the remote side'), _('CMD')),
60 _('specify hg command to run on the remote side'), _('CMD')),
61 ('', 'insecure', None,
61 ('', 'insecure', None,
62 _('do not verify server certificate (ignoring web.cacerts config)')),
62 _('do not verify server certificate (ignoring web.cacerts config)')),
63 ]
63 ]
64
64
65 walkopts = [
65 walkopts = [
66 ('I', 'include', [],
66 ('I', 'include', [],
67 _('include names matching the given patterns'), _('PATTERN')),
67 _('include names matching the given patterns'), _('PATTERN')),
68 ('X', 'exclude', [],
68 ('X', 'exclude', [],
69 _('exclude names matching the given patterns'), _('PATTERN')),
69 _('exclude names matching the given patterns'), _('PATTERN')),
70 ]
70 ]
71
71
72 commitopts = [
72 commitopts = [
73 ('m', 'message', '',
73 ('m', 'message', '',
74 _('use text as commit message'), _('TEXT')),
74 _('use text as commit message'), _('TEXT')),
75 ('l', 'logfile', '',
75 ('l', 'logfile', '',
76 _('read commit message from file'), _('FILE')),
76 _('read commit message from file'), _('FILE')),
77 ]
77 ]
78
78
79 commitopts2 = [
79 commitopts2 = [
80 ('d', 'date', '',
80 ('d', 'date', '',
81 _('record the specified date as commit date'), _('DATE')),
81 _('record the specified date as commit date'), _('DATE')),
82 ('u', 'user', '',
82 ('u', 'user', '',
83 _('record the specified user as committer'), _('USER')),
83 _('record the specified user as committer'), _('USER')),
84 ]
84 ]
85
85
86 templateopts = [
86 templateopts = [
87 ('', 'style', '',
87 ('', 'style', '',
88 _('display using template map file'), _('STYLE')),
88 _('display using template map file'), _('STYLE')),
89 ('', 'template', '',
89 ('', 'template', '',
90 _('display with template'), _('TEMPLATE')),
90 _('display with template'), _('TEMPLATE')),
91 ]
91 ]
92
92
93 logopts = [
93 logopts = [
94 ('p', 'patch', None, _('show patch')),
94 ('p', 'patch', None, _('show patch')),
95 ('g', 'git', None, _('use git extended diff format')),
95 ('g', 'git', None, _('use git extended diff format')),
96 ('l', 'limit', '',
96 ('l', 'limit', '',
97 _('limit number of changes displayed'), _('NUM')),
97 _('limit number of changes displayed'), _('NUM')),
98 ('M', 'no-merges', None, _('do not show merges')),
98 ('M', 'no-merges', None, _('do not show merges')),
99 ('', 'stat', None, _('output diffstat-style summary of changes')),
99 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ] + templateopts
100 ] + templateopts
101
101
102 diffopts = [
102 diffopts = [
103 ('a', 'text', None, _('treat all files as text')),
103 ('a', 'text', None, _('treat all files as text')),
104 ('g', 'git', None, _('use git extended diff format')),
104 ('g', 'git', None, _('use git extended diff format')),
105 ('', 'nodates', None, _('omit dates from diff headers'))
105 ('', 'nodates', None, _('omit dates from diff headers'))
106 ]
106 ]
107
107
108 diffopts2 = [
108 diffopts2 = [
109 ('p', 'show-function', None, _('show which function each change is in')),
109 ('p', 'show-function', None, _('show which function each change is in')),
110 ('', 'reverse', None, _('produce a diff that undoes the changes')),
110 ('', 'reverse', None, _('produce a diff that undoes the changes')),
111 ('w', 'ignore-all-space', None,
111 ('w', 'ignore-all-space', None,
112 _('ignore white space when comparing lines')),
112 _('ignore white space when comparing lines')),
113 ('b', 'ignore-space-change', None,
113 ('b', 'ignore-space-change', None,
114 _('ignore changes in the amount of white space')),
114 _('ignore changes in the amount of white space')),
115 ('B', 'ignore-blank-lines', None,
115 ('B', 'ignore-blank-lines', None,
116 _('ignore changes whose lines are all blank')),
116 _('ignore changes whose lines are all blank')),
117 ('U', 'unified', '',
117 ('U', 'unified', '',
118 _('number of lines of context to show'), _('NUM')),
118 _('number of lines of context to show'), _('NUM')),
119 ('', 'stat', None, _('output diffstat-style summary of changes')),
119 ('', 'stat', None, _('output diffstat-style summary of changes')),
120 ]
120 ]
121
121
122 mergetoolopts = [
122 mergetoolopts = [
123 ('t', 'tool', '', _('specify merge tool')),
123 ('t', 'tool', '', _('specify merge tool')),
124 ]
124 ]
125
125
126 similarityopts = [
126 similarityopts = [
127 ('s', 'similarity', '',
127 ('s', 'similarity', '',
128 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
128 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
129 ]
129 ]
130
130
131 subrepoopts = [
131 subrepoopts = [
132 ('S', 'subrepos', None,
132 ('S', 'subrepos', None,
133 _('recurse into subrepositories'))
133 _('recurse into subrepositories'))
134 ]
134 ]
135
135
136 # Commands start here, listed alphabetically
136 # Commands start here, listed alphabetically
137
137
138 @command('^add',
138 @command('^add',
139 walkopts + subrepoopts + dryrunopts,
139 walkopts + subrepoopts + dryrunopts,
140 _('[OPTION]... [FILE]...'))
140 _('[OPTION]... [FILE]...'))
141 def add(ui, repo, *pats, **opts):
141 def add(ui, repo, *pats, **opts):
142 """add the specified files on the next commit
142 """add the specified files on the next commit
143
143
144 Schedule files to be version controlled and added to the
144 Schedule files to be version controlled and added to the
145 repository.
145 repository.
146
146
147 The files will be added to the repository at the next commit. To
147 The files will be added to the repository at the next commit. To
148 undo an add before that, see :hg:`forget`.
148 undo an add before that, see :hg:`forget`.
149
149
150 If no names are given, add all files to the repository.
150 If no names are given, add all files to the repository.
151
151
152 .. container:: verbose
152 .. container:: verbose
153
153
154 An example showing how new (unknown) files are added
154 An example showing how new (unknown) files are added
155 automatically by :hg:`add`::
155 automatically by :hg:`add`::
156
156
157 $ ls
157 $ ls
158 foo.c
158 foo.c
159 $ hg status
159 $ hg status
160 ? foo.c
160 ? foo.c
161 $ hg add
161 $ hg add
162 adding foo.c
162 adding foo.c
163 $ hg status
163 $ hg status
164 A foo.c
164 A foo.c
165
165
166 Returns 0 if all files are successfully added.
166 Returns 0 if all files are successfully added.
167 """
167 """
168
168
169 m = scmutil.match(repo[None], pats, opts)
169 m = scmutil.match(repo[None], pats, opts)
170 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
170 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
171 opts.get('subrepos'), prefix="")
171 opts.get('subrepos'), prefix="")
172 return rejected and 1 or 0
172 return rejected and 1 or 0
173
173
174 @command('addremove',
174 @command('addremove',
175 similarityopts + walkopts + dryrunopts,
175 similarityopts + walkopts + dryrunopts,
176 _('[OPTION]... [FILE]...'))
176 _('[OPTION]... [FILE]...'))
177 def addremove(ui, repo, *pats, **opts):
177 def addremove(ui, repo, *pats, **opts):
178 """add all new files, delete all missing files
178 """add all new files, delete all missing files
179
179
180 Add all new files and remove all missing files from the
180 Add all new files and remove all missing files from the
181 repository.
181 repository.
182
182
183 New files are ignored if they match any of the patterns in
183 New files are ignored if they match any of the patterns in
184 ``.hgignore``. As with add, these changes take effect at the next
184 ``.hgignore``. As with add, these changes take effect at the next
185 commit.
185 commit.
186
186
187 Use the -s/--similarity option to detect renamed files. With a
187 Use the -s/--similarity option to detect renamed files. With a
188 parameter greater than 0, this compares every removed file with
188 parameter greater than 0, this compares every removed file with
189 every added file and records those similar enough as renames. This
189 every added file and records those similar enough as renames. This
190 option takes a percentage between 0 (disabled) and 100 (files must
190 option takes a percentage between 0 (disabled) and 100 (files must
191 be identical) as its parameter. Detecting renamed files this way
191 be identical) as its parameter. Detecting renamed files this way
192 can be expensive. After using this option, :hg:`status -C` can be
192 can be expensive. After using this option, :hg:`status -C` can be
193 used to check which files were identified as moved or renamed.
193 used to check which files were identified as moved or renamed.
194
194
195 Returns 0 if all files are successfully added.
195 Returns 0 if all files are successfully added.
196 """
196 """
197 try:
197 try:
198 sim = float(opts.get('similarity') or 100)
198 sim = float(opts.get('similarity') or 100)
199 except ValueError:
199 except ValueError:
200 raise util.Abort(_('similarity must be a number'))
200 raise util.Abort(_('similarity must be a number'))
201 if sim < 0 or sim > 100:
201 if sim < 0 or sim > 100:
202 raise util.Abort(_('similarity must be between 0 and 100'))
202 raise util.Abort(_('similarity must be between 0 and 100'))
203 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
203 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
204
204
205 @command('^annotate|blame',
205 @command('^annotate|blame',
206 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
206 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
207 ('', 'follow', None,
207 ('', 'follow', None,
208 _('follow copies/renames and list the filename (DEPRECATED)')),
208 _('follow copies/renames and list the filename (DEPRECATED)')),
209 ('', 'no-follow', None, _("don't follow copies and renames")),
209 ('', 'no-follow', None, _("don't follow copies and renames")),
210 ('a', 'text', None, _('treat all files as text')),
210 ('a', 'text', None, _('treat all files as text')),
211 ('u', 'user', None, _('list the author (long with -v)')),
211 ('u', 'user', None, _('list the author (long with -v)')),
212 ('f', 'file', None, _('list the filename')),
212 ('f', 'file', None, _('list the filename')),
213 ('d', 'date', None, _('list the date (short with -q)')),
213 ('d', 'date', None, _('list the date (short with -q)')),
214 ('n', 'number', None, _('list the revision number (default)')),
214 ('n', 'number', None, _('list the revision number (default)')),
215 ('c', 'changeset', None, _('list the changeset')),
215 ('c', 'changeset', None, _('list the changeset')),
216 ('l', 'line-number', None, _('show line number at the first appearance'))
216 ('l', 'line-number', None, _('show line number at the first appearance'))
217 ] + walkopts,
217 ] + walkopts,
218 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
218 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
219 def annotate(ui, repo, *pats, **opts):
219 def annotate(ui, repo, *pats, **opts):
220 """show changeset information by line for each file
220 """show changeset information by line for each file
221
221
222 List changes in files, showing the revision id responsible for
222 List changes in files, showing the revision id responsible for
223 each line
223 each line
224
224
225 This command is useful for discovering when a change was made and
225 This command is useful for discovering when a change was made and
226 by whom.
226 by whom.
227
227
228 Without the -a/--text option, annotate will avoid processing files
228 Without the -a/--text option, annotate will avoid processing files
229 it detects as binary. With -a, annotate will annotate the file
229 it detects as binary. With -a, annotate will annotate the file
230 anyway, although the results will probably be neither useful
230 anyway, although the results will probably be neither useful
231 nor desirable.
231 nor desirable.
232
232
233 Returns 0 on success.
233 Returns 0 on success.
234 """
234 """
235 if opts.get('follow'):
235 if opts.get('follow'):
236 # --follow is deprecated and now just an alias for -f/--file
236 # --follow is deprecated and now just an alias for -f/--file
237 # to mimic the behavior of Mercurial before version 1.5
237 # to mimic the behavior of Mercurial before version 1.5
238 opts['file'] = True
238 opts['file'] = True
239
239
240 datefunc = ui.quiet and util.shortdate or util.datestr
240 datefunc = ui.quiet and util.shortdate or util.datestr
241 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
241 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
242
242
243 if not pats:
243 if not pats:
244 raise util.Abort(_('at least one filename or pattern is required'))
244 raise util.Abort(_('at least one filename or pattern is required'))
245
245
246 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
246 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
247 ('number', ' ', lambda x: str(x[0].rev())),
247 ('number', ' ', lambda x: str(x[0].rev())),
248 ('changeset', ' ', lambda x: short(x[0].node())),
248 ('changeset', ' ', lambda x: short(x[0].node())),
249 ('date', ' ', getdate),
249 ('date', ' ', getdate),
250 ('file', ' ', lambda x: x[0].path()),
250 ('file', ' ', lambda x: x[0].path()),
251 ('line_number', ':', lambda x: str(x[1])),
251 ('line_number', ':', lambda x: str(x[1])),
252 ]
252 ]
253
253
254 if (not opts.get('user') and not opts.get('changeset')
254 if (not opts.get('user') and not opts.get('changeset')
255 and not opts.get('date') and not opts.get('file')):
255 and not opts.get('date') and not opts.get('file')):
256 opts['number'] = True
256 opts['number'] = True
257
257
258 linenumber = opts.get('line_number') is not None
258 linenumber = opts.get('line_number') is not None
259 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
259 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
260 raise util.Abort(_('at least one of -n/-c is required for -l'))
260 raise util.Abort(_('at least one of -n/-c is required for -l'))
261
261
262 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
262 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
263 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
263 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
264
264
265 def bad(x, y):
265 def bad(x, y):
266 raise util.Abort("%s: %s" % (x, y))
266 raise util.Abort("%s: %s" % (x, y))
267
267
268 ctx = scmutil.revsingle(repo, opts.get('rev'))
268 ctx = scmutil.revsingle(repo, opts.get('rev'))
269 m = scmutil.match(ctx, pats, opts)
269 m = scmutil.match(ctx, pats, opts)
270 m.bad = bad
270 m.bad = bad
271 follow = not opts.get('no_follow')
271 follow = not opts.get('no_follow')
272 for abs in ctx.walk(m):
272 for abs in ctx.walk(m):
273 fctx = ctx[abs]
273 fctx = ctx[abs]
274 if not opts.get('text') and util.binary(fctx.data()):
274 if not opts.get('text') and util.binary(fctx.data()):
275 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
275 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
276 continue
276 continue
277
277
278 lines = fctx.annotate(follow=follow, linenumber=linenumber)
278 lines = fctx.annotate(follow=follow, linenumber=linenumber)
279 pieces = []
279 pieces = []
280
280
281 for f, sep in funcmap:
281 for f, sep in funcmap:
282 l = [f(n) for n, dummy in lines]
282 l = [f(n) for n, dummy in lines]
283 if l:
283 if l:
284 sized = [(x, encoding.colwidth(x)) for x in l]
284 sized = [(x, encoding.colwidth(x)) for x in l]
285 ml = max([w for x, w in sized])
285 ml = max([w for x, w in sized])
286 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
286 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
287 for x, w in sized])
287 for x, w in sized])
288
288
289 if pieces:
289 if pieces:
290 for p, l in zip(zip(*pieces), lines):
290 for p, l in zip(zip(*pieces), lines):
291 ui.write("%s: %s" % ("".join(p), l[1]))
291 ui.write("%s: %s" % ("".join(p), l[1]))
292
292
293 @command('archive',
293 @command('archive',
294 [('', 'no-decode', None, _('do not pass files through decoders')),
294 [('', 'no-decode', None, _('do not pass files through decoders')),
295 ('p', 'prefix', '', _('directory prefix for files in archive'),
295 ('p', 'prefix', '', _('directory prefix for files in archive'),
296 _('PREFIX')),
296 _('PREFIX')),
297 ('r', 'rev', '', _('revision to distribute'), _('REV')),
297 ('r', 'rev', '', _('revision to distribute'), _('REV')),
298 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
298 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
299 ] + subrepoopts + walkopts,
299 ] + subrepoopts + walkopts,
300 _('[OPTION]... DEST'))
300 _('[OPTION]... DEST'))
301 def archive(ui, repo, dest, **opts):
301 def archive(ui, repo, dest, **opts):
302 '''create an unversioned archive of a repository revision
302 '''create an unversioned archive of a repository revision
303
303
304 By default, the revision used is the parent of the working
304 By default, the revision used is the parent of the working
305 directory; use -r/--rev to specify a different revision.
305 directory; use -r/--rev to specify a different revision.
306
306
307 The archive type is automatically detected based on file
307 The archive type is automatically detected based on file
308 extension (or override using -t/--type).
308 extension (or override using -t/--type).
309
309
310 .. container:: verbose
310 .. container:: verbose
311
311
312 Examples:
312 Examples:
313
313
314 - create a zip file containing the 1.0 release::
314 - create a zip file containing the 1.0 release::
315
315
316 hg archive -r 1.0 project-1.0.zip
316 hg archive -r 1.0 project-1.0.zip
317
317
318 - create a tarball excluding .hg files::
318 - create a tarball excluding .hg files::
319
319
320 hg archive project.tar.gz -X ".hg*"
320 hg archive project.tar.gz -X ".hg*"
321
321
322 Valid types are:
322 Valid types are:
323
323
324 :``files``: a directory full of files (default)
324 :``files``: a directory full of files (default)
325 :``tar``: tar archive, uncompressed
325 :``tar``: tar archive, uncompressed
326 :``tbz2``: tar archive, compressed using bzip2
326 :``tbz2``: tar archive, compressed using bzip2
327 :``tgz``: tar archive, compressed using gzip
327 :``tgz``: tar archive, compressed using gzip
328 :``uzip``: zip archive, uncompressed
328 :``uzip``: zip archive, uncompressed
329 :``zip``: zip archive, compressed using deflate
329 :``zip``: zip archive, compressed using deflate
330
330
331 The exact name of the destination archive or directory is given
331 The exact name of the destination archive or directory is given
332 using a format string; see :hg:`help export` for details.
332 using a format string; see :hg:`help export` for details.
333
333
334 Each member added to an archive file has a directory prefix
334 Each member added to an archive file has a directory prefix
335 prepended. Use -p/--prefix to specify a format string for the
335 prepended. Use -p/--prefix to specify a format string for the
336 prefix. The default is the basename of the archive, with suffixes
336 prefix. The default is the basename of the archive, with suffixes
337 removed.
337 removed.
338
338
339 Returns 0 on success.
339 Returns 0 on success.
340 '''
340 '''
341
341
342 ctx = scmutil.revsingle(repo, opts.get('rev'))
342 ctx = scmutil.revsingle(repo, opts.get('rev'))
343 if not ctx:
343 if not ctx:
344 raise util.Abort(_('no working directory: please specify a revision'))
344 raise util.Abort(_('no working directory: please specify a revision'))
345 node = ctx.node()
345 node = ctx.node()
346 dest = cmdutil.makefilename(repo, dest, node)
346 dest = cmdutil.makefilename(repo, dest, node)
347 if os.path.realpath(dest) == repo.root:
347 if os.path.realpath(dest) == repo.root:
348 raise util.Abort(_('repository root cannot be destination'))
348 raise util.Abort(_('repository root cannot be destination'))
349
349
350 kind = opts.get('type') or archival.guesskind(dest) or 'files'
350 kind = opts.get('type') or archival.guesskind(dest) or 'files'
351 prefix = opts.get('prefix')
351 prefix = opts.get('prefix')
352
352
353 if dest == '-':
353 if dest == '-':
354 if kind == 'files':
354 if kind == 'files':
355 raise util.Abort(_('cannot archive plain files to stdout'))
355 raise util.Abort(_('cannot archive plain files to stdout'))
356 dest = cmdutil.makefileobj(repo, dest)
356 dest = cmdutil.makefileobj(repo, dest)
357 if not prefix:
357 if not prefix:
358 prefix = os.path.basename(repo.root) + '-%h'
358 prefix = os.path.basename(repo.root) + '-%h'
359
359
360 prefix = cmdutil.makefilename(repo, prefix, node)
360 prefix = cmdutil.makefilename(repo, prefix, node)
361 matchfn = scmutil.match(ctx, [], opts)
361 matchfn = scmutil.match(ctx, [], opts)
362 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
362 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
363 matchfn, prefix, subrepos=opts.get('subrepos'))
363 matchfn, prefix, subrepos=opts.get('subrepos'))
364
364
365 @command('backout',
365 @command('backout',
366 [('', 'merge', None, _('merge with old dirstate parent after backout')),
366 [('', 'merge', None, _('merge with old dirstate parent after backout')),
367 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
367 ('', 'parent', '', _('parent to choose when backing out merge'), _('REV')),
368 ('r', 'rev', '', _('revision to backout'), _('REV')),
368 ('r', 'rev', '', _('revision to backout'), _('REV')),
369 ] + mergetoolopts + walkopts + commitopts + commitopts2,
369 ] + mergetoolopts + walkopts + commitopts + commitopts2,
370 _('[OPTION]... [-r] REV'))
370 _('[OPTION]... [-r] REV'))
371 def backout(ui, repo, node=None, rev=None, **opts):
371 def backout(ui, repo, node=None, rev=None, **opts):
372 '''reverse effect of earlier changeset
372 '''reverse effect of earlier changeset
373
373
374 Prepare a new changeset with the effect of REV undone in the
374 Prepare a new changeset with the effect of REV undone in the
375 current working directory.
375 current working directory.
376
376
377 If REV is the parent of the working directory, then this new changeset
377 If REV is the parent of the working directory, then this new changeset
378 is committed automatically. Otherwise, hg needs to merge the
378 is committed automatically. Otherwise, hg needs to merge the
379 changes and the merged result is left uncommitted.
379 changes and the merged result is left uncommitted.
380
380
381 By default, the pending changeset will have one parent,
381 By default, the pending changeset will have one parent,
382 maintaining a linear history. With --merge, the pending changeset
382 maintaining a linear history. With --merge, the pending changeset
383 will instead have two parents: the old parent of the working
383 will instead have two parents: the old parent of the working
384 directory and a new child of REV that simply undoes REV.
384 directory and a new child of REV that simply undoes REV.
385
385
386 Before version 1.7, the behavior without --merge was equivalent to
386 Before version 1.7, the behavior without --merge was equivalent to
387 specifying --merge followed by :hg:`update --clean .` to cancel
387 specifying --merge followed by :hg:`update --clean .` to cancel
388 the merge and leave the child of REV as a head to be merged
388 the merge and leave the child of REV as a head to be merged
389 separately.
389 separately.
390
390
391 See :hg:`help dates` for a list of formats valid for -d/--date.
391 See :hg:`help dates` for a list of formats valid for -d/--date.
392
392
393 Returns 0 on success.
393 Returns 0 on success.
394 '''
394 '''
395 if rev and node:
395 if rev and node:
396 raise util.Abort(_("please specify just one revision"))
396 raise util.Abort(_("please specify just one revision"))
397
397
398 if not rev:
398 if not rev:
399 rev = node
399 rev = node
400
400
401 if not rev:
401 if not rev:
402 raise util.Abort(_("please specify a revision to backout"))
402 raise util.Abort(_("please specify a revision to backout"))
403
403
404 date = opts.get('date')
404 date = opts.get('date')
405 if date:
405 if date:
406 opts['date'] = util.parsedate(date)
406 opts['date'] = util.parsedate(date)
407
407
408 cmdutil.bailifchanged(repo)
408 cmdutil.bailifchanged(repo)
409 node = scmutil.revsingle(repo, rev).node()
409 node = scmutil.revsingle(repo, rev).node()
410
410
411 op1, op2 = repo.dirstate.parents()
411 op1, op2 = repo.dirstate.parents()
412 a = repo.changelog.ancestor(op1, node)
412 a = repo.changelog.ancestor(op1, node)
413 if a != node:
413 if a != node:
414 raise util.Abort(_('cannot backout change on a different branch'))
414 raise util.Abort(_('cannot backout change on a different branch'))
415
415
416 p1, p2 = repo.changelog.parents(node)
416 p1, p2 = repo.changelog.parents(node)
417 if p1 == nullid:
417 if p1 == nullid:
418 raise util.Abort(_('cannot backout a change with no parents'))
418 raise util.Abort(_('cannot backout a change with no parents'))
419 if p2 != nullid:
419 if p2 != nullid:
420 if not opts.get('parent'):
420 if not opts.get('parent'):
421 raise util.Abort(_('cannot backout a merge changeset without '
421 raise util.Abort(_('cannot backout a merge changeset without '
422 '--parent'))
422 '--parent'))
423 p = repo.lookup(opts['parent'])
423 p = repo.lookup(opts['parent'])
424 if p not in (p1, p2):
424 if p not in (p1, p2):
425 raise util.Abort(_('%s is not a parent of %s') %
425 raise util.Abort(_('%s is not a parent of %s') %
426 (short(p), short(node)))
426 (short(p), short(node)))
427 parent = p
427 parent = p
428 else:
428 else:
429 if opts.get('parent'):
429 if opts.get('parent'):
430 raise util.Abort(_('cannot use --parent on non-merge changeset'))
430 raise util.Abort(_('cannot use --parent on non-merge changeset'))
431 parent = p1
431 parent = p1
432
432
433 # the backout should appear on the same branch
433 # the backout should appear on the same branch
434 branch = repo.dirstate.branch()
434 branch = repo.dirstate.branch()
435 hg.clean(repo, node, show_stats=False)
435 hg.clean(repo, node, show_stats=False)
436 repo.dirstate.setbranch(branch)
436 repo.dirstate.setbranch(branch)
437 revert_opts = opts.copy()
437 revert_opts = opts.copy()
438 revert_opts['date'] = None
438 revert_opts['date'] = None
439 revert_opts['all'] = True
439 revert_opts['all'] = True
440 revert_opts['rev'] = hex(parent)
440 revert_opts['rev'] = hex(parent)
441 revert_opts['no_backup'] = None
441 revert_opts['no_backup'] = None
442 revert(ui, repo, **revert_opts)
442 revert(ui, repo, **revert_opts)
443 if not opts.get('merge') and op1 != node:
443 if not opts.get('merge') and op1 != node:
444 try:
444 try:
445 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
445 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
446 return hg.update(repo, op1)
446 return hg.update(repo, op1)
447 finally:
447 finally:
448 ui.setconfig('ui', 'forcemerge', '')
448 ui.setconfig('ui', 'forcemerge', '')
449
449
450 commit_opts = opts.copy()
450 commit_opts = opts.copy()
451 commit_opts['addremove'] = False
451 commit_opts['addremove'] = False
452 if not commit_opts['message'] and not commit_opts['logfile']:
452 if not commit_opts['message'] and not commit_opts['logfile']:
453 # we don't translate commit messages
453 # we don't translate commit messages
454 commit_opts['message'] = "Backed out changeset %s" % short(node)
454 commit_opts['message'] = "Backed out changeset %s" % short(node)
455 commit_opts['force_editor'] = True
455 commit_opts['force_editor'] = True
456 commit(ui, repo, **commit_opts)
456 commit(ui, repo, **commit_opts)
457 def nice(node):
457 def nice(node):
458 return '%d:%s' % (repo.changelog.rev(node), short(node))
458 return '%d:%s' % (repo.changelog.rev(node), short(node))
459 ui.status(_('changeset %s backs out changeset %s\n') %
459 ui.status(_('changeset %s backs out changeset %s\n') %
460 (nice(repo.changelog.tip()), nice(node)))
460 (nice(repo.changelog.tip()), nice(node)))
461 if opts.get('merge') and op1 != node:
461 if opts.get('merge') and op1 != node:
462 hg.clean(repo, op1, show_stats=False)
462 hg.clean(repo, op1, show_stats=False)
463 ui.status(_('merging with changeset %s\n')
463 ui.status(_('merging with changeset %s\n')
464 % nice(repo.changelog.tip()))
464 % nice(repo.changelog.tip()))
465 try:
465 try:
466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
467 return hg.merge(repo, hex(repo.changelog.tip()))
467 return hg.merge(repo, hex(repo.changelog.tip()))
468 finally:
468 finally:
469 ui.setconfig('ui', 'forcemerge', '')
469 ui.setconfig('ui', 'forcemerge', '')
470 return 0
470 return 0
471
471
472 @command('bisect',
472 @command('bisect',
473 [('r', 'reset', False, _('reset bisect state')),
473 [('r', 'reset', False, _('reset bisect state')),
474 ('g', 'good', False, _('mark changeset good')),
474 ('g', 'good', False, _('mark changeset good')),
475 ('b', 'bad', False, _('mark changeset bad')),
475 ('b', 'bad', False, _('mark changeset bad')),
476 ('s', 'skip', False, _('skip testing changeset')),
476 ('s', 'skip', False, _('skip testing changeset')),
477 ('e', 'extend', False, _('extend the bisect range')),
477 ('e', 'extend', False, _('extend the bisect range')),
478 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
478 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
479 ('U', 'noupdate', False, _('do not update to target'))],
479 ('U', 'noupdate', False, _('do not update to target'))],
480 _("[-gbsr] [-U] [-c CMD] [REV]"))
480 _("[-gbsr] [-U] [-c CMD] [REV]"))
481 def bisect(ui, repo, rev=None, extra=None, command=None,
481 def bisect(ui, repo, rev=None, extra=None, command=None,
482 reset=None, good=None, bad=None, skip=None, extend=None,
482 reset=None, good=None, bad=None, skip=None, extend=None,
483 noupdate=None):
483 noupdate=None):
484 """subdivision search of changesets
484 """subdivision search of changesets
485
485
486 This command helps to find changesets which introduce problems. To
486 This command helps to find changesets which introduce problems. To
487 use, mark the earliest changeset you know exhibits the problem as
487 use, mark the earliest changeset you know exhibits the problem as
488 bad, then mark the latest changeset which is free from the problem
488 bad, then mark the latest changeset which is free from the problem
489 as good. Bisect will update your working directory to a revision
489 as good. Bisect will update your working directory to a revision
490 for testing (unless the -U/--noupdate option is specified). Once
490 for testing (unless the -U/--noupdate option is specified). Once
491 you have performed tests, mark the working directory as good or
491 you have performed tests, mark the working directory as good or
492 bad, and bisect will either update to another candidate changeset
492 bad, and bisect will either update to another candidate changeset
493 or announce that it has found the bad revision.
493 or announce that it has found the bad revision.
494
494
495 As a shortcut, you can also use the revision argument to mark a
495 As a shortcut, you can also use the revision argument to mark a
496 revision as good or bad without checking it out first.
496 revision as good or bad without checking it out first.
497
497
498 If you supply a command, it will be used for automatic bisection.
498 If you supply a command, it will be used for automatic bisection.
499 Its exit status will be used to mark revisions as good or bad:
499 Its exit status will be used to mark revisions as good or bad:
500 status 0 means good, 125 means to skip the revision, 127
500 status 0 means good, 125 means to skip the revision, 127
501 (command not found) will abort the bisection, and any other
501 (command not found) will abort the bisection, and any other
502 non-zero exit status means the revision is bad.
502 non-zero exit status means the revision is bad.
503
503
504 .. container:: verbose
504 .. container:: verbose
505
505
506 Some examples:
506 Some examples:
507
507
508 - start a bisection with known bad revision 12, and good revision 34::
508 - start a bisection with known bad revision 12, and good revision 34::
509
509
510 hg bisect --bad 34
510 hg bisect --bad 34
511 hg bisect --good 12
511 hg bisect --good 12
512
512
513 - advance the current bisection by marking current revision as good or
513 - advance the current bisection by marking current revision as good or
514 bad::
514 bad::
515
515
516 hg bisect --good
516 hg bisect --good
517 hg bisect --bad
517 hg bisect --bad
518
518
519 - mark the current revision, or a known revision, to be skipped (eg. if
519 - mark the current revision, or a known revision, to be skipped (eg. if
520 that revision is not usable because of another issue)::
520 that revision is not usable because of another issue)::
521
521
522 hg bisect --skip
522 hg bisect --skip
523 hg bisect --skip 23
523 hg bisect --skip 23
524
524
525 - forget the current bisection::
525 - forget the current bisection::
526
526
527 hg bisect --reset
527 hg bisect --reset
528
528
529 - use 'make && make tests' to automatically find the first broken
529 - use 'make && make tests' to automatically find the first broken
530 revision::
530 revision::
531
531
532 hg bisect --reset
532 hg bisect --reset
533 hg bisect --bad 34
533 hg bisect --bad 34
534 hg bisect --good 12
534 hg bisect --good 12
535 hg bisect --command 'make && make tests'
535 hg bisect --command 'make && make tests'
536
536
537 - see all changesets whose states are already known in the current
537 - see all changesets whose states are already known in the current
538 bisection::
538 bisection::
539
539
540 hg log -r "bisect(pruned)"
540 hg log -r "bisect(pruned)"
541
541
542 - see all changesets that took part in the current bisection::
542 - see all changesets that took part in the current bisection::
543
543
544 hg log -r "bisect(range)"
544 hg log -r "bisect(range)"
545
545
546 - with the graphlog extension, you can even get a nice graph::
546 - with the graphlog extension, you can even get a nice graph::
547
547
548 hg log --graph -r "bisect(range)"
548 hg log --graph -r "bisect(range)"
549
549
550 See :hg:`help revsets` for more about the `bisect()` keyword.
550 See :hg:`help revsets` for more about the `bisect()` keyword.
551
551
552 Returns 0 on success.
552 Returns 0 on success.
553 """
553 """
554 def extendbisectrange(nodes, good):
554 def extendbisectrange(nodes, good):
555 # bisect is incomplete when it ends on a merge node and
555 # bisect is incomplete when it ends on a merge node and
556 # one of the parent was not checked.
556 # one of the parent was not checked.
557 parents = repo[nodes[0]].parents()
557 parents = repo[nodes[0]].parents()
558 if len(parents) > 1:
558 if len(parents) > 1:
559 side = good and state['bad'] or state['good']
559 side = good and state['bad'] or state['good']
560 num = len(set(i.node() for i in parents) & set(side))
560 num = len(set(i.node() for i in parents) & set(side))
561 if num == 1:
561 if num == 1:
562 return parents[0].ancestor(parents[1])
562 return parents[0].ancestor(parents[1])
563 return None
563 return None
564
564
565 def print_result(nodes, good):
565 def print_result(nodes, good):
566 displayer = cmdutil.show_changeset(ui, repo, {})
566 displayer = cmdutil.show_changeset(ui, repo, {})
567 if len(nodes) == 1:
567 if len(nodes) == 1:
568 # narrowed it down to a single revision
568 # narrowed it down to a single revision
569 if good:
569 if good:
570 ui.write(_("The first good revision is:\n"))
570 ui.write(_("The first good revision is:\n"))
571 else:
571 else:
572 ui.write(_("The first bad revision is:\n"))
572 ui.write(_("The first bad revision is:\n"))
573 displayer.show(repo[nodes[0]])
573 displayer.show(repo[nodes[0]])
574 extendnode = extendbisectrange(nodes, good)
574 extendnode = extendbisectrange(nodes, good)
575 if extendnode is not None:
575 if extendnode is not None:
576 ui.write(_('Not all ancestors of this changeset have been'
576 ui.write(_('Not all ancestors of this changeset have been'
577 ' checked.\nUse bisect --extend to continue the '
577 ' checked.\nUse bisect --extend to continue the '
578 'bisection from\nthe common ancestor, %s.\n')
578 'bisection from\nthe common ancestor, %s.\n')
579 % extendnode)
579 % extendnode)
580 else:
580 else:
581 # multiple possible revisions
581 # multiple possible revisions
582 if good:
582 if good:
583 ui.write(_("Due to skipped revisions, the first "
583 ui.write(_("Due to skipped revisions, the first "
584 "good revision could be any of:\n"))
584 "good revision could be any of:\n"))
585 else:
585 else:
586 ui.write(_("Due to skipped revisions, the first "
586 ui.write(_("Due to skipped revisions, the first "
587 "bad revision could be any of:\n"))
587 "bad revision could be any of:\n"))
588 for n in nodes:
588 for n in nodes:
589 displayer.show(repo[n])
589 displayer.show(repo[n])
590 displayer.close()
590 displayer.close()
591
591
592 def check_state(state, interactive=True):
592 def check_state(state, interactive=True):
593 if not state['good'] or not state['bad']:
593 if not state['good'] or not state['bad']:
594 if (good or bad or skip or reset) and interactive:
594 if (good or bad or skip or reset) and interactive:
595 return
595 return
596 if not state['good']:
596 if not state['good']:
597 raise util.Abort(_('cannot bisect (no known good revisions)'))
597 raise util.Abort(_('cannot bisect (no known good revisions)'))
598 else:
598 else:
599 raise util.Abort(_('cannot bisect (no known bad revisions)'))
599 raise util.Abort(_('cannot bisect (no known bad revisions)'))
600 return True
600 return True
601
601
602 # backward compatibility
602 # backward compatibility
603 if rev in "good bad reset init".split():
603 if rev in "good bad reset init".split():
604 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
604 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
605 cmd, rev, extra = rev, extra, None
605 cmd, rev, extra = rev, extra, None
606 if cmd == "good":
606 if cmd == "good":
607 good = True
607 good = True
608 elif cmd == "bad":
608 elif cmd == "bad":
609 bad = True
609 bad = True
610 else:
610 else:
611 reset = True
611 reset = True
612 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
612 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
613 raise util.Abort(_('incompatible arguments'))
613 raise util.Abort(_('incompatible arguments'))
614
614
615 if reset:
615 if reset:
616 p = repo.join("bisect.state")
616 p = repo.join("bisect.state")
617 if os.path.exists(p):
617 if os.path.exists(p):
618 os.unlink(p)
618 os.unlink(p)
619 return
619 return
620
620
621 state = hbisect.load_state(repo)
621 state = hbisect.load_state(repo)
622
622
623 if command:
623 if command:
624 changesets = 1
624 changesets = 1
625 try:
625 try:
626 while changesets:
626 while changesets:
627 # update state
627 # update state
628 status = util.system(command, out=ui.fout)
628 status = util.system(command, out=ui.fout)
629 if status == 125:
629 if status == 125:
630 transition = "skip"
630 transition = "skip"
631 elif status == 0:
631 elif status == 0:
632 transition = "good"
632 transition = "good"
633 # status < 0 means process was killed
633 # status < 0 means process was killed
634 elif status == 127:
634 elif status == 127:
635 raise util.Abort(_("failed to execute %s") % command)
635 raise util.Abort(_("failed to execute %s") % command)
636 elif status < 0:
636 elif status < 0:
637 raise util.Abort(_("%s killed") % command)
637 raise util.Abort(_("%s killed") % command)
638 else:
638 else:
639 transition = "bad"
639 transition = "bad"
640 ctx = scmutil.revsingle(repo, rev)
640 ctx = scmutil.revsingle(repo, rev)
641 rev = None # clear for future iterations
641 rev = None # clear for future iterations
642 state[transition].append(ctx.node())
642 state[transition].append(ctx.node())
643 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
643 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
644 check_state(state, interactive=False)
644 check_state(state, interactive=False)
645 # bisect
645 # bisect
646 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
646 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
647 # update to next check
647 # update to next check
648 cmdutil.bailifchanged(repo)
648 cmdutil.bailifchanged(repo)
649 hg.clean(repo, nodes[0], show_stats=False)
649 hg.clean(repo, nodes[0], show_stats=False)
650 finally:
650 finally:
651 hbisect.save_state(repo, state)
651 hbisect.save_state(repo, state)
652 print_result(nodes, good)
652 print_result(nodes, good)
653 return
653 return
654
654
655 # update state
655 # update state
656
656
657 if rev:
657 if rev:
658 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
658 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
659 else:
659 else:
660 nodes = [repo.lookup('.')]
660 nodes = [repo.lookup('.')]
661
661
662 if good or bad or skip:
662 if good or bad or skip:
663 if good:
663 if good:
664 state['good'] += nodes
664 state['good'] += nodes
665 elif bad:
665 elif bad:
666 state['bad'] += nodes
666 state['bad'] += nodes
667 elif skip:
667 elif skip:
668 state['skip'] += nodes
668 state['skip'] += nodes
669 hbisect.save_state(repo, state)
669 hbisect.save_state(repo, state)
670
670
671 if not check_state(state):
671 if not check_state(state):
672 return
672 return
673
673
674 # actually bisect
674 # actually bisect
675 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
675 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
676 if extend:
676 if extend:
677 if not changesets:
677 if not changesets:
678 extendnode = extendbisectrange(nodes, good)
678 extendnode = extendbisectrange(nodes, good)
679 if extendnode is not None:
679 if extendnode is not None:
680 ui.write(_("Extending search to changeset %d:%s\n"
680 ui.write(_("Extending search to changeset %d:%s\n"
681 % (extendnode.rev(), extendnode)))
681 % (extendnode.rev(), extendnode)))
682 if noupdate:
682 if noupdate:
683 return
683 return
684 cmdutil.bailifchanged(repo)
684 cmdutil.bailifchanged(repo)
685 return hg.clean(repo, extendnode.node())
685 return hg.clean(repo, extendnode.node())
686 raise util.Abort(_("nothing to extend"))
686 raise util.Abort(_("nothing to extend"))
687
687
688 if changesets == 0:
688 if changesets == 0:
689 print_result(nodes, good)
689 print_result(nodes, good)
690 else:
690 else:
691 assert len(nodes) == 1 # only a single node can be tested next
691 assert len(nodes) == 1 # only a single node can be tested next
692 node = nodes[0]
692 node = nodes[0]
693 # compute the approximate number of remaining tests
693 # compute the approximate number of remaining tests
694 tests, size = 0, 2
694 tests, size = 0, 2
695 while size <= changesets:
695 while size <= changesets:
696 tests, size = tests + 1, size * 2
696 tests, size = tests + 1, size * 2
697 rev = repo.changelog.rev(node)
697 rev = repo.changelog.rev(node)
698 ui.write(_("Testing changeset %d:%s "
698 ui.write(_("Testing changeset %d:%s "
699 "(%d changesets remaining, ~%d tests)\n")
699 "(%d changesets remaining, ~%d tests)\n")
700 % (rev, short(node), changesets, tests))
700 % (rev, short(node), changesets, tests))
701 if not noupdate:
701 if not noupdate:
702 cmdutil.bailifchanged(repo)
702 cmdutil.bailifchanged(repo)
703 return hg.clean(repo, node)
703 return hg.clean(repo, node)
704
704
705 @command('bookmarks',
705 @command('bookmarks',
706 [('f', 'force', False, _('force')),
706 [('f', 'force', False, _('force')),
707 ('r', 'rev', '', _('revision'), _('REV')),
707 ('r', 'rev', '', _('revision'), _('REV')),
708 ('d', 'delete', False, _('delete a given bookmark')),
708 ('d', 'delete', False, _('delete a given bookmark')),
709 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
709 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
710 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
710 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
711 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
711 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
712 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
712 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
713 rename=None, inactive=False):
713 rename=None, inactive=False):
714 '''track a line of development with movable markers
714 '''track a line of development with movable markers
715
715
716 Bookmarks are pointers to certain commits that move when
716 Bookmarks are pointers to certain commits that move when
717 committing. Bookmarks are local. They can be renamed, copied and
717 committing. Bookmarks are local. They can be renamed, copied and
718 deleted. It is possible to use bookmark names in :hg:`merge` and
718 deleted. It is possible to use bookmark names in :hg:`merge` and
719 :hg:`update` to merge and update respectively to a given bookmark.
719 :hg:`update` to merge and update respectively to a given bookmark.
720
720
721 You can use :hg:`bookmark NAME` to set a bookmark on the working
721 You can use :hg:`bookmark NAME` to set a bookmark on the working
722 directory's parent revision with the given name. If you specify
722 directory's parent revision with the given name. If you specify
723 a revision using -r REV (where REV may be an existing bookmark),
723 a revision using -r REV (where REV may be an existing bookmark),
724 the bookmark is assigned to that revision.
724 the bookmark is assigned to that revision.
725
725
726 Bookmarks can be pushed and pulled between repositories (see :hg:`help
726 Bookmarks can be pushed and pulled between repositories (see :hg:`help
727 push` and :hg:`help pull`). This requires both the local and remote
727 push` and :hg:`help pull`). This requires both the local and remote
728 repositories to support bookmarks. For versions prior to 1.8, this means
728 repositories to support bookmarks. For versions prior to 1.8, this means
729 the bookmarks extension must be enabled.
729 the bookmarks extension must be enabled.
730 '''
730 '''
731 hexfn = ui.debugflag and hex or short
731 hexfn = ui.debugflag and hex or short
732 marks = repo._bookmarks
732 marks = repo._bookmarks
733 cur = repo.changectx('.').node()
733 cur = repo.changectx('.').node()
734
734
735 if rename:
735 if rename:
736 if rename not in marks:
736 if rename not in marks:
737 raise util.Abort(_("bookmark '%s' does not exist") % rename)
737 raise util.Abort(_("bookmark '%s' does not exist") % rename)
738 if mark in marks and not force:
738 if mark in marks and not force:
739 raise util.Abort(_("bookmark '%s' already exists "
739 raise util.Abort(_("bookmark '%s' already exists "
740 "(use -f to force)") % mark)
740 "(use -f to force)") % mark)
741 if mark is None:
741 if mark is None:
742 raise util.Abort(_("new bookmark name required"))
742 raise util.Abort(_("new bookmark name required"))
743 marks[mark] = marks[rename]
743 marks[mark] = marks[rename]
744 if repo._bookmarkcurrent == rename and not inactive:
744 if repo._bookmarkcurrent == rename and not inactive:
745 bookmarks.setcurrent(repo, mark)
745 bookmarks.setcurrent(repo, mark)
746 del marks[rename]
746 del marks[rename]
747 bookmarks.write(repo)
747 bookmarks.write(repo)
748 return
748 return
749
749
750 if delete:
750 if delete:
751 if mark is None:
751 if mark is None:
752 raise util.Abort(_("bookmark name required"))
752 raise util.Abort(_("bookmark name required"))
753 if mark not in marks:
753 if mark not in marks:
754 raise util.Abort(_("bookmark '%s' does not exist") % mark)
754 raise util.Abort(_("bookmark '%s' does not exist") % mark)
755 if mark == repo._bookmarkcurrent:
755 if mark == repo._bookmarkcurrent:
756 bookmarks.setcurrent(repo, None)
756 bookmarks.setcurrent(repo, None)
757 del marks[mark]
757 del marks[mark]
758 bookmarks.write(repo)
758 bookmarks.write(repo)
759 return
759 return
760
760
761 if mark is not None:
761 if mark is not None:
762 if "\n" in mark:
762 if "\n" in mark:
763 raise util.Abort(_("bookmark name cannot contain newlines"))
763 raise util.Abort(_("bookmark name cannot contain newlines"))
764 mark = mark.strip()
764 mark = mark.strip()
765 if not mark:
765 if not mark:
766 raise util.Abort(_("bookmark names cannot consist entirely of "
766 raise util.Abort(_("bookmark names cannot consist entirely of "
767 "whitespace"))
767 "whitespace"))
768 if inactive and mark == repo._bookmarkcurrent:
768 if inactive and mark == repo._bookmarkcurrent:
769 bookmarks.setcurrent(repo, None)
769 bookmarks.setcurrent(repo, None)
770 return
770 return
771 if mark in marks and not force:
771 if mark in marks and not force:
772 raise util.Abort(_("bookmark '%s' already exists "
772 raise util.Abort(_("bookmark '%s' already exists "
773 "(use -f to force)") % mark)
773 "(use -f to force)") % mark)
774 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
774 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
775 and not force):
775 and not force):
776 raise util.Abort(
776 raise util.Abort(
777 _("a bookmark cannot have the name of an existing branch"))
777 _("a bookmark cannot have the name of an existing branch"))
778 if rev:
778 if rev:
779 marks[mark] = repo.lookup(rev)
779 marks[mark] = repo.lookup(rev)
780 else:
780 else:
781 marks[mark] = repo.changectx('.').node()
781 marks[mark] = repo.changectx('.').node()
782 if not inactive and repo.changectx('.').node() == marks[mark]:
782 if not inactive and repo.changectx('.').node() == marks[mark]:
783 bookmarks.setcurrent(repo, mark)
783 bookmarks.setcurrent(repo, mark)
784 bookmarks.write(repo)
784 bookmarks.write(repo)
785 return
785 return
786
786
787 if mark is None:
787 if mark is None:
788 if rev:
788 if rev:
789 raise util.Abort(_("bookmark name required"))
789 raise util.Abort(_("bookmark name required"))
790 if len(marks) == 0:
790 if len(marks) == 0:
791 ui.status(_("no bookmarks set\n"))
791 ui.status(_("no bookmarks set\n"))
792 else:
792 else:
793 for bmark, n in sorted(marks.iteritems()):
793 for bmark, n in sorted(marks.iteritems()):
794 current = repo._bookmarkcurrent
794 current = repo._bookmarkcurrent
795 if bmark == current and n == cur:
795 if bmark == current and n == cur:
796 prefix, label = '*', 'bookmarks.current'
796 prefix, label = '*', 'bookmarks.current'
797 else:
797 else:
798 prefix, label = ' ', ''
798 prefix, label = ' ', ''
799
799
800 if ui.quiet:
800 if ui.quiet:
801 ui.write("%s\n" % bmark, label=label)
801 ui.write("%s\n" % bmark, label=label)
802 else:
802 else:
803 ui.write(" %s %-25s %d:%s\n" % (
803 ui.write(" %s %-25s %d:%s\n" % (
804 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
804 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
805 label=label)
805 label=label)
806 return
806 return
807
807
808 @command('branch',
808 @command('branch',
809 [('f', 'force', None,
809 [('f', 'force', None,
810 _('set branch name even if it shadows an existing branch')),
810 _('set branch name even if it shadows an existing branch')),
811 ('C', 'clean', None, _('reset branch name to parent branch name'))],
811 ('C', 'clean', None, _('reset branch name to parent branch name'))],
812 _('[-fC] [NAME]'))
812 _('[-fC] [NAME]'))
813 def branch(ui, repo, label=None, **opts):
813 def branch(ui, repo, label=None, **opts):
814 """set or show the current branch name
814 """set or show the current branch name
815
815
816 With no argument, show the current branch name. With one argument,
816 With no argument, show the current branch name. With one argument,
817 set the working directory branch name (the branch will not exist
817 set the working directory branch name (the branch will not exist
818 in the repository until the next commit). Standard practice
818 in the repository until the next commit). Standard practice
819 recommends that primary development take place on the 'default'
819 recommends that primary development take place on the 'default'
820 branch.
820 branch.
821
821
822 Unless -f/--force is specified, branch will not let you set a
822 Unless -f/--force is specified, branch will not let you set a
823 branch name that already exists, even if it's inactive.
823 branch name that already exists, even if it's inactive.
824
824
825 Use -C/--clean to reset the working directory branch to that of
825 Use -C/--clean to reset the working directory branch to that of
826 the parent of the working directory, negating a previous branch
826 the parent of the working directory, negating a previous branch
827 change.
827 change.
828
828
829 Use the command :hg:`update` to switch to an existing branch. Use
829 Use the command :hg:`update` to switch to an existing branch. Use
830 :hg:`commit --close-branch` to mark this branch as closed.
830 :hg:`commit --close-branch` to mark this branch as closed.
831
831
832 .. note::
832 .. note::
833
833
834 Branch names are permanent. Use :hg:`bookmark` to create a
834 Branch names are permanent. Use :hg:`bookmark` to create a
835 light-weight bookmark instead. See :hg:`help glossary` for more
835 light-weight bookmark instead. See :hg:`help glossary` for more
836 information about named branches and bookmarks.
836 information about named branches and bookmarks.
837
837
838 Returns 0 on success.
838 Returns 0 on success.
839 """
839 """
840
840
841 if opts.get('clean'):
841 if opts.get('clean'):
842 label = repo[None].p1().branch()
842 label = repo[None].p1().branch()
843 repo.dirstate.setbranch(label)
843 repo.dirstate.setbranch(label)
844 ui.status(_('reset working directory to branch %s\n') % label)
844 ui.status(_('reset working directory to branch %s\n') % label)
845 elif label:
845 elif label:
846 if not opts.get('force') and label in repo.branchtags():
846 if not opts.get('force') and label in repo.branchtags():
847 if label not in [p.branch() for p in repo.parents()]:
847 if label not in [p.branch() for p in repo.parents()]:
848 raise util.Abort(_('a branch of the same name already exists'),
848 raise util.Abort(_('a branch of the same name already exists'),
849 # i18n: "it" refers to an existing branch
849 # i18n: "it" refers to an existing branch
850 hint=_("use 'hg update' to switch to it"))
850 hint=_("use 'hg update' to switch to it"))
851 repo.dirstate.setbranch(label)
851 repo.dirstate.setbranch(label)
852 ui.status(_('marked working directory as branch %s\n') % label)
852 ui.status(_('marked working directory as branch %s\n') % label)
853 else:
853 else:
854 ui.write("%s\n" % repo.dirstate.branch())
854 ui.write("%s\n" % repo.dirstate.branch())
855
855
856 @command('branches',
856 @command('branches',
857 [('a', 'active', False, _('show only branches that have unmerged heads')),
857 [('a', 'active', False, _('show only branches that have unmerged heads')),
858 ('c', 'closed', False, _('show normal and closed branches'))],
858 ('c', 'closed', False, _('show normal and closed branches'))],
859 _('[-ac]'))
859 _('[-ac]'))
860 def branches(ui, repo, active=False, closed=False):
860 def branches(ui, repo, active=False, closed=False):
861 """list repository named branches
861 """list repository named branches
862
862
863 List the repository's named branches, indicating which ones are
863 List the repository's named branches, indicating which ones are
864 inactive. If -c/--closed is specified, also list branches which have
864 inactive. If -c/--closed is specified, also list branches which have
865 been marked closed (see :hg:`commit --close-branch`).
865 been marked closed (see :hg:`commit --close-branch`).
866
866
867 If -a/--active is specified, only show active branches. A branch
867 If -a/--active is specified, only show active branches. A branch
868 is considered active if it contains repository heads.
868 is considered active if it contains repository heads.
869
869
870 Use the command :hg:`update` to switch to an existing branch.
870 Use the command :hg:`update` to switch to an existing branch.
871
871
872 Returns 0.
872 Returns 0.
873 """
873 """
874
874
875 hexfunc = ui.debugflag and hex or short
875 hexfunc = ui.debugflag and hex or short
876 activebranches = [repo[n].branch() for n in repo.heads()]
876 activebranches = [repo[n].branch() for n in repo.heads()]
877 def testactive(tag, node):
877 def testactive(tag, node):
878 realhead = tag in activebranches
878 realhead = tag in activebranches
879 open = node in repo.branchheads(tag, closed=False)
879 open = node in repo.branchheads(tag, closed=False)
880 return realhead and open
880 return realhead and open
881 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
881 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
882 for tag, node in repo.branchtags().items()],
882 for tag, node in repo.branchtags().items()],
883 reverse=True)
883 reverse=True)
884
884
885 for isactive, node, tag in branches:
885 for isactive, node, tag in branches:
886 if (not active) or isactive:
886 if (not active) or isactive:
887 if ui.quiet:
887 if ui.quiet:
888 ui.write("%s\n" % tag)
888 ui.write("%s\n" % tag)
889 else:
889 else:
890 hn = repo.lookup(node)
890 hn = repo.lookup(node)
891 if isactive:
891 if isactive:
892 label = 'branches.active'
892 label = 'branches.active'
893 notice = ''
893 notice = ''
894 elif hn not in repo.branchheads(tag, closed=False):
894 elif hn not in repo.branchheads(tag, closed=False):
895 if not closed:
895 if not closed:
896 continue
896 continue
897 label = 'branches.closed'
897 label = 'branches.closed'
898 notice = _(' (closed)')
898 notice = _(' (closed)')
899 else:
899 else:
900 label = 'branches.inactive'
900 label = 'branches.inactive'
901 notice = _(' (inactive)')
901 notice = _(' (inactive)')
902 if tag == repo.dirstate.branch():
902 if tag == repo.dirstate.branch():
903 label = 'branches.current'
903 label = 'branches.current'
904 rev = str(node).rjust(31 - encoding.colwidth(tag))
904 rev = str(node).rjust(31 - encoding.colwidth(tag))
905 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
905 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
906 tag = ui.label(tag, label)
906 tag = ui.label(tag, label)
907 ui.write("%s %s%s\n" % (tag, rev, notice))
907 ui.write("%s %s%s\n" % (tag, rev, notice))
908
908
909 @command('bundle',
909 @command('bundle',
910 [('f', 'force', None, _('run even when the destination is unrelated')),
910 [('f', 'force', None, _('run even when the destination is unrelated')),
911 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
911 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
912 _('REV')),
912 _('REV')),
913 ('b', 'branch', [], _('a specific branch you would like to bundle'),
913 ('b', 'branch', [], _('a specific branch you would like to bundle'),
914 _('BRANCH')),
914 _('BRANCH')),
915 ('', 'base', [],
915 ('', 'base', [],
916 _('a base changeset assumed to be available at the destination'),
916 _('a base changeset assumed to be available at the destination'),
917 _('REV')),
917 _('REV')),
918 ('a', 'all', None, _('bundle all changesets in the repository')),
918 ('a', 'all', None, _('bundle all changesets in the repository')),
919 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
919 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
920 ] + remoteopts,
920 ] + remoteopts,
921 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
921 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
922 def bundle(ui, repo, fname, dest=None, **opts):
922 def bundle(ui, repo, fname, dest=None, **opts):
923 """create a changegroup file
923 """create a changegroup file
924
924
925 Generate a compressed changegroup file collecting changesets not
925 Generate a compressed changegroup file collecting changesets not
926 known to be in another repository.
926 known to be in another repository.
927
927
928 If you omit the destination repository, then hg assumes the
928 If you omit the destination repository, then hg assumes the
929 destination will have all the nodes you specify with --base
929 destination will have all the nodes you specify with --base
930 parameters. To create a bundle containing all changesets, use
930 parameters. To create a bundle containing all changesets, use
931 -a/--all (or --base null).
931 -a/--all (or --base null).
932
932
933 You can change compression method with the -t/--type option.
933 You can change compression method with the -t/--type option.
934 The available compression methods are: none, bzip2, and
934 The available compression methods are: none, bzip2, and
935 gzip (by default, bundles are compressed using bzip2).
935 gzip (by default, bundles are compressed using bzip2).
936
936
937 The bundle file can then be transferred using conventional means
937 The bundle file can then be transferred using conventional means
938 and applied to another repository with the unbundle or pull
938 and applied to another repository with the unbundle or pull
939 command. This is useful when direct push and pull are not
939 command. This is useful when direct push and pull are not
940 available or when exporting an entire repository is undesirable.
940 available or when exporting an entire repository is undesirable.
941
941
942 Applying bundles preserves all changeset contents including
942 Applying bundles preserves all changeset contents including
943 permissions, copy/rename information, and revision history.
943 permissions, copy/rename information, and revision history.
944
944
945 Returns 0 on success, 1 if no changes found.
945 Returns 0 on success, 1 if no changes found.
946 """
946 """
947 revs = None
947 revs = None
948 if 'rev' in opts:
948 if 'rev' in opts:
949 revs = scmutil.revrange(repo, opts['rev'])
949 revs = scmutil.revrange(repo, opts['rev'])
950
950
951 if opts.get('all'):
951 if opts.get('all'):
952 base = ['null']
952 base = ['null']
953 else:
953 else:
954 base = scmutil.revrange(repo, opts.get('base'))
954 base = scmutil.revrange(repo, opts.get('base'))
955 if base:
955 if base:
956 if dest:
956 if dest:
957 raise util.Abort(_("--base is incompatible with specifying "
957 raise util.Abort(_("--base is incompatible with specifying "
958 "a destination"))
958 "a destination"))
959 common = [repo.lookup(rev) for rev in base]
959 common = [repo.lookup(rev) for rev in base]
960 heads = revs and map(repo.lookup, revs) or revs
960 heads = revs and map(repo.lookup, revs) or revs
961 else:
961 else:
962 dest = ui.expandpath(dest or 'default-push', dest or 'default')
962 dest = ui.expandpath(dest or 'default-push', dest or 'default')
963 dest, branches = hg.parseurl(dest, opts.get('branch'))
963 dest, branches = hg.parseurl(dest, opts.get('branch'))
964 other = hg.peer(repo, opts, dest)
964 other = hg.peer(repo, opts, dest)
965 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
965 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
966 heads = revs and map(repo.lookup, revs) or revs
966 heads = revs and map(repo.lookup, revs) or revs
967 common, outheads = discovery.findcommonoutgoing(repo, other,
967 common, outheads = discovery.findcommonoutgoing(repo, other,
968 onlyheads=heads,
968 onlyheads=heads,
969 force=opts.get('force'))
969 force=opts.get('force'))
970
970
971 cg = repo.getbundle('bundle', common=common, heads=heads)
971 cg = repo.getbundle('bundle', common=common, heads=heads)
972 if not cg:
972 if not cg:
973 ui.status(_("no changes found\n"))
973 ui.status(_("no changes found\n"))
974 return 1
974 return 1
975
975
976 bundletype = opts.get('type', 'bzip2').lower()
976 bundletype = opts.get('type', 'bzip2').lower()
977 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
977 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
978 bundletype = btypes.get(bundletype)
978 bundletype = btypes.get(bundletype)
979 if bundletype not in changegroup.bundletypes:
979 if bundletype not in changegroup.bundletypes:
980 raise util.Abort(_('unknown bundle type specified with --type'))
980 raise util.Abort(_('unknown bundle type specified with --type'))
981
981
982 changegroup.writebundle(cg, fname, bundletype)
982 changegroup.writebundle(cg, fname, bundletype)
983
983
984 @command('cat',
984 @command('cat',
985 [('o', 'output', '',
985 [('o', 'output', '',
986 _('print output to file with formatted name'), _('FORMAT')),
986 _('print output to file with formatted name'), _('FORMAT')),
987 ('r', 'rev', '', _('print the given revision'), _('REV')),
987 ('r', 'rev', '', _('print the given revision'), _('REV')),
988 ('', 'decode', None, _('apply any matching decode filter')),
988 ('', 'decode', None, _('apply any matching decode filter')),
989 ] + walkopts,
989 ] + walkopts,
990 _('[OPTION]... FILE...'))
990 _('[OPTION]... FILE...'))
991 def cat(ui, repo, file1, *pats, **opts):
991 def cat(ui, repo, file1, *pats, **opts):
992 """output the current or given revision of files
992 """output the current or given revision of files
993
993
994 Print the specified files as they were at the given revision. If
994 Print the specified files as they were at the given revision. If
995 no revision is given, the parent of the working directory is used,
995 no revision is given, the parent of the working directory is used,
996 or tip if no revision is checked out.
996 or tip if no revision is checked out.
997
997
998 Output may be to a file, in which case the name of the file is
998 Output may be to a file, in which case the name of the file is
999 given using a format string. The formatting rules are the same as
999 given using a format string. The formatting rules are the same as
1000 for the export command, with the following additions:
1000 for the export command, with the following additions:
1001
1001
1002 :``%s``: basename of file being printed
1002 :``%s``: basename of file being printed
1003 :``%d``: dirname of file being printed, or '.' if in repository root
1003 :``%d``: dirname of file being printed, or '.' if in repository root
1004 :``%p``: root-relative path name of file being printed
1004 :``%p``: root-relative path name of file being printed
1005
1005
1006 Returns 0 on success.
1006 Returns 0 on success.
1007 """
1007 """
1008 ctx = scmutil.revsingle(repo, opts.get('rev'))
1008 ctx = scmutil.revsingle(repo, opts.get('rev'))
1009 err = 1
1009 err = 1
1010 m = scmutil.match(ctx, (file1,) + pats, opts)
1010 m = scmutil.match(ctx, (file1,) + pats, opts)
1011 for abs in ctx.walk(m):
1011 for abs in ctx.walk(m):
1012 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1012 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1013 pathname=abs)
1013 pathname=abs)
1014 data = ctx[abs].data()
1014 data = ctx[abs].data()
1015 if opts.get('decode'):
1015 if opts.get('decode'):
1016 data = repo.wwritedata(abs, data)
1016 data = repo.wwritedata(abs, data)
1017 fp.write(data)
1017 fp.write(data)
1018 fp.close()
1018 fp.close()
1019 err = 0
1019 err = 0
1020 return err
1020 return err
1021
1021
1022 @command('^clone',
1022 @command('^clone',
1023 [('U', 'noupdate', None,
1023 [('U', 'noupdate', None,
1024 _('the clone will include an empty working copy (only a repository)')),
1024 _('the clone will include an empty working copy (only a repository)')),
1025 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1025 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1026 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1026 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1027 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1027 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1028 ('', 'pull', None, _('use pull protocol to copy metadata')),
1028 ('', 'pull', None, _('use pull protocol to copy metadata')),
1029 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1029 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1030 ] + remoteopts,
1030 ] + remoteopts,
1031 _('[OPTION]... SOURCE [DEST]'))
1031 _('[OPTION]... SOURCE [DEST]'))
1032 def clone(ui, source, dest=None, **opts):
1032 def clone(ui, source, dest=None, **opts):
1033 """make a copy of an existing repository
1033 """make a copy of an existing repository
1034
1034
1035 Create a copy of an existing repository in a new directory.
1035 Create a copy of an existing repository in a new directory.
1036
1036
1037 If no destination directory name is specified, it defaults to the
1037 If no destination directory name is specified, it defaults to the
1038 basename of the source.
1038 basename of the source.
1039
1039
1040 The location of the source is added to the new repository's
1040 The location of the source is added to the new repository's
1041 ``.hg/hgrc`` file, as the default to be used for future pulls.
1041 ``.hg/hgrc`` file, as the default to be used for future pulls.
1042
1042
1043 Only local paths and ``ssh://`` URLs are supported as
1043 Only local paths and ``ssh://`` URLs are supported as
1044 destinations. For ``ssh://`` destinations, no working directory or
1044 destinations. For ``ssh://`` destinations, no working directory or
1045 ``.hg/hgrc`` will be created on the remote side.
1045 ``.hg/hgrc`` will be created on the remote side.
1046
1046
1047 To pull only a subset of changesets, specify one or more revisions
1047 To pull only a subset of changesets, specify one or more revisions
1048 identifiers with -r/--rev or branches with -b/--branch. The
1048 identifiers with -r/--rev or branches with -b/--branch. The
1049 resulting clone will contain only the specified changesets and
1049 resulting clone will contain only the specified changesets and
1050 their ancestors. These options (or 'clone src#rev dest') imply
1050 their ancestors. These options (or 'clone src#rev dest') imply
1051 --pull, even for local source repositories. Note that specifying a
1051 --pull, even for local source repositories. Note that specifying a
1052 tag will include the tagged changeset but not the changeset
1052 tag will include the tagged changeset but not the changeset
1053 containing the tag.
1053 containing the tag.
1054
1054
1055 To check out a particular version, use -u/--update, or
1055 To check out a particular version, use -u/--update, or
1056 -U/--noupdate to create a clone with no working directory.
1056 -U/--noupdate to create a clone with no working directory.
1057
1057
1058 .. container:: verbose
1058 .. container:: verbose
1059
1059
1060 For efficiency, hardlinks are used for cloning whenever the
1060 For efficiency, hardlinks are used for cloning whenever the
1061 source and destination are on the same filesystem (note this
1061 source and destination are on the same filesystem (note this
1062 applies only to the repository data, not to the working
1062 applies only to the repository data, not to the working
1063 directory). Some filesystems, such as AFS, implement hardlinking
1063 directory). Some filesystems, such as AFS, implement hardlinking
1064 incorrectly, but do not report errors. In these cases, use the
1064 incorrectly, but do not report errors. In these cases, use the
1065 --pull option to avoid hardlinking.
1065 --pull option to avoid hardlinking.
1066
1066
1067 In some cases, you can clone repositories and the working
1067 In some cases, you can clone repositories and the working
1068 directory using full hardlinks with ::
1068 directory using full hardlinks with ::
1069
1069
1070 $ cp -al REPO REPOCLONE
1070 $ cp -al REPO REPOCLONE
1071
1071
1072 This is the fastest way to clone, but it is not always safe. The
1072 This is the fastest way to clone, but it is not always safe. The
1073 operation is not atomic (making sure REPO is not modified during
1073 operation is not atomic (making sure REPO is not modified during
1074 the operation is up to you) and you have to make sure your
1074 the operation is up to you) and you have to make sure your
1075 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1075 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1076 so). Also, this is not compatible with certain extensions that
1076 so). Also, this is not compatible with certain extensions that
1077 place their metadata under the .hg directory, such as mq.
1077 place their metadata under the .hg directory, such as mq.
1078
1078
1079 Mercurial will update the working directory to the first applicable
1079 Mercurial will update the working directory to the first applicable
1080 revision from this list:
1080 revision from this list:
1081
1081
1082 a) null if -U or the source repository has no changesets
1082 a) null if -U or the source repository has no changesets
1083 b) if -u . and the source repository is local, the first parent of
1083 b) if -u . and the source repository is local, the first parent of
1084 the source repository's working directory
1084 the source repository's working directory
1085 c) the changeset specified with -u (if a branch name, this means the
1085 c) the changeset specified with -u (if a branch name, this means the
1086 latest head of that branch)
1086 latest head of that branch)
1087 d) the changeset specified with -r
1087 d) the changeset specified with -r
1088 e) the tipmost head specified with -b
1088 e) the tipmost head specified with -b
1089 f) the tipmost head specified with the url#branch source syntax
1089 f) the tipmost head specified with the url#branch source syntax
1090 g) the tipmost head of the default branch
1090 g) the tipmost head of the default branch
1091 h) tip
1091 h) tip
1092
1092
1093 Examples:
1093 Examples:
1094
1094
1095 - clone a remote repository to a new directory named hg/::
1095 - clone a remote repository to a new directory named hg/::
1096
1096
1097 hg clone http://selenic.com/hg
1097 hg clone http://selenic.com/hg
1098
1098
1099 - create a lightweight local clone::
1099 - create a lightweight local clone::
1100
1100
1101 hg clone project/ project-feature/
1101 hg clone project/ project-feature/
1102
1102
1103 - clone from an absolute path on an ssh server (note double-slash)::
1103 - clone from an absolute path on an ssh server (note double-slash)::
1104
1104
1105 hg clone ssh://user@server//home/projects/alpha/
1105 hg clone ssh://user@server//home/projects/alpha/
1106
1106
1107 - do a high-speed clone over a LAN while checking out a
1107 - do a high-speed clone over a LAN while checking out a
1108 specified version::
1108 specified version::
1109
1109
1110 hg clone --uncompressed http://server/repo -u 1.5
1110 hg clone --uncompressed http://server/repo -u 1.5
1111
1111
1112 - create a repository without changesets after a particular revision::
1112 - create a repository without changesets after a particular revision::
1113
1113
1114 hg clone -r 04e544 experimental/ good/
1114 hg clone -r 04e544 experimental/ good/
1115
1115
1116 - clone (and track) a particular named branch::
1116 - clone (and track) a particular named branch::
1117
1117
1118 hg clone http://selenic.com/hg#stable
1118 hg clone http://selenic.com/hg#stable
1119
1119
1120 See :hg:`help urls` for details on specifying URLs.
1120 See :hg:`help urls` for details on specifying URLs.
1121
1121
1122 Returns 0 on success.
1122 Returns 0 on success.
1123 """
1123 """
1124 if opts.get('noupdate') and opts.get('updaterev'):
1124 if opts.get('noupdate') and opts.get('updaterev'):
1125 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1125 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1126
1126
1127 r = hg.clone(ui, opts, source, dest,
1127 r = hg.clone(ui, opts, source, dest,
1128 pull=opts.get('pull'),
1128 pull=opts.get('pull'),
1129 stream=opts.get('uncompressed'),
1129 stream=opts.get('uncompressed'),
1130 rev=opts.get('rev'),
1130 rev=opts.get('rev'),
1131 update=opts.get('updaterev') or not opts.get('noupdate'),
1131 update=opts.get('updaterev') or not opts.get('noupdate'),
1132 branch=opts.get('branch'))
1132 branch=opts.get('branch'))
1133
1133
1134 return r is None
1134 return r is None
1135
1135
1136 @command('^commit|ci',
1136 @command('^commit|ci',
1137 [('A', 'addremove', None,
1137 [('A', 'addremove', None,
1138 _('mark new/missing files as added/removed before committing')),
1138 _('mark new/missing files as added/removed before committing')),
1139 ('', 'close-branch', None,
1139 ('', 'close-branch', None,
1140 _('mark a branch as closed, hiding it from the branch list')),
1140 _('mark a branch as closed, hiding it from the branch list')),
1141 ] + walkopts + commitopts + commitopts2,
1141 ] + walkopts + commitopts + commitopts2,
1142 _('[OPTION]... [FILE]...'))
1142 _('[OPTION]... [FILE]...'))
1143 def commit(ui, repo, *pats, **opts):
1143 def commit(ui, repo, *pats, **opts):
1144 """commit the specified files or all outstanding changes
1144 """commit the specified files or all outstanding changes
1145
1145
1146 Commit changes to the given files into the repository. Unlike a
1146 Commit changes to the given files into the repository. Unlike a
1147 centralized SCM, this operation is a local operation. See
1147 centralized SCM, this operation is a local operation. See
1148 :hg:`push` for a way to actively distribute your changes.
1148 :hg:`push` for a way to actively distribute your changes.
1149
1149
1150 If a list of files is omitted, all changes reported by :hg:`status`
1150 If a list of files is omitted, all changes reported by :hg:`status`
1151 will be committed.
1151 will be committed.
1152
1152
1153 If you are committing the result of a merge, do not provide any
1153 If you are committing the result of a merge, do not provide any
1154 filenames or -I/-X filters.
1154 filenames or -I/-X filters.
1155
1155
1156 If no commit message is specified, Mercurial starts your
1156 If no commit message is specified, Mercurial starts your
1157 configured editor where you can enter a message. In case your
1157 configured editor where you can enter a message. In case your
1158 commit fails, you will find a backup of your message in
1158 commit fails, you will find a backup of your message in
1159 ``.hg/last-message.txt``.
1159 ``.hg/last-message.txt``.
1160
1160
1161 See :hg:`help dates` for a list of formats valid for -d/--date.
1161 See :hg:`help dates` for a list of formats valid for -d/--date.
1162
1162
1163 Returns 0 on success, 1 if nothing changed.
1163 Returns 0 on success, 1 if nothing changed.
1164 """
1164 """
1165 extra = {}
1165 extra = {}
1166 if opts.get('close_branch'):
1166 if opts.get('close_branch'):
1167 if repo['.'].node() not in repo.branchheads():
1167 if repo['.'].node() not in repo.branchheads():
1168 # The topo heads set is included in the branch heads set of the
1168 # The topo heads set is included in the branch heads set of the
1169 # current branch, so it's sufficient to test branchheads
1169 # current branch, so it's sufficient to test branchheads
1170 raise util.Abort(_('can only close branch heads'))
1170 raise util.Abort(_('can only close branch heads'))
1171 extra['close'] = 1
1171 extra['close'] = 1
1172 e = cmdutil.commiteditor
1172 e = cmdutil.commiteditor
1173 if opts.get('force_editor'):
1173 if opts.get('force_editor'):
1174 e = cmdutil.commitforceeditor
1174 e = cmdutil.commitforceeditor
1175
1175
1176 def commitfunc(ui, repo, message, match, opts):
1176 def commitfunc(ui, repo, message, match, opts):
1177 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1177 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1178 editor=e, extra=extra)
1178 editor=e, extra=extra)
1179
1179
1180 branch = repo[None].branch()
1180 branch = repo[None].branch()
1181 bheads = repo.branchheads(branch)
1181 bheads = repo.branchheads(branch)
1182
1182
1183 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1183 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1184 if not node:
1184 if not node:
1185 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1185 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1186 if stat[3]:
1186 if stat[3]:
1187 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1187 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1188 % len(stat[3]))
1188 % len(stat[3]))
1189 else:
1189 else:
1190 ui.status(_("nothing changed\n"))
1190 ui.status(_("nothing changed\n"))
1191 return 1
1191 return 1
1192
1192
1193 ctx = repo[node]
1193 ctx = repo[node]
1194 parents = ctx.parents()
1194 parents = ctx.parents()
1195
1195
1196 if (bheads and node not in bheads and not
1196 if (bheads and node not in bheads and not
1197 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1197 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1198 ui.status(_('created new head\n'))
1198 ui.status(_('created new head\n'))
1199 # The message is not printed for initial roots. For the other
1199 # The message is not printed for initial roots. For the other
1200 # changesets, it is printed in the following situations:
1200 # changesets, it is printed in the following situations:
1201 #
1201 #
1202 # Par column: for the 2 parents with ...
1202 # Par column: for the 2 parents with ...
1203 # N: null or no parent
1203 # N: null or no parent
1204 # B: parent is on another named branch
1204 # B: parent is on another named branch
1205 # C: parent is a regular non head changeset
1205 # C: parent is a regular non head changeset
1206 # H: parent was a branch head of the current branch
1206 # H: parent was a branch head of the current branch
1207 # Msg column: whether we print "created new head" message
1207 # Msg column: whether we print "created new head" message
1208 # In the following, it is assumed that there already exists some
1208 # In the following, it is assumed that there already exists some
1209 # initial branch heads of the current branch, otherwise nothing is
1209 # initial branch heads of the current branch, otherwise nothing is
1210 # printed anyway.
1210 # printed anyway.
1211 #
1211 #
1212 # Par Msg Comment
1212 # Par Msg Comment
1213 # NN y additional topo root
1213 # NN y additional topo root
1214 #
1214 #
1215 # BN y additional branch root
1215 # BN y additional branch root
1216 # CN y additional topo head
1216 # CN y additional topo head
1217 # HN n usual case
1217 # HN n usual case
1218 #
1218 #
1219 # BB y weird additional branch root
1219 # BB y weird additional branch root
1220 # CB y branch merge
1220 # CB y branch merge
1221 # HB n merge with named branch
1221 # HB n merge with named branch
1222 #
1222 #
1223 # CC y additional head from merge
1223 # CC y additional head from merge
1224 # CH n merge with a head
1224 # CH n merge with a head
1225 #
1225 #
1226 # HH n head merge: head count decreases
1226 # HH n head merge: head count decreases
1227
1227
1228 if not opts.get('close_branch'):
1228 if not opts.get('close_branch'):
1229 for r in parents:
1229 for r in parents:
1230 if r.extra().get('close') and r.branch() == branch:
1230 if r.extra().get('close') and r.branch() == branch:
1231 ui.status(_('reopening closed branch head %d\n') % r)
1231 ui.status(_('reopening closed branch head %d\n') % r)
1232
1232
1233 if ui.debugflag:
1233 if ui.debugflag:
1234 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1234 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1235 elif ui.verbose:
1235 elif ui.verbose:
1236 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1236 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1237
1237
1238 @command('copy|cp',
1238 @command('copy|cp',
1239 [('A', 'after', None, _('record a copy that has already occurred')),
1239 [('A', 'after', None, _('record a copy that has already occurred')),
1240 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1240 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1241 ] + walkopts + dryrunopts,
1241 ] + walkopts + dryrunopts,
1242 _('[OPTION]... [SOURCE]... DEST'))
1242 _('[OPTION]... [SOURCE]... DEST'))
1243 def copy(ui, repo, *pats, **opts):
1243 def copy(ui, repo, *pats, **opts):
1244 """mark files as copied for the next commit
1244 """mark files as copied for the next commit
1245
1245
1246 Mark dest as having copies of source files. If dest is a
1246 Mark dest as having copies of source files. If dest is a
1247 directory, copies are put in that directory. If dest is a file,
1247 directory, copies are put in that directory. If dest is a file,
1248 the source must be a single file.
1248 the source must be a single file.
1249
1249
1250 By default, this command copies the contents of files as they
1250 By default, this command copies the contents of files as they
1251 exist in the working directory. If invoked with -A/--after, the
1251 exist in the working directory. If invoked with -A/--after, the
1252 operation is recorded, but no copying is performed.
1252 operation is recorded, but no copying is performed.
1253
1253
1254 This command takes effect with the next commit. To undo a copy
1254 This command takes effect with the next commit. To undo a copy
1255 before that, see :hg:`revert`.
1255 before that, see :hg:`revert`.
1256
1256
1257 Returns 0 on success, 1 if errors are encountered.
1257 Returns 0 on success, 1 if errors are encountered.
1258 """
1258 """
1259 wlock = repo.wlock(False)
1259 wlock = repo.wlock(False)
1260 try:
1260 try:
1261 return cmdutil.copy(ui, repo, pats, opts)
1261 return cmdutil.copy(ui, repo, pats, opts)
1262 finally:
1262 finally:
1263 wlock.release()
1263 wlock.release()
1264
1264
1265 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1265 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1266 def debugancestor(ui, repo, *args):
1266 def debugancestor(ui, repo, *args):
1267 """find the ancestor revision of two revisions in a given index"""
1267 """find the ancestor revision of two revisions in a given index"""
1268 if len(args) == 3:
1268 if len(args) == 3:
1269 index, rev1, rev2 = args
1269 index, rev1, rev2 = args
1270 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1270 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1271 lookup = r.lookup
1271 lookup = r.lookup
1272 elif len(args) == 2:
1272 elif len(args) == 2:
1273 if not repo:
1273 if not repo:
1274 raise util.Abort(_("there is no Mercurial repository here "
1274 raise util.Abort(_("there is no Mercurial repository here "
1275 "(.hg not found)"))
1275 "(.hg not found)"))
1276 rev1, rev2 = args
1276 rev1, rev2 = args
1277 r = repo.changelog
1277 r = repo.changelog
1278 lookup = repo.lookup
1278 lookup = repo.lookup
1279 else:
1279 else:
1280 raise util.Abort(_('either two or three arguments required'))
1280 raise util.Abort(_('either two or three arguments required'))
1281 a = r.ancestor(lookup(rev1), lookup(rev2))
1281 a = r.ancestor(lookup(rev1), lookup(rev2))
1282 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1282 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1283
1283
1284 @command('debugbuilddag',
1284 @command('debugbuilddag',
1285 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1285 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1286 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1286 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1287 ('n', 'new-file', None, _('add new file at each rev'))],
1287 ('n', 'new-file', None, _('add new file at each rev'))],
1288 _('[OPTION]... [TEXT]'))
1288 _('[OPTION]... [TEXT]'))
1289 def debugbuilddag(ui, repo, text=None,
1289 def debugbuilddag(ui, repo, text=None,
1290 mergeable_file=False,
1290 mergeable_file=False,
1291 overwritten_file=False,
1291 overwritten_file=False,
1292 new_file=False):
1292 new_file=False):
1293 """builds a repo with a given DAG from scratch in the current empty repo
1293 """builds a repo with a given DAG from scratch in the current empty repo
1294
1294
1295 The description of the DAG is read from stdin if not given on the
1295 The description of the DAG is read from stdin if not given on the
1296 command line.
1296 command line.
1297
1297
1298 Elements:
1298 Elements:
1299
1299
1300 - "+n" is a linear run of n nodes based on the current default parent
1300 - "+n" is a linear run of n nodes based on the current default parent
1301 - "." is a single node based on the current default parent
1301 - "." is a single node based on the current default parent
1302 - "$" resets the default parent to null (implied at the start);
1302 - "$" resets the default parent to null (implied at the start);
1303 otherwise the default parent is always the last node created
1303 otherwise the default parent is always the last node created
1304 - "<p" sets the default parent to the backref p
1304 - "<p" sets the default parent to the backref p
1305 - "*p" is a fork at parent p, which is a backref
1305 - "*p" is a fork at parent p, which is a backref
1306 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1306 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1307 - "/p2" is a merge of the preceding node and p2
1307 - "/p2" is a merge of the preceding node and p2
1308 - ":tag" defines a local tag for the preceding node
1308 - ":tag" defines a local tag for the preceding node
1309 - "@branch" sets the named branch for subsequent nodes
1309 - "@branch" sets the named branch for subsequent nodes
1310 - "#...\\n" is a comment up to the end of the line
1310 - "#...\\n" is a comment up to the end of the line
1311
1311
1312 Whitespace between the above elements is ignored.
1312 Whitespace between the above elements is ignored.
1313
1313
1314 A backref is either
1314 A backref is either
1315
1315
1316 - a number n, which references the node curr-n, where curr is the current
1316 - a number n, which references the node curr-n, where curr is the current
1317 node, or
1317 node, or
1318 - the name of a local tag you placed earlier using ":tag", or
1318 - the name of a local tag you placed earlier using ":tag", or
1319 - empty to denote the default parent.
1319 - empty to denote the default parent.
1320
1320
1321 All string valued-elements are either strictly alphanumeric, or must
1321 All string valued-elements are either strictly alphanumeric, or must
1322 be enclosed in double quotes ("..."), with "\\" as escape character.
1322 be enclosed in double quotes ("..."), with "\\" as escape character.
1323 """
1323 """
1324
1324
1325 if text is None:
1325 if text is None:
1326 ui.status(_("reading DAG from stdin\n"))
1326 ui.status(_("reading DAG from stdin\n"))
1327 text = ui.fin.read()
1327 text = ui.fin.read()
1328
1328
1329 cl = repo.changelog
1329 cl = repo.changelog
1330 if len(cl) > 0:
1330 if len(cl) > 0:
1331 raise util.Abort(_('repository is not empty'))
1331 raise util.Abort(_('repository is not empty'))
1332
1332
1333 # determine number of revs in DAG
1333 # determine number of revs in DAG
1334 total = 0
1334 total = 0
1335 for type, data in dagparser.parsedag(text):
1335 for type, data in dagparser.parsedag(text):
1336 if type == 'n':
1336 if type == 'n':
1337 total += 1
1337 total += 1
1338
1338
1339 if mergeable_file:
1339 if mergeable_file:
1340 linesperrev = 2
1340 linesperrev = 2
1341 # make a file with k lines per rev
1341 # make a file with k lines per rev
1342 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1342 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1343 initialmergedlines.append("")
1343 initialmergedlines.append("")
1344
1344
1345 tags = []
1345 tags = []
1346
1346
1347 tr = repo.transaction("builddag")
1347 tr = repo.transaction("builddag")
1348 try:
1348 try:
1349
1349
1350 at = -1
1350 at = -1
1351 atbranch = 'default'
1351 atbranch = 'default'
1352 nodeids = []
1352 nodeids = []
1353 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1353 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1354 for type, data in dagparser.parsedag(text):
1354 for type, data in dagparser.parsedag(text):
1355 if type == 'n':
1355 if type == 'n':
1356 ui.note('node %s\n' % str(data))
1356 ui.note('node %s\n' % str(data))
1357 id, ps = data
1357 id, ps = data
1358
1358
1359 files = []
1359 files = []
1360 fctxs = {}
1360 fctxs = {}
1361
1361
1362 p2 = None
1362 p2 = None
1363 if mergeable_file:
1363 if mergeable_file:
1364 fn = "mf"
1364 fn = "mf"
1365 p1 = repo[ps[0]]
1365 p1 = repo[ps[0]]
1366 if len(ps) > 1:
1366 if len(ps) > 1:
1367 p2 = repo[ps[1]]
1367 p2 = repo[ps[1]]
1368 pa = p1.ancestor(p2)
1368 pa = p1.ancestor(p2)
1369 base, local, other = [x[fn].data() for x in pa, p1, p2]
1369 base, local, other = [x[fn].data() for x in pa, p1, p2]
1370 m3 = simplemerge.Merge3Text(base, local, other)
1370 m3 = simplemerge.Merge3Text(base, local, other)
1371 ml = [l.strip() for l in m3.merge_lines()]
1371 ml = [l.strip() for l in m3.merge_lines()]
1372 ml.append("")
1372 ml.append("")
1373 elif at > 0:
1373 elif at > 0:
1374 ml = p1[fn].data().split("\n")
1374 ml = p1[fn].data().split("\n")
1375 else:
1375 else:
1376 ml = initialmergedlines
1376 ml = initialmergedlines
1377 ml[id * linesperrev] += " r%i" % id
1377 ml[id * linesperrev] += " r%i" % id
1378 mergedtext = "\n".join(ml)
1378 mergedtext = "\n".join(ml)
1379 files.append(fn)
1379 files.append(fn)
1380 fctxs[fn] = context.memfilectx(fn, mergedtext)
1380 fctxs[fn] = context.memfilectx(fn, mergedtext)
1381
1381
1382 if overwritten_file:
1382 if overwritten_file:
1383 fn = "of"
1383 fn = "of"
1384 files.append(fn)
1384 files.append(fn)
1385 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1385 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1386
1386
1387 if new_file:
1387 if new_file:
1388 fn = "nf%i" % id
1388 fn = "nf%i" % id
1389 files.append(fn)
1389 files.append(fn)
1390 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1390 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1391 if len(ps) > 1:
1391 if len(ps) > 1:
1392 if not p2:
1392 if not p2:
1393 p2 = repo[ps[1]]
1393 p2 = repo[ps[1]]
1394 for fn in p2:
1394 for fn in p2:
1395 if fn.startswith("nf"):
1395 if fn.startswith("nf"):
1396 files.append(fn)
1396 files.append(fn)
1397 fctxs[fn] = p2[fn]
1397 fctxs[fn] = p2[fn]
1398
1398
1399 def fctxfn(repo, cx, path):
1399 def fctxfn(repo, cx, path):
1400 return fctxs.get(path)
1400 return fctxs.get(path)
1401
1401
1402 if len(ps) == 0 or ps[0] < 0:
1402 if len(ps) == 0 or ps[0] < 0:
1403 pars = [None, None]
1403 pars = [None, None]
1404 elif len(ps) == 1:
1404 elif len(ps) == 1:
1405 pars = [nodeids[ps[0]], None]
1405 pars = [nodeids[ps[0]], None]
1406 else:
1406 else:
1407 pars = [nodeids[p] for p in ps]
1407 pars = [nodeids[p] for p in ps]
1408 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1408 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1409 date=(id, 0),
1409 date=(id, 0),
1410 user="debugbuilddag",
1410 user="debugbuilddag",
1411 extra={'branch': atbranch})
1411 extra={'branch': atbranch})
1412 nodeid = repo.commitctx(cx)
1412 nodeid = repo.commitctx(cx)
1413 nodeids.append(nodeid)
1413 nodeids.append(nodeid)
1414 at = id
1414 at = id
1415 elif type == 'l':
1415 elif type == 'l':
1416 id, name = data
1416 id, name = data
1417 ui.note('tag %s\n' % name)
1417 ui.note('tag %s\n' % name)
1418 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1418 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1419 elif type == 'a':
1419 elif type == 'a':
1420 ui.note('branch %s\n' % data)
1420 ui.note('branch %s\n' % data)
1421 atbranch = data
1421 atbranch = data
1422 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1422 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1423 tr.close()
1423 tr.close()
1424 finally:
1424 finally:
1425 ui.progress(_('building'), None)
1425 ui.progress(_('building'), None)
1426 tr.release()
1426 tr.release()
1427
1427
1428 if tags:
1428 if tags:
1429 repo.opener.write("localtags", "".join(tags))
1429 repo.opener.write("localtags", "".join(tags))
1430
1430
1431 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1431 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1432 def debugbundle(ui, bundlepath, all=None, **opts):
1432 def debugbundle(ui, bundlepath, all=None, **opts):
1433 """lists the contents of a bundle"""
1433 """lists the contents of a bundle"""
1434 f = url.open(ui, bundlepath)
1434 f = url.open(ui, bundlepath)
1435 try:
1435 try:
1436 gen = changegroup.readbundle(f, bundlepath)
1436 gen = changegroup.readbundle(f, bundlepath)
1437 if all:
1437 if all:
1438 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1438 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1439
1439
1440 def showchunks(named):
1440 def showchunks(named):
1441 ui.write("\n%s\n" % named)
1441 ui.write("\n%s\n" % named)
1442 chain = None
1442 chain = None
1443 while True:
1443 while True:
1444 chunkdata = gen.deltachunk(chain)
1444 chunkdata = gen.deltachunk(chain)
1445 if not chunkdata:
1445 if not chunkdata:
1446 break
1446 break
1447 node = chunkdata['node']
1447 node = chunkdata['node']
1448 p1 = chunkdata['p1']
1448 p1 = chunkdata['p1']
1449 p2 = chunkdata['p2']
1449 p2 = chunkdata['p2']
1450 cs = chunkdata['cs']
1450 cs = chunkdata['cs']
1451 deltabase = chunkdata['deltabase']
1451 deltabase = chunkdata['deltabase']
1452 delta = chunkdata['delta']
1452 delta = chunkdata['delta']
1453 ui.write("%s %s %s %s %s %s\n" %
1453 ui.write("%s %s %s %s %s %s\n" %
1454 (hex(node), hex(p1), hex(p2),
1454 (hex(node), hex(p1), hex(p2),
1455 hex(cs), hex(deltabase), len(delta)))
1455 hex(cs), hex(deltabase), len(delta)))
1456 chain = node
1456 chain = node
1457
1457
1458 chunkdata = gen.changelogheader()
1458 chunkdata = gen.changelogheader()
1459 showchunks("changelog")
1459 showchunks("changelog")
1460 chunkdata = gen.manifestheader()
1460 chunkdata = gen.manifestheader()
1461 showchunks("manifest")
1461 showchunks("manifest")
1462 while True:
1462 while True:
1463 chunkdata = gen.filelogheader()
1463 chunkdata = gen.filelogheader()
1464 if not chunkdata:
1464 if not chunkdata:
1465 break
1465 break
1466 fname = chunkdata['filename']
1466 fname = chunkdata['filename']
1467 showchunks(fname)
1467 showchunks(fname)
1468 else:
1468 else:
1469 chunkdata = gen.changelogheader()
1469 chunkdata = gen.changelogheader()
1470 chain = None
1470 chain = None
1471 while True:
1471 while True:
1472 chunkdata = gen.deltachunk(chain)
1472 chunkdata = gen.deltachunk(chain)
1473 if not chunkdata:
1473 if not chunkdata:
1474 break
1474 break
1475 node = chunkdata['node']
1475 node = chunkdata['node']
1476 ui.write("%s\n" % hex(node))
1476 ui.write("%s\n" % hex(node))
1477 chain = node
1477 chain = node
1478 finally:
1478 finally:
1479 f.close()
1479 f.close()
1480
1480
1481 @command('debugcheckstate', [], '')
1481 @command('debugcheckstate', [], '')
1482 def debugcheckstate(ui, repo):
1482 def debugcheckstate(ui, repo):
1483 """validate the correctness of the current dirstate"""
1483 """validate the correctness of the current dirstate"""
1484 parent1, parent2 = repo.dirstate.parents()
1484 parent1, parent2 = repo.dirstate.parents()
1485 m1 = repo[parent1].manifest()
1485 m1 = repo[parent1].manifest()
1486 m2 = repo[parent2].manifest()
1486 m2 = repo[parent2].manifest()
1487 errors = 0
1487 errors = 0
1488 for f in repo.dirstate:
1488 for f in repo.dirstate:
1489 state = repo.dirstate[f]
1489 state = repo.dirstate[f]
1490 if state in "nr" and f not in m1:
1490 if state in "nr" and f not in m1:
1491 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1491 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1492 errors += 1
1492 errors += 1
1493 if state in "a" and f in m1:
1493 if state in "a" and f in m1:
1494 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1494 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1495 errors += 1
1495 errors += 1
1496 if state in "m" and f not in m1 and f not in m2:
1496 if state in "m" and f not in m1 and f not in m2:
1497 ui.warn(_("%s in state %s, but not in either manifest\n") %
1497 ui.warn(_("%s in state %s, but not in either manifest\n") %
1498 (f, state))
1498 (f, state))
1499 errors += 1
1499 errors += 1
1500 for f in m1:
1500 for f in m1:
1501 state = repo.dirstate[f]
1501 state = repo.dirstate[f]
1502 if state not in "nrm":
1502 if state not in "nrm":
1503 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1503 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1504 errors += 1
1504 errors += 1
1505 if errors:
1505 if errors:
1506 error = _(".hg/dirstate inconsistent with current parent's manifest")
1506 error = _(".hg/dirstate inconsistent with current parent's manifest")
1507 raise util.Abort(error)
1507 raise util.Abort(error)
1508
1508
1509 @command('debugcommands', [], _('[COMMAND]'))
1509 @command('debugcommands', [], _('[COMMAND]'))
1510 def debugcommands(ui, cmd='', *args):
1510 def debugcommands(ui, cmd='', *args):
1511 """list all available commands and options"""
1511 """list all available commands and options"""
1512 for cmd, vals in sorted(table.iteritems()):
1512 for cmd, vals in sorted(table.iteritems()):
1513 cmd = cmd.split('|')[0].strip('^')
1513 cmd = cmd.split('|')[0].strip('^')
1514 opts = ', '.join([i[1] for i in vals[1]])
1514 opts = ', '.join([i[1] for i in vals[1]])
1515 ui.write('%s: %s\n' % (cmd, opts))
1515 ui.write('%s: %s\n' % (cmd, opts))
1516
1516
1517 @command('debugcomplete',
1517 @command('debugcomplete',
1518 [('o', 'options', None, _('show the command options'))],
1518 [('o', 'options', None, _('show the command options'))],
1519 _('[-o] CMD'))
1519 _('[-o] CMD'))
1520 def debugcomplete(ui, cmd='', **opts):
1520 def debugcomplete(ui, cmd='', **opts):
1521 """returns the completion list associated with the given command"""
1521 """returns the completion list associated with the given command"""
1522
1522
1523 if opts.get('options'):
1523 if opts.get('options'):
1524 options = []
1524 options = []
1525 otables = [globalopts]
1525 otables = [globalopts]
1526 if cmd:
1526 if cmd:
1527 aliases, entry = cmdutil.findcmd(cmd, table, False)
1527 aliases, entry = cmdutil.findcmd(cmd, table, False)
1528 otables.append(entry[1])
1528 otables.append(entry[1])
1529 for t in otables:
1529 for t in otables:
1530 for o in t:
1530 for o in t:
1531 if "(DEPRECATED)" in o[3]:
1531 if "(DEPRECATED)" in o[3]:
1532 continue
1532 continue
1533 if o[0]:
1533 if o[0]:
1534 options.append('-%s' % o[0])
1534 options.append('-%s' % o[0])
1535 options.append('--%s' % o[1])
1535 options.append('--%s' % o[1])
1536 ui.write("%s\n" % "\n".join(options))
1536 ui.write("%s\n" % "\n".join(options))
1537 return
1537 return
1538
1538
1539 cmdlist = cmdutil.findpossible(cmd, table)
1539 cmdlist = cmdutil.findpossible(cmd, table)
1540 if ui.verbose:
1540 if ui.verbose:
1541 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1541 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1542 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1542 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1543
1543
1544 @command('debugdag',
1544 @command('debugdag',
1545 [('t', 'tags', None, _('use tags as labels')),
1545 [('t', 'tags', None, _('use tags as labels')),
1546 ('b', 'branches', None, _('annotate with branch names')),
1546 ('b', 'branches', None, _('annotate with branch names')),
1547 ('', 'dots', None, _('use dots for runs')),
1547 ('', 'dots', None, _('use dots for runs')),
1548 ('s', 'spaces', None, _('separate elements by spaces'))],
1548 ('s', 'spaces', None, _('separate elements by spaces'))],
1549 _('[OPTION]... [FILE [REV]...]'))
1549 _('[OPTION]... [FILE [REV]...]'))
1550 def debugdag(ui, repo, file_=None, *revs, **opts):
1550 def debugdag(ui, repo, file_=None, *revs, **opts):
1551 """format the changelog or an index DAG as a concise textual description
1551 """format the changelog or an index DAG as a concise textual description
1552
1552
1553 If you pass a revlog index, the revlog's DAG is emitted. If you list
1553 If you pass a revlog index, the revlog's DAG is emitted. If you list
1554 revision numbers, they get labelled in the output as rN.
1554 revision numbers, they get labelled in the output as rN.
1555
1555
1556 Otherwise, the changelog DAG of the current repo is emitted.
1556 Otherwise, the changelog DAG of the current repo is emitted.
1557 """
1557 """
1558 spaces = opts.get('spaces')
1558 spaces = opts.get('spaces')
1559 dots = opts.get('dots')
1559 dots = opts.get('dots')
1560 if file_:
1560 if file_:
1561 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1561 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1562 revs = set((int(r) for r in revs))
1562 revs = set((int(r) for r in revs))
1563 def events():
1563 def events():
1564 for r in rlog:
1564 for r in rlog:
1565 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1565 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1566 if r in revs:
1566 if r in revs:
1567 yield 'l', (r, "r%i" % r)
1567 yield 'l', (r, "r%i" % r)
1568 elif repo:
1568 elif repo:
1569 cl = repo.changelog
1569 cl = repo.changelog
1570 tags = opts.get('tags')
1570 tags = opts.get('tags')
1571 branches = opts.get('branches')
1571 branches = opts.get('branches')
1572 if tags:
1572 if tags:
1573 labels = {}
1573 labels = {}
1574 for l, n in repo.tags().items():
1574 for l, n in repo.tags().items():
1575 labels.setdefault(cl.rev(n), []).append(l)
1575 labels.setdefault(cl.rev(n), []).append(l)
1576 def events():
1576 def events():
1577 b = "default"
1577 b = "default"
1578 for r in cl:
1578 for r in cl:
1579 if branches:
1579 if branches:
1580 newb = cl.read(cl.node(r))[5]['branch']
1580 newb = cl.read(cl.node(r))[5]['branch']
1581 if newb != b:
1581 if newb != b:
1582 yield 'a', newb
1582 yield 'a', newb
1583 b = newb
1583 b = newb
1584 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1584 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1585 if tags:
1585 if tags:
1586 ls = labels.get(r)
1586 ls = labels.get(r)
1587 if ls:
1587 if ls:
1588 for l in ls:
1588 for l in ls:
1589 yield 'l', (r, l)
1589 yield 'l', (r, l)
1590 else:
1590 else:
1591 raise util.Abort(_('need repo for changelog dag'))
1591 raise util.Abort(_('need repo for changelog dag'))
1592
1592
1593 for line in dagparser.dagtextlines(events(),
1593 for line in dagparser.dagtextlines(events(),
1594 addspaces=spaces,
1594 addspaces=spaces,
1595 wraplabels=True,
1595 wraplabels=True,
1596 wrapannotations=True,
1596 wrapannotations=True,
1597 wrapnonlinear=dots,
1597 wrapnonlinear=dots,
1598 usedots=dots,
1598 usedots=dots,
1599 maxlinewidth=70):
1599 maxlinewidth=70):
1600 ui.write(line)
1600 ui.write(line)
1601 ui.write("\n")
1601 ui.write("\n")
1602
1602
1603 @command('debugdata',
1603 @command('debugdata',
1604 [('c', 'changelog', False, _('open changelog')),
1604 [('c', 'changelog', False, _('open changelog')),
1605 ('m', 'manifest', False, _('open manifest'))],
1605 ('m', 'manifest', False, _('open manifest'))],
1606 _('-c|-m|FILE REV'))
1606 _('-c|-m|FILE REV'))
1607 def debugdata(ui, repo, file_, rev = None, **opts):
1607 def debugdata(ui, repo, file_, rev = None, **opts):
1608 """dump the contents of a data file revision"""
1608 """dump the contents of a data file revision"""
1609 if opts.get('changelog') or opts.get('manifest'):
1609 if opts.get('changelog') or opts.get('manifest'):
1610 file_, rev = None, file_
1610 file_, rev = None, file_
1611 elif rev is None:
1611 elif rev is None:
1612 raise error.CommandError('debugdata', _('invalid arguments'))
1612 raise error.CommandError('debugdata', _('invalid arguments'))
1613 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1613 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1614 try:
1614 try:
1615 ui.write(r.revision(r.lookup(rev)))
1615 ui.write(r.revision(r.lookup(rev)))
1616 except KeyError:
1616 except KeyError:
1617 raise util.Abort(_('invalid revision identifier %s') % rev)
1617 raise util.Abort(_('invalid revision identifier %s') % rev)
1618
1618
1619 @command('debugdate',
1619 @command('debugdate',
1620 [('e', 'extended', None, _('try extended date formats'))],
1620 [('e', 'extended', None, _('try extended date formats'))],
1621 _('[-e] DATE [RANGE]'))
1621 _('[-e] DATE [RANGE]'))
1622 def debugdate(ui, date, range=None, **opts):
1622 def debugdate(ui, date, range=None, **opts):
1623 """parse and display a date"""
1623 """parse and display a date"""
1624 if opts["extended"]:
1624 if opts["extended"]:
1625 d = util.parsedate(date, util.extendeddateformats)
1625 d = util.parsedate(date, util.extendeddateformats)
1626 else:
1626 else:
1627 d = util.parsedate(date)
1627 d = util.parsedate(date)
1628 ui.write("internal: %s %s\n" % d)
1628 ui.write("internal: %s %s\n" % d)
1629 ui.write("standard: %s\n" % util.datestr(d))
1629 ui.write("standard: %s\n" % util.datestr(d))
1630 if range:
1630 if range:
1631 m = util.matchdate(range)
1631 m = util.matchdate(range)
1632 ui.write("match: %s\n" % m(d[0]))
1632 ui.write("match: %s\n" % m(d[0]))
1633
1633
1634 @command('debugdiscovery',
1634 @command('debugdiscovery',
1635 [('', 'old', None, _('use old-style discovery')),
1635 [('', 'old', None, _('use old-style discovery')),
1636 ('', 'nonheads', None,
1636 ('', 'nonheads', None,
1637 _('use old-style discovery with non-heads included')),
1637 _('use old-style discovery with non-heads included')),
1638 ] + remoteopts,
1638 ] + remoteopts,
1639 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1639 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1640 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1640 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1641 """runs the changeset discovery protocol in isolation"""
1641 """runs the changeset discovery protocol in isolation"""
1642 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1642 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1643 remote = hg.peer(repo, opts, remoteurl)
1643 remote = hg.peer(repo, opts, remoteurl)
1644 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1644 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1645
1645
1646 # make sure tests are repeatable
1646 # make sure tests are repeatable
1647 random.seed(12323)
1647 random.seed(12323)
1648
1648
1649 def doit(localheads, remoteheads):
1649 def doit(localheads, remoteheads):
1650 if opts.get('old'):
1650 if opts.get('old'):
1651 if localheads:
1651 if localheads:
1652 raise util.Abort('cannot use localheads with old style discovery')
1652 raise util.Abort('cannot use localheads with old style discovery')
1653 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1653 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1654 force=True)
1654 force=True)
1655 common = set(common)
1655 common = set(common)
1656 if not opts.get('nonheads'):
1656 if not opts.get('nonheads'):
1657 ui.write("unpruned common: %s\n" % " ".join([short(n)
1657 ui.write("unpruned common: %s\n" % " ".join([short(n)
1658 for n in common]))
1658 for n in common]))
1659 dag = dagutil.revlogdag(repo.changelog)
1659 dag = dagutil.revlogdag(repo.changelog)
1660 all = dag.ancestorset(dag.internalizeall(common))
1660 all = dag.ancestorset(dag.internalizeall(common))
1661 common = dag.externalizeall(dag.headsetofconnecteds(all))
1661 common = dag.externalizeall(dag.headsetofconnecteds(all))
1662 else:
1662 else:
1663 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1663 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1664 common = set(common)
1664 common = set(common)
1665 rheads = set(hds)
1665 rheads = set(hds)
1666 lheads = set(repo.heads())
1666 lheads = set(repo.heads())
1667 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1667 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1668 if lheads <= common:
1668 if lheads <= common:
1669 ui.write("local is subset\n")
1669 ui.write("local is subset\n")
1670 elif rheads <= common:
1670 elif rheads <= common:
1671 ui.write("remote is subset\n")
1671 ui.write("remote is subset\n")
1672
1672
1673 serverlogs = opts.get('serverlog')
1673 serverlogs = opts.get('serverlog')
1674 if serverlogs:
1674 if serverlogs:
1675 for filename in serverlogs:
1675 for filename in serverlogs:
1676 logfile = open(filename, 'r')
1676 logfile = open(filename, 'r')
1677 try:
1677 try:
1678 line = logfile.readline()
1678 line = logfile.readline()
1679 while line:
1679 while line:
1680 parts = line.strip().split(';')
1680 parts = line.strip().split(';')
1681 op = parts[1]
1681 op = parts[1]
1682 if op == 'cg':
1682 if op == 'cg':
1683 pass
1683 pass
1684 elif op == 'cgss':
1684 elif op == 'cgss':
1685 doit(parts[2].split(' '), parts[3].split(' '))
1685 doit(parts[2].split(' '), parts[3].split(' '))
1686 elif op == 'unb':
1686 elif op == 'unb':
1687 doit(parts[3].split(' '), parts[2].split(' '))
1687 doit(parts[3].split(' '), parts[2].split(' '))
1688 line = logfile.readline()
1688 line = logfile.readline()
1689 finally:
1689 finally:
1690 logfile.close()
1690 logfile.close()
1691
1691
1692 else:
1692 else:
1693 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1693 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1694 opts.get('remote_head'))
1694 opts.get('remote_head'))
1695 localrevs = opts.get('local_head')
1695 localrevs = opts.get('local_head')
1696 doit(localrevs, remoterevs)
1696 doit(localrevs, remoterevs)
1697
1697
1698 @command('debugfileset', [], ('REVSPEC'))
1698 @command('debugfileset', [], ('REVSPEC'))
1699 def debugfileset(ui, repo, expr):
1699 def debugfileset(ui, repo, expr):
1700 '''parse and apply a fileset specification'''
1700 '''parse and apply a fileset specification'''
1701 if ui.verbose:
1701 if ui.verbose:
1702 tree = fileset.parse(expr)[0]
1702 tree = fileset.parse(expr)[0]
1703 ui.note(tree, "\n")
1703 ui.note(tree, "\n")
1704
1704
1705 for f in fileset.getfileset(repo[None], expr):
1705 for f in fileset.getfileset(repo[None], expr):
1706 ui.write("%s\n" % f)
1706 ui.write("%s\n" % f)
1707
1707
1708 @command('debugfsinfo', [], _('[PATH]'))
1708 @command('debugfsinfo', [], _('[PATH]'))
1709 def debugfsinfo(ui, path = "."):
1709 def debugfsinfo(ui, path = "."):
1710 """show information detected about current filesystem"""
1710 """show information detected about current filesystem"""
1711 util.writefile('.debugfsinfo', '')
1711 util.writefile('.debugfsinfo', '')
1712 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1712 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1713 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1713 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1714 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1714 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1715 and 'yes' or 'no'))
1715 and 'yes' or 'no'))
1716 os.unlink('.debugfsinfo')
1716 os.unlink('.debugfsinfo')
1717
1717
1718 @command('debuggetbundle',
1718 @command('debuggetbundle',
1719 [('H', 'head', [], _('id of head node'), _('ID')),
1719 [('H', 'head', [], _('id of head node'), _('ID')),
1720 ('C', 'common', [], _('id of common node'), _('ID')),
1720 ('C', 'common', [], _('id of common node'), _('ID')),
1721 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1721 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1722 _('REPO FILE [-H|-C ID]...'))
1722 _('REPO FILE [-H|-C ID]...'))
1723 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1723 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1724 """retrieves a bundle from a repo
1724 """retrieves a bundle from a repo
1725
1725
1726 Every ID must be a full-length hex node id string. Saves the bundle to the
1726 Every ID must be a full-length hex node id string. Saves the bundle to the
1727 given file.
1727 given file.
1728 """
1728 """
1729 repo = hg.peer(ui, opts, repopath)
1729 repo = hg.peer(ui, opts, repopath)
1730 if not repo.capable('getbundle'):
1730 if not repo.capable('getbundle'):
1731 raise util.Abort("getbundle() not supported by target repository")
1731 raise util.Abort("getbundle() not supported by target repository")
1732 args = {}
1732 args = {}
1733 if common:
1733 if common:
1734 args['common'] = [bin(s) for s in common]
1734 args['common'] = [bin(s) for s in common]
1735 if head:
1735 if head:
1736 args['heads'] = [bin(s) for s in head]
1736 args['heads'] = [bin(s) for s in head]
1737 bundle = repo.getbundle('debug', **args)
1737 bundle = repo.getbundle('debug', **args)
1738
1738
1739 bundletype = opts.get('type', 'bzip2').lower()
1739 bundletype = opts.get('type', 'bzip2').lower()
1740 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1740 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1741 bundletype = btypes.get(bundletype)
1741 bundletype = btypes.get(bundletype)
1742 if bundletype not in changegroup.bundletypes:
1742 if bundletype not in changegroup.bundletypes:
1743 raise util.Abort(_('unknown bundle type specified with --type'))
1743 raise util.Abort(_('unknown bundle type specified with --type'))
1744 changegroup.writebundle(bundle, bundlepath, bundletype)
1744 changegroup.writebundle(bundle, bundlepath, bundletype)
1745
1745
1746 @command('debugignore', [], '')
1746 @command('debugignore', [], '')
1747 def debugignore(ui, repo, *values, **opts):
1747 def debugignore(ui, repo, *values, **opts):
1748 """display the combined ignore pattern"""
1748 """display the combined ignore pattern"""
1749 ignore = repo.dirstate._ignore
1749 ignore = repo.dirstate._ignore
1750 includepat = getattr(ignore, 'includepat', None)
1750 includepat = getattr(ignore, 'includepat', None)
1751 if includepat is not None:
1751 if includepat is not None:
1752 ui.write("%s\n" % includepat)
1752 ui.write("%s\n" % includepat)
1753 else:
1753 else:
1754 raise util.Abort(_("no ignore patterns found"))
1754 raise util.Abort(_("no ignore patterns found"))
1755
1755
1756 @command('debugindex',
1756 @command('debugindex',
1757 [('c', 'changelog', False, _('open changelog')),
1757 [('c', 'changelog', False, _('open changelog')),
1758 ('m', 'manifest', False, _('open manifest')),
1758 ('m', 'manifest', False, _('open manifest')),
1759 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1759 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1760 _('[-f FORMAT] -c|-m|FILE'))
1760 _('[-f FORMAT] -c|-m|FILE'))
1761 def debugindex(ui, repo, file_ = None, **opts):
1761 def debugindex(ui, repo, file_ = None, **opts):
1762 """dump the contents of an index file"""
1762 """dump the contents of an index file"""
1763 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1763 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1764 format = opts.get('format', 0)
1764 format = opts.get('format', 0)
1765 if format not in (0, 1):
1765 if format not in (0, 1):
1766 raise util.Abort(_("unknown format %d") % format)
1766 raise util.Abort(_("unknown format %d") % format)
1767
1767
1768 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1768 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1769 if generaldelta:
1769 if generaldelta:
1770 basehdr = ' delta'
1770 basehdr = ' delta'
1771 else:
1771 else:
1772 basehdr = ' base'
1772 basehdr = ' base'
1773
1773
1774 if format == 0:
1774 if format == 0:
1775 ui.write(" rev offset length " + basehdr + " linkrev"
1775 ui.write(" rev offset length " + basehdr + " linkrev"
1776 " nodeid p1 p2\n")
1776 " nodeid p1 p2\n")
1777 elif format == 1:
1777 elif format == 1:
1778 ui.write(" rev flag offset length"
1778 ui.write(" rev flag offset length"
1779 " size " + basehdr + " link p1 p2 nodeid\n")
1779 " size " + basehdr + " link p1 p2 nodeid\n")
1780
1780
1781 for i in r:
1781 for i in r:
1782 node = r.node(i)
1782 node = r.node(i)
1783 if generaldelta:
1783 if generaldelta:
1784 base = r.deltaparent(i)
1784 base = r.deltaparent(i)
1785 else:
1785 else:
1786 base = r.chainbase(i)
1786 base = r.chainbase(i)
1787 if format == 0:
1787 if format == 0:
1788 try:
1788 try:
1789 pp = r.parents(node)
1789 pp = r.parents(node)
1790 except:
1790 except:
1791 pp = [nullid, nullid]
1791 pp = [nullid, nullid]
1792 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1792 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1793 i, r.start(i), r.length(i), base, r.linkrev(i),
1793 i, r.start(i), r.length(i), base, r.linkrev(i),
1794 short(node), short(pp[0]), short(pp[1])))
1794 short(node), short(pp[0]), short(pp[1])))
1795 elif format == 1:
1795 elif format == 1:
1796 pr = r.parentrevs(i)
1796 pr = r.parentrevs(i)
1797 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1797 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1798 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1798 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1799 base, r.linkrev(i), pr[0], pr[1], short(node)))
1799 base, r.linkrev(i), pr[0], pr[1], short(node)))
1800
1800
1801 @command('debugindexdot', [], _('FILE'))
1801 @command('debugindexdot', [], _('FILE'))
1802 def debugindexdot(ui, repo, file_):
1802 def debugindexdot(ui, repo, file_):
1803 """dump an index DAG as a graphviz dot file"""
1803 """dump an index DAG as a graphviz dot file"""
1804 r = None
1804 r = None
1805 if repo:
1805 if repo:
1806 filelog = repo.file(file_)
1806 filelog = repo.file(file_)
1807 if len(filelog):
1807 if len(filelog):
1808 r = filelog
1808 r = filelog
1809 if not r:
1809 if not r:
1810 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1810 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1811 ui.write("digraph G {\n")
1811 ui.write("digraph G {\n")
1812 for i in r:
1812 for i in r:
1813 node = r.node(i)
1813 node = r.node(i)
1814 pp = r.parents(node)
1814 pp = r.parents(node)
1815 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1815 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1816 if pp[1] != nullid:
1816 if pp[1] != nullid:
1817 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1817 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1818 ui.write("}\n")
1818 ui.write("}\n")
1819
1819
1820 @command('debuginstall', [], '')
1820 @command('debuginstall', [], '')
1821 def debuginstall(ui):
1821 def debuginstall(ui):
1822 '''test Mercurial installation
1822 '''test Mercurial installation
1823
1823
1824 Returns 0 on success.
1824 Returns 0 on success.
1825 '''
1825 '''
1826
1826
1827 def writetemp(contents):
1827 def writetemp(contents):
1828 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1828 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1829 f = os.fdopen(fd, "wb")
1829 f = os.fdopen(fd, "wb")
1830 f.write(contents)
1830 f.write(contents)
1831 f.close()
1831 f.close()
1832 return name
1832 return name
1833
1833
1834 problems = 0
1834 problems = 0
1835
1835
1836 # encoding
1836 # encoding
1837 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1837 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1838 try:
1838 try:
1839 encoding.fromlocal("test")
1839 encoding.fromlocal("test")
1840 except util.Abort, inst:
1840 except util.Abort, inst:
1841 ui.write(" %s\n" % inst)
1841 ui.write(" %s\n" % inst)
1842 ui.write(_(" (check that your locale is properly set)\n"))
1842 ui.write(_(" (check that your locale is properly set)\n"))
1843 problems += 1
1843 problems += 1
1844
1844
1845 # compiled modules
1845 # compiled modules
1846 ui.status(_("Checking installed modules (%s)...\n")
1846 ui.status(_("Checking installed modules (%s)...\n")
1847 % os.path.dirname(__file__))
1847 % os.path.dirname(__file__))
1848 try:
1848 try:
1849 import bdiff, mpatch, base85, osutil
1849 import bdiff, mpatch, base85, osutil
1850 except Exception, inst:
1850 except Exception, inst:
1851 ui.write(" %s\n" % inst)
1851 ui.write(" %s\n" % inst)
1852 ui.write(_(" One or more extensions could not be found"))
1852 ui.write(_(" One or more extensions could not be found"))
1853 ui.write(_(" (check that you compiled the extensions)\n"))
1853 ui.write(_(" (check that you compiled the extensions)\n"))
1854 problems += 1
1854 problems += 1
1855
1855
1856 # templates
1856 # templates
1857 ui.status(_("Checking templates...\n"))
1857 ui.status(_("Checking templates...\n"))
1858 try:
1858 try:
1859 import templater
1859 import templater
1860 templater.templater(templater.templatepath("map-cmdline.default"))
1860 templater.templater(templater.templatepath("map-cmdline.default"))
1861 except Exception, inst:
1861 except Exception, inst:
1862 ui.write(" %s\n" % inst)
1862 ui.write(" %s\n" % inst)
1863 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1863 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1864 problems += 1
1864 problems += 1
1865
1865
1866 # editor
1866 # editor
1867 ui.status(_("Checking commit editor...\n"))
1867 ui.status(_("Checking commit editor...\n"))
1868 editor = ui.geteditor()
1868 editor = ui.geteditor()
1869 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1869 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1870 if not cmdpath:
1870 if not cmdpath:
1871 if editor == 'vi':
1871 if editor == 'vi':
1872 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1872 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1873 ui.write(_(" (specify a commit editor in your configuration"
1873 ui.write(_(" (specify a commit editor in your configuration"
1874 " file)\n"))
1874 " file)\n"))
1875 else:
1875 else:
1876 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1876 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1877 ui.write(_(" (specify a commit editor in your configuration"
1877 ui.write(_(" (specify a commit editor in your configuration"
1878 " file)\n"))
1878 " file)\n"))
1879 problems += 1
1879 problems += 1
1880
1880
1881 # check username
1881 # check username
1882 ui.status(_("Checking username...\n"))
1882 ui.status(_("Checking username...\n"))
1883 try:
1883 try:
1884 ui.username()
1884 ui.username()
1885 except util.Abort, e:
1885 except util.Abort, e:
1886 ui.write(" %s\n" % e)
1886 ui.write(" %s\n" % e)
1887 ui.write(_(" (specify a username in your configuration file)\n"))
1887 ui.write(_(" (specify a username in your configuration file)\n"))
1888 problems += 1
1888 problems += 1
1889
1889
1890 if not problems:
1890 if not problems:
1891 ui.status(_("No problems detected\n"))
1891 ui.status(_("No problems detected\n"))
1892 else:
1892 else:
1893 ui.write(_("%s problems detected,"
1893 ui.write(_("%s problems detected,"
1894 " please check your install!\n") % problems)
1894 " please check your install!\n") % problems)
1895
1895
1896 return problems
1896 return problems
1897
1897
1898 @command('debugknown', [], _('REPO ID...'))
1898 @command('debugknown', [], _('REPO ID...'))
1899 def debugknown(ui, repopath, *ids, **opts):
1899 def debugknown(ui, repopath, *ids, **opts):
1900 """test whether node ids are known to a repo
1900 """test whether node ids are known to a repo
1901
1901
1902 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1902 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1903 indicating unknown/known.
1903 indicating unknown/known.
1904 """
1904 """
1905 repo = hg.peer(ui, opts, repopath)
1905 repo = hg.peer(ui, opts, repopath)
1906 if not repo.capable('known'):
1906 if not repo.capable('known'):
1907 raise util.Abort("known() not supported by target repository")
1907 raise util.Abort("known() not supported by target repository")
1908 flags = repo.known([bin(s) for s in ids])
1908 flags = repo.known([bin(s) for s in ids])
1909 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1909 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1910
1910
1911 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1911 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1912 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1912 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1913 '''access the pushkey key/value protocol
1913 '''access the pushkey key/value protocol
1914
1914
1915 With two args, list the keys in the given namespace.
1915 With two args, list the keys in the given namespace.
1916
1916
1917 With five args, set a key to new if it currently is set to old.
1917 With five args, set a key to new if it currently is set to old.
1918 Reports success or failure.
1918 Reports success or failure.
1919 '''
1919 '''
1920
1920
1921 target = hg.peer(ui, {}, repopath)
1921 target = hg.peer(ui, {}, repopath)
1922 if keyinfo:
1922 if keyinfo:
1923 key, old, new = keyinfo
1923 key, old, new = keyinfo
1924 r = target.pushkey(namespace, key, old, new)
1924 r = target.pushkey(namespace, key, old, new)
1925 ui.status(str(r) + '\n')
1925 ui.status(str(r) + '\n')
1926 return not r
1926 return not r
1927 else:
1927 else:
1928 for k, v in target.listkeys(namespace).iteritems():
1928 for k, v in target.listkeys(namespace).iteritems():
1929 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1929 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1930 v.encode('string-escape')))
1930 v.encode('string-escape')))
1931
1931
1932 @command('debugrebuildstate',
1932 @command('debugrebuildstate',
1933 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1933 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1934 _('[-r REV] [REV]'))
1934 _('[-r REV] [REV]'))
1935 def debugrebuildstate(ui, repo, rev="tip"):
1935 def debugrebuildstate(ui, repo, rev="tip"):
1936 """rebuild the dirstate as it would look like for the given revision"""
1936 """rebuild the dirstate as it would look like for the given revision"""
1937 ctx = scmutil.revsingle(repo, rev)
1937 ctx = scmutil.revsingle(repo, rev)
1938 wlock = repo.wlock()
1938 wlock = repo.wlock()
1939 try:
1939 try:
1940 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1940 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1941 finally:
1941 finally:
1942 wlock.release()
1942 wlock.release()
1943
1943
1944 @command('debugrename',
1944 @command('debugrename',
1945 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1945 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1946 _('[-r REV] FILE'))
1946 _('[-r REV] FILE'))
1947 def debugrename(ui, repo, file1, *pats, **opts):
1947 def debugrename(ui, repo, file1, *pats, **opts):
1948 """dump rename information"""
1948 """dump rename information"""
1949
1949
1950 ctx = scmutil.revsingle(repo, opts.get('rev'))
1950 ctx = scmutil.revsingle(repo, opts.get('rev'))
1951 m = scmutil.match(ctx, (file1,) + pats, opts)
1951 m = scmutil.match(ctx, (file1,) + pats, opts)
1952 for abs in ctx.walk(m):
1952 for abs in ctx.walk(m):
1953 fctx = ctx[abs]
1953 fctx = ctx[abs]
1954 o = fctx.filelog().renamed(fctx.filenode())
1954 o = fctx.filelog().renamed(fctx.filenode())
1955 rel = m.rel(abs)
1955 rel = m.rel(abs)
1956 if o:
1956 if o:
1957 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1957 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1958 else:
1958 else:
1959 ui.write(_("%s not renamed\n") % rel)
1959 ui.write(_("%s not renamed\n") % rel)
1960
1960
1961 @command('debugrevlog',
1961 @command('debugrevlog',
1962 [('c', 'changelog', False, _('open changelog')),
1962 [('c', 'changelog', False, _('open changelog')),
1963 ('m', 'manifest', False, _('open manifest')),
1963 ('m', 'manifest', False, _('open manifest')),
1964 ('d', 'dump', False, _('dump index data'))],
1964 ('d', 'dump', False, _('dump index data'))],
1965 _('-c|-m|FILE'))
1965 _('-c|-m|FILE'))
1966 def debugrevlog(ui, repo, file_ = None, **opts):
1966 def debugrevlog(ui, repo, file_ = None, **opts):
1967 """show data and statistics about a revlog"""
1967 """show data and statistics about a revlog"""
1968 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1968 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1969
1969
1970 if opts.get("dump"):
1970 if opts.get("dump"):
1971 numrevs = len(r)
1971 numrevs = len(r)
1972 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1972 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1973 " rawsize totalsize compression heads\n")
1973 " rawsize totalsize compression heads\n")
1974 ts = 0
1974 ts = 0
1975 heads = set()
1975 heads = set()
1976 for rev in xrange(numrevs):
1976 for rev in xrange(numrevs):
1977 dbase = r.deltaparent(rev)
1977 dbase = r.deltaparent(rev)
1978 if dbase == -1:
1978 if dbase == -1:
1979 dbase = rev
1979 dbase = rev
1980 cbase = r.chainbase(rev)
1980 cbase = r.chainbase(rev)
1981 p1, p2 = r.parentrevs(rev)
1981 p1, p2 = r.parentrevs(rev)
1982 rs = r.rawsize(rev)
1982 rs = r.rawsize(rev)
1983 ts = ts + rs
1983 ts = ts + rs
1984 heads -= set(r.parentrevs(rev))
1984 heads -= set(r.parentrevs(rev))
1985 heads.add(rev)
1985 heads.add(rev)
1986 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1986 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
1987 (rev, p1, p2, r.start(rev), r.end(rev),
1987 (rev, p1, p2, r.start(rev), r.end(rev),
1988 r.start(dbase), r.start(cbase),
1988 r.start(dbase), r.start(cbase),
1989 r.start(p1), r.start(p2),
1989 r.start(p1), r.start(p2),
1990 rs, ts, ts / r.end(rev), len(heads)))
1990 rs, ts, ts / r.end(rev), len(heads)))
1991 return 0
1991 return 0
1992
1992
1993 v = r.version
1993 v = r.version
1994 format = v & 0xFFFF
1994 format = v & 0xFFFF
1995 flags = []
1995 flags = []
1996 gdelta = False
1996 gdelta = False
1997 if v & revlog.REVLOGNGINLINEDATA:
1997 if v & revlog.REVLOGNGINLINEDATA:
1998 flags.append('inline')
1998 flags.append('inline')
1999 if v & revlog.REVLOGGENERALDELTA:
1999 if v & revlog.REVLOGGENERALDELTA:
2000 gdelta = True
2000 gdelta = True
2001 flags.append('generaldelta')
2001 flags.append('generaldelta')
2002 if not flags:
2002 if not flags:
2003 flags = ['(none)']
2003 flags = ['(none)']
2004
2004
2005 nummerges = 0
2005 nummerges = 0
2006 numfull = 0
2006 numfull = 0
2007 numprev = 0
2007 numprev = 0
2008 nump1 = 0
2008 nump1 = 0
2009 nump2 = 0
2009 nump2 = 0
2010 numother = 0
2010 numother = 0
2011 nump1prev = 0
2011 nump1prev = 0
2012 nump2prev = 0
2012 nump2prev = 0
2013 chainlengths = []
2013 chainlengths = []
2014
2014
2015 datasize = [None, 0, 0L]
2015 datasize = [None, 0, 0L]
2016 fullsize = [None, 0, 0L]
2016 fullsize = [None, 0, 0L]
2017 deltasize = [None, 0, 0L]
2017 deltasize = [None, 0, 0L]
2018
2018
2019 def addsize(size, l):
2019 def addsize(size, l):
2020 if l[0] is None or size < l[0]:
2020 if l[0] is None or size < l[0]:
2021 l[0] = size
2021 l[0] = size
2022 if size > l[1]:
2022 if size > l[1]:
2023 l[1] = size
2023 l[1] = size
2024 l[2] += size
2024 l[2] += size
2025
2025
2026 numrevs = len(r)
2026 numrevs = len(r)
2027 for rev in xrange(numrevs):
2027 for rev in xrange(numrevs):
2028 p1, p2 = r.parentrevs(rev)
2028 p1, p2 = r.parentrevs(rev)
2029 delta = r.deltaparent(rev)
2029 delta = r.deltaparent(rev)
2030 if format > 0:
2030 if format > 0:
2031 addsize(r.rawsize(rev), datasize)
2031 addsize(r.rawsize(rev), datasize)
2032 if p2 != nullrev:
2032 if p2 != nullrev:
2033 nummerges += 1
2033 nummerges += 1
2034 size = r.length(rev)
2034 size = r.length(rev)
2035 if delta == nullrev:
2035 if delta == nullrev:
2036 chainlengths.append(0)
2036 chainlengths.append(0)
2037 numfull += 1
2037 numfull += 1
2038 addsize(size, fullsize)
2038 addsize(size, fullsize)
2039 else:
2039 else:
2040 chainlengths.append(chainlengths[delta] + 1)
2040 chainlengths.append(chainlengths[delta] + 1)
2041 addsize(size, deltasize)
2041 addsize(size, deltasize)
2042 if delta == rev - 1:
2042 if delta == rev - 1:
2043 numprev += 1
2043 numprev += 1
2044 if delta == p1:
2044 if delta == p1:
2045 nump1prev += 1
2045 nump1prev += 1
2046 elif delta == p2:
2046 elif delta == p2:
2047 nump2prev += 1
2047 nump2prev += 1
2048 elif delta == p1:
2048 elif delta == p1:
2049 nump1 += 1
2049 nump1 += 1
2050 elif delta == p2:
2050 elif delta == p2:
2051 nump2 += 1
2051 nump2 += 1
2052 elif delta != nullrev:
2052 elif delta != nullrev:
2053 numother += 1
2053 numother += 1
2054
2054
2055 numdeltas = numrevs - numfull
2055 numdeltas = numrevs - numfull
2056 numoprev = numprev - nump1prev - nump2prev
2056 numoprev = numprev - nump1prev - nump2prev
2057 totalrawsize = datasize[2]
2057 totalrawsize = datasize[2]
2058 datasize[2] /= numrevs
2058 datasize[2] /= numrevs
2059 fulltotal = fullsize[2]
2059 fulltotal = fullsize[2]
2060 fullsize[2] /= numfull
2060 fullsize[2] /= numfull
2061 deltatotal = deltasize[2]
2061 deltatotal = deltasize[2]
2062 deltasize[2] /= numrevs - numfull
2062 deltasize[2] /= numrevs - numfull
2063 totalsize = fulltotal + deltatotal
2063 totalsize = fulltotal + deltatotal
2064 avgchainlen = sum(chainlengths) / numrevs
2064 avgchainlen = sum(chainlengths) / numrevs
2065 compratio = totalrawsize / totalsize
2065 compratio = totalrawsize / totalsize
2066
2066
2067 basedfmtstr = '%%%dd\n'
2067 basedfmtstr = '%%%dd\n'
2068 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2068 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2069
2069
2070 def dfmtstr(max):
2070 def dfmtstr(max):
2071 return basedfmtstr % len(str(max))
2071 return basedfmtstr % len(str(max))
2072 def pcfmtstr(max, padding=0):
2072 def pcfmtstr(max, padding=0):
2073 return basepcfmtstr % (len(str(max)), ' ' * padding)
2073 return basepcfmtstr % (len(str(max)), ' ' * padding)
2074
2074
2075 def pcfmt(value, total):
2075 def pcfmt(value, total):
2076 return (value, 100 * float(value) / total)
2076 return (value, 100 * float(value) / total)
2077
2077
2078 ui.write('format : %d\n' % format)
2078 ui.write('format : %d\n' % format)
2079 ui.write('flags : %s\n' % ', '.join(flags))
2079 ui.write('flags : %s\n' % ', '.join(flags))
2080
2080
2081 ui.write('\n')
2081 ui.write('\n')
2082 fmt = pcfmtstr(totalsize)
2082 fmt = pcfmtstr(totalsize)
2083 fmt2 = dfmtstr(totalsize)
2083 fmt2 = dfmtstr(totalsize)
2084 ui.write('revisions : ' + fmt2 % numrevs)
2084 ui.write('revisions : ' + fmt2 % numrevs)
2085 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2085 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2086 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2086 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2087 ui.write('revisions : ' + fmt2 % numrevs)
2087 ui.write('revisions : ' + fmt2 % numrevs)
2088 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2088 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2089 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2089 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2090 ui.write('revision size : ' + fmt2 % totalsize)
2090 ui.write('revision size : ' + fmt2 % totalsize)
2091 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2091 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2092 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2092 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2093
2093
2094 ui.write('\n')
2094 ui.write('\n')
2095 fmt = dfmtstr(max(avgchainlen, compratio))
2095 fmt = dfmtstr(max(avgchainlen, compratio))
2096 ui.write('avg chain length : ' + fmt % avgchainlen)
2096 ui.write('avg chain length : ' + fmt % avgchainlen)
2097 ui.write('compression ratio : ' + fmt % compratio)
2097 ui.write('compression ratio : ' + fmt % compratio)
2098
2098
2099 if format > 0:
2099 if format > 0:
2100 ui.write('\n')
2100 ui.write('\n')
2101 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2101 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2102 % tuple(datasize))
2102 % tuple(datasize))
2103 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2103 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2104 % tuple(fullsize))
2104 % tuple(fullsize))
2105 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2105 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2106 % tuple(deltasize))
2106 % tuple(deltasize))
2107
2107
2108 if numdeltas > 0:
2108 if numdeltas > 0:
2109 ui.write('\n')
2109 ui.write('\n')
2110 fmt = pcfmtstr(numdeltas)
2110 fmt = pcfmtstr(numdeltas)
2111 fmt2 = pcfmtstr(numdeltas, 4)
2111 fmt2 = pcfmtstr(numdeltas, 4)
2112 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2112 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2113 if numprev > 0:
2113 if numprev > 0:
2114 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2114 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2115 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2115 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2116 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2116 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2117 if gdelta:
2117 if gdelta:
2118 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2118 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2119 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2119 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2120 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2120 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2121
2121
2122 @command('debugrevspec', [], ('REVSPEC'))
2122 @command('debugrevspec', [], ('REVSPEC'))
2123 def debugrevspec(ui, repo, expr):
2123 def debugrevspec(ui, repo, expr):
2124 '''parse and apply a revision specification'''
2124 '''parse and apply a revision specification'''
2125 if ui.verbose:
2125 if ui.verbose:
2126 tree = revset.parse(expr)[0]
2126 tree = revset.parse(expr)[0]
2127 ui.note(tree, "\n")
2127 ui.note(tree, "\n")
2128 newtree = revset.findaliases(ui, tree)
2128 newtree = revset.findaliases(ui, tree)
2129 if newtree != tree:
2129 if newtree != tree:
2130 ui.note(newtree, "\n")
2130 ui.note(newtree, "\n")
2131 func = revset.match(ui, expr)
2131 func = revset.match(ui, expr)
2132 for c in func(repo, range(len(repo))):
2132 for c in func(repo, range(len(repo))):
2133 ui.write("%s\n" % c)
2133 ui.write("%s\n" % c)
2134
2134
2135 @command('debugsetparents', [], _('REV1 [REV2]'))
2135 @command('debugsetparents', [], _('REV1 [REV2]'))
2136 def debugsetparents(ui, repo, rev1, rev2=None):
2136 def debugsetparents(ui, repo, rev1, rev2=None):
2137 """manually set the parents of the current working directory
2137 """manually set the parents of the current working directory
2138
2138
2139 This is useful for writing repository conversion tools, but should
2139 This is useful for writing repository conversion tools, but should
2140 be used with care.
2140 be used with care.
2141
2141
2142 Returns 0 on success.
2142 Returns 0 on success.
2143 """
2143 """
2144
2144
2145 r1 = scmutil.revsingle(repo, rev1).node()
2145 r1 = scmutil.revsingle(repo, rev1).node()
2146 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2146 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2147
2147
2148 wlock = repo.wlock()
2148 wlock = repo.wlock()
2149 try:
2149 try:
2150 repo.dirstate.setparents(r1, r2)
2150 repo.dirstate.setparents(r1, r2)
2151 finally:
2151 finally:
2152 wlock.release()
2152 wlock.release()
2153
2153
2154 @command('debugstate',
2154 @command('debugstate',
2155 [('', 'nodates', None, _('do not display the saved mtime')),
2155 [('', 'nodates', None, _('do not display the saved mtime')),
2156 ('', 'datesort', None, _('sort by saved mtime'))],
2156 ('', 'datesort', None, _('sort by saved mtime'))],
2157 _('[OPTION]...'))
2157 _('[OPTION]...'))
2158 def debugstate(ui, repo, nodates=None, datesort=None):
2158 def debugstate(ui, repo, nodates=None, datesort=None):
2159 """show the contents of the current dirstate"""
2159 """show the contents of the current dirstate"""
2160 timestr = ""
2160 timestr = ""
2161 showdate = not nodates
2161 showdate = not nodates
2162 if datesort:
2162 if datesort:
2163 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2163 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2164 else:
2164 else:
2165 keyfunc = None # sort by filename
2165 keyfunc = None # sort by filename
2166 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2166 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2167 if showdate:
2167 if showdate:
2168 if ent[3] == -1:
2168 if ent[3] == -1:
2169 # Pad or slice to locale representation
2169 # Pad or slice to locale representation
2170 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2170 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2171 time.localtime(0)))
2171 time.localtime(0)))
2172 timestr = 'unset'
2172 timestr = 'unset'
2173 timestr = (timestr[:locale_len] +
2173 timestr = (timestr[:locale_len] +
2174 ' ' * (locale_len - len(timestr)))
2174 ' ' * (locale_len - len(timestr)))
2175 else:
2175 else:
2176 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2176 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2177 time.localtime(ent[3]))
2177 time.localtime(ent[3]))
2178 if ent[1] & 020000:
2178 if ent[1] & 020000:
2179 mode = 'lnk'
2179 mode = 'lnk'
2180 else:
2180 else:
2181 mode = '%3o' % (ent[1] & 0777)
2181 mode = '%3o' % (ent[1] & 0777)
2182 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2182 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2183 for f in repo.dirstate.copies():
2183 for f in repo.dirstate.copies():
2184 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2184 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2185
2185
2186 @command('debugsub',
2186 @command('debugsub',
2187 [('r', 'rev', '',
2187 [('r', 'rev', '',
2188 _('revision to check'), _('REV'))],
2188 _('revision to check'), _('REV'))],
2189 _('[-r REV] [REV]'))
2189 _('[-r REV] [REV]'))
2190 def debugsub(ui, repo, rev=None):
2190 def debugsub(ui, repo, rev=None):
2191 ctx = scmutil.revsingle(repo, rev, None)
2191 ctx = scmutil.revsingle(repo, rev, None)
2192 for k, v in sorted(ctx.substate.items()):
2192 for k, v in sorted(ctx.substate.items()):
2193 ui.write('path %s\n' % k)
2193 ui.write('path %s\n' % k)
2194 ui.write(' source %s\n' % v[0])
2194 ui.write(' source %s\n' % v[0])
2195 ui.write(' revision %s\n' % v[1])
2195 ui.write(' revision %s\n' % v[1])
2196
2196
2197 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2197 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2198 def debugwalk(ui, repo, *pats, **opts):
2198 def debugwalk(ui, repo, *pats, **opts):
2199 """show how files match on given patterns"""
2199 """show how files match on given patterns"""
2200 m = scmutil.match(repo[None], pats, opts)
2200 m = scmutil.match(repo[None], pats, opts)
2201 items = list(repo.walk(m))
2201 items = list(repo.walk(m))
2202 if not items:
2202 if not items:
2203 return
2203 return
2204 fmt = 'f %%-%ds %%-%ds %%s' % (
2204 fmt = 'f %%-%ds %%-%ds %%s' % (
2205 max([len(abs) for abs in items]),
2205 max([len(abs) for abs in items]),
2206 max([len(m.rel(abs)) for abs in items]))
2206 max([len(m.rel(abs)) for abs in items]))
2207 for abs in items:
2207 for abs in items:
2208 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2208 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2209 ui.write("%s\n" % line.rstrip())
2209 ui.write("%s\n" % line.rstrip())
2210
2210
2211 @command('debugwireargs',
2211 @command('debugwireargs',
2212 [('', 'three', '', 'three'),
2212 [('', 'three', '', 'three'),
2213 ('', 'four', '', 'four'),
2213 ('', 'four', '', 'four'),
2214 ('', 'five', '', 'five'),
2214 ('', 'five', '', 'five'),
2215 ] + remoteopts,
2215 ] + remoteopts,
2216 _('REPO [OPTIONS]... [ONE [TWO]]'))
2216 _('REPO [OPTIONS]... [ONE [TWO]]'))
2217 def debugwireargs(ui, repopath, *vals, **opts):
2217 def debugwireargs(ui, repopath, *vals, **opts):
2218 repo = hg.peer(ui, opts, repopath)
2218 repo = hg.peer(ui, opts, repopath)
2219 for opt in remoteopts:
2219 for opt in remoteopts:
2220 del opts[opt[1]]
2220 del opts[opt[1]]
2221 args = {}
2221 args = {}
2222 for k, v in opts.iteritems():
2222 for k, v in opts.iteritems():
2223 if v:
2223 if v:
2224 args[k] = v
2224 args[k] = v
2225 # run twice to check that we don't mess up the stream for the next command
2225 # run twice to check that we don't mess up the stream for the next command
2226 res1 = repo.debugwireargs(*vals, **args)
2226 res1 = repo.debugwireargs(*vals, **args)
2227 res2 = repo.debugwireargs(*vals, **args)
2227 res2 = repo.debugwireargs(*vals, **args)
2228 ui.write("%s\n" % res1)
2228 ui.write("%s\n" % res1)
2229 if res1 != res2:
2229 if res1 != res2:
2230 ui.warn("%s\n" % res2)
2230 ui.warn("%s\n" % res2)
2231
2231
2232 @command('^diff',
2232 @command('^diff',
2233 [('r', 'rev', [], _('revision'), _('REV')),
2233 [('r', 'rev', [], _('revision'), _('REV')),
2234 ('c', 'change', '', _('change made by revision'), _('REV'))
2234 ('c', 'change', '', _('change made by revision'), _('REV'))
2235 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2235 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2236 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2236 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2237 def diff(ui, repo, *pats, **opts):
2237 def diff(ui, repo, *pats, **opts):
2238 """diff repository (or selected files)
2238 """diff repository (or selected files)
2239
2239
2240 Show differences between revisions for the specified files.
2240 Show differences between revisions for the specified files.
2241
2241
2242 Differences between files are shown using the unified diff format.
2242 Differences between files are shown using the unified diff format.
2243
2243
2244 .. note::
2244 .. note::
2245 diff may generate unexpected results for merges, as it will
2245 diff may generate unexpected results for merges, as it will
2246 default to comparing against the working directory's first
2246 default to comparing against the working directory's first
2247 parent changeset if no revisions are specified.
2247 parent changeset if no revisions are specified.
2248
2248
2249 When two revision arguments are given, then changes are shown
2249 When two revision arguments are given, then changes are shown
2250 between those revisions. If only one revision is specified then
2250 between those revisions. If only one revision is specified then
2251 that revision is compared to the working directory, and, when no
2251 that revision is compared to the working directory, and, when no
2252 revisions are specified, the working directory files are compared
2252 revisions are specified, the working directory files are compared
2253 to its parent.
2253 to its parent.
2254
2254
2255 Alternatively you can specify -c/--change with a revision to see
2255 Alternatively you can specify -c/--change with a revision to see
2256 the changes in that changeset relative to its first parent.
2256 the changes in that changeset relative to its first parent.
2257
2257
2258 Without the -a/--text option, diff will avoid generating diffs of
2258 Without the -a/--text option, diff will avoid generating diffs of
2259 files it detects as binary. With -a, diff will generate a diff
2259 files it detects as binary. With -a, diff will generate a diff
2260 anyway, probably with undesirable results.
2260 anyway, probably with undesirable results.
2261
2261
2262 Use the -g/--git option to generate diffs in the git extended diff
2262 Use the -g/--git option to generate diffs in the git extended diff
2263 format. For more information, read :hg:`help diffs`.
2263 format. For more information, read :hg:`help diffs`.
2264
2264
2265 .. container:: verbose
2265 .. container:: verbose
2266
2266
2267 Examples:
2267 Examples:
2268
2268
2269 - compare a file in the current working directory to its parent::
2269 - compare a file in the current working directory to its parent::
2270
2270
2271 hg diff foo.c
2271 hg diff foo.c
2272
2272
2273 - compare two historical versions of a directory, with rename info::
2273 - compare two historical versions of a directory, with rename info::
2274
2274
2275 hg diff --git -r 1.0:1.2 lib/
2275 hg diff --git -r 1.0:1.2 lib/
2276
2276
2277 - get change stats relative to the last change on some date::
2277 - get change stats relative to the last change on some date::
2278
2278
2279 hg diff --stat -r "date('may 2')"
2279 hg diff --stat -r "date('may 2')"
2280
2280
2281 - diff all newly-added files that contain a keyword::
2281 - diff all newly-added files that contain a keyword::
2282
2282
2283 hg diff "set:added() and grep(GNU)"
2283 hg diff "set:added() and grep(GNU)"
2284
2284
2285 - compare a revision and its parents::
2285 - compare a revision and its parents::
2286
2286
2287 hg diff -c 9353 # compare against first parent
2287 hg diff -c 9353 # compare against first parent
2288 hg diff -r 9353^:9353 # same using revset syntax
2288 hg diff -r 9353^:9353 # same using revset syntax
2289 hg diff -r 9353^2:9353 # compare against the second parent
2289 hg diff -r 9353^2:9353 # compare against the second parent
2290
2290
2291 Returns 0 on success.
2291 Returns 0 on success.
2292 """
2292 """
2293
2293
2294 revs = opts.get('rev')
2294 revs = opts.get('rev')
2295 change = opts.get('change')
2295 change = opts.get('change')
2296 stat = opts.get('stat')
2296 stat = opts.get('stat')
2297 reverse = opts.get('reverse')
2297 reverse = opts.get('reverse')
2298
2298
2299 if revs and change:
2299 if revs and change:
2300 msg = _('cannot specify --rev and --change at the same time')
2300 msg = _('cannot specify --rev and --change at the same time')
2301 raise util.Abort(msg)
2301 raise util.Abort(msg)
2302 elif change:
2302 elif change:
2303 node2 = scmutil.revsingle(repo, change, None).node()
2303 node2 = scmutil.revsingle(repo, change, None).node()
2304 node1 = repo[node2].p1().node()
2304 node1 = repo[node2].p1().node()
2305 else:
2305 else:
2306 node1, node2 = scmutil.revpair(repo, revs)
2306 node1, node2 = scmutil.revpair(repo, revs)
2307
2307
2308 if reverse:
2308 if reverse:
2309 node1, node2 = node2, node1
2309 node1, node2 = node2, node1
2310
2310
2311 diffopts = patch.diffopts(ui, opts)
2311 diffopts = patch.diffopts(ui, opts)
2312 m = scmutil.match(repo[node2], pats, opts)
2312 m = scmutil.match(repo[node2], pats, opts)
2313 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2313 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2314 listsubrepos=opts.get('subrepos'))
2314 listsubrepos=opts.get('subrepos'))
2315
2315
2316 @command('^export',
2316 @command('^export',
2317 [('o', 'output', '',
2317 [('o', 'output', '',
2318 _('print output to file with formatted name'), _('FORMAT')),
2318 _('print output to file with formatted name'), _('FORMAT')),
2319 ('', 'switch-parent', None, _('diff against the second parent')),
2319 ('', 'switch-parent', None, _('diff against the second parent')),
2320 ('r', 'rev', [], _('revisions to export'), _('REV')),
2320 ('r', 'rev', [], _('revisions to export'), _('REV')),
2321 ] + diffopts,
2321 ] + diffopts,
2322 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2322 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2323 def export(ui, repo, *changesets, **opts):
2323 def export(ui, repo, *changesets, **opts):
2324 """dump the header and diffs for one or more changesets
2324 """dump the header and diffs for one or more changesets
2325
2325
2326 Print the changeset header and diffs for one or more revisions.
2326 Print the changeset header and diffs for one or more revisions.
2327
2327
2328 The information shown in the changeset header is: author, date,
2328 The information shown in the changeset header is: author, date,
2329 branch name (if non-default), changeset hash, parent(s) and commit
2329 branch name (if non-default), changeset hash, parent(s) and commit
2330 comment.
2330 comment.
2331
2331
2332 .. note::
2332 .. note::
2333 export may generate unexpected diff output for merge
2333 export may generate unexpected diff output for merge
2334 changesets, as it will compare the merge changeset against its
2334 changesets, as it will compare the merge changeset against its
2335 first parent only.
2335 first parent only.
2336
2336
2337 Output may be to a file, in which case the name of the file is
2337 Output may be to a file, in which case the name of the file is
2338 given using a format string. The formatting rules are as follows:
2338 given using a format string. The formatting rules are as follows:
2339
2339
2340 :``%%``: literal "%" character
2340 :``%%``: literal "%" character
2341 :``%H``: changeset hash (40 hexadecimal digits)
2341 :``%H``: changeset hash (40 hexadecimal digits)
2342 :``%N``: number of patches being generated
2342 :``%N``: number of patches being generated
2343 :``%R``: changeset revision number
2343 :``%R``: changeset revision number
2344 :``%b``: basename of the exporting repository
2344 :``%b``: basename of the exporting repository
2345 :``%h``: short-form changeset hash (12 hexadecimal digits)
2345 :``%h``: short-form changeset hash (12 hexadecimal digits)
2346 :``%m``: first line of the commit message (only alphanumeric characters)
2346 :``%m``: first line of the commit message (only alphanumeric characters)
2347 :``%n``: zero-padded sequence number, starting at 1
2347 :``%n``: zero-padded sequence number, starting at 1
2348 :``%r``: zero-padded changeset revision number
2348 :``%r``: zero-padded changeset revision number
2349
2349
2350 Without the -a/--text option, export will avoid generating diffs
2350 Without the -a/--text option, export will avoid generating diffs
2351 of files it detects as binary. With -a, export will generate a
2351 of files it detects as binary. With -a, export will generate a
2352 diff anyway, probably with undesirable results.
2352 diff anyway, probably with undesirable results.
2353
2353
2354 Use the -g/--git option to generate diffs in the git extended diff
2354 Use the -g/--git option to generate diffs in the git extended diff
2355 format. See :hg:`help diffs` for more information.
2355 format. See :hg:`help diffs` for more information.
2356
2356
2357 With the --switch-parent option, the diff will be against the
2357 With the --switch-parent option, the diff will be against the
2358 second parent. It can be useful to review a merge.
2358 second parent. It can be useful to review a merge.
2359
2359
2360 .. container:: verbose
2360 .. container:: verbose
2361
2361
2362 Examples:
2362 Examples:
2363
2363
2364 - use export and import to transplant a bugfix to the current
2364 - use export and import to transplant a bugfix to the current
2365 branch::
2365 branch::
2366
2366
2367 hg export -r 9353 | hg import -
2367 hg export -r 9353 | hg import -
2368
2368
2369 - export all the changesets between two revisions to a file with
2369 - export all the changesets between two revisions to a file with
2370 rename information::
2370 rename information::
2371
2371
2372 hg export --git -r 123:150 > changes.txt
2372 hg export --git -r 123:150 > changes.txt
2373
2373
2374 - split outgoing changes into a series of patches with
2374 - split outgoing changes into a series of patches with
2375 descriptive names::
2375 descriptive names::
2376
2376
2377 hg export -r "outgoing()" -o "%n-%m.patch"
2377 hg export -r "outgoing()" -o "%n-%m.patch"
2378
2378
2379 Returns 0 on success.
2379 Returns 0 on success.
2380 """
2380 """
2381 changesets += tuple(opts.get('rev', []))
2381 changesets += tuple(opts.get('rev', []))
2382 if not changesets:
2382 if not changesets:
2383 raise util.Abort(_("export requires at least one changeset"))
2383 raise util.Abort(_("export requires at least one changeset"))
2384 revs = scmutil.revrange(repo, changesets)
2384 revs = scmutil.revrange(repo, changesets)
2385 if len(revs) > 1:
2385 if len(revs) > 1:
2386 ui.note(_('exporting patches:\n'))
2386 ui.note(_('exporting patches:\n'))
2387 else:
2387 else:
2388 ui.note(_('exporting patch:\n'))
2388 ui.note(_('exporting patch:\n'))
2389 cmdutil.export(repo, revs, template=opts.get('output'),
2389 cmdutil.export(repo, revs, template=opts.get('output'),
2390 switch_parent=opts.get('switch_parent'),
2390 switch_parent=opts.get('switch_parent'),
2391 opts=patch.diffopts(ui, opts))
2391 opts=patch.diffopts(ui, opts))
2392
2392
2393 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2393 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2394 def forget(ui, repo, *pats, **opts):
2394 def forget(ui, repo, *pats, **opts):
2395 """forget the specified files on the next commit
2395 """forget the specified files on the next commit
2396
2396
2397 Mark the specified files so they will no longer be tracked
2397 Mark the specified files so they will no longer be tracked
2398 after the next commit.
2398 after the next commit.
2399
2399
2400 This only removes files from the current branch, not from the
2400 This only removes files from the current branch, not from the
2401 entire project history, and it does not delete them from the
2401 entire project history, and it does not delete them from the
2402 working directory.
2402 working directory.
2403
2403
2404 To undo a forget before the next commit, see :hg:`add`.
2404 To undo a forget before the next commit, see :hg:`add`.
2405
2405
2406 .. container:: verbose
2406 .. container:: verbose
2407
2407
2408 Examples:
2408 Examples:
2409
2409
2410 - forget newly-added binary files::
2410 - forget newly-added binary files::
2411
2411
2412 hg forget "set:added() and binary()"
2412 hg forget "set:added() and binary()"
2413
2413
2414 - forget files that would be excluded by .hgignore::
2414 - forget files that would be excluded by .hgignore::
2415
2415
2416 hg forget "set:hgignore()"
2416 hg forget "set:hgignore()"
2417
2417
2418 Returns 0 on success.
2418 Returns 0 on success.
2419 """
2419 """
2420
2420
2421 if not pats:
2421 if not pats:
2422 raise util.Abort(_('no files specified'))
2422 raise util.Abort(_('no files specified'))
2423
2423
2424 m = scmutil.match(repo[None], pats, opts)
2424 m = scmutil.match(repo[None], pats, opts)
2425 s = repo.status(match=m, clean=True)
2425 s = repo.status(match=m, clean=True)
2426 forget = sorted(s[0] + s[1] + s[3] + s[6])
2426 forget = sorted(s[0] + s[1] + s[3] + s[6])
2427 errs = 0
2427 errs = 0
2428
2428
2429 for f in m.files():
2429 for f in m.files():
2430 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2430 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2431 if os.path.exists(m.rel(f)):
2431 if os.path.exists(m.rel(f)):
2432 ui.warn(_('not removing %s: file is already untracked\n')
2432 ui.warn(_('not removing %s: file is already untracked\n')
2433 % m.rel(f))
2433 % m.rel(f))
2434 errs = 1
2434 errs = 1
2435
2435
2436 for f in forget:
2436 for f in forget:
2437 if ui.verbose or not m.exact(f):
2437 if ui.verbose or not m.exact(f):
2438 ui.status(_('removing %s\n') % m.rel(f))
2438 ui.status(_('removing %s\n') % m.rel(f))
2439
2439
2440 repo[None].forget(forget)
2440 repo[None].forget(forget)
2441 return errs
2441 return errs
2442
2442
2443 @command('grep',
2443 @command('grep',
2444 [('0', 'print0', None, _('end fields with NUL')),
2444 [('0', 'print0', None, _('end fields with NUL')),
2445 ('', 'all', None, _('print all revisions that match')),
2445 ('', 'all', None, _('print all revisions that match')),
2446 ('a', 'text', None, _('treat all files as text')),
2446 ('a', 'text', None, _('treat all files as text')),
2447 ('f', 'follow', None,
2447 ('f', 'follow', None,
2448 _('follow changeset history,'
2448 _('follow changeset history,'
2449 ' or file history across copies and renames')),
2449 ' or file history across copies and renames')),
2450 ('i', 'ignore-case', None, _('ignore case when matching')),
2450 ('i', 'ignore-case', None, _('ignore case when matching')),
2451 ('l', 'files-with-matches', None,
2451 ('l', 'files-with-matches', None,
2452 _('print only filenames and revisions that match')),
2452 _('print only filenames and revisions that match')),
2453 ('n', 'line-number', None, _('print matching line numbers')),
2453 ('n', 'line-number', None, _('print matching line numbers')),
2454 ('r', 'rev', [],
2454 ('r', 'rev', [],
2455 _('only search files changed within revision range'), _('REV')),
2455 _('only search files changed within revision range'), _('REV')),
2456 ('u', 'user', None, _('list the author (long with -v)')),
2456 ('u', 'user', None, _('list the author (long with -v)')),
2457 ('d', 'date', None, _('list the date (short with -q)')),
2457 ('d', 'date', None, _('list the date (short with -q)')),
2458 ] + walkopts,
2458 ] + walkopts,
2459 _('[OPTION]... PATTERN [FILE]...'))
2459 _('[OPTION]... PATTERN [FILE]...'))
2460 def grep(ui, repo, pattern, *pats, **opts):
2460 def grep(ui, repo, pattern, *pats, **opts):
2461 """search for a pattern in specified files and revisions
2461 """search for a pattern in specified files and revisions
2462
2462
2463 Search revisions of files for a regular expression.
2463 Search revisions of files for a regular expression.
2464
2464
2465 This command behaves differently than Unix grep. It only accepts
2465 This command behaves differently than Unix grep. It only accepts
2466 Python/Perl regexps. It searches repository history, not the
2466 Python/Perl regexps. It searches repository history, not the
2467 working directory. It always prints the revision number in which a
2467 working directory. It always prints the revision number in which a
2468 match appears.
2468 match appears.
2469
2469
2470 By default, grep only prints output for the first revision of a
2470 By default, grep only prints output for the first revision of a
2471 file in which it finds a match. To get it to print every revision
2471 file in which it finds a match. To get it to print every revision
2472 that contains a change in match status ("-" for a match that
2472 that contains a change in match status ("-" for a match that
2473 becomes a non-match, or "+" for a non-match that becomes a match),
2473 becomes a non-match, or "+" for a non-match that becomes a match),
2474 use the --all flag.
2474 use the --all flag.
2475
2475
2476 Returns 0 if a match is found, 1 otherwise.
2476 Returns 0 if a match is found, 1 otherwise.
2477 """
2477 """
2478 reflags = 0
2478 reflags = 0
2479 if opts.get('ignore_case'):
2479 if opts.get('ignore_case'):
2480 reflags |= re.I
2480 reflags |= re.I
2481 try:
2481 try:
2482 regexp = re.compile(pattern, reflags)
2482 regexp = re.compile(pattern, reflags)
2483 except re.error, inst:
2483 except re.error, inst:
2484 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2484 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2485 return 1
2485 return 1
2486 sep, eol = ':', '\n'
2486 sep, eol = ':', '\n'
2487 if opts.get('print0'):
2487 if opts.get('print0'):
2488 sep = eol = '\0'
2488 sep = eol = '\0'
2489
2489
2490 getfile = util.lrucachefunc(repo.file)
2490 getfile = util.lrucachefunc(repo.file)
2491
2491
2492 def matchlines(body):
2492 def matchlines(body):
2493 begin = 0
2493 begin = 0
2494 linenum = 0
2494 linenum = 0
2495 while True:
2495 while True:
2496 match = regexp.search(body, begin)
2496 match = regexp.search(body, begin)
2497 if not match:
2497 if not match:
2498 break
2498 break
2499 mstart, mend = match.span()
2499 mstart, mend = match.span()
2500 linenum += body.count('\n', begin, mstart) + 1
2500 linenum += body.count('\n', begin, mstart) + 1
2501 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2501 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2502 begin = body.find('\n', mend) + 1 or len(body)
2502 begin = body.find('\n', mend) + 1 or len(body)
2503 lend = begin - 1
2503 lend = begin - 1
2504 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2504 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2505
2505
2506 class linestate(object):
2506 class linestate(object):
2507 def __init__(self, line, linenum, colstart, colend):
2507 def __init__(self, line, linenum, colstart, colend):
2508 self.line = line
2508 self.line = line
2509 self.linenum = linenum
2509 self.linenum = linenum
2510 self.colstart = colstart
2510 self.colstart = colstart
2511 self.colend = colend
2511 self.colend = colend
2512
2512
2513 def __hash__(self):
2513 def __hash__(self):
2514 return hash((self.linenum, self.line))
2514 return hash((self.linenum, self.line))
2515
2515
2516 def __eq__(self, other):
2516 def __eq__(self, other):
2517 return self.line == other.line
2517 return self.line == other.line
2518
2518
2519 matches = {}
2519 matches = {}
2520 copies = {}
2520 copies = {}
2521 def grepbody(fn, rev, body):
2521 def grepbody(fn, rev, body):
2522 matches[rev].setdefault(fn, [])
2522 matches[rev].setdefault(fn, [])
2523 m = matches[rev][fn]
2523 m = matches[rev][fn]
2524 for lnum, cstart, cend, line in matchlines(body):
2524 for lnum, cstart, cend, line in matchlines(body):
2525 s = linestate(line, lnum, cstart, cend)
2525 s = linestate(line, lnum, cstart, cend)
2526 m.append(s)
2526 m.append(s)
2527
2527
2528 def difflinestates(a, b):
2528 def difflinestates(a, b):
2529 sm = difflib.SequenceMatcher(None, a, b)
2529 sm = difflib.SequenceMatcher(None, a, b)
2530 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2530 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2531 if tag == 'insert':
2531 if tag == 'insert':
2532 for i in xrange(blo, bhi):
2532 for i in xrange(blo, bhi):
2533 yield ('+', b[i])
2533 yield ('+', b[i])
2534 elif tag == 'delete':
2534 elif tag == 'delete':
2535 for i in xrange(alo, ahi):
2535 for i in xrange(alo, ahi):
2536 yield ('-', a[i])
2536 yield ('-', a[i])
2537 elif tag == 'replace':
2537 elif tag == 'replace':
2538 for i in xrange(alo, ahi):
2538 for i in xrange(alo, ahi):
2539 yield ('-', a[i])
2539 yield ('-', a[i])
2540 for i in xrange(blo, bhi):
2540 for i in xrange(blo, bhi):
2541 yield ('+', b[i])
2541 yield ('+', b[i])
2542
2542
2543 def display(fn, ctx, pstates, states):
2543 def display(fn, ctx, pstates, states):
2544 rev = ctx.rev()
2544 rev = ctx.rev()
2545 datefunc = ui.quiet and util.shortdate or util.datestr
2545 datefunc = ui.quiet and util.shortdate or util.datestr
2546 found = False
2546 found = False
2547 filerevmatches = {}
2547 filerevmatches = {}
2548 def binary():
2548 def binary():
2549 flog = getfile(fn)
2549 flog = getfile(fn)
2550 return util.binary(flog.read(ctx.filenode(fn)))
2550 return util.binary(flog.read(ctx.filenode(fn)))
2551
2551
2552 if opts.get('all'):
2552 if opts.get('all'):
2553 iter = difflinestates(pstates, states)
2553 iter = difflinestates(pstates, states)
2554 else:
2554 else:
2555 iter = [('', l) for l in states]
2555 iter = [('', l) for l in states]
2556 for change, l in iter:
2556 for change, l in iter:
2557 cols = [fn, str(rev)]
2557 cols = [fn, str(rev)]
2558 before, match, after = None, None, None
2558 before, match, after = None, None, None
2559 if opts.get('line_number'):
2559 if opts.get('line_number'):
2560 cols.append(str(l.linenum))
2560 cols.append(str(l.linenum))
2561 if opts.get('all'):
2561 if opts.get('all'):
2562 cols.append(change)
2562 cols.append(change)
2563 if opts.get('user'):
2563 if opts.get('user'):
2564 cols.append(ui.shortuser(ctx.user()))
2564 cols.append(ui.shortuser(ctx.user()))
2565 if opts.get('date'):
2565 if opts.get('date'):
2566 cols.append(datefunc(ctx.date()))
2566 cols.append(datefunc(ctx.date()))
2567 if opts.get('files_with_matches'):
2567 if opts.get('files_with_matches'):
2568 c = (fn, rev)
2568 c = (fn, rev)
2569 if c in filerevmatches:
2569 if c in filerevmatches:
2570 continue
2570 continue
2571 filerevmatches[c] = 1
2571 filerevmatches[c] = 1
2572 else:
2572 else:
2573 before = l.line[:l.colstart]
2573 before = l.line[:l.colstart]
2574 match = l.line[l.colstart:l.colend]
2574 match = l.line[l.colstart:l.colend]
2575 after = l.line[l.colend:]
2575 after = l.line[l.colend:]
2576 ui.write(sep.join(cols))
2576 ui.write(sep.join(cols))
2577 if before is not None:
2577 if before is not None:
2578 if not opts.get('text') and binary():
2578 if not opts.get('text') and binary():
2579 ui.write(sep + " Binary file matches")
2579 ui.write(sep + " Binary file matches")
2580 else:
2580 else:
2581 ui.write(sep + before)
2581 ui.write(sep + before)
2582 ui.write(match, label='grep.match')
2582 ui.write(match, label='grep.match')
2583 ui.write(after)
2583 ui.write(after)
2584 ui.write(eol)
2584 ui.write(eol)
2585 found = True
2585 found = True
2586 return found
2586 return found
2587
2587
2588 skip = {}
2588 skip = {}
2589 revfiles = {}
2589 revfiles = {}
2590 matchfn = scmutil.match(repo[None], pats, opts)
2590 matchfn = scmutil.match(repo[None], pats, opts)
2591 found = False
2591 found = False
2592 follow = opts.get('follow')
2592 follow = opts.get('follow')
2593
2593
2594 def prep(ctx, fns):
2594 def prep(ctx, fns):
2595 rev = ctx.rev()
2595 rev = ctx.rev()
2596 pctx = ctx.p1()
2596 pctx = ctx.p1()
2597 parent = pctx.rev()
2597 parent = pctx.rev()
2598 matches.setdefault(rev, {})
2598 matches.setdefault(rev, {})
2599 matches.setdefault(parent, {})
2599 matches.setdefault(parent, {})
2600 files = revfiles.setdefault(rev, [])
2600 files = revfiles.setdefault(rev, [])
2601 for fn in fns:
2601 for fn in fns:
2602 flog = getfile(fn)
2602 flog = getfile(fn)
2603 try:
2603 try:
2604 fnode = ctx.filenode(fn)
2604 fnode = ctx.filenode(fn)
2605 except error.LookupError:
2605 except error.LookupError:
2606 continue
2606 continue
2607
2607
2608 copied = flog.renamed(fnode)
2608 copied = flog.renamed(fnode)
2609 copy = follow and copied and copied[0]
2609 copy = follow and copied and copied[0]
2610 if copy:
2610 if copy:
2611 copies.setdefault(rev, {})[fn] = copy
2611 copies.setdefault(rev, {})[fn] = copy
2612 if fn in skip:
2612 if fn in skip:
2613 if copy:
2613 if copy:
2614 skip[copy] = True
2614 skip[copy] = True
2615 continue
2615 continue
2616 files.append(fn)
2616 files.append(fn)
2617
2617
2618 if fn not in matches[rev]:
2618 if fn not in matches[rev]:
2619 grepbody(fn, rev, flog.read(fnode))
2619 grepbody(fn, rev, flog.read(fnode))
2620
2620
2621 pfn = copy or fn
2621 pfn = copy or fn
2622 if pfn not in matches[parent]:
2622 if pfn not in matches[parent]:
2623 try:
2623 try:
2624 fnode = pctx.filenode(pfn)
2624 fnode = pctx.filenode(pfn)
2625 grepbody(pfn, parent, flog.read(fnode))
2625 grepbody(pfn, parent, flog.read(fnode))
2626 except error.LookupError:
2626 except error.LookupError:
2627 pass
2627 pass
2628
2628
2629 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2629 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2630 rev = ctx.rev()
2630 rev = ctx.rev()
2631 parent = ctx.p1().rev()
2631 parent = ctx.p1().rev()
2632 for fn in sorted(revfiles.get(rev, [])):
2632 for fn in sorted(revfiles.get(rev, [])):
2633 states = matches[rev][fn]
2633 states = matches[rev][fn]
2634 copy = copies.get(rev, {}).get(fn)
2634 copy = copies.get(rev, {}).get(fn)
2635 if fn in skip:
2635 if fn in skip:
2636 if copy:
2636 if copy:
2637 skip[copy] = True
2637 skip[copy] = True
2638 continue
2638 continue
2639 pstates = matches.get(parent, {}).get(copy or fn, [])
2639 pstates = matches.get(parent, {}).get(copy or fn, [])
2640 if pstates or states:
2640 if pstates or states:
2641 r = display(fn, ctx, pstates, states)
2641 r = display(fn, ctx, pstates, states)
2642 found = found or r
2642 found = found or r
2643 if r and not opts.get('all'):
2643 if r and not opts.get('all'):
2644 skip[fn] = True
2644 skip[fn] = True
2645 if copy:
2645 if copy:
2646 skip[copy] = True
2646 skip[copy] = True
2647 del matches[rev]
2647 del matches[rev]
2648 del revfiles[rev]
2648 del revfiles[rev]
2649
2649
2650 return not found
2650 return not found
2651
2651
2652 @command('heads',
2652 @command('heads',
2653 [('r', 'rev', '',
2653 [('r', 'rev', '',
2654 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2654 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2655 ('t', 'topo', False, _('show topological heads only')),
2655 ('t', 'topo', False, _('show topological heads only')),
2656 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2656 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2657 ('c', 'closed', False, _('show normal and closed branch heads')),
2657 ('c', 'closed', False, _('show normal and closed branch heads')),
2658 ] + templateopts,
2658 ] + templateopts,
2659 _('[-ac] [-r STARTREV] [REV]...'))
2659 _('[-ac] [-r STARTREV] [REV]...'))
2660 def heads(ui, repo, *branchrevs, **opts):
2660 def heads(ui, repo, *branchrevs, **opts):
2661 """show current repository heads or show branch heads
2661 """show current repository heads or show branch heads
2662
2662
2663 With no arguments, show all repository branch heads.
2663 With no arguments, show all repository branch heads.
2664
2664
2665 Repository "heads" are changesets with no child changesets. They are
2665 Repository "heads" are changesets with no child changesets. They are
2666 where development generally takes place and are the usual targets
2666 where development generally takes place and are the usual targets
2667 for update and merge operations. Branch heads are changesets that have
2667 for update and merge operations. Branch heads are changesets that have
2668 no child changeset on the same branch.
2668 no child changeset on the same branch.
2669
2669
2670 If one or more REVs are given, only branch heads on the branches
2670 If one or more REVs are given, only branch heads on the branches
2671 associated with the specified changesets are shown. This means
2671 associated with the specified changesets are shown. This means
2672 that you can use :hg:`heads foo` to see the heads on a branch
2672 that you can use :hg:`heads foo` to see the heads on a branch
2673 named ``foo``.
2673 named ``foo``.
2674
2674
2675 If -c/--closed is specified, also show branch heads marked closed
2675 If -c/--closed is specified, also show branch heads marked closed
2676 (see :hg:`commit --close-branch`).
2676 (see :hg:`commit --close-branch`).
2677
2677
2678 If STARTREV is specified, only those heads that are descendants of
2678 If STARTREV is specified, only those heads that are descendants of
2679 STARTREV will be displayed.
2679 STARTREV will be displayed.
2680
2680
2681 If -t/--topo is specified, named branch mechanics will be ignored and only
2681 If -t/--topo is specified, named branch mechanics will be ignored and only
2682 changesets without children will be shown.
2682 changesets without children will be shown.
2683
2683
2684 Returns 0 if matching heads are found, 1 if not.
2684 Returns 0 if matching heads are found, 1 if not.
2685 """
2685 """
2686
2686
2687 start = None
2687 start = None
2688 if 'rev' in opts:
2688 if 'rev' in opts:
2689 start = scmutil.revsingle(repo, opts['rev'], None).node()
2689 start = scmutil.revsingle(repo, opts['rev'], None).node()
2690
2690
2691 if opts.get('topo'):
2691 if opts.get('topo'):
2692 heads = [repo[h] for h in repo.heads(start)]
2692 heads = [repo[h] for h in repo.heads(start)]
2693 else:
2693 else:
2694 heads = []
2694 heads = []
2695 for branch in repo.branchmap():
2695 for branch in repo.branchmap():
2696 heads += repo.branchheads(branch, start, opts.get('closed'))
2696 heads += repo.branchheads(branch, start, opts.get('closed'))
2697 heads = [repo[h] for h in heads]
2697 heads = [repo[h] for h in heads]
2698
2698
2699 if branchrevs:
2699 if branchrevs:
2700 branches = set(repo[br].branch() for br in branchrevs)
2700 branches = set(repo[br].branch() for br in branchrevs)
2701 heads = [h for h in heads if h.branch() in branches]
2701 heads = [h for h in heads if h.branch() in branches]
2702
2702
2703 if opts.get('active') and branchrevs:
2703 if opts.get('active') and branchrevs:
2704 dagheads = repo.heads(start)
2704 dagheads = repo.heads(start)
2705 heads = [h for h in heads if h.node() in dagheads]
2705 heads = [h for h in heads if h.node() in dagheads]
2706
2706
2707 if branchrevs:
2707 if branchrevs:
2708 haveheads = set(h.branch() for h in heads)
2708 haveheads = set(h.branch() for h in heads)
2709 if branches - haveheads:
2709 if branches - haveheads:
2710 headless = ', '.join(b for b in branches - haveheads)
2710 headless = ', '.join(b for b in branches - haveheads)
2711 msg = _('no open branch heads found on branches %s')
2711 msg = _('no open branch heads found on branches %s')
2712 if opts.get('rev'):
2712 if opts.get('rev'):
2713 msg += _(' (started at %s)' % opts['rev'])
2713 msg += _(' (started at %s)' % opts['rev'])
2714 ui.warn((msg + '\n') % headless)
2714 ui.warn((msg + '\n') % headless)
2715
2715
2716 if not heads:
2716 if not heads:
2717 return 1
2717 return 1
2718
2718
2719 heads = sorted(heads, key=lambda x: -x.rev())
2719 heads = sorted(heads, key=lambda x: -x.rev())
2720 displayer = cmdutil.show_changeset(ui, repo, opts)
2720 displayer = cmdutil.show_changeset(ui, repo, opts)
2721 for ctx in heads:
2721 for ctx in heads:
2722 displayer.show(ctx)
2722 displayer.show(ctx)
2723 displayer.close()
2723 displayer.close()
2724
2724
2725 @command('help',
2725 @command('help',
2726 [('e', 'extension', None, _('show only help for extensions')),
2726 [('e', 'extension', None, _('show only help for extensions')),
2727 ('c', 'command', None, _('show only help for commands'))],
2727 ('c', 'command', None, _('show only help for commands'))],
2728 _('[-ec] [TOPIC]'))
2728 _('[-ec] [TOPIC]'))
2729 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2729 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2730 """show help for a given topic or a help overview
2730 """show help for a given topic or a help overview
2731
2731
2732 With no arguments, print a list of commands with short help messages.
2732 With no arguments, print a list of commands with short help messages.
2733
2733
2734 Given a topic, extension, or command name, print help for that
2734 Given a topic, extension, or command name, print help for that
2735 topic.
2735 topic.
2736
2736
2737 Returns 0 if successful.
2737 Returns 0 if successful.
2738 """
2738 """
2739
2739
2740 textwidth = min(ui.termwidth(), 80) - 2
2740 textwidth = min(ui.termwidth(), 80) - 2
2741
2741
2742 def optrst(options):
2742 def optrst(options):
2743 data = []
2743 data = []
2744 multioccur = False
2744 multioccur = False
2745 for option in options:
2745 for option in options:
2746 if len(option) == 5:
2746 if len(option) == 5:
2747 shortopt, longopt, default, desc, optlabel = option
2747 shortopt, longopt, default, desc, optlabel = option
2748 else:
2748 else:
2749 shortopt, longopt, default, desc = option
2749 shortopt, longopt, default, desc = option
2750 optlabel = _("VALUE") # default label
2750 optlabel = _("VALUE") # default label
2751
2751
2752 if _("DEPRECATED") in desc and not ui.verbose:
2752 if _("DEPRECATED") in desc and not ui.verbose:
2753 continue
2753 continue
2754
2754
2755 so = ''
2755 so = ''
2756 if shortopt:
2756 if shortopt:
2757 so = '-' + shortopt
2757 so = '-' + shortopt
2758 lo = '--' + longopt
2758 lo = '--' + longopt
2759 if default:
2759 if default:
2760 desc += _(" (default: %s)") % default
2760 desc += _(" (default: %s)") % default
2761
2761
2762 if isinstance(default, list):
2762 if isinstance(default, list):
2763 lo += " %s [+]" % optlabel
2763 lo += " %s [+]" % optlabel
2764 multioccur = True
2764 multioccur = True
2765 elif (default is not None) and not isinstance(default, bool):
2765 elif (default is not None) and not isinstance(default, bool):
2766 lo += " %s" % optlabel
2766 lo += " %s" % optlabel
2767
2767
2768 data.append((so, lo, desc))
2768 data.append((so, lo, desc))
2769
2769
2770 rst = minirst.maketable(data, 1)
2770 rst = minirst.maketable(data, 1)
2771
2771 if multioccur:
2772 if multioccur:
2772 rst += _("\n[+] marked option can be specified multiple times")
2773 rst += _("\n[+] marked option can be specified multiple times")
2773
2774
2774 return rst
2775 return rst
2775
2776
2776 # list all option lists
2777 # list all option lists
2777 def opttext(optlist, width):
2778 def opttext(optlist, width):
2778 rst = ''
2779 rst = ''
2779 if not optlist:
2780 if not optlist:
2780 return ''
2781 return ''
2781
2782
2782 for title, options in optlist:
2783 for title, options in optlist:
2783 rst += '\n%s\n\n' % title
2784 rst += '\n%s\n\n' % title
2784 rst += optrst(options)
2785 rst += optrst(options)
2785 rst += '\n'
2786 rst += '\n'
2786
2787
2787 return '\n' + minirst.format(rst, width)
2788 return '\n' + minirst.format(rst, width)
2788
2789
2789 def addglobalopts(optlist, aliases):
2790 def addglobalopts(optlist, aliases):
2790 if ui.quiet:
2791 if ui.quiet:
2791 return []
2792 return []
2792
2793
2793 if ui.verbose:
2794 if ui.verbose:
2794 optlist.append((_("global options:"), globalopts))
2795 optlist.append((_("global options:"), globalopts))
2795 if name == 'shortlist':
2796 if name == 'shortlist':
2796 optlist.append((_('use "hg help" for the full list '
2797 optlist.append((_('use "hg help" for the full list '
2797 'of commands'), ()))
2798 'of commands'), ()))
2798 else:
2799 else:
2799 if name == 'shortlist':
2800 if name == 'shortlist':
2800 msg = _('use "hg help" for the full list of commands '
2801 msg = _('use "hg help" for the full list of commands '
2801 'or "hg -v" for details')
2802 'or "hg -v" for details')
2802 elif name and not full:
2803 elif name and not full:
2803 msg = _('use "hg help %s" to show the full help text' % name)
2804 msg = _('use "hg help %s" to show the full help text' % name)
2804 elif aliases:
2805 elif aliases:
2805 msg = _('use "hg -v help%s" to show builtin aliases and '
2806 msg = _('use "hg -v help%s" to show builtin aliases and '
2806 'global options') % (name and " " + name or "")
2807 'global options') % (name and " " + name or "")
2807 else:
2808 else:
2808 msg = _('use "hg -v help %s" to show global options') % name
2809 msg = _('use "hg -v help %s" to show global options') % name
2809 optlist.append((msg, ()))
2810 optlist.append((msg, ()))
2810
2811
2811 def helpcmd(name):
2812 def helpcmd(name):
2812 optlist = []
2813 optlist = []
2813 try:
2814 try:
2814 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2815 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2815 except error.AmbiguousCommand, inst:
2816 except error.AmbiguousCommand, inst:
2816 # py3k fix: except vars can't be used outside the scope of the
2817 # py3k fix: except vars can't be used outside the scope of the
2817 # except block, nor can be used inside a lambda. python issue4617
2818 # except block, nor can be used inside a lambda. python issue4617
2818 prefix = inst.args[0]
2819 prefix = inst.args[0]
2819 select = lambda c: c.lstrip('^').startswith(prefix)
2820 select = lambda c: c.lstrip('^').startswith(prefix)
2820 helplist(select)
2821 helplist(select)
2821 return
2822 return
2822
2823
2823 # check if it's an invalid alias and display its error if it is
2824 # check if it's an invalid alias and display its error if it is
2824 if getattr(entry[0], 'badalias', False):
2825 if getattr(entry[0], 'badalias', False):
2825 if not unknowncmd:
2826 if not unknowncmd:
2826 entry[0](ui)
2827 entry[0](ui)
2827 return
2828 return
2828
2829
2829 # synopsis
2830 # synopsis
2830 if len(entry) > 2:
2831 if len(entry) > 2:
2831 if entry[2].startswith('hg'):
2832 if entry[2].startswith('hg'):
2832 ui.write("%s\n" % entry[2])
2833 ui.write("%s\n" % entry[2])
2833 else:
2834 else:
2834 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2835 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2835 else:
2836 else:
2836 ui.write('hg %s\n' % aliases[0])
2837 ui.write('hg %s\n' % aliases[0])
2837
2838
2838 # aliases
2839 # aliases
2839 if full and not ui.quiet and len(aliases) > 1:
2840 if full and not ui.quiet and len(aliases) > 1:
2840 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2841 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2841
2842
2842 # description
2843 # description
2843 doc = gettext(entry[0].__doc__)
2844 doc = gettext(entry[0].__doc__)
2844 if not doc:
2845 if not doc:
2845 doc = _("(no help text available)")
2846 doc = _("(no help text available)")
2846 if util.safehasattr(entry[0], 'definition'): # aliased command
2847 if util.safehasattr(entry[0], 'definition'): # aliased command
2847 if entry[0].definition.startswith('!'): # shell alias
2848 if entry[0].definition.startswith('!'): # shell alias
2848 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2849 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2849 else:
2850 else:
2850 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2851 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2851 if ui.quiet or not full:
2852 if ui.quiet or not full:
2852 doc = doc.splitlines()[0]
2853 doc = doc.splitlines()[0]
2853 keep = ui.verbose and ['verbose'] or []
2854 keep = ui.verbose and ['verbose'] or []
2854 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2855 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2855 ui.write("\n%s" % formatted)
2856 ui.write("\n%s" % formatted)
2856 if pruned:
2857 if pruned:
2857 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2858 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2858
2859
2859 if not ui.quiet:
2860 if not ui.quiet:
2860 # options
2861 # options
2861 if entry[1]:
2862 if entry[1]:
2862 optlist.append((_("options:\n"), entry[1]))
2863 optlist.append((_("options:\n"), entry[1]))
2863
2864
2864 # check if this command shadows a non-trivial (multi-line)
2865 # check if this command shadows a non-trivial (multi-line)
2865 # extension help text
2866 # extension help text
2866 try:
2867 try:
2867 mod = extensions.find(name)
2868 mod = extensions.find(name)
2868 doc = gettext(mod.__doc__) or ''
2869 doc = gettext(mod.__doc__) or ''
2869 if '\n' in doc.strip():
2870 if '\n' in doc.strip():
2870 msg = _('use "hg help -e %s" to show help for '
2871 msg = _('use "hg help -e %s" to show help for '
2871 'the %s extension') % (name, name)
2872 'the %s extension') % (name, name)
2872 ui.write('\n%s\n' % msg)
2873 ui.write('\n%s\n' % msg)
2873 except KeyError:
2874 except KeyError:
2874 pass
2875 pass
2875
2876
2876 addglobalopts(optlist, False)
2877 addglobalopts(optlist, False)
2877 ui.write(opttext(optlist, textwidth))
2878 ui.write(opttext(optlist, textwidth))
2878
2879
2879 def helplist(select=None):
2880 def helplist(select=None):
2880 # list of commands
2881 # list of commands
2881 if name == "shortlist":
2882 if name == "shortlist":
2882 header = _('basic commands:\n\n')
2883 header = _('basic commands:\n\n')
2883 else:
2884 else:
2884 header = _('list of commands:\n\n')
2885 header = _('list of commands:\n\n')
2885
2886
2886 h = {}
2887 h = {}
2887 cmds = {}
2888 cmds = {}
2888 for c, e in table.iteritems():
2889 for c, e in table.iteritems():
2889 f = c.split("|", 1)[0]
2890 f = c.split("|", 1)[0]
2890 if select and not select(f):
2891 if select and not select(f):
2891 continue
2892 continue
2892 if (not select and name != 'shortlist' and
2893 if (not select and name != 'shortlist' and
2893 e[0].__module__ != __name__):
2894 e[0].__module__ != __name__):
2894 continue
2895 continue
2895 if name == "shortlist" and not f.startswith("^"):
2896 if name == "shortlist" and not f.startswith("^"):
2896 continue
2897 continue
2897 f = f.lstrip("^")
2898 f = f.lstrip("^")
2898 if not ui.debugflag and f.startswith("debug"):
2899 if not ui.debugflag and f.startswith("debug"):
2899 continue
2900 continue
2900 doc = e[0].__doc__
2901 doc = e[0].__doc__
2901 if doc and 'DEPRECATED' in doc and not ui.verbose:
2902 if doc and 'DEPRECATED' in doc and not ui.verbose:
2902 continue
2903 continue
2903 doc = gettext(doc)
2904 doc = gettext(doc)
2904 if not doc:
2905 if not doc:
2905 doc = _("(no help text available)")
2906 doc = _("(no help text available)")
2906 h[f] = doc.splitlines()[0].rstrip()
2907 h[f] = doc.splitlines()[0].rstrip()
2907 cmds[f] = c.lstrip("^")
2908 cmds[f] = c.lstrip("^")
2908
2909
2909 if not h:
2910 if not h:
2910 ui.status(_('no commands defined\n'))
2911 ui.status(_('no commands defined\n'))
2911 return
2912 return
2912
2913
2913 ui.status(header)
2914 ui.status(header)
2914 fns = sorted(h)
2915 fns = sorted(h)
2915 m = max(map(len, fns))
2916 m = max(map(len, fns))
2916 for f in fns:
2917 for f in fns:
2917 if ui.verbose:
2918 if ui.verbose:
2918 commands = cmds[f].replace("|",", ")
2919 commands = cmds[f].replace("|",", ")
2919 ui.write(" %s:\n %s\n"%(commands, h[f]))
2920 ui.write(" %s:\n %s\n"%(commands, h[f]))
2920 else:
2921 else:
2921 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2922 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2922 initindent=' %-*s ' % (m, f),
2923 initindent=' %-*s ' % (m, f),
2923 hangindent=' ' * (m + 4))))
2924 hangindent=' ' * (m + 4))))
2924
2925
2925 if not name:
2926 if not name:
2926 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2927 text = help.listexts(_('enabled extensions:'), extensions.enabled())
2927 if text:
2928 if text:
2928 ui.write("\n%s" % minirst.format(text, textwidth))
2929 ui.write("\n%s" % minirst.format(text, textwidth))
2929
2930
2930 ui.write(_("\nadditional help topics:\n\n"))
2931 ui.write(_("\nadditional help topics:\n\n"))
2931 topics = []
2932 topics = []
2932 for names, header, doc in help.helptable:
2933 for names, header, doc in help.helptable:
2933 topics.append((sorted(names, key=len, reverse=True)[0], header))
2934 topics.append((sorted(names, key=len, reverse=True)[0], header))
2934 topics_len = max([len(s[0]) for s in topics])
2935 topics_len = max([len(s[0]) for s in topics])
2935 for t, desc in topics:
2936 for t, desc in topics:
2936 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2937 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2937
2938
2938 optlist = []
2939 optlist = []
2939 addglobalopts(optlist, True)
2940 addglobalopts(optlist, True)
2940 ui.write(opttext(optlist, textwidth))
2941 ui.write(opttext(optlist, textwidth))
2941
2942
2942 def helptopic(name):
2943 def helptopic(name):
2943 for names, header, doc in help.helptable:
2944 for names, header, doc in help.helptable:
2944 if name in names:
2945 if name in names:
2945 break
2946 break
2946 else:
2947 else:
2947 raise error.UnknownCommand(name)
2948 raise error.UnknownCommand(name)
2948
2949
2949 # description
2950 # description
2950 if not doc:
2951 if not doc:
2951 doc = _("(no help text available)")
2952 doc = _("(no help text available)")
2952 if util.safehasattr(doc, '__call__'):
2953 if util.safehasattr(doc, '__call__'):
2953 doc = doc()
2954 doc = doc()
2954
2955
2955 ui.write("%s\n\n" % header)
2956 ui.write("%s\n\n" % header)
2956 ui.write("%s" % minirst.format(doc, textwidth, indent=4))
2957 ui.write("%s" % minirst.format(doc, textwidth, indent=4))
2957 try:
2958 try:
2958 cmdutil.findcmd(name, table)
2959 cmdutil.findcmd(name, table)
2959 ui.write(_('\nuse "hg help -c %s" to see help for '
2960 ui.write(_('\nuse "hg help -c %s" to see help for '
2960 'the %s command\n') % (name, name))
2961 'the %s command\n') % (name, name))
2961 except error.UnknownCommand:
2962 except error.UnknownCommand:
2962 pass
2963 pass
2963
2964
2964 def helpext(name):
2965 def helpext(name):
2965 try:
2966 try:
2966 mod = extensions.find(name)
2967 mod = extensions.find(name)
2967 doc = gettext(mod.__doc__) or _('no help text available')
2968 doc = gettext(mod.__doc__) or _('no help text available')
2968 except KeyError:
2969 except KeyError:
2969 mod = None
2970 mod = None
2970 doc = extensions.disabledext(name)
2971 doc = extensions.disabledext(name)
2971 if not doc:
2972 if not doc:
2972 raise error.UnknownCommand(name)
2973 raise error.UnknownCommand(name)
2973
2974
2974 if '\n' not in doc:
2975 if '\n' not in doc:
2975 head, tail = doc, ""
2976 head, tail = doc, ""
2976 else:
2977 else:
2977 head, tail = doc.split('\n', 1)
2978 head, tail = doc.split('\n', 1)
2978 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2979 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2979 if tail:
2980 if tail:
2980 ui.write(minirst.format(tail, textwidth))
2981 ui.write(minirst.format(tail, textwidth))
2981 ui.status('\n')
2982 ui.status('\n')
2982
2983
2983 if mod:
2984 if mod:
2984 try:
2985 try:
2985 ct = mod.cmdtable
2986 ct = mod.cmdtable
2986 except AttributeError:
2987 except AttributeError:
2987 ct = {}
2988 ct = {}
2988 modcmds = set([c.split('|', 1)[0] for c in ct])
2989 modcmds = set([c.split('|', 1)[0] for c in ct])
2989 helplist(modcmds.__contains__)
2990 helplist(modcmds.__contains__)
2990 else:
2991 else:
2991 ui.write(_('use "hg help extensions" for information on enabling '
2992 ui.write(_('use "hg help extensions" for information on enabling '
2992 'extensions\n'))
2993 'extensions\n'))
2993
2994
2994 def helpextcmd(name):
2995 def helpextcmd(name):
2995 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2996 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2996 doc = gettext(mod.__doc__).splitlines()[0]
2997 doc = gettext(mod.__doc__).splitlines()[0]
2997
2998
2998 msg = help.listexts(_("'%s' is provided by the following "
2999 msg = help.listexts(_("'%s' is provided by the following "
2999 "extension:") % cmd, {ext: doc}, indent=4)
3000 "extension:") % cmd, {ext: doc}, indent=4)
3000 ui.write(minirst.format(msg, textwidth))
3001 ui.write(minirst.format(msg, textwidth))
3001 ui.write('\n')
3002 ui.write('\n')
3002 ui.write(_('use "hg help extensions" for information on enabling '
3003 ui.write(_('use "hg help extensions" for information on enabling '
3003 'extensions\n'))
3004 'extensions\n'))
3004
3005
3005 if name and name != 'shortlist':
3006 if name and name != 'shortlist':
3006 i = None
3007 i = None
3007 if unknowncmd:
3008 if unknowncmd:
3008 queries = (helpextcmd,)
3009 queries = (helpextcmd,)
3009 elif opts.get('extension'):
3010 elif opts.get('extension'):
3010 queries = (helpext,)
3011 queries = (helpext,)
3011 elif opts.get('command'):
3012 elif opts.get('command'):
3012 queries = (helpcmd,)
3013 queries = (helpcmd,)
3013 else:
3014 else:
3014 queries = (helptopic, helpcmd, helpext, helpextcmd)
3015 queries = (helptopic, helpcmd, helpext, helpextcmd)
3015 for f in queries:
3016 for f in queries:
3016 try:
3017 try:
3017 f(name)
3018 f(name)
3018 i = None
3019 i = None
3019 break
3020 break
3020 except error.UnknownCommand, inst:
3021 except error.UnknownCommand, inst:
3021 i = inst
3022 i = inst
3022 if i:
3023 if i:
3023 raise i
3024 raise i
3024 else:
3025 else:
3025 # program name
3026 # program name
3026 ui.status(_("Mercurial Distributed SCM\n"))
3027 ui.status(_("Mercurial Distributed SCM\n"))
3027 ui.status('\n')
3028 ui.status('\n')
3028 helplist()
3029 helplist()
3029
3030
3030
3031
3031 @command('identify|id',
3032 @command('identify|id',
3032 [('r', 'rev', '',
3033 [('r', 'rev', '',
3033 _('identify the specified revision'), _('REV')),
3034 _('identify the specified revision'), _('REV')),
3034 ('n', 'num', None, _('show local revision number')),
3035 ('n', 'num', None, _('show local revision number')),
3035 ('i', 'id', None, _('show global revision id')),
3036 ('i', 'id', None, _('show global revision id')),
3036 ('b', 'branch', None, _('show branch')),
3037 ('b', 'branch', None, _('show branch')),
3037 ('t', 'tags', None, _('show tags')),
3038 ('t', 'tags', None, _('show tags')),
3038 ('B', 'bookmarks', None, _('show bookmarks'))],
3039 ('B', 'bookmarks', None, _('show bookmarks'))],
3039 _('[-nibtB] [-r REV] [SOURCE]'))
3040 _('[-nibtB] [-r REV] [SOURCE]'))
3040 def identify(ui, repo, source=None, rev=None,
3041 def identify(ui, repo, source=None, rev=None,
3041 num=None, id=None, branch=None, tags=None, bookmarks=None):
3042 num=None, id=None, branch=None, tags=None, bookmarks=None):
3042 """identify the working copy or specified revision
3043 """identify the working copy or specified revision
3043
3044
3044 Print a summary identifying the repository state at REV using one or
3045 Print a summary identifying the repository state at REV using one or
3045 two parent hash identifiers, followed by a "+" if the working
3046 two parent hash identifiers, followed by a "+" if the working
3046 directory has uncommitted changes, the branch name (if not default),
3047 directory has uncommitted changes, the branch name (if not default),
3047 a list of tags, and a list of bookmarks.
3048 a list of tags, and a list of bookmarks.
3048
3049
3049 When REV is not given, print a summary of the current state of the
3050 When REV is not given, print a summary of the current state of the
3050 repository.
3051 repository.
3051
3052
3052 Specifying a path to a repository root or Mercurial bundle will
3053 Specifying a path to a repository root or Mercurial bundle will
3053 cause lookup to operate on that repository/bundle.
3054 cause lookup to operate on that repository/bundle.
3054
3055
3055 .. container:: verbose
3056 .. container:: verbose
3056
3057
3057 Examples:
3058 Examples:
3058
3059
3059 - generate a build identifier for the working directory::
3060 - generate a build identifier for the working directory::
3060
3061
3061 hg id --id > build-id.dat
3062 hg id --id > build-id.dat
3062
3063
3063 - find the revision corresponding to a tag::
3064 - find the revision corresponding to a tag::
3064
3065
3065 hg id -n -r 1.3
3066 hg id -n -r 1.3
3066
3067
3067 - check the most recent revision of a remote repository::
3068 - check the most recent revision of a remote repository::
3068
3069
3069 hg id -r tip http://selenic.com/hg/
3070 hg id -r tip http://selenic.com/hg/
3070
3071
3071 Returns 0 if successful.
3072 Returns 0 if successful.
3072 """
3073 """
3073
3074
3074 if not repo and not source:
3075 if not repo and not source:
3075 raise util.Abort(_("there is no Mercurial repository here "
3076 raise util.Abort(_("there is no Mercurial repository here "
3076 "(.hg not found)"))
3077 "(.hg not found)"))
3077
3078
3078 hexfunc = ui.debugflag and hex or short
3079 hexfunc = ui.debugflag and hex or short
3079 default = not (num or id or branch or tags or bookmarks)
3080 default = not (num or id or branch or tags or bookmarks)
3080 output = []
3081 output = []
3081 revs = []
3082 revs = []
3082
3083
3083 if source:
3084 if source:
3084 source, branches = hg.parseurl(ui.expandpath(source))
3085 source, branches = hg.parseurl(ui.expandpath(source))
3085 repo = hg.peer(ui, {}, source)
3086 repo = hg.peer(ui, {}, source)
3086 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3087 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3087
3088
3088 if not repo.local():
3089 if not repo.local():
3089 if num or branch or tags:
3090 if num or branch or tags:
3090 raise util.Abort(
3091 raise util.Abort(
3091 _("can't query remote revision number, branch, or tags"))
3092 _("can't query remote revision number, branch, or tags"))
3092 if not rev and revs:
3093 if not rev and revs:
3093 rev = revs[0]
3094 rev = revs[0]
3094 if not rev:
3095 if not rev:
3095 rev = "tip"
3096 rev = "tip"
3096
3097
3097 remoterev = repo.lookup(rev)
3098 remoterev = repo.lookup(rev)
3098 if default or id:
3099 if default or id:
3099 output = [hexfunc(remoterev)]
3100 output = [hexfunc(remoterev)]
3100
3101
3101 def getbms():
3102 def getbms():
3102 bms = []
3103 bms = []
3103
3104
3104 if 'bookmarks' in repo.listkeys('namespaces'):
3105 if 'bookmarks' in repo.listkeys('namespaces'):
3105 hexremoterev = hex(remoterev)
3106 hexremoterev = hex(remoterev)
3106 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3107 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3107 if bmr == hexremoterev]
3108 if bmr == hexremoterev]
3108
3109
3109 return bms
3110 return bms
3110
3111
3111 if bookmarks:
3112 if bookmarks:
3112 output.extend(getbms())
3113 output.extend(getbms())
3113 elif default and not ui.quiet:
3114 elif default and not ui.quiet:
3114 # multiple bookmarks for a single parent separated by '/'
3115 # multiple bookmarks for a single parent separated by '/'
3115 bm = '/'.join(getbms())
3116 bm = '/'.join(getbms())
3116 if bm:
3117 if bm:
3117 output.append(bm)
3118 output.append(bm)
3118 else:
3119 else:
3119 if not rev:
3120 if not rev:
3120 ctx = repo[None]
3121 ctx = repo[None]
3121 parents = ctx.parents()
3122 parents = ctx.parents()
3122 changed = ""
3123 changed = ""
3123 if default or id or num:
3124 if default or id or num:
3124 changed = util.any(repo.status()) and "+" or ""
3125 changed = util.any(repo.status()) and "+" or ""
3125 if default or id:
3126 if default or id:
3126 output = ["%s%s" %
3127 output = ["%s%s" %
3127 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3128 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3128 if num:
3129 if num:
3129 output.append("%s%s" %
3130 output.append("%s%s" %
3130 ('+'.join([str(p.rev()) for p in parents]), changed))
3131 ('+'.join([str(p.rev()) for p in parents]), changed))
3131 else:
3132 else:
3132 ctx = scmutil.revsingle(repo, rev)
3133 ctx = scmutil.revsingle(repo, rev)
3133 if default or id:
3134 if default or id:
3134 output = [hexfunc(ctx.node())]
3135 output = [hexfunc(ctx.node())]
3135 if num:
3136 if num:
3136 output.append(str(ctx.rev()))
3137 output.append(str(ctx.rev()))
3137
3138
3138 if default and not ui.quiet:
3139 if default and not ui.quiet:
3139 b = ctx.branch()
3140 b = ctx.branch()
3140 if b != 'default':
3141 if b != 'default':
3141 output.append("(%s)" % b)
3142 output.append("(%s)" % b)
3142
3143
3143 # multiple tags for a single parent separated by '/'
3144 # multiple tags for a single parent separated by '/'
3144 t = '/'.join(ctx.tags())
3145 t = '/'.join(ctx.tags())
3145 if t:
3146 if t:
3146 output.append(t)
3147 output.append(t)
3147
3148
3148 # multiple bookmarks for a single parent separated by '/'
3149 # multiple bookmarks for a single parent separated by '/'
3149 bm = '/'.join(ctx.bookmarks())
3150 bm = '/'.join(ctx.bookmarks())
3150 if bm:
3151 if bm:
3151 output.append(bm)
3152 output.append(bm)
3152 else:
3153 else:
3153 if branch:
3154 if branch:
3154 output.append(ctx.branch())
3155 output.append(ctx.branch())
3155
3156
3156 if tags:
3157 if tags:
3157 output.extend(ctx.tags())
3158 output.extend(ctx.tags())
3158
3159
3159 if bookmarks:
3160 if bookmarks:
3160 output.extend(ctx.bookmarks())
3161 output.extend(ctx.bookmarks())
3161
3162
3162 ui.write("%s\n" % ' '.join(output))
3163 ui.write("%s\n" % ' '.join(output))
3163
3164
3164 @command('import|patch',
3165 @command('import|patch',
3165 [('p', 'strip', 1,
3166 [('p', 'strip', 1,
3166 _('directory strip option for patch. This has the same '
3167 _('directory strip option for patch. This has the same '
3167 'meaning as the corresponding patch option'), _('NUM')),
3168 'meaning as the corresponding patch option'), _('NUM')),
3168 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3169 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3169 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3170 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3170 ('', 'no-commit', None,
3171 ('', 'no-commit', None,
3171 _("don't commit, just update the working directory")),
3172 _("don't commit, just update the working directory")),
3172 ('', 'bypass', None,
3173 ('', 'bypass', None,
3173 _("apply patch without touching the working directory")),
3174 _("apply patch without touching the working directory")),
3174 ('', 'exact', None,
3175 ('', 'exact', None,
3175 _('apply patch to the nodes from which it was generated')),
3176 _('apply patch to the nodes from which it was generated')),
3176 ('', 'import-branch', None,
3177 ('', 'import-branch', None,
3177 _('use any branch information in patch (implied by --exact)'))] +
3178 _('use any branch information in patch (implied by --exact)'))] +
3178 commitopts + commitopts2 + similarityopts,
3179 commitopts + commitopts2 + similarityopts,
3179 _('[OPTION]... PATCH...'))
3180 _('[OPTION]... PATCH...'))
3180 def import_(ui, repo, patch1, *patches, **opts):
3181 def import_(ui, repo, patch1, *patches, **opts):
3181 """import an ordered set of patches
3182 """import an ordered set of patches
3182
3183
3183 Import a list of patches and commit them individually (unless
3184 Import a list of patches and commit them individually (unless
3184 --no-commit is specified).
3185 --no-commit is specified).
3185
3186
3186 If there are outstanding changes in the working directory, import
3187 If there are outstanding changes in the working directory, import
3187 will abort unless given the -f/--force flag.
3188 will abort unless given the -f/--force flag.
3188
3189
3189 You can import a patch straight from a mail message. Even patches
3190 You can import a patch straight from a mail message. Even patches
3190 as attachments work (to use the body part, it must have type
3191 as attachments work (to use the body part, it must have type
3191 text/plain or text/x-patch). From and Subject headers of email
3192 text/plain or text/x-patch). From and Subject headers of email
3192 message are used as default committer and commit message. All
3193 message are used as default committer and commit message. All
3193 text/plain body parts before first diff are added to commit
3194 text/plain body parts before first diff are added to commit
3194 message.
3195 message.
3195
3196
3196 If the imported patch was generated by :hg:`export`, user and
3197 If the imported patch was generated by :hg:`export`, user and
3197 description from patch override values from message headers and
3198 description from patch override values from message headers and
3198 body. Values given on command line with -m/--message and -u/--user
3199 body. Values given on command line with -m/--message and -u/--user
3199 override these.
3200 override these.
3200
3201
3201 If --exact is specified, import will set the working directory to
3202 If --exact is specified, import will set the working directory to
3202 the parent of each patch before applying it, and will abort if the
3203 the parent of each patch before applying it, and will abort if the
3203 resulting changeset has a different ID than the one recorded in
3204 resulting changeset has a different ID than the one recorded in
3204 the patch. This may happen due to character set problems or other
3205 the patch. This may happen due to character set problems or other
3205 deficiencies in the text patch format.
3206 deficiencies in the text patch format.
3206
3207
3207 Use --bypass to apply and commit patches directly to the
3208 Use --bypass to apply and commit patches directly to the
3208 repository, not touching the working directory. Without --exact,
3209 repository, not touching the working directory. Without --exact,
3209 patches will be applied on top of the working directory parent
3210 patches will be applied on top of the working directory parent
3210 revision.
3211 revision.
3211
3212
3212 With -s/--similarity, hg will attempt to discover renames and
3213 With -s/--similarity, hg will attempt to discover renames and
3213 copies in the patch in the same way as 'addremove'.
3214 copies in the patch in the same way as 'addremove'.
3214
3215
3215 To read a patch from standard input, use "-" as the patch name. If
3216 To read a patch from standard input, use "-" as the patch name. If
3216 a URL is specified, the patch will be downloaded from it.
3217 a URL is specified, the patch will be downloaded from it.
3217 See :hg:`help dates` for a list of formats valid for -d/--date.
3218 See :hg:`help dates` for a list of formats valid for -d/--date.
3218
3219
3219 .. container:: verbose
3220 .. container:: verbose
3220
3221
3221 Examples:
3222 Examples:
3222
3223
3223 - import a traditional patch from a website and detect renames::
3224 - import a traditional patch from a website and detect renames::
3224
3225
3225 hg import -s 80 http://example.com/bugfix.patch
3226 hg import -s 80 http://example.com/bugfix.patch
3226
3227
3227 - import a changeset from an hgweb server::
3228 - import a changeset from an hgweb server::
3228
3229
3229 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3230 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3230
3231
3231 - import all the patches in an Unix-style mbox::
3232 - import all the patches in an Unix-style mbox::
3232
3233
3233 hg import incoming-patches.mbox
3234 hg import incoming-patches.mbox
3234
3235
3235 - attempt to exactly restore an exported changeset (not always
3236 - attempt to exactly restore an exported changeset (not always
3236 possible)::
3237 possible)::
3237
3238
3238 hg import --exact proposed-fix.patch
3239 hg import --exact proposed-fix.patch
3239
3240
3240 Returns 0 on success.
3241 Returns 0 on success.
3241 """
3242 """
3242 patches = (patch1,) + patches
3243 patches = (patch1,) + patches
3243
3244
3244 date = opts.get('date')
3245 date = opts.get('date')
3245 if date:
3246 if date:
3246 opts['date'] = util.parsedate(date)
3247 opts['date'] = util.parsedate(date)
3247
3248
3248 update = not opts.get('bypass')
3249 update = not opts.get('bypass')
3249 if not update and opts.get('no_commit'):
3250 if not update and opts.get('no_commit'):
3250 raise util.Abort(_('cannot use --no-commit with --bypass'))
3251 raise util.Abort(_('cannot use --no-commit with --bypass'))
3251 try:
3252 try:
3252 sim = float(opts.get('similarity') or 0)
3253 sim = float(opts.get('similarity') or 0)
3253 except ValueError:
3254 except ValueError:
3254 raise util.Abort(_('similarity must be a number'))
3255 raise util.Abort(_('similarity must be a number'))
3255 if sim < 0 or sim > 100:
3256 if sim < 0 or sim > 100:
3256 raise util.Abort(_('similarity must be between 0 and 100'))
3257 raise util.Abort(_('similarity must be between 0 and 100'))
3257 if sim and not update:
3258 if sim and not update:
3258 raise util.Abort(_('cannot use --similarity with --bypass'))
3259 raise util.Abort(_('cannot use --similarity with --bypass'))
3259
3260
3260 if (opts.get('exact') or not opts.get('force')) and update:
3261 if (opts.get('exact') or not opts.get('force')) and update:
3261 cmdutil.bailifchanged(repo)
3262 cmdutil.bailifchanged(repo)
3262
3263
3263 d = opts["base"]
3264 d = opts["base"]
3264 strip = opts["strip"]
3265 strip = opts["strip"]
3265 wlock = lock = None
3266 wlock = lock = None
3266 msgs = []
3267 msgs = []
3267
3268
3268 def checkexact(repo, n, nodeid):
3269 def checkexact(repo, n, nodeid):
3269 if opts.get('exact') and hex(n) != nodeid:
3270 if opts.get('exact') and hex(n) != nodeid:
3270 repo.rollback()
3271 repo.rollback()
3271 raise util.Abort(_('patch is damaged or loses information'))
3272 raise util.Abort(_('patch is damaged or loses information'))
3272
3273
3273 def tryone(ui, hunk, parents):
3274 def tryone(ui, hunk, parents):
3274 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3275 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3275 patch.extract(ui, hunk)
3276 patch.extract(ui, hunk)
3276
3277
3277 if not tmpname:
3278 if not tmpname:
3278 return None
3279 return None
3279 commitid = _('to working directory')
3280 commitid = _('to working directory')
3280
3281
3281 try:
3282 try:
3282 cmdline_message = cmdutil.logmessage(ui, opts)
3283 cmdline_message = cmdutil.logmessage(ui, opts)
3283 if cmdline_message:
3284 if cmdline_message:
3284 # pickup the cmdline msg
3285 # pickup the cmdline msg
3285 message = cmdline_message
3286 message = cmdline_message
3286 elif message:
3287 elif message:
3287 # pickup the patch msg
3288 # pickup the patch msg
3288 message = message.strip()
3289 message = message.strip()
3289 else:
3290 else:
3290 # launch the editor
3291 # launch the editor
3291 message = None
3292 message = None
3292 ui.debug('message:\n%s\n' % message)
3293 ui.debug('message:\n%s\n' % message)
3293
3294
3294 if len(parents) == 1:
3295 if len(parents) == 1:
3295 parents.append(repo[nullid])
3296 parents.append(repo[nullid])
3296 if opts.get('exact'):
3297 if opts.get('exact'):
3297 if not nodeid or not p1:
3298 if not nodeid or not p1:
3298 raise util.Abort(_('not a Mercurial patch'))
3299 raise util.Abort(_('not a Mercurial patch'))
3299 p1 = repo[p1]
3300 p1 = repo[p1]
3300 p2 = repo[p2 or nullid]
3301 p2 = repo[p2 or nullid]
3301 elif p2:
3302 elif p2:
3302 try:
3303 try:
3303 p1 = repo[p1]
3304 p1 = repo[p1]
3304 p2 = repo[p2]
3305 p2 = repo[p2]
3305 except error.RepoError:
3306 except error.RepoError:
3306 p1, p2 = parents
3307 p1, p2 = parents
3307 else:
3308 else:
3308 p1, p2 = parents
3309 p1, p2 = parents
3309
3310
3310 n = None
3311 n = None
3311 if update:
3312 if update:
3312 if opts.get('exact') and p1 != parents[0]:
3313 if opts.get('exact') and p1 != parents[0]:
3313 hg.clean(repo, p1.node())
3314 hg.clean(repo, p1.node())
3314 if p1 != parents[0] and p2 != parents[1]:
3315 if p1 != parents[0] and p2 != parents[1]:
3315 repo.dirstate.setparents(p1.node(), p2.node())
3316 repo.dirstate.setparents(p1.node(), p2.node())
3316
3317
3317 if opts.get('exact') or opts.get('import_branch'):
3318 if opts.get('exact') or opts.get('import_branch'):
3318 repo.dirstate.setbranch(branch or 'default')
3319 repo.dirstate.setbranch(branch or 'default')
3319
3320
3320 files = set()
3321 files = set()
3321 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3322 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3322 eolmode=None, similarity=sim / 100.0)
3323 eolmode=None, similarity=sim / 100.0)
3323 files = list(files)
3324 files = list(files)
3324 if opts.get('no_commit'):
3325 if opts.get('no_commit'):
3325 if message:
3326 if message:
3326 msgs.append(message)
3327 msgs.append(message)
3327 else:
3328 else:
3328 if opts.get('exact'):
3329 if opts.get('exact'):
3329 m = None
3330 m = None
3330 else:
3331 else:
3331 m = scmutil.matchfiles(repo, files or [])
3332 m = scmutil.matchfiles(repo, files or [])
3332 n = repo.commit(message, opts.get('user') or user,
3333 n = repo.commit(message, opts.get('user') or user,
3333 opts.get('date') or date, match=m,
3334 opts.get('date') or date, match=m,
3334 editor=cmdutil.commiteditor)
3335 editor=cmdutil.commiteditor)
3335 checkexact(repo, n, nodeid)
3336 checkexact(repo, n, nodeid)
3336 # Force a dirstate write so that the next transaction
3337 # Force a dirstate write so that the next transaction
3337 # backups an up-to-date file.
3338 # backups an up-to-date file.
3338 repo.dirstate.write()
3339 repo.dirstate.write()
3339 else:
3340 else:
3340 if opts.get('exact') or opts.get('import_branch'):
3341 if opts.get('exact') or opts.get('import_branch'):
3341 branch = branch or 'default'
3342 branch = branch or 'default'
3342 else:
3343 else:
3343 branch = p1.branch()
3344 branch = p1.branch()
3344 store = patch.filestore()
3345 store = patch.filestore()
3345 try:
3346 try:
3346 files = set()
3347 files = set()
3347 try:
3348 try:
3348 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3349 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3349 files, eolmode=None)
3350 files, eolmode=None)
3350 except patch.PatchError, e:
3351 except patch.PatchError, e:
3351 raise util.Abort(str(e))
3352 raise util.Abort(str(e))
3352 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3353 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3353 message,
3354 message,
3354 opts.get('user') or user,
3355 opts.get('user') or user,
3355 opts.get('date') or date,
3356 opts.get('date') or date,
3356 branch, files, store,
3357 branch, files, store,
3357 editor=cmdutil.commiteditor)
3358 editor=cmdutil.commiteditor)
3358 repo.savecommitmessage(memctx.description())
3359 repo.savecommitmessage(memctx.description())
3359 n = memctx.commit()
3360 n = memctx.commit()
3360 checkexact(repo, n, nodeid)
3361 checkexact(repo, n, nodeid)
3361 finally:
3362 finally:
3362 store.close()
3363 store.close()
3363 if n:
3364 if n:
3364 commitid = short(n)
3365 commitid = short(n)
3365 return commitid
3366 return commitid
3366 finally:
3367 finally:
3367 os.unlink(tmpname)
3368 os.unlink(tmpname)
3368
3369
3369 try:
3370 try:
3370 wlock = repo.wlock()
3371 wlock = repo.wlock()
3371 lock = repo.lock()
3372 lock = repo.lock()
3372 parents = repo.parents()
3373 parents = repo.parents()
3373 lastcommit = None
3374 lastcommit = None
3374 for p in patches:
3375 for p in patches:
3375 pf = os.path.join(d, p)
3376 pf = os.path.join(d, p)
3376
3377
3377 if pf == '-':
3378 if pf == '-':
3378 ui.status(_("applying patch from stdin\n"))
3379 ui.status(_("applying patch from stdin\n"))
3379 pf = ui.fin
3380 pf = ui.fin
3380 else:
3381 else:
3381 ui.status(_("applying %s\n") % p)
3382 ui.status(_("applying %s\n") % p)
3382 pf = url.open(ui, pf)
3383 pf = url.open(ui, pf)
3383
3384
3384 haspatch = False
3385 haspatch = False
3385 for hunk in patch.split(pf):
3386 for hunk in patch.split(pf):
3386 commitid = tryone(ui, hunk, parents)
3387 commitid = tryone(ui, hunk, parents)
3387 if commitid:
3388 if commitid:
3388 haspatch = True
3389 haspatch = True
3389 if lastcommit:
3390 if lastcommit:
3390 ui.status(_('applied %s\n') % lastcommit)
3391 ui.status(_('applied %s\n') % lastcommit)
3391 lastcommit = commitid
3392 lastcommit = commitid
3392 if update or opts.get('exact'):
3393 if update or opts.get('exact'):
3393 parents = repo.parents()
3394 parents = repo.parents()
3394 else:
3395 else:
3395 parents = [repo[commitid]]
3396 parents = [repo[commitid]]
3396
3397
3397 if not haspatch:
3398 if not haspatch:
3398 raise util.Abort(_('no diffs found'))
3399 raise util.Abort(_('no diffs found'))
3399
3400
3400 if msgs:
3401 if msgs:
3401 repo.savecommitmessage('\n* * *\n'.join(msgs))
3402 repo.savecommitmessage('\n* * *\n'.join(msgs))
3402 finally:
3403 finally:
3403 release(lock, wlock)
3404 release(lock, wlock)
3404
3405
3405 @command('incoming|in',
3406 @command('incoming|in',
3406 [('f', 'force', None,
3407 [('f', 'force', None,
3407 _('run even if remote repository is unrelated')),
3408 _('run even if remote repository is unrelated')),
3408 ('n', 'newest-first', None, _('show newest record first')),
3409 ('n', 'newest-first', None, _('show newest record first')),
3409 ('', 'bundle', '',
3410 ('', 'bundle', '',
3410 _('file to store the bundles into'), _('FILE')),
3411 _('file to store the bundles into'), _('FILE')),
3411 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3412 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3412 ('B', 'bookmarks', False, _("compare bookmarks")),
3413 ('B', 'bookmarks', False, _("compare bookmarks")),
3413 ('b', 'branch', [],
3414 ('b', 'branch', [],
3414 _('a specific branch you would like to pull'), _('BRANCH')),
3415 _('a specific branch you would like to pull'), _('BRANCH')),
3415 ] + logopts + remoteopts + subrepoopts,
3416 ] + logopts + remoteopts + subrepoopts,
3416 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3417 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3417 def incoming(ui, repo, source="default", **opts):
3418 def incoming(ui, repo, source="default", **opts):
3418 """show new changesets found in source
3419 """show new changesets found in source
3419
3420
3420 Show new changesets found in the specified path/URL or the default
3421 Show new changesets found in the specified path/URL or the default
3421 pull location. These are the changesets that would have been pulled
3422 pull location. These are the changesets that would have been pulled
3422 if a pull at the time you issued this command.
3423 if a pull at the time you issued this command.
3423
3424
3424 For remote repository, using --bundle avoids downloading the
3425 For remote repository, using --bundle avoids downloading the
3425 changesets twice if the incoming is followed by a pull.
3426 changesets twice if the incoming is followed by a pull.
3426
3427
3427 See pull for valid source format details.
3428 See pull for valid source format details.
3428
3429
3429 Returns 0 if there are incoming changes, 1 otherwise.
3430 Returns 0 if there are incoming changes, 1 otherwise.
3430 """
3431 """
3431 if opts.get('bundle') and opts.get('subrepos'):
3432 if opts.get('bundle') and opts.get('subrepos'):
3432 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3433 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3433
3434
3434 if opts.get('bookmarks'):
3435 if opts.get('bookmarks'):
3435 source, branches = hg.parseurl(ui.expandpath(source),
3436 source, branches = hg.parseurl(ui.expandpath(source),
3436 opts.get('branch'))
3437 opts.get('branch'))
3437 other = hg.peer(repo, opts, source)
3438 other = hg.peer(repo, opts, source)
3438 if 'bookmarks' not in other.listkeys('namespaces'):
3439 if 'bookmarks' not in other.listkeys('namespaces'):
3439 ui.warn(_("remote doesn't support bookmarks\n"))
3440 ui.warn(_("remote doesn't support bookmarks\n"))
3440 return 0
3441 return 0
3441 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3442 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3442 return bookmarks.diff(ui, repo, other)
3443 return bookmarks.diff(ui, repo, other)
3443
3444
3444 repo._subtoppath = ui.expandpath(source)
3445 repo._subtoppath = ui.expandpath(source)
3445 try:
3446 try:
3446 return hg.incoming(ui, repo, source, opts)
3447 return hg.incoming(ui, repo, source, opts)
3447 finally:
3448 finally:
3448 del repo._subtoppath
3449 del repo._subtoppath
3449
3450
3450
3451
3451 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3452 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3452 def init(ui, dest=".", **opts):
3453 def init(ui, dest=".", **opts):
3453 """create a new repository in the given directory
3454 """create a new repository in the given directory
3454
3455
3455 Initialize a new repository in the given directory. If the given
3456 Initialize a new repository in the given directory. If the given
3456 directory does not exist, it will be created.
3457 directory does not exist, it will be created.
3457
3458
3458 If no directory is given, the current directory is used.
3459 If no directory is given, the current directory is used.
3459
3460
3460 It is possible to specify an ``ssh://`` URL as the destination.
3461 It is possible to specify an ``ssh://`` URL as the destination.
3461 See :hg:`help urls` for more information.
3462 See :hg:`help urls` for more information.
3462
3463
3463 Returns 0 on success.
3464 Returns 0 on success.
3464 """
3465 """
3465 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3466 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3466
3467
3467 @command('locate',
3468 @command('locate',
3468 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3469 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3469 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3470 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3470 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3471 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3471 ] + walkopts,
3472 ] + walkopts,
3472 _('[OPTION]... [PATTERN]...'))
3473 _('[OPTION]... [PATTERN]...'))
3473 def locate(ui, repo, *pats, **opts):
3474 def locate(ui, repo, *pats, **opts):
3474 """locate files matching specific patterns
3475 """locate files matching specific patterns
3475
3476
3476 Print files under Mercurial control in the working directory whose
3477 Print files under Mercurial control in the working directory whose
3477 names match the given patterns.
3478 names match the given patterns.
3478
3479
3479 By default, this command searches all directories in the working
3480 By default, this command searches all directories in the working
3480 directory. To search just the current directory and its
3481 directory. To search just the current directory and its
3481 subdirectories, use "--include .".
3482 subdirectories, use "--include .".
3482
3483
3483 If no patterns are given to match, this command prints the names
3484 If no patterns are given to match, this command prints the names
3484 of all files under Mercurial control in the working directory.
3485 of all files under Mercurial control in the working directory.
3485
3486
3486 If you want to feed the output of this command into the "xargs"
3487 If you want to feed the output of this command into the "xargs"
3487 command, use the -0 option to both this command and "xargs". This
3488 command, use the -0 option to both this command and "xargs". This
3488 will avoid the problem of "xargs" treating single filenames that
3489 will avoid the problem of "xargs" treating single filenames that
3489 contain whitespace as multiple filenames.
3490 contain whitespace as multiple filenames.
3490
3491
3491 Returns 0 if a match is found, 1 otherwise.
3492 Returns 0 if a match is found, 1 otherwise.
3492 """
3493 """
3493 end = opts.get('print0') and '\0' or '\n'
3494 end = opts.get('print0') and '\0' or '\n'
3494 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3495 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3495
3496
3496 ret = 1
3497 ret = 1
3497 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3498 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3498 m.bad = lambda x, y: False
3499 m.bad = lambda x, y: False
3499 for abs in repo[rev].walk(m):
3500 for abs in repo[rev].walk(m):
3500 if not rev and abs not in repo.dirstate:
3501 if not rev and abs not in repo.dirstate:
3501 continue
3502 continue
3502 if opts.get('fullpath'):
3503 if opts.get('fullpath'):
3503 ui.write(repo.wjoin(abs), end)
3504 ui.write(repo.wjoin(abs), end)
3504 else:
3505 else:
3505 ui.write(((pats and m.rel(abs)) or abs), end)
3506 ui.write(((pats and m.rel(abs)) or abs), end)
3506 ret = 0
3507 ret = 0
3507
3508
3508 return ret
3509 return ret
3509
3510
3510 @command('^log|history',
3511 @command('^log|history',
3511 [('f', 'follow', None,
3512 [('f', 'follow', None,
3512 _('follow changeset history, or file history across copies and renames')),
3513 _('follow changeset history, or file history across copies and renames')),
3513 ('', 'follow-first', None,
3514 ('', 'follow-first', None,
3514 _('only follow the first parent of merge changesets')),
3515 _('only follow the first parent of merge changesets')),
3515 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3516 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3516 ('C', 'copies', None, _('show copied files')),
3517 ('C', 'copies', None, _('show copied files')),
3517 ('k', 'keyword', [],
3518 ('k', 'keyword', [],
3518 _('do case-insensitive search for a given text'), _('TEXT')),
3519 _('do case-insensitive search for a given text'), _('TEXT')),
3519 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3520 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3520 ('', 'removed', None, _('include revisions where files were removed')),
3521 ('', 'removed', None, _('include revisions where files were removed')),
3521 ('m', 'only-merges', None, _('show only merges')),
3522 ('m', 'only-merges', None, _('show only merges')),
3522 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3523 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3523 ('', 'only-branch', [],
3524 ('', 'only-branch', [],
3524 _('show only changesets within the given named branch (DEPRECATED)'),
3525 _('show only changesets within the given named branch (DEPRECATED)'),
3525 _('BRANCH')),
3526 _('BRANCH')),
3526 ('b', 'branch', [],
3527 ('b', 'branch', [],
3527 _('show changesets within the given named branch'), _('BRANCH')),
3528 _('show changesets within the given named branch'), _('BRANCH')),
3528 ('P', 'prune', [],
3529 ('P', 'prune', [],
3529 _('do not display revision or any of its ancestors'), _('REV')),
3530 _('do not display revision or any of its ancestors'), _('REV')),
3530 ('', 'hidden', False, _('show hidden changesets')),
3531 ('', 'hidden', False, _('show hidden changesets')),
3531 ] + logopts + walkopts,
3532 ] + logopts + walkopts,
3532 _('[OPTION]... [FILE]'))
3533 _('[OPTION]... [FILE]'))
3533 def log(ui, repo, *pats, **opts):
3534 def log(ui, repo, *pats, **opts):
3534 """show revision history of entire repository or files
3535 """show revision history of entire repository or files
3535
3536
3536 Print the revision history of the specified files or the entire
3537 Print the revision history of the specified files or the entire
3537 project.
3538 project.
3538
3539
3539 If no revision range is specified, the default is ``tip:0`` unless
3540 If no revision range is specified, the default is ``tip:0`` unless
3540 --follow is set, in which case the working directory parent is
3541 --follow is set, in which case the working directory parent is
3541 used as the starting revision.
3542 used as the starting revision.
3542
3543
3543 File history is shown without following rename or copy history of
3544 File history is shown without following rename or copy history of
3544 files. Use -f/--follow with a filename to follow history across
3545 files. Use -f/--follow with a filename to follow history across
3545 renames and copies. --follow without a filename will only show
3546 renames and copies. --follow without a filename will only show
3546 ancestors or descendants of the starting revision.
3547 ancestors or descendants of the starting revision.
3547
3548
3548 By default this command prints revision number and changeset id,
3549 By default this command prints revision number and changeset id,
3549 tags, non-trivial parents, user, date and time, and a summary for
3550 tags, non-trivial parents, user, date and time, and a summary for
3550 each commit. When the -v/--verbose switch is used, the list of
3551 each commit. When the -v/--verbose switch is used, the list of
3551 changed files and full commit message are shown.
3552 changed files and full commit message are shown.
3552
3553
3553 .. note::
3554 .. note::
3554 log -p/--patch may generate unexpected diff output for merge
3555 log -p/--patch may generate unexpected diff output for merge
3555 changesets, as it will only compare the merge changeset against
3556 changesets, as it will only compare the merge changeset against
3556 its first parent. Also, only files different from BOTH parents
3557 its first parent. Also, only files different from BOTH parents
3557 will appear in files:.
3558 will appear in files:.
3558
3559
3559 .. note::
3560 .. note::
3560 for performance reasons, log FILE may omit duplicate changes
3561 for performance reasons, log FILE may omit duplicate changes
3561 made on branches and will not show deletions. To see all
3562 made on branches and will not show deletions. To see all
3562 changes including duplicates and deletions, use the --removed
3563 changes including duplicates and deletions, use the --removed
3563 switch.
3564 switch.
3564
3565
3565 .. container:: verbose
3566 .. container:: verbose
3566
3567
3567 Some examples:
3568 Some examples:
3568
3569
3569 - changesets with full descriptions and file lists::
3570 - changesets with full descriptions and file lists::
3570
3571
3571 hg log -v
3572 hg log -v
3572
3573
3573 - changesets ancestral to the working directory::
3574 - changesets ancestral to the working directory::
3574
3575
3575 hg log -f
3576 hg log -f
3576
3577
3577 - last 10 commits on the current branch::
3578 - last 10 commits on the current branch::
3578
3579
3579 hg log -l 10 -b .
3580 hg log -l 10 -b .
3580
3581
3581 - changesets showing all modifications of a file, including removals::
3582 - changesets showing all modifications of a file, including removals::
3582
3583
3583 hg log --removed file.c
3584 hg log --removed file.c
3584
3585
3585 - all changesets that touch a directory, with diffs, excluding merges::
3586 - all changesets that touch a directory, with diffs, excluding merges::
3586
3587
3587 hg log -Mp lib/
3588 hg log -Mp lib/
3588
3589
3589 - all revision numbers that match a keyword::
3590 - all revision numbers that match a keyword::
3590
3591
3591 hg log -k bug --template "{rev}\\n"
3592 hg log -k bug --template "{rev}\\n"
3592
3593
3593 - check if a given changeset is included is a tagged release::
3594 - check if a given changeset is included is a tagged release::
3594
3595
3595 hg log -r "a21ccf and ancestor(1.9)"
3596 hg log -r "a21ccf and ancestor(1.9)"
3596
3597
3597 - find all changesets by some user in a date range::
3598 - find all changesets by some user in a date range::
3598
3599
3599 hg log -k alice -d "may 2008 to jul 2008"
3600 hg log -k alice -d "may 2008 to jul 2008"
3600
3601
3601 - summary of all changesets after the last tag::
3602 - summary of all changesets after the last tag::
3602
3603
3603 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3604 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3604
3605
3605 See :hg:`help dates` for a list of formats valid for -d/--date.
3606 See :hg:`help dates` for a list of formats valid for -d/--date.
3606
3607
3607 See :hg:`help revisions` and :hg:`help revsets` for more about
3608 See :hg:`help revisions` and :hg:`help revsets` for more about
3608 specifying revisions.
3609 specifying revisions.
3609
3610
3610 Returns 0 on success.
3611 Returns 0 on success.
3611 """
3612 """
3612
3613
3613 matchfn = scmutil.match(repo[None], pats, opts)
3614 matchfn = scmutil.match(repo[None], pats, opts)
3614 limit = cmdutil.loglimit(opts)
3615 limit = cmdutil.loglimit(opts)
3615 count = 0
3616 count = 0
3616
3617
3617 endrev = None
3618 endrev = None
3618 if opts.get('copies') and opts.get('rev'):
3619 if opts.get('copies') and opts.get('rev'):
3619 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3620 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3620
3621
3621 df = False
3622 df = False
3622 if opts["date"]:
3623 if opts["date"]:
3623 df = util.matchdate(opts["date"])
3624 df = util.matchdate(opts["date"])
3624
3625
3625 branches = opts.get('branch', []) + opts.get('only_branch', [])
3626 branches = opts.get('branch', []) + opts.get('only_branch', [])
3626 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3627 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3627
3628
3628 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3629 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3629 def prep(ctx, fns):
3630 def prep(ctx, fns):
3630 rev = ctx.rev()
3631 rev = ctx.rev()
3631 parents = [p for p in repo.changelog.parentrevs(rev)
3632 parents = [p for p in repo.changelog.parentrevs(rev)
3632 if p != nullrev]
3633 if p != nullrev]
3633 if opts.get('no_merges') and len(parents) == 2:
3634 if opts.get('no_merges') and len(parents) == 2:
3634 return
3635 return
3635 if opts.get('only_merges') and len(parents) != 2:
3636 if opts.get('only_merges') and len(parents) != 2:
3636 return
3637 return
3637 if opts.get('branch') and ctx.branch() not in opts['branch']:
3638 if opts.get('branch') and ctx.branch() not in opts['branch']:
3638 return
3639 return
3639 if not opts.get('hidden') and ctx.hidden():
3640 if not opts.get('hidden') and ctx.hidden():
3640 return
3641 return
3641 if df and not df(ctx.date()[0]):
3642 if df and not df(ctx.date()[0]):
3642 return
3643 return
3643 if opts['user'] and not [k for k in opts['user']
3644 if opts['user'] and not [k for k in opts['user']
3644 if k.lower() in ctx.user().lower()]:
3645 if k.lower() in ctx.user().lower()]:
3645 return
3646 return
3646 if opts.get('keyword'):
3647 if opts.get('keyword'):
3647 for k in [kw.lower() for kw in opts['keyword']]:
3648 for k in [kw.lower() for kw in opts['keyword']]:
3648 if (k in ctx.user().lower() or
3649 if (k in ctx.user().lower() or
3649 k in ctx.description().lower() or
3650 k in ctx.description().lower() or
3650 k in " ".join(ctx.files()).lower()):
3651 k in " ".join(ctx.files()).lower()):
3651 break
3652 break
3652 else:
3653 else:
3653 return
3654 return
3654
3655
3655 copies = None
3656 copies = None
3656 if opts.get('copies') and rev:
3657 if opts.get('copies') and rev:
3657 copies = []
3658 copies = []
3658 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3659 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3659 for fn in ctx.files():
3660 for fn in ctx.files():
3660 rename = getrenamed(fn, rev)
3661 rename = getrenamed(fn, rev)
3661 if rename:
3662 if rename:
3662 copies.append((fn, rename[0]))
3663 copies.append((fn, rename[0]))
3663
3664
3664 revmatchfn = None
3665 revmatchfn = None
3665 if opts.get('patch') or opts.get('stat'):
3666 if opts.get('patch') or opts.get('stat'):
3666 if opts.get('follow') or opts.get('follow_first'):
3667 if opts.get('follow') or opts.get('follow_first'):
3667 # note: this might be wrong when following through merges
3668 # note: this might be wrong when following through merges
3668 revmatchfn = scmutil.match(repo[None], fns, default='path')
3669 revmatchfn = scmutil.match(repo[None], fns, default='path')
3669 else:
3670 else:
3670 revmatchfn = matchfn
3671 revmatchfn = matchfn
3671
3672
3672 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3673 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3673
3674
3674 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3675 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3675 if count == limit:
3676 if count == limit:
3676 break
3677 break
3677 if displayer.flush(ctx.rev()):
3678 if displayer.flush(ctx.rev()):
3678 count += 1
3679 count += 1
3679 displayer.close()
3680 displayer.close()
3680
3681
3681 @command('manifest',
3682 @command('manifest',
3682 [('r', 'rev', '', _('revision to display'), _('REV')),
3683 [('r', 'rev', '', _('revision to display'), _('REV')),
3683 ('', 'all', False, _("list files from all revisions"))],
3684 ('', 'all', False, _("list files from all revisions"))],
3684 _('[-r REV]'))
3685 _('[-r REV]'))
3685 def manifest(ui, repo, node=None, rev=None, **opts):
3686 def manifest(ui, repo, node=None, rev=None, **opts):
3686 """output the current or given revision of the project manifest
3687 """output the current or given revision of the project manifest
3687
3688
3688 Print a list of version controlled files for the given revision.
3689 Print a list of version controlled files for the given revision.
3689 If no revision is given, the first parent of the working directory
3690 If no revision is given, the first parent of the working directory
3690 is used, or the null revision if no revision is checked out.
3691 is used, or the null revision if no revision is checked out.
3691
3692
3692 With -v, print file permissions, symlink and executable bits.
3693 With -v, print file permissions, symlink and executable bits.
3693 With --debug, print file revision hashes.
3694 With --debug, print file revision hashes.
3694
3695
3695 If option --all is specified, the list of all files from all revisions
3696 If option --all is specified, the list of all files from all revisions
3696 is printed. This includes deleted and renamed files.
3697 is printed. This includes deleted and renamed files.
3697
3698
3698 Returns 0 on success.
3699 Returns 0 on success.
3699 """
3700 """
3700 if opts.get('all'):
3701 if opts.get('all'):
3701 if rev or node:
3702 if rev or node:
3702 raise util.Abort(_("can't specify a revision with --all"))
3703 raise util.Abort(_("can't specify a revision with --all"))
3703
3704
3704 res = []
3705 res = []
3705 prefix = "data/"
3706 prefix = "data/"
3706 suffix = ".i"
3707 suffix = ".i"
3707 plen = len(prefix)
3708 plen = len(prefix)
3708 slen = len(suffix)
3709 slen = len(suffix)
3709 lock = repo.lock()
3710 lock = repo.lock()
3710 try:
3711 try:
3711 for fn, b, size in repo.store.datafiles():
3712 for fn, b, size in repo.store.datafiles():
3712 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3713 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3713 res.append(fn[plen:-slen])
3714 res.append(fn[plen:-slen])
3714 finally:
3715 finally:
3715 lock.release()
3716 lock.release()
3716 for f in sorted(res):
3717 for f in sorted(res):
3717 ui.write("%s\n" % f)
3718 ui.write("%s\n" % f)
3718 return
3719 return
3719
3720
3720 if rev and node:
3721 if rev and node:
3721 raise util.Abort(_("please specify just one revision"))
3722 raise util.Abort(_("please specify just one revision"))
3722
3723
3723 if not node:
3724 if not node:
3724 node = rev
3725 node = rev
3725
3726
3726 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3727 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3727 ctx = scmutil.revsingle(repo, node)
3728 ctx = scmutil.revsingle(repo, node)
3728 for f in ctx:
3729 for f in ctx:
3729 if ui.debugflag:
3730 if ui.debugflag:
3730 ui.write("%40s " % hex(ctx.manifest()[f]))
3731 ui.write("%40s " % hex(ctx.manifest()[f]))
3731 if ui.verbose:
3732 if ui.verbose:
3732 ui.write(decor[ctx.flags(f)])
3733 ui.write(decor[ctx.flags(f)])
3733 ui.write("%s\n" % f)
3734 ui.write("%s\n" % f)
3734
3735
3735 @command('^merge',
3736 @command('^merge',
3736 [('f', 'force', None, _('force a merge with outstanding changes')),
3737 [('f', 'force', None, _('force a merge with outstanding changes')),
3737 ('r', 'rev', '', _('revision to merge'), _('REV')),
3738 ('r', 'rev', '', _('revision to merge'), _('REV')),
3738 ('P', 'preview', None,
3739 ('P', 'preview', None,
3739 _('review revisions to merge (no merge is performed)'))
3740 _('review revisions to merge (no merge is performed)'))
3740 ] + mergetoolopts,
3741 ] + mergetoolopts,
3741 _('[-P] [-f] [[-r] REV]'))
3742 _('[-P] [-f] [[-r] REV]'))
3742 def merge(ui, repo, node=None, **opts):
3743 def merge(ui, repo, node=None, **opts):
3743 """merge working directory with another revision
3744 """merge working directory with another revision
3744
3745
3745 The current working directory is updated with all changes made in
3746 The current working directory is updated with all changes made in
3746 the requested revision since the last common predecessor revision.
3747 the requested revision since the last common predecessor revision.
3747
3748
3748 Files that changed between either parent are marked as changed for
3749 Files that changed between either parent are marked as changed for
3749 the next commit and a commit must be performed before any further
3750 the next commit and a commit must be performed before any further
3750 updates to the repository are allowed. The next commit will have
3751 updates to the repository are allowed. The next commit will have
3751 two parents.
3752 two parents.
3752
3753
3753 ``--tool`` can be used to specify the merge tool used for file
3754 ``--tool`` can be used to specify the merge tool used for file
3754 merges. It overrides the HGMERGE environment variable and your
3755 merges. It overrides the HGMERGE environment variable and your
3755 configuration files. See :hg:`help merge-tools` for options.
3756 configuration files. See :hg:`help merge-tools` for options.
3756
3757
3757 If no revision is specified, the working directory's parent is a
3758 If no revision is specified, the working directory's parent is a
3758 head revision, and the current branch contains exactly one other
3759 head revision, and the current branch contains exactly one other
3759 head, the other head is merged with by default. Otherwise, an
3760 head, the other head is merged with by default. Otherwise, an
3760 explicit revision with which to merge with must be provided.
3761 explicit revision with which to merge with must be provided.
3761
3762
3762 :hg:`resolve` must be used to resolve unresolved files.
3763 :hg:`resolve` must be used to resolve unresolved files.
3763
3764
3764 To undo an uncommitted merge, use :hg:`update --clean .` which
3765 To undo an uncommitted merge, use :hg:`update --clean .` which
3765 will check out a clean copy of the original merge parent, losing
3766 will check out a clean copy of the original merge parent, losing
3766 all changes.
3767 all changes.
3767
3768
3768 Returns 0 on success, 1 if there are unresolved files.
3769 Returns 0 on success, 1 if there are unresolved files.
3769 """
3770 """
3770
3771
3771 if opts.get('rev') and node:
3772 if opts.get('rev') and node:
3772 raise util.Abort(_("please specify just one revision"))
3773 raise util.Abort(_("please specify just one revision"))
3773 if not node:
3774 if not node:
3774 node = opts.get('rev')
3775 node = opts.get('rev')
3775
3776
3776 if not node:
3777 if not node:
3777 branch = repo[None].branch()
3778 branch = repo[None].branch()
3778 bheads = repo.branchheads(branch)
3779 bheads = repo.branchheads(branch)
3779 if len(bheads) > 2:
3780 if len(bheads) > 2:
3780 raise util.Abort(_("branch '%s' has %d heads - "
3781 raise util.Abort(_("branch '%s' has %d heads - "
3781 "please merge with an explicit rev")
3782 "please merge with an explicit rev")
3782 % (branch, len(bheads)),
3783 % (branch, len(bheads)),
3783 hint=_("run 'hg heads .' to see heads"))
3784 hint=_("run 'hg heads .' to see heads"))
3784
3785
3785 parent = repo.dirstate.p1()
3786 parent = repo.dirstate.p1()
3786 if len(bheads) == 1:
3787 if len(bheads) == 1:
3787 if len(repo.heads()) > 1:
3788 if len(repo.heads()) > 1:
3788 raise util.Abort(_("branch '%s' has one head - "
3789 raise util.Abort(_("branch '%s' has one head - "
3789 "please merge with an explicit rev")
3790 "please merge with an explicit rev")
3790 % branch,
3791 % branch,
3791 hint=_("run 'hg heads' to see all heads"))
3792 hint=_("run 'hg heads' to see all heads"))
3792 msg = _('there is nothing to merge')
3793 msg = _('there is nothing to merge')
3793 if parent != repo.lookup(repo[None].branch()):
3794 if parent != repo.lookup(repo[None].branch()):
3794 msg = _('%s - use "hg update" instead') % msg
3795 msg = _('%s - use "hg update" instead') % msg
3795 raise util.Abort(msg)
3796 raise util.Abort(msg)
3796
3797
3797 if parent not in bheads:
3798 if parent not in bheads:
3798 raise util.Abort(_('working directory not at a head revision'),
3799 raise util.Abort(_('working directory not at a head revision'),
3799 hint=_("use 'hg update' or merge with an "
3800 hint=_("use 'hg update' or merge with an "
3800 "explicit revision"))
3801 "explicit revision"))
3801 node = parent == bheads[0] and bheads[-1] or bheads[0]
3802 node = parent == bheads[0] and bheads[-1] or bheads[0]
3802 else:
3803 else:
3803 node = scmutil.revsingle(repo, node).node()
3804 node = scmutil.revsingle(repo, node).node()
3804
3805
3805 if opts.get('preview'):
3806 if opts.get('preview'):
3806 # find nodes that are ancestors of p2 but not of p1
3807 # find nodes that are ancestors of p2 but not of p1
3807 p1 = repo.lookup('.')
3808 p1 = repo.lookup('.')
3808 p2 = repo.lookup(node)
3809 p2 = repo.lookup(node)
3809 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3810 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3810
3811
3811 displayer = cmdutil.show_changeset(ui, repo, opts)
3812 displayer = cmdutil.show_changeset(ui, repo, opts)
3812 for node in nodes:
3813 for node in nodes:
3813 displayer.show(repo[node])
3814 displayer.show(repo[node])
3814 displayer.close()
3815 displayer.close()
3815 return 0
3816 return 0
3816
3817
3817 try:
3818 try:
3818 # ui.forcemerge is an internal variable, do not document
3819 # ui.forcemerge is an internal variable, do not document
3819 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3820 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3820 return hg.merge(repo, node, force=opts.get('force'))
3821 return hg.merge(repo, node, force=opts.get('force'))
3821 finally:
3822 finally:
3822 ui.setconfig('ui', 'forcemerge', '')
3823 ui.setconfig('ui', 'forcemerge', '')
3823
3824
3824 @command('outgoing|out',
3825 @command('outgoing|out',
3825 [('f', 'force', None, _('run even when the destination is unrelated')),
3826 [('f', 'force', None, _('run even when the destination is unrelated')),
3826 ('r', 'rev', [],
3827 ('r', 'rev', [],
3827 _('a changeset intended to be included in the destination'), _('REV')),
3828 _('a changeset intended to be included in the destination'), _('REV')),
3828 ('n', 'newest-first', None, _('show newest record first')),
3829 ('n', 'newest-first', None, _('show newest record first')),
3829 ('B', 'bookmarks', False, _('compare bookmarks')),
3830 ('B', 'bookmarks', False, _('compare bookmarks')),
3830 ('b', 'branch', [], _('a specific branch you would like to push'),
3831 ('b', 'branch', [], _('a specific branch you would like to push'),
3831 _('BRANCH')),
3832 _('BRANCH')),
3832 ] + logopts + remoteopts + subrepoopts,
3833 ] + logopts + remoteopts + subrepoopts,
3833 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3834 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3834 def outgoing(ui, repo, dest=None, **opts):
3835 def outgoing(ui, repo, dest=None, **opts):
3835 """show changesets not found in the destination
3836 """show changesets not found in the destination
3836
3837
3837 Show changesets not found in the specified destination repository
3838 Show changesets not found in the specified destination repository
3838 or the default push location. These are the changesets that would
3839 or the default push location. These are the changesets that would
3839 be pushed if a push was requested.
3840 be pushed if a push was requested.
3840
3841
3841 See pull for details of valid destination formats.
3842 See pull for details of valid destination formats.
3842
3843
3843 Returns 0 if there are outgoing changes, 1 otherwise.
3844 Returns 0 if there are outgoing changes, 1 otherwise.
3844 """
3845 """
3845
3846
3846 if opts.get('bookmarks'):
3847 if opts.get('bookmarks'):
3847 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3848 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3848 dest, branches = hg.parseurl(dest, opts.get('branch'))
3849 dest, branches = hg.parseurl(dest, opts.get('branch'))
3849 other = hg.peer(repo, opts, dest)
3850 other = hg.peer(repo, opts, dest)
3850 if 'bookmarks' not in other.listkeys('namespaces'):
3851 if 'bookmarks' not in other.listkeys('namespaces'):
3851 ui.warn(_("remote doesn't support bookmarks\n"))
3852 ui.warn(_("remote doesn't support bookmarks\n"))
3852 return 0
3853 return 0
3853 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3854 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3854 return bookmarks.diff(ui, other, repo)
3855 return bookmarks.diff(ui, other, repo)
3855
3856
3856 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3857 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3857 try:
3858 try:
3858 return hg.outgoing(ui, repo, dest, opts)
3859 return hg.outgoing(ui, repo, dest, opts)
3859 finally:
3860 finally:
3860 del repo._subtoppath
3861 del repo._subtoppath
3861
3862
3862 @command('parents',
3863 @command('parents',
3863 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3864 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3864 ] + templateopts,
3865 ] + templateopts,
3865 _('[-r REV] [FILE]'))
3866 _('[-r REV] [FILE]'))
3866 def parents(ui, repo, file_=None, **opts):
3867 def parents(ui, repo, file_=None, **opts):
3867 """show the parents of the working directory or revision
3868 """show the parents of the working directory or revision
3868
3869
3869 Print the working directory's parent revisions. If a revision is
3870 Print the working directory's parent revisions. If a revision is
3870 given via -r/--rev, the parent of that revision will be printed.
3871 given via -r/--rev, the parent of that revision will be printed.
3871 If a file argument is given, the revision in which the file was
3872 If a file argument is given, the revision in which the file was
3872 last changed (before the working directory revision or the
3873 last changed (before the working directory revision or the
3873 argument to --rev if given) is printed.
3874 argument to --rev if given) is printed.
3874
3875
3875 Returns 0 on success.
3876 Returns 0 on success.
3876 """
3877 """
3877
3878
3878 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3879 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3879
3880
3880 if file_:
3881 if file_:
3881 m = scmutil.match(ctx, (file_,), opts)
3882 m = scmutil.match(ctx, (file_,), opts)
3882 if m.anypats() or len(m.files()) != 1:
3883 if m.anypats() or len(m.files()) != 1:
3883 raise util.Abort(_('can only specify an explicit filename'))
3884 raise util.Abort(_('can only specify an explicit filename'))
3884 file_ = m.files()[0]
3885 file_ = m.files()[0]
3885 filenodes = []
3886 filenodes = []
3886 for cp in ctx.parents():
3887 for cp in ctx.parents():
3887 if not cp:
3888 if not cp:
3888 continue
3889 continue
3889 try:
3890 try:
3890 filenodes.append(cp.filenode(file_))
3891 filenodes.append(cp.filenode(file_))
3891 except error.LookupError:
3892 except error.LookupError:
3892 pass
3893 pass
3893 if not filenodes:
3894 if not filenodes:
3894 raise util.Abort(_("'%s' not found in manifest!") % file_)
3895 raise util.Abort(_("'%s' not found in manifest!") % file_)
3895 fl = repo.file(file_)
3896 fl = repo.file(file_)
3896 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3897 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
3897 else:
3898 else:
3898 p = [cp.node() for cp in ctx.parents()]
3899 p = [cp.node() for cp in ctx.parents()]
3899
3900
3900 displayer = cmdutil.show_changeset(ui, repo, opts)
3901 displayer = cmdutil.show_changeset(ui, repo, opts)
3901 for n in p:
3902 for n in p:
3902 if n != nullid:
3903 if n != nullid:
3903 displayer.show(repo[n])
3904 displayer.show(repo[n])
3904 displayer.close()
3905 displayer.close()
3905
3906
3906 @command('paths', [], _('[NAME]'))
3907 @command('paths', [], _('[NAME]'))
3907 def paths(ui, repo, search=None):
3908 def paths(ui, repo, search=None):
3908 """show aliases for remote repositories
3909 """show aliases for remote repositories
3909
3910
3910 Show definition of symbolic path name NAME. If no name is given,
3911 Show definition of symbolic path name NAME. If no name is given,
3911 show definition of all available names.
3912 show definition of all available names.
3912
3913
3913 Option -q/--quiet suppresses all output when searching for NAME
3914 Option -q/--quiet suppresses all output when searching for NAME
3914 and shows only the path names when listing all definitions.
3915 and shows only the path names when listing all definitions.
3915
3916
3916 Path names are defined in the [paths] section of your
3917 Path names are defined in the [paths] section of your
3917 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3918 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3918 repository, ``.hg/hgrc`` is used, too.
3919 repository, ``.hg/hgrc`` is used, too.
3919
3920
3920 The path names ``default`` and ``default-push`` have a special
3921 The path names ``default`` and ``default-push`` have a special
3921 meaning. When performing a push or pull operation, they are used
3922 meaning. When performing a push or pull operation, they are used
3922 as fallbacks if no location is specified on the command-line.
3923 as fallbacks if no location is specified on the command-line.
3923 When ``default-push`` is set, it will be used for push and
3924 When ``default-push`` is set, it will be used for push and
3924 ``default`` will be used for pull; otherwise ``default`` is used
3925 ``default`` will be used for pull; otherwise ``default`` is used
3925 as the fallback for both. When cloning a repository, the clone
3926 as the fallback for both. When cloning a repository, the clone
3926 source is written as ``default`` in ``.hg/hgrc``. Note that
3927 source is written as ``default`` in ``.hg/hgrc``. Note that
3927 ``default`` and ``default-push`` apply to all inbound (e.g.
3928 ``default`` and ``default-push`` apply to all inbound (e.g.
3928 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3929 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
3929 :hg:`bundle`) operations.
3930 :hg:`bundle`) operations.
3930
3931
3931 See :hg:`help urls` for more information.
3932 See :hg:`help urls` for more information.
3932
3933
3933 Returns 0 on success.
3934 Returns 0 on success.
3934 """
3935 """
3935 if search:
3936 if search:
3936 for name, path in ui.configitems("paths"):
3937 for name, path in ui.configitems("paths"):
3937 if name == search:
3938 if name == search:
3938 ui.status("%s\n" % util.hidepassword(path))
3939 ui.status("%s\n" % util.hidepassword(path))
3939 return
3940 return
3940 if not ui.quiet:
3941 if not ui.quiet:
3941 ui.warn(_("not found!\n"))
3942 ui.warn(_("not found!\n"))
3942 return 1
3943 return 1
3943 else:
3944 else:
3944 for name, path in ui.configitems("paths"):
3945 for name, path in ui.configitems("paths"):
3945 if ui.quiet:
3946 if ui.quiet:
3946 ui.write("%s\n" % name)
3947 ui.write("%s\n" % name)
3947 else:
3948 else:
3948 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3949 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
3949
3950
3950 def postincoming(ui, repo, modheads, optupdate, checkout):
3951 def postincoming(ui, repo, modheads, optupdate, checkout):
3951 if modheads == 0:
3952 if modheads == 0:
3952 return
3953 return
3953 if optupdate:
3954 if optupdate:
3954 try:
3955 try:
3955 return hg.update(repo, checkout)
3956 return hg.update(repo, checkout)
3956 except util.Abort, inst:
3957 except util.Abort, inst:
3957 ui.warn(_("not updating: %s\n" % str(inst)))
3958 ui.warn(_("not updating: %s\n" % str(inst)))
3958 return 0
3959 return 0
3959 if modheads > 1:
3960 if modheads > 1:
3960 currentbranchheads = len(repo.branchheads())
3961 currentbranchheads = len(repo.branchheads())
3961 if currentbranchheads == modheads:
3962 if currentbranchheads == modheads:
3962 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3963 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3963 elif currentbranchheads > 1:
3964 elif currentbranchheads > 1:
3964 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3965 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3965 else:
3966 else:
3966 ui.status(_("(run 'hg heads' to see heads)\n"))
3967 ui.status(_("(run 'hg heads' to see heads)\n"))
3967 else:
3968 else:
3968 ui.status(_("(run 'hg update' to get a working copy)\n"))
3969 ui.status(_("(run 'hg update' to get a working copy)\n"))
3969
3970
3970 @command('^pull',
3971 @command('^pull',
3971 [('u', 'update', None,
3972 [('u', 'update', None,
3972 _('update to new branch head if changesets were pulled')),
3973 _('update to new branch head if changesets were pulled')),
3973 ('f', 'force', None, _('run even when remote repository is unrelated')),
3974 ('f', 'force', None, _('run even when remote repository is unrelated')),
3974 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3975 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3975 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3976 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3976 ('b', 'branch', [], _('a specific branch you would like to pull'),
3977 ('b', 'branch', [], _('a specific branch you would like to pull'),
3977 _('BRANCH')),
3978 _('BRANCH')),
3978 ] + remoteopts,
3979 ] + remoteopts,
3979 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3980 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3980 def pull(ui, repo, source="default", **opts):
3981 def pull(ui, repo, source="default", **opts):
3981 """pull changes from the specified source
3982 """pull changes from the specified source
3982
3983
3983 Pull changes from a remote repository to a local one.
3984 Pull changes from a remote repository to a local one.
3984
3985
3985 This finds all changes from the repository at the specified path
3986 This finds all changes from the repository at the specified path
3986 or URL and adds them to a local repository (the current one unless
3987 or URL and adds them to a local repository (the current one unless
3987 -R is specified). By default, this does not update the copy of the
3988 -R is specified). By default, this does not update the copy of the
3988 project in the working directory.
3989 project in the working directory.
3989
3990
3990 Use :hg:`incoming` if you want to see what would have been added
3991 Use :hg:`incoming` if you want to see what would have been added
3991 by a pull at the time you issued this command. If you then decide
3992 by a pull at the time you issued this command. If you then decide
3992 to add those changes to the repository, you should use :hg:`pull
3993 to add those changes to the repository, you should use :hg:`pull
3993 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3994 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3994
3995
3995 If SOURCE is omitted, the 'default' path will be used.
3996 If SOURCE is omitted, the 'default' path will be used.
3996 See :hg:`help urls` for more information.
3997 See :hg:`help urls` for more information.
3997
3998
3998 Returns 0 on success, 1 if an update had unresolved files.
3999 Returns 0 on success, 1 if an update had unresolved files.
3999 """
4000 """
4000 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4001 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4001 other = hg.peer(repo, opts, source)
4002 other = hg.peer(repo, opts, source)
4002 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4003 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4003 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4004 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4004
4005
4005 if opts.get('bookmark'):
4006 if opts.get('bookmark'):
4006 if not revs:
4007 if not revs:
4007 revs = []
4008 revs = []
4008 rb = other.listkeys('bookmarks')
4009 rb = other.listkeys('bookmarks')
4009 for b in opts['bookmark']:
4010 for b in opts['bookmark']:
4010 if b not in rb:
4011 if b not in rb:
4011 raise util.Abort(_('remote bookmark %s not found!') % b)
4012 raise util.Abort(_('remote bookmark %s not found!') % b)
4012 revs.append(rb[b])
4013 revs.append(rb[b])
4013
4014
4014 if revs:
4015 if revs:
4015 try:
4016 try:
4016 revs = [other.lookup(rev) for rev in revs]
4017 revs = [other.lookup(rev) for rev in revs]
4017 except error.CapabilityError:
4018 except error.CapabilityError:
4018 err = _("other repository doesn't support revision lookup, "
4019 err = _("other repository doesn't support revision lookup, "
4019 "so a rev cannot be specified.")
4020 "so a rev cannot be specified.")
4020 raise util.Abort(err)
4021 raise util.Abort(err)
4021
4022
4022 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4023 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4023 bookmarks.updatefromremote(ui, repo, other)
4024 bookmarks.updatefromremote(ui, repo, other)
4024 if checkout:
4025 if checkout:
4025 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4026 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4026 repo._subtoppath = source
4027 repo._subtoppath = source
4027 try:
4028 try:
4028 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4029 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4029
4030
4030 finally:
4031 finally:
4031 del repo._subtoppath
4032 del repo._subtoppath
4032
4033
4033 # update specified bookmarks
4034 # update specified bookmarks
4034 if opts.get('bookmark'):
4035 if opts.get('bookmark'):
4035 for b in opts['bookmark']:
4036 for b in opts['bookmark']:
4036 # explicit pull overrides local bookmark if any
4037 # explicit pull overrides local bookmark if any
4037 ui.status(_("importing bookmark %s\n") % b)
4038 ui.status(_("importing bookmark %s\n") % b)
4038 repo._bookmarks[b] = repo[rb[b]].node()
4039 repo._bookmarks[b] = repo[rb[b]].node()
4039 bookmarks.write(repo)
4040 bookmarks.write(repo)
4040
4041
4041 return ret
4042 return ret
4042
4043
4043 @command('^push',
4044 @command('^push',
4044 [('f', 'force', None, _('force push')),
4045 [('f', 'force', None, _('force push')),
4045 ('r', 'rev', [],
4046 ('r', 'rev', [],
4046 _('a changeset intended to be included in the destination'),
4047 _('a changeset intended to be included in the destination'),
4047 _('REV')),
4048 _('REV')),
4048 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4049 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4049 ('b', 'branch', [],
4050 ('b', 'branch', [],
4050 _('a specific branch you would like to push'), _('BRANCH')),
4051 _('a specific branch you would like to push'), _('BRANCH')),
4051 ('', 'new-branch', False, _('allow pushing a new branch')),
4052 ('', 'new-branch', False, _('allow pushing a new branch')),
4052 ] + remoteopts,
4053 ] + remoteopts,
4053 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4054 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4054 def push(ui, repo, dest=None, **opts):
4055 def push(ui, repo, dest=None, **opts):
4055 """push changes to the specified destination
4056 """push changes to the specified destination
4056
4057
4057 Push changesets from the local repository to the specified
4058 Push changesets from the local repository to the specified
4058 destination.
4059 destination.
4059
4060
4060 This operation is symmetrical to pull: it is identical to a pull
4061 This operation is symmetrical to pull: it is identical to a pull
4061 in the destination repository from the current one.
4062 in the destination repository from the current one.
4062
4063
4063 By default, push will not allow creation of new heads at the
4064 By default, push will not allow creation of new heads at the
4064 destination, since multiple heads would make it unclear which head
4065 destination, since multiple heads would make it unclear which head
4065 to use. In this situation, it is recommended to pull and merge
4066 to use. In this situation, it is recommended to pull and merge
4066 before pushing.
4067 before pushing.
4067
4068
4068 Use --new-branch if you want to allow push to create a new named
4069 Use --new-branch if you want to allow push to create a new named
4069 branch that is not present at the destination. This allows you to
4070 branch that is not present at the destination. This allows you to
4070 only create a new branch without forcing other changes.
4071 only create a new branch without forcing other changes.
4071
4072
4072 Use -f/--force to override the default behavior and push all
4073 Use -f/--force to override the default behavior and push all
4073 changesets on all branches.
4074 changesets on all branches.
4074
4075
4075 If -r/--rev is used, the specified revision and all its ancestors
4076 If -r/--rev is used, the specified revision and all its ancestors
4076 will be pushed to the remote repository.
4077 will be pushed to the remote repository.
4077
4078
4078 Please see :hg:`help urls` for important details about ``ssh://``
4079 Please see :hg:`help urls` for important details about ``ssh://``
4079 URLs. If DESTINATION is omitted, a default path will be used.
4080 URLs. If DESTINATION is omitted, a default path will be used.
4080
4081
4081 Returns 0 if push was successful, 1 if nothing to push.
4082 Returns 0 if push was successful, 1 if nothing to push.
4082 """
4083 """
4083
4084
4084 if opts.get('bookmark'):
4085 if opts.get('bookmark'):
4085 for b in opts['bookmark']:
4086 for b in opts['bookmark']:
4086 # translate -B options to -r so changesets get pushed
4087 # translate -B options to -r so changesets get pushed
4087 if b in repo._bookmarks:
4088 if b in repo._bookmarks:
4088 opts.setdefault('rev', []).append(b)
4089 opts.setdefault('rev', []).append(b)
4089 else:
4090 else:
4090 # if we try to push a deleted bookmark, translate it to null
4091 # if we try to push a deleted bookmark, translate it to null
4091 # this lets simultaneous -r, -b options continue working
4092 # this lets simultaneous -r, -b options continue working
4092 opts.setdefault('rev', []).append("null")
4093 opts.setdefault('rev', []).append("null")
4093
4094
4094 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4095 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4095 dest, branches = hg.parseurl(dest, opts.get('branch'))
4096 dest, branches = hg.parseurl(dest, opts.get('branch'))
4096 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4097 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4097 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4098 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4098 other = hg.peer(repo, opts, dest)
4099 other = hg.peer(repo, opts, dest)
4099 if revs:
4100 if revs:
4100 revs = [repo.lookup(rev) for rev in revs]
4101 revs = [repo.lookup(rev) for rev in revs]
4101
4102
4102 repo._subtoppath = dest
4103 repo._subtoppath = dest
4103 try:
4104 try:
4104 # push subrepos depth-first for coherent ordering
4105 # push subrepos depth-first for coherent ordering
4105 c = repo['']
4106 c = repo['']
4106 subs = c.substate # only repos that are committed
4107 subs = c.substate # only repos that are committed
4107 for s in sorted(subs):
4108 for s in sorted(subs):
4108 if not c.sub(s).push(opts.get('force')):
4109 if not c.sub(s).push(opts.get('force')):
4109 return False
4110 return False
4110 finally:
4111 finally:
4111 del repo._subtoppath
4112 del repo._subtoppath
4112 result = repo.push(other, opts.get('force'), revs=revs,
4113 result = repo.push(other, opts.get('force'), revs=revs,
4113 newbranch=opts.get('new_branch'))
4114 newbranch=opts.get('new_branch'))
4114
4115
4115 result = (result == 0)
4116 result = (result == 0)
4116
4117
4117 if opts.get('bookmark'):
4118 if opts.get('bookmark'):
4118 rb = other.listkeys('bookmarks')
4119 rb = other.listkeys('bookmarks')
4119 for b in opts['bookmark']:
4120 for b in opts['bookmark']:
4120 # explicit push overrides remote bookmark if any
4121 # explicit push overrides remote bookmark if any
4121 if b in repo._bookmarks:
4122 if b in repo._bookmarks:
4122 ui.status(_("exporting bookmark %s\n") % b)
4123 ui.status(_("exporting bookmark %s\n") % b)
4123 new = repo[b].hex()
4124 new = repo[b].hex()
4124 elif b in rb:
4125 elif b in rb:
4125 ui.status(_("deleting remote bookmark %s\n") % b)
4126 ui.status(_("deleting remote bookmark %s\n") % b)
4126 new = '' # delete
4127 new = '' # delete
4127 else:
4128 else:
4128 ui.warn(_('bookmark %s does not exist on the local '
4129 ui.warn(_('bookmark %s does not exist on the local '
4129 'or remote repository!\n') % b)
4130 'or remote repository!\n') % b)
4130 return 2
4131 return 2
4131 old = rb.get(b, '')
4132 old = rb.get(b, '')
4132 r = other.pushkey('bookmarks', b, old, new)
4133 r = other.pushkey('bookmarks', b, old, new)
4133 if not r:
4134 if not r:
4134 ui.warn(_('updating bookmark %s failed!\n') % b)
4135 ui.warn(_('updating bookmark %s failed!\n') % b)
4135 if not result:
4136 if not result:
4136 result = 2
4137 result = 2
4137
4138
4138 return result
4139 return result
4139
4140
4140 @command('recover', [])
4141 @command('recover', [])
4141 def recover(ui, repo):
4142 def recover(ui, repo):
4142 """roll back an interrupted transaction
4143 """roll back an interrupted transaction
4143
4144
4144 Recover from an interrupted commit or pull.
4145 Recover from an interrupted commit or pull.
4145
4146
4146 This command tries to fix the repository status after an
4147 This command tries to fix the repository status after an
4147 interrupted operation. It should only be necessary when Mercurial
4148 interrupted operation. It should only be necessary when Mercurial
4148 suggests it.
4149 suggests it.
4149
4150
4150 Returns 0 if successful, 1 if nothing to recover or verify fails.
4151 Returns 0 if successful, 1 if nothing to recover or verify fails.
4151 """
4152 """
4152 if repo.recover():
4153 if repo.recover():
4153 return hg.verify(repo)
4154 return hg.verify(repo)
4154 return 1
4155 return 1
4155
4156
4156 @command('^remove|rm',
4157 @command('^remove|rm',
4157 [('A', 'after', None, _('record delete for missing files')),
4158 [('A', 'after', None, _('record delete for missing files')),
4158 ('f', 'force', None,
4159 ('f', 'force', None,
4159 _('remove (and delete) file even if added or modified')),
4160 _('remove (and delete) file even if added or modified')),
4160 ] + walkopts,
4161 ] + walkopts,
4161 _('[OPTION]... FILE...'))
4162 _('[OPTION]... FILE...'))
4162 def remove(ui, repo, *pats, **opts):
4163 def remove(ui, repo, *pats, **opts):
4163 """remove the specified files on the next commit
4164 """remove the specified files on the next commit
4164
4165
4165 Schedule the indicated files for removal from the current branch.
4166 Schedule the indicated files for removal from the current branch.
4166
4167
4167 This command schedules the files to be removed at the next commit.
4168 This command schedules the files to be removed at the next commit.
4168 To undo a remove before that, see :hg:`revert`. To undo added
4169 To undo a remove before that, see :hg:`revert`. To undo added
4169 files, see :hg:`forget`.
4170 files, see :hg:`forget`.
4170
4171
4171 .. container:: verbose
4172 .. container:: verbose
4172
4173
4173 -A/--after can be used to remove only files that have already
4174 -A/--after can be used to remove only files that have already
4174 been deleted, -f/--force can be used to force deletion, and -Af
4175 been deleted, -f/--force can be used to force deletion, and -Af
4175 can be used to remove files from the next revision without
4176 can be used to remove files from the next revision without
4176 deleting them from the working directory.
4177 deleting them from the working directory.
4177
4178
4178 The following table details the behavior of remove for different
4179 The following table details the behavior of remove for different
4179 file states (columns) and option combinations (rows). The file
4180 file states (columns) and option combinations (rows). The file
4180 states are Added [A], Clean [C], Modified [M] and Missing [!]
4181 states are Added [A], Clean [C], Modified [M] and Missing [!]
4181 (as reported by :hg:`status`). The actions are Warn, Remove
4182 (as reported by :hg:`status`). The actions are Warn, Remove
4182 (from branch) and Delete (from disk):
4183 (from branch) and Delete (from disk):
4183
4184
4184 ======= == == == ==
4185 ======= == == == ==
4185 A C M !
4186 A C M !
4186 ======= == == == ==
4187 ======= == == == ==
4187 none W RD W R
4188 none W RD W R
4188 -f R RD RD R
4189 -f R RD RD R
4189 -A W W W R
4190 -A W W W R
4190 -Af R R R R
4191 -Af R R R R
4191 ======= == == == ==
4192 ======= == == == ==
4192
4193
4193 Note that remove never deletes files in Added [A] state from the
4194 Note that remove never deletes files in Added [A] state from the
4194 working directory, not even if option --force is specified.
4195 working directory, not even if option --force is specified.
4195
4196
4196 Returns 0 on success, 1 if any warnings encountered.
4197 Returns 0 on success, 1 if any warnings encountered.
4197 """
4198 """
4198
4199
4199 ret = 0
4200 ret = 0
4200 after, force = opts.get('after'), opts.get('force')
4201 after, force = opts.get('after'), opts.get('force')
4201 if not pats and not after:
4202 if not pats and not after:
4202 raise util.Abort(_('no files specified'))
4203 raise util.Abort(_('no files specified'))
4203
4204
4204 m = scmutil.match(repo[None], pats, opts)
4205 m = scmutil.match(repo[None], pats, opts)
4205 s = repo.status(match=m, clean=True)
4206 s = repo.status(match=m, clean=True)
4206 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4207 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4207
4208
4208 for f in m.files():
4209 for f in m.files():
4209 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4210 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4210 if os.path.exists(m.rel(f)):
4211 if os.path.exists(m.rel(f)):
4211 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4212 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4212 ret = 1
4213 ret = 1
4213
4214
4214 if force:
4215 if force:
4215 list = modified + deleted + clean + added
4216 list = modified + deleted + clean + added
4216 elif after:
4217 elif after:
4217 list = deleted
4218 list = deleted
4218 for f in modified + added + clean:
4219 for f in modified + added + clean:
4219 ui.warn(_('not removing %s: file still exists (use -f'
4220 ui.warn(_('not removing %s: file still exists (use -f'
4220 ' to force removal)\n') % m.rel(f))
4221 ' to force removal)\n') % m.rel(f))
4221 ret = 1
4222 ret = 1
4222 else:
4223 else:
4223 list = deleted + clean
4224 list = deleted + clean
4224 for f in modified:
4225 for f in modified:
4225 ui.warn(_('not removing %s: file is modified (use -f'
4226 ui.warn(_('not removing %s: file is modified (use -f'
4226 ' to force removal)\n') % m.rel(f))
4227 ' to force removal)\n') % m.rel(f))
4227 ret = 1
4228 ret = 1
4228 for f in added:
4229 for f in added:
4229 ui.warn(_('not removing %s: file has been marked for add'
4230 ui.warn(_('not removing %s: file has been marked for add'
4230 ' (use forget to undo)\n') % m.rel(f))
4231 ' (use forget to undo)\n') % m.rel(f))
4231 ret = 1
4232 ret = 1
4232
4233
4233 for f in sorted(list):
4234 for f in sorted(list):
4234 if ui.verbose or not m.exact(f):
4235 if ui.verbose or not m.exact(f):
4235 ui.status(_('removing %s\n') % m.rel(f))
4236 ui.status(_('removing %s\n') % m.rel(f))
4236
4237
4237 wlock = repo.wlock()
4238 wlock = repo.wlock()
4238 try:
4239 try:
4239 if not after:
4240 if not after:
4240 for f in list:
4241 for f in list:
4241 if f in added:
4242 if f in added:
4242 continue # we never unlink added files on remove
4243 continue # we never unlink added files on remove
4243 try:
4244 try:
4244 util.unlinkpath(repo.wjoin(f))
4245 util.unlinkpath(repo.wjoin(f))
4245 except OSError, inst:
4246 except OSError, inst:
4246 if inst.errno != errno.ENOENT:
4247 if inst.errno != errno.ENOENT:
4247 raise
4248 raise
4248 repo[None].forget(list)
4249 repo[None].forget(list)
4249 finally:
4250 finally:
4250 wlock.release()
4251 wlock.release()
4251
4252
4252 return ret
4253 return ret
4253
4254
4254 @command('rename|move|mv',
4255 @command('rename|move|mv',
4255 [('A', 'after', None, _('record a rename that has already occurred')),
4256 [('A', 'after', None, _('record a rename that has already occurred')),
4256 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4257 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4257 ] + walkopts + dryrunopts,
4258 ] + walkopts + dryrunopts,
4258 _('[OPTION]... SOURCE... DEST'))
4259 _('[OPTION]... SOURCE... DEST'))
4259 def rename(ui, repo, *pats, **opts):
4260 def rename(ui, repo, *pats, **opts):
4260 """rename files; equivalent of copy + remove
4261 """rename files; equivalent of copy + remove
4261
4262
4262 Mark dest as copies of sources; mark sources for deletion. If dest
4263 Mark dest as copies of sources; mark sources for deletion. If dest
4263 is a directory, copies are put in that directory. If dest is a
4264 is a directory, copies are put in that directory. If dest is a
4264 file, there can only be one source.
4265 file, there can only be one source.
4265
4266
4266 By default, this command copies the contents of files as they
4267 By default, this command copies the contents of files as they
4267 exist in the working directory. If invoked with -A/--after, the
4268 exist in the working directory. If invoked with -A/--after, the
4268 operation is recorded, but no copying is performed.
4269 operation is recorded, but no copying is performed.
4269
4270
4270 This command takes effect at the next commit. To undo a rename
4271 This command takes effect at the next commit. To undo a rename
4271 before that, see :hg:`revert`.
4272 before that, see :hg:`revert`.
4272
4273
4273 Returns 0 on success, 1 if errors are encountered.
4274 Returns 0 on success, 1 if errors are encountered.
4274 """
4275 """
4275 wlock = repo.wlock(False)
4276 wlock = repo.wlock(False)
4276 try:
4277 try:
4277 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4278 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4278 finally:
4279 finally:
4279 wlock.release()
4280 wlock.release()
4280
4281
4281 @command('resolve',
4282 @command('resolve',
4282 [('a', 'all', None, _('select all unresolved files')),
4283 [('a', 'all', None, _('select all unresolved files')),
4283 ('l', 'list', None, _('list state of files needing merge')),
4284 ('l', 'list', None, _('list state of files needing merge')),
4284 ('m', 'mark', None, _('mark files as resolved')),
4285 ('m', 'mark', None, _('mark files as resolved')),
4285 ('u', 'unmark', None, _('mark files as unresolved')),
4286 ('u', 'unmark', None, _('mark files as unresolved')),
4286 ('n', 'no-status', None, _('hide status prefix'))]
4287 ('n', 'no-status', None, _('hide status prefix'))]
4287 + mergetoolopts + walkopts,
4288 + mergetoolopts + walkopts,
4288 _('[OPTION]... [FILE]...'))
4289 _('[OPTION]... [FILE]...'))
4289 def resolve(ui, repo, *pats, **opts):
4290 def resolve(ui, repo, *pats, **opts):
4290 """redo merges or set/view the merge status of files
4291 """redo merges or set/view the merge status of files
4291
4292
4292 Merges with unresolved conflicts are often the result of
4293 Merges with unresolved conflicts are often the result of
4293 non-interactive merging using the ``internal:merge`` configuration
4294 non-interactive merging using the ``internal:merge`` configuration
4294 setting, or a command-line merge tool like ``diff3``. The resolve
4295 setting, or a command-line merge tool like ``diff3``. The resolve
4295 command is used to manage the files involved in a merge, after
4296 command is used to manage the files involved in a merge, after
4296 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4297 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4297 working directory must have two parents).
4298 working directory must have two parents).
4298
4299
4299 The resolve command can be used in the following ways:
4300 The resolve command can be used in the following ways:
4300
4301
4301 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4302 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4302 files, discarding any previous merge attempts. Re-merging is not
4303 files, discarding any previous merge attempts. Re-merging is not
4303 performed for files already marked as resolved. Use ``--all/-a``
4304 performed for files already marked as resolved. Use ``--all/-a``
4304 to select all unresolved files. ``--tool`` can be used to specify
4305 to select all unresolved files. ``--tool`` can be used to specify
4305 the merge tool used for the given files. It overrides the HGMERGE
4306 the merge tool used for the given files. It overrides the HGMERGE
4306 environment variable and your configuration files.
4307 environment variable and your configuration files.
4307
4308
4308 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4309 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4309 (e.g. after having manually fixed-up the files). The default is
4310 (e.g. after having manually fixed-up the files). The default is
4310 to mark all unresolved files.
4311 to mark all unresolved files.
4311
4312
4312 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4313 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4313 default is to mark all resolved files.
4314 default is to mark all resolved files.
4314
4315
4315 - :hg:`resolve -l`: list files which had or still have conflicts.
4316 - :hg:`resolve -l`: list files which had or still have conflicts.
4316 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4317 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4317
4318
4318 Note that Mercurial will not let you commit files with unresolved
4319 Note that Mercurial will not let you commit files with unresolved
4319 merge conflicts. You must use :hg:`resolve -m ...` before you can
4320 merge conflicts. You must use :hg:`resolve -m ...` before you can
4320 commit after a conflicting merge.
4321 commit after a conflicting merge.
4321
4322
4322 Returns 0 on success, 1 if any files fail a resolve attempt.
4323 Returns 0 on success, 1 if any files fail a resolve attempt.
4323 """
4324 """
4324
4325
4325 all, mark, unmark, show, nostatus = \
4326 all, mark, unmark, show, nostatus = \
4326 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4327 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4327
4328
4328 if (show and (mark or unmark)) or (mark and unmark):
4329 if (show and (mark or unmark)) or (mark and unmark):
4329 raise util.Abort(_("too many options specified"))
4330 raise util.Abort(_("too many options specified"))
4330 if pats and all:
4331 if pats and all:
4331 raise util.Abort(_("can't specify --all and patterns"))
4332 raise util.Abort(_("can't specify --all and patterns"))
4332 if not (all or pats or show or mark or unmark):
4333 if not (all or pats or show or mark or unmark):
4333 raise util.Abort(_('no files or directories specified; '
4334 raise util.Abort(_('no files or directories specified; '
4334 'use --all to remerge all files'))
4335 'use --all to remerge all files'))
4335
4336
4336 ms = mergemod.mergestate(repo)
4337 ms = mergemod.mergestate(repo)
4337 m = scmutil.match(repo[None], pats, opts)
4338 m = scmutil.match(repo[None], pats, opts)
4338 ret = 0
4339 ret = 0
4339
4340
4340 for f in ms:
4341 for f in ms:
4341 if m(f):
4342 if m(f):
4342 if show:
4343 if show:
4343 if nostatus:
4344 if nostatus:
4344 ui.write("%s\n" % f)
4345 ui.write("%s\n" % f)
4345 else:
4346 else:
4346 ui.write("%s %s\n" % (ms[f].upper(), f),
4347 ui.write("%s %s\n" % (ms[f].upper(), f),
4347 label='resolve.' +
4348 label='resolve.' +
4348 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4349 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4349 elif mark:
4350 elif mark:
4350 ms.mark(f, "r")
4351 ms.mark(f, "r")
4351 elif unmark:
4352 elif unmark:
4352 ms.mark(f, "u")
4353 ms.mark(f, "u")
4353 else:
4354 else:
4354 wctx = repo[None]
4355 wctx = repo[None]
4355 mctx = wctx.parents()[-1]
4356 mctx = wctx.parents()[-1]
4356
4357
4357 # backup pre-resolve (merge uses .orig for its own purposes)
4358 # backup pre-resolve (merge uses .orig for its own purposes)
4358 a = repo.wjoin(f)
4359 a = repo.wjoin(f)
4359 util.copyfile(a, a + ".resolve")
4360 util.copyfile(a, a + ".resolve")
4360
4361
4361 try:
4362 try:
4362 # resolve file
4363 # resolve file
4363 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4364 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4364 if ms.resolve(f, wctx, mctx):
4365 if ms.resolve(f, wctx, mctx):
4365 ret = 1
4366 ret = 1
4366 finally:
4367 finally:
4367 ui.setconfig('ui', 'forcemerge', '')
4368 ui.setconfig('ui', 'forcemerge', '')
4368
4369
4369 # replace filemerge's .orig file with our resolve file
4370 # replace filemerge's .orig file with our resolve file
4370 util.rename(a + ".resolve", a + ".orig")
4371 util.rename(a + ".resolve", a + ".orig")
4371
4372
4372 ms.commit()
4373 ms.commit()
4373 return ret
4374 return ret
4374
4375
4375 @command('revert',
4376 @command('revert',
4376 [('a', 'all', None, _('revert all changes when no arguments given')),
4377 [('a', 'all', None, _('revert all changes when no arguments given')),
4377 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4378 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4378 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4379 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4379 ('C', 'no-backup', None, _('do not save backup copies of files')),
4380 ('C', 'no-backup', None, _('do not save backup copies of files')),
4380 ] + walkopts + dryrunopts,
4381 ] + walkopts + dryrunopts,
4381 _('[OPTION]... [-r REV] [NAME]...'))
4382 _('[OPTION]... [-r REV] [NAME]...'))
4382 def revert(ui, repo, *pats, **opts):
4383 def revert(ui, repo, *pats, **opts):
4383 """restore files to their checkout state
4384 """restore files to their checkout state
4384
4385
4385 .. note::
4386 .. note::
4386 To check out earlier revisions, you should use :hg:`update REV`.
4387 To check out earlier revisions, you should use :hg:`update REV`.
4387 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4388 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4388
4389
4389 With no revision specified, revert the specified files or directories
4390 With no revision specified, revert the specified files or directories
4390 to the contents they had in the parent of the working directory.
4391 to the contents they had in the parent of the working directory.
4391 This restores the contents of files to an unmodified
4392 This restores the contents of files to an unmodified
4392 state and unschedules adds, removes, copies, and renames. If the
4393 state and unschedules adds, removes, copies, and renames. If the
4393 working directory has two parents, you must explicitly specify a
4394 working directory has two parents, you must explicitly specify a
4394 revision.
4395 revision.
4395
4396
4396 Using the -r/--rev or -d/--date options, revert the given files or
4397 Using the -r/--rev or -d/--date options, revert the given files or
4397 directories to their states as of a specific revision. Because
4398 directories to their states as of a specific revision. Because
4398 revert does not change the working directory parents, this will
4399 revert does not change the working directory parents, this will
4399 cause these files to appear modified. This can be helpful to "back
4400 cause these files to appear modified. This can be helpful to "back
4400 out" some or all of an earlier change. See :hg:`backout` for a
4401 out" some or all of an earlier change. See :hg:`backout` for a
4401 related method.
4402 related method.
4402
4403
4403 Modified files are saved with a .orig suffix before reverting.
4404 Modified files are saved with a .orig suffix before reverting.
4404 To disable these backups, use --no-backup.
4405 To disable these backups, use --no-backup.
4405
4406
4406 See :hg:`help dates` for a list of formats valid for -d/--date.
4407 See :hg:`help dates` for a list of formats valid for -d/--date.
4407
4408
4408 Returns 0 on success.
4409 Returns 0 on success.
4409 """
4410 """
4410
4411
4411 if opts.get("date"):
4412 if opts.get("date"):
4412 if opts.get("rev"):
4413 if opts.get("rev"):
4413 raise util.Abort(_("you can't specify a revision and a date"))
4414 raise util.Abort(_("you can't specify a revision and a date"))
4414 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4415 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4415
4416
4416 parent, p2 = repo.dirstate.parents()
4417 parent, p2 = repo.dirstate.parents()
4417 if not opts.get('rev') and p2 != nullid:
4418 if not opts.get('rev') and p2 != nullid:
4418 # revert after merge is a trap for new users (issue2915)
4419 # revert after merge is a trap for new users (issue2915)
4419 raise util.Abort(_('uncommitted merge with no revision specified'),
4420 raise util.Abort(_('uncommitted merge with no revision specified'),
4420 hint=_('use "hg update" or see "hg help revert"'))
4421 hint=_('use "hg update" or see "hg help revert"'))
4421
4422
4422 ctx = scmutil.revsingle(repo, opts.get('rev'))
4423 ctx = scmutil.revsingle(repo, opts.get('rev'))
4423 node = ctx.node()
4424 node = ctx.node()
4424
4425
4425 if not pats and not opts.get('all'):
4426 if not pats and not opts.get('all'):
4426 msg = _("no files or directories specified")
4427 msg = _("no files or directories specified")
4427 if p2 != nullid:
4428 if p2 != nullid:
4428 hint = _("uncommitted merge, use --all to discard all changes,"
4429 hint = _("uncommitted merge, use --all to discard all changes,"
4429 " or 'hg update -C .' to abort the merge")
4430 " or 'hg update -C .' to abort the merge")
4430 raise util.Abort(msg, hint=hint)
4431 raise util.Abort(msg, hint=hint)
4431 dirty = util.any(repo.status())
4432 dirty = util.any(repo.status())
4432 if node != parent:
4433 if node != parent:
4433 if dirty:
4434 if dirty:
4434 hint = _("uncommitted changes, use --all to discard all"
4435 hint = _("uncommitted changes, use --all to discard all"
4435 " changes, or 'hg update %s' to update") % ctx.rev()
4436 " changes, or 'hg update %s' to update") % ctx.rev()
4436 else:
4437 else:
4437 hint = _("use --all to revert all files,"
4438 hint = _("use --all to revert all files,"
4438 " or 'hg update %s' to update") % ctx.rev()
4439 " or 'hg update %s' to update") % ctx.rev()
4439 elif dirty:
4440 elif dirty:
4440 hint = _("uncommitted changes, use --all to discard all changes")
4441 hint = _("uncommitted changes, use --all to discard all changes")
4441 else:
4442 else:
4442 hint = _("use --all to revert all files")
4443 hint = _("use --all to revert all files")
4443 raise util.Abort(msg, hint=hint)
4444 raise util.Abort(msg, hint=hint)
4444
4445
4445 mf = ctx.manifest()
4446 mf = ctx.manifest()
4446 if node == parent:
4447 if node == parent:
4447 pmf = mf
4448 pmf = mf
4448 else:
4449 else:
4449 pmf = None
4450 pmf = None
4450
4451
4451 # need all matching names in dirstate and manifest of target rev,
4452 # need all matching names in dirstate and manifest of target rev,
4452 # so have to walk both. do not print errors if files exist in one
4453 # so have to walk both. do not print errors if files exist in one
4453 # but not other.
4454 # but not other.
4454
4455
4455 names = {}
4456 names = {}
4456
4457
4457 wlock = repo.wlock()
4458 wlock = repo.wlock()
4458 try:
4459 try:
4459 # walk dirstate.
4460 # walk dirstate.
4460
4461
4461 m = scmutil.match(repo[None], pats, opts)
4462 m = scmutil.match(repo[None], pats, opts)
4462 m.bad = lambda x, y: False
4463 m.bad = lambda x, y: False
4463 for abs in repo.walk(m):
4464 for abs in repo.walk(m):
4464 names[abs] = m.rel(abs), m.exact(abs)
4465 names[abs] = m.rel(abs), m.exact(abs)
4465
4466
4466 # walk target manifest.
4467 # walk target manifest.
4467
4468
4468 def badfn(path, msg):
4469 def badfn(path, msg):
4469 if path in names:
4470 if path in names:
4470 return
4471 return
4471 path_ = path + '/'
4472 path_ = path + '/'
4472 for f in names:
4473 for f in names:
4473 if f.startswith(path_):
4474 if f.startswith(path_):
4474 return
4475 return
4475 ui.warn("%s: %s\n" % (m.rel(path), msg))
4476 ui.warn("%s: %s\n" % (m.rel(path), msg))
4476
4477
4477 m = scmutil.match(repo[node], pats, opts)
4478 m = scmutil.match(repo[node], pats, opts)
4478 m.bad = badfn
4479 m.bad = badfn
4479 for abs in repo[node].walk(m):
4480 for abs in repo[node].walk(m):
4480 if abs not in names:
4481 if abs not in names:
4481 names[abs] = m.rel(abs), m.exact(abs)
4482 names[abs] = m.rel(abs), m.exact(abs)
4482
4483
4483 m = scmutil.matchfiles(repo, names)
4484 m = scmutil.matchfiles(repo, names)
4484 changes = repo.status(match=m)[:4]
4485 changes = repo.status(match=m)[:4]
4485 modified, added, removed, deleted = map(set, changes)
4486 modified, added, removed, deleted = map(set, changes)
4486
4487
4487 # if f is a rename, also revert the source
4488 # if f is a rename, also revert the source
4488 cwd = repo.getcwd()
4489 cwd = repo.getcwd()
4489 for f in added:
4490 for f in added:
4490 src = repo.dirstate.copied(f)
4491 src = repo.dirstate.copied(f)
4491 if src and src not in names and repo.dirstate[src] == 'r':
4492 if src and src not in names and repo.dirstate[src] == 'r':
4492 removed.add(src)
4493 removed.add(src)
4493 names[src] = (repo.pathto(src, cwd), True)
4494 names[src] = (repo.pathto(src, cwd), True)
4494
4495
4495 def removeforget(abs):
4496 def removeforget(abs):
4496 if repo.dirstate[abs] == 'a':
4497 if repo.dirstate[abs] == 'a':
4497 return _('forgetting %s\n')
4498 return _('forgetting %s\n')
4498 return _('removing %s\n')
4499 return _('removing %s\n')
4499
4500
4500 revert = ([], _('reverting %s\n'))
4501 revert = ([], _('reverting %s\n'))
4501 add = ([], _('adding %s\n'))
4502 add = ([], _('adding %s\n'))
4502 remove = ([], removeforget)
4503 remove = ([], removeforget)
4503 undelete = ([], _('undeleting %s\n'))
4504 undelete = ([], _('undeleting %s\n'))
4504
4505
4505 disptable = (
4506 disptable = (
4506 # dispatch table:
4507 # dispatch table:
4507 # file state
4508 # file state
4508 # action if in target manifest
4509 # action if in target manifest
4509 # action if not in target manifest
4510 # action if not in target manifest
4510 # make backup if in target manifest
4511 # make backup if in target manifest
4511 # make backup if not in target manifest
4512 # make backup if not in target manifest
4512 (modified, revert, remove, True, True),
4513 (modified, revert, remove, True, True),
4513 (added, revert, remove, True, False),
4514 (added, revert, remove, True, False),
4514 (removed, undelete, None, False, False),
4515 (removed, undelete, None, False, False),
4515 (deleted, revert, remove, False, False),
4516 (deleted, revert, remove, False, False),
4516 )
4517 )
4517
4518
4518 for abs, (rel, exact) in sorted(names.items()):
4519 for abs, (rel, exact) in sorted(names.items()):
4519 mfentry = mf.get(abs)
4520 mfentry = mf.get(abs)
4520 target = repo.wjoin(abs)
4521 target = repo.wjoin(abs)
4521 def handle(xlist, dobackup):
4522 def handle(xlist, dobackup):
4522 xlist[0].append(abs)
4523 xlist[0].append(abs)
4523 if (dobackup and not opts.get('no_backup') and
4524 if (dobackup and not opts.get('no_backup') and
4524 os.path.lexists(target)):
4525 os.path.lexists(target)):
4525 bakname = "%s.orig" % rel
4526 bakname = "%s.orig" % rel
4526 ui.note(_('saving current version of %s as %s\n') %
4527 ui.note(_('saving current version of %s as %s\n') %
4527 (rel, bakname))
4528 (rel, bakname))
4528 if not opts.get('dry_run'):
4529 if not opts.get('dry_run'):
4529 util.rename(target, bakname)
4530 util.rename(target, bakname)
4530 if ui.verbose or not exact:
4531 if ui.verbose or not exact:
4531 msg = xlist[1]
4532 msg = xlist[1]
4532 if not isinstance(msg, basestring):
4533 if not isinstance(msg, basestring):
4533 msg = msg(abs)
4534 msg = msg(abs)
4534 ui.status(msg % rel)
4535 ui.status(msg % rel)
4535 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4536 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4536 if abs not in table:
4537 if abs not in table:
4537 continue
4538 continue
4538 # file has changed in dirstate
4539 # file has changed in dirstate
4539 if mfentry:
4540 if mfentry:
4540 handle(hitlist, backuphit)
4541 handle(hitlist, backuphit)
4541 elif misslist is not None:
4542 elif misslist is not None:
4542 handle(misslist, backupmiss)
4543 handle(misslist, backupmiss)
4543 break
4544 break
4544 else:
4545 else:
4545 if abs not in repo.dirstate:
4546 if abs not in repo.dirstate:
4546 if mfentry:
4547 if mfentry:
4547 handle(add, True)
4548 handle(add, True)
4548 elif exact:
4549 elif exact:
4549 ui.warn(_('file not managed: %s\n') % rel)
4550 ui.warn(_('file not managed: %s\n') % rel)
4550 continue
4551 continue
4551 # file has not changed in dirstate
4552 # file has not changed in dirstate
4552 if node == parent:
4553 if node == parent:
4553 if exact:
4554 if exact:
4554 ui.warn(_('no changes needed to %s\n') % rel)
4555 ui.warn(_('no changes needed to %s\n') % rel)
4555 continue
4556 continue
4556 if pmf is None:
4557 if pmf is None:
4557 # only need parent manifest in this unlikely case,
4558 # only need parent manifest in this unlikely case,
4558 # so do not read by default
4559 # so do not read by default
4559 pmf = repo[parent].manifest()
4560 pmf = repo[parent].manifest()
4560 if abs in pmf:
4561 if abs in pmf:
4561 if mfentry:
4562 if mfentry:
4562 # if version of file is same in parent and target
4563 # if version of file is same in parent and target
4563 # manifests, do nothing
4564 # manifests, do nothing
4564 if (pmf[abs] != mfentry or
4565 if (pmf[abs] != mfentry or
4565 pmf.flags(abs) != mf.flags(abs)):
4566 pmf.flags(abs) != mf.flags(abs)):
4566 handle(revert, False)
4567 handle(revert, False)
4567 else:
4568 else:
4568 handle(remove, False)
4569 handle(remove, False)
4569
4570
4570 if not opts.get('dry_run'):
4571 if not opts.get('dry_run'):
4571 def checkout(f):
4572 def checkout(f):
4572 fc = ctx[f]
4573 fc = ctx[f]
4573 repo.wwrite(f, fc.data(), fc.flags())
4574 repo.wwrite(f, fc.data(), fc.flags())
4574
4575
4575 audit_path = scmutil.pathauditor(repo.root)
4576 audit_path = scmutil.pathauditor(repo.root)
4576 for f in remove[0]:
4577 for f in remove[0]:
4577 if repo.dirstate[f] == 'a':
4578 if repo.dirstate[f] == 'a':
4578 repo.dirstate.drop(f)
4579 repo.dirstate.drop(f)
4579 continue
4580 continue
4580 audit_path(f)
4581 audit_path(f)
4581 try:
4582 try:
4582 util.unlinkpath(repo.wjoin(f))
4583 util.unlinkpath(repo.wjoin(f))
4583 except OSError:
4584 except OSError:
4584 pass
4585 pass
4585 repo.dirstate.remove(f)
4586 repo.dirstate.remove(f)
4586
4587
4587 normal = None
4588 normal = None
4588 if node == parent:
4589 if node == parent:
4589 # We're reverting to our parent. If possible, we'd like status
4590 # We're reverting to our parent. If possible, we'd like status
4590 # to report the file as clean. We have to use normallookup for
4591 # to report the file as clean. We have to use normallookup for
4591 # merges to avoid losing information about merged/dirty files.
4592 # merges to avoid losing information about merged/dirty files.
4592 if p2 != nullid:
4593 if p2 != nullid:
4593 normal = repo.dirstate.normallookup
4594 normal = repo.dirstate.normallookup
4594 else:
4595 else:
4595 normal = repo.dirstate.normal
4596 normal = repo.dirstate.normal
4596 for f in revert[0]:
4597 for f in revert[0]:
4597 checkout(f)
4598 checkout(f)
4598 if normal:
4599 if normal:
4599 normal(f)
4600 normal(f)
4600
4601
4601 for f in add[0]:
4602 for f in add[0]:
4602 checkout(f)
4603 checkout(f)
4603 repo.dirstate.add(f)
4604 repo.dirstate.add(f)
4604
4605
4605 normal = repo.dirstate.normallookup
4606 normal = repo.dirstate.normallookup
4606 if node == parent and p2 == nullid:
4607 if node == parent and p2 == nullid:
4607 normal = repo.dirstate.normal
4608 normal = repo.dirstate.normal
4608 for f in undelete[0]:
4609 for f in undelete[0]:
4609 checkout(f)
4610 checkout(f)
4610 normal(f)
4611 normal(f)
4611
4612
4612 finally:
4613 finally:
4613 wlock.release()
4614 wlock.release()
4614
4615
4615 @command('rollback', dryrunopts +
4616 @command('rollback', dryrunopts +
4616 [('f', 'force', False, _('ignore safety measures'))])
4617 [('f', 'force', False, _('ignore safety measures'))])
4617 def rollback(ui, repo, **opts):
4618 def rollback(ui, repo, **opts):
4618 """roll back the last transaction (dangerous)
4619 """roll back the last transaction (dangerous)
4619
4620
4620 This command should be used with care. There is only one level of
4621 This command should be used with care. There is only one level of
4621 rollback, and there is no way to undo a rollback. It will also
4622 rollback, and there is no way to undo a rollback. It will also
4622 restore the dirstate at the time of the last transaction, losing
4623 restore the dirstate at the time of the last transaction, losing
4623 any dirstate changes since that time. This command does not alter
4624 any dirstate changes since that time. This command does not alter
4624 the working directory.
4625 the working directory.
4625
4626
4626 Transactions are used to encapsulate the effects of all commands
4627 Transactions are used to encapsulate the effects of all commands
4627 that create new changesets or propagate existing changesets into a
4628 that create new changesets or propagate existing changesets into a
4628 repository. For example, the following commands are transactional,
4629 repository. For example, the following commands are transactional,
4629 and their effects can be rolled back:
4630 and their effects can be rolled back:
4630
4631
4631 - commit
4632 - commit
4632 - import
4633 - import
4633 - pull
4634 - pull
4634 - push (with this repository as the destination)
4635 - push (with this repository as the destination)
4635 - unbundle
4636 - unbundle
4636
4637
4637 It's possible to lose data with rollback: commit, update back to
4638 It's possible to lose data with rollback: commit, update back to
4638 an older changeset, and then rollback. The update removes the
4639 an older changeset, and then rollback. The update removes the
4639 changes you committed from the working directory, and rollback
4640 changes you committed from the working directory, and rollback
4640 removes them from history. To avoid data loss, you must pass
4641 removes them from history. To avoid data loss, you must pass
4641 --force in this case.
4642 --force in this case.
4642
4643
4643 This command is not intended for use on public repositories. Once
4644 This command is not intended for use on public repositories. Once
4644 changes are visible for pull by other users, rolling a transaction
4645 changes are visible for pull by other users, rolling a transaction
4645 back locally is ineffective (someone else may already have pulled
4646 back locally is ineffective (someone else may already have pulled
4646 the changes). Furthermore, a race is possible with readers of the
4647 the changes). Furthermore, a race is possible with readers of the
4647 repository; for example an in-progress pull from the repository
4648 repository; for example an in-progress pull from the repository
4648 may fail if a rollback is performed.
4649 may fail if a rollback is performed.
4649
4650
4650 Returns 0 on success, 1 if no rollback data is available.
4651 Returns 0 on success, 1 if no rollback data is available.
4651 """
4652 """
4652 return repo.rollback(dryrun=opts.get('dry_run'),
4653 return repo.rollback(dryrun=opts.get('dry_run'),
4653 force=opts.get('force'))
4654 force=opts.get('force'))
4654
4655
4655 @command('root', [])
4656 @command('root', [])
4656 def root(ui, repo):
4657 def root(ui, repo):
4657 """print the root (top) of the current working directory
4658 """print the root (top) of the current working directory
4658
4659
4659 Print the root directory of the current repository.
4660 Print the root directory of the current repository.
4660
4661
4661 Returns 0 on success.
4662 Returns 0 on success.
4662 """
4663 """
4663 ui.write(repo.root + "\n")
4664 ui.write(repo.root + "\n")
4664
4665
4665 @command('^serve',
4666 @command('^serve',
4666 [('A', 'accesslog', '', _('name of access log file to write to'),
4667 [('A', 'accesslog', '', _('name of access log file to write to'),
4667 _('FILE')),
4668 _('FILE')),
4668 ('d', 'daemon', None, _('run server in background')),
4669 ('d', 'daemon', None, _('run server in background')),
4669 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4670 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4670 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4671 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4671 # use string type, then we can check if something was passed
4672 # use string type, then we can check if something was passed
4672 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4673 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4673 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4674 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4674 _('ADDR')),
4675 _('ADDR')),
4675 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4676 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4676 _('PREFIX')),
4677 _('PREFIX')),
4677 ('n', 'name', '',
4678 ('n', 'name', '',
4678 _('name to show in web pages (default: working directory)'), _('NAME')),
4679 _('name to show in web pages (default: working directory)'), _('NAME')),
4679 ('', 'web-conf', '',
4680 ('', 'web-conf', '',
4680 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4681 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4681 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4682 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4682 _('FILE')),
4683 _('FILE')),
4683 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4684 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4684 ('', 'stdio', None, _('for remote clients')),
4685 ('', 'stdio', None, _('for remote clients')),
4685 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4686 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4686 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4687 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4687 ('', 'style', '', _('template style to use'), _('STYLE')),
4688 ('', 'style', '', _('template style to use'), _('STYLE')),
4688 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4689 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4689 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4690 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4690 _('[OPTION]...'))
4691 _('[OPTION]...'))
4691 def serve(ui, repo, **opts):
4692 def serve(ui, repo, **opts):
4692 """start stand-alone webserver
4693 """start stand-alone webserver
4693
4694
4694 Start a local HTTP repository browser and pull server. You can use
4695 Start a local HTTP repository browser and pull server. You can use
4695 this for ad-hoc sharing and browsing of repositories. It is
4696 this for ad-hoc sharing and browsing of repositories. It is
4696 recommended to use a real web server to serve a repository for
4697 recommended to use a real web server to serve a repository for
4697 longer periods of time.
4698 longer periods of time.
4698
4699
4699 Please note that the server does not implement access control.
4700 Please note that the server does not implement access control.
4700 This means that, by default, anybody can read from the server and
4701 This means that, by default, anybody can read from the server and
4701 nobody can write to it by default. Set the ``web.allow_push``
4702 nobody can write to it by default. Set the ``web.allow_push``
4702 option to ``*`` to allow everybody to push to the server. You
4703 option to ``*`` to allow everybody to push to the server. You
4703 should use a real web server if you need to authenticate users.
4704 should use a real web server if you need to authenticate users.
4704
4705
4705 By default, the server logs accesses to stdout and errors to
4706 By default, the server logs accesses to stdout and errors to
4706 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4707 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4707 files.
4708 files.
4708
4709
4709 To have the server choose a free port number to listen on, specify
4710 To have the server choose a free port number to listen on, specify
4710 a port number of 0; in this case, the server will print the port
4711 a port number of 0; in this case, the server will print the port
4711 number it uses.
4712 number it uses.
4712
4713
4713 Returns 0 on success.
4714 Returns 0 on success.
4714 """
4715 """
4715
4716
4716 if opts["stdio"] and opts["cmdserver"]:
4717 if opts["stdio"] and opts["cmdserver"]:
4717 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4718 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4718
4719
4719 def checkrepo():
4720 def checkrepo():
4720 if repo is None:
4721 if repo is None:
4721 raise error.RepoError(_("There is no Mercurial repository here"
4722 raise error.RepoError(_("There is no Mercurial repository here"
4722 " (.hg not found)"))
4723 " (.hg not found)"))
4723
4724
4724 if opts["stdio"]:
4725 if opts["stdio"]:
4725 checkrepo()
4726 checkrepo()
4726 s = sshserver.sshserver(ui, repo)
4727 s = sshserver.sshserver(ui, repo)
4727 s.serve_forever()
4728 s.serve_forever()
4728
4729
4729 if opts["cmdserver"]:
4730 if opts["cmdserver"]:
4730 checkrepo()
4731 checkrepo()
4731 s = commandserver.server(ui, repo, opts["cmdserver"])
4732 s = commandserver.server(ui, repo, opts["cmdserver"])
4732 return s.serve()
4733 return s.serve()
4733
4734
4734 # this way we can check if something was given in the command-line
4735 # this way we can check if something was given in the command-line
4735 if opts.get('port'):
4736 if opts.get('port'):
4736 opts['port'] = util.getport(opts.get('port'))
4737 opts['port'] = util.getport(opts.get('port'))
4737
4738
4738 baseui = repo and repo.baseui or ui
4739 baseui = repo and repo.baseui or ui
4739 optlist = ("name templates style address port prefix ipv6"
4740 optlist = ("name templates style address port prefix ipv6"
4740 " accesslog errorlog certificate encoding")
4741 " accesslog errorlog certificate encoding")
4741 for o in optlist.split():
4742 for o in optlist.split():
4742 val = opts.get(o, '')
4743 val = opts.get(o, '')
4743 if val in (None, ''): # should check against default options instead
4744 if val in (None, ''): # should check against default options instead
4744 continue
4745 continue
4745 baseui.setconfig("web", o, val)
4746 baseui.setconfig("web", o, val)
4746 if repo and repo.ui != baseui:
4747 if repo and repo.ui != baseui:
4747 repo.ui.setconfig("web", o, val)
4748 repo.ui.setconfig("web", o, val)
4748
4749
4749 o = opts.get('web_conf') or opts.get('webdir_conf')
4750 o = opts.get('web_conf') or opts.get('webdir_conf')
4750 if not o:
4751 if not o:
4751 if not repo:
4752 if not repo:
4752 raise error.RepoError(_("There is no Mercurial repository"
4753 raise error.RepoError(_("There is no Mercurial repository"
4753 " here (.hg not found)"))
4754 " here (.hg not found)"))
4754 o = repo.root
4755 o = repo.root
4755
4756
4756 app = hgweb.hgweb(o, baseui=ui)
4757 app = hgweb.hgweb(o, baseui=ui)
4757
4758
4758 class service(object):
4759 class service(object):
4759 def init(self):
4760 def init(self):
4760 util.setsignalhandler()
4761 util.setsignalhandler()
4761 self.httpd = hgweb.server.create_server(ui, app)
4762 self.httpd = hgweb.server.create_server(ui, app)
4762
4763
4763 if opts['port'] and not ui.verbose:
4764 if opts['port'] and not ui.verbose:
4764 return
4765 return
4765
4766
4766 if self.httpd.prefix:
4767 if self.httpd.prefix:
4767 prefix = self.httpd.prefix.strip('/') + '/'
4768 prefix = self.httpd.prefix.strip('/') + '/'
4768 else:
4769 else:
4769 prefix = ''
4770 prefix = ''
4770
4771
4771 port = ':%d' % self.httpd.port
4772 port = ':%d' % self.httpd.port
4772 if port == ':80':
4773 if port == ':80':
4773 port = ''
4774 port = ''
4774
4775
4775 bindaddr = self.httpd.addr
4776 bindaddr = self.httpd.addr
4776 if bindaddr == '0.0.0.0':
4777 if bindaddr == '0.0.0.0':
4777 bindaddr = '*'
4778 bindaddr = '*'
4778 elif ':' in bindaddr: # IPv6
4779 elif ':' in bindaddr: # IPv6
4779 bindaddr = '[%s]' % bindaddr
4780 bindaddr = '[%s]' % bindaddr
4780
4781
4781 fqaddr = self.httpd.fqaddr
4782 fqaddr = self.httpd.fqaddr
4782 if ':' in fqaddr:
4783 if ':' in fqaddr:
4783 fqaddr = '[%s]' % fqaddr
4784 fqaddr = '[%s]' % fqaddr
4784 if opts['port']:
4785 if opts['port']:
4785 write = ui.status
4786 write = ui.status
4786 else:
4787 else:
4787 write = ui.write
4788 write = ui.write
4788 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4789 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
4789 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4790 (fqaddr, port, prefix, bindaddr, self.httpd.port))
4790
4791
4791 def run(self):
4792 def run(self):
4792 self.httpd.serve_forever()
4793 self.httpd.serve_forever()
4793
4794
4794 service = service()
4795 service = service()
4795
4796
4796 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4797 cmdutil.service(opts, initfn=service.init, runfn=service.run)
4797
4798
4798 @command('showconfig|debugconfig',
4799 @command('showconfig|debugconfig',
4799 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4800 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4800 _('[-u] [NAME]...'))
4801 _('[-u] [NAME]...'))
4801 def showconfig(ui, repo, *values, **opts):
4802 def showconfig(ui, repo, *values, **opts):
4802 """show combined config settings from all hgrc files
4803 """show combined config settings from all hgrc files
4803
4804
4804 With no arguments, print names and values of all config items.
4805 With no arguments, print names and values of all config items.
4805
4806
4806 With one argument of the form section.name, print just the value
4807 With one argument of the form section.name, print just the value
4807 of that config item.
4808 of that config item.
4808
4809
4809 With multiple arguments, print names and values of all config
4810 With multiple arguments, print names and values of all config
4810 items with matching section names.
4811 items with matching section names.
4811
4812
4812 With --debug, the source (filename and line number) is printed
4813 With --debug, the source (filename and line number) is printed
4813 for each config item.
4814 for each config item.
4814
4815
4815 Returns 0 on success.
4816 Returns 0 on success.
4816 """
4817 """
4817
4818
4818 for f in scmutil.rcpath():
4819 for f in scmutil.rcpath():
4819 ui.debug('read config from: %s\n' % f)
4820 ui.debug('read config from: %s\n' % f)
4820 untrusted = bool(opts.get('untrusted'))
4821 untrusted = bool(opts.get('untrusted'))
4821 if values:
4822 if values:
4822 sections = [v for v in values if '.' not in v]
4823 sections = [v for v in values if '.' not in v]
4823 items = [v for v in values if '.' in v]
4824 items = [v for v in values if '.' in v]
4824 if len(items) > 1 or items and sections:
4825 if len(items) > 1 or items and sections:
4825 raise util.Abort(_('only one config item permitted'))
4826 raise util.Abort(_('only one config item permitted'))
4826 for section, name, value in ui.walkconfig(untrusted=untrusted):
4827 for section, name, value in ui.walkconfig(untrusted=untrusted):
4827 value = str(value).replace('\n', '\\n')
4828 value = str(value).replace('\n', '\\n')
4828 sectname = section + '.' + name
4829 sectname = section + '.' + name
4829 if values:
4830 if values:
4830 for v in values:
4831 for v in values:
4831 if v == section:
4832 if v == section:
4832 ui.debug('%s: ' %
4833 ui.debug('%s: ' %
4833 ui.configsource(section, name, untrusted))
4834 ui.configsource(section, name, untrusted))
4834 ui.write('%s=%s\n' % (sectname, value))
4835 ui.write('%s=%s\n' % (sectname, value))
4835 elif v == sectname:
4836 elif v == sectname:
4836 ui.debug('%s: ' %
4837 ui.debug('%s: ' %
4837 ui.configsource(section, name, untrusted))
4838 ui.configsource(section, name, untrusted))
4838 ui.write(value, '\n')
4839 ui.write(value, '\n')
4839 else:
4840 else:
4840 ui.debug('%s: ' %
4841 ui.debug('%s: ' %
4841 ui.configsource(section, name, untrusted))
4842 ui.configsource(section, name, untrusted))
4842 ui.write('%s=%s\n' % (sectname, value))
4843 ui.write('%s=%s\n' % (sectname, value))
4843
4844
4844 @command('^status|st',
4845 @command('^status|st',
4845 [('A', 'all', None, _('show status of all files')),
4846 [('A', 'all', None, _('show status of all files')),
4846 ('m', 'modified', None, _('show only modified files')),
4847 ('m', 'modified', None, _('show only modified files')),
4847 ('a', 'added', None, _('show only added files')),
4848 ('a', 'added', None, _('show only added files')),
4848 ('r', 'removed', None, _('show only removed files')),
4849 ('r', 'removed', None, _('show only removed files')),
4849 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4850 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4850 ('c', 'clean', None, _('show only files without changes')),
4851 ('c', 'clean', None, _('show only files without changes')),
4851 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4852 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4852 ('i', 'ignored', None, _('show only ignored files')),
4853 ('i', 'ignored', None, _('show only ignored files')),
4853 ('n', 'no-status', None, _('hide status prefix')),
4854 ('n', 'no-status', None, _('hide status prefix')),
4854 ('C', 'copies', None, _('show source of copied files')),
4855 ('C', 'copies', None, _('show source of copied files')),
4855 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4856 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4856 ('', 'rev', [], _('show difference from revision'), _('REV')),
4857 ('', 'rev', [], _('show difference from revision'), _('REV')),
4857 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4858 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4858 ] + walkopts + subrepoopts,
4859 ] + walkopts + subrepoopts,
4859 _('[OPTION]... [FILE]...'))
4860 _('[OPTION]... [FILE]...'))
4860 def status(ui, repo, *pats, **opts):
4861 def status(ui, repo, *pats, **opts):
4861 """show changed files in the working directory
4862 """show changed files in the working directory
4862
4863
4863 Show status of files in the repository. If names are given, only
4864 Show status of files in the repository. If names are given, only
4864 files that match are shown. Files that are clean or ignored or
4865 files that match are shown. Files that are clean or ignored or
4865 the source of a copy/move operation, are not listed unless
4866 the source of a copy/move operation, are not listed unless
4866 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4867 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4867 Unless options described with "show only ..." are given, the
4868 Unless options described with "show only ..." are given, the
4868 options -mardu are used.
4869 options -mardu are used.
4869
4870
4870 Option -q/--quiet hides untracked (unknown and ignored) files
4871 Option -q/--quiet hides untracked (unknown and ignored) files
4871 unless explicitly requested with -u/--unknown or -i/--ignored.
4872 unless explicitly requested with -u/--unknown or -i/--ignored.
4872
4873
4873 .. note::
4874 .. note::
4874 status may appear to disagree with diff if permissions have
4875 status may appear to disagree with diff if permissions have
4875 changed or a merge has occurred. The standard diff format does
4876 changed or a merge has occurred. The standard diff format does
4876 not report permission changes and diff only reports changes
4877 not report permission changes and diff only reports changes
4877 relative to one merge parent.
4878 relative to one merge parent.
4878
4879
4879 If one revision is given, it is used as the base revision.
4880 If one revision is given, it is used as the base revision.
4880 If two revisions are given, the differences between them are
4881 If two revisions are given, the differences between them are
4881 shown. The --change option can also be used as a shortcut to list
4882 shown. The --change option can also be used as a shortcut to list
4882 the changed files of a revision from its first parent.
4883 the changed files of a revision from its first parent.
4883
4884
4884 The codes used to show the status of files are::
4885 The codes used to show the status of files are::
4885
4886
4886 M = modified
4887 M = modified
4887 A = added
4888 A = added
4888 R = removed
4889 R = removed
4889 C = clean
4890 C = clean
4890 ! = missing (deleted by non-hg command, but still tracked)
4891 ! = missing (deleted by non-hg command, but still tracked)
4891 ? = not tracked
4892 ? = not tracked
4892 I = ignored
4893 I = ignored
4893 = origin of the previous file listed as A (added)
4894 = origin of the previous file listed as A (added)
4894
4895
4895 .. container:: verbose
4896 .. container:: verbose
4896
4897
4897 Examples:
4898 Examples:
4898
4899
4899 - show changes in the working directory relative to a changeset:
4900 - show changes in the working directory relative to a changeset:
4900
4901
4901 hg status --rev 9353
4902 hg status --rev 9353
4902
4903
4903 - show all changes including copies in an existing changeset::
4904 - show all changes including copies in an existing changeset::
4904
4905
4905 hg status --copies --change 9353
4906 hg status --copies --change 9353
4906
4907
4907 - get a NUL separated list of added files, suitable for xargs::
4908 - get a NUL separated list of added files, suitable for xargs::
4908
4909
4909 hg status -an0
4910 hg status -an0
4910
4911
4911 Returns 0 on success.
4912 Returns 0 on success.
4912 """
4913 """
4913
4914
4914 revs = opts.get('rev')
4915 revs = opts.get('rev')
4915 change = opts.get('change')
4916 change = opts.get('change')
4916
4917
4917 if revs and change:
4918 if revs and change:
4918 msg = _('cannot specify --rev and --change at the same time')
4919 msg = _('cannot specify --rev and --change at the same time')
4919 raise util.Abort(msg)
4920 raise util.Abort(msg)
4920 elif change:
4921 elif change:
4921 node2 = repo.lookup(change)
4922 node2 = repo.lookup(change)
4922 node1 = repo[node2].p1().node()
4923 node1 = repo[node2].p1().node()
4923 else:
4924 else:
4924 node1, node2 = scmutil.revpair(repo, revs)
4925 node1, node2 = scmutil.revpair(repo, revs)
4925
4926
4926 cwd = (pats and repo.getcwd()) or ''
4927 cwd = (pats and repo.getcwd()) or ''
4927 end = opts.get('print0') and '\0' or '\n'
4928 end = opts.get('print0') and '\0' or '\n'
4928 copy = {}
4929 copy = {}
4929 states = 'modified added removed deleted unknown ignored clean'.split()
4930 states = 'modified added removed deleted unknown ignored clean'.split()
4930 show = [k for k in states if opts.get(k)]
4931 show = [k for k in states if opts.get(k)]
4931 if opts.get('all'):
4932 if opts.get('all'):
4932 show += ui.quiet and (states[:4] + ['clean']) or states
4933 show += ui.quiet and (states[:4] + ['clean']) or states
4933 if not show:
4934 if not show:
4934 show = ui.quiet and states[:4] or states[:5]
4935 show = ui.quiet and states[:4] or states[:5]
4935
4936
4936 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
4937 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
4937 'ignored' in show, 'clean' in show, 'unknown' in show,
4938 'ignored' in show, 'clean' in show, 'unknown' in show,
4938 opts.get('subrepos'))
4939 opts.get('subrepos'))
4939 changestates = zip(states, 'MAR!?IC', stat)
4940 changestates = zip(states, 'MAR!?IC', stat)
4940
4941
4941 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4942 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
4942 ctxn = repo[nullid]
4943 ctxn = repo[nullid]
4943 ctx1 = repo[node1]
4944 ctx1 = repo[node1]
4944 ctx2 = repo[node2]
4945 ctx2 = repo[node2]
4945 added = stat[1]
4946 added = stat[1]
4946 if node2 is None:
4947 if node2 is None:
4947 added = stat[0] + stat[1] # merged?
4948 added = stat[0] + stat[1] # merged?
4948
4949
4949 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4950 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
4950 if k in added:
4951 if k in added:
4951 copy[k] = v
4952 copy[k] = v
4952 elif v in added:
4953 elif v in added:
4953 copy[v] = k
4954 copy[v] = k
4954
4955
4955 for state, char, files in changestates:
4956 for state, char, files in changestates:
4956 if state in show:
4957 if state in show:
4957 format = "%s %%s%s" % (char, end)
4958 format = "%s %%s%s" % (char, end)
4958 if opts.get('no_status'):
4959 if opts.get('no_status'):
4959 format = "%%s%s" % end
4960 format = "%%s%s" % end
4960
4961
4961 for f in files:
4962 for f in files:
4962 ui.write(format % repo.pathto(f, cwd),
4963 ui.write(format % repo.pathto(f, cwd),
4963 label='status.' + state)
4964 label='status.' + state)
4964 if f in copy:
4965 if f in copy:
4965 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4966 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
4966 label='status.copied')
4967 label='status.copied')
4967
4968
4968 @command('^summary|sum',
4969 @command('^summary|sum',
4969 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4970 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4970 def summary(ui, repo, **opts):
4971 def summary(ui, repo, **opts):
4971 """summarize working directory state
4972 """summarize working directory state
4972
4973
4973 This generates a brief summary of the working directory state,
4974 This generates a brief summary of the working directory state,
4974 including parents, branch, commit status, and available updates.
4975 including parents, branch, commit status, and available updates.
4975
4976
4976 With the --remote option, this will check the default paths for
4977 With the --remote option, this will check the default paths for
4977 incoming and outgoing changes. This can be time-consuming.
4978 incoming and outgoing changes. This can be time-consuming.
4978
4979
4979 Returns 0 on success.
4980 Returns 0 on success.
4980 """
4981 """
4981
4982
4982 ctx = repo[None]
4983 ctx = repo[None]
4983 parents = ctx.parents()
4984 parents = ctx.parents()
4984 pnode = parents[0].node()
4985 pnode = parents[0].node()
4985 marks = []
4986 marks = []
4986
4987
4987 for p in parents:
4988 for p in parents:
4988 # label with log.changeset (instead of log.parent) since this
4989 # label with log.changeset (instead of log.parent) since this
4989 # shows a working directory parent *changeset*:
4990 # shows a working directory parent *changeset*:
4990 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4991 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4991 label='log.changeset')
4992 label='log.changeset')
4992 ui.write(' '.join(p.tags()), label='log.tag')
4993 ui.write(' '.join(p.tags()), label='log.tag')
4993 if p.bookmarks():
4994 if p.bookmarks():
4994 marks.extend(p.bookmarks())
4995 marks.extend(p.bookmarks())
4995 if p.rev() == -1:
4996 if p.rev() == -1:
4996 if not len(repo):
4997 if not len(repo):
4997 ui.write(_(' (empty repository)'))
4998 ui.write(_(' (empty repository)'))
4998 else:
4999 else:
4999 ui.write(_(' (no revision checked out)'))
5000 ui.write(_(' (no revision checked out)'))
5000 ui.write('\n')
5001 ui.write('\n')
5001 if p.description():
5002 if p.description():
5002 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5003 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5003 label='log.summary')
5004 label='log.summary')
5004
5005
5005 branch = ctx.branch()
5006 branch = ctx.branch()
5006 bheads = repo.branchheads(branch)
5007 bheads = repo.branchheads(branch)
5007 m = _('branch: %s\n') % branch
5008 m = _('branch: %s\n') % branch
5008 if branch != 'default':
5009 if branch != 'default':
5009 ui.write(m, label='log.branch')
5010 ui.write(m, label='log.branch')
5010 else:
5011 else:
5011 ui.status(m, label='log.branch')
5012 ui.status(m, label='log.branch')
5012
5013
5013 if marks:
5014 if marks:
5014 current = repo._bookmarkcurrent
5015 current = repo._bookmarkcurrent
5015 ui.write(_('bookmarks:'), label='log.bookmark')
5016 ui.write(_('bookmarks:'), label='log.bookmark')
5016 if current is not None:
5017 if current is not None:
5017 try:
5018 try:
5018 marks.remove(current)
5019 marks.remove(current)
5019 ui.write(' *' + current, label='bookmarks.current')
5020 ui.write(' *' + current, label='bookmarks.current')
5020 except ValueError:
5021 except ValueError:
5021 # current bookmark not in parent ctx marks
5022 # current bookmark not in parent ctx marks
5022 pass
5023 pass
5023 for m in marks:
5024 for m in marks:
5024 ui.write(' ' + m, label='log.bookmark')
5025 ui.write(' ' + m, label='log.bookmark')
5025 ui.write('\n', label='log.bookmark')
5026 ui.write('\n', label='log.bookmark')
5026
5027
5027 st = list(repo.status(unknown=True))[:6]
5028 st = list(repo.status(unknown=True))[:6]
5028
5029
5029 c = repo.dirstate.copies()
5030 c = repo.dirstate.copies()
5030 copied, renamed = [], []
5031 copied, renamed = [], []
5031 for d, s in c.iteritems():
5032 for d, s in c.iteritems():
5032 if s in st[2]:
5033 if s in st[2]:
5033 st[2].remove(s)
5034 st[2].remove(s)
5034 renamed.append(d)
5035 renamed.append(d)
5035 else:
5036 else:
5036 copied.append(d)
5037 copied.append(d)
5037 if d in st[1]:
5038 if d in st[1]:
5038 st[1].remove(d)
5039 st[1].remove(d)
5039 st.insert(3, renamed)
5040 st.insert(3, renamed)
5040 st.insert(4, copied)
5041 st.insert(4, copied)
5041
5042
5042 ms = mergemod.mergestate(repo)
5043 ms = mergemod.mergestate(repo)
5043 st.append([f for f in ms if ms[f] == 'u'])
5044 st.append([f for f in ms if ms[f] == 'u'])
5044
5045
5045 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5046 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5046 st.append(subs)
5047 st.append(subs)
5047
5048
5048 labels = [ui.label(_('%d modified'), 'status.modified'),
5049 labels = [ui.label(_('%d modified'), 'status.modified'),
5049 ui.label(_('%d added'), 'status.added'),
5050 ui.label(_('%d added'), 'status.added'),
5050 ui.label(_('%d removed'), 'status.removed'),
5051 ui.label(_('%d removed'), 'status.removed'),
5051 ui.label(_('%d renamed'), 'status.copied'),
5052 ui.label(_('%d renamed'), 'status.copied'),
5052 ui.label(_('%d copied'), 'status.copied'),
5053 ui.label(_('%d copied'), 'status.copied'),
5053 ui.label(_('%d deleted'), 'status.deleted'),
5054 ui.label(_('%d deleted'), 'status.deleted'),
5054 ui.label(_('%d unknown'), 'status.unknown'),
5055 ui.label(_('%d unknown'), 'status.unknown'),
5055 ui.label(_('%d ignored'), 'status.ignored'),
5056 ui.label(_('%d ignored'), 'status.ignored'),
5056 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5057 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5057 ui.label(_('%d subrepos'), 'status.modified')]
5058 ui.label(_('%d subrepos'), 'status.modified')]
5058 t = []
5059 t = []
5059 for s, l in zip(st, labels):
5060 for s, l in zip(st, labels):
5060 if s:
5061 if s:
5061 t.append(l % len(s))
5062 t.append(l % len(s))
5062
5063
5063 t = ', '.join(t)
5064 t = ', '.join(t)
5064 cleanworkdir = False
5065 cleanworkdir = False
5065
5066
5066 if len(parents) > 1:
5067 if len(parents) > 1:
5067 t += _(' (merge)')
5068 t += _(' (merge)')
5068 elif branch != parents[0].branch():
5069 elif branch != parents[0].branch():
5069 t += _(' (new branch)')
5070 t += _(' (new branch)')
5070 elif (parents[0].extra().get('close') and
5071 elif (parents[0].extra().get('close') and
5071 pnode in repo.branchheads(branch, closed=True)):
5072 pnode in repo.branchheads(branch, closed=True)):
5072 t += _(' (head closed)')
5073 t += _(' (head closed)')
5073 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5074 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5074 t += _(' (clean)')
5075 t += _(' (clean)')
5075 cleanworkdir = True
5076 cleanworkdir = True
5076 elif pnode not in bheads:
5077 elif pnode not in bheads:
5077 t += _(' (new branch head)')
5078 t += _(' (new branch head)')
5078
5079
5079 if cleanworkdir:
5080 if cleanworkdir:
5080 ui.status(_('commit: %s\n') % t.strip())
5081 ui.status(_('commit: %s\n') % t.strip())
5081 else:
5082 else:
5082 ui.write(_('commit: %s\n') % t.strip())
5083 ui.write(_('commit: %s\n') % t.strip())
5083
5084
5084 # all ancestors of branch heads - all ancestors of parent = new csets
5085 # all ancestors of branch heads - all ancestors of parent = new csets
5085 new = [0] * len(repo)
5086 new = [0] * len(repo)
5086 cl = repo.changelog
5087 cl = repo.changelog
5087 for a in [cl.rev(n) for n in bheads]:
5088 for a in [cl.rev(n) for n in bheads]:
5088 new[a] = 1
5089 new[a] = 1
5089 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
5090 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
5090 new[a] = 1
5091 new[a] = 1
5091 for a in [p.rev() for p in parents]:
5092 for a in [p.rev() for p in parents]:
5092 if a >= 0:
5093 if a >= 0:
5093 new[a] = 0
5094 new[a] = 0
5094 for a in cl.ancestors(*[p.rev() for p in parents]):
5095 for a in cl.ancestors(*[p.rev() for p in parents]):
5095 new[a] = 0
5096 new[a] = 0
5096 new = sum(new)
5097 new = sum(new)
5097
5098
5098 if new == 0:
5099 if new == 0:
5099 ui.status(_('update: (current)\n'))
5100 ui.status(_('update: (current)\n'))
5100 elif pnode not in bheads:
5101 elif pnode not in bheads:
5101 ui.write(_('update: %d new changesets (update)\n') % new)
5102 ui.write(_('update: %d new changesets (update)\n') % new)
5102 else:
5103 else:
5103 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5104 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5104 (new, len(bheads)))
5105 (new, len(bheads)))
5105
5106
5106 if opts.get('remote'):
5107 if opts.get('remote'):
5107 t = []
5108 t = []
5108 source, branches = hg.parseurl(ui.expandpath('default'))
5109 source, branches = hg.parseurl(ui.expandpath('default'))
5109 other = hg.peer(repo, {}, source)
5110 other = hg.peer(repo, {}, source)
5110 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5111 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5111 ui.debug('comparing with %s\n' % util.hidepassword(source))
5112 ui.debug('comparing with %s\n' % util.hidepassword(source))
5112 repo.ui.pushbuffer()
5113 repo.ui.pushbuffer()
5113 commoninc = discovery.findcommonincoming(repo, other)
5114 commoninc = discovery.findcommonincoming(repo, other)
5114 _common, incoming, _rheads = commoninc
5115 _common, incoming, _rheads = commoninc
5115 repo.ui.popbuffer()
5116 repo.ui.popbuffer()
5116 if incoming:
5117 if incoming:
5117 t.append(_('1 or more incoming'))
5118 t.append(_('1 or more incoming'))
5118
5119
5119 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5120 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5120 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5121 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5121 if source != dest:
5122 if source != dest:
5122 other = hg.peer(repo, {}, dest)
5123 other = hg.peer(repo, {}, dest)
5123 commoninc = None
5124 commoninc = None
5124 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5125 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5125 repo.ui.pushbuffer()
5126 repo.ui.pushbuffer()
5126 common, outheads = discovery.findcommonoutgoing(repo, other,
5127 common, outheads = discovery.findcommonoutgoing(repo, other,
5127 commoninc=commoninc)
5128 commoninc=commoninc)
5128 repo.ui.popbuffer()
5129 repo.ui.popbuffer()
5129 o = repo.changelog.findmissing(common=common, heads=outheads)
5130 o = repo.changelog.findmissing(common=common, heads=outheads)
5130 if o:
5131 if o:
5131 t.append(_('%d outgoing') % len(o))
5132 t.append(_('%d outgoing') % len(o))
5132 if 'bookmarks' in other.listkeys('namespaces'):
5133 if 'bookmarks' in other.listkeys('namespaces'):
5133 lmarks = repo.listkeys('bookmarks')
5134 lmarks = repo.listkeys('bookmarks')
5134 rmarks = other.listkeys('bookmarks')
5135 rmarks = other.listkeys('bookmarks')
5135 diff = set(rmarks) - set(lmarks)
5136 diff = set(rmarks) - set(lmarks)
5136 if len(diff) > 0:
5137 if len(diff) > 0:
5137 t.append(_('%d incoming bookmarks') % len(diff))
5138 t.append(_('%d incoming bookmarks') % len(diff))
5138 diff = set(lmarks) - set(rmarks)
5139 diff = set(lmarks) - set(rmarks)
5139 if len(diff) > 0:
5140 if len(diff) > 0:
5140 t.append(_('%d outgoing bookmarks') % len(diff))
5141 t.append(_('%d outgoing bookmarks') % len(diff))
5141
5142
5142 if t:
5143 if t:
5143 ui.write(_('remote: %s\n') % (', '.join(t)))
5144 ui.write(_('remote: %s\n') % (', '.join(t)))
5144 else:
5145 else:
5145 ui.status(_('remote: (synced)\n'))
5146 ui.status(_('remote: (synced)\n'))
5146
5147
5147 @command('tag',
5148 @command('tag',
5148 [('f', 'force', None, _('force tag')),
5149 [('f', 'force', None, _('force tag')),
5149 ('l', 'local', None, _('make the tag local')),
5150 ('l', 'local', None, _('make the tag local')),
5150 ('r', 'rev', '', _('revision to tag'), _('REV')),
5151 ('r', 'rev', '', _('revision to tag'), _('REV')),
5151 ('', 'remove', None, _('remove a tag')),
5152 ('', 'remove', None, _('remove a tag')),
5152 # -l/--local is already there, commitopts cannot be used
5153 # -l/--local is already there, commitopts cannot be used
5153 ('e', 'edit', None, _('edit commit message')),
5154 ('e', 'edit', None, _('edit commit message')),
5154 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5155 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5155 ] + commitopts2,
5156 ] + commitopts2,
5156 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5157 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5157 def tag(ui, repo, name1, *names, **opts):
5158 def tag(ui, repo, name1, *names, **opts):
5158 """add one or more tags for the current or given revision
5159 """add one or more tags for the current or given revision
5159
5160
5160 Name a particular revision using <name>.
5161 Name a particular revision using <name>.
5161
5162
5162 Tags are used to name particular revisions of the repository and are
5163 Tags are used to name particular revisions of the repository and are
5163 very useful to compare different revisions, to go back to significant
5164 very useful to compare different revisions, to go back to significant
5164 earlier versions or to mark branch points as releases, etc. Changing
5165 earlier versions or to mark branch points as releases, etc. Changing
5165 an existing tag is normally disallowed; use -f/--force to override.
5166 an existing tag is normally disallowed; use -f/--force to override.
5166
5167
5167 If no revision is given, the parent of the working directory is
5168 If no revision is given, the parent of the working directory is
5168 used, or tip if no revision is checked out.
5169 used, or tip if no revision is checked out.
5169
5170
5170 To facilitate version control, distribution, and merging of tags,
5171 To facilitate version control, distribution, and merging of tags,
5171 they are stored as a file named ".hgtags" which is managed similarly
5172 they are stored as a file named ".hgtags" which is managed similarly
5172 to other project files and can be hand-edited if necessary. This
5173 to other project files and can be hand-edited if necessary. This
5173 also means that tagging creates a new commit. The file
5174 also means that tagging creates a new commit. The file
5174 ".hg/localtags" is used for local tags (not shared among
5175 ".hg/localtags" is used for local tags (not shared among
5175 repositories).
5176 repositories).
5176
5177
5177 Tag commits are usually made at the head of a branch. If the parent
5178 Tag commits are usually made at the head of a branch. If the parent
5178 of the working directory is not a branch head, :hg:`tag` aborts; use
5179 of the working directory is not a branch head, :hg:`tag` aborts; use
5179 -f/--force to force the tag commit to be based on a non-head
5180 -f/--force to force the tag commit to be based on a non-head
5180 changeset.
5181 changeset.
5181
5182
5182 See :hg:`help dates` for a list of formats valid for -d/--date.
5183 See :hg:`help dates` for a list of formats valid for -d/--date.
5183
5184
5184 Since tag names have priority over branch names during revision
5185 Since tag names have priority over branch names during revision
5185 lookup, using an existing branch name as a tag name is discouraged.
5186 lookup, using an existing branch name as a tag name is discouraged.
5186
5187
5187 Returns 0 on success.
5188 Returns 0 on success.
5188 """
5189 """
5189
5190
5190 rev_ = "."
5191 rev_ = "."
5191 names = [t.strip() for t in (name1,) + names]
5192 names = [t.strip() for t in (name1,) + names]
5192 if len(names) != len(set(names)):
5193 if len(names) != len(set(names)):
5193 raise util.Abort(_('tag names must be unique'))
5194 raise util.Abort(_('tag names must be unique'))
5194 for n in names:
5195 for n in names:
5195 if n in ['tip', '.', 'null']:
5196 if n in ['tip', '.', 'null']:
5196 raise util.Abort(_("the name '%s' is reserved") % n)
5197 raise util.Abort(_("the name '%s' is reserved") % n)
5197 if not n:
5198 if not n:
5198 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
5199 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
5199 if opts.get('rev') and opts.get('remove'):
5200 if opts.get('rev') and opts.get('remove'):
5200 raise util.Abort(_("--rev and --remove are incompatible"))
5201 raise util.Abort(_("--rev and --remove are incompatible"))
5201 if opts.get('rev'):
5202 if opts.get('rev'):
5202 rev_ = opts['rev']
5203 rev_ = opts['rev']
5203 message = opts.get('message')
5204 message = opts.get('message')
5204 if opts.get('remove'):
5205 if opts.get('remove'):
5205 expectedtype = opts.get('local') and 'local' or 'global'
5206 expectedtype = opts.get('local') and 'local' or 'global'
5206 for n in names:
5207 for n in names:
5207 if not repo.tagtype(n):
5208 if not repo.tagtype(n):
5208 raise util.Abort(_("tag '%s' does not exist") % n)
5209 raise util.Abort(_("tag '%s' does not exist") % n)
5209 if repo.tagtype(n) != expectedtype:
5210 if repo.tagtype(n) != expectedtype:
5210 if expectedtype == 'global':
5211 if expectedtype == 'global':
5211 raise util.Abort(_("tag '%s' is not a global tag") % n)
5212 raise util.Abort(_("tag '%s' is not a global tag") % n)
5212 else:
5213 else:
5213 raise util.Abort(_("tag '%s' is not a local tag") % n)
5214 raise util.Abort(_("tag '%s' is not a local tag") % n)
5214 rev_ = nullid
5215 rev_ = nullid
5215 if not message:
5216 if not message:
5216 # we don't translate commit messages
5217 # we don't translate commit messages
5217 message = 'Removed tag %s' % ', '.join(names)
5218 message = 'Removed tag %s' % ', '.join(names)
5218 elif not opts.get('force'):
5219 elif not opts.get('force'):
5219 for n in names:
5220 for n in names:
5220 if n in repo.tags():
5221 if n in repo.tags():
5221 raise util.Abort(_("tag '%s' already exists "
5222 raise util.Abort(_("tag '%s' already exists "
5222 "(use -f to force)") % n)
5223 "(use -f to force)") % n)
5223 if not opts.get('local'):
5224 if not opts.get('local'):
5224 p1, p2 = repo.dirstate.parents()
5225 p1, p2 = repo.dirstate.parents()
5225 if p2 != nullid:
5226 if p2 != nullid:
5226 raise util.Abort(_('uncommitted merge'))
5227 raise util.Abort(_('uncommitted merge'))
5227 bheads = repo.branchheads()
5228 bheads = repo.branchheads()
5228 if not opts.get('force') and bheads and p1 not in bheads:
5229 if not opts.get('force') and bheads and p1 not in bheads:
5229 raise util.Abort(_('not at a branch head (use -f to force)'))
5230 raise util.Abort(_('not at a branch head (use -f to force)'))
5230 r = scmutil.revsingle(repo, rev_).node()
5231 r = scmutil.revsingle(repo, rev_).node()
5231
5232
5232 if not message:
5233 if not message:
5233 # we don't translate commit messages
5234 # we don't translate commit messages
5234 message = ('Added tag %s for changeset %s' %
5235 message = ('Added tag %s for changeset %s' %
5235 (', '.join(names), short(r)))
5236 (', '.join(names), short(r)))
5236
5237
5237 date = opts.get('date')
5238 date = opts.get('date')
5238 if date:
5239 if date:
5239 date = util.parsedate(date)
5240 date = util.parsedate(date)
5240
5241
5241 if opts.get('edit'):
5242 if opts.get('edit'):
5242 message = ui.edit(message, ui.username())
5243 message = ui.edit(message, ui.username())
5243
5244
5244 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5245 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5245
5246
5246 @command('tags', [], '')
5247 @command('tags', [], '')
5247 def tags(ui, repo):
5248 def tags(ui, repo):
5248 """list repository tags
5249 """list repository tags
5249
5250
5250 This lists both regular and local tags. When the -v/--verbose
5251 This lists both regular and local tags. When the -v/--verbose
5251 switch is used, a third column "local" is printed for local tags.
5252 switch is used, a third column "local" is printed for local tags.
5252
5253
5253 Returns 0 on success.
5254 Returns 0 on success.
5254 """
5255 """
5255
5256
5256 hexfunc = ui.debugflag and hex or short
5257 hexfunc = ui.debugflag and hex or short
5257 tagtype = ""
5258 tagtype = ""
5258
5259
5259 for t, n in reversed(repo.tagslist()):
5260 for t, n in reversed(repo.tagslist()):
5260 if ui.quiet:
5261 if ui.quiet:
5261 ui.write("%s\n" % t, label='tags.normal')
5262 ui.write("%s\n" % t, label='tags.normal')
5262 continue
5263 continue
5263
5264
5264 hn = hexfunc(n)
5265 hn = hexfunc(n)
5265 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5266 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5266 rev = ui.label(r, 'log.changeset')
5267 rev = ui.label(r, 'log.changeset')
5267 spaces = " " * (30 - encoding.colwidth(t))
5268 spaces = " " * (30 - encoding.colwidth(t))
5268
5269
5269 tag = ui.label(t, 'tags.normal')
5270 tag = ui.label(t, 'tags.normal')
5270 if ui.verbose:
5271 if ui.verbose:
5271 if repo.tagtype(t) == 'local':
5272 if repo.tagtype(t) == 'local':
5272 tagtype = " local"
5273 tagtype = " local"
5273 tag = ui.label(t, 'tags.local')
5274 tag = ui.label(t, 'tags.local')
5274 else:
5275 else:
5275 tagtype = ""
5276 tagtype = ""
5276 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5277 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5277
5278
5278 @command('tip',
5279 @command('tip',
5279 [('p', 'patch', None, _('show patch')),
5280 [('p', 'patch', None, _('show patch')),
5280 ('g', 'git', None, _('use git extended diff format')),
5281 ('g', 'git', None, _('use git extended diff format')),
5281 ] + templateopts,
5282 ] + templateopts,
5282 _('[-p] [-g]'))
5283 _('[-p] [-g]'))
5283 def tip(ui, repo, **opts):
5284 def tip(ui, repo, **opts):
5284 """show the tip revision
5285 """show the tip revision
5285
5286
5286 The tip revision (usually just called the tip) is the changeset
5287 The tip revision (usually just called the tip) is the changeset
5287 most recently added to the repository (and therefore the most
5288 most recently added to the repository (and therefore the most
5288 recently changed head).
5289 recently changed head).
5289
5290
5290 If you have just made a commit, that commit will be the tip. If
5291 If you have just made a commit, that commit will be the tip. If
5291 you have just pulled changes from another repository, the tip of
5292 you have just pulled changes from another repository, the tip of
5292 that repository becomes the current tip. The "tip" tag is special
5293 that repository becomes the current tip. The "tip" tag is special
5293 and cannot be renamed or assigned to a different changeset.
5294 and cannot be renamed or assigned to a different changeset.
5294
5295
5295 Returns 0 on success.
5296 Returns 0 on success.
5296 """
5297 """
5297 displayer = cmdutil.show_changeset(ui, repo, opts)
5298 displayer = cmdutil.show_changeset(ui, repo, opts)
5298 displayer.show(repo[len(repo) - 1])
5299 displayer.show(repo[len(repo) - 1])
5299 displayer.close()
5300 displayer.close()
5300
5301
5301 @command('unbundle',
5302 @command('unbundle',
5302 [('u', 'update', None,
5303 [('u', 'update', None,
5303 _('update to new branch head if changesets were unbundled'))],
5304 _('update to new branch head if changesets were unbundled'))],
5304 _('[-u] FILE...'))
5305 _('[-u] FILE...'))
5305 def unbundle(ui, repo, fname1, *fnames, **opts):
5306 def unbundle(ui, repo, fname1, *fnames, **opts):
5306 """apply one or more changegroup files
5307 """apply one or more changegroup files
5307
5308
5308 Apply one or more compressed changegroup files generated by the
5309 Apply one or more compressed changegroup files generated by the
5309 bundle command.
5310 bundle command.
5310
5311
5311 Returns 0 on success, 1 if an update has unresolved files.
5312 Returns 0 on success, 1 if an update has unresolved files.
5312 """
5313 """
5313 fnames = (fname1,) + fnames
5314 fnames = (fname1,) + fnames
5314
5315
5315 lock = repo.lock()
5316 lock = repo.lock()
5316 wc = repo['.']
5317 wc = repo['.']
5317 try:
5318 try:
5318 for fname in fnames:
5319 for fname in fnames:
5319 f = url.open(ui, fname)
5320 f = url.open(ui, fname)
5320 gen = changegroup.readbundle(f, fname)
5321 gen = changegroup.readbundle(f, fname)
5321 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5322 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5322 lock=lock)
5323 lock=lock)
5323 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5324 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5324 finally:
5325 finally:
5325 lock.release()
5326 lock.release()
5326 return postincoming(ui, repo, modheads, opts.get('update'), None)
5327 return postincoming(ui, repo, modheads, opts.get('update'), None)
5327
5328
5328 @command('^update|up|checkout|co',
5329 @command('^update|up|checkout|co',
5329 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5330 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5330 ('c', 'check', None,
5331 ('c', 'check', None,
5331 _('update across branches if no uncommitted changes')),
5332 _('update across branches if no uncommitted changes')),
5332 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5333 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5333 ('r', 'rev', '', _('revision'), _('REV'))],
5334 ('r', 'rev', '', _('revision'), _('REV'))],
5334 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5335 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5335 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5336 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5336 """update working directory (or switch revisions)
5337 """update working directory (or switch revisions)
5337
5338
5338 Update the repository's working directory to the specified
5339 Update the repository's working directory to the specified
5339 changeset. If no changeset is specified, update to the tip of the
5340 changeset. If no changeset is specified, update to the tip of the
5340 current named branch.
5341 current named branch.
5341
5342
5342 If the changeset is not a descendant of the working directory's
5343 If the changeset is not a descendant of the working directory's
5343 parent, the update is aborted. With the -c/--check option, the
5344 parent, the update is aborted. With the -c/--check option, the
5344 working directory is checked for uncommitted changes; if none are
5345 working directory is checked for uncommitted changes; if none are
5345 found, the working directory is updated to the specified
5346 found, the working directory is updated to the specified
5346 changeset.
5347 changeset.
5347
5348
5348 Update sets the working directory's parent revison to the specified
5349 Update sets the working directory's parent revison to the specified
5349 changeset (see :hg:`help parents`).
5350 changeset (see :hg:`help parents`).
5350
5351
5351 The following rules apply when the working directory contains
5352 The following rules apply when the working directory contains
5352 uncommitted changes:
5353 uncommitted changes:
5353
5354
5354 1. If neither -c/--check nor -C/--clean is specified, and if
5355 1. If neither -c/--check nor -C/--clean is specified, and if
5355 the requested changeset is an ancestor or descendant of
5356 the requested changeset is an ancestor or descendant of
5356 the working directory's parent, the uncommitted changes
5357 the working directory's parent, the uncommitted changes
5357 are merged into the requested changeset and the merged
5358 are merged into the requested changeset and the merged
5358 result is left uncommitted. If the requested changeset is
5359 result is left uncommitted. If the requested changeset is
5359 not an ancestor or descendant (that is, it is on another
5360 not an ancestor or descendant (that is, it is on another
5360 branch), the update is aborted and the uncommitted changes
5361 branch), the update is aborted and the uncommitted changes
5361 are preserved.
5362 are preserved.
5362
5363
5363 2. With the -c/--check option, the update is aborted and the
5364 2. With the -c/--check option, the update is aborted and the
5364 uncommitted changes are preserved.
5365 uncommitted changes are preserved.
5365
5366
5366 3. With the -C/--clean option, uncommitted changes are discarded and
5367 3. With the -C/--clean option, uncommitted changes are discarded and
5367 the working directory is updated to the requested changeset.
5368 the working directory is updated to the requested changeset.
5368
5369
5369 Use null as the changeset to remove the working directory (like
5370 Use null as the changeset to remove the working directory (like
5370 :hg:`clone -U`).
5371 :hg:`clone -U`).
5371
5372
5372 If you want to revert just one file to an older revision, use
5373 If you want to revert just one file to an older revision, use
5373 :hg:`revert [-r REV] NAME`.
5374 :hg:`revert [-r REV] NAME`.
5374
5375
5375 See :hg:`help dates` for a list of formats valid for -d/--date.
5376 See :hg:`help dates` for a list of formats valid for -d/--date.
5376
5377
5377 Returns 0 on success, 1 if there are unresolved files.
5378 Returns 0 on success, 1 if there are unresolved files.
5378 """
5379 """
5379 if rev and node:
5380 if rev and node:
5380 raise util.Abort(_("please specify just one revision"))
5381 raise util.Abort(_("please specify just one revision"))
5381
5382
5382 if rev is None or rev == '':
5383 if rev is None or rev == '':
5383 rev = node
5384 rev = node
5384
5385
5385 # if we defined a bookmark, we have to remember the original bookmark name
5386 # if we defined a bookmark, we have to remember the original bookmark name
5386 brev = rev
5387 brev = rev
5387 rev = scmutil.revsingle(repo, rev, rev).rev()
5388 rev = scmutil.revsingle(repo, rev, rev).rev()
5388
5389
5389 if check and clean:
5390 if check and clean:
5390 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5391 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5391
5392
5392 if check:
5393 if check:
5393 # we could use dirty() but we can ignore merge and branch trivia
5394 # we could use dirty() but we can ignore merge and branch trivia
5394 c = repo[None]
5395 c = repo[None]
5395 if c.modified() or c.added() or c.removed():
5396 if c.modified() or c.added() or c.removed():
5396 raise util.Abort(_("uncommitted local changes"))
5397 raise util.Abort(_("uncommitted local changes"))
5397
5398
5398 if date:
5399 if date:
5399 if rev is not None:
5400 if rev is not None:
5400 raise util.Abort(_("you can't specify a revision and a date"))
5401 raise util.Abort(_("you can't specify a revision and a date"))
5401 rev = cmdutil.finddate(ui, repo, date)
5402 rev = cmdutil.finddate(ui, repo, date)
5402
5403
5403 if clean or check:
5404 if clean or check:
5404 ret = hg.clean(repo, rev)
5405 ret = hg.clean(repo, rev)
5405 else:
5406 else:
5406 ret = hg.update(repo, rev)
5407 ret = hg.update(repo, rev)
5407
5408
5408 if brev in repo._bookmarks:
5409 if brev in repo._bookmarks:
5409 bookmarks.setcurrent(repo, brev)
5410 bookmarks.setcurrent(repo, brev)
5410
5411
5411 return ret
5412 return ret
5412
5413
5413 @command('verify', [])
5414 @command('verify', [])
5414 def verify(ui, repo):
5415 def verify(ui, repo):
5415 """verify the integrity of the repository
5416 """verify the integrity of the repository
5416
5417
5417 Verify the integrity of the current repository.
5418 Verify the integrity of the current repository.
5418
5419
5419 This will perform an extensive check of the repository's
5420 This will perform an extensive check of the repository's
5420 integrity, validating the hashes and checksums of each entry in
5421 integrity, validating the hashes and checksums of each entry in
5421 the changelog, manifest, and tracked files, as well as the
5422 the changelog, manifest, and tracked files, as well as the
5422 integrity of their crosslinks and indices.
5423 integrity of their crosslinks and indices.
5423
5424
5424 Returns 0 on success, 1 if errors are encountered.
5425 Returns 0 on success, 1 if errors are encountered.
5425 """
5426 """
5426 return hg.verify(repo)
5427 return hg.verify(repo)
5427
5428
5428 @command('version', [])
5429 @command('version', [])
5429 def version_(ui):
5430 def version_(ui):
5430 """output version and copyright information"""
5431 """output version and copyright information"""
5431 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5432 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5432 % util.version())
5433 % util.version())
5433 ui.status(_(
5434 ui.status(_(
5434 "(see http://mercurial.selenic.com for more information)\n"
5435 "(see http://mercurial.selenic.com for more information)\n"
5435 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5436 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5436 "This is free software; see the source for copying conditions. "
5437 "This is free software; see the source for copying conditions. "
5437 "There is NO\nwarranty; "
5438 "There is NO\nwarranty; "
5438 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5439 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5439 ))
5440 ))
5440
5441
5441 norepo = ("clone init version help debugcommands debugcomplete"
5442 norepo = ("clone init version help debugcommands debugcomplete"
5442 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5443 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5443 " debugknown debuggetbundle debugbundle")
5444 " debugknown debuggetbundle debugbundle")
5444 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5445 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5445 " debugdata debugindex debugindexdot debugrevlog")
5446 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,579 +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
21 import re
22 import util, encoding
22 import util, encoding
23 from i18n import _
23 from i18n import _
24
24
25 def replace(text, substs):
25 def replace(text, substs):
26 for f, t in substs:
26 for f, t in substs:
27 text = text.replace(f, t)
27 text = text.replace(f, t)
28 return text
28 return text
29
29
30 _blockre = re.compile(r"\n(?:\s*\n)+")
30 _blockre = re.compile(r"\n(?:\s*\n)+")
31
31
32 def findblocks(text):
32 def findblocks(text):
33 """Find continuous blocks of lines in text.
33 """Find continuous blocks of lines in text.
34
34
35 Returns a list of dictionaries representing the blocks. Each block
35 Returns a list of dictionaries representing the blocks. Each block
36 has an 'indent' field and a 'lines' field.
36 has an 'indent' field and a 'lines' field.
37 """
37 """
38 blocks = []
38 blocks = []
39 for b in _blockre.split(text.lstrip('\n').rstrip()):
39 for b in _blockre.split(text.lstrip('\n').rstrip()):
40 lines = b.splitlines()
40 lines = b.splitlines()
41 if lines:
41 if lines:
42 indent = min((len(l) - len(l.lstrip())) for l in lines)
42 indent = min((len(l) - len(l.lstrip())) for l in lines)
43 lines = [l[indent:] for l in lines]
43 lines = [l[indent:] for l in lines]
44 blocks.append(dict(indent=indent, lines=lines))
44 blocks.append(dict(indent=indent, lines=lines))
45 return blocks
45 return blocks
46
46
47 def findliteralblocks(blocks):
47 def findliteralblocks(blocks):
48 """Finds literal blocks and adds a 'type' field to the blocks.
48 """Finds literal blocks and adds a 'type' field to the blocks.
49
49
50 Literal blocks are given the type 'literal', all other blocks are
50 Literal blocks are given the type 'literal', all other blocks are
51 given type the 'paragraph'.
51 given type the 'paragraph'.
52 """
52 """
53 i = 0
53 i = 0
54 while i < len(blocks):
54 while i < len(blocks):
55 # Searching for a block that looks like this:
55 # Searching for a block that looks like this:
56 #
56 #
57 # +------------------------------+
57 # +------------------------------+
58 # | paragraph |
58 # | paragraph |
59 # | (ends with "::") |
59 # | (ends with "::") |
60 # +------------------------------+
60 # +------------------------------+
61 # +---------------------------+
61 # +---------------------------+
62 # | indented literal block |
62 # | indented literal block |
63 # +---------------------------+
63 # +---------------------------+
64 blocks[i]['type'] = 'paragraph'
64 blocks[i]['type'] = 'paragraph'
65 if blocks[i]['lines'][-1].endswith('::') and i + 1 < len(blocks):
65 if blocks[i]['lines'][-1].endswith('::') and i + 1 < len(blocks):
66 indent = blocks[i]['indent']
66 indent = blocks[i]['indent']
67 adjustment = blocks[i + 1]['indent'] - indent
67 adjustment = blocks[i + 1]['indent'] - indent
68
68
69 if blocks[i]['lines'] == ['::']:
69 if blocks[i]['lines'] == ['::']:
70 # Expanded form: remove block
70 # Expanded form: remove block
71 del blocks[i]
71 del blocks[i]
72 i -= 1
72 i -= 1
73 elif blocks[i]['lines'][-1].endswith(' ::'):
73 elif blocks[i]['lines'][-1].endswith(' ::'):
74 # Partially minimized form: remove space and both
74 # Partially minimized form: remove space and both
75 # colons.
75 # colons.
76 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-3]
76 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-3]
77 else:
77 else:
78 # Fully minimized form: remove just one colon.
78 # Fully minimized form: remove just one colon.
79 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-1]
79 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-1]
80
80
81 # List items are formatted with a hanging indent. We must
81 # List items are formatted with a hanging indent. We must
82 # correct for this here while we still have the original
82 # correct for this here while we still have the original
83 # information on the indentation of the subsequent literal
83 # information on the indentation of the subsequent literal
84 # blocks available.
84 # blocks available.
85 m = _bulletre.match(blocks[i]['lines'][0])
85 m = _bulletre.match(blocks[i]['lines'][0])
86 if m:
86 if m:
87 indent += m.end()
87 indent += m.end()
88 adjustment -= m.end()
88 adjustment -= m.end()
89
89
90 # Mark the following indented blocks.
90 # Mark the following indented blocks.
91 while i + 1 < len(blocks) and blocks[i + 1]['indent'] > indent:
91 while i + 1 < len(blocks) and blocks[i + 1]['indent'] > indent:
92 blocks[i + 1]['type'] = 'literal'
92 blocks[i + 1]['type'] = 'literal'
93 blocks[i + 1]['indent'] -= adjustment
93 blocks[i + 1]['indent'] -= adjustment
94 i += 1
94 i += 1
95 i += 1
95 i += 1
96 return blocks
96 return blocks
97
97
98 _bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)|\|) ')
98 _bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)|\|) ')
99 _optionre = re.compile(r'^(-([a-zA-Z0-9]), )?(--[a-z0-9-]+)'
99 _optionre = re.compile(r'^(-([a-zA-Z0-9]), )?(--[a-z0-9-]+)'
100 r'((.*) +)(.*)$')
100 r'((.*) +)(.*)$')
101 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):[ ]+(.*)')
101 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):[ ]+(.*)')
102 _definitionre = re.compile(r'[^ ]')
102 _definitionre = re.compile(r'[^ ]')
103 _tablere = re.compile(r'(=+\s+)*=+')
103 _tablere = re.compile(r'(=+\s+)*=+')
104
104
105 def splitparagraphs(blocks):
105 def splitparagraphs(blocks):
106 """Split paragraphs into lists."""
106 """Split paragraphs into lists."""
107 # Tuples with (list type, item regexp, single line items?). Order
107 # Tuples with (list type, item regexp, single line items?). Order
108 # matters: definition lists has the least specific regexp and must
108 # matters: definition lists has the least specific regexp and must
109 # come last.
109 # come last.
110 listtypes = [('bullet', _bulletre, True),
110 listtypes = [('bullet', _bulletre, True),
111 ('option', _optionre, True),
111 ('option', _optionre, True),
112 ('field', _fieldre, True),
112 ('field', _fieldre, True),
113 ('definition', _definitionre, False)]
113 ('definition', _definitionre, False)]
114
114
115 def match(lines, i, itemre, singleline):
115 def match(lines, i, itemre, singleline):
116 """Does itemre match an item at line i?
116 """Does itemre match an item at line i?
117
117
118 A list item can be followed by an idented line or another list
118 A list item can be followed by an idented line or another list
119 item (but only if singleline is True).
119 item (but only if singleline is True).
120 """
120 """
121 line1 = lines[i]
121 line1 = lines[i]
122 line2 = i + 1 < len(lines) and lines[i + 1] or ''
122 line2 = i + 1 < len(lines) and lines[i + 1] or ''
123 if not itemre.match(line1):
123 if not itemre.match(line1):
124 return False
124 return False
125 if singleline:
125 if singleline:
126 return line2 == '' or line2[0] == ' ' or itemre.match(line2)
126 return line2 == '' or line2[0] == ' ' or itemre.match(line2)
127 else:
127 else:
128 return line2.startswith(' ')
128 return line2.startswith(' ')
129
129
130 i = 0
130 i = 0
131 while i < len(blocks):
131 while i < len(blocks):
132 if blocks[i]['type'] == 'paragraph':
132 if blocks[i]['type'] == 'paragraph':
133 lines = blocks[i]['lines']
133 lines = blocks[i]['lines']
134 for type, itemre, singleline in listtypes:
134 for type, itemre, singleline in listtypes:
135 if match(lines, 0, itemre, singleline):
135 if match(lines, 0, itemre, singleline):
136 items = []
136 items = []
137 for j, line in enumerate(lines):
137 for j, line in enumerate(lines):
138 if match(lines, j, itemre, singleline):
138 if match(lines, j, itemre, singleline):
139 items.append(dict(type=type, lines=[],
139 items.append(dict(type=type, lines=[],
140 indent=blocks[i]['indent']))
140 indent=blocks[i]['indent']))
141 items[-1]['lines'].append(line)
141 items[-1]['lines'].append(line)
142 blocks[i:i + 1] = items
142 blocks[i:i + 1] = items
143 break
143 break
144 i += 1
144 i += 1
145 return blocks
145 return blocks
146
146
147 _fieldwidth = 12
147 _fieldwidth = 12
148
148
149 def updatefieldlists(blocks):
149 def updatefieldlists(blocks):
150 """Find key and maximum key width for field lists."""
150 """Find key and maximum key width for field lists."""
151 i = 0
151 i = 0
152 while i < len(blocks):
152 while i < len(blocks):
153 if blocks[i]['type'] != 'field':
153 if blocks[i]['type'] != 'field':
154 i += 1
154 i += 1
155 continue
155 continue
156
156
157 keywidth = 0
157 keywidth = 0
158 j = i
158 j = i
159 while j < len(blocks) and blocks[j]['type'] == 'field':
159 while j < len(blocks) and blocks[j]['type'] == 'field':
160 m = _fieldre.match(blocks[j]['lines'][0])
160 m = _fieldre.match(blocks[j]['lines'][0])
161 key, rest = m.groups()
161 key, rest = m.groups()
162 blocks[j]['lines'][0] = rest
162 blocks[j]['lines'][0] = rest
163 blocks[j]['key'] = key
163 blocks[j]['key'] = key
164 keywidth = max(keywidth, len(key))
164 keywidth = max(keywidth, len(key))
165 j += 1
165 j += 1
166
166
167 for block in blocks[i:j]:
167 for block in blocks[i:j]:
168 block['keywidth'] = keywidth
168 block['keywidth'] = keywidth
169 i = j + 1
169 i = j + 1
170
170
171 return blocks
171 return blocks
172
172
173 def updateoptionlists(blocks):
173 def updateoptionlists(blocks):
174 i = 0
174 i = 0
175 while i < len(blocks):
175 while i < len(blocks):
176 if blocks[i]['type'] != 'option':
176 if blocks[i]['type'] != 'option':
177 i += 1
177 i += 1
178 continue
178 continue
179
179
180 optstrwidth = 0
180 optstrwidth = 0
181 j = i
181 j = i
182 while j < len(blocks) and blocks[j]['type'] == 'option':
182 while j < len(blocks) and blocks[j]['type'] == 'option':
183 m = _optionre.match(blocks[j]['lines'][0])
183 m = _optionre.match(blocks[j]['lines'][0])
184
184
185 shortoption = m.group(2)
185 shortoption = m.group(2)
186 group3 = m.group(3)
186 group3 = m.group(3)
187 longoption = group3[2:].strip()
187 longoption = group3[2:].strip()
188 desc = m.group(6).strip()
188 desc = m.group(6).strip()
189 longoptionarg = m.group(5).strip()
189 longoptionarg = m.group(5).strip()
190 blocks[j]['lines'][0] = desc
190 blocks[j]['lines'][0] = desc
191
191
192 noshortop = ''
192 noshortop = ''
193 if not shortoption:
193 if not shortoption:
194 noshortop = ' '
194 noshortop = ' '
195
195
196 opt = "%s%s" % (shortoption and "-%s " % shortoption or '',
196 opt = "%s%s" % (shortoption and "-%s " % shortoption or '',
197 ("%s--%s %s") % (noshortop, longoption,
197 ("%s--%s %s") % (noshortop, longoption,
198 longoptionarg))
198 longoptionarg))
199 opt = opt.rstrip()
199 opt = opt.rstrip()
200 blocks[j]['optstr'] = opt
200 blocks[j]['optstr'] = opt
201 optstrwidth = max(optstrwidth, encoding.colwidth(opt))
201 optstrwidth = max(optstrwidth, encoding.colwidth(opt))
202 j += 1
202 j += 1
203
203
204 for block in blocks[i:j]:
204 for block in blocks[i:j]:
205 block['optstrwidth'] = optstrwidth
205 block['optstrwidth'] = optstrwidth
206 i = j + 1
206 i = j + 1
207 return blocks
207 return blocks
208
208
209 def prunecontainers(blocks, keep):
209 def prunecontainers(blocks, keep):
210 """Prune unwanted containers.
210 """Prune unwanted containers.
211
211
212 The blocks must have a 'type' field, i.e., they should have been
212 The blocks must have a 'type' field, i.e., they should have been
213 run through findliteralblocks first.
213 run through findliteralblocks first.
214 """
214 """
215 pruned = []
215 pruned = []
216 i = 0
216 i = 0
217 while i + 1 < len(blocks):
217 while i + 1 < len(blocks):
218 # Searching for a block that looks like this:
218 # Searching for a block that looks like this:
219 #
219 #
220 # +-------+---------------------------+
220 # +-------+---------------------------+
221 # | ".. container ::" type |
221 # | ".. container ::" type |
222 # +---+ |
222 # +---+ |
223 # | blocks |
223 # | blocks |
224 # +-------------------------------+
224 # +-------------------------------+
225 if (blocks[i]['type'] == 'paragraph' and
225 if (blocks[i]['type'] == 'paragraph' and
226 blocks[i]['lines'][0].startswith('.. container::')):
226 blocks[i]['lines'][0].startswith('.. container::')):
227 indent = blocks[i]['indent']
227 indent = blocks[i]['indent']
228 adjustment = blocks[i + 1]['indent'] - indent
228 adjustment = blocks[i + 1]['indent'] - indent
229 containertype = blocks[i]['lines'][0][15:]
229 containertype = blocks[i]['lines'][0][15:]
230 prune = containertype not in keep
230 prune = containertype not in keep
231 if prune:
231 if prune:
232 pruned.append(containertype)
232 pruned.append(containertype)
233
233
234 # Always delete "..container:: type" block
234 # Always delete "..container:: type" block
235 del blocks[i]
235 del blocks[i]
236 j = i
236 j = i
237 i -= 1
237 i -= 1
238 while j < len(blocks) and blocks[j]['indent'] > indent:
238 while j < len(blocks) and blocks[j]['indent'] > indent:
239 if prune:
239 if prune:
240 del blocks[j]
240 del blocks[j]
241 else:
241 else:
242 blocks[j]['indent'] -= adjustment
242 blocks[j]['indent'] -= adjustment
243 j += 1
243 j += 1
244 i += 1
244 i += 1
245 return blocks, pruned
245 return blocks, pruned
246
246
247 _sectionre = re.compile(r"""^([-=`:.'"~^_*+#])\1+$""")
247 _sectionre = re.compile(r"""^([-=`:.'"~^_*+#])\1+$""")
248
248
249 def findtables(blocks):
249 def findtables(blocks):
250 '''Find simple tables
250 '''Find simple tables
251
251
252 Only simple one-line table elements are supported
252 Only simple one-line table elements are supported
253 '''
253 '''
254
254
255 for block in blocks:
255 for block in blocks:
256 # Searching for a block that looks like this:
256 # Searching for a block that looks like this:
257 #
257 #
258 # === ==== ===
258 # === ==== ===
259 # A B C
259 # A B C
260 # === ==== === <- optional
260 # === ==== === <- optional
261 # 1 2 3
261 # 1 2 3
262 # x y z
262 # x y z
263 # === ==== ===
263 # === ==== ===
264 if (block['type'] == 'paragraph' and
264 if (block['type'] == 'paragraph' and
265 len(block['lines']) > 4 and
265 len(block['lines']) > 2 and
266 _tablere.match(block['lines'][0]) and
266 _tablere.match(block['lines'][0]) and
267 block['lines'][0] == block['lines'][-1]):
267 block['lines'][0] == block['lines'][-1]):
268 block['type'] = 'table'
268 block['type'] = 'table'
269 block['header'] = False
269 block['header'] = False
270 div = block['lines'][0]
270 div = block['lines'][0]
271
271
272 # column markers are ASCII so we can calculate column
272 # column markers are ASCII so we can calculate column
273 # position in bytes
273 # position in bytes
274 columns = [x for x in xrange(len(div))
274 columns = [x for x in xrange(len(div))
275 if div[x] == '=' and (x == 0 or div[x - 1] == ' ')]
275 if div[x] == '=' and (x == 0 or div[x - 1] == ' ')]
276 rows = []
276 rows = []
277 for l in block['lines'][1:-1]:
277 for l in block['lines'][1:-1]:
278 if l == div:
278 if l == div:
279 block['header'] = True
279 block['header'] = True
280 continue
280 continue
281 row = []
281 row = []
282 # we measure columns not in bytes or characters but in
282 # we measure columns not in bytes or characters but in
283 # colwidth which makes things tricky
283 # colwidth which makes things tricky
284 pos = columns[0] # leading whitespace is bytes
284 pos = columns[0] # leading whitespace is bytes
285 for n, start in enumerate(columns):
285 for n, start in enumerate(columns):
286 if n + 1 < len(columns):
286 if n + 1 < len(columns):
287 width = columns[n + 1] - start
287 width = columns[n + 1] - start
288 v = encoding.getcols(l, pos, width) # gather columns
288 v = encoding.getcols(l, pos, width) # gather columns
289 pos += len(v) # calculate byte position of end
289 pos += len(v) # calculate byte position of end
290 row.append(v.strip())
290 row.append(v.strip())
291 else:
291 else:
292 row.append(l[pos:].strip())
292 row.append(l[pos:].strip())
293 rows.append(row)
293 rows.append(row)
294
294
295 block['table'] = rows
295 block['table'] = rows
296
296
297 return blocks
297 return blocks
298
298
299 def findsections(blocks):
299 def findsections(blocks):
300 """Finds sections.
300 """Finds sections.
301
301
302 The blocks must have a 'type' field, i.e., they should have been
302 The blocks must have a 'type' field, i.e., they should have been
303 run through findliteralblocks first.
303 run through findliteralblocks first.
304 """
304 """
305 for block in blocks:
305 for block in blocks:
306 # Searching for a block that looks like this:
306 # Searching for a block that looks like this:
307 #
307 #
308 # +------------------------------+
308 # +------------------------------+
309 # | Section title |
309 # | Section title |
310 # | ------------- |
310 # | ------------- |
311 # +------------------------------+
311 # +------------------------------+
312 if (block['type'] == 'paragraph' and
312 if (block['type'] == 'paragraph' and
313 len(block['lines']) == 2 and
313 len(block['lines']) == 2 and
314 encoding.colwidth(block['lines'][0]) == len(block['lines'][1]) and
314 encoding.colwidth(block['lines'][0]) == len(block['lines'][1]) and
315 _sectionre.match(block['lines'][1])):
315 _sectionre.match(block['lines'][1])):
316 block['underline'] = block['lines'][1][0]
316 block['underline'] = block['lines'][1][0]
317 block['type'] = 'section'
317 block['type'] = 'section'
318 del block['lines'][1]
318 del block['lines'][1]
319 return blocks
319 return blocks
320
320
321 def inlineliterals(blocks):
321 def inlineliterals(blocks):
322 substs = [('``', '"')]
322 substs = [('``', '"')]
323 for b in blocks:
323 for b in blocks:
324 if b['type'] in ('paragraph', 'section'):
324 if b['type'] in ('paragraph', 'section'):
325 b['lines'] = [replace(l, substs) for l in b['lines']]
325 b['lines'] = [replace(l, substs) for l in b['lines']]
326 return blocks
326 return blocks
327
327
328 def hgrole(blocks):
328 def hgrole(blocks):
329 substs = [(':hg:`', '"hg '), ('`', '"')]
329 substs = [(':hg:`', '"hg '), ('`', '"')]
330 for b in blocks:
330 for b in blocks:
331 if b['type'] in ('paragraph', 'section'):
331 if b['type'] in ('paragraph', 'section'):
332 # Turn :hg:`command` into "hg command". This also works
332 # Turn :hg:`command` into "hg command". This also works
333 # when there is a line break in the command and relies on
333 # when there is a line break in the command and relies on
334 # the fact that we have no stray back-quotes in the input
334 # the fact that we have no stray back-quotes in the input
335 # (run the blocks through inlineliterals first).
335 # (run the blocks through inlineliterals first).
336 b['lines'] = [replace(l, substs) for l in b['lines']]
336 b['lines'] = [replace(l, substs) for l in b['lines']]
337 return blocks
337 return blocks
338
338
339 def addmargins(blocks):
339 def addmargins(blocks):
340 """Adds empty blocks for vertical spacing.
340 """Adds empty blocks for vertical spacing.
341
341
342 This groups bullets, options, and definitions together with no vertical
342 This groups bullets, options, and definitions together with no vertical
343 space between them, and adds an empty block between all other blocks.
343 space between them, and adds an empty block between all other blocks.
344 """
344 """
345 i = 1
345 i = 1
346 while i < len(blocks):
346 while i < len(blocks):
347 if (blocks[i]['type'] == blocks[i - 1]['type'] and
347 if (blocks[i]['type'] == blocks[i - 1]['type'] and
348 blocks[i]['type'] in ('bullet', 'option', 'field')):
348 blocks[i]['type'] in ('bullet', 'option', 'field')):
349 i += 1
349 i += 1
350 else:
350 else:
351 blocks.insert(i, dict(lines=[''], indent=0, type='margin'))
351 blocks.insert(i, dict(lines=[''], indent=0, type='margin'))
352 i += 2
352 i += 2
353 return blocks
353 return blocks
354
354
355 def prunecomments(blocks):
355 def prunecomments(blocks):
356 """Remove comments."""
356 """Remove comments."""
357 i = 0
357 i = 0
358 while i < len(blocks):
358 while i < len(blocks):
359 b = blocks[i]
359 b = blocks[i]
360 if b['type'] == 'paragraph' and (b['lines'][0].startswith('.. ') or
360 if b['type'] == 'paragraph' and (b['lines'][0].startswith('.. ') or
361 b['lines'] == ['..']):
361 b['lines'] == ['..']):
362 del blocks[i]
362 del blocks[i]
363 if i < len(blocks) and blocks[i]['type'] == 'margin':
363 if i < len(blocks) and blocks[i]['type'] == 'margin':
364 del blocks[i]
364 del blocks[i]
365 else:
365 else:
366 i += 1
366 i += 1
367 return blocks
367 return blocks
368
368
369 _admonitionre = re.compile(r"\.\. (admonition|attention|caution|danger|"
369 _admonitionre = re.compile(r"\.\. (admonition|attention|caution|danger|"
370 r"error|hint|important|note|tip|warning)::",
370 r"error|hint|important|note|tip|warning)::",
371 flags=re.IGNORECASE)
371 flags=re.IGNORECASE)
372
372
373 def findadmonitions(blocks):
373 def findadmonitions(blocks):
374 """
374 """
375 Makes the type of the block an admonition block if
375 Makes the type of the block an admonition block if
376 the first line is an admonition directive
376 the first line is an admonition directive
377 """
377 """
378 i = 0
378 i = 0
379 while i < len(blocks):
379 while i < len(blocks):
380 m = _admonitionre.match(blocks[i]['lines'][0])
380 m = _admonitionre.match(blocks[i]['lines'][0])
381 if m:
381 if m:
382 blocks[i]['type'] = 'admonition'
382 blocks[i]['type'] = 'admonition'
383 admonitiontitle = blocks[i]['lines'][0][3:m.end() - 2].lower()
383 admonitiontitle = blocks[i]['lines'][0][3:m.end() - 2].lower()
384
384
385 firstline = blocks[i]['lines'][0][m.end() + 1:]
385 firstline = blocks[i]['lines'][0][m.end() + 1:]
386 if firstline:
386 if firstline:
387 blocks[i]['lines'].insert(1, ' ' + firstline)
387 blocks[i]['lines'].insert(1, ' ' + firstline)
388
388
389 blocks[i]['admonitiontitle'] = admonitiontitle
389 blocks[i]['admonitiontitle'] = admonitiontitle
390 del blocks[i]['lines'][0]
390 del blocks[i]['lines'][0]
391 i = i + 1
391 i = i + 1
392 return blocks
392 return blocks
393
393
394 _admonitiontitles = {'attention': _('Attention:'),
394 _admonitiontitles = {'attention': _('Attention:'),
395 'caution': _('Caution:'),
395 'caution': _('Caution:'),
396 'danger': _('!Danger!') ,
396 'danger': _('!Danger!') ,
397 'error': _('Error:'),
397 'error': _('Error:'),
398 'hint': _('Hint:'),
398 'hint': _('Hint:'),
399 'important': _('Important:'),
399 'important': _('Important:'),
400 'note': _('Note:'),
400 'note': _('Note:'),
401 'tip': _('Tip:'),
401 'tip': _('Tip:'),
402 'warning': _('Warning!')}
402 'warning': _('Warning!')}
403
403
404 def formatoption(block, width):
404 def formatoption(block, width):
405 desc = ' '.join(map(str.strip, block['lines']))
405 desc = ' '.join(map(str.strip, block['lines']))
406 colwidth = encoding.colwidth(block['optstr'])
406 colwidth = encoding.colwidth(block['optstr'])
407 usablewidth = width - 1
407 usablewidth = width - 1
408 hanging = block['optstrwidth']
408 hanging = block['optstrwidth']
409 initindent = '%s%s ' % (block['optstr'], ' ' * ((hanging - colwidth)))
409 initindent = '%s%s ' % (block['optstr'], ' ' * ((hanging - colwidth)))
410 hangindent = ' ' * (encoding.colwidth(initindent) + 1)
410 hangindent = ' ' * (encoding.colwidth(initindent) + 1)
411 return ' %s\n' % (util.wrap(desc, usablewidth,
411 return ' %s\n' % (util.wrap(desc, usablewidth,
412 initindent=initindent,
412 initindent=initindent,
413 hangindent=hangindent))
413 hangindent=hangindent))
414
414
415 def formatblock(block, width):
415 def formatblock(block, width):
416 """Format a block according to width."""
416 """Format a block according to width."""
417 if width <= 0:
417 if width <= 0:
418 width = 78
418 width = 78
419 indent = ' ' * block['indent']
419 indent = ' ' * block['indent']
420 if block['type'] == 'admonition':
420 if block['type'] == 'admonition':
421 admonition = _admonitiontitles[block['admonitiontitle']]
421 admonition = _admonitiontitles[block['admonitiontitle']]
422 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
422 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
423
423
424 defindent = indent + hang * ' '
424 defindent = indent + hang * ' '
425 text = ' '.join(map(str.strip, block['lines']))
425 text = ' '.join(map(str.strip, block['lines']))
426 return '%s\n%s\n' % (indent + admonition,
426 return '%s\n%s\n' % (indent + admonition,
427 util.wrap(text, width=width,
427 util.wrap(text, width=width,
428 initindent=defindent,
428 initindent=defindent,
429 hangindent=defindent))
429 hangindent=defindent))
430 if block['type'] == 'margin':
430 if block['type'] == 'margin':
431 return '\n'
431 return '\n'
432 if block['type'] == 'literal':
432 if block['type'] == 'literal':
433 indent += ' '
433 indent += ' '
434 return indent + ('\n' + indent).join(block['lines']) + '\n'
434 return indent + ('\n' + indent).join(block['lines']) + '\n'
435 if block['type'] == 'section':
435 if block['type'] == 'section':
436 underline = encoding.colwidth(block['lines'][0]) * block['underline']
436 underline = encoding.colwidth(block['lines'][0]) * block['underline']
437 return "%s%s\n%s%s\n" % (indent, block['lines'][0],indent, underline)
437 return "%s%s\n%s%s\n" % (indent, block['lines'][0],indent, underline)
438 if block['type'] == 'table':
438 if block['type'] == 'table':
439 table = block['table']
439 table = block['table']
440 # compute column widths
440 # compute column widths
441 widths = [max([encoding.colwidth(e) for e in c]) for c in zip(*table)]
441 widths = [max([encoding.colwidth(e) for e in c]) for c in zip(*table)]
442 text = ''
442 text = ''
443 span = sum(widths) + len(widths) - 1
443 span = sum(widths) + len(widths) - 1
444 indent = ' ' * block['indent']
444 indent = ' ' * block['indent']
445 hang = ' ' * (len(indent) + span - widths[-1])
445 hang = ' ' * (len(indent) + span - widths[-1])
446
446
447 for row in table:
447 for row in table:
448 l = []
448 l = []
449 for w, v in zip(widths, row):
449 for w, v in zip(widths, row):
450 pad = ' ' * (w - encoding.colwidth(v))
450 pad = ' ' * (w - encoding.colwidth(v))
451 l.append(v + pad)
451 l.append(v + pad)
452 l = ' '.join(l)
452 l = ' '.join(l)
453 l = util.wrap(l, width=width, initindent=indent, hangindent=hang)
453 l = util.wrap(l, width=width, initindent=indent, hangindent=hang)
454 if not text and block['header']:
454 if not text and block['header']:
455 text = l + '\n' + indent + '-' * (min(width, span)) + '\n'
455 text = l + '\n' + indent + '-' * (min(width, span)) + '\n'
456 else:
456 else:
457 text += l + "\n"
457 text += l + "\n"
458 return text
458 return text
459 if block['type'] == 'definition':
459 if block['type'] == 'definition':
460 term = indent + block['lines'][0]
460 term = indent + block['lines'][0]
461 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
461 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
462 defindent = indent + hang * ' '
462 defindent = indent + hang * ' '
463 text = ' '.join(map(str.strip, block['lines'][1:]))
463 text = ' '.join(map(str.strip, block['lines'][1:]))
464 return '%s\n%s\n' % (term, util.wrap(text, width=width,
464 return '%s\n%s\n' % (term, util.wrap(text, width=width,
465 initindent=defindent,
465 initindent=defindent,
466 hangindent=defindent))
466 hangindent=defindent))
467 subindent = indent
467 subindent = indent
468 if block['type'] == 'bullet':
468 if block['type'] == 'bullet':
469 if block['lines'][0].startswith('| '):
469 if block['lines'][0].startswith('| '):
470 # Remove bullet for line blocks and add no extra
470 # Remove bullet for line blocks and add no extra
471 # indention.
471 # indention.
472 block['lines'][0] = block['lines'][0][2:]
472 block['lines'][0] = block['lines'][0][2:]
473 else:
473 else:
474 m = _bulletre.match(block['lines'][0])
474 m = _bulletre.match(block['lines'][0])
475 subindent = indent + m.end() * ' '
475 subindent = indent + m.end() * ' '
476 elif block['type'] == 'field':
476 elif block['type'] == 'field':
477 keywidth = block['keywidth']
477 keywidth = block['keywidth']
478 key = block['key']
478 key = block['key']
479
479
480 subindent = indent + _fieldwidth * ' '
480 subindent = indent + _fieldwidth * ' '
481 if len(key) + 2 > _fieldwidth:
481 if len(key) + 2 > _fieldwidth:
482 # key too large, use full line width
482 # key too large, use full line width
483 key = key.ljust(width)
483 key = key.ljust(width)
484 elif keywidth + 2 < _fieldwidth:
484 elif keywidth + 2 < _fieldwidth:
485 # all keys are small, add only two spaces
485 # all keys are small, add only two spaces
486 key = key.ljust(keywidth + 2)
486 key = key.ljust(keywidth + 2)
487 subindent = indent + (keywidth + 2) * ' '
487 subindent = indent + (keywidth + 2) * ' '
488 else:
488 else:
489 # mixed sizes, use fieldwidth for this one
489 # mixed sizes, use fieldwidth for this one
490 key = key.ljust(_fieldwidth)
490 key = key.ljust(_fieldwidth)
491 block['lines'][0] = key + block['lines'][0]
491 block['lines'][0] = key + block['lines'][0]
492 elif block['type'] == 'option':
492 elif block['type'] == 'option':
493 return formatoption(block, width)
493 return formatoption(block, width)
494
494
495 text = ' '.join(map(str.strip, block['lines']))
495 text = ' '.join(map(str.strip, block['lines']))
496 return util.wrap(text, width=width,
496 return util.wrap(text, width=width,
497 initindent=indent,
497 initindent=indent,
498 hangindent=subindent) + '\n'
498 hangindent=subindent) + '\n'
499
499
500 def parse(text, indent=0, keep=None):
500 def parse(text, indent=0, keep=None):
501 """Parse text into a list of blocks"""
501 """Parse text into a list of blocks"""
502 pruned = []
502 pruned = []
503 blocks = findblocks(text)
503 blocks = findblocks(text)
504 for b in blocks:
504 for b in blocks:
505 b['indent'] += indent
505 b['indent'] += indent
506 blocks = findliteralblocks(blocks)
506 blocks = findliteralblocks(blocks)
507 blocks = findtables(blocks)
507 blocks = findtables(blocks)
508 blocks, pruned = prunecontainers(blocks, keep or [])
508 blocks, pruned = prunecontainers(blocks, keep or [])
509 blocks = findsections(blocks)
509 blocks = findsections(blocks)
510 blocks = inlineliterals(blocks)
510 blocks = inlineliterals(blocks)
511 blocks = hgrole(blocks)
511 blocks = hgrole(blocks)
512 blocks = splitparagraphs(blocks)
512 blocks = splitparagraphs(blocks)
513 blocks = updatefieldlists(blocks)
513 blocks = updatefieldlists(blocks)
514 blocks = updateoptionlists(blocks)
514 blocks = updateoptionlists(blocks)
515 blocks = addmargins(blocks)
515 blocks = addmargins(blocks)
516 blocks = prunecomments(blocks)
516 blocks = prunecomments(blocks)
517 blocks = findadmonitions(blocks)
517 blocks = findadmonitions(blocks)
518 return blocks, pruned
518 return blocks, pruned
519
519
520 def formatblocks(blocks, width):
520 def formatblocks(blocks, width):
521 text = ''.join(formatblock(b, width) for b in blocks)
521 text = ''.join(formatblock(b, width) for b in blocks)
522 return text
522 return text
523
523
524 def format(text, width, indent=0, keep=None):
524 def format(text, width, indent=0, keep=None):
525 """Parse and format the text according to width."""
525 """Parse and format the text according to width."""
526 blocks, pruned = parse(text, indent, keep or [])
526 blocks, pruned = parse(text, indent, keep or [])
527 text = ''.join(formatblock(b, width) for b in blocks)
527 text = ''.join(formatblock(b, width) for b in blocks)
528 if keep is None:
528 if keep is None:
529 return text
529 return text
530 else:
530 else:
531 return text, pruned
531 return text, pruned
532
532
533 def getsections(blocks):
533 def getsections(blocks):
534 '''return a list of (section name, nesting level, blocks) tuples'''
534 '''return a list of (section name, nesting level, blocks) tuples'''
535 nest = ""
535 nest = ""
536 level = 0
536 level = 0
537 secs = []
537 secs = []
538 for b in blocks:
538 for b in blocks:
539 if b['type'] == 'section':
539 if b['type'] == 'section':
540 i = b['underline']
540 i = b['underline']
541 if i not in nest:
541 if i not in nest:
542 nest += i
542 nest += i
543 level = nest.index(i) + 1
543 level = nest.index(i) + 1
544 nest = nest[:level]
544 nest = nest[:level]
545 secs.append((b['lines'][0], level, [b]))
545 secs.append((b['lines'][0], level, [b]))
546 else:
546 else:
547 if not secs:
547 if not secs:
548 # add an initial empty section
548 # add an initial empty section
549 secs = [('', 0, [])]
549 secs = [('', 0, [])]
550 secs[-1][2].append(b)
550 secs[-1][2].append(b)
551 return secs
551 return secs
552
552
553 def decorateblocks(blocks, width):
553 def decorateblocks(blocks, width):
554 '''generate a list of (section name, line text) pairs for search'''
554 '''generate a list of (section name, line text) pairs for search'''
555 lines = []
555 lines = []
556 for s in getsections(blocks):
556 for s in getsections(blocks):
557 section = s[0]
557 section = s[0]
558 text = formatblocks(s[2], width)
558 text = formatblocks(s[2], width)
559 lines.append([(section, l) for l in text.splitlines(True)])
559 lines.append([(section, l) for l in text.splitlines(True)])
560 return lines
560 return lines
561
561
562 def maketable(data, indent=0, header=False):
562 def maketable(data, indent=0, header=False):
563 '''Generate an RST table for the given table data'''
563 '''Generate an RST table for the given table data'''
564
564
565 widths = [max(encoding.colwidth(e) for e in c) for c in zip(*data)]
565 widths = [max(encoding.colwidth(e) for e in c) for c in zip(*data)]
566 indent = ' ' * indent
566 indent = ' ' * indent
567 div = indent + ' '.join('=' * w for w in widths) + '\n'
567 div = indent + ' '.join('=' * w for w in widths) + '\n'
568
568
569 out = [div]
569 out = [div]
570 for row in data:
570 for row in data:
571 l = []
571 l = []
572 for w, v in zip(widths, row):
572 for w, v in zip(widths, row):
573 pad = ' ' * (w - encoding.colwidth(v))
573 pad = ' ' * (w - encoding.colwidth(v))
574 l.append(v + pad)
574 l.append(v + pad)
575 out.append(indent + ' '.join(l) + "\n")
575 out.append(indent + ' '.join(l) + "\n")
576 if header and len(data) > 1:
576 if header and len(data) > 1:
577 out.insert(2, div)
577 out.insert(2, div)
578 out.append(div)
578 out.append(div)
579 return ''.join(out)
579 return ''.join(out)
General Comments 0
You need to be logged in to leave comments. Login now