##// END OF EJS Templates
help: use the first topic name from helptable, not the longest alias...
Mads Kiilerich -
r17322:7124f984 stable
parent child Browse files
Show More
@@ -1,5895 +1,5895 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, graphmod
18 import dagparser, context, simplemerge, graphmod
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
20 import phases, obsolete
20 import phases, obsolete
21
21
22 table = {}
22 table = {}
23
23
24 command = cmdutil.command(table)
24 command = cmdutil.command(table)
25
25
26 # common command options
26 # common command options
27
27
28 globalopts = [
28 globalopts = [
29 ('R', 'repository', '',
29 ('R', 'repository', '',
30 _('repository root directory or name of overlay bundle file'),
30 _('repository root directory or name of overlay bundle file'),
31 _('REPO')),
31 _('REPO')),
32 ('', 'cwd', '',
32 ('', 'cwd', '',
33 _('change working directory'), _('DIR')),
33 _('change working directory'), _('DIR')),
34 ('y', 'noninteractive', None,
34 ('y', 'noninteractive', None,
35 _('do not prompt, automatically pick the first choice for all prompts')),
35 _('do not prompt, automatically pick the first choice for all prompts')),
36 ('q', 'quiet', None, _('suppress output')),
36 ('q', 'quiet', None, _('suppress output')),
37 ('v', 'verbose', None, _('enable additional output')),
37 ('v', 'verbose', None, _('enable additional output')),
38 ('', 'config', [],
38 ('', 'config', [],
39 _('set/override config option (use \'section.name=value\')'),
39 _('set/override config option (use \'section.name=value\')'),
40 _('CONFIG')),
40 _('CONFIG')),
41 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debug', None, _('enable debugging output')),
42 ('', 'debugger', None, _('start debugger')),
42 ('', 'debugger', None, _('start debugger')),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
44 _('ENCODE')),
44 _('ENCODE')),
45 ('', 'encodingmode', encoding.encodingmode,
45 ('', 'encodingmode', encoding.encodingmode,
46 _('set the charset encoding mode'), _('MODE')),
46 _('set the charset encoding mode'), _('MODE')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
48 ('', 'time', None, _('time how long the command takes')),
48 ('', 'time', None, _('time how long the command takes')),
49 ('', 'profile', None, _('print command execution profile')),
49 ('', 'profile', None, _('print command execution profile')),
50 ('', 'version', None, _('output version information and exit')),
50 ('', 'version', None, _('output version information and exit')),
51 ('h', 'help', None, _('display help and exit')),
51 ('h', 'help', None, _('display help and exit')),
52 ]
52 ]
53
53
54 dryrunopts = [('n', 'dry-run', None,
54 dryrunopts = [('n', 'dry-run', None,
55 _('do not perform actions, just print output'))]
55 _('do not perform actions, just print output'))]
56
56
57 remoteopts = [
57 remoteopts = [
58 ('e', 'ssh', '',
58 ('e', 'ssh', '',
59 _('specify ssh command to use'), _('CMD')),
59 _('specify ssh command to use'), _('CMD')),
60 ('', 'remotecmd', '',
60 ('', 'remotecmd', '',
61 _('specify hg command to run on the remote side'), _('CMD')),
61 _('specify hg command to run on the remote side'), _('CMD')),
62 ('', 'insecure', None,
62 ('', 'insecure', None,
63 _('do not verify server certificate (ignoring web.cacerts config)')),
63 _('do not verify server certificate (ignoring web.cacerts config)')),
64 ]
64 ]
65
65
66 walkopts = [
66 walkopts = [
67 ('I', 'include', [],
67 ('I', 'include', [],
68 _('include names matching the given patterns'), _('PATTERN')),
68 _('include names matching the given patterns'), _('PATTERN')),
69 ('X', 'exclude', [],
69 ('X', 'exclude', [],
70 _('exclude names matching the given patterns'), _('PATTERN')),
70 _('exclude names matching the given patterns'), _('PATTERN')),
71 ]
71 ]
72
72
73 commitopts = [
73 commitopts = [
74 ('m', 'message', '',
74 ('m', 'message', '',
75 _('use text as commit message'), _('TEXT')),
75 _('use text as commit message'), _('TEXT')),
76 ('l', 'logfile', '',
76 ('l', 'logfile', '',
77 _('read commit message from file'), _('FILE')),
77 _('read commit message from file'), _('FILE')),
78 ]
78 ]
79
79
80 commitopts2 = [
80 commitopts2 = [
81 ('d', 'date', '',
81 ('d', 'date', '',
82 _('record the specified date as commit date'), _('DATE')),
82 _('record the specified date as commit date'), _('DATE')),
83 ('u', 'user', '',
83 ('u', 'user', '',
84 _('record the specified user as committer'), _('USER')),
84 _('record the specified user as committer'), _('USER')),
85 ]
85 ]
86
86
87 templateopts = [
87 templateopts = [
88 ('', 'style', '',
88 ('', 'style', '',
89 _('display using template map file'), _('STYLE')),
89 _('display using template map file'), _('STYLE')),
90 ('', 'template', '',
90 ('', 'template', '',
91 _('display with template'), _('TEMPLATE')),
91 _('display with template'), _('TEMPLATE')),
92 ]
92 ]
93
93
94 logopts = [
94 logopts = [
95 ('p', 'patch', None, _('show patch')),
95 ('p', 'patch', None, _('show patch')),
96 ('g', 'git', None, _('use git extended diff format')),
96 ('g', 'git', None, _('use git extended diff format')),
97 ('l', 'limit', '',
97 ('l', 'limit', '',
98 _('limit number of changes displayed'), _('NUM')),
98 _('limit number of changes displayed'), _('NUM')),
99 ('M', 'no-merges', None, _('do not show merges')),
99 ('M', 'no-merges', None, _('do not show merges')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 ('G', 'graph', None, _("show the revision DAG")),
101 ('G', 'graph', None, _("show the revision DAG")),
102 ] + templateopts
102 ] + templateopts
103
103
104 diffopts = [
104 diffopts = [
105 ('a', 'text', None, _('treat all files as text')),
105 ('a', 'text', None, _('treat all files as text')),
106 ('g', 'git', None, _('use git extended diff format')),
106 ('g', 'git', None, _('use git extended diff format')),
107 ('', 'nodates', None, _('omit dates from diff headers'))
107 ('', 'nodates', None, _('omit dates from diff headers'))
108 ]
108 ]
109
109
110 diffwsopts = [
110 diffwsopts = [
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 ]
117 ]
118
118
119 diffopts2 = [
119 diffopts2 = [
120 ('p', 'show-function', None, _('show which function each change is in')),
120 ('p', 'show-function', None, _('show which function each change is in')),
121 ('', 'reverse', None, _('produce a diff that undoes the changes')),
121 ('', 'reverse', None, _('produce a diff that undoes the changes')),
122 ] + diffwsopts + [
122 ] + diffwsopts + [
123 ('U', 'unified', '',
123 ('U', 'unified', '',
124 _('number of lines of context to show'), _('NUM')),
124 _('number of lines of context to show'), _('NUM')),
125 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ('', 'stat', None, _('output diffstat-style summary of changes')),
126 ]
126 ]
127
127
128 mergetoolopts = [
128 mergetoolopts = [
129 ('t', 'tool', '', _('specify merge tool')),
129 ('t', 'tool', '', _('specify merge tool')),
130 ]
130 ]
131
131
132 similarityopts = [
132 similarityopts = [
133 ('s', 'similarity', '',
133 ('s', 'similarity', '',
134 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
134 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
135 ]
135 ]
136
136
137 subrepoopts = [
137 subrepoopts = [
138 ('S', 'subrepos', None,
138 ('S', 'subrepos', None,
139 _('recurse into subrepositories'))
139 _('recurse into subrepositories'))
140 ]
140 ]
141
141
142 # Commands start here, listed alphabetically
142 # Commands start here, listed alphabetically
143
143
144 @command('^add',
144 @command('^add',
145 walkopts + subrepoopts + dryrunopts,
145 walkopts + subrepoopts + dryrunopts,
146 _('[OPTION]... [FILE]...'))
146 _('[OPTION]... [FILE]...'))
147 def add(ui, repo, *pats, **opts):
147 def add(ui, repo, *pats, **opts):
148 """add the specified files on the next commit
148 """add the specified files on the next commit
149
149
150 Schedule files to be version controlled and added to the
150 Schedule files to be version controlled and added to the
151 repository.
151 repository.
152
152
153 The files will be added to the repository at the next commit. To
153 The files will be added to the repository at the next commit. To
154 undo an add before that, see :hg:`forget`.
154 undo an add before that, see :hg:`forget`.
155
155
156 If no names are given, add all files to the repository.
156 If no names are given, add all files to the repository.
157
157
158 .. container:: verbose
158 .. container:: verbose
159
159
160 An example showing how new (unknown) files are added
160 An example showing how new (unknown) files are added
161 automatically by :hg:`add`::
161 automatically by :hg:`add`::
162
162
163 $ ls
163 $ ls
164 foo.c
164 foo.c
165 $ hg status
165 $ hg status
166 ? foo.c
166 ? foo.c
167 $ hg add
167 $ hg add
168 adding foo.c
168 adding foo.c
169 $ hg status
169 $ hg status
170 A foo.c
170 A foo.c
171
171
172 Returns 0 if all files are successfully added.
172 Returns 0 if all files are successfully added.
173 """
173 """
174
174
175 m = scmutil.match(repo[None], pats, opts)
175 m = scmutil.match(repo[None], pats, opts)
176 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
176 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
177 opts.get('subrepos'), prefix="", explicitonly=False)
177 opts.get('subrepos'), prefix="", explicitonly=False)
178 return rejected and 1 or 0
178 return rejected and 1 or 0
179
179
180 @command('addremove',
180 @command('addremove',
181 similarityopts + walkopts + dryrunopts,
181 similarityopts + walkopts + dryrunopts,
182 _('[OPTION]... [FILE]...'))
182 _('[OPTION]... [FILE]...'))
183 def addremove(ui, repo, *pats, **opts):
183 def addremove(ui, repo, *pats, **opts):
184 """add all new files, delete all missing files
184 """add all new files, delete all missing files
185
185
186 Add all new files and remove all missing files from the
186 Add all new files and remove all missing files from the
187 repository.
187 repository.
188
188
189 New files are ignored if they match any of the patterns in
189 New files are ignored if they match any of the patterns in
190 ``.hgignore``. As with add, these changes take effect at the next
190 ``.hgignore``. As with add, these changes take effect at the next
191 commit.
191 commit.
192
192
193 Use the -s/--similarity option to detect renamed files. This
193 Use the -s/--similarity option to detect renamed files. This
194 option takes a percentage between 0 (disabled) and 100 (files must
194 option takes a percentage between 0 (disabled) and 100 (files must
195 be identical) as its parameter. With a parameter greater than 0,
195 be identical) as its parameter. With a parameter greater than 0,
196 this compares every removed file with every added file and records
196 this compares every removed file with every added file and records
197 those similar enough as renames. Detecting renamed files this way
197 those similar enough as renames. Detecting renamed files this way
198 can be expensive. After using this option, :hg:`status -C` can be
198 can be expensive. After using this option, :hg:`status -C` can be
199 used to check which files were identified as moved or renamed. If
199 used to check which files were identified as moved or renamed. If
200 not specified, -s/--similarity defaults to 100 and only renames of
200 not specified, -s/--similarity defaults to 100 and only renames of
201 identical files are detected.
201 identical files are detected.
202
202
203 Returns 0 if all files are successfully added.
203 Returns 0 if all files are successfully added.
204 """
204 """
205 try:
205 try:
206 sim = float(opts.get('similarity') or 100)
206 sim = float(opts.get('similarity') or 100)
207 except ValueError:
207 except ValueError:
208 raise util.Abort(_('similarity must be a number'))
208 raise util.Abort(_('similarity must be a number'))
209 if sim < 0 or sim > 100:
209 if sim < 0 or sim > 100:
210 raise util.Abort(_('similarity must be between 0 and 100'))
210 raise util.Abort(_('similarity must be between 0 and 100'))
211 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
211 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
212
212
213 @command('^annotate|blame',
213 @command('^annotate|blame',
214 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
214 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
215 ('', 'follow', None,
215 ('', 'follow', None,
216 _('follow copies/renames and list the filename (DEPRECATED)')),
216 _('follow copies/renames and list the filename (DEPRECATED)')),
217 ('', 'no-follow', None, _("don't follow copies and renames")),
217 ('', 'no-follow', None, _("don't follow copies and renames")),
218 ('a', 'text', None, _('treat all files as text')),
218 ('a', 'text', None, _('treat all files as text')),
219 ('u', 'user', None, _('list the author (long with -v)')),
219 ('u', 'user', None, _('list the author (long with -v)')),
220 ('f', 'file', None, _('list the filename')),
220 ('f', 'file', None, _('list the filename')),
221 ('d', 'date', None, _('list the date (short with -q)')),
221 ('d', 'date', None, _('list the date (short with -q)')),
222 ('n', 'number', None, _('list the revision number (default)')),
222 ('n', 'number', None, _('list the revision number (default)')),
223 ('c', 'changeset', None, _('list the changeset')),
223 ('c', 'changeset', None, _('list the changeset')),
224 ('l', 'line-number', None, _('show line number at the first appearance'))
224 ('l', 'line-number', None, _('show line number at the first appearance'))
225 ] + diffwsopts + walkopts,
225 ] + diffwsopts + walkopts,
226 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
226 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
227 def annotate(ui, repo, *pats, **opts):
227 def annotate(ui, repo, *pats, **opts):
228 """show changeset information by line for each file
228 """show changeset information by line for each file
229
229
230 List changes in files, showing the revision id responsible for
230 List changes in files, showing the revision id responsible for
231 each line
231 each line
232
232
233 This command is useful for discovering when a change was made and
233 This command is useful for discovering when a change was made and
234 by whom.
234 by whom.
235
235
236 Without the -a/--text option, annotate will avoid processing files
236 Without the -a/--text option, annotate will avoid processing files
237 it detects as binary. With -a, annotate will annotate the file
237 it detects as binary. With -a, annotate will annotate the file
238 anyway, although the results will probably be neither useful
238 anyway, although the results will probably be neither useful
239 nor desirable.
239 nor desirable.
240
240
241 Returns 0 on success.
241 Returns 0 on success.
242 """
242 """
243 if opts.get('follow'):
243 if opts.get('follow'):
244 # --follow is deprecated and now just an alias for -f/--file
244 # --follow is deprecated and now just an alias for -f/--file
245 # to mimic the behavior of Mercurial before version 1.5
245 # to mimic the behavior of Mercurial before version 1.5
246 opts['file'] = True
246 opts['file'] = True
247
247
248 datefunc = ui.quiet and util.shortdate or util.datestr
248 datefunc = ui.quiet and util.shortdate or util.datestr
249 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
249 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
250
250
251 if not pats:
251 if not pats:
252 raise util.Abort(_('at least one filename or pattern is required'))
252 raise util.Abort(_('at least one filename or pattern is required'))
253
253
254 hexfn = ui.debugflag and hex or short
254 hexfn = ui.debugflag and hex or short
255
255
256 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
256 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
257 ('number', ' ', lambda x: str(x[0].rev())),
257 ('number', ' ', lambda x: str(x[0].rev())),
258 ('changeset', ' ', lambda x: hexfn(x[0].node())),
258 ('changeset', ' ', lambda x: hexfn(x[0].node())),
259 ('date', ' ', getdate),
259 ('date', ' ', getdate),
260 ('file', ' ', lambda x: x[0].path()),
260 ('file', ' ', lambda x: x[0].path()),
261 ('line_number', ':', lambda x: str(x[1])),
261 ('line_number', ':', lambda x: str(x[1])),
262 ]
262 ]
263
263
264 if (not opts.get('user') and not opts.get('changeset')
264 if (not opts.get('user') and not opts.get('changeset')
265 and not opts.get('date') and not opts.get('file')):
265 and not opts.get('date') and not opts.get('file')):
266 opts['number'] = True
266 opts['number'] = True
267
267
268 linenumber = opts.get('line_number') is not None
268 linenumber = opts.get('line_number') is not None
269 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
269 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
270 raise util.Abort(_('at least one of -n/-c is required for -l'))
270 raise util.Abort(_('at least one of -n/-c is required for -l'))
271
271
272 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
272 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
273 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
273 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
274
274
275 def bad(x, y):
275 def bad(x, y):
276 raise util.Abort("%s: %s" % (x, y))
276 raise util.Abort("%s: %s" % (x, y))
277
277
278 ctx = scmutil.revsingle(repo, opts.get('rev'))
278 ctx = scmutil.revsingle(repo, opts.get('rev'))
279 m = scmutil.match(ctx, pats, opts)
279 m = scmutil.match(ctx, pats, opts)
280 m.bad = bad
280 m.bad = bad
281 follow = not opts.get('no_follow')
281 follow = not opts.get('no_follow')
282 diffopts = patch.diffopts(ui, opts, section='annotate')
282 diffopts = patch.diffopts(ui, opts, section='annotate')
283 for abs in ctx.walk(m):
283 for abs in ctx.walk(m):
284 fctx = ctx[abs]
284 fctx = ctx[abs]
285 if not opts.get('text') and util.binary(fctx.data()):
285 if not opts.get('text') and util.binary(fctx.data()):
286 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
286 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
287 continue
287 continue
288
288
289 lines = fctx.annotate(follow=follow, linenumber=linenumber,
289 lines = fctx.annotate(follow=follow, linenumber=linenumber,
290 diffopts=diffopts)
290 diffopts=diffopts)
291 pieces = []
291 pieces = []
292
292
293 for f, sep in funcmap:
293 for f, sep in funcmap:
294 l = [f(n) for n, dummy in lines]
294 l = [f(n) for n, dummy in lines]
295 if l:
295 if l:
296 sized = [(x, encoding.colwidth(x)) for x in l]
296 sized = [(x, encoding.colwidth(x)) for x in l]
297 ml = max([w for x, w in sized])
297 ml = max([w for x, w in sized])
298 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
298 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
299 for x, w in sized])
299 for x, w in sized])
300
300
301 if pieces:
301 if pieces:
302 for p, l in zip(zip(*pieces), lines):
302 for p, l in zip(zip(*pieces), lines):
303 ui.write("%s: %s" % ("".join(p), l[1]))
303 ui.write("%s: %s" % ("".join(p), l[1]))
304
304
305 if lines and not lines[-1][1].endswith('\n'):
305 if lines and not lines[-1][1].endswith('\n'):
306 ui.write('\n')
306 ui.write('\n')
307
307
308 @command('archive',
308 @command('archive',
309 [('', 'no-decode', None, _('do not pass files through decoders')),
309 [('', 'no-decode', None, _('do not pass files through decoders')),
310 ('p', 'prefix', '', _('directory prefix for files in archive'),
310 ('p', 'prefix', '', _('directory prefix for files in archive'),
311 _('PREFIX')),
311 _('PREFIX')),
312 ('r', 'rev', '', _('revision to distribute'), _('REV')),
312 ('r', 'rev', '', _('revision to distribute'), _('REV')),
313 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
313 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
314 ] + subrepoopts + walkopts,
314 ] + subrepoopts + walkopts,
315 _('[OPTION]... DEST'))
315 _('[OPTION]... DEST'))
316 def archive(ui, repo, dest, **opts):
316 def archive(ui, repo, dest, **opts):
317 '''create an unversioned archive of a repository revision
317 '''create an unversioned archive of a repository revision
318
318
319 By default, the revision used is the parent of the working
319 By default, the revision used is the parent of the working
320 directory; use -r/--rev to specify a different revision.
320 directory; use -r/--rev to specify a different revision.
321
321
322 The archive type is automatically detected based on file
322 The archive type is automatically detected based on file
323 extension (or override using -t/--type).
323 extension (or override using -t/--type).
324
324
325 .. container:: verbose
325 .. container:: verbose
326
326
327 Examples:
327 Examples:
328
328
329 - create a zip file containing the 1.0 release::
329 - create a zip file containing the 1.0 release::
330
330
331 hg archive -r 1.0 project-1.0.zip
331 hg archive -r 1.0 project-1.0.zip
332
332
333 - create a tarball excluding .hg files::
333 - create a tarball excluding .hg files::
334
334
335 hg archive project.tar.gz -X ".hg*"
335 hg archive project.tar.gz -X ".hg*"
336
336
337 Valid types are:
337 Valid types are:
338
338
339 :``files``: a directory full of files (default)
339 :``files``: a directory full of files (default)
340 :``tar``: tar archive, uncompressed
340 :``tar``: tar archive, uncompressed
341 :``tbz2``: tar archive, compressed using bzip2
341 :``tbz2``: tar archive, compressed using bzip2
342 :``tgz``: tar archive, compressed using gzip
342 :``tgz``: tar archive, compressed using gzip
343 :``uzip``: zip archive, uncompressed
343 :``uzip``: zip archive, uncompressed
344 :``zip``: zip archive, compressed using deflate
344 :``zip``: zip archive, compressed using deflate
345
345
346 The exact name of the destination archive or directory is given
346 The exact name of the destination archive or directory is given
347 using a format string; see :hg:`help export` for details.
347 using a format string; see :hg:`help export` for details.
348
348
349 Each member added to an archive file has a directory prefix
349 Each member added to an archive file has a directory prefix
350 prepended. Use -p/--prefix to specify a format string for the
350 prepended. Use -p/--prefix to specify a format string for the
351 prefix. The default is the basename of the archive, with suffixes
351 prefix. The default is the basename of the archive, with suffixes
352 removed.
352 removed.
353
353
354 Returns 0 on success.
354 Returns 0 on success.
355 '''
355 '''
356
356
357 ctx = scmutil.revsingle(repo, opts.get('rev'))
357 ctx = scmutil.revsingle(repo, opts.get('rev'))
358 if not ctx:
358 if not ctx:
359 raise util.Abort(_('no working directory: please specify a revision'))
359 raise util.Abort(_('no working directory: please specify a revision'))
360 node = ctx.node()
360 node = ctx.node()
361 dest = cmdutil.makefilename(repo, dest, node)
361 dest = cmdutil.makefilename(repo, dest, node)
362 if os.path.realpath(dest) == repo.root:
362 if os.path.realpath(dest) == repo.root:
363 raise util.Abort(_('repository root cannot be destination'))
363 raise util.Abort(_('repository root cannot be destination'))
364
364
365 kind = opts.get('type') or archival.guesskind(dest) or 'files'
365 kind = opts.get('type') or archival.guesskind(dest) or 'files'
366 prefix = opts.get('prefix')
366 prefix = opts.get('prefix')
367
367
368 if dest == '-':
368 if dest == '-':
369 if kind == 'files':
369 if kind == 'files':
370 raise util.Abort(_('cannot archive plain files to stdout'))
370 raise util.Abort(_('cannot archive plain files to stdout'))
371 dest = cmdutil.makefileobj(repo, dest)
371 dest = cmdutil.makefileobj(repo, dest)
372 if not prefix:
372 if not prefix:
373 prefix = os.path.basename(repo.root) + '-%h'
373 prefix = os.path.basename(repo.root) + '-%h'
374
374
375 prefix = cmdutil.makefilename(repo, prefix, node)
375 prefix = cmdutil.makefilename(repo, prefix, node)
376 matchfn = scmutil.match(ctx, [], opts)
376 matchfn = scmutil.match(ctx, [], opts)
377 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
377 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
378 matchfn, prefix, subrepos=opts.get('subrepos'))
378 matchfn, prefix, subrepos=opts.get('subrepos'))
379
379
380 @command('backout',
380 @command('backout',
381 [('', 'merge', None, _('merge with old dirstate parent after backout')),
381 [('', 'merge', None, _('merge with old dirstate parent after backout')),
382 ('', 'parent', '',
382 ('', 'parent', '',
383 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
383 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
384 ('r', 'rev', '', _('revision to backout'), _('REV')),
384 ('r', 'rev', '', _('revision to backout'), _('REV')),
385 ] + mergetoolopts + walkopts + commitopts + commitopts2,
385 ] + mergetoolopts + walkopts + commitopts + commitopts2,
386 _('[OPTION]... [-r] REV'))
386 _('[OPTION]... [-r] REV'))
387 def backout(ui, repo, node=None, rev=None, **opts):
387 def backout(ui, repo, node=None, rev=None, **opts):
388 '''reverse effect of earlier changeset
388 '''reverse effect of earlier changeset
389
389
390 Prepare a new changeset with the effect of REV undone in the
390 Prepare a new changeset with the effect of REV undone in the
391 current working directory.
391 current working directory.
392
392
393 If REV is the parent of the working directory, then this new changeset
393 If REV is the parent of the working directory, then this new changeset
394 is committed automatically. Otherwise, hg needs to merge the
394 is committed automatically. Otherwise, hg needs to merge the
395 changes and the merged result is left uncommitted.
395 changes and the merged result is left uncommitted.
396
396
397 .. note::
397 .. note::
398 backout cannot be used to fix either an unwanted or
398 backout cannot be used to fix either an unwanted or
399 incorrect merge.
399 incorrect merge.
400
400
401 .. container:: verbose
401 .. container:: verbose
402
402
403 By default, the pending changeset will have one parent,
403 By default, the pending changeset will have one parent,
404 maintaining a linear history. With --merge, the pending
404 maintaining a linear history. With --merge, the pending
405 changeset will instead have two parents: the old parent of the
405 changeset will instead have two parents: the old parent of the
406 working directory and a new child of REV that simply undoes REV.
406 working directory and a new child of REV that simply undoes REV.
407
407
408 Before version 1.7, the behavior without --merge was equivalent
408 Before version 1.7, the behavior without --merge was equivalent
409 to specifying --merge followed by :hg:`update --clean .` to
409 to specifying --merge followed by :hg:`update --clean .` to
410 cancel the merge and leave the child of REV as a head to be
410 cancel the merge and leave the child of REV as a head to be
411 merged separately.
411 merged separately.
412
412
413 See :hg:`help dates` for a list of formats valid for -d/--date.
413 See :hg:`help dates` for a list of formats valid for -d/--date.
414
414
415 Returns 0 on success.
415 Returns 0 on success.
416 '''
416 '''
417 if rev and node:
417 if rev and node:
418 raise util.Abort(_("please specify just one revision"))
418 raise util.Abort(_("please specify just one revision"))
419
419
420 if not rev:
420 if not rev:
421 rev = node
421 rev = node
422
422
423 if not rev:
423 if not rev:
424 raise util.Abort(_("please specify a revision to backout"))
424 raise util.Abort(_("please specify a revision to backout"))
425
425
426 date = opts.get('date')
426 date = opts.get('date')
427 if date:
427 if date:
428 opts['date'] = util.parsedate(date)
428 opts['date'] = util.parsedate(date)
429
429
430 cmdutil.bailifchanged(repo)
430 cmdutil.bailifchanged(repo)
431 node = scmutil.revsingle(repo, rev).node()
431 node = scmutil.revsingle(repo, rev).node()
432
432
433 op1, op2 = repo.dirstate.parents()
433 op1, op2 = repo.dirstate.parents()
434 a = repo.changelog.ancestor(op1, node)
434 a = repo.changelog.ancestor(op1, node)
435 if a != node:
435 if a != node:
436 raise util.Abort(_('cannot backout change on a different branch'))
436 raise util.Abort(_('cannot backout change on a different branch'))
437
437
438 p1, p2 = repo.changelog.parents(node)
438 p1, p2 = repo.changelog.parents(node)
439 if p1 == nullid:
439 if p1 == nullid:
440 raise util.Abort(_('cannot backout a change with no parents'))
440 raise util.Abort(_('cannot backout a change with no parents'))
441 if p2 != nullid:
441 if p2 != nullid:
442 if not opts.get('parent'):
442 if not opts.get('parent'):
443 raise util.Abort(_('cannot backout a merge changeset'))
443 raise util.Abort(_('cannot backout a merge changeset'))
444 p = repo.lookup(opts['parent'])
444 p = repo.lookup(opts['parent'])
445 if p not in (p1, p2):
445 if p not in (p1, p2):
446 raise util.Abort(_('%s is not a parent of %s') %
446 raise util.Abort(_('%s is not a parent of %s') %
447 (short(p), short(node)))
447 (short(p), short(node)))
448 parent = p
448 parent = p
449 else:
449 else:
450 if opts.get('parent'):
450 if opts.get('parent'):
451 raise util.Abort(_('cannot use --parent on non-merge changeset'))
451 raise util.Abort(_('cannot use --parent on non-merge changeset'))
452 parent = p1
452 parent = p1
453
453
454 # the backout should appear on the same branch
454 # the backout should appear on the same branch
455 wlock = repo.wlock()
455 wlock = repo.wlock()
456 try:
456 try:
457 branch = repo.dirstate.branch()
457 branch = repo.dirstate.branch()
458 hg.clean(repo, node, show_stats=False)
458 hg.clean(repo, node, show_stats=False)
459 repo.dirstate.setbranch(branch)
459 repo.dirstate.setbranch(branch)
460 revert_opts = opts.copy()
460 revert_opts = opts.copy()
461 revert_opts['date'] = None
461 revert_opts['date'] = None
462 revert_opts['all'] = True
462 revert_opts['all'] = True
463 revert_opts['rev'] = hex(parent)
463 revert_opts['rev'] = hex(parent)
464 revert_opts['no_backup'] = None
464 revert_opts['no_backup'] = None
465 revert(ui, repo, **revert_opts)
465 revert(ui, repo, **revert_opts)
466 if not opts.get('merge') and op1 != node:
466 if not opts.get('merge') and op1 != node:
467 try:
467 try:
468 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
468 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
469 return hg.update(repo, op1)
469 return hg.update(repo, op1)
470 finally:
470 finally:
471 ui.setconfig('ui', 'forcemerge', '')
471 ui.setconfig('ui', 'forcemerge', '')
472
472
473 commit_opts = opts.copy()
473 commit_opts = opts.copy()
474 commit_opts['addremove'] = False
474 commit_opts['addremove'] = False
475 if not commit_opts['message'] and not commit_opts['logfile']:
475 if not commit_opts['message'] and not commit_opts['logfile']:
476 # we don't translate commit messages
476 # we don't translate commit messages
477 commit_opts['message'] = "Backed out changeset %s" % short(node)
477 commit_opts['message'] = "Backed out changeset %s" % short(node)
478 commit_opts['force_editor'] = True
478 commit_opts['force_editor'] = True
479 commit(ui, repo, **commit_opts)
479 commit(ui, repo, **commit_opts)
480 def nice(node):
480 def nice(node):
481 return '%d:%s' % (repo.changelog.rev(node), short(node))
481 return '%d:%s' % (repo.changelog.rev(node), short(node))
482 ui.status(_('changeset %s backs out changeset %s\n') %
482 ui.status(_('changeset %s backs out changeset %s\n') %
483 (nice(repo.changelog.tip()), nice(node)))
483 (nice(repo.changelog.tip()), nice(node)))
484 if opts.get('merge') and op1 != node:
484 if opts.get('merge') and op1 != node:
485 hg.clean(repo, op1, show_stats=False)
485 hg.clean(repo, op1, show_stats=False)
486 ui.status(_('merging with changeset %s\n')
486 ui.status(_('merging with changeset %s\n')
487 % nice(repo.changelog.tip()))
487 % nice(repo.changelog.tip()))
488 try:
488 try:
489 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
489 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
490 return hg.merge(repo, hex(repo.changelog.tip()))
490 return hg.merge(repo, hex(repo.changelog.tip()))
491 finally:
491 finally:
492 ui.setconfig('ui', 'forcemerge', '')
492 ui.setconfig('ui', 'forcemerge', '')
493 finally:
493 finally:
494 wlock.release()
494 wlock.release()
495 return 0
495 return 0
496
496
497 @command('bisect',
497 @command('bisect',
498 [('r', 'reset', False, _('reset bisect state')),
498 [('r', 'reset', False, _('reset bisect state')),
499 ('g', 'good', False, _('mark changeset good')),
499 ('g', 'good', False, _('mark changeset good')),
500 ('b', 'bad', False, _('mark changeset bad')),
500 ('b', 'bad', False, _('mark changeset bad')),
501 ('s', 'skip', False, _('skip testing changeset')),
501 ('s', 'skip', False, _('skip testing changeset')),
502 ('e', 'extend', False, _('extend the bisect range')),
502 ('e', 'extend', False, _('extend the bisect range')),
503 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
503 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
504 ('U', 'noupdate', False, _('do not update to target'))],
504 ('U', 'noupdate', False, _('do not update to target'))],
505 _("[-gbsr] [-U] [-c CMD] [REV]"))
505 _("[-gbsr] [-U] [-c CMD] [REV]"))
506 def bisect(ui, repo, rev=None, extra=None, command=None,
506 def bisect(ui, repo, rev=None, extra=None, command=None,
507 reset=None, good=None, bad=None, skip=None, extend=None,
507 reset=None, good=None, bad=None, skip=None, extend=None,
508 noupdate=None):
508 noupdate=None):
509 """subdivision search of changesets
509 """subdivision search of changesets
510
510
511 This command helps to find changesets which introduce problems. To
511 This command helps to find changesets which introduce problems. To
512 use, mark the earliest changeset you know exhibits the problem as
512 use, mark the earliest changeset you know exhibits the problem as
513 bad, then mark the latest changeset which is free from the problem
513 bad, then mark the latest changeset which is free from the problem
514 as good. Bisect will update your working directory to a revision
514 as good. Bisect will update your working directory to a revision
515 for testing (unless the -U/--noupdate option is specified). Once
515 for testing (unless the -U/--noupdate option is specified). Once
516 you have performed tests, mark the working directory as good or
516 you have performed tests, mark the working directory as good or
517 bad, and bisect will either update to another candidate changeset
517 bad, and bisect will either update to another candidate changeset
518 or announce that it has found the bad revision.
518 or announce that it has found the bad revision.
519
519
520 As a shortcut, you can also use the revision argument to mark a
520 As a shortcut, you can also use the revision argument to mark a
521 revision as good or bad without checking it out first.
521 revision as good or bad without checking it out first.
522
522
523 If you supply a command, it will be used for automatic bisection.
523 If you supply a command, it will be used for automatic bisection.
524 The environment variable HG_NODE will contain the ID of the
524 The environment variable HG_NODE will contain the ID of the
525 changeset being tested. The exit status of the command will be
525 changeset being tested. The exit status of the command will be
526 used to mark revisions as good or bad: status 0 means good, 125
526 used to mark revisions as good or bad: status 0 means good, 125
527 means to skip the revision, 127 (command not found) will abort the
527 means to skip the revision, 127 (command not found) will abort the
528 bisection, and any other non-zero exit status means the revision
528 bisection, and any other non-zero exit status means the revision
529 is bad.
529 is bad.
530
530
531 .. container:: verbose
531 .. container:: verbose
532
532
533 Some examples:
533 Some examples:
534
534
535 - start a bisection with known bad revision 12, and good revision 34::
535 - start a bisection with known bad revision 12, and good revision 34::
536
536
537 hg bisect --bad 34
537 hg bisect --bad 34
538 hg bisect --good 12
538 hg bisect --good 12
539
539
540 - advance the current bisection by marking current revision as good or
540 - advance the current bisection by marking current revision as good or
541 bad::
541 bad::
542
542
543 hg bisect --good
543 hg bisect --good
544 hg bisect --bad
544 hg bisect --bad
545
545
546 - mark the current revision, or a known revision, to be skipped (eg. if
546 - mark the current revision, or a known revision, to be skipped (eg. if
547 that revision is not usable because of another issue)::
547 that revision is not usable because of another issue)::
548
548
549 hg bisect --skip
549 hg bisect --skip
550 hg bisect --skip 23
550 hg bisect --skip 23
551
551
552 - forget the current bisection::
552 - forget the current bisection::
553
553
554 hg bisect --reset
554 hg bisect --reset
555
555
556 - use 'make && make tests' to automatically find the first broken
556 - use 'make && make tests' to automatically find the first broken
557 revision::
557 revision::
558
558
559 hg bisect --reset
559 hg bisect --reset
560 hg bisect --bad 34
560 hg bisect --bad 34
561 hg bisect --good 12
561 hg bisect --good 12
562 hg bisect --command 'make && make tests'
562 hg bisect --command 'make && make tests'
563
563
564 - see all changesets whose states are already known in the current
564 - see all changesets whose states are already known in the current
565 bisection::
565 bisection::
566
566
567 hg log -r "bisect(pruned)"
567 hg log -r "bisect(pruned)"
568
568
569 - see the changeset currently being bisected (especially useful
569 - see the changeset currently being bisected (especially useful
570 if running with -U/--noupdate)::
570 if running with -U/--noupdate)::
571
571
572 hg log -r "bisect(current)"
572 hg log -r "bisect(current)"
573
573
574 - see all changesets that took part in the current bisection::
574 - see all changesets that took part in the current bisection::
575
575
576 hg log -r "bisect(range)"
576 hg log -r "bisect(range)"
577
577
578 - with the graphlog extension, you can even get a nice graph::
578 - with the graphlog extension, you can even get a nice graph::
579
579
580 hg log --graph -r "bisect(range)"
580 hg log --graph -r "bisect(range)"
581
581
582 See :hg:`help revsets` for more about the `bisect()` keyword.
582 See :hg:`help revsets` for more about the `bisect()` keyword.
583
583
584 Returns 0 on success.
584 Returns 0 on success.
585 """
585 """
586 def extendbisectrange(nodes, good):
586 def extendbisectrange(nodes, good):
587 # bisect is incomplete when it ends on a merge node and
587 # bisect is incomplete when it ends on a merge node and
588 # one of the parent was not checked.
588 # one of the parent was not checked.
589 parents = repo[nodes[0]].parents()
589 parents = repo[nodes[0]].parents()
590 if len(parents) > 1:
590 if len(parents) > 1:
591 side = good and state['bad'] or state['good']
591 side = good and state['bad'] or state['good']
592 num = len(set(i.node() for i in parents) & set(side))
592 num = len(set(i.node() for i in parents) & set(side))
593 if num == 1:
593 if num == 1:
594 return parents[0].ancestor(parents[1])
594 return parents[0].ancestor(parents[1])
595 return None
595 return None
596
596
597 def print_result(nodes, good):
597 def print_result(nodes, good):
598 displayer = cmdutil.show_changeset(ui, repo, {})
598 displayer = cmdutil.show_changeset(ui, repo, {})
599 if len(nodes) == 1:
599 if len(nodes) == 1:
600 # narrowed it down to a single revision
600 # narrowed it down to a single revision
601 if good:
601 if good:
602 ui.write(_("The first good revision is:\n"))
602 ui.write(_("The first good revision is:\n"))
603 else:
603 else:
604 ui.write(_("The first bad revision is:\n"))
604 ui.write(_("The first bad revision is:\n"))
605 displayer.show(repo[nodes[0]])
605 displayer.show(repo[nodes[0]])
606 extendnode = extendbisectrange(nodes, good)
606 extendnode = extendbisectrange(nodes, good)
607 if extendnode is not None:
607 if extendnode is not None:
608 ui.write(_('Not all ancestors of this changeset have been'
608 ui.write(_('Not all ancestors of this changeset have been'
609 ' checked.\nUse bisect --extend to continue the '
609 ' checked.\nUse bisect --extend to continue the '
610 'bisection from\nthe common ancestor, %s.\n')
610 'bisection from\nthe common ancestor, %s.\n')
611 % extendnode)
611 % extendnode)
612 else:
612 else:
613 # multiple possible revisions
613 # multiple possible revisions
614 if good:
614 if good:
615 ui.write(_("Due to skipped revisions, the first "
615 ui.write(_("Due to skipped revisions, the first "
616 "good revision could be any of:\n"))
616 "good revision could be any of:\n"))
617 else:
617 else:
618 ui.write(_("Due to skipped revisions, the first "
618 ui.write(_("Due to skipped revisions, the first "
619 "bad revision could be any of:\n"))
619 "bad revision could be any of:\n"))
620 for n in nodes:
620 for n in nodes:
621 displayer.show(repo[n])
621 displayer.show(repo[n])
622 displayer.close()
622 displayer.close()
623
623
624 def check_state(state, interactive=True):
624 def check_state(state, interactive=True):
625 if not state['good'] or not state['bad']:
625 if not state['good'] or not state['bad']:
626 if (good or bad or skip or reset) and interactive:
626 if (good or bad or skip or reset) and interactive:
627 return
627 return
628 if not state['good']:
628 if not state['good']:
629 raise util.Abort(_('cannot bisect (no known good revisions)'))
629 raise util.Abort(_('cannot bisect (no known good revisions)'))
630 else:
630 else:
631 raise util.Abort(_('cannot bisect (no known bad revisions)'))
631 raise util.Abort(_('cannot bisect (no known bad revisions)'))
632 return True
632 return True
633
633
634 # backward compatibility
634 # backward compatibility
635 if rev in "good bad reset init".split():
635 if rev in "good bad reset init".split():
636 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
636 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
637 cmd, rev, extra = rev, extra, None
637 cmd, rev, extra = rev, extra, None
638 if cmd == "good":
638 if cmd == "good":
639 good = True
639 good = True
640 elif cmd == "bad":
640 elif cmd == "bad":
641 bad = True
641 bad = True
642 else:
642 else:
643 reset = True
643 reset = True
644 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
644 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
645 raise util.Abort(_('incompatible arguments'))
645 raise util.Abort(_('incompatible arguments'))
646
646
647 if reset:
647 if reset:
648 p = repo.join("bisect.state")
648 p = repo.join("bisect.state")
649 if os.path.exists(p):
649 if os.path.exists(p):
650 os.unlink(p)
650 os.unlink(p)
651 return
651 return
652
652
653 state = hbisect.load_state(repo)
653 state = hbisect.load_state(repo)
654
654
655 if command:
655 if command:
656 changesets = 1
656 changesets = 1
657 try:
657 try:
658 node = state['current'][0]
658 node = state['current'][0]
659 except LookupError:
659 except LookupError:
660 if noupdate:
660 if noupdate:
661 raise util.Abort(_('current bisect revision is unknown - '
661 raise util.Abort(_('current bisect revision is unknown - '
662 'start a new bisect to fix'))
662 'start a new bisect to fix'))
663 node, p2 = repo.dirstate.parents()
663 node, p2 = repo.dirstate.parents()
664 if p2 != nullid:
664 if p2 != nullid:
665 raise util.Abort(_('current bisect revision is a merge'))
665 raise util.Abort(_('current bisect revision is a merge'))
666 try:
666 try:
667 while changesets:
667 while changesets:
668 # update state
668 # update state
669 state['current'] = [node]
669 state['current'] = [node]
670 hbisect.save_state(repo, state)
670 hbisect.save_state(repo, state)
671 status = util.system(command,
671 status = util.system(command,
672 environ={'HG_NODE': hex(node)},
672 environ={'HG_NODE': hex(node)},
673 out=ui.fout)
673 out=ui.fout)
674 if status == 125:
674 if status == 125:
675 transition = "skip"
675 transition = "skip"
676 elif status == 0:
676 elif status == 0:
677 transition = "good"
677 transition = "good"
678 # status < 0 means process was killed
678 # status < 0 means process was killed
679 elif status == 127:
679 elif status == 127:
680 raise util.Abort(_("failed to execute %s") % command)
680 raise util.Abort(_("failed to execute %s") % command)
681 elif status < 0:
681 elif status < 0:
682 raise util.Abort(_("%s killed") % command)
682 raise util.Abort(_("%s killed") % command)
683 else:
683 else:
684 transition = "bad"
684 transition = "bad"
685 ctx = scmutil.revsingle(repo, rev, node)
685 ctx = scmutil.revsingle(repo, rev, node)
686 rev = None # clear for future iterations
686 rev = None # clear for future iterations
687 state[transition].append(ctx.node())
687 state[transition].append(ctx.node())
688 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
688 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
689 check_state(state, interactive=False)
689 check_state(state, interactive=False)
690 # bisect
690 # bisect
691 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
691 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
692 # update to next check
692 # update to next check
693 node = nodes[0]
693 node = nodes[0]
694 if not noupdate:
694 if not noupdate:
695 cmdutil.bailifchanged(repo)
695 cmdutil.bailifchanged(repo)
696 hg.clean(repo, node, show_stats=False)
696 hg.clean(repo, node, show_stats=False)
697 finally:
697 finally:
698 state['current'] = [node]
698 state['current'] = [node]
699 hbisect.save_state(repo, state)
699 hbisect.save_state(repo, state)
700 print_result(nodes, good)
700 print_result(nodes, good)
701 return
701 return
702
702
703 # update state
703 # update state
704
704
705 if rev:
705 if rev:
706 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
706 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
707 else:
707 else:
708 nodes = [repo.lookup('.')]
708 nodes = [repo.lookup('.')]
709
709
710 if good or bad or skip:
710 if good or bad or skip:
711 if good:
711 if good:
712 state['good'] += nodes
712 state['good'] += nodes
713 elif bad:
713 elif bad:
714 state['bad'] += nodes
714 state['bad'] += nodes
715 elif skip:
715 elif skip:
716 state['skip'] += nodes
716 state['skip'] += nodes
717 hbisect.save_state(repo, state)
717 hbisect.save_state(repo, state)
718
718
719 if not check_state(state):
719 if not check_state(state):
720 return
720 return
721
721
722 # actually bisect
722 # actually bisect
723 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
723 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
724 if extend:
724 if extend:
725 if not changesets:
725 if not changesets:
726 extendnode = extendbisectrange(nodes, good)
726 extendnode = extendbisectrange(nodes, good)
727 if extendnode is not None:
727 if extendnode is not None:
728 ui.write(_("Extending search to changeset %d:%s\n"
728 ui.write(_("Extending search to changeset %d:%s\n"
729 % (extendnode.rev(), extendnode)))
729 % (extendnode.rev(), extendnode)))
730 state['current'] = [extendnode.node()]
730 state['current'] = [extendnode.node()]
731 hbisect.save_state(repo, state)
731 hbisect.save_state(repo, state)
732 if noupdate:
732 if noupdate:
733 return
733 return
734 cmdutil.bailifchanged(repo)
734 cmdutil.bailifchanged(repo)
735 return hg.clean(repo, extendnode.node())
735 return hg.clean(repo, extendnode.node())
736 raise util.Abort(_("nothing to extend"))
736 raise util.Abort(_("nothing to extend"))
737
737
738 if changesets == 0:
738 if changesets == 0:
739 print_result(nodes, good)
739 print_result(nodes, good)
740 else:
740 else:
741 assert len(nodes) == 1 # only a single node can be tested next
741 assert len(nodes) == 1 # only a single node can be tested next
742 node = nodes[0]
742 node = nodes[0]
743 # compute the approximate number of remaining tests
743 # compute the approximate number of remaining tests
744 tests, size = 0, 2
744 tests, size = 0, 2
745 while size <= changesets:
745 while size <= changesets:
746 tests, size = tests + 1, size * 2
746 tests, size = tests + 1, size * 2
747 rev = repo.changelog.rev(node)
747 rev = repo.changelog.rev(node)
748 ui.write(_("Testing changeset %d:%s "
748 ui.write(_("Testing changeset %d:%s "
749 "(%d changesets remaining, ~%d tests)\n")
749 "(%d changesets remaining, ~%d tests)\n")
750 % (rev, short(node), changesets, tests))
750 % (rev, short(node), changesets, tests))
751 state['current'] = [node]
751 state['current'] = [node]
752 hbisect.save_state(repo, state)
752 hbisect.save_state(repo, state)
753 if not noupdate:
753 if not noupdate:
754 cmdutil.bailifchanged(repo)
754 cmdutil.bailifchanged(repo)
755 return hg.clean(repo, node)
755 return hg.clean(repo, node)
756
756
757 @command('bookmarks',
757 @command('bookmarks',
758 [('f', 'force', False, _('force')),
758 [('f', 'force', False, _('force')),
759 ('r', 'rev', '', _('revision'), _('REV')),
759 ('r', 'rev', '', _('revision'), _('REV')),
760 ('d', 'delete', False, _('delete a given bookmark')),
760 ('d', 'delete', False, _('delete a given bookmark')),
761 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
761 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
762 ('i', 'inactive', False, _('mark a bookmark inactive'))],
762 ('i', 'inactive', False, _('mark a bookmark inactive'))],
763 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
763 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
764 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
764 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
765 rename=None, inactive=False):
765 rename=None, inactive=False):
766 '''track a line of development with movable markers
766 '''track a line of development with movable markers
767
767
768 Bookmarks are pointers to certain commits that move when committing.
768 Bookmarks are pointers to certain commits that move when committing.
769 Bookmarks are local. They can be renamed, copied and deleted. It is
769 Bookmarks are local. They can be renamed, copied and deleted. It is
770 possible to use :hg:`merge NAME` to merge from a given bookmark, and
770 possible to use :hg:`merge NAME` to merge from a given bookmark, and
771 :hg:`update NAME` to update to a given bookmark.
771 :hg:`update NAME` to update to a given bookmark.
772
772
773 You can use :hg:`bookmark NAME` to set a bookmark on the working
773 You can use :hg:`bookmark NAME` to set a bookmark on the working
774 directory's parent revision with the given name. If you specify
774 directory's parent revision with the given name. If you specify
775 a revision using -r REV (where REV may be an existing bookmark),
775 a revision using -r REV (where REV may be an existing bookmark),
776 the bookmark is assigned to that revision.
776 the bookmark is assigned to that revision.
777
777
778 Bookmarks can be pushed and pulled between repositories (see :hg:`help
778 Bookmarks can be pushed and pulled between repositories (see :hg:`help
779 push` and :hg:`help pull`). This requires both the local and remote
779 push` and :hg:`help pull`). This requires both the local and remote
780 repositories to support bookmarks. For versions prior to 1.8, this means
780 repositories to support bookmarks. For versions prior to 1.8, this means
781 the bookmarks extension must be enabled.
781 the bookmarks extension must be enabled.
782
782
783 With -i/--inactive, the new bookmark will not be made the active
783 With -i/--inactive, the new bookmark will not be made the active
784 bookmark. If -r/--rev is given, the new bookmark will not be made
784 bookmark. If -r/--rev is given, the new bookmark will not be made
785 active even if -i/--inactive is not given. If no NAME is given, the
785 active even if -i/--inactive is not given. If no NAME is given, the
786 current active bookmark will be marked inactive.
786 current active bookmark will be marked inactive.
787 '''
787 '''
788 hexfn = ui.debugflag and hex or short
788 hexfn = ui.debugflag and hex or short
789 marks = repo._bookmarks
789 marks = repo._bookmarks
790 cur = repo.changectx('.').node()
790 cur = repo.changectx('.').node()
791
791
792 if delete:
792 if delete:
793 if mark is None:
793 if mark is None:
794 raise util.Abort(_("bookmark name required"))
794 raise util.Abort(_("bookmark name required"))
795 if mark not in marks:
795 if mark not in marks:
796 raise util.Abort(_("bookmark '%s' does not exist") % mark)
796 raise util.Abort(_("bookmark '%s' does not exist") % mark)
797 if mark == repo._bookmarkcurrent:
797 if mark == repo._bookmarkcurrent:
798 bookmarks.setcurrent(repo, None)
798 bookmarks.setcurrent(repo, None)
799 del marks[mark]
799 del marks[mark]
800 bookmarks.write(repo)
800 bookmarks.write(repo)
801 return
801 return
802
802
803 if rename:
803 if rename:
804 if rename not in marks:
804 if rename not in marks:
805 raise util.Abort(_("bookmark '%s' does not exist") % rename)
805 raise util.Abort(_("bookmark '%s' does not exist") % rename)
806 if mark in marks and not force:
806 if mark in marks and not force:
807 raise util.Abort(_("bookmark '%s' already exists "
807 raise util.Abort(_("bookmark '%s' already exists "
808 "(use -f to force)") % mark)
808 "(use -f to force)") % mark)
809 if mark is None:
809 if mark is None:
810 raise util.Abort(_("new bookmark name required"))
810 raise util.Abort(_("new bookmark name required"))
811 marks[mark] = marks[rename]
811 marks[mark] = marks[rename]
812 if repo._bookmarkcurrent == rename and not inactive:
812 if repo._bookmarkcurrent == rename and not inactive:
813 bookmarks.setcurrent(repo, mark)
813 bookmarks.setcurrent(repo, mark)
814 del marks[rename]
814 del marks[rename]
815 bookmarks.write(repo)
815 bookmarks.write(repo)
816 return
816 return
817
817
818 if mark is not None:
818 if mark is not None:
819 if "\n" in mark:
819 if "\n" in mark:
820 raise util.Abort(_("bookmark name cannot contain newlines"))
820 raise util.Abort(_("bookmark name cannot contain newlines"))
821 mark = mark.strip()
821 mark = mark.strip()
822 if not mark:
822 if not mark:
823 raise util.Abort(_("bookmark names cannot consist entirely of "
823 raise util.Abort(_("bookmark names cannot consist entirely of "
824 "whitespace"))
824 "whitespace"))
825 if inactive and mark == repo._bookmarkcurrent:
825 if inactive and mark == repo._bookmarkcurrent:
826 bookmarks.setcurrent(repo, None)
826 bookmarks.setcurrent(repo, None)
827 return
827 return
828 if mark in marks and not force:
828 if mark in marks and not force:
829 raise util.Abort(_("bookmark '%s' already exists "
829 raise util.Abort(_("bookmark '%s' already exists "
830 "(use -f to force)") % mark)
830 "(use -f to force)") % mark)
831 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
831 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
832 and not force):
832 and not force):
833 raise util.Abort(
833 raise util.Abort(
834 _("a bookmark cannot have the name of an existing branch"))
834 _("a bookmark cannot have the name of an existing branch"))
835 if rev:
835 if rev:
836 marks[mark] = repo.lookup(rev)
836 marks[mark] = repo.lookup(rev)
837 else:
837 else:
838 marks[mark] = cur
838 marks[mark] = cur
839 if not inactive and cur == marks[mark]:
839 if not inactive and cur == marks[mark]:
840 bookmarks.setcurrent(repo, mark)
840 bookmarks.setcurrent(repo, mark)
841 bookmarks.write(repo)
841 bookmarks.write(repo)
842 return
842 return
843
843
844 if mark is None:
844 if mark is None:
845 if rev:
845 if rev:
846 raise util.Abort(_("bookmark name required"))
846 raise util.Abort(_("bookmark name required"))
847 if len(marks) == 0:
847 if len(marks) == 0:
848 ui.status(_("no bookmarks set\n"))
848 ui.status(_("no bookmarks set\n"))
849 else:
849 else:
850 for bmark, n in sorted(marks.iteritems()):
850 for bmark, n in sorted(marks.iteritems()):
851 current = repo._bookmarkcurrent
851 current = repo._bookmarkcurrent
852 if bmark == current and n == cur:
852 if bmark == current and n == cur:
853 prefix, label = '*', 'bookmarks.current'
853 prefix, label = '*', 'bookmarks.current'
854 else:
854 else:
855 prefix, label = ' ', ''
855 prefix, label = ' ', ''
856
856
857 if ui.quiet:
857 if ui.quiet:
858 ui.write("%s\n" % bmark, label=label)
858 ui.write("%s\n" % bmark, label=label)
859 else:
859 else:
860 ui.write(" %s %-25s %d:%s\n" % (
860 ui.write(" %s %-25s %d:%s\n" % (
861 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
861 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
862 label=label)
862 label=label)
863 return
863 return
864
864
865 @command('branch',
865 @command('branch',
866 [('f', 'force', None,
866 [('f', 'force', None,
867 _('set branch name even if it shadows an existing branch')),
867 _('set branch name even if it shadows an existing branch')),
868 ('C', 'clean', None, _('reset branch name to parent branch name'))],
868 ('C', 'clean', None, _('reset branch name to parent branch name'))],
869 _('[-fC] [NAME]'))
869 _('[-fC] [NAME]'))
870 def branch(ui, repo, label=None, **opts):
870 def branch(ui, repo, label=None, **opts):
871 """set or show the current branch name
871 """set or show the current branch name
872
872
873 .. note::
873 .. note::
874 Branch names are permanent and global. Use :hg:`bookmark` to create a
874 Branch names are permanent and global. Use :hg:`bookmark` to create a
875 light-weight bookmark instead. See :hg:`help glossary` for more
875 light-weight bookmark instead. See :hg:`help glossary` for more
876 information about named branches and bookmarks.
876 information about named branches and bookmarks.
877
877
878 With no argument, show the current branch name. With one argument,
878 With no argument, show the current branch name. With one argument,
879 set the working directory branch name (the branch will not exist
879 set the working directory branch name (the branch will not exist
880 in the repository until the next commit). Standard practice
880 in the repository until the next commit). Standard practice
881 recommends that primary development take place on the 'default'
881 recommends that primary development take place on the 'default'
882 branch.
882 branch.
883
883
884 Unless -f/--force is specified, branch will not let you set a
884 Unless -f/--force is specified, branch will not let you set a
885 branch name that already exists, even if it's inactive.
885 branch name that already exists, even if it's inactive.
886
886
887 Use -C/--clean to reset the working directory branch to that of
887 Use -C/--clean to reset the working directory branch to that of
888 the parent of the working directory, negating a previous branch
888 the parent of the working directory, negating a previous branch
889 change.
889 change.
890
890
891 Use the command :hg:`update` to switch to an existing branch. Use
891 Use the command :hg:`update` to switch to an existing branch. Use
892 :hg:`commit --close-branch` to mark this branch as closed.
892 :hg:`commit --close-branch` to mark this branch as closed.
893
893
894 Returns 0 on success.
894 Returns 0 on success.
895 """
895 """
896 if not opts.get('clean') and not label:
896 if not opts.get('clean') and not label:
897 ui.write("%s\n" % repo.dirstate.branch())
897 ui.write("%s\n" % repo.dirstate.branch())
898 return
898 return
899
899
900 wlock = repo.wlock()
900 wlock = repo.wlock()
901 try:
901 try:
902 if opts.get('clean'):
902 if opts.get('clean'):
903 label = repo[None].p1().branch()
903 label = repo[None].p1().branch()
904 repo.dirstate.setbranch(label)
904 repo.dirstate.setbranch(label)
905 ui.status(_('reset working directory to branch %s\n') % label)
905 ui.status(_('reset working directory to branch %s\n') % label)
906 elif label:
906 elif label:
907 if not opts.get('force') and label in repo.branchmap():
907 if not opts.get('force') and label in repo.branchmap():
908 if label not in [p.branch() for p in repo.parents()]:
908 if label not in [p.branch() for p in repo.parents()]:
909 raise util.Abort(_('a branch of the same name already'
909 raise util.Abort(_('a branch of the same name already'
910 ' exists'),
910 ' exists'),
911 # i18n: "it" refers to an existing branch
911 # i18n: "it" refers to an existing branch
912 hint=_("use 'hg update' to switch to it"))
912 hint=_("use 'hg update' to switch to it"))
913 repo.dirstate.setbranch(label)
913 repo.dirstate.setbranch(label)
914 ui.status(_('marked working directory as branch %s\n') % label)
914 ui.status(_('marked working directory as branch %s\n') % label)
915 ui.status(_('(branches are permanent and global, '
915 ui.status(_('(branches are permanent and global, '
916 'did you want a bookmark?)\n'))
916 'did you want a bookmark?)\n'))
917 finally:
917 finally:
918 wlock.release()
918 wlock.release()
919
919
920 @command('branches',
920 @command('branches',
921 [('a', 'active', False, _('show only branches that have unmerged heads')),
921 [('a', 'active', False, _('show only branches that have unmerged heads')),
922 ('c', 'closed', False, _('show normal and closed branches'))],
922 ('c', 'closed', False, _('show normal and closed branches'))],
923 _('[-ac]'))
923 _('[-ac]'))
924 def branches(ui, repo, active=False, closed=False):
924 def branches(ui, repo, active=False, closed=False):
925 """list repository named branches
925 """list repository named branches
926
926
927 List the repository's named branches, indicating which ones are
927 List the repository's named branches, indicating which ones are
928 inactive. If -c/--closed is specified, also list branches which have
928 inactive. If -c/--closed is specified, also list branches which have
929 been marked closed (see :hg:`commit --close-branch`).
929 been marked closed (see :hg:`commit --close-branch`).
930
930
931 If -a/--active is specified, only show active branches. A branch
931 If -a/--active is specified, only show active branches. A branch
932 is considered active if it contains repository heads.
932 is considered active if it contains repository heads.
933
933
934 Use the command :hg:`update` to switch to an existing branch.
934 Use the command :hg:`update` to switch to an existing branch.
935
935
936 Returns 0.
936 Returns 0.
937 """
937 """
938
938
939 hexfunc = ui.debugflag and hex or short
939 hexfunc = ui.debugflag and hex or short
940
940
941 activebranches = set([repo[n].branch() for n in repo.heads()])
941 activebranches = set([repo[n].branch() for n in repo.heads()])
942 branches = []
942 branches = []
943 for tag, heads in repo.branchmap().iteritems():
943 for tag, heads in repo.branchmap().iteritems():
944 for h in reversed(heads):
944 for h in reversed(heads):
945 ctx = repo[h]
945 ctx = repo[h]
946 isopen = not ctx.closesbranch()
946 isopen = not ctx.closesbranch()
947 if isopen:
947 if isopen:
948 tip = ctx
948 tip = ctx
949 break
949 break
950 else:
950 else:
951 tip = repo[heads[-1]]
951 tip = repo[heads[-1]]
952 isactive = tag in activebranches and isopen
952 isactive = tag in activebranches and isopen
953 branches.append((tip, isactive, isopen))
953 branches.append((tip, isactive, isopen))
954 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
954 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
955 reverse=True)
955 reverse=True)
956
956
957 for ctx, isactive, isopen in branches:
957 for ctx, isactive, isopen in branches:
958 if (not active) or isactive:
958 if (not active) or isactive:
959 if isactive:
959 if isactive:
960 label = 'branches.active'
960 label = 'branches.active'
961 notice = ''
961 notice = ''
962 elif not isopen:
962 elif not isopen:
963 if not closed:
963 if not closed:
964 continue
964 continue
965 label = 'branches.closed'
965 label = 'branches.closed'
966 notice = _(' (closed)')
966 notice = _(' (closed)')
967 else:
967 else:
968 label = 'branches.inactive'
968 label = 'branches.inactive'
969 notice = _(' (inactive)')
969 notice = _(' (inactive)')
970 if ctx.branch() == repo.dirstate.branch():
970 if ctx.branch() == repo.dirstate.branch():
971 label = 'branches.current'
971 label = 'branches.current'
972 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
972 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
973 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
973 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
974 'log.changeset')
974 'log.changeset')
975 tag = ui.label(ctx.branch(), label)
975 tag = ui.label(ctx.branch(), label)
976 if ui.quiet:
976 if ui.quiet:
977 ui.write("%s\n" % tag)
977 ui.write("%s\n" % tag)
978 else:
978 else:
979 ui.write("%s %s%s\n" % (tag, rev, notice))
979 ui.write("%s %s%s\n" % (tag, rev, notice))
980
980
981 @command('bundle',
981 @command('bundle',
982 [('f', 'force', None, _('run even when the destination is unrelated')),
982 [('f', 'force', None, _('run even when the destination is unrelated')),
983 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
983 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
984 _('REV')),
984 _('REV')),
985 ('b', 'branch', [], _('a specific branch you would like to bundle'),
985 ('b', 'branch', [], _('a specific branch you would like to bundle'),
986 _('BRANCH')),
986 _('BRANCH')),
987 ('', 'base', [],
987 ('', 'base', [],
988 _('a base changeset assumed to be available at the destination'),
988 _('a base changeset assumed to be available at the destination'),
989 _('REV')),
989 _('REV')),
990 ('a', 'all', None, _('bundle all changesets in the repository')),
990 ('a', 'all', None, _('bundle all changesets in the repository')),
991 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
991 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
992 ] + remoteopts,
992 ] + remoteopts,
993 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
993 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
994 def bundle(ui, repo, fname, dest=None, **opts):
994 def bundle(ui, repo, fname, dest=None, **opts):
995 """create a changegroup file
995 """create a changegroup file
996
996
997 Generate a compressed changegroup file collecting changesets not
997 Generate a compressed changegroup file collecting changesets not
998 known to be in another repository.
998 known to be in another repository.
999
999
1000 If you omit the destination repository, then hg assumes the
1000 If you omit the destination repository, then hg assumes the
1001 destination will have all the nodes you specify with --base
1001 destination will have all the nodes you specify with --base
1002 parameters. To create a bundle containing all changesets, use
1002 parameters. To create a bundle containing all changesets, use
1003 -a/--all (or --base null).
1003 -a/--all (or --base null).
1004
1004
1005 You can change compression method with the -t/--type option.
1005 You can change compression method with the -t/--type option.
1006 The available compression methods are: none, bzip2, and
1006 The available compression methods are: none, bzip2, and
1007 gzip (by default, bundles are compressed using bzip2).
1007 gzip (by default, bundles are compressed using bzip2).
1008
1008
1009 The bundle file can then be transferred using conventional means
1009 The bundle file can then be transferred using conventional means
1010 and applied to another repository with the unbundle or pull
1010 and applied to another repository with the unbundle or pull
1011 command. This is useful when direct push and pull are not
1011 command. This is useful when direct push and pull are not
1012 available or when exporting an entire repository is undesirable.
1012 available or when exporting an entire repository is undesirable.
1013
1013
1014 Applying bundles preserves all changeset contents including
1014 Applying bundles preserves all changeset contents including
1015 permissions, copy/rename information, and revision history.
1015 permissions, copy/rename information, and revision history.
1016
1016
1017 Returns 0 on success, 1 if no changes found.
1017 Returns 0 on success, 1 if no changes found.
1018 """
1018 """
1019 revs = None
1019 revs = None
1020 if 'rev' in opts:
1020 if 'rev' in opts:
1021 revs = scmutil.revrange(repo, opts['rev'])
1021 revs = scmutil.revrange(repo, opts['rev'])
1022
1022
1023 bundletype = opts.get('type', 'bzip2').lower()
1023 bundletype = opts.get('type', 'bzip2').lower()
1024 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1024 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1025 bundletype = btypes.get(bundletype)
1025 bundletype = btypes.get(bundletype)
1026 if bundletype not in changegroup.bundletypes:
1026 if bundletype not in changegroup.bundletypes:
1027 raise util.Abort(_('unknown bundle type specified with --type'))
1027 raise util.Abort(_('unknown bundle type specified with --type'))
1028
1028
1029 if opts.get('all'):
1029 if opts.get('all'):
1030 base = ['null']
1030 base = ['null']
1031 else:
1031 else:
1032 base = scmutil.revrange(repo, opts.get('base'))
1032 base = scmutil.revrange(repo, opts.get('base'))
1033 if base:
1033 if base:
1034 if dest:
1034 if dest:
1035 raise util.Abort(_("--base is incompatible with specifying "
1035 raise util.Abort(_("--base is incompatible with specifying "
1036 "a destination"))
1036 "a destination"))
1037 common = [repo.lookup(rev) for rev in base]
1037 common = [repo.lookup(rev) for rev in base]
1038 heads = revs and map(repo.lookup, revs) or revs
1038 heads = revs and map(repo.lookup, revs) or revs
1039 cg = repo.getbundle('bundle', heads=heads, common=common)
1039 cg = repo.getbundle('bundle', heads=heads, common=common)
1040 outgoing = None
1040 outgoing = None
1041 else:
1041 else:
1042 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1042 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1043 dest, branches = hg.parseurl(dest, opts.get('branch'))
1043 dest, branches = hg.parseurl(dest, opts.get('branch'))
1044 other = hg.peer(repo, opts, dest)
1044 other = hg.peer(repo, opts, dest)
1045 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1045 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1046 heads = revs and map(repo.lookup, revs) or revs
1046 heads = revs and map(repo.lookup, revs) or revs
1047 outgoing = discovery.findcommonoutgoing(repo, other,
1047 outgoing = discovery.findcommonoutgoing(repo, other,
1048 onlyheads=heads,
1048 onlyheads=heads,
1049 force=opts.get('force'),
1049 force=opts.get('force'),
1050 portable=True)
1050 portable=True)
1051 cg = repo.getlocalbundle('bundle', outgoing)
1051 cg = repo.getlocalbundle('bundle', outgoing)
1052 if not cg:
1052 if not cg:
1053 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1053 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1054 return 1
1054 return 1
1055
1055
1056 changegroup.writebundle(cg, fname, bundletype)
1056 changegroup.writebundle(cg, fname, bundletype)
1057
1057
1058 @command('cat',
1058 @command('cat',
1059 [('o', 'output', '',
1059 [('o', 'output', '',
1060 _('print output to file with formatted name'), _('FORMAT')),
1060 _('print output to file with formatted name'), _('FORMAT')),
1061 ('r', 'rev', '', _('print the given revision'), _('REV')),
1061 ('r', 'rev', '', _('print the given revision'), _('REV')),
1062 ('', 'decode', None, _('apply any matching decode filter')),
1062 ('', 'decode', None, _('apply any matching decode filter')),
1063 ] + walkopts,
1063 ] + walkopts,
1064 _('[OPTION]... FILE...'))
1064 _('[OPTION]... FILE...'))
1065 def cat(ui, repo, file1, *pats, **opts):
1065 def cat(ui, repo, file1, *pats, **opts):
1066 """output the current or given revision of files
1066 """output the current or given revision of files
1067
1067
1068 Print the specified files as they were at the given revision. If
1068 Print the specified files as they were at the given revision. If
1069 no revision is given, the parent of the working directory is used,
1069 no revision is given, the parent of the working directory is used,
1070 or tip if no revision is checked out.
1070 or tip if no revision is checked out.
1071
1071
1072 Output may be to a file, in which case the name of the file is
1072 Output may be to a file, in which case the name of the file is
1073 given using a format string. The formatting rules are the same as
1073 given using a format string. The formatting rules are the same as
1074 for the export command, with the following additions:
1074 for the export command, with the following additions:
1075
1075
1076 :``%s``: basename of file being printed
1076 :``%s``: basename of file being printed
1077 :``%d``: dirname of file being printed, or '.' if in repository root
1077 :``%d``: dirname of file being printed, or '.' if in repository root
1078 :``%p``: root-relative path name of file being printed
1078 :``%p``: root-relative path name of file being printed
1079
1079
1080 Returns 0 on success.
1080 Returns 0 on success.
1081 """
1081 """
1082 ctx = scmutil.revsingle(repo, opts.get('rev'))
1082 ctx = scmutil.revsingle(repo, opts.get('rev'))
1083 err = 1
1083 err = 1
1084 m = scmutil.match(ctx, (file1,) + pats, opts)
1084 m = scmutil.match(ctx, (file1,) + pats, opts)
1085 for abs in ctx.walk(m):
1085 for abs in ctx.walk(m):
1086 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1086 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1087 pathname=abs)
1087 pathname=abs)
1088 data = ctx[abs].data()
1088 data = ctx[abs].data()
1089 if opts.get('decode'):
1089 if opts.get('decode'):
1090 data = repo.wwritedata(abs, data)
1090 data = repo.wwritedata(abs, data)
1091 fp.write(data)
1091 fp.write(data)
1092 fp.close()
1092 fp.close()
1093 err = 0
1093 err = 0
1094 return err
1094 return err
1095
1095
1096 @command('^clone',
1096 @command('^clone',
1097 [('U', 'noupdate', None,
1097 [('U', 'noupdate', None,
1098 _('the clone will include an empty working copy (only a repository)')),
1098 _('the clone will include an empty working copy (only a repository)')),
1099 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1099 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1100 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1100 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1101 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1101 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1102 ('', 'pull', None, _('use pull protocol to copy metadata')),
1102 ('', 'pull', None, _('use pull protocol to copy metadata')),
1103 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1103 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1104 ] + remoteopts,
1104 ] + remoteopts,
1105 _('[OPTION]... SOURCE [DEST]'))
1105 _('[OPTION]... SOURCE [DEST]'))
1106 def clone(ui, source, dest=None, **opts):
1106 def clone(ui, source, dest=None, **opts):
1107 """make a copy of an existing repository
1107 """make a copy of an existing repository
1108
1108
1109 Create a copy of an existing repository in a new directory.
1109 Create a copy of an existing repository in a new directory.
1110
1110
1111 If no destination directory name is specified, it defaults to the
1111 If no destination directory name is specified, it defaults to the
1112 basename of the source.
1112 basename of the source.
1113
1113
1114 The location of the source is added to the new repository's
1114 The location of the source is added to the new repository's
1115 ``.hg/hgrc`` file, as the default to be used for future pulls.
1115 ``.hg/hgrc`` file, as the default to be used for future pulls.
1116
1116
1117 Only local paths and ``ssh://`` URLs are supported as
1117 Only local paths and ``ssh://`` URLs are supported as
1118 destinations. For ``ssh://`` destinations, no working directory or
1118 destinations. For ``ssh://`` destinations, no working directory or
1119 ``.hg/hgrc`` will be created on the remote side.
1119 ``.hg/hgrc`` will be created on the remote side.
1120
1120
1121 To pull only a subset of changesets, specify one or more revisions
1121 To pull only a subset of changesets, specify one or more revisions
1122 identifiers with -r/--rev or branches with -b/--branch. The
1122 identifiers with -r/--rev or branches with -b/--branch. The
1123 resulting clone will contain only the specified changesets and
1123 resulting clone will contain only the specified changesets and
1124 their ancestors. These options (or 'clone src#rev dest') imply
1124 their ancestors. These options (or 'clone src#rev dest') imply
1125 --pull, even for local source repositories. Note that specifying a
1125 --pull, even for local source repositories. Note that specifying a
1126 tag will include the tagged changeset but not the changeset
1126 tag will include the tagged changeset but not the changeset
1127 containing the tag.
1127 containing the tag.
1128
1128
1129 To check out a particular version, use -u/--update, or
1129 To check out a particular version, use -u/--update, or
1130 -U/--noupdate to create a clone with no working directory.
1130 -U/--noupdate to create a clone with no working directory.
1131
1131
1132 .. container:: verbose
1132 .. container:: verbose
1133
1133
1134 For efficiency, hardlinks are used for cloning whenever the
1134 For efficiency, hardlinks are used for cloning whenever the
1135 source and destination are on the same filesystem (note this
1135 source and destination are on the same filesystem (note this
1136 applies only to the repository data, not to the working
1136 applies only to the repository data, not to the working
1137 directory). Some filesystems, such as AFS, implement hardlinking
1137 directory). Some filesystems, such as AFS, implement hardlinking
1138 incorrectly, but do not report errors. In these cases, use the
1138 incorrectly, but do not report errors. In these cases, use the
1139 --pull option to avoid hardlinking.
1139 --pull option to avoid hardlinking.
1140
1140
1141 In some cases, you can clone repositories and the working
1141 In some cases, you can clone repositories and the working
1142 directory using full hardlinks with ::
1142 directory using full hardlinks with ::
1143
1143
1144 $ cp -al REPO REPOCLONE
1144 $ cp -al REPO REPOCLONE
1145
1145
1146 This is the fastest way to clone, but it is not always safe. The
1146 This is the fastest way to clone, but it is not always safe. The
1147 operation is not atomic (making sure REPO is not modified during
1147 operation is not atomic (making sure REPO is not modified during
1148 the operation is up to you) and you have to make sure your
1148 the operation is up to you) and you have to make sure your
1149 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1149 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1150 so). Also, this is not compatible with certain extensions that
1150 so). Also, this is not compatible with certain extensions that
1151 place their metadata under the .hg directory, such as mq.
1151 place their metadata under the .hg directory, such as mq.
1152
1152
1153 Mercurial will update the working directory to the first applicable
1153 Mercurial will update the working directory to the first applicable
1154 revision from this list:
1154 revision from this list:
1155
1155
1156 a) null if -U or the source repository has no changesets
1156 a) null if -U or the source repository has no changesets
1157 b) if -u . and the source repository is local, the first parent of
1157 b) if -u . and the source repository is local, the first parent of
1158 the source repository's working directory
1158 the source repository's working directory
1159 c) the changeset specified with -u (if a branch name, this means the
1159 c) the changeset specified with -u (if a branch name, this means the
1160 latest head of that branch)
1160 latest head of that branch)
1161 d) the changeset specified with -r
1161 d) the changeset specified with -r
1162 e) the tipmost head specified with -b
1162 e) the tipmost head specified with -b
1163 f) the tipmost head specified with the url#branch source syntax
1163 f) the tipmost head specified with the url#branch source syntax
1164 g) the tipmost head of the default branch
1164 g) the tipmost head of the default branch
1165 h) tip
1165 h) tip
1166
1166
1167 Examples:
1167 Examples:
1168
1168
1169 - clone a remote repository to a new directory named hg/::
1169 - clone a remote repository to a new directory named hg/::
1170
1170
1171 hg clone http://selenic.com/hg
1171 hg clone http://selenic.com/hg
1172
1172
1173 - create a lightweight local clone::
1173 - create a lightweight local clone::
1174
1174
1175 hg clone project/ project-feature/
1175 hg clone project/ project-feature/
1176
1176
1177 - clone from an absolute path on an ssh server (note double-slash)::
1177 - clone from an absolute path on an ssh server (note double-slash)::
1178
1178
1179 hg clone ssh://user@server//home/projects/alpha/
1179 hg clone ssh://user@server//home/projects/alpha/
1180
1180
1181 - do a high-speed clone over a LAN while checking out a
1181 - do a high-speed clone over a LAN while checking out a
1182 specified version::
1182 specified version::
1183
1183
1184 hg clone --uncompressed http://server/repo -u 1.5
1184 hg clone --uncompressed http://server/repo -u 1.5
1185
1185
1186 - create a repository without changesets after a particular revision::
1186 - create a repository without changesets after a particular revision::
1187
1187
1188 hg clone -r 04e544 experimental/ good/
1188 hg clone -r 04e544 experimental/ good/
1189
1189
1190 - clone (and track) a particular named branch::
1190 - clone (and track) a particular named branch::
1191
1191
1192 hg clone http://selenic.com/hg#stable
1192 hg clone http://selenic.com/hg#stable
1193
1193
1194 See :hg:`help urls` for details on specifying URLs.
1194 See :hg:`help urls` for details on specifying URLs.
1195
1195
1196 Returns 0 on success.
1196 Returns 0 on success.
1197 """
1197 """
1198 if opts.get('noupdate') and opts.get('updaterev'):
1198 if opts.get('noupdate') and opts.get('updaterev'):
1199 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1199 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1200
1200
1201 r = hg.clone(ui, opts, source, dest,
1201 r = hg.clone(ui, opts, source, dest,
1202 pull=opts.get('pull'),
1202 pull=opts.get('pull'),
1203 stream=opts.get('uncompressed'),
1203 stream=opts.get('uncompressed'),
1204 rev=opts.get('rev'),
1204 rev=opts.get('rev'),
1205 update=opts.get('updaterev') or not opts.get('noupdate'),
1205 update=opts.get('updaterev') or not opts.get('noupdate'),
1206 branch=opts.get('branch'))
1206 branch=opts.get('branch'))
1207
1207
1208 return r is None
1208 return r is None
1209
1209
1210 @command('^commit|ci',
1210 @command('^commit|ci',
1211 [('A', 'addremove', None,
1211 [('A', 'addremove', None,
1212 _('mark new/missing files as added/removed before committing')),
1212 _('mark new/missing files as added/removed before committing')),
1213 ('', 'close-branch', None,
1213 ('', 'close-branch', None,
1214 _('mark a branch as closed, hiding it from the branch list')),
1214 _('mark a branch as closed, hiding it from the branch list')),
1215 ('', 'amend', None, _('amend the parent of the working dir')),
1215 ('', 'amend', None, _('amend the parent of the working dir')),
1216 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1216 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1217 _('[OPTION]... [FILE]...'))
1217 _('[OPTION]... [FILE]...'))
1218 def commit(ui, repo, *pats, **opts):
1218 def commit(ui, repo, *pats, **opts):
1219 """commit the specified files or all outstanding changes
1219 """commit the specified files or all outstanding changes
1220
1220
1221 Commit changes to the given files into the repository. Unlike a
1221 Commit changes to the given files into the repository. Unlike a
1222 centralized SCM, this operation is a local operation. See
1222 centralized SCM, this operation is a local operation. See
1223 :hg:`push` for a way to actively distribute your changes.
1223 :hg:`push` for a way to actively distribute your changes.
1224
1224
1225 If a list of files is omitted, all changes reported by :hg:`status`
1225 If a list of files is omitted, all changes reported by :hg:`status`
1226 will be committed.
1226 will be committed.
1227
1227
1228 If you are committing the result of a merge, do not provide any
1228 If you are committing the result of a merge, do not provide any
1229 filenames or -I/-X filters.
1229 filenames or -I/-X filters.
1230
1230
1231 If no commit message is specified, Mercurial starts your
1231 If no commit message is specified, Mercurial starts your
1232 configured editor where you can enter a message. In case your
1232 configured editor where you can enter a message. In case your
1233 commit fails, you will find a backup of your message in
1233 commit fails, you will find a backup of your message in
1234 ``.hg/last-message.txt``.
1234 ``.hg/last-message.txt``.
1235
1235
1236 The --amend flag can be used to amend the parent of the
1236 The --amend flag can be used to amend the parent of the
1237 working directory with a new commit that contains the changes
1237 working directory with a new commit that contains the changes
1238 in the parent in addition to those currently reported by :hg:`status`,
1238 in the parent in addition to those currently reported by :hg:`status`,
1239 if there are any. The old commit is stored in a backup bundle in
1239 if there are any. The old commit is stored in a backup bundle in
1240 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1240 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1241 on how to restore it).
1241 on how to restore it).
1242
1242
1243 Message, user and date are taken from the amended commit unless
1243 Message, user and date are taken from the amended commit unless
1244 specified. When a message isn't specified on the command line,
1244 specified. When a message isn't specified on the command line,
1245 the editor will open with the message of the amended commit.
1245 the editor will open with the message of the amended commit.
1246
1246
1247 It is not possible to amend public changesets (see :hg:`help phases`)
1247 It is not possible to amend public changesets (see :hg:`help phases`)
1248 or changesets that have children.
1248 or changesets that have children.
1249
1249
1250 See :hg:`help dates` for a list of formats valid for -d/--date.
1250 See :hg:`help dates` for a list of formats valid for -d/--date.
1251
1251
1252 Returns 0 on success, 1 if nothing changed.
1252 Returns 0 on success, 1 if nothing changed.
1253 """
1253 """
1254 if opts.get('subrepos'):
1254 if opts.get('subrepos'):
1255 # Let --subrepos on the command line overide config setting.
1255 # Let --subrepos on the command line overide config setting.
1256 ui.setconfig('ui', 'commitsubrepos', True)
1256 ui.setconfig('ui', 'commitsubrepos', True)
1257
1257
1258 extra = {}
1258 extra = {}
1259 if opts.get('close_branch'):
1259 if opts.get('close_branch'):
1260 if repo['.'].node() not in repo.branchheads():
1260 if repo['.'].node() not in repo.branchheads():
1261 # The topo heads set is included in the branch heads set of the
1261 # The topo heads set is included in the branch heads set of the
1262 # current branch, so it's sufficient to test branchheads
1262 # current branch, so it's sufficient to test branchheads
1263 raise util.Abort(_('can only close branch heads'))
1263 raise util.Abort(_('can only close branch heads'))
1264 extra['close'] = 1
1264 extra['close'] = 1
1265
1265
1266 branch = repo[None].branch()
1266 branch = repo[None].branch()
1267 bheads = repo.branchheads(branch)
1267 bheads = repo.branchheads(branch)
1268
1268
1269 if opts.get('amend'):
1269 if opts.get('amend'):
1270 if ui.configbool('ui', 'commitsubrepos'):
1270 if ui.configbool('ui', 'commitsubrepos'):
1271 raise util.Abort(_('cannot amend recursively'))
1271 raise util.Abort(_('cannot amend recursively'))
1272
1272
1273 old = repo['.']
1273 old = repo['.']
1274 if old.phase() == phases.public:
1274 if old.phase() == phases.public:
1275 raise util.Abort(_('cannot amend public changesets'))
1275 raise util.Abort(_('cannot amend public changesets'))
1276 if len(old.parents()) > 1:
1276 if len(old.parents()) > 1:
1277 raise util.Abort(_('cannot amend merge changesets'))
1277 raise util.Abort(_('cannot amend merge changesets'))
1278 if len(repo[None].parents()) > 1:
1278 if len(repo[None].parents()) > 1:
1279 raise util.Abort(_('cannot amend while merging'))
1279 raise util.Abort(_('cannot amend while merging'))
1280 if old.children():
1280 if old.children():
1281 raise util.Abort(_('cannot amend changeset with children'))
1281 raise util.Abort(_('cannot amend changeset with children'))
1282
1282
1283 e = cmdutil.commiteditor
1283 e = cmdutil.commiteditor
1284 if opts.get('force_editor'):
1284 if opts.get('force_editor'):
1285 e = cmdutil.commitforceeditor
1285 e = cmdutil.commitforceeditor
1286
1286
1287 def commitfunc(ui, repo, message, match, opts):
1287 def commitfunc(ui, repo, message, match, opts):
1288 editor = e
1288 editor = e
1289 # message contains text from -m or -l, if it's empty,
1289 # message contains text from -m or -l, if it's empty,
1290 # open the editor with the old message
1290 # open the editor with the old message
1291 if not message:
1291 if not message:
1292 message = old.description()
1292 message = old.description()
1293 editor = cmdutil.commitforceeditor
1293 editor = cmdutil.commitforceeditor
1294 return repo.commit(message,
1294 return repo.commit(message,
1295 opts.get('user') or old.user(),
1295 opts.get('user') or old.user(),
1296 opts.get('date') or old.date(),
1296 opts.get('date') or old.date(),
1297 match,
1297 match,
1298 editor=editor,
1298 editor=editor,
1299 extra=extra)
1299 extra=extra)
1300
1300
1301 current = repo._bookmarkcurrent
1301 current = repo._bookmarkcurrent
1302 marks = old.bookmarks()
1302 marks = old.bookmarks()
1303 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1303 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1304 if node == old.node():
1304 if node == old.node():
1305 ui.status(_("nothing changed\n"))
1305 ui.status(_("nothing changed\n"))
1306 return 1
1306 return 1
1307 elif marks:
1307 elif marks:
1308 ui.debug('moving bookmarks %r from %s to %s\n' %
1308 ui.debug('moving bookmarks %r from %s to %s\n' %
1309 (marks, old.hex(), hex(node)))
1309 (marks, old.hex(), hex(node)))
1310 for bm in marks:
1310 for bm in marks:
1311 repo._bookmarks[bm] = node
1311 repo._bookmarks[bm] = node
1312 if bm == current:
1312 if bm == current:
1313 bookmarks.setcurrent(repo, bm)
1313 bookmarks.setcurrent(repo, bm)
1314 bookmarks.write(repo)
1314 bookmarks.write(repo)
1315 else:
1315 else:
1316 e = cmdutil.commiteditor
1316 e = cmdutil.commiteditor
1317 if opts.get('force_editor'):
1317 if opts.get('force_editor'):
1318 e = cmdutil.commitforceeditor
1318 e = cmdutil.commitforceeditor
1319
1319
1320 def commitfunc(ui, repo, message, match, opts):
1320 def commitfunc(ui, repo, message, match, opts):
1321 return repo.commit(message, opts.get('user'), opts.get('date'),
1321 return repo.commit(message, opts.get('user'), opts.get('date'),
1322 match, editor=e, extra=extra)
1322 match, editor=e, extra=extra)
1323
1323
1324 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1324 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1325
1325
1326 if not node:
1326 if not node:
1327 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1327 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1328 if stat[3]:
1328 if stat[3]:
1329 ui.status(_("nothing changed (%d missing files, see "
1329 ui.status(_("nothing changed (%d missing files, see "
1330 "'hg status')\n") % len(stat[3]))
1330 "'hg status')\n") % len(stat[3]))
1331 else:
1331 else:
1332 ui.status(_("nothing changed\n"))
1332 ui.status(_("nothing changed\n"))
1333 return 1
1333 return 1
1334
1334
1335 ctx = repo[node]
1335 ctx = repo[node]
1336 parents = ctx.parents()
1336 parents = ctx.parents()
1337
1337
1338 if (not opts.get('amend') and bheads and node not in bheads and not
1338 if (not opts.get('amend') and bheads and node not in bheads and not
1339 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1339 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1340 ui.status(_('created new head\n'))
1340 ui.status(_('created new head\n'))
1341 # The message is not printed for initial roots. For the other
1341 # The message is not printed for initial roots. For the other
1342 # changesets, it is printed in the following situations:
1342 # changesets, it is printed in the following situations:
1343 #
1343 #
1344 # Par column: for the 2 parents with ...
1344 # Par column: for the 2 parents with ...
1345 # N: null or no parent
1345 # N: null or no parent
1346 # B: parent is on another named branch
1346 # B: parent is on another named branch
1347 # C: parent is a regular non head changeset
1347 # C: parent is a regular non head changeset
1348 # H: parent was a branch head of the current branch
1348 # H: parent was a branch head of the current branch
1349 # Msg column: whether we print "created new head" message
1349 # Msg column: whether we print "created new head" message
1350 # In the following, it is assumed that there already exists some
1350 # In the following, it is assumed that there already exists some
1351 # initial branch heads of the current branch, otherwise nothing is
1351 # initial branch heads of the current branch, otherwise nothing is
1352 # printed anyway.
1352 # printed anyway.
1353 #
1353 #
1354 # Par Msg Comment
1354 # Par Msg Comment
1355 # NN y additional topo root
1355 # NN y additional topo root
1356 #
1356 #
1357 # BN y additional branch root
1357 # BN y additional branch root
1358 # CN y additional topo head
1358 # CN y additional topo head
1359 # HN n usual case
1359 # HN n usual case
1360 #
1360 #
1361 # BB y weird additional branch root
1361 # BB y weird additional branch root
1362 # CB y branch merge
1362 # CB y branch merge
1363 # HB n merge with named branch
1363 # HB n merge with named branch
1364 #
1364 #
1365 # CC y additional head from merge
1365 # CC y additional head from merge
1366 # CH n merge with a head
1366 # CH n merge with a head
1367 #
1367 #
1368 # HH n head merge: head count decreases
1368 # HH n head merge: head count decreases
1369
1369
1370 if not opts.get('close_branch'):
1370 if not opts.get('close_branch'):
1371 for r in parents:
1371 for r in parents:
1372 if r.closesbranch() and r.branch() == branch:
1372 if r.closesbranch() and r.branch() == branch:
1373 ui.status(_('reopening closed branch head %d\n') % r)
1373 ui.status(_('reopening closed branch head %d\n') % r)
1374
1374
1375 if ui.debugflag:
1375 if ui.debugflag:
1376 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1376 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1377 elif ui.verbose:
1377 elif ui.verbose:
1378 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1378 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1379
1379
1380 @command('copy|cp',
1380 @command('copy|cp',
1381 [('A', 'after', None, _('record a copy that has already occurred')),
1381 [('A', 'after', None, _('record a copy that has already occurred')),
1382 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1382 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1383 ] + walkopts + dryrunopts,
1383 ] + walkopts + dryrunopts,
1384 _('[OPTION]... [SOURCE]... DEST'))
1384 _('[OPTION]... [SOURCE]... DEST'))
1385 def copy(ui, repo, *pats, **opts):
1385 def copy(ui, repo, *pats, **opts):
1386 """mark files as copied for the next commit
1386 """mark files as copied for the next commit
1387
1387
1388 Mark dest as having copies of source files. If dest is a
1388 Mark dest as having copies of source files. If dest is a
1389 directory, copies are put in that directory. If dest is a file,
1389 directory, copies are put in that directory. If dest is a file,
1390 the source must be a single file.
1390 the source must be a single file.
1391
1391
1392 By default, this command copies the contents of files as they
1392 By default, this command copies the contents of files as they
1393 exist in the working directory. If invoked with -A/--after, the
1393 exist in the working directory. If invoked with -A/--after, the
1394 operation is recorded, but no copying is performed.
1394 operation is recorded, but no copying is performed.
1395
1395
1396 This command takes effect with the next commit. To undo a copy
1396 This command takes effect with the next commit. To undo a copy
1397 before that, see :hg:`revert`.
1397 before that, see :hg:`revert`.
1398
1398
1399 Returns 0 on success, 1 if errors are encountered.
1399 Returns 0 on success, 1 if errors are encountered.
1400 """
1400 """
1401 wlock = repo.wlock(False)
1401 wlock = repo.wlock(False)
1402 try:
1402 try:
1403 return cmdutil.copy(ui, repo, pats, opts)
1403 return cmdutil.copy(ui, repo, pats, opts)
1404 finally:
1404 finally:
1405 wlock.release()
1405 wlock.release()
1406
1406
1407 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1407 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1408 def debugancestor(ui, repo, *args):
1408 def debugancestor(ui, repo, *args):
1409 """find the ancestor revision of two revisions in a given index"""
1409 """find the ancestor revision of two revisions in a given index"""
1410 if len(args) == 3:
1410 if len(args) == 3:
1411 index, rev1, rev2 = args
1411 index, rev1, rev2 = args
1412 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1412 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1413 lookup = r.lookup
1413 lookup = r.lookup
1414 elif len(args) == 2:
1414 elif len(args) == 2:
1415 if not repo:
1415 if not repo:
1416 raise util.Abort(_("there is no Mercurial repository here "
1416 raise util.Abort(_("there is no Mercurial repository here "
1417 "(.hg not found)"))
1417 "(.hg not found)"))
1418 rev1, rev2 = args
1418 rev1, rev2 = args
1419 r = repo.changelog
1419 r = repo.changelog
1420 lookup = repo.lookup
1420 lookup = repo.lookup
1421 else:
1421 else:
1422 raise util.Abort(_('either two or three arguments required'))
1422 raise util.Abort(_('either two or three arguments required'))
1423 a = r.ancestor(lookup(rev1), lookup(rev2))
1423 a = r.ancestor(lookup(rev1), lookup(rev2))
1424 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1424 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1425
1425
1426 @command('debugbuilddag',
1426 @command('debugbuilddag',
1427 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1427 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1428 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1428 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1429 ('n', 'new-file', None, _('add new file at each rev'))],
1429 ('n', 'new-file', None, _('add new file at each rev'))],
1430 _('[OPTION]... [TEXT]'))
1430 _('[OPTION]... [TEXT]'))
1431 def debugbuilddag(ui, repo, text=None,
1431 def debugbuilddag(ui, repo, text=None,
1432 mergeable_file=False,
1432 mergeable_file=False,
1433 overwritten_file=False,
1433 overwritten_file=False,
1434 new_file=False):
1434 new_file=False):
1435 """builds a repo with a given DAG from scratch in the current empty repo
1435 """builds a repo with a given DAG from scratch in the current empty repo
1436
1436
1437 The description of the DAG is read from stdin if not given on the
1437 The description of the DAG is read from stdin if not given on the
1438 command line.
1438 command line.
1439
1439
1440 Elements:
1440 Elements:
1441
1441
1442 - "+n" is a linear run of n nodes based on the current default parent
1442 - "+n" is a linear run of n nodes based on the current default parent
1443 - "." is a single node based on the current default parent
1443 - "." is a single node based on the current default parent
1444 - "$" resets the default parent to null (implied at the start);
1444 - "$" resets the default parent to null (implied at the start);
1445 otherwise the default parent is always the last node created
1445 otherwise the default parent is always the last node created
1446 - "<p" sets the default parent to the backref p
1446 - "<p" sets the default parent to the backref p
1447 - "*p" is a fork at parent p, which is a backref
1447 - "*p" is a fork at parent p, which is a backref
1448 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1448 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1449 - "/p2" is a merge of the preceding node and p2
1449 - "/p2" is a merge of the preceding node and p2
1450 - ":tag" defines a local tag for the preceding node
1450 - ":tag" defines a local tag for the preceding node
1451 - "@branch" sets the named branch for subsequent nodes
1451 - "@branch" sets the named branch for subsequent nodes
1452 - "#...\\n" is a comment up to the end of the line
1452 - "#...\\n" is a comment up to the end of the line
1453
1453
1454 Whitespace between the above elements is ignored.
1454 Whitespace between the above elements is ignored.
1455
1455
1456 A backref is either
1456 A backref is either
1457
1457
1458 - a number n, which references the node curr-n, where curr is the current
1458 - a number n, which references the node curr-n, where curr is the current
1459 node, or
1459 node, or
1460 - the name of a local tag you placed earlier using ":tag", or
1460 - the name of a local tag you placed earlier using ":tag", or
1461 - empty to denote the default parent.
1461 - empty to denote the default parent.
1462
1462
1463 All string valued-elements are either strictly alphanumeric, or must
1463 All string valued-elements are either strictly alphanumeric, or must
1464 be enclosed in double quotes ("..."), with "\\" as escape character.
1464 be enclosed in double quotes ("..."), with "\\" as escape character.
1465 """
1465 """
1466
1466
1467 if text is None:
1467 if text is None:
1468 ui.status(_("reading DAG from stdin\n"))
1468 ui.status(_("reading DAG from stdin\n"))
1469 text = ui.fin.read()
1469 text = ui.fin.read()
1470
1470
1471 cl = repo.changelog
1471 cl = repo.changelog
1472 if len(cl) > 0:
1472 if len(cl) > 0:
1473 raise util.Abort(_('repository is not empty'))
1473 raise util.Abort(_('repository is not empty'))
1474
1474
1475 # determine number of revs in DAG
1475 # determine number of revs in DAG
1476 total = 0
1476 total = 0
1477 for type, data in dagparser.parsedag(text):
1477 for type, data in dagparser.parsedag(text):
1478 if type == 'n':
1478 if type == 'n':
1479 total += 1
1479 total += 1
1480
1480
1481 if mergeable_file:
1481 if mergeable_file:
1482 linesperrev = 2
1482 linesperrev = 2
1483 # make a file with k lines per rev
1483 # make a file with k lines per rev
1484 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1484 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1485 initialmergedlines.append("")
1485 initialmergedlines.append("")
1486
1486
1487 tags = []
1487 tags = []
1488
1488
1489 lock = tr = None
1489 lock = tr = None
1490 try:
1490 try:
1491 lock = repo.lock()
1491 lock = repo.lock()
1492 tr = repo.transaction("builddag")
1492 tr = repo.transaction("builddag")
1493
1493
1494 at = -1
1494 at = -1
1495 atbranch = 'default'
1495 atbranch = 'default'
1496 nodeids = []
1496 nodeids = []
1497 id = 0
1497 id = 0
1498 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1498 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1499 for type, data in dagparser.parsedag(text):
1499 for type, data in dagparser.parsedag(text):
1500 if type == 'n':
1500 if type == 'n':
1501 ui.note('node %s\n' % str(data))
1501 ui.note('node %s\n' % str(data))
1502 id, ps = data
1502 id, ps = data
1503
1503
1504 files = []
1504 files = []
1505 fctxs = {}
1505 fctxs = {}
1506
1506
1507 p2 = None
1507 p2 = None
1508 if mergeable_file:
1508 if mergeable_file:
1509 fn = "mf"
1509 fn = "mf"
1510 p1 = repo[ps[0]]
1510 p1 = repo[ps[0]]
1511 if len(ps) > 1:
1511 if len(ps) > 1:
1512 p2 = repo[ps[1]]
1512 p2 = repo[ps[1]]
1513 pa = p1.ancestor(p2)
1513 pa = p1.ancestor(p2)
1514 base, local, other = [x[fn].data() for x in pa, p1, p2]
1514 base, local, other = [x[fn].data() for x in pa, p1, p2]
1515 m3 = simplemerge.Merge3Text(base, local, other)
1515 m3 = simplemerge.Merge3Text(base, local, other)
1516 ml = [l.strip() for l in m3.merge_lines()]
1516 ml = [l.strip() for l in m3.merge_lines()]
1517 ml.append("")
1517 ml.append("")
1518 elif at > 0:
1518 elif at > 0:
1519 ml = p1[fn].data().split("\n")
1519 ml = p1[fn].data().split("\n")
1520 else:
1520 else:
1521 ml = initialmergedlines
1521 ml = initialmergedlines
1522 ml[id * linesperrev] += " r%i" % id
1522 ml[id * linesperrev] += " r%i" % id
1523 mergedtext = "\n".join(ml)
1523 mergedtext = "\n".join(ml)
1524 files.append(fn)
1524 files.append(fn)
1525 fctxs[fn] = context.memfilectx(fn, mergedtext)
1525 fctxs[fn] = context.memfilectx(fn, mergedtext)
1526
1526
1527 if overwritten_file:
1527 if overwritten_file:
1528 fn = "of"
1528 fn = "of"
1529 files.append(fn)
1529 files.append(fn)
1530 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1530 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1531
1531
1532 if new_file:
1532 if new_file:
1533 fn = "nf%i" % id
1533 fn = "nf%i" % id
1534 files.append(fn)
1534 files.append(fn)
1535 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1535 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1536 if len(ps) > 1:
1536 if len(ps) > 1:
1537 if not p2:
1537 if not p2:
1538 p2 = repo[ps[1]]
1538 p2 = repo[ps[1]]
1539 for fn in p2:
1539 for fn in p2:
1540 if fn.startswith("nf"):
1540 if fn.startswith("nf"):
1541 files.append(fn)
1541 files.append(fn)
1542 fctxs[fn] = p2[fn]
1542 fctxs[fn] = p2[fn]
1543
1543
1544 def fctxfn(repo, cx, path):
1544 def fctxfn(repo, cx, path):
1545 return fctxs.get(path)
1545 return fctxs.get(path)
1546
1546
1547 if len(ps) == 0 or ps[0] < 0:
1547 if len(ps) == 0 or ps[0] < 0:
1548 pars = [None, None]
1548 pars = [None, None]
1549 elif len(ps) == 1:
1549 elif len(ps) == 1:
1550 pars = [nodeids[ps[0]], None]
1550 pars = [nodeids[ps[0]], None]
1551 else:
1551 else:
1552 pars = [nodeids[p] for p in ps]
1552 pars = [nodeids[p] for p in ps]
1553 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1553 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1554 date=(id, 0),
1554 date=(id, 0),
1555 user="debugbuilddag",
1555 user="debugbuilddag",
1556 extra={'branch': atbranch})
1556 extra={'branch': atbranch})
1557 nodeid = repo.commitctx(cx)
1557 nodeid = repo.commitctx(cx)
1558 nodeids.append(nodeid)
1558 nodeids.append(nodeid)
1559 at = id
1559 at = id
1560 elif type == 'l':
1560 elif type == 'l':
1561 id, name = data
1561 id, name = data
1562 ui.note('tag %s\n' % name)
1562 ui.note('tag %s\n' % name)
1563 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1563 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1564 elif type == 'a':
1564 elif type == 'a':
1565 ui.note('branch %s\n' % data)
1565 ui.note('branch %s\n' % data)
1566 atbranch = data
1566 atbranch = data
1567 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1567 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1568 tr.close()
1568 tr.close()
1569
1569
1570 if tags:
1570 if tags:
1571 repo.opener.write("localtags", "".join(tags))
1571 repo.opener.write("localtags", "".join(tags))
1572 finally:
1572 finally:
1573 ui.progress(_('building'), None)
1573 ui.progress(_('building'), None)
1574 release(tr, lock)
1574 release(tr, lock)
1575
1575
1576 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1576 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1577 def debugbundle(ui, bundlepath, all=None, **opts):
1577 def debugbundle(ui, bundlepath, all=None, **opts):
1578 """lists the contents of a bundle"""
1578 """lists the contents of a bundle"""
1579 f = url.open(ui, bundlepath)
1579 f = url.open(ui, bundlepath)
1580 try:
1580 try:
1581 gen = changegroup.readbundle(f, bundlepath)
1581 gen = changegroup.readbundle(f, bundlepath)
1582 if all:
1582 if all:
1583 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1583 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1584
1584
1585 def showchunks(named):
1585 def showchunks(named):
1586 ui.write("\n%s\n" % named)
1586 ui.write("\n%s\n" % named)
1587 chain = None
1587 chain = None
1588 while True:
1588 while True:
1589 chunkdata = gen.deltachunk(chain)
1589 chunkdata = gen.deltachunk(chain)
1590 if not chunkdata:
1590 if not chunkdata:
1591 break
1591 break
1592 node = chunkdata['node']
1592 node = chunkdata['node']
1593 p1 = chunkdata['p1']
1593 p1 = chunkdata['p1']
1594 p2 = chunkdata['p2']
1594 p2 = chunkdata['p2']
1595 cs = chunkdata['cs']
1595 cs = chunkdata['cs']
1596 deltabase = chunkdata['deltabase']
1596 deltabase = chunkdata['deltabase']
1597 delta = chunkdata['delta']
1597 delta = chunkdata['delta']
1598 ui.write("%s %s %s %s %s %s\n" %
1598 ui.write("%s %s %s %s %s %s\n" %
1599 (hex(node), hex(p1), hex(p2),
1599 (hex(node), hex(p1), hex(p2),
1600 hex(cs), hex(deltabase), len(delta)))
1600 hex(cs), hex(deltabase), len(delta)))
1601 chain = node
1601 chain = node
1602
1602
1603 chunkdata = gen.changelogheader()
1603 chunkdata = gen.changelogheader()
1604 showchunks("changelog")
1604 showchunks("changelog")
1605 chunkdata = gen.manifestheader()
1605 chunkdata = gen.manifestheader()
1606 showchunks("manifest")
1606 showchunks("manifest")
1607 while True:
1607 while True:
1608 chunkdata = gen.filelogheader()
1608 chunkdata = gen.filelogheader()
1609 if not chunkdata:
1609 if not chunkdata:
1610 break
1610 break
1611 fname = chunkdata['filename']
1611 fname = chunkdata['filename']
1612 showchunks(fname)
1612 showchunks(fname)
1613 else:
1613 else:
1614 chunkdata = gen.changelogheader()
1614 chunkdata = gen.changelogheader()
1615 chain = None
1615 chain = None
1616 while True:
1616 while True:
1617 chunkdata = gen.deltachunk(chain)
1617 chunkdata = gen.deltachunk(chain)
1618 if not chunkdata:
1618 if not chunkdata:
1619 break
1619 break
1620 node = chunkdata['node']
1620 node = chunkdata['node']
1621 ui.write("%s\n" % hex(node))
1621 ui.write("%s\n" % hex(node))
1622 chain = node
1622 chain = node
1623 finally:
1623 finally:
1624 f.close()
1624 f.close()
1625
1625
1626 @command('debugcheckstate', [], '')
1626 @command('debugcheckstate', [], '')
1627 def debugcheckstate(ui, repo):
1627 def debugcheckstate(ui, repo):
1628 """validate the correctness of the current dirstate"""
1628 """validate the correctness of the current dirstate"""
1629 parent1, parent2 = repo.dirstate.parents()
1629 parent1, parent2 = repo.dirstate.parents()
1630 m1 = repo[parent1].manifest()
1630 m1 = repo[parent1].manifest()
1631 m2 = repo[parent2].manifest()
1631 m2 = repo[parent2].manifest()
1632 errors = 0
1632 errors = 0
1633 for f in repo.dirstate:
1633 for f in repo.dirstate:
1634 state = repo.dirstate[f]
1634 state = repo.dirstate[f]
1635 if state in "nr" and f not in m1:
1635 if state in "nr" and f not in m1:
1636 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1636 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1637 errors += 1
1637 errors += 1
1638 if state in "a" and f in m1:
1638 if state in "a" and f in m1:
1639 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1639 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1640 errors += 1
1640 errors += 1
1641 if state in "m" and f not in m1 and f not in m2:
1641 if state in "m" and f not in m1 and f not in m2:
1642 ui.warn(_("%s in state %s, but not in either manifest\n") %
1642 ui.warn(_("%s in state %s, but not in either manifest\n") %
1643 (f, state))
1643 (f, state))
1644 errors += 1
1644 errors += 1
1645 for f in m1:
1645 for f in m1:
1646 state = repo.dirstate[f]
1646 state = repo.dirstate[f]
1647 if state not in "nrm":
1647 if state not in "nrm":
1648 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1648 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1649 errors += 1
1649 errors += 1
1650 if errors:
1650 if errors:
1651 error = _(".hg/dirstate inconsistent with current parent's manifest")
1651 error = _(".hg/dirstate inconsistent with current parent's manifest")
1652 raise util.Abort(error)
1652 raise util.Abort(error)
1653
1653
1654 @command('debugcommands', [], _('[COMMAND]'))
1654 @command('debugcommands', [], _('[COMMAND]'))
1655 def debugcommands(ui, cmd='', *args):
1655 def debugcommands(ui, cmd='', *args):
1656 """list all available commands and options"""
1656 """list all available commands and options"""
1657 for cmd, vals in sorted(table.iteritems()):
1657 for cmd, vals in sorted(table.iteritems()):
1658 cmd = cmd.split('|')[0].strip('^')
1658 cmd = cmd.split('|')[0].strip('^')
1659 opts = ', '.join([i[1] for i in vals[1]])
1659 opts = ', '.join([i[1] for i in vals[1]])
1660 ui.write('%s: %s\n' % (cmd, opts))
1660 ui.write('%s: %s\n' % (cmd, opts))
1661
1661
1662 @command('debugcomplete',
1662 @command('debugcomplete',
1663 [('o', 'options', None, _('show the command options'))],
1663 [('o', 'options', None, _('show the command options'))],
1664 _('[-o] CMD'))
1664 _('[-o] CMD'))
1665 def debugcomplete(ui, cmd='', **opts):
1665 def debugcomplete(ui, cmd='', **opts):
1666 """returns the completion list associated with the given command"""
1666 """returns the completion list associated with the given command"""
1667
1667
1668 if opts.get('options'):
1668 if opts.get('options'):
1669 options = []
1669 options = []
1670 otables = [globalopts]
1670 otables = [globalopts]
1671 if cmd:
1671 if cmd:
1672 aliases, entry = cmdutil.findcmd(cmd, table, False)
1672 aliases, entry = cmdutil.findcmd(cmd, table, False)
1673 otables.append(entry[1])
1673 otables.append(entry[1])
1674 for t in otables:
1674 for t in otables:
1675 for o in t:
1675 for o in t:
1676 if "(DEPRECATED)" in o[3]:
1676 if "(DEPRECATED)" in o[3]:
1677 continue
1677 continue
1678 if o[0]:
1678 if o[0]:
1679 options.append('-%s' % o[0])
1679 options.append('-%s' % o[0])
1680 options.append('--%s' % o[1])
1680 options.append('--%s' % o[1])
1681 ui.write("%s\n" % "\n".join(options))
1681 ui.write("%s\n" % "\n".join(options))
1682 return
1682 return
1683
1683
1684 cmdlist = cmdutil.findpossible(cmd, table)
1684 cmdlist = cmdutil.findpossible(cmd, table)
1685 if ui.verbose:
1685 if ui.verbose:
1686 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1686 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1687 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1687 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1688
1688
1689 @command('debugdag',
1689 @command('debugdag',
1690 [('t', 'tags', None, _('use tags as labels')),
1690 [('t', 'tags', None, _('use tags as labels')),
1691 ('b', 'branches', None, _('annotate with branch names')),
1691 ('b', 'branches', None, _('annotate with branch names')),
1692 ('', 'dots', None, _('use dots for runs')),
1692 ('', 'dots', None, _('use dots for runs')),
1693 ('s', 'spaces', None, _('separate elements by spaces'))],
1693 ('s', 'spaces', None, _('separate elements by spaces'))],
1694 _('[OPTION]... [FILE [REV]...]'))
1694 _('[OPTION]... [FILE [REV]...]'))
1695 def debugdag(ui, repo, file_=None, *revs, **opts):
1695 def debugdag(ui, repo, file_=None, *revs, **opts):
1696 """format the changelog or an index DAG as a concise textual description
1696 """format the changelog or an index DAG as a concise textual description
1697
1697
1698 If you pass a revlog index, the revlog's DAG is emitted. If you list
1698 If you pass a revlog index, the revlog's DAG is emitted. If you list
1699 revision numbers, they get labelled in the output as rN.
1699 revision numbers, they get labelled in the output as rN.
1700
1700
1701 Otherwise, the changelog DAG of the current repo is emitted.
1701 Otherwise, the changelog DAG of the current repo is emitted.
1702 """
1702 """
1703 spaces = opts.get('spaces')
1703 spaces = opts.get('spaces')
1704 dots = opts.get('dots')
1704 dots = opts.get('dots')
1705 if file_:
1705 if file_:
1706 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1706 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1707 revs = set((int(r) for r in revs))
1707 revs = set((int(r) for r in revs))
1708 def events():
1708 def events():
1709 for r in rlog:
1709 for r in rlog:
1710 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1710 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1711 if p != -1)))
1711 if p != -1)))
1712 if r in revs:
1712 if r in revs:
1713 yield 'l', (r, "r%i" % r)
1713 yield 'l', (r, "r%i" % r)
1714 elif repo:
1714 elif repo:
1715 cl = repo.changelog
1715 cl = repo.changelog
1716 tags = opts.get('tags')
1716 tags = opts.get('tags')
1717 branches = opts.get('branches')
1717 branches = opts.get('branches')
1718 if tags:
1718 if tags:
1719 labels = {}
1719 labels = {}
1720 for l, n in repo.tags().items():
1720 for l, n in repo.tags().items():
1721 labels.setdefault(cl.rev(n), []).append(l)
1721 labels.setdefault(cl.rev(n), []).append(l)
1722 def events():
1722 def events():
1723 b = "default"
1723 b = "default"
1724 for r in cl:
1724 for r in cl:
1725 if branches:
1725 if branches:
1726 newb = cl.read(cl.node(r))[5]['branch']
1726 newb = cl.read(cl.node(r))[5]['branch']
1727 if newb != b:
1727 if newb != b:
1728 yield 'a', newb
1728 yield 'a', newb
1729 b = newb
1729 b = newb
1730 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1730 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1731 if p != -1)))
1731 if p != -1)))
1732 if tags:
1732 if tags:
1733 ls = labels.get(r)
1733 ls = labels.get(r)
1734 if ls:
1734 if ls:
1735 for l in ls:
1735 for l in ls:
1736 yield 'l', (r, l)
1736 yield 'l', (r, l)
1737 else:
1737 else:
1738 raise util.Abort(_('need repo for changelog dag'))
1738 raise util.Abort(_('need repo for changelog dag'))
1739
1739
1740 for line in dagparser.dagtextlines(events(),
1740 for line in dagparser.dagtextlines(events(),
1741 addspaces=spaces,
1741 addspaces=spaces,
1742 wraplabels=True,
1742 wraplabels=True,
1743 wrapannotations=True,
1743 wrapannotations=True,
1744 wrapnonlinear=dots,
1744 wrapnonlinear=dots,
1745 usedots=dots,
1745 usedots=dots,
1746 maxlinewidth=70):
1746 maxlinewidth=70):
1747 ui.write(line)
1747 ui.write(line)
1748 ui.write("\n")
1748 ui.write("\n")
1749
1749
1750 @command('debugdata',
1750 @command('debugdata',
1751 [('c', 'changelog', False, _('open changelog')),
1751 [('c', 'changelog', False, _('open changelog')),
1752 ('m', 'manifest', False, _('open manifest'))],
1752 ('m', 'manifest', False, _('open manifest'))],
1753 _('-c|-m|FILE REV'))
1753 _('-c|-m|FILE REV'))
1754 def debugdata(ui, repo, file_, rev = None, **opts):
1754 def debugdata(ui, repo, file_, rev = None, **opts):
1755 """dump the contents of a data file revision"""
1755 """dump the contents of a data file revision"""
1756 if opts.get('changelog') or opts.get('manifest'):
1756 if opts.get('changelog') or opts.get('manifest'):
1757 file_, rev = None, file_
1757 file_, rev = None, file_
1758 elif rev is None:
1758 elif rev is None:
1759 raise error.CommandError('debugdata', _('invalid arguments'))
1759 raise error.CommandError('debugdata', _('invalid arguments'))
1760 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1760 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1761 try:
1761 try:
1762 ui.write(r.revision(r.lookup(rev)))
1762 ui.write(r.revision(r.lookup(rev)))
1763 except KeyError:
1763 except KeyError:
1764 raise util.Abort(_('invalid revision identifier %s') % rev)
1764 raise util.Abort(_('invalid revision identifier %s') % rev)
1765
1765
1766 @command('debugdate',
1766 @command('debugdate',
1767 [('e', 'extended', None, _('try extended date formats'))],
1767 [('e', 'extended', None, _('try extended date formats'))],
1768 _('[-e] DATE [RANGE]'))
1768 _('[-e] DATE [RANGE]'))
1769 def debugdate(ui, date, range=None, **opts):
1769 def debugdate(ui, date, range=None, **opts):
1770 """parse and display a date"""
1770 """parse and display a date"""
1771 if opts["extended"]:
1771 if opts["extended"]:
1772 d = util.parsedate(date, util.extendeddateformats)
1772 d = util.parsedate(date, util.extendeddateformats)
1773 else:
1773 else:
1774 d = util.parsedate(date)
1774 d = util.parsedate(date)
1775 ui.write("internal: %s %s\n" % d)
1775 ui.write("internal: %s %s\n" % d)
1776 ui.write("standard: %s\n" % util.datestr(d))
1776 ui.write("standard: %s\n" % util.datestr(d))
1777 if range:
1777 if range:
1778 m = util.matchdate(range)
1778 m = util.matchdate(range)
1779 ui.write("match: %s\n" % m(d[0]))
1779 ui.write("match: %s\n" % m(d[0]))
1780
1780
1781 @command('debugdiscovery',
1781 @command('debugdiscovery',
1782 [('', 'old', None, _('use old-style discovery')),
1782 [('', 'old', None, _('use old-style discovery')),
1783 ('', 'nonheads', None,
1783 ('', 'nonheads', None,
1784 _('use old-style discovery with non-heads included')),
1784 _('use old-style discovery with non-heads included')),
1785 ] + remoteopts,
1785 ] + remoteopts,
1786 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1786 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1787 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1787 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1788 """runs the changeset discovery protocol in isolation"""
1788 """runs the changeset discovery protocol in isolation"""
1789 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1789 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1790 opts.get('branch'))
1790 opts.get('branch'))
1791 remote = hg.peer(repo, opts, remoteurl)
1791 remote = hg.peer(repo, opts, remoteurl)
1792 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1792 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1793
1793
1794 # make sure tests are repeatable
1794 # make sure tests are repeatable
1795 random.seed(12323)
1795 random.seed(12323)
1796
1796
1797 def doit(localheads, remoteheads, remote=remote):
1797 def doit(localheads, remoteheads, remote=remote):
1798 if opts.get('old'):
1798 if opts.get('old'):
1799 if localheads:
1799 if localheads:
1800 raise util.Abort('cannot use localheads with old style '
1800 raise util.Abort('cannot use localheads with old style '
1801 'discovery')
1801 'discovery')
1802 if not util.safehasattr(remote, 'branches'):
1802 if not util.safehasattr(remote, 'branches'):
1803 # enable in-client legacy support
1803 # enable in-client legacy support
1804 remote = localrepo.locallegacypeer(remote.local())
1804 remote = localrepo.locallegacypeer(remote.local())
1805 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1805 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1806 force=True)
1806 force=True)
1807 common = set(common)
1807 common = set(common)
1808 if not opts.get('nonheads'):
1808 if not opts.get('nonheads'):
1809 ui.write("unpruned common: %s\n" % " ".join([short(n)
1809 ui.write("unpruned common: %s\n" % " ".join([short(n)
1810 for n in common]))
1810 for n in common]))
1811 dag = dagutil.revlogdag(repo.changelog)
1811 dag = dagutil.revlogdag(repo.changelog)
1812 all = dag.ancestorset(dag.internalizeall(common))
1812 all = dag.ancestorset(dag.internalizeall(common))
1813 common = dag.externalizeall(dag.headsetofconnecteds(all))
1813 common = dag.externalizeall(dag.headsetofconnecteds(all))
1814 else:
1814 else:
1815 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1815 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1816 common = set(common)
1816 common = set(common)
1817 rheads = set(hds)
1817 rheads = set(hds)
1818 lheads = set(repo.heads())
1818 lheads = set(repo.heads())
1819 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1819 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1820 if lheads <= common:
1820 if lheads <= common:
1821 ui.write("local is subset\n")
1821 ui.write("local is subset\n")
1822 elif rheads <= common:
1822 elif rheads <= common:
1823 ui.write("remote is subset\n")
1823 ui.write("remote is subset\n")
1824
1824
1825 serverlogs = opts.get('serverlog')
1825 serverlogs = opts.get('serverlog')
1826 if serverlogs:
1826 if serverlogs:
1827 for filename in serverlogs:
1827 for filename in serverlogs:
1828 logfile = open(filename, 'r')
1828 logfile = open(filename, 'r')
1829 try:
1829 try:
1830 line = logfile.readline()
1830 line = logfile.readline()
1831 while line:
1831 while line:
1832 parts = line.strip().split(';')
1832 parts = line.strip().split(';')
1833 op = parts[1]
1833 op = parts[1]
1834 if op == 'cg':
1834 if op == 'cg':
1835 pass
1835 pass
1836 elif op == 'cgss':
1836 elif op == 'cgss':
1837 doit(parts[2].split(' '), parts[3].split(' '))
1837 doit(parts[2].split(' '), parts[3].split(' '))
1838 elif op == 'unb':
1838 elif op == 'unb':
1839 doit(parts[3].split(' '), parts[2].split(' '))
1839 doit(parts[3].split(' '), parts[2].split(' '))
1840 line = logfile.readline()
1840 line = logfile.readline()
1841 finally:
1841 finally:
1842 logfile.close()
1842 logfile.close()
1843
1843
1844 else:
1844 else:
1845 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1845 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1846 opts.get('remote_head'))
1846 opts.get('remote_head'))
1847 localrevs = opts.get('local_head')
1847 localrevs = opts.get('local_head')
1848 doit(localrevs, remoterevs)
1848 doit(localrevs, remoterevs)
1849
1849
1850 @command('debugfileset', [], ('REVSPEC'))
1850 @command('debugfileset', [], ('REVSPEC'))
1851 def debugfileset(ui, repo, expr):
1851 def debugfileset(ui, repo, expr):
1852 '''parse and apply a fileset specification'''
1852 '''parse and apply a fileset specification'''
1853 if ui.verbose:
1853 if ui.verbose:
1854 tree = fileset.parse(expr)[0]
1854 tree = fileset.parse(expr)[0]
1855 ui.note(tree, "\n")
1855 ui.note(tree, "\n")
1856
1856
1857 for f in fileset.getfileset(repo[None], expr):
1857 for f in fileset.getfileset(repo[None], expr):
1858 ui.write("%s\n" % f)
1858 ui.write("%s\n" % f)
1859
1859
1860 @command('debugfsinfo', [], _('[PATH]'))
1860 @command('debugfsinfo', [], _('[PATH]'))
1861 def debugfsinfo(ui, path = "."):
1861 def debugfsinfo(ui, path = "."):
1862 """show information detected about current filesystem"""
1862 """show information detected about current filesystem"""
1863 util.writefile('.debugfsinfo', '')
1863 util.writefile('.debugfsinfo', '')
1864 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1864 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1865 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1865 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1866 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1866 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1867 and 'yes' or 'no'))
1867 and 'yes' or 'no'))
1868 os.unlink('.debugfsinfo')
1868 os.unlink('.debugfsinfo')
1869
1869
1870 @command('debuggetbundle',
1870 @command('debuggetbundle',
1871 [('H', 'head', [], _('id of head node'), _('ID')),
1871 [('H', 'head', [], _('id of head node'), _('ID')),
1872 ('C', 'common', [], _('id of common node'), _('ID')),
1872 ('C', 'common', [], _('id of common node'), _('ID')),
1873 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1873 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1874 _('REPO FILE [-H|-C ID]...'))
1874 _('REPO FILE [-H|-C ID]...'))
1875 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1875 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1876 """retrieves a bundle from a repo
1876 """retrieves a bundle from a repo
1877
1877
1878 Every ID must be a full-length hex node id string. Saves the bundle to the
1878 Every ID must be a full-length hex node id string. Saves the bundle to the
1879 given file.
1879 given file.
1880 """
1880 """
1881 repo = hg.peer(ui, opts, repopath)
1881 repo = hg.peer(ui, opts, repopath)
1882 if not repo.capable('getbundle'):
1882 if not repo.capable('getbundle'):
1883 raise util.Abort("getbundle() not supported by target repository")
1883 raise util.Abort("getbundle() not supported by target repository")
1884 args = {}
1884 args = {}
1885 if common:
1885 if common:
1886 args['common'] = [bin(s) for s in common]
1886 args['common'] = [bin(s) for s in common]
1887 if head:
1887 if head:
1888 args['heads'] = [bin(s) for s in head]
1888 args['heads'] = [bin(s) for s in head]
1889 bundle = repo.getbundle('debug', **args)
1889 bundle = repo.getbundle('debug', **args)
1890
1890
1891 bundletype = opts.get('type', 'bzip2').lower()
1891 bundletype = opts.get('type', 'bzip2').lower()
1892 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1892 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1893 bundletype = btypes.get(bundletype)
1893 bundletype = btypes.get(bundletype)
1894 if bundletype not in changegroup.bundletypes:
1894 if bundletype not in changegroup.bundletypes:
1895 raise util.Abort(_('unknown bundle type specified with --type'))
1895 raise util.Abort(_('unknown bundle type specified with --type'))
1896 changegroup.writebundle(bundle, bundlepath, bundletype)
1896 changegroup.writebundle(bundle, bundlepath, bundletype)
1897
1897
1898 @command('debugignore', [], '')
1898 @command('debugignore', [], '')
1899 def debugignore(ui, repo, *values, **opts):
1899 def debugignore(ui, repo, *values, **opts):
1900 """display the combined ignore pattern"""
1900 """display the combined ignore pattern"""
1901 ignore = repo.dirstate._ignore
1901 ignore = repo.dirstate._ignore
1902 includepat = getattr(ignore, 'includepat', None)
1902 includepat = getattr(ignore, 'includepat', None)
1903 if includepat is not None:
1903 if includepat is not None:
1904 ui.write("%s\n" % includepat)
1904 ui.write("%s\n" % includepat)
1905 else:
1905 else:
1906 raise util.Abort(_("no ignore patterns found"))
1906 raise util.Abort(_("no ignore patterns found"))
1907
1907
1908 @command('debugindex',
1908 @command('debugindex',
1909 [('c', 'changelog', False, _('open changelog')),
1909 [('c', 'changelog', False, _('open changelog')),
1910 ('m', 'manifest', False, _('open manifest')),
1910 ('m', 'manifest', False, _('open manifest')),
1911 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1911 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1912 _('[-f FORMAT] -c|-m|FILE'))
1912 _('[-f FORMAT] -c|-m|FILE'))
1913 def debugindex(ui, repo, file_ = None, **opts):
1913 def debugindex(ui, repo, file_ = None, **opts):
1914 """dump the contents of an index file"""
1914 """dump the contents of an index file"""
1915 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1915 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1916 format = opts.get('format', 0)
1916 format = opts.get('format', 0)
1917 if format not in (0, 1):
1917 if format not in (0, 1):
1918 raise util.Abort(_("unknown format %d") % format)
1918 raise util.Abort(_("unknown format %d") % format)
1919
1919
1920 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1920 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1921 if generaldelta:
1921 if generaldelta:
1922 basehdr = ' delta'
1922 basehdr = ' delta'
1923 else:
1923 else:
1924 basehdr = ' base'
1924 basehdr = ' base'
1925
1925
1926 if format == 0:
1926 if format == 0:
1927 ui.write(" rev offset length " + basehdr + " linkrev"
1927 ui.write(" rev offset length " + basehdr + " linkrev"
1928 " nodeid p1 p2\n")
1928 " nodeid p1 p2\n")
1929 elif format == 1:
1929 elif format == 1:
1930 ui.write(" rev flag offset length"
1930 ui.write(" rev flag offset length"
1931 " size " + basehdr + " link p1 p2"
1931 " size " + basehdr + " link p1 p2"
1932 " nodeid\n")
1932 " nodeid\n")
1933
1933
1934 for i in r:
1934 for i in r:
1935 node = r.node(i)
1935 node = r.node(i)
1936 if generaldelta:
1936 if generaldelta:
1937 base = r.deltaparent(i)
1937 base = r.deltaparent(i)
1938 else:
1938 else:
1939 base = r.chainbase(i)
1939 base = r.chainbase(i)
1940 if format == 0:
1940 if format == 0:
1941 try:
1941 try:
1942 pp = r.parents(node)
1942 pp = r.parents(node)
1943 except Exception:
1943 except Exception:
1944 pp = [nullid, nullid]
1944 pp = [nullid, nullid]
1945 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1945 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1946 i, r.start(i), r.length(i), base, r.linkrev(i),
1946 i, r.start(i), r.length(i), base, r.linkrev(i),
1947 short(node), short(pp[0]), short(pp[1])))
1947 short(node), short(pp[0]), short(pp[1])))
1948 elif format == 1:
1948 elif format == 1:
1949 pr = r.parentrevs(i)
1949 pr = r.parentrevs(i)
1950 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1950 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1951 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1951 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1952 base, r.linkrev(i), pr[0], pr[1], short(node)))
1952 base, r.linkrev(i), pr[0], pr[1], short(node)))
1953
1953
1954 @command('debugindexdot', [], _('FILE'))
1954 @command('debugindexdot', [], _('FILE'))
1955 def debugindexdot(ui, repo, file_):
1955 def debugindexdot(ui, repo, file_):
1956 """dump an index DAG as a graphviz dot file"""
1956 """dump an index DAG as a graphviz dot file"""
1957 r = None
1957 r = None
1958 if repo:
1958 if repo:
1959 filelog = repo.file(file_)
1959 filelog = repo.file(file_)
1960 if len(filelog):
1960 if len(filelog):
1961 r = filelog
1961 r = filelog
1962 if not r:
1962 if not r:
1963 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1963 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1964 ui.write("digraph G {\n")
1964 ui.write("digraph G {\n")
1965 for i in r:
1965 for i in r:
1966 node = r.node(i)
1966 node = r.node(i)
1967 pp = r.parents(node)
1967 pp = r.parents(node)
1968 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1968 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1969 if pp[1] != nullid:
1969 if pp[1] != nullid:
1970 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1970 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1971 ui.write("}\n")
1971 ui.write("}\n")
1972
1972
1973 @command('debuginstall', [], '')
1973 @command('debuginstall', [], '')
1974 def debuginstall(ui):
1974 def debuginstall(ui):
1975 '''test Mercurial installation
1975 '''test Mercurial installation
1976
1976
1977 Returns 0 on success.
1977 Returns 0 on success.
1978 '''
1978 '''
1979
1979
1980 def writetemp(contents):
1980 def writetemp(contents):
1981 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1981 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1982 f = os.fdopen(fd, "wb")
1982 f = os.fdopen(fd, "wb")
1983 f.write(contents)
1983 f.write(contents)
1984 f.close()
1984 f.close()
1985 return name
1985 return name
1986
1986
1987 problems = 0
1987 problems = 0
1988
1988
1989 # encoding
1989 # encoding
1990 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
1990 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
1991 try:
1991 try:
1992 encoding.fromlocal("test")
1992 encoding.fromlocal("test")
1993 except util.Abort, inst:
1993 except util.Abort, inst:
1994 ui.write(" %s\n" % inst)
1994 ui.write(" %s\n" % inst)
1995 ui.write(_(" (check that your locale is properly set)\n"))
1995 ui.write(_(" (check that your locale is properly set)\n"))
1996 problems += 1
1996 problems += 1
1997
1997
1998 # compiled modules
1998 # compiled modules
1999 ui.status(_("checking installed modules (%s)...\n")
1999 ui.status(_("checking installed modules (%s)...\n")
2000 % os.path.dirname(__file__))
2000 % os.path.dirname(__file__))
2001 try:
2001 try:
2002 import bdiff, mpatch, base85, osutil
2002 import bdiff, mpatch, base85, osutil
2003 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2003 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2004 except Exception, inst:
2004 except Exception, inst:
2005 ui.write(" %s\n" % inst)
2005 ui.write(" %s\n" % inst)
2006 ui.write(_(" One or more extensions could not be found"))
2006 ui.write(_(" One or more extensions could not be found"))
2007 ui.write(_(" (check that you compiled the extensions)\n"))
2007 ui.write(_(" (check that you compiled the extensions)\n"))
2008 problems += 1
2008 problems += 1
2009
2009
2010 # templates
2010 # templates
2011 import templater
2011 import templater
2012 p = templater.templatepath()
2012 p = templater.templatepath()
2013 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2013 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2014 try:
2014 try:
2015 templater.templater(templater.templatepath("map-cmdline.default"))
2015 templater.templater(templater.templatepath("map-cmdline.default"))
2016 except Exception, inst:
2016 except Exception, inst:
2017 ui.write(" %s\n" % inst)
2017 ui.write(" %s\n" % inst)
2018 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2018 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2019 problems += 1
2019 problems += 1
2020
2020
2021 # editor
2021 # editor
2022 ui.status(_("checking commit editor...\n"))
2022 ui.status(_("checking commit editor...\n"))
2023 editor = ui.geteditor()
2023 editor = ui.geteditor()
2024 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2024 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2025 if not cmdpath:
2025 if not cmdpath:
2026 if editor == 'vi':
2026 if editor == 'vi':
2027 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2027 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2028 ui.write(_(" (specify a commit editor in your configuration"
2028 ui.write(_(" (specify a commit editor in your configuration"
2029 " file)\n"))
2029 " file)\n"))
2030 else:
2030 else:
2031 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2031 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2032 ui.write(_(" (specify a commit editor in your configuration"
2032 ui.write(_(" (specify a commit editor in your configuration"
2033 " file)\n"))
2033 " file)\n"))
2034 problems += 1
2034 problems += 1
2035
2035
2036 # check username
2036 # check username
2037 ui.status(_("checking username...\n"))
2037 ui.status(_("checking username...\n"))
2038 try:
2038 try:
2039 ui.username()
2039 ui.username()
2040 except util.Abort, e:
2040 except util.Abort, e:
2041 ui.write(" %s\n" % e)
2041 ui.write(" %s\n" % e)
2042 ui.write(_(" (specify a username in your configuration file)\n"))
2042 ui.write(_(" (specify a username in your configuration file)\n"))
2043 problems += 1
2043 problems += 1
2044
2044
2045 if not problems:
2045 if not problems:
2046 ui.status(_("no problems detected\n"))
2046 ui.status(_("no problems detected\n"))
2047 else:
2047 else:
2048 ui.write(_("%s problems detected,"
2048 ui.write(_("%s problems detected,"
2049 " please check your install!\n") % problems)
2049 " please check your install!\n") % problems)
2050
2050
2051 return problems
2051 return problems
2052
2052
2053 @command('debugknown', [], _('REPO ID...'))
2053 @command('debugknown', [], _('REPO ID...'))
2054 def debugknown(ui, repopath, *ids, **opts):
2054 def debugknown(ui, repopath, *ids, **opts):
2055 """test whether node ids are known to a repo
2055 """test whether node ids are known to a repo
2056
2056
2057 Every ID must be a full-length hex node id string. Returns a list of 0s
2057 Every ID must be a full-length hex node id string. Returns a list of 0s
2058 and 1s indicating unknown/known.
2058 and 1s indicating unknown/known.
2059 """
2059 """
2060 repo = hg.peer(ui, opts, repopath)
2060 repo = hg.peer(ui, opts, repopath)
2061 if not repo.capable('known'):
2061 if not repo.capable('known'):
2062 raise util.Abort("known() not supported by target repository")
2062 raise util.Abort("known() not supported by target repository")
2063 flags = repo.known([bin(s) for s in ids])
2063 flags = repo.known([bin(s) for s in ids])
2064 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2064 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2065
2065
2066 @command('debugobsolete', [] + commitopts2,
2066 @command('debugobsolete', [] + commitopts2,
2067 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2067 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2068 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2068 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2069 """create arbitrary obsolete marker"""
2069 """create arbitrary obsolete marker"""
2070 def parsenodeid(s):
2070 def parsenodeid(s):
2071 try:
2071 try:
2072 # We do not use revsingle/revrange functions here to accept
2072 # We do not use revsingle/revrange functions here to accept
2073 # arbitrary node identifiers, possibly not present in the
2073 # arbitrary node identifiers, possibly not present in the
2074 # local repository.
2074 # local repository.
2075 n = bin(s)
2075 n = bin(s)
2076 if len(n) != len(nullid):
2076 if len(n) != len(nullid):
2077 raise TypeError()
2077 raise TypeError()
2078 return n
2078 return n
2079 except TypeError:
2079 except TypeError:
2080 raise util.Abort('changeset references must be full hexadecimal '
2080 raise util.Abort('changeset references must be full hexadecimal '
2081 'node identifiers')
2081 'node identifiers')
2082
2082
2083 if precursor is not None:
2083 if precursor is not None:
2084 metadata = {}
2084 metadata = {}
2085 if 'date' in opts:
2085 if 'date' in opts:
2086 metadata['date'] = opts['date']
2086 metadata['date'] = opts['date']
2087 metadata['user'] = opts['user'] or ui.username()
2087 metadata['user'] = opts['user'] or ui.username()
2088 succs = tuple(parsenodeid(succ) for succ in successors)
2088 succs = tuple(parsenodeid(succ) for succ in successors)
2089 l = repo.lock()
2089 l = repo.lock()
2090 try:
2090 try:
2091 tr = repo.transaction('debugobsolete')
2091 tr = repo.transaction('debugobsolete')
2092 try:
2092 try:
2093 repo.obsstore.create(tr, parsenodeid(precursor), succs, 0,
2093 repo.obsstore.create(tr, parsenodeid(precursor), succs, 0,
2094 metadata)
2094 metadata)
2095 tr.close()
2095 tr.close()
2096 finally:
2096 finally:
2097 tr.release()
2097 tr.release()
2098 finally:
2098 finally:
2099 l.release()
2099 l.release()
2100 else:
2100 else:
2101 for m in obsolete.allmarkers(repo):
2101 for m in obsolete.allmarkers(repo):
2102 ui.write(hex(m.precnode()))
2102 ui.write(hex(m.precnode()))
2103 for repl in m.succnodes():
2103 for repl in m.succnodes():
2104 ui.write(' ')
2104 ui.write(' ')
2105 ui.write(hex(repl))
2105 ui.write(hex(repl))
2106 ui.write(' %X ' % m._data[2])
2106 ui.write(' %X ' % m._data[2])
2107 ui.write(m.metadata())
2107 ui.write(m.metadata())
2108 ui.write('\n')
2108 ui.write('\n')
2109
2109
2110 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2110 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2111 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2111 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2112 '''access the pushkey key/value protocol
2112 '''access the pushkey key/value protocol
2113
2113
2114 With two args, list the keys in the given namespace.
2114 With two args, list the keys in the given namespace.
2115
2115
2116 With five args, set a key to new if it currently is set to old.
2116 With five args, set a key to new if it currently is set to old.
2117 Reports success or failure.
2117 Reports success or failure.
2118 '''
2118 '''
2119
2119
2120 target = hg.peer(ui, {}, repopath)
2120 target = hg.peer(ui, {}, repopath)
2121 if keyinfo:
2121 if keyinfo:
2122 key, old, new = keyinfo
2122 key, old, new = keyinfo
2123 r = target.pushkey(namespace, key, old, new)
2123 r = target.pushkey(namespace, key, old, new)
2124 ui.status(str(r) + '\n')
2124 ui.status(str(r) + '\n')
2125 return not r
2125 return not r
2126 else:
2126 else:
2127 for k, v in target.listkeys(namespace).iteritems():
2127 for k, v in target.listkeys(namespace).iteritems():
2128 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2128 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2129 v.encode('string-escape')))
2129 v.encode('string-escape')))
2130
2130
2131 @command('debugpvec', [], _('A B'))
2131 @command('debugpvec', [], _('A B'))
2132 def debugpvec(ui, repo, a, b=None):
2132 def debugpvec(ui, repo, a, b=None):
2133 ca = scmutil.revsingle(repo, a)
2133 ca = scmutil.revsingle(repo, a)
2134 cb = scmutil.revsingle(repo, b)
2134 cb = scmutil.revsingle(repo, b)
2135 pa = pvec.ctxpvec(ca)
2135 pa = pvec.ctxpvec(ca)
2136 pb = pvec.ctxpvec(cb)
2136 pb = pvec.ctxpvec(cb)
2137 if pa == pb:
2137 if pa == pb:
2138 rel = "="
2138 rel = "="
2139 elif pa > pb:
2139 elif pa > pb:
2140 rel = ">"
2140 rel = ">"
2141 elif pa < pb:
2141 elif pa < pb:
2142 rel = "<"
2142 rel = "<"
2143 elif pa | pb:
2143 elif pa | pb:
2144 rel = "|"
2144 rel = "|"
2145 ui.write(_("a: %s\n") % pa)
2145 ui.write(_("a: %s\n") % pa)
2146 ui.write(_("b: %s\n") % pb)
2146 ui.write(_("b: %s\n") % pb)
2147 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2147 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2148 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2148 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2149 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2149 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2150 pa.distance(pb), rel))
2150 pa.distance(pb), rel))
2151
2151
2152 @command('debugrebuildstate',
2152 @command('debugrebuildstate',
2153 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2153 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2154 _('[-r REV] [REV]'))
2154 _('[-r REV] [REV]'))
2155 def debugrebuildstate(ui, repo, rev="tip"):
2155 def debugrebuildstate(ui, repo, rev="tip"):
2156 """rebuild the dirstate as it would look like for the given revision"""
2156 """rebuild the dirstate as it would look like for the given revision"""
2157 ctx = scmutil.revsingle(repo, rev)
2157 ctx = scmutil.revsingle(repo, rev)
2158 wlock = repo.wlock()
2158 wlock = repo.wlock()
2159 try:
2159 try:
2160 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2160 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2161 finally:
2161 finally:
2162 wlock.release()
2162 wlock.release()
2163
2163
2164 @command('debugrename',
2164 @command('debugrename',
2165 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2165 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2166 _('[-r REV] FILE'))
2166 _('[-r REV] FILE'))
2167 def debugrename(ui, repo, file1, *pats, **opts):
2167 def debugrename(ui, repo, file1, *pats, **opts):
2168 """dump rename information"""
2168 """dump rename information"""
2169
2169
2170 ctx = scmutil.revsingle(repo, opts.get('rev'))
2170 ctx = scmutil.revsingle(repo, opts.get('rev'))
2171 m = scmutil.match(ctx, (file1,) + pats, opts)
2171 m = scmutil.match(ctx, (file1,) + pats, opts)
2172 for abs in ctx.walk(m):
2172 for abs in ctx.walk(m):
2173 fctx = ctx[abs]
2173 fctx = ctx[abs]
2174 o = fctx.filelog().renamed(fctx.filenode())
2174 o = fctx.filelog().renamed(fctx.filenode())
2175 rel = m.rel(abs)
2175 rel = m.rel(abs)
2176 if o:
2176 if o:
2177 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2177 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2178 else:
2178 else:
2179 ui.write(_("%s not renamed\n") % rel)
2179 ui.write(_("%s not renamed\n") % rel)
2180
2180
2181 @command('debugrevlog',
2181 @command('debugrevlog',
2182 [('c', 'changelog', False, _('open changelog')),
2182 [('c', 'changelog', False, _('open changelog')),
2183 ('m', 'manifest', False, _('open manifest')),
2183 ('m', 'manifest', False, _('open manifest')),
2184 ('d', 'dump', False, _('dump index data'))],
2184 ('d', 'dump', False, _('dump index data'))],
2185 _('-c|-m|FILE'))
2185 _('-c|-m|FILE'))
2186 def debugrevlog(ui, repo, file_ = None, **opts):
2186 def debugrevlog(ui, repo, file_ = None, **opts):
2187 """show data and statistics about a revlog"""
2187 """show data and statistics about a revlog"""
2188 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2188 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2189
2189
2190 if opts.get("dump"):
2190 if opts.get("dump"):
2191 numrevs = len(r)
2191 numrevs = len(r)
2192 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2192 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2193 " rawsize totalsize compression heads\n")
2193 " rawsize totalsize compression heads\n")
2194 ts = 0
2194 ts = 0
2195 heads = set()
2195 heads = set()
2196 for rev in xrange(numrevs):
2196 for rev in xrange(numrevs):
2197 dbase = r.deltaparent(rev)
2197 dbase = r.deltaparent(rev)
2198 if dbase == -1:
2198 if dbase == -1:
2199 dbase = rev
2199 dbase = rev
2200 cbase = r.chainbase(rev)
2200 cbase = r.chainbase(rev)
2201 p1, p2 = r.parentrevs(rev)
2201 p1, p2 = r.parentrevs(rev)
2202 rs = r.rawsize(rev)
2202 rs = r.rawsize(rev)
2203 ts = ts + rs
2203 ts = ts + rs
2204 heads -= set(r.parentrevs(rev))
2204 heads -= set(r.parentrevs(rev))
2205 heads.add(rev)
2205 heads.add(rev)
2206 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2206 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2207 (rev, p1, p2, r.start(rev), r.end(rev),
2207 (rev, p1, p2, r.start(rev), r.end(rev),
2208 r.start(dbase), r.start(cbase),
2208 r.start(dbase), r.start(cbase),
2209 r.start(p1), r.start(p2),
2209 r.start(p1), r.start(p2),
2210 rs, ts, ts / r.end(rev), len(heads)))
2210 rs, ts, ts / r.end(rev), len(heads)))
2211 return 0
2211 return 0
2212
2212
2213 v = r.version
2213 v = r.version
2214 format = v & 0xFFFF
2214 format = v & 0xFFFF
2215 flags = []
2215 flags = []
2216 gdelta = False
2216 gdelta = False
2217 if v & revlog.REVLOGNGINLINEDATA:
2217 if v & revlog.REVLOGNGINLINEDATA:
2218 flags.append('inline')
2218 flags.append('inline')
2219 if v & revlog.REVLOGGENERALDELTA:
2219 if v & revlog.REVLOGGENERALDELTA:
2220 gdelta = True
2220 gdelta = True
2221 flags.append('generaldelta')
2221 flags.append('generaldelta')
2222 if not flags:
2222 if not flags:
2223 flags = ['(none)']
2223 flags = ['(none)']
2224
2224
2225 nummerges = 0
2225 nummerges = 0
2226 numfull = 0
2226 numfull = 0
2227 numprev = 0
2227 numprev = 0
2228 nump1 = 0
2228 nump1 = 0
2229 nump2 = 0
2229 nump2 = 0
2230 numother = 0
2230 numother = 0
2231 nump1prev = 0
2231 nump1prev = 0
2232 nump2prev = 0
2232 nump2prev = 0
2233 chainlengths = []
2233 chainlengths = []
2234
2234
2235 datasize = [None, 0, 0L]
2235 datasize = [None, 0, 0L]
2236 fullsize = [None, 0, 0L]
2236 fullsize = [None, 0, 0L]
2237 deltasize = [None, 0, 0L]
2237 deltasize = [None, 0, 0L]
2238
2238
2239 def addsize(size, l):
2239 def addsize(size, l):
2240 if l[0] is None or size < l[0]:
2240 if l[0] is None or size < l[0]:
2241 l[0] = size
2241 l[0] = size
2242 if size > l[1]:
2242 if size > l[1]:
2243 l[1] = size
2243 l[1] = size
2244 l[2] += size
2244 l[2] += size
2245
2245
2246 numrevs = len(r)
2246 numrevs = len(r)
2247 for rev in xrange(numrevs):
2247 for rev in xrange(numrevs):
2248 p1, p2 = r.parentrevs(rev)
2248 p1, p2 = r.parentrevs(rev)
2249 delta = r.deltaparent(rev)
2249 delta = r.deltaparent(rev)
2250 if format > 0:
2250 if format > 0:
2251 addsize(r.rawsize(rev), datasize)
2251 addsize(r.rawsize(rev), datasize)
2252 if p2 != nullrev:
2252 if p2 != nullrev:
2253 nummerges += 1
2253 nummerges += 1
2254 size = r.length(rev)
2254 size = r.length(rev)
2255 if delta == nullrev:
2255 if delta == nullrev:
2256 chainlengths.append(0)
2256 chainlengths.append(0)
2257 numfull += 1
2257 numfull += 1
2258 addsize(size, fullsize)
2258 addsize(size, fullsize)
2259 else:
2259 else:
2260 chainlengths.append(chainlengths[delta] + 1)
2260 chainlengths.append(chainlengths[delta] + 1)
2261 addsize(size, deltasize)
2261 addsize(size, deltasize)
2262 if delta == rev - 1:
2262 if delta == rev - 1:
2263 numprev += 1
2263 numprev += 1
2264 if delta == p1:
2264 if delta == p1:
2265 nump1prev += 1
2265 nump1prev += 1
2266 elif delta == p2:
2266 elif delta == p2:
2267 nump2prev += 1
2267 nump2prev += 1
2268 elif delta == p1:
2268 elif delta == p1:
2269 nump1 += 1
2269 nump1 += 1
2270 elif delta == p2:
2270 elif delta == p2:
2271 nump2 += 1
2271 nump2 += 1
2272 elif delta != nullrev:
2272 elif delta != nullrev:
2273 numother += 1
2273 numother += 1
2274
2274
2275 # Adjust size min value for empty cases
2275 # Adjust size min value for empty cases
2276 for size in (datasize, fullsize, deltasize):
2276 for size in (datasize, fullsize, deltasize):
2277 if size[0] is None:
2277 if size[0] is None:
2278 size[0] = 0
2278 size[0] = 0
2279
2279
2280 numdeltas = numrevs - numfull
2280 numdeltas = numrevs - numfull
2281 numoprev = numprev - nump1prev - nump2prev
2281 numoprev = numprev - nump1prev - nump2prev
2282 totalrawsize = datasize[2]
2282 totalrawsize = datasize[2]
2283 datasize[2] /= numrevs
2283 datasize[2] /= numrevs
2284 fulltotal = fullsize[2]
2284 fulltotal = fullsize[2]
2285 fullsize[2] /= numfull
2285 fullsize[2] /= numfull
2286 deltatotal = deltasize[2]
2286 deltatotal = deltasize[2]
2287 if numrevs - numfull > 0:
2287 if numrevs - numfull > 0:
2288 deltasize[2] /= numrevs - numfull
2288 deltasize[2] /= numrevs - numfull
2289 totalsize = fulltotal + deltatotal
2289 totalsize = fulltotal + deltatotal
2290 avgchainlen = sum(chainlengths) / numrevs
2290 avgchainlen = sum(chainlengths) / numrevs
2291 compratio = totalrawsize / totalsize
2291 compratio = totalrawsize / totalsize
2292
2292
2293 basedfmtstr = '%%%dd\n'
2293 basedfmtstr = '%%%dd\n'
2294 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2294 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2295
2295
2296 def dfmtstr(max):
2296 def dfmtstr(max):
2297 return basedfmtstr % len(str(max))
2297 return basedfmtstr % len(str(max))
2298 def pcfmtstr(max, padding=0):
2298 def pcfmtstr(max, padding=0):
2299 return basepcfmtstr % (len(str(max)), ' ' * padding)
2299 return basepcfmtstr % (len(str(max)), ' ' * padding)
2300
2300
2301 def pcfmt(value, total):
2301 def pcfmt(value, total):
2302 return (value, 100 * float(value) / total)
2302 return (value, 100 * float(value) / total)
2303
2303
2304 ui.write('format : %d\n' % format)
2304 ui.write('format : %d\n' % format)
2305 ui.write('flags : %s\n' % ', '.join(flags))
2305 ui.write('flags : %s\n' % ', '.join(flags))
2306
2306
2307 ui.write('\n')
2307 ui.write('\n')
2308 fmt = pcfmtstr(totalsize)
2308 fmt = pcfmtstr(totalsize)
2309 fmt2 = dfmtstr(totalsize)
2309 fmt2 = dfmtstr(totalsize)
2310 ui.write('revisions : ' + fmt2 % numrevs)
2310 ui.write('revisions : ' + fmt2 % numrevs)
2311 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2311 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2312 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2312 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2313 ui.write('revisions : ' + fmt2 % numrevs)
2313 ui.write('revisions : ' + fmt2 % numrevs)
2314 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2314 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2315 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2315 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2316 ui.write('revision size : ' + fmt2 % totalsize)
2316 ui.write('revision size : ' + fmt2 % totalsize)
2317 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2317 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2318 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2318 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2319
2319
2320 ui.write('\n')
2320 ui.write('\n')
2321 fmt = dfmtstr(max(avgchainlen, compratio))
2321 fmt = dfmtstr(max(avgchainlen, compratio))
2322 ui.write('avg chain length : ' + fmt % avgchainlen)
2322 ui.write('avg chain length : ' + fmt % avgchainlen)
2323 ui.write('compression ratio : ' + fmt % compratio)
2323 ui.write('compression ratio : ' + fmt % compratio)
2324
2324
2325 if format > 0:
2325 if format > 0:
2326 ui.write('\n')
2326 ui.write('\n')
2327 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2327 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2328 % tuple(datasize))
2328 % tuple(datasize))
2329 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2329 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2330 % tuple(fullsize))
2330 % tuple(fullsize))
2331 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2331 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2332 % tuple(deltasize))
2332 % tuple(deltasize))
2333
2333
2334 if numdeltas > 0:
2334 if numdeltas > 0:
2335 ui.write('\n')
2335 ui.write('\n')
2336 fmt = pcfmtstr(numdeltas)
2336 fmt = pcfmtstr(numdeltas)
2337 fmt2 = pcfmtstr(numdeltas, 4)
2337 fmt2 = pcfmtstr(numdeltas, 4)
2338 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2338 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2339 if numprev > 0:
2339 if numprev > 0:
2340 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev,
2340 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev,
2341 numprev))
2341 numprev))
2342 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev,
2342 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev,
2343 numprev))
2343 numprev))
2344 ui.write(' other : ' + fmt2 % pcfmt(numoprev,
2344 ui.write(' other : ' + fmt2 % pcfmt(numoprev,
2345 numprev))
2345 numprev))
2346 if gdelta:
2346 if gdelta:
2347 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2347 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2348 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2348 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2349 ui.write('deltas against other : ' + fmt % pcfmt(numother,
2349 ui.write('deltas against other : ' + fmt % pcfmt(numother,
2350 numdeltas))
2350 numdeltas))
2351
2351
2352 @command('debugrevspec', [], ('REVSPEC'))
2352 @command('debugrevspec', [], ('REVSPEC'))
2353 def debugrevspec(ui, repo, expr):
2353 def debugrevspec(ui, repo, expr):
2354 """parse and apply a revision specification
2354 """parse and apply a revision specification
2355
2355
2356 Use --verbose to print the parsed tree before and after aliases
2356 Use --verbose to print the parsed tree before and after aliases
2357 expansion.
2357 expansion.
2358 """
2358 """
2359 if ui.verbose:
2359 if ui.verbose:
2360 tree = revset.parse(expr)[0]
2360 tree = revset.parse(expr)[0]
2361 ui.note(revset.prettyformat(tree), "\n")
2361 ui.note(revset.prettyformat(tree), "\n")
2362 newtree = revset.findaliases(ui, tree)
2362 newtree = revset.findaliases(ui, tree)
2363 if newtree != tree:
2363 if newtree != tree:
2364 ui.note(revset.prettyformat(newtree), "\n")
2364 ui.note(revset.prettyformat(newtree), "\n")
2365 func = revset.match(ui, expr)
2365 func = revset.match(ui, expr)
2366 for c in func(repo, range(len(repo))):
2366 for c in func(repo, range(len(repo))):
2367 ui.write("%s\n" % c)
2367 ui.write("%s\n" % c)
2368
2368
2369 @command('debugsetparents', [], _('REV1 [REV2]'))
2369 @command('debugsetparents', [], _('REV1 [REV2]'))
2370 def debugsetparents(ui, repo, rev1, rev2=None):
2370 def debugsetparents(ui, repo, rev1, rev2=None):
2371 """manually set the parents of the current working directory
2371 """manually set the parents of the current working directory
2372
2372
2373 This is useful for writing repository conversion tools, but should
2373 This is useful for writing repository conversion tools, but should
2374 be used with care.
2374 be used with care.
2375
2375
2376 Returns 0 on success.
2376 Returns 0 on success.
2377 """
2377 """
2378
2378
2379 r1 = scmutil.revsingle(repo, rev1).node()
2379 r1 = scmutil.revsingle(repo, rev1).node()
2380 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2380 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2381
2381
2382 wlock = repo.wlock()
2382 wlock = repo.wlock()
2383 try:
2383 try:
2384 repo.setparents(r1, r2)
2384 repo.setparents(r1, r2)
2385 finally:
2385 finally:
2386 wlock.release()
2386 wlock.release()
2387
2387
2388 @command('debugstate',
2388 @command('debugstate',
2389 [('', 'nodates', None, _('do not display the saved mtime')),
2389 [('', 'nodates', None, _('do not display the saved mtime')),
2390 ('', 'datesort', None, _('sort by saved mtime'))],
2390 ('', 'datesort', None, _('sort by saved mtime'))],
2391 _('[OPTION]...'))
2391 _('[OPTION]...'))
2392 def debugstate(ui, repo, nodates=None, datesort=None):
2392 def debugstate(ui, repo, nodates=None, datesort=None):
2393 """show the contents of the current dirstate"""
2393 """show the contents of the current dirstate"""
2394 timestr = ""
2394 timestr = ""
2395 showdate = not nodates
2395 showdate = not nodates
2396 if datesort:
2396 if datesort:
2397 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2397 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2398 else:
2398 else:
2399 keyfunc = None # sort by filename
2399 keyfunc = None # sort by filename
2400 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2400 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2401 if showdate:
2401 if showdate:
2402 if ent[3] == -1:
2402 if ent[3] == -1:
2403 # Pad or slice to locale representation
2403 # Pad or slice to locale representation
2404 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2404 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2405 time.localtime(0)))
2405 time.localtime(0)))
2406 timestr = 'unset'
2406 timestr = 'unset'
2407 timestr = (timestr[:locale_len] +
2407 timestr = (timestr[:locale_len] +
2408 ' ' * (locale_len - len(timestr)))
2408 ' ' * (locale_len - len(timestr)))
2409 else:
2409 else:
2410 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2410 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2411 time.localtime(ent[3]))
2411 time.localtime(ent[3]))
2412 if ent[1] & 020000:
2412 if ent[1] & 020000:
2413 mode = 'lnk'
2413 mode = 'lnk'
2414 else:
2414 else:
2415 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2415 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2416 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2416 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2417 for f in repo.dirstate.copies():
2417 for f in repo.dirstate.copies():
2418 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2418 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2419
2419
2420 @command('debugsub',
2420 @command('debugsub',
2421 [('r', 'rev', '',
2421 [('r', 'rev', '',
2422 _('revision to check'), _('REV'))],
2422 _('revision to check'), _('REV'))],
2423 _('[-r REV] [REV]'))
2423 _('[-r REV] [REV]'))
2424 def debugsub(ui, repo, rev=None):
2424 def debugsub(ui, repo, rev=None):
2425 ctx = scmutil.revsingle(repo, rev, None)
2425 ctx = scmutil.revsingle(repo, rev, None)
2426 for k, v in sorted(ctx.substate.items()):
2426 for k, v in sorted(ctx.substate.items()):
2427 ui.write('path %s\n' % k)
2427 ui.write('path %s\n' % k)
2428 ui.write(' source %s\n' % v[0])
2428 ui.write(' source %s\n' % v[0])
2429 ui.write(' revision %s\n' % v[1])
2429 ui.write(' revision %s\n' % v[1])
2430
2430
2431 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2431 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2432 def debugwalk(ui, repo, *pats, **opts):
2432 def debugwalk(ui, repo, *pats, **opts):
2433 """show how files match on given patterns"""
2433 """show how files match on given patterns"""
2434 m = scmutil.match(repo[None], pats, opts)
2434 m = scmutil.match(repo[None], pats, opts)
2435 items = list(repo.walk(m))
2435 items = list(repo.walk(m))
2436 if not items:
2436 if not items:
2437 return
2437 return
2438 f = lambda fn: fn
2438 f = lambda fn: fn
2439 if ui.configbool('ui', 'slash') and os.sep != '/':
2439 if ui.configbool('ui', 'slash') and os.sep != '/':
2440 f = lambda fn: util.normpath(fn)
2440 f = lambda fn: util.normpath(fn)
2441 fmt = 'f %%-%ds %%-%ds %%s' % (
2441 fmt = 'f %%-%ds %%-%ds %%s' % (
2442 max([len(abs) for abs in items]),
2442 max([len(abs) for abs in items]),
2443 max([len(m.rel(abs)) for abs in items]))
2443 max([len(m.rel(abs)) for abs in items]))
2444 for abs in items:
2444 for abs in items:
2445 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2445 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2446 ui.write("%s\n" % line.rstrip())
2446 ui.write("%s\n" % line.rstrip())
2447
2447
2448 @command('debugwireargs',
2448 @command('debugwireargs',
2449 [('', 'three', '', 'three'),
2449 [('', 'three', '', 'three'),
2450 ('', 'four', '', 'four'),
2450 ('', 'four', '', 'four'),
2451 ('', 'five', '', 'five'),
2451 ('', 'five', '', 'five'),
2452 ] + remoteopts,
2452 ] + remoteopts,
2453 _('REPO [OPTIONS]... [ONE [TWO]]'))
2453 _('REPO [OPTIONS]... [ONE [TWO]]'))
2454 def debugwireargs(ui, repopath, *vals, **opts):
2454 def debugwireargs(ui, repopath, *vals, **opts):
2455 repo = hg.peer(ui, opts, repopath)
2455 repo = hg.peer(ui, opts, repopath)
2456 for opt in remoteopts:
2456 for opt in remoteopts:
2457 del opts[opt[1]]
2457 del opts[opt[1]]
2458 args = {}
2458 args = {}
2459 for k, v in opts.iteritems():
2459 for k, v in opts.iteritems():
2460 if v:
2460 if v:
2461 args[k] = v
2461 args[k] = v
2462 # run twice to check that we don't mess up the stream for the next command
2462 # run twice to check that we don't mess up the stream for the next command
2463 res1 = repo.debugwireargs(*vals, **args)
2463 res1 = repo.debugwireargs(*vals, **args)
2464 res2 = repo.debugwireargs(*vals, **args)
2464 res2 = repo.debugwireargs(*vals, **args)
2465 ui.write("%s\n" % res1)
2465 ui.write("%s\n" % res1)
2466 if res1 != res2:
2466 if res1 != res2:
2467 ui.warn("%s\n" % res2)
2467 ui.warn("%s\n" % res2)
2468
2468
2469 @command('^diff',
2469 @command('^diff',
2470 [('r', 'rev', [], _('revision'), _('REV')),
2470 [('r', 'rev', [], _('revision'), _('REV')),
2471 ('c', 'change', '', _('change made by revision'), _('REV'))
2471 ('c', 'change', '', _('change made by revision'), _('REV'))
2472 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2472 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2473 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2473 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2474 def diff(ui, repo, *pats, **opts):
2474 def diff(ui, repo, *pats, **opts):
2475 """diff repository (or selected files)
2475 """diff repository (or selected files)
2476
2476
2477 Show differences between revisions for the specified files.
2477 Show differences between revisions for the specified files.
2478
2478
2479 Differences between files are shown using the unified diff format.
2479 Differences between files are shown using the unified diff format.
2480
2480
2481 .. note::
2481 .. note::
2482 diff may generate unexpected results for merges, as it will
2482 diff may generate unexpected results for merges, as it will
2483 default to comparing against the working directory's first
2483 default to comparing against the working directory's first
2484 parent changeset if no revisions are specified.
2484 parent changeset if no revisions are specified.
2485
2485
2486 When two revision arguments are given, then changes are shown
2486 When two revision arguments are given, then changes are shown
2487 between those revisions. If only one revision is specified then
2487 between those revisions. If only one revision is specified then
2488 that revision is compared to the working directory, and, when no
2488 that revision is compared to the working directory, and, when no
2489 revisions are specified, the working directory files are compared
2489 revisions are specified, the working directory files are compared
2490 to its parent.
2490 to its parent.
2491
2491
2492 Alternatively you can specify -c/--change with a revision to see
2492 Alternatively you can specify -c/--change with a revision to see
2493 the changes in that changeset relative to its first parent.
2493 the changes in that changeset relative to its first parent.
2494
2494
2495 Without the -a/--text option, diff will avoid generating diffs of
2495 Without the -a/--text option, diff will avoid generating diffs of
2496 files it detects as binary. With -a, diff will generate a diff
2496 files it detects as binary. With -a, diff will generate a diff
2497 anyway, probably with undesirable results.
2497 anyway, probably with undesirable results.
2498
2498
2499 Use the -g/--git option to generate diffs in the git extended diff
2499 Use the -g/--git option to generate diffs in the git extended diff
2500 format. For more information, read :hg:`help diffs`.
2500 format. For more information, read :hg:`help diffs`.
2501
2501
2502 .. container:: verbose
2502 .. container:: verbose
2503
2503
2504 Examples:
2504 Examples:
2505
2505
2506 - compare a file in the current working directory to its parent::
2506 - compare a file in the current working directory to its parent::
2507
2507
2508 hg diff foo.c
2508 hg diff foo.c
2509
2509
2510 - compare two historical versions of a directory, with rename info::
2510 - compare two historical versions of a directory, with rename info::
2511
2511
2512 hg diff --git -r 1.0:1.2 lib/
2512 hg diff --git -r 1.0:1.2 lib/
2513
2513
2514 - get change stats relative to the last change on some date::
2514 - get change stats relative to the last change on some date::
2515
2515
2516 hg diff --stat -r "date('may 2')"
2516 hg diff --stat -r "date('may 2')"
2517
2517
2518 - diff all newly-added files that contain a keyword::
2518 - diff all newly-added files that contain a keyword::
2519
2519
2520 hg diff "set:added() and grep(GNU)"
2520 hg diff "set:added() and grep(GNU)"
2521
2521
2522 - compare a revision and its parents::
2522 - compare a revision and its parents::
2523
2523
2524 hg diff -c 9353 # compare against first parent
2524 hg diff -c 9353 # compare against first parent
2525 hg diff -r 9353^:9353 # same using revset syntax
2525 hg diff -r 9353^:9353 # same using revset syntax
2526 hg diff -r 9353^2:9353 # compare against the second parent
2526 hg diff -r 9353^2:9353 # compare against the second parent
2527
2527
2528 Returns 0 on success.
2528 Returns 0 on success.
2529 """
2529 """
2530
2530
2531 revs = opts.get('rev')
2531 revs = opts.get('rev')
2532 change = opts.get('change')
2532 change = opts.get('change')
2533 stat = opts.get('stat')
2533 stat = opts.get('stat')
2534 reverse = opts.get('reverse')
2534 reverse = opts.get('reverse')
2535
2535
2536 if revs and change:
2536 if revs and change:
2537 msg = _('cannot specify --rev and --change at the same time')
2537 msg = _('cannot specify --rev and --change at the same time')
2538 raise util.Abort(msg)
2538 raise util.Abort(msg)
2539 elif change:
2539 elif change:
2540 node2 = scmutil.revsingle(repo, change, None).node()
2540 node2 = scmutil.revsingle(repo, change, None).node()
2541 node1 = repo[node2].p1().node()
2541 node1 = repo[node2].p1().node()
2542 else:
2542 else:
2543 node1, node2 = scmutil.revpair(repo, revs)
2543 node1, node2 = scmutil.revpair(repo, revs)
2544
2544
2545 if reverse:
2545 if reverse:
2546 node1, node2 = node2, node1
2546 node1, node2 = node2, node1
2547
2547
2548 diffopts = patch.diffopts(ui, opts)
2548 diffopts = patch.diffopts(ui, opts)
2549 m = scmutil.match(repo[node2], pats, opts)
2549 m = scmutil.match(repo[node2], pats, opts)
2550 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2550 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2551 listsubrepos=opts.get('subrepos'))
2551 listsubrepos=opts.get('subrepos'))
2552
2552
2553 @command('^export',
2553 @command('^export',
2554 [('o', 'output', '',
2554 [('o', 'output', '',
2555 _('print output to file with formatted name'), _('FORMAT')),
2555 _('print output to file with formatted name'), _('FORMAT')),
2556 ('', 'switch-parent', None, _('diff against the second parent')),
2556 ('', 'switch-parent', None, _('diff against the second parent')),
2557 ('r', 'rev', [], _('revisions to export'), _('REV')),
2557 ('r', 'rev', [], _('revisions to export'), _('REV')),
2558 ] + diffopts,
2558 ] + diffopts,
2559 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2559 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2560 def export(ui, repo, *changesets, **opts):
2560 def export(ui, repo, *changesets, **opts):
2561 """dump the header and diffs for one or more changesets
2561 """dump the header and diffs for one or more changesets
2562
2562
2563 Print the changeset header and diffs for one or more revisions.
2563 Print the changeset header and diffs for one or more revisions.
2564
2564
2565 The information shown in the changeset header is: author, date,
2565 The information shown in the changeset header is: author, date,
2566 branch name (if non-default), changeset hash, parent(s) and commit
2566 branch name (if non-default), changeset hash, parent(s) and commit
2567 comment.
2567 comment.
2568
2568
2569 .. note::
2569 .. note::
2570 export may generate unexpected diff output for merge
2570 export may generate unexpected diff output for merge
2571 changesets, as it will compare the merge changeset against its
2571 changesets, as it will compare the merge changeset against its
2572 first parent only.
2572 first parent only.
2573
2573
2574 Output may be to a file, in which case the name of the file is
2574 Output may be to a file, in which case the name of the file is
2575 given using a format string. The formatting rules are as follows:
2575 given using a format string. The formatting rules are as follows:
2576
2576
2577 :``%%``: literal "%" character
2577 :``%%``: literal "%" character
2578 :``%H``: changeset hash (40 hexadecimal digits)
2578 :``%H``: changeset hash (40 hexadecimal digits)
2579 :``%N``: number of patches being generated
2579 :``%N``: number of patches being generated
2580 :``%R``: changeset revision number
2580 :``%R``: changeset revision number
2581 :``%b``: basename of the exporting repository
2581 :``%b``: basename of the exporting repository
2582 :``%h``: short-form changeset hash (12 hexadecimal digits)
2582 :``%h``: short-form changeset hash (12 hexadecimal digits)
2583 :``%m``: first line of the commit message (only alphanumeric characters)
2583 :``%m``: first line of the commit message (only alphanumeric characters)
2584 :``%n``: zero-padded sequence number, starting at 1
2584 :``%n``: zero-padded sequence number, starting at 1
2585 :``%r``: zero-padded changeset revision number
2585 :``%r``: zero-padded changeset revision number
2586
2586
2587 Without the -a/--text option, export will avoid generating diffs
2587 Without the -a/--text option, export will avoid generating diffs
2588 of files it detects as binary. With -a, export will generate a
2588 of files it detects as binary. With -a, export will generate a
2589 diff anyway, probably with undesirable results.
2589 diff anyway, probably with undesirable results.
2590
2590
2591 Use the -g/--git option to generate diffs in the git extended diff
2591 Use the -g/--git option to generate diffs in the git extended diff
2592 format. See :hg:`help diffs` for more information.
2592 format. See :hg:`help diffs` for more information.
2593
2593
2594 With the --switch-parent option, the diff will be against the
2594 With the --switch-parent option, the diff will be against the
2595 second parent. It can be useful to review a merge.
2595 second parent. It can be useful to review a merge.
2596
2596
2597 .. container:: verbose
2597 .. container:: verbose
2598
2598
2599 Examples:
2599 Examples:
2600
2600
2601 - use export and import to transplant a bugfix to the current
2601 - use export and import to transplant a bugfix to the current
2602 branch::
2602 branch::
2603
2603
2604 hg export -r 9353 | hg import -
2604 hg export -r 9353 | hg import -
2605
2605
2606 - export all the changesets between two revisions to a file with
2606 - export all the changesets between two revisions to a file with
2607 rename information::
2607 rename information::
2608
2608
2609 hg export --git -r 123:150 > changes.txt
2609 hg export --git -r 123:150 > changes.txt
2610
2610
2611 - split outgoing changes into a series of patches with
2611 - split outgoing changes into a series of patches with
2612 descriptive names::
2612 descriptive names::
2613
2613
2614 hg export -r "outgoing()" -o "%n-%m.patch"
2614 hg export -r "outgoing()" -o "%n-%m.patch"
2615
2615
2616 Returns 0 on success.
2616 Returns 0 on success.
2617 """
2617 """
2618 changesets += tuple(opts.get('rev', []))
2618 changesets += tuple(opts.get('rev', []))
2619 revs = scmutil.revrange(repo, changesets)
2619 revs = scmutil.revrange(repo, changesets)
2620 if not revs:
2620 if not revs:
2621 raise util.Abort(_("export requires at least one changeset"))
2621 raise util.Abort(_("export requires at least one changeset"))
2622 if len(revs) > 1:
2622 if len(revs) > 1:
2623 ui.note(_('exporting patches:\n'))
2623 ui.note(_('exporting patches:\n'))
2624 else:
2624 else:
2625 ui.note(_('exporting patch:\n'))
2625 ui.note(_('exporting patch:\n'))
2626 cmdutil.export(repo, revs, template=opts.get('output'),
2626 cmdutil.export(repo, revs, template=opts.get('output'),
2627 switch_parent=opts.get('switch_parent'),
2627 switch_parent=opts.get('switch_parent'),
2628 opts=patch.diffopts(ui, opts))
2628 opts=patch.diffopts(ui, opts))
2629
2629
2630 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2630 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2631 def forget(ui, repo, *pats, **opts):
2631 def forget(ui, repo, *pats, **opts):
2632 """forget the specified files on the next commit
2632 """forget the specified files on the next commit
2633
2633
2634 Mark the specified files so they will no longer be tracked
2634 Mark the specified files so they will no longer be tracked
2635 after the next commit.
2635 after the next commit.
2636
2636
2637 This only removes files from the current branch, not from the
2637 This only removes files from the current branch, not from the
2638 entire project history, and it does not delete them from the
2638 entire project history, and it does not delete them from the
2639 working directory.
2639 working directory.
2640
2640
2641 To undo a forget before the next commit, see :hg:`add`.
2641 To undo a forget before the next commit, see :hg:`add`.
2642
2642
2643 .. container:: verbose
2643 .. container:: verbose
2644
2644
2645 Examples:
2645 Examples:
2646
2646
2647 - forget newly-added binary files::
2647 - forget newly-added binary files::
2648
2648
2649 hg forget "set:added() and binary()"
2649 hg forget "set:added() and binary()"
2650
2650
2651 - forget files that would be excluded by .hgignore::
2651 - forget files that would be excluded by .hgignore::
2652
2652
2653 hg forget "set:hgignore()"
2653 hg forget "set:hgignore()"
2654
2654
2655 Returns 0 on success.
2655 Returns 0 on success.
2656 """
2656 """
2657
2657
2658 if not pats:
2658 if not pats:
2659 raise util.Abort(_('no files specified'))
2659 raise util.Abort(_('no files specified'))
2660
2660
2661 m = scmutil.match(repo[None], pats, opts)
2661 m = scmutil.match(repo[None], pats, opts)
2662 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2662 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2663 return rejected and 1 or 0
2663 return rejected and 1 or 0
2664
2664
2665 @command(
2665 @command(
2666 'graft',
2666 'graft',
2667 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2667 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2668 ('c', 'continue', False, _('resume interrupted graft')),
2668 ('c', 'continue', False, _('resume interrupted graft')),
2669 ('e', 'edit', False, _('invoke editor on commit messages')),
2669 ('e', 'edit', False, _('invoke editor on commit messages')),
2670 ('', 'log', None, _('append graft info to log message')),
2670 ('', 'log', None, _('append graft info to log message')),
2671 ('D', 'currentdate', False,
2671 ('D', 'currentdate', False,
2672 _('record the current date as commit date')),
2672 _('record the current date as commit date')),
2673 ('U', 'currentuser', False,
2673 ('U', 'currentuser', False,
2674 _('record the current user as committer'), _('DATE'))]
2674 _('record the current user as committer'), _('DATE'))]
2675 + commitopts2 + mergetoolopts + dryrunopts,
2675 + commitopts2 + mergetoolopts + dryrunopts,
2676 _('[OPTION]... [-r] REV...'))
2676 _('[OPTION]... [-r] REV...'))
2677 def graft(ui, repo, *revs, **opts):
2677 def graft(ui, repo, *revs, **opts):
2678 '''copy changes from other branches onto the current branch
2678 '''copy changes from other branches onto the current branch
2679
2679
2680 This command uses Mercurial's merge logic to copy individual
2680 This command uses Mercurial's merge logic to copy individual
2681 changes from other branches without merging branches in the
2681 changes from other branches without merging branches in the
2682 history graph. This is sometimes known as 'backporting' or
2682 history graph. This is sometimes known as 'backporting' or
2683 'cherry-picking'. By default, graft will copy user, date, and
2683 'cherry-picking'. By default, graft will copy user, date, and
2684 description from the source changesets.
2684 description from the source changesets.
2685
2685
2686 Changesets that are ancestors of the current revision, that have
2686 Changesets that are ancestors of the current revision, that have
2687 already been grafted, or that are merges will be skipped.
2687 already been grafted, or that are merges will be skipped.
2688
2688
2689 If --log is specified, log messages will have a comment appended
2689 If --log is specified, log messages will have a comment appended
2690 of the form::
2690 of the form::
2691
2691
2692 (grafted from CHANGESETHASH)
2692 (grafted from CHANGESETHASH)
2693
2693
2694 If a graft merge results in conflicts, the graft process is
2694 If a graft merge results in conflicts, the graft process is
2695 interrupted so that the current merge can be manually resolved.
2695 interrupted so that the current merge can be manually resolved.
2696 Once all conflicts are addressed, the graft process can be
2696 Once all conflicts are addressed, the graft process can be
2697 continued with the -c/--continue option.
2697 continued with the -c/--continue option.
2698
2698
2699 .. note::
2699 .. note::
2700 The -c/--continue option does not reapply earlier options.
2700 The -c/--continue option does not reapply earlier options.
2701
2701
2702 .. container:: verbose
2702 .. container:: verbose
2703
2703
2704 Examples:
2704 Examples:
2705
2705
2706 - copy a single change to the stable branch and edit its description::
2706 - copy a single change to the stable branch and edit its description::
2707
2707
2708 hg update stable
2708 hg update stable
2709 hg graft --edit 9393
2709 hg graft --edit 9393
2710
2710
2711 - graft a range of changesets with one exception, updating dates::
2711 - graft a range of changesets with one exception, updating dates::
2712
2712
2713 hg graft -D "2085::2093 and not 2091"
2713 hg graft -D "2085::2093 and not 2091"
2714
2714
2715 - continue a graft after resolving conflicts::
2715 - continue a graft after resolving conflicts::
2716
2716
2717 hg graft -c
2717 hg graft -c
2718
2718
2719 - show the source of a grafted changeset::
2719 - show the source of a grafted changeset::
2720
2720
2721 hg log --debug -r tip
2721 hg log --debug -r tip
2722
2722
2723 Returns 0 on successful completion.
2723 Returns 0 on successful completion.
2724 '''
2724 '''
2725
2725
2726 revs = list(revs)
2726 revs = list(revs)
2727 revs.extend(opts['rev'])
2727 revs.extend(opts['rev'])
2728
2728
2729 if not opts.get('user') and opts.get('currentuser'):
2729 if not opts.get('user') and opts.get('currentuser'):
2730 opts['user'] = ui.username()
2730 opts['user'] = ui.username()
2731 if not opts.get('date') and opts.get('currentdate'):
2731 if not opts.get('date') and opts.get('currentdate'):
2732 opts['date'] = "%d %d" % util.makedate()
2732 opts['date'] = "%d %d" % util.makedate()
2733
2733
2734 editor = None
2734 editor = None
2735 if opts.get('edit'):
2735 if opts.get('edit'):
2736 editor = cmdutil.commitforceeditor
2736 editor = cmdutil.commitforceeditor
2737
2737
2738 cont = False
2738 cont = False
2739 if opts['continue']:
2739 if opts['continue']:
2740 cont = True
2740 cont = True
2741 if revs:
2741 if revs:
2742 raise util.Abort(_("can't specify --continue and revisions"))
2742 raise util.Abort(_("can't specify --continue and revisions"))
2743 # read in unfinished revisions
2743 # read in unfinished revisions
2744 try:
2744 try:
2745 nodes = repo.opener.read('graftstate').splitlines()
2745 nodes = repo.opener.read('graftstate').splitlines()
2746 revs = [repo[node].rev() for node in nodes]
2746 revs = [repo[node].rev() for node in nodes]
2747 except IOError, inst:
2747 except IOError, inst:
2748 if inst.errno != errno.ENOENT:
2748 if inst.errno != errno.ENOENT:
2749 raise
2749 raise
2750 raise util.Abort(_("no graft state found, can't continue"))
2750 raise util.Abort(_("no graft state found, can't continue"))
2751 else:
2751 else:
2752 cmdutil.bailifchanged(repo)
2752 cmdutil.bailifchanged(repo)
2753 if not revs:
2753 if not revs:
2754 raise util.Abort(_('no revisions specified'))
2754 raise util.Abort(_('no revisions specified'))
2755 revs = scmutil.revrange(repo, revs)
2755 revs = scmutil.revrange(repo, revs)
2756
2756
2757 # check for merges
2757 # check for merges
2758 for rev in repo.revs('%ld and merge()', revs):
2758 for rev in repo.revs('%ld and merge()', revs):
2759 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2759 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2760 revs.remove(rev)
2760 revs.remove(rev)
2761 if not revs:
2761 if not revs:
2762 return -1
2762 return -1
2763
2763
2764 # check for ancestors of dest branch
2764 # check for ancestors of dest branch
2765 for rev in repo.revs('::. and %ld', revs):
2765 for rev in repo.revs('::. and %ld', revs):
2766 ui.warn(_('skipping ancestor revision %s\n') % rev)
2766 ui.warn(_('skipping ancestor revision %s\n') % rev)
2767 revs.remove(rev)
2767 revs.remove(rev)
2768 if not revs:
2768 if not revs:
2769 return -1
2769 return -1
2770
2770
2771 # analyze revs for earlier grafts
2771 # analyze revs for earlier grafts
2772 ids = {}
2772 ids = {}
2773 for ctx in repo.set("%ld", revs):
2773 for ctx in repo.set("%ld", revs):
2774 ids[ctx.hex()] = ctx.rev()
2774 ids[ctx.hex()] = ctx.rev()
2775 n = ctx.extra().get('source')
2775 n = ctx.extra().get('source')
2776 if n:
2776 if n:
2777 ids[n] = ctx.rev()
2777 ids[n] = ctx.rev()
2778
2778
2779 # check ancestors for earlier grafts
2779 # check ancestors for earlier grafts
2780 ui.debug('scanning for duplicate grafts\n')
2780 ui.debug('scanning for duplicate grafts\n')
2781 for ctx in repo.set("::. - ::%ld", revs):
2781 for ctx in repo.set("::. - ::%ld", revs):
2782 n = ctx.extra().get('source')
2782 n = ctx.extra().get('source')
2783 if n in ids:
2783 if n in ids:
2784 r = repo[n].rev()
2784 r = repo[n].rev()
2785 if r in revs:
2785 if r in revs:
2786 ui.warn(_('skipping already grafted revision %s\n') % r)
2786 ui.warn(_('skipping already grafted revision %s\n') % r)
2787 revs.remove(r)
2787 revs.remove(r)
2788 elif ids[n] in revs:
2788 elif ids[n] in revs:
2789 ui.warn(_('skipping already grafted revision %s '
2789 ui.warn(_('skipping already grafted revision %s '
2790 '(same origin %d)\n') % (ids[n], r))
2790 '(same origin %d)\n') % (ids[n], r))
2791 revs.remove(ids[n])
2791 revs.remove(ids[n])
2792 elif ctx.hex() in ids:
2792 elif ctx.hex() in ids:
2793 r = ids[ctx.hex()]
2793 r = ids[ctx.hex()]
2794 ui.warn(_('skipping already grafted revision %s '
2794 ui.warn(_('skipping already grafted revision %s '
2795 '(was grafted from %d)\n') % (r, ctx.rev()))
2795 '(was grafted from %d)\n') % (r, ctx.rev()))
2796 revs.remove(r)
2796 revs.remove(r)
2797 if not revs:
2797 if not revs:
2798 return -1
2798 return -1
2799
2799
2800 wlock = repo.wlock()
2800 wlock = repo.wlock()
2801 try:
2801 try:
2802 for pos, ctx in enumerate(repo.set("%ld", revs)):
2802 for pos, ctx in enumerate(repo.set("%ld", revs)):
2803 current = repo['.']
2803 current = repo['.']
2804
2804
2805 ui.status(_('grafting revision %s\n') % ctx.rev())
2805 ui.status(_('grafting revision %s\n') % ctx.rev())
2806 if opts.get('dry_run'):
2806 if opts.get('dry_run'):
2807 continue
2807 continue
2808
2808
2809 # we don't merge the first commit when continuing
2809 # we don't merge the first commit when continuing
2810 if not cont:
2810 if not cont:
2811 # perform the graft merge with p1(rev) as 'ancestor'
2811 # perform the graft merge with p1(rev) as 'ancestor'
2812 try:
2812 try:
2813 # ui.forcemerge is an internal variable, do not document
2813 # ui.forcemerge is an internal variable, do not document
2814 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2814 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2815 stats = mergemod.update(repo, ctx.node(), True, True, False,
2815 stats = mergemod.update(repo, ctx.node(), True, True, False,
2816 ctx.p1().node())
2816 ctx.p1().node())
2817 finally:
2817 finally:
2818 repo.ui.setconfig('ui', 'forcemerge', '')
2818 repo.ui.setconfig('ui', 'forcemerge', '')
2819 # report any conflicts
2819 # report any conflicts
2820 if stats and stats[3] > 0:
2820 if stats and stats[3] > 0:
2821 # write out state for --continue
2821 # write out state for --continue
2822 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2822 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2823 repo.opener.write('graftstate', ''.join(nodelines))
2823 repo.opener.write('graftstate', ''.join(nodelines))
2824 raise util.Abort(
2824 raise util.Abort(
2825 _("unresolved conflicts, can't continue"),
2825 _("unresolved conflicts, can't continue"),
2826 hint=_('use hg resolve and hg graft --continue'))
2826 hint=_('use hg resolve and hg graft --continue'))
2827 else:
2827 else:
2828 cont = False
2828 cont = False
2829
2829
2830 # drop the second merge parent
2830 # drop the second merge parent
2831 repo.setparents(current.node(), nullid)
2831 repo.setparents(current.node(), nullid)
2832 repo.dirstate.write()
2832 repo.dirstate.write()
2833 # fix up dirstate for copies and renames
2833 # fix up dirstate for copies and renames
2834 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2834 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2835
2835
2836 # commit
2836 # commit
2837 source = ctx.extra().get('source')
2837 source = ctx.extra().get('source')
2838 if not source:
2838 if not source:
2839 source = ctx.hex()
2839 source = ctx.hex()
2840 extra = {'source': source}
2840 extra = {'source': source}
2841 user = ctx.user()
2841 user = ctx.user()
2842 if opts.get('user'):
2842 if opts.get('user'):
2843 user = opts['user']
2843 user = opts['user']
2844 date = ctx.date()
2844 date = ctx.date()
2845 if opts.get('date'):
2845 if opts.get('date'):
2846 date = opts['date']
2846 date = opts['date']
2847 message = ctx.description()
2847 message = ctx.description()
2848 if opts.get('log'):
2848 if opts.get('log'):
2849 message += '\n(grafted from %s)' % ctx.hex()
2849 message += '\n(grafted from %s)' % ctx.hex()
2850 node = repo.commit(text=message, user=user,
2850 node = repo.commit(text=message, user=user,
2851 date=date, extra=extra, editor=editor)
2851 date=date, extra=extra, editor=editor)
2852 if node is None:
2852 if node is None:
2853 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2853 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2854 finally:
2854 finally:
2855 wlock.release()
2855 wlock.release()
2856
2856
2857 # remove state when we complete successfully
2857 # remove state when we complete successfully
2858 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2858 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2859 util.unlinkpath(repo.join('graftstate'))
2859 util.unlinkpath(repo.join('graftstate'))
2860
2860
2861 return 0
2861 return 0
2862
2862
2863 @command('grep',
2863 @command('grep',
2864 [('0', 'print0', None, _('end fields with NUL')),
2864 [('0', 'print0', None, _('end fields with NUL')),
2865 ('', 'all', None, _('print all revisions that match')),
2865 ('', 'all', None, _('print all revisions that match')),
2866 ('a', 'text', None, _('treat all files as text')),
2866 ('a', 'text', None, _('treat all files as text')),
2867 ('f', 'follow', None,
2867 ('f', 'follow', None,
2868 _('follow changeset history,'
2868 _('follow changeset history,'
2869 ' or file history across copies and renames')),
2869 ' or file history across copies and renames')),
2870 ('i', 'ignore-case', None, _('ignore case when matching')),
2870 ('i', 'ignore-case', None, _('ignore case when matching')),
2871 ('l', 'files-with-matches', None,
2871 ('l', 'files-with-matches', None,
2872 _('print only filenames and revisions that match')),
2872 _('print only filenames and revisions that match')),
2873 ('n', 'line-number', None, _('print matching line numbers')),
2873 ('n', 'line-number', None, _('print matching line numbers')),
2874 ('r', 'rev', [],
2874 ('r', 'rev', [],
2875 _('only search files changed within revision range'), _('REV')),
2875 _('only search files changed within revision range'), _('REV')),
2876 ('u', 'user', None, _('list the author (long with -v)')),
2876 ('u', 'user', None, _('list the author (long with -v)')),
2877 ('d', 'date', None, _('list the date (short with -q)')),
2877 ('d', 'date', None, _('list the date (short with -q)')),
2878 ] + walkopts,
2878 ] + walkopts,
2879 _('[OPTION]... PATTERN [FILE]...'))
2879 _('[OPTION]... PATTERN [FILE]...'))
2880 def grep(ui, repo, pattern, *pats, **opts):
2880 def grep(ui, repo, pattern, *pats, **opts):
2881 """search for a pattern in specified files and revisions
2881 """search for a pattern in specified files and revisions
2882
2882
2883 Search revisions of files for a regular expression.
2883 Search revisions of files for a regular expression.
2884
2884
2885 This command behaves differently than Unix grep. It only accepts
2885 This command behaves differently than Unix grep. It only accepts
2886 Python/Perl regexps. It searches repository history, not the
2886 Python/Perl regexps. It searches repository history, not the
2887 working directory. It always prints the revision number in which a
2887 working directory. It always prints the revision number in which a
2888 match appears.
2888 match appears.
2889
2889
2890 By default, grep only prints output for the first revision of a
2890 By default, grep only prints output for the first revision of a
2891 file in which it finds a match. To get it to print every revision
2891 file in which it finds a match. To get it to print every revision
2892 that contains a change in match status ("-" for a match that
2892 that contains a change in match status ("-" for a match that
2893 becomes a non-match, or "+" for a non-match that becomes a match),
2893 becomes a non-match, or "+" for a non-match that becomes a match),
2894 use the --all flag.
2894 use the --all flag.
2895
2895
2896 Returns 0 if a match is found, 1 otherwise.
2896 Returns 0 if a match is found, 1 otherwise.
2897 """
2897 """
2898 reflags = re.M
2898 reflags = re.M
2899 if opts.get('ignore_case'):
2899 if opts.get('ignore_case'):
2900 reflags |= re.I
2900 reflags |= re.I
2901 try:
2901 try:
2902 regexp = re.compile(pattern, reflags)
2902 regexp = re.compile(pattern, reflags)
2903 except re.error, inst:
2903 except re.error, inst:
2904 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2904 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2905 return 1
2905 return 1
2906 sep, eol = ':', '\n'
2906 sep, eol = ':', '\n'
2907 if opts.get('print0'):
2907 if opts.get('print0'):
2908 sep = eol = '\0'
2908 sep = eol = '\0'
2909
2909
2910 getfile = util.lrucachefunc(repo.file)
2910 getfile = util.lrucachefunc(repo.file)
2911
2911
2912 def matchlines(body):
2912 def matchlines(body):
2913 begin = 0
2913 begin = 0
2914 linenum = 0
2914 linenum = 0
2915 while True:
2915 while True:
2916 match = regexp.search(body, begin)
2916 match = regexp.search(body, begin)
2917 if not match:
2917 if not match:
2918 break
2918 break
2919 mstart, mend = match.span()
2919 mstart, mend = match.span()
2920 linenum += body.count('\n', begin, mstart) + 1
2920 linenum += body.count('\n', begin, mstart) + 1
2921 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2921 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2922 begin = body.find('\n', mend) + 1 or len(body) + 1
2922 begin = body.find('\n', mend) + 1 or len(body) + 1
2923 lend = begin - 1
2923 lend = begin - 1
2924 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2924 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2925
2925
2926 class linestate(object):
2926 class linestate(object):
2927 def __init__(self, line, linenum, colstart, colend):
2927 def __init__(self, line, linenum, colstart, colend):
2928 self.line = line
2928 self.line = line
2929 self.linenum = linenum
2929 self.linenum = linenum
2930 self.colstart = colstart
2930 self.colstart = colstart
2931 self.colend = colend
2931 self.colend = colend
2932
2932
2933 def __hash__(self):
2933 def __hash__(self):
2934 return hash((self.linenum, self.line))
2934 return hash((self.linenum, self.line))
2935
2935
2936 def __eq__(self, other):
2936 def __eq__(self, other):
2937 return self.line == other.line
2937 return self.line == other.line
2938
2938
2939 matches = {}
2939 matches = {}
2940 copies = {}
2940 copies = {}
2941 def grepbody(fn, rev, body):
2941 def grepbody(fn, rev, body):
2942 matches[rev].setdefault(fn, [])
2942 matches[rev].setdefault(fn, [])
2943 m = matches[rev][fn]
2943 m = matches[rev][fn]
2944 for lnum, cstart, cend, line in matchlines(body):
2944 for lnum, cstart, cend, line in matchlines(body):
2945 s = linestate(line, lnum, cstart, cend)
2945 s = linestate(line, lnum, cstart, cend)
2946 m.append(s)
2946 m.append(s)
2947
2947
2948 def difflinestates(a, b):
2948 def difflinestates(a, b):
2949 sm = difflib.SequenceMatcher(None, a, b)
2949 sm = difflib.SequenceMatcher(None, a, b)
2950 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2950 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2951 if tag == 'insert':
2951 if tag == 'insert':
2952 for i in xrange(blo, bhi):
2952 for i in xrange(blo, bhi):
2953 yield ('+', b[i])
2953 yield ('+', b[i])
2954 elif tag == 'delete':
2954 elif tag == 'delete':
2955 for i in xrange(alo, ahi):
2955 for i in xrange(alo, ahi):
2956 yield ('-', a[i])
2956 yield ('-', a[i])
2957 elif tag == 'replace':
2957 elif tag == 'replace':
2958 for i in xrange(alo, ahi):
2958 for i in xrange(alo, ahi):
2959 yield ('-', a[i])
2959 yield ('-', a[i])
2960 for i in xrange(blo, bhi):
2960 for i in xrange(blo, bhi):
2961 yield ('+', b[i])
2961 yield ('+', b[i])
2962
2962
2963 def display(fn, ctx, pstates, states):
2963 def display(fn, ctx, pstates, states):
2964 rev = ctx.rev()
2964 rev = ctx.rev()
2965 datefunc = ui.quiet and util.shortdate or util.datestr
2965 datefunc = ui.quiet and util.shortdate or util.datestr
2966 found = False
2966 found = False
2967 filerevmatches = {}
2967 filerevmatches = {}
2968 def binary():
2968 def binary():
2969 flog = getfile(fn)
2969 flog = getfile(fn)
2970 return util.binary(flog.read(ctx.filenode(fn)))
2970 return util.binary(flog.read(ctx.filenode(fn)))
2971
2971
2972 if opts.get('all'):
2972 if opts.get('all'):
2973 iter = difflinestates(pstates, states)
2973 iter = difflinestates(pstates, states)
2974 else:
2974 else:
2975 iter = [('', l) for l in states]
2975 iter = [('', l) for l in states]
2976 for change, l in iter:
2976 for change, l in iter:
2977 cols = [fn, str(rev)]
2977 cols = [fn, str(rev)]
2978 before, match, after = None, None, None
2978 before, match, after = None, None, None
2979 if opts.get('line_number'):
2979 if opts.get('line_number'):
2980 cols.append(str(l.linenum))
2980 cols.append(str(l.linenum))
2981 if opts.get('all'):
2981 if opts.get('all'):
2982 cols.append(change)
2982 cols.append(change)
2983 if opts.get('user'):
2983 if opts.get('user'):
2984 cols.append(ui.shortuser(ctx.user()))
2984 cols.append(ui.shortuser(ctx.user()))
2985 if opts.get('date'):
2985 if opts.get('date'):
2986 cols.append(datefunc(ctx.date()))
2986 cols.append(datefunc(ctx.date()))
2987 if opts.get('files_with_matches'):
2987 if opts.get('files_with_matches'):
2988 c = (fn, rev)
2988 c = (fn, rev)
2989 if c in filerevmatches:
2989 if c in filerevmatches:
2990 continue
2990 continue
2991 filerevmatches[c] = 1
2991 filerevmatches[c] = 1
2992 else:
2992 else:
2993 before = l.line[:l.colstart]
2993 before = l.line[:l.colstart]
2994 match = l.line[l.colstart:l.colend]
2994 match = l.line[l.colstart:l.colend]
2995 after = l.line[l.colend:]
2995 after = l.line[l.colend:]
2996 ui.write(sep.join(cols))
2996 ui.write(sep.join(cols))
2997 if before is not None:
2997 if before is not None:
2998 if not opts.get('text') and binary():
2998 if not opts.get('text') and binary():
2999 ui.write(sep + " Binary file matches")
2999 ui.write(sep + " Binary file matches")
3000 else:
3000 else:
3001 ui.write(sep + before)
3001 ui.write(sep + before)
3002 ui.write(match, label='grep.match')
3002 ui.write(match, label='grep.match')
3003 ui.write(after)
3003 ui.write(after)
3004 ui.write(eol)
3004 ui.write(eol)
3005 found = True
3005 found = True
3006 return found
3006 return found
3007
3007
3008 skip = {}
3008 skip = {}
3009 revfiles = {}
3009 revfiles = {}
3010 matchfn = scmutil.match(repo[None], pats, opts)
3010 matchfn = scmutil.match(repo[None], pats, opts)
3011 found = False
3011 found = False
3012 follow = opts.get('follow')
3012 follow = opts.get('follow')
3013
3013
3014 def prep(ctx, fns):
3014 def prep(ctx, fns):
3015 rev = ctx.rev()
3015 rev = ctx.rev()
3016 pctx = ctx.p1()
3016 pctx = ctx.p1()
3017 parent = pctx.rev()
3017 parent = pctx.rev()
3018 matches.setdefault(rev, {})
3018 matches.setdefault(rev, {})
3019 matches.setdefault(parent, {})
3019 matches.setdefault(parent, {})
3020 files = revfiles.setdefault(rev, [])
3020 files = revfiles.setdefault(rev, [])
3021 for fn in fns:
3021 for fn in fns:
3022 flog = getfile(fn)
3022 flog = getfile(fn)
3023 try:
3023 try:
3024 fnode = ctx.filenode(fn)
3024 fnode = ctx.filenode(fn)
3025 except error.LookupError:
3025 except error.LookupError:
3026 continue
3026 continue
3027
3027
3028 copied = flog.renamed(fnode)
3028 copied = flog.renamed(fnode)
3029 copy = follow and copied and copied[0]
3029 copy = follow and copied and copied[0]
3030 if copy:
3030 if copy:
3031 copies.setdefault(rev, {})[fn] = copy
3031 copies.setdefault(rev, {})[fn] = copy
3032 if fn in skip:
3032 if fn in skip:
3033 if copy:
3033 if copy:
3034 skip[copy] = True
3034 skip[copy] = True
3035 continue
3035 continue
3036 files.append(fn)
3036 files.append(fn)
3037
3037
3038 if fn not in matches[rev]:
3038 if fn not in matches[rev]:
3039 grepbody(fn, rev, flog.read(fnode))
3039 grepbody(fn, rev, flog.read(fnode))
3040
3040
3041 pfn = copy or fn
3041 pfn = copy or fn
3042 if pfn not in matches[parent]:
3042 if pfn not in matches[parent]:
3043 try:
3043 try:
3044 fnode = pctx.filenode(pfn)
3044 fnode = pctx.filenode(pfn)
3045 grepbody(pfn, parent, flog.read(fnode))
3045 grepbody(pfn, parent, flog.read(fnode))
3046 except error.LookupError:
3046 except error.LookupError:
3047 pass
3047 pass
3048
3048
3049 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3049 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3050 rev = ctx.rev()
3050 rev = ctx.rev()
3051 parent = ctx.p1().rev()
3051 parent = ctx.p1().rev()
3052 for fn in sorted(revfiles.get(rev, [])):
3052 for fn in sorted(revfiles.get(rev, [])):
3053 states = matches[rev][fn]
3053 states = matches[rev][fn]
3054 copy = copies.get(rev, {}).get(fn)
3054 copy = copies.get(rev, {}).get(fn)
3055 if fn in skip:
3055 if fn in skip:
3056 if copy:
3056 if copy:
3057 skip[copy] = True
3057 skip[copy] = True
3058 continue
3058 continue
3059 pstates = matches.get(parent, {}).get(copy or fn, [])
3059 pstates = matches.get(parent, {}).get(copy or fn, [])
3060 if pstates or states:
3060 if pstates or states:
3061 r = display(fn, ctx, pstates, states)
3061 r = display(fn, ctx, pstates, states)
3062 found = found or r
3062 found = found or r
3063 if r and not opts.get('all'):
3063 if r and not opts.get('all'):
3064 skip[fn] = True
3064 skip[fn] = True
3065 if copy:
3065 if copy:
3066 skip[copy] = True
3066 skip[copy] = True
3067 del matches[rev]
3067 del matches[rev]
3068 del revfiles[rev]
3068 del revfiles[rev]
3069
3069
3070 return not found
3070 return not found
3071
3071
3072 @command('heads',
3072 @command('heads',
3073 [('r', 'rev', '',
3073 [('r', 'rev', '',
3074 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3074 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3075 ('t', 'topo', False, _('show topological heads only')),
3075 ('t', 'topo', False, _('show topological heads only')),
3076 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3076 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3077 ('c', 'closed', False, _('show normal and closed branch heads')),
3077 ('c', 'closed', False, _('show normal and closed branch heads')),
3078 ] + templateopts,
3078 ] + templateopts,
3079 _('[-ct] [-r STARTREV] [REV]...'))
3079 _('[-ct] [-r STARTREV] [REV]...'))
3080 def heads(ui, repo, *branchrevs, **opts):
3080 def heads(ui, repo, *branchrevs, **opts):
3081 """show current repository heads or show branch heads
3081 """show current repository heads or show branch heads
3082
3082
3083 With no arguments, show all repository branch heads.
3083 With no arguments, show all repository branch heads.
3084
3084
3085 Repository "heads" are changesets with no child changesets. They are
3085 Repository "heads" are changesets with no child changesets. They are
3086 where development generally takes place and are the usual targets
3086 where development generally takes place and are the usual targets
3087 for update and merge operations. Branch heads are changesets that have
3087 for update and merge operations. Branch heads are changesets that have
3088 no child changeset on the same branch.
3088 no child changeset on the same branch.
3089
3089
3090 If one or more REVs are given, only branch heads on the branches
3090 If one or more REVs are given, only branch heads on the branches
3091 associated with the specified changesets are shown. This means
3091 associated with the specified changesets are shown. This means
3092 that you can use :hg:`heads foo` to see the heads on a branch
3092 that you can use :hg:`heads foo` to see the heads on a branch
3093 named ``foo``.
3093 named ``foo``.
3094
3094
3095 If -c/--closed is specified, also show branch heads marked closed
3095 If -c/--closed is specified, also show branch heads marked closed
3096 (see :hg:`commit --close-branch`).
3096 (see :hg:`commit --close-branch`).
3097
3097
3098 If STARTREV is specified, only those heads that are descendants of
3098 If STARTREV is specified, only those heads that are descendants of
3099 STARTREV will be displayed.
3099 STARTREV will be displayed.
3100
3100
3101 If -t/--topo is specified, named branch mechanics will be ignored and only
3101 If -t/--topo is specified, named branch mechanics will be ignored and only
3102 changesets without children will be shown.
3102 changesets without children will be shown.
3103
3103
3104 Returns 0 if matching heads are found, 1 if not.
3104 Returns 0 if matching heads are found, 1 if not.
3105 """
3105 """
3106
3106
3107 start = None
3107 start = None
3108 if 'rev' in opts:
3108 if 'rev' in opts:
3109 start = scmutil.revsingle(repo, opts['rev'], None).node()
3109 start = scmutil.revsingle(repo, opts['rev'], None).node()
3110
3110
3111 if opts.get('topo'):
3111 if opts.get('topo'):
3112 heads = [repo[h] for h in repo.heads(start)]
3112 heads = [repo[h] for h in repo.heads(start)]
3113 else:
3113 else:
3114 heads = []
3114 heads = []
3115 for branch in repo.branchmap():
3115 for branch in repo.branchmap():
3116 heads += repo.branchheads(branch, start, opts.get('closed'))
3116 heads += repo.branchheads(branch, start, opts.get('closed'))
3117 heads = [repo[h] for h in heads]
3117 heads = [repo[h] for h in heads]
3118
3118
3119 if branchrevs:
3119 if branchrevs:
3120 branches = set(repo[br].branch() for br in branchrevs)
3120 branches = set(repo[br].branch() for br in branchrevs)
3121 heads = [h for h in heads if h.branch() in branches]
3121 heads = [h for h in heads if h.branch() in branches]
3122
3122
3123 if opts.get('active') and branchrevs:
3123 if opts.get('active') and branchrevs:
3124 dagheads = repo.heads(start)
3124 dagheads = repo.heads(start)
3125 heads = [h for h in heads if h.node() in dagheads]
3125 heads = [h for h in heads if h.node() in dagheads]
3126
3126
3127 if branchrevs:
3127 if branchrevs:
3128 haveheads = set(h.branch() for h in heads)
3128 haveheads = set(h.branch() for h in heads)
3129 if branches - haveheads:
3129 if branches - haveheads:
3130 headless = ', '.join(b for b in branches - haveheads)
3130 headless = ', '.join(b for b in branches - haveheads)
3131 msg = _('no open branch heads found on branches %s')
3131 msg = _('no open branch heads found on branches %s')
3132 if opts.get('rev'):
3132 if opts.get('rev'):
3133 msg += _(' (started at %s)') % opts['rev']
3133 msg += _(' (started at %s)') % opts['rev']
3134 ui.warn((msg + '\n') % headless)
3134 ui.warn((msg + '\n') % headless)
3135
3135
3136 if not heads:
3136 if not heads:
3137 return 1
3137 return 1
3138
3138
3139 heads = sorted(heads, key=lambda x: -x.rev())
3139 heads = sorted(heads, key=lambda x: -x.rev())
3140 displayer = cmdutil.show_changeset(ui, repo, opts)
3140 displayer = cmdutil.show_changeset(ui, repo, opts)
3141 for ctx in heads:
3141 for ctx in heads:
3142 displayer.show(ctx)
3142 displayer.show(ctx)
3143 displayer.close()
3143 displayer.close()
3144
3144
3145 @command('help',
3145 @command('help',
3146 [('e', 'extension', None, _('show only help for extensions')),
3146 [('e', 'extension', None, _('show only help for extensions')),
3147 ('c', 'command', None, _('show only help for commands')),
3147 ('c', 'command', None, _('show only help for commands')),
3148 ('k', 'keyword', '', _('show topics matching keyword')),
3148 ('k', 'keyword', '', _('show topics matching keyword')),
3149 ],
3149 ],
3150 _('[-ec] [TOPIC]'))
3150 _('[-ec] [TOPIC]'))
3151 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3151 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3152 """show help for a given topic or a help overview
3152 """show help for a given topic or a help overview
3153
3153
3154 With no arguments, print a list of commands with short help messages.
3154 With no arguments, print a list of commands with short help messages.
3155
3155
3156 Given a topic, extension, or command name, print help for that
3156 Given a topic, extension, or command name, print help for that
3157 topic.
3157 topic.
3158
3158
3159 Returns 0 if successful.
3159 Returns 0 if successful.
3160 """
3160 """
3161
3161
3162 textwidth = min(ui.termwidth(), 80) - 2
3162 textwidth = min(ui.termwidth(), 80) - 2
3163
3163
3164 def helpcmd(name):
3164 def helpcmd(name):
3165 try:
3165 try:
3166 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3166 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3167 except error.AmbiguousCommand, inst:
3167 except error.AmbiguousCommand, inst:
3168 # py3k fix: except vars can't be used outside the scope of the
3168 # py3k fix: except vars can't be used outside the scope of the
3169 # except block, nor can be used inside a lambda. python issue4617
3169 # except block, nor can be used inside a lambda. python issue4617
3170 prefix = inst.args[0]
3170 prefix = inst.args[0]
3171 select = lambda c: c.lstrip('^').startswith(prefix)
3171 select = lambda c: c.lstrip('^').startswith(prefix)
3172 rst = helplist(select)
3172 rst = helplist(select)
3173 return rst
3173 return rst
3174
3174
3175 rst = []
3175 rst = []
3176
3176
3177 # check if it's an invalid alias and display its error if it is
3177 # check if it's an invalid alias and display its error if it is
3178 if getattr(entry[0], 'badalias', False):
3178 if getattr(entry[0], 'badalias', False):
3179 if not unknowncmd:
3179 if not unknowncmd:
3180 ui.pushbuffer()
3180 ui.pushbuffer()
3181 entry[0](ui)
3181 entry[0](ui)
3182 rst.append(ui.popbuffer())
3182 rst.append(ui.popbuffer())
3183 return rst
3183 return rst
3184
3184
3185 # synopsis
3185 # synopsis
3186 if len(entry) > 2:
3186 if len(entry) > 2:
3187 if entry[2].startswith('hg'):
3187 if entry[2].startswith('hg'):
3188 rst.append("%s\n" % entry[2])
3188 rst.append("%s\n" % entry[2])
3189 else:
3189 else:
3190 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3190 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3191 else:
3191 else:
3192 rst.append('hg %s\n' % aliases[0])
3192 rst.append('hg %s\n' % aliases[0])
3193 # aliases
3193 # aliases
3194 if full and not ui.quiet and len(aliases) > 1:
3194 if full and not ui.quiet and len(aliases) > 1:
3195 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3195 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3196 rst.append('\n')
3196 rst.append('\n')
3197
3197
3198 # description
3198 # description
3199 doc = gettext(entry[0].__doc__)
3199 doc = gettext(entry[0].__doc__)
3200 if not doc:
3200 if not doc:
3201 doc = _("(no help text available)")
3201 doc = _("(no help text available)")
3202 if util.safehasattr(entry[0], 'definition'): # aliased command
3202 if util.safehasattr(entry[0], 'definition'): # aliased command
3203 if entry[0].definition.startswith('!'): # shell alias
3203 if entry[0].definition.startswith('!'): # shell alias
3204 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3204 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3205 else:
3205 else:
3206 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3206 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3207 doc = doc.splitlines(True)
3207 doc = doc.splitlines(True)
3208 if ui.quiet or not full:
3208 if ui.quiet or not full:
3209 rst.append(doc[0])
3209 rst.append(doc[0])
3210 else:
3210 else:
3211 rst.extend(doc)
3211 rst.extend(doc)
3212 rst.append('\n')
3212 rst.append('\n')
3213
3213
3214 # check if this command shadows a non-trivial (multi-line)
3214 # check if this command shadows a non-trivial (multi-line)
3215 # extension help text
3215 # extension help text
3216 try:
3216 try:
3217 mod = extensions.find(name)
3217 mod = extensions.find(name)
3218 doc = gettext(mod.__doc__) or ''
3218 doc = gettext(mod.__doc__) or ''
3219 if '\n' in doc.strip():
3219 if '\n' in doc.strip():
3220 msg = _('use "hg help -e %s" to show help for '
3220 msg = _('use "hg help -e %s" to show help for '
3221 'the %s extension') % (name, name)
3221 'the %s extension') % (name, name)
3222 rst.append('\n%s\n' % msg)
3222 rst.append('\n%s\n' % msg)
3223 except KeyError:
3223 except KeyError:
3224 pass
3224 pass
3225
3225
3226 # options
3226 # options
3227 if not ui.quiet and entry[1]:
3227 if not ui.quiet and entry[1]:
3228 rst.append('\n%s\n\n' % _("options:"))
3228 rst.append('\n%s\n\n' % _("options:"))
3229 rst.append(help.optrst(entry[1], ui.verbose))
3229 rst.append(help.optrst(entry[1], ui.verbose))
3230
3230
3231 if ui.verbose:
3231 if ui.verbose:
3232 rst.append('\n%s\n\n' % _("global options:"))
3232 rst.append('\n%s\n\n' % _("global options:"))
3233 rst.append(help.optrst(globalopts, ui.verbose))
3233 rst.append(help.optrst(globalopts, ui.verbose))
3234
3234
3235 if not ui.verbose:
3235 if not ui.verbose:
3236 if not full:
3236 if not full:
3237 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3237 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3238 % name)
3238 % name)
3239 elif not ui.quiet:
3239 elif not ui.quiet:
3240 rst.append(_('\nuse "hg -v help %s" to show more info\n')
3240 rst.append(_('\nuse "hg -v help %s" to show more info\n')
3241 % name)
3241 % name)
3242 return rst
3242 return rst
3243
3243
3244
3244
3245 def helplist(select=None):
3245 def helplist(select=None):
3246 # list of commands
3246 # list of commands
3247 if name == "shortlist":
3247 if name == "shortlist":
3248 header = _('basic commands:\n\n')
3248 header = _('basic commands:\n\n')
3249 else:
3249 else:
3250 header = _('list of commands:\n\n')
3250 header = _('list of commands:\n\n')
3251
3251
3252 h = {}
3252 h = {}
3253 cmds = {}
3253 cmds = {}
3254 for c, e in table.iteritems():
3254 for c, e in table.iteritems():
3255 f = c.split("|", 1)[0]
3255 f = c.split("|", 1)[0]
3256 if select and not select(f):
3256 if select and not select(f):
3257 continue
3257 continue
3258 if (not select and name != 'shortlist' and
3258 if (not select and name != 'shortlist' and
3259 e[0].__module__ != __name__):
3259 e[0].__module__ != __name__):
3260 continue
3260 continue
3261 if name == "shortlist" and not f.startswith("^"):
3261 if name == "shortlist" and not f.startswith("^"):
3262 continue
3262 continue
3263 f = f.lstrip("^")
3263 f = f.lstrip("^")
3264 if not ui.debugflag and f.startswith("debug"):
3264 if not ui.debugflag and f.startswith("debug"):
3265 continue
3265 continue
3266 doc = e[0].__doc__
3266 doc = e[0].__doc__
3267 if doc and 'DEPRECATED' in doc and not ui.verbose:
3267 if doc and 'DEPRECATED' in doc and not ui.verbose:
3268 continue
3268 continue
3269 doc = gettext(doc)
3269 doc = gettext(doc)
3270 if not doc:
3270 if not doc:
3271 doc = _("(no help text available)")
3271 doc = _("(no help text available)")
3272 h[f] = doc.splitlines()[0].rstrip()
3272 h[f] = doc.splitlines()[0].rstrip()
3273 cmds[f] = c.lstrip("^")
3273 cmds[f] = c.lstrip("^")
3274
3274
3275 rst = []
3275 rst = []
3276 if not h:
3276 if not h:
3277 if not ui.quiet:
3277 if not ui.quiet:
3278 rst.append(_('no commands defined\n'))
3278 rst.append(_('no commands defined\n'))
3279 return rst
3279 return rst
3280
3280
3281 if not ui.quiet:
3281 if not ui.quiet:
3282 rst.append(header)
3282 rst.append(header)
3283 fns = sorted(h)
3283 fns = sorted(h)
3284 for f in fns:
3284 for f in fns:
3285 if ui.verbose:
3285 if ui.verbose:
3286 commands = cmds[f].replace("|",", ")
3286 commands = cmds[f].replace("|",", ")
3287 rst.append(" :%s: %s\n" % (commands, h[f]))
3287 rst.append(" :%s: %s\n" % (commands, h[f]))
3288 else:
3288 else:
3289 rst.append(' :%s: %s\n' % (f, h[f]))
3289 rst.append(' :%s: %s\n' % (f, h[f]))
3290
3290
3291 if not name:
3291 if not name:
3292 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3292 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3293 if exts:
3293 if exts:
3294 rst.append('\n')
3294 rst.append('\n')
3295 rst.extend(exts)
3295 rst.extend(exts)
3296
3296
3297 rst.append(_("\nadditional help topics:\n\n"))
3297 rst.append(_("\nadditional help topics:\n\n"))
3298 topics = []
3298 topics = []
3299 for names, header, doc in help.helptable:
3299 for names, header, doc in help.helptable:
3300 topics.append((sorted(names, key=len, reverse=True)[0], header))
3300 topics.append((names[0], header))
3301 for t, desc in topics:
3301 for t, desc in topics:
3302 rst.append(" :%s: %s\n" % (t, desc))
3302 rst.append(" :%s: %s\n" % (t, desc))
3303
3303
3304 optlist = []
3304 optlist = []
3305 if not ui.quiet:
3305 if not ui.quiet:
3306 if ui.verbose:
3306 if ui.verbose:
3307 optlist.append((_("global options:"), globalopts))
3307 optlist.append((_("global options:"), globalopts))
3308 if name == 'shortlist':
3308 if name == 'shortlist':
3309 optlist.append((_('use "hg help" for the full list '
3309 optlist.append((_('use "hg help" for the full list '
3310 'of commands'), ()))
3310 'of commands'), ()))
3311 else:
3311 else:
3312 if name == 'shortlist':
3312 if name == 'shortlist':
3313 msg = _('use "hg help" for the full list of commands '
3313 msg = _('use "hg help" for the full list of commands '
3314 'or "hg -v" for details')
3314 'or "hg -v" for details')
3315 elif name and not full:
3315 elif name and not full:
3316 msg = _('use "hg help %s" to show the full help '
3316 msg = _('use "hg help %s" to show the full help '
3317 'text') % name
3317 'text') % name
3318 else:
3318 else:
3319 msg = _('use "hg -v help%s" to show builtin aliases and '
3319 msg = _('use "hg -v help%s" to show builtin aliases and '
3320 'global options') % (name and " " + name or "")
3320 'global options') % (name and " " + name or "")
3321 optlist.append((msg, ()))
3321 optlist.append((msg, ()))
3322
3322
3323 if optlist:
3323 if optlist:
3324 for title, options in optlist:
3324 for title, options in optlist:
3325 rst.append('\n%s\n' % title)
3325 rst.append('\n%s\n' % title)
3326 if options:
3326 if options:
3327 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3327 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3328 return rst
3328 return rst
3329
3329
3330 def helptopic(name):
3330 def helptopic(name):
3331 for names, header, doc in help.helptable:
3331 for names, header, doc in help.helptable:
3332 if name in names:
3332 if name in names:
3333 break
3333 break
3334 else:
3334 else:
3335 raise error.UnknownCommand(name)
3335 raise error.UnknownCommand(name)
3336
3336
3337 rst = ["%s\n\n" % header]
3337 rst = ["%s\n\n" % header]
3338 # description
3338 # description
3339 if not doc:
3339 if not doc:
3340 rst.append(" %s\n" % _("(no help text available)"))
3340 rst.append(" %s\n" % _("(no help text available)"))
3341 if util.safehasattr(doc, '__call__'):
3341 if util.safehasattr(doc, '__call__'):
3342 rst += [" %s\n" % l for l in doc().splitlines()]
3342 rst += [" %s\n" % l for l in doc().splitlines()]
3343
3343
3344 try:
3344 try:
3345 cmdutil.findcmd(name, table)
3345 cmdutil.findcmd(name, table)
3346 rst.append(_('\nuse "hg help -c %s" to see help for '
3346 rst.append(_('\nuse "hg help -c %s" to see help for '
3347 'the %s command\n') % (name, name))
3347 'the %s command\n') % (name, name))
3348 except error.UnknownCommand:
3348 except error.UnknownCommand:
3349 pass
3349 pass
3350 return rst
3350 return rst
3351
3351
3352 def helpext(name):
3352 def helpext(name):
3353 try:
3353 try:
3354 mod = extensions.find(name)
3354 mod = extensions.find(name)
3355 doc = gettext(mod.__doc__) or _('no help text available')
3355 doc = gettext(mod.__doc__) or _('no help text available')
3356 except KeyError:
3356 except KeyError:
3357 mod = None
3357 mod = None
3358 doc = extensions.disabledext(name)
3358 doc = extensions.disabledext(name)
3359 if not doc:
3359 if not doc:
3360 raise error.UnknownCommand(name)
3360 raise error.UnknownCommand(name)
3361
3361
3362 if '\n' not in doc:
3362 if '\n' not in doc:
3363 head, tail = doc, ""
3363 head, tail = doc, ""
3364 else:
3364 else:
3365 head, tail = doc.split('\n', 1)
3365 head, tail = doc.split('\n', 1)
3366 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3366 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3367 if tail:
3367 if tail:
3368 rst.extend(tail.splitlines(True))
3368 rst.extend(tail.splitlines(True))
3369 rst.append('\n')
3369 rst.append('\n')
3370
3370
3371 if mod:
3371 if mod:
3372 try:
3372 try:
3373 ct = mod.cmdtable
3373 ct = mod.cmdtable
3374 except AttributeError:
3374 except AttributeError:
3375 ct = {}
3375 ct = {}
3376 modcmds = set([c.split('|', 1)[0] for c in ct])
3376 modcmds = set([c.split('|', 1)[0] for c in ct])
3377 rst.extend(helplist(modcmds.__contains__))
3377 rst.extend(helplist(modcmds.__contains__))
3378 else:
3378 else:
3379 rst.append(_('use "hg help extensions" for information on enabling '
3379 rst.append(_('use "hg help extensions" for information on enabling '
3380 'extensions\n'))
3380 'extensions\n'))
3381 return rst
3381 return rst
3382
3382
3383 def helpextcmd(name):
3383 def helpextcmd(name):
3384 cmd, ext, mod = extensions.disabledcmd(ui, name,
3384 cmd, ext, mod = extensions.disabledcmd(ui, name,
3385 ui.configbool('ui', 'strict'))
3385 ui.configbool('ui', 'strict'))
3386 doc = gettext(mod.__doc__).splitlines()[0]
3386 doc = gettext(mod.__doc__).splitlines()[0]
3387
3387
3388 rst = help.listexts(_("'%s' is provided by the following "
3388 rst = help.listexts(_("'%s' is provided by the following "
3389 "extension:") % cmd, {ext: doc}, indent=4)
3389 "extension:") % cmd, {ext: doc}, indent=4)
3390 rst.append('\n')
3390 rst.append('\n')
3391 rst.append(_('use "hg help extensions" for information on enabling '
3391 rst.append(_('use "hg help extensions" for information on enabling '
3392 'extensions\n'))
3392 'extensions\n'))
3393 return rst
3393 return rst
3394
3394
3395
3395
3396 rst = []
3396 rst = []
3397 kw = opts.get('keyword')
3397 kw = opts.get('keyword')
3398 if kw:
3398 if kw:
3399 matches = help.topicmatch(kw)
3399 matches = help.topicmatch(kw)
3400 for t, title in (('topics', _('Topics')),
3400 for t, title in (('topics', _('Topics')),
3401 ('commands', _('Commands')),
3401 ('commands', _('Commands')),
3402 ('extensions', _('Extensions')),
3402 ('extensions', _('Extensions')),
3403 ('extensioncommands', _('Extension Commands'))):
3403 ('extensioncommands', _('Extension Commands'))):
3404 if matches[t]:
3404 if matches[t]:
3405 rst.append('%s:\n\n' % title)
3405 rst.append('%s:\n\n' % title)
3406 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3406 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3407 rst.append('\n')
3407 rst.append('\n')
3408 elif name and name != 'shortlist':
3408 elif name and name != 'shortlist':
3409 i = None
3409 i = None
3410 if unknowncmd:
3410 if unknowncmd:
3411 queries = (helpextcmd,)
3411 queries = (helpextcmd,)
3412 elif opts.get('extension'):
3412 elif opts.get('extension'):
3413 queries = (helpext,)
3413 queries = (helpext,)
3414 elif opts.get('command'):
3414 elif opts.get('command'):
3415 queries = (helpcmd,)
3415 queries = (helpcmd,)
3416 else:
3416 else:
3417 queries = (helptopic, helpcmd, helpext, helpextcmd)
3417 queries = (helptopic, helpcmd, helpext, helpextcmd)
3418 for f in queries:
3418 for f in queries:
3419 try:
3419 try:
3420 rst = f(name)
3420 rst = f(name)
3421 i = None
3421 i = None
3422 break
3422 break
3423 except error.UnknownCommand, inst:
3423 except error.UnknownCommand, inst:
3424 i = inst
3424 i = inst
3425 if i:
3425 if i:
3426 raise i
3426 raise i
3427 else:
3427 else:
3428 # program name
3428 # program name
3429 if not ui.quiet:
3429 if not ui.quiet:
3430 rst = [_("Mercurial Distributed SCM\n"), '\n']
3430 rst = [_("Mercurial Distributed SCM\n"), '\n']
3431 rst.extend(helplist())
3431 rst.extend(helplist())
3432
3432
3433 keep = ui.verbose and ['verbose'] or []
3433 keep = ui.verbose and ['verbose'] or []
3434 formatted, pruned = minirst.format(''.join(rst), textwidth, keep=keep)
3434 formatted, pruned = minirst.format(''.join(rst), textwidth, keep=keep)
3435 ui.write(formatted)
3435 ui.write(formatted)
3436
3436
3437
3437
3438 @command('identify|id',
3438 @command('identify|id',
3439 [('r', 'rev', '',
3439 [('r', 'rev', '',
3440 _('identify the specified revision'), _('REV')),
3440 _('identify the specified revision'), _('REV')),
3441 ('n', 'num', None, _('show local revision number')),
3441 ('n', 'num', None, _('show local revision number')),
3442 ('i', 'id', None, _('show global revision id')),
3442 ('i', 'id', None, _('show global revision id')),
3443 ('b', 'branch', None, _('show branch')),
3443 ('b', 'branch', None, _('show branch')),
3444 ('t', 'tags', None, _('show tags')),
3444 ('t', 'tags', None, _('show tags')),
3445 ('B', 'bookmarks', None, _('show bookmarks')),
3445 ('B', 'bookmarks', None, _('show bookmarks')),
3446 ] + remoteopts,
3446 ] + remoteopts,
3447 _('[-nibtB] [-r REV] [SOURCE]'))
3447 _('[-nibtB] [-r REV] [SOURCE]'))
3448 def identify(ui, repo, source=None, rev=None,
3448 def identify(ui, repo, source=None, rev=None,
3449 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3449 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3450 """identify the working copy or specified revision
3450 """identify the working copy or specified revision
3451
3451
3452 Print a summary identifying the repository state at REV using one or
3452 Print a summary identifying the repository state at REV using one or
3453 two parent hash identifiers, followed by a "+" if the working
3453 two parent hash identifiers, followed by a "+" if the working
3454 directory has uncommitted changes, the branch name (if not default),
3454 directory has uncommitted changes, the branch name (if not default),
3455 a list of tags, and a list of bookmarks.
3455 a list of tags, and a list of bookmarks.
3456
3456
3457 When REV is not given, print a summary of the current state of the
3457 When REV is not given, print a summary of the current state of the
3458 repository.
3458 repository.
3459
3459
3460 Specifying a path to a repository root or Mercurial bundle will
3460 Specifying a path to a repository root or Mercurial bundle will
3461 cause lookup to operate on that repository/bundle.
3461 cause lookup to operate on that repository/bundle.
3462
3462
3463 .. container:: verbose
3463 .. container:: verbose
3464
3464
3465 Examples:
3465 Examples:
3466
3466
3467 - generate a build identifier for the working directory::
3467 - generate a build identifier for the working directory::
3468
3468
3469 hg id --id > build-id.dat
3469 hg id --id > build-id.dat
3470
3470
3471 - find the revision corresponding to a tag::
3471 - find the revision corresponding to a tag::
3472
3472
3473 hg id -n -r 1.3
3473 hg id -n -r 1.3
3474
3474
3475 - check the most recent revision of a remote repository::
3475 - check the most recent revision of a remote repository::
3476
3476
3477 hg id -r tip http://selenic.com/hg/
3477 hg id -r tip http://selenic.com/hg/
3478
3478
3479 Returns 0 if successful.
3479 Returns 0 if successful.
3480 """
3480 """
3481
3481
3482 if not repo and not source:
3482 if not repo and not source:
3483 raise util.Abort(_("there is no Mercurial repository here "
3483 raise util.Abort(_("there is no Mercurial repository here "
3484 "(.hg not found)"))
3484 "(.hg not found)"))
3485
3485
3486 hexfunc = ui.debugflag and hex or short
3486 hexfunc = ui.debugflag and hex or short
3487 default = not (num or id or branch or tags or bookmarks)
3487 default = not (num or id or branch or tags or bookmarks)
3488 output = []
3488 output = []
3489 revs = []
3489 revs = []
3490
3490
3491 if source:
3491 if source:
3492 source, branches = hg.parseurl(ui.expandpath(source))
3492 source, branches = hg.parseurl(ui.expandpath(source))
3493 peer = hg.peer(ui, opts, source)
3493 peer = hg.peer(ui, opts, source)
3494 repo = peer.local()
3494 repo = peer.local()
3495 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3495 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3496
3496
3497 if not repo:
3497 if not repo:
3498 if num or branch or tags:
3498 if num or branch or tags:
3499 raise util.Abort(
3499 raise util.Abort(
3500 _("can't query remote revision number, branch, or tags"))
3500 _("can't query remote revision number, branch, or tags"))
3501 if not rev and revs:
3501 if not rev and revs:
3502 rev = revs[0]
3502 rev = revs[0]
3503 if not rev:
3503 if not rev:
3504 rev = "tip"
3504 rev = "tip"
3505
3505
3506 remoterev = peer.lookup(rev)
3506 remoterev = peer.lookup(rev)
3507 if default or id:
3507 if default or id:
3508 output = [hexfunc(remoterev)]
3508 output = [hexfunc(remoterev)]
3509
3509
3510 def getbms():
3510 def getbms():
3511 bms = []
3511 bms = []
3512
3512
3513 if 'bookmarks' in peer.listkeys('namespaces'):
3513 if 'bookmarks' in peer.listkeys('namespaces'):
3514 hexremoterev = hex(remoterev)
3514 hexremoterev = hex(remoterev)
3515 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3515 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3516 if bmr == hexremoterev]
3516 if bmr == hexremoterev]
3517
3517
3518 return bms
3518 return bms
3519
3519
3520 if bookmarks:
3520 if bookmarks:
3521 output.extend(getbms())
3521 output.extend(getbms())
3522 elif default and not ui.quiet:
3522 elif default and not ui.quiet:
3523 # multiple bookmarks for a single parent separated by '/'
3523 # multiple bookmarks for a single parent separated by '/'
3524 bm = '/'.join(getbms())
3524 bm = '/'.join(getbms())
3525 if bm:
3525 if bm:
3526 output.append(bm)
3526 output.append(bm)
3527 else:
3527 else:
3528 if not rev:
3528 if not rev:
3529 ctx = repo[None]
3529 ctx = repo[None]
3530 parents = ctx.parents()
3530 parents = ctx.parents()
3531 changed = ""
3531 changed = ""
3532 if default or id or num:
3532 if default or id or num:
3533 if (util.any(repo.status())
3533 if (util.any(repo.status())
3534 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3534 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3535 changed = '+'
3535 changed = '+'
3536 if default or id:
3536 if default or id:
3537 output = ["%s%s" %
3537 output = ["%s%s" %
3538 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3538 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3539 if num:
3539 if num:
3540 output.append("%s%s" %
3540 output.append("%s%s" %
3541 ('+'.join([str(p.rev()) for p in parents]), changed))
3541 ('+'.join([str(p.rev()) for p in parents]), changed))
3542 else:
3542 else:
3543 ctx = scmutil.revsingle(repo, rev)
3543 ctx = scmutil.revsingle(repo, rev)
3544 if default or id:
3544 if default or id:
3545 output = [hexfunc(ctx.node())]
3545 output = [hexfunc(ctx.node())]
3546 if num:
3546 if num:
3547 output.append(str(ctx.rev()))
3547 output.append(str(ctx.rev()))
3548
3548
3549 if default and not ui.quiet:
3549 if default and not ui.quiet:
3550 b = ctx.branch()
3550 b = ctx.branch()
3551 if b != 'default':
3551 if b != 'default':
3552 output.append("(%s)" % b)
3552 output.append("(%s)" % b)
3553
3553
3554 # multiple tags for a single parent separated by '/'
3554 # multiple tags for a single parent separated by '/'
3555 t = '/'.join(ctx.tags())
3555 t = '/'.join(ctx.tags())
3556 if t:
3556 if t:
3557 output.append(t)
3557 output.append(t)
3558
3558
3559 # multiple bookmarks for a single parent separated by '/'
3559 # multiple bookmarks for a single parent separated by '/'
3560 bm = '/'.join(ctx.bookmarks())
3560 bm = '/'.join(ctx.bookmarks())
3561 if bm:
3561 if bm:
3562 output.append(bm)
3562 output.append(bm)
3563 else:
3563 else:
3564 if branch:
3564 if branch:
3565 output.append(ctx.branch())
3565 output.append(ctx.branch())
3566
3566
3567 if tags:
3567 if tags:
3568 output.extend(ctx.tags())
3568 output.extend(ctx.tags())
3569
3569
3570 if bookmarks:
3570 if bookmarks:
3571 output.extend(ctx.bookmarks())
3571 output.extend(ctx.bookmarks())
3572
3572
3573 ui.write("%s\n" % ' '.join(output))
3573 ui.write("%s\n" % ' '.join(output))
3574
3574
3575 @command('import|patch',
3575 @command('import|patch',
3576 [('p', 'strip', 1,
3576 [('p', 'strip', 1,
3577 _('directory strip option for patch. This has the same '
3577 _('directory strip option for patch. This has the same '
3578 'meaning as the corresponding patch option'), _('NUM')),
3578 'meaning as the corresponding patch option'), _('NUM')),
3579 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3579 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3580 ('e', 'edit', False, _('invoke editor on commit messages')),
3580 ('e', 'edit', False, _('invoke editor on commit messages')),
3581 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3581 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3582 ('', 'no-commit', None,
3582 ('', 'no-commit', None,
3583 _("don't commit, just update the working directory")),
3583 _("don't commit, just update the working directory")),
3584 ('', 'bypass', None,
3584 ('', 'bypass', None,
3585 _("apply patch without touching the working directory")),
3585 _("apply patch without touching the working directory")),
3586 ('', 'exact', None,
3586 ('', 'exact', None,
3587 _('apply patch to the nodes from which it was generated')),
3587 _('apply patch to the nodes from which it was generated')),
3588 ('', 'import-branch', None,
3588 ('', 'import-branch', None,
3589 _('use any branch information in patch (implied by --exact)'))] +
3589 _('use any branch information in patch (implied by --exact)'))] +
3590 commitopts + commitopts2 + similarityopts,
3590 commitopts + commitopts2 + similarityopts,
3591 _('[OPTION]... PATCH...'))
3591 _('[OPTION]... PATCH...'))
3592 def import_(ui, repo, patch1=None, *patches, **opts):
3592 def import_(ui, repo, patch1=None, *patches, **opts):
3593 """import an ordered set of patches
3593 """import an ordered set of patches
3594
3594
3595 Import a list of patches and commit them individually (unless
3595 Import a list of patches and commit them individually (unless
3596 --no-commit is specified).
3596 --no-commit is specified).
3597
3597
3598 If there are outstanding changes in the working directory, import
3598 If there are outstanding changes in the working directory, import
3599 will abort unless given the -f/--force flag.
3599 will abort unless given the -f/--force flag.
3600
3600
3601 You can import a patch straight from a mail message. Even patches
3601 You can import a patch straight from a mail message. Even patches
3602 as attachments work (to use the body part, it must have type
3602 as attachments work (to use the body part, it must have type
3603 text/plain or text/x-patch). From and Subject headers of email
3603 text/plain or text/x-patch). From and Subject headers of email
3604 message are used as default committer and commit message. All
3604 message are used as default committer and commit message. All
3605 text/plain body parts before first diff are added to commit
3605 text/plain body parts before first diff are added to commit
3606 message.
3606 message.
3607
3607
3608 If the imported patch was generated by :hg:`export`, user and
3608 If the imported patch was generated by :hg:`export`, user and
3609 description from patch override values from message headers and
3609 description from patch override values from message headers and
3610 body. Values given on command line with -m/--message and -u/--user
3610 body. Values given on command line with -m/--message and -u/--user
3611 override these.
3611 override these.
3612
3612
3613 If --exact is specified, import will set the working directory to
3613 If --exact is specified, import will set the working directory to
3614 the parent of each patch before applying it, and will abort if the
3614 the parent of each patch before applying it, and will abort if the
3615 resulting changeset has a different ID than the one recorded in
3615 resulting changeset has a different ID than the one recorded in
3616 the patch. This may happen due to character set problems or other
3616 the patch. This may happen due to character set problems or other
3617 deficiencies in the text patch format.
3617 deficiencies in the text patch format.
3618
3618
3619 Use --bypass to apply and commit patches directly to the
3619 Use --bypass to apply and commit patches directly to the
3620 repository, not touching the working directory. Without --exact,
3620 repository, not touching the working directory. Without --exact,
3621 patches will be applied on top of the working directory parent
3621 patches will be applied on top of the working directory parent
3622 revision.
3622 revision.
3623
3623
3624 With -s/--similarity, hg will attempt to discover renames and
3624 With -s/--similarity, hg will attempt to discover renames and
3625 copies in the patch in the same way as :hg:`addremove`.
3625 copies in the patch in the same way as :hg:`addremove`.
3626
3626
3627 To read a patch from standard input, use "-" as the patch name. If
3627 To read a patch from standard input, use "-" as the patch name. If
3628 a URL is specified, the patch will be downloaded from it.
3628 a URL is specified, the patch will be downloaded from it.
3629 See :hg:`help dates` for a list of formats valid for -d/--date.
3629 See :hg:`help dates` for a list of formats valid for -d/--date.
3630
3630
3631 .. container:: verbose
3631 .. container:: verbose
3632
3632
3633 Examples:
3633 Examples:
3634
3634
3635 - import a traditional patch from a website and detect renames::
3635 - import a traditional patch from a website and detect renames::
3636
3636
3637 hg import -s 80 http://example.com/bugfix.patch
3637 hg import -s 80 http://example.com/bugfix.patch
3638
3638
3639 - import a changeset from an hgweb server::
3639 - import a changeset from an hgweb server::
3640
3640
3641 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3641 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3642
3642
3643 - import all the patches in an Unix-style mbox::
3643 - import all the patches in an Unix-style mbox::
3644
3644
3645 hg import incoming-patches.mbox
3645 hg import incoming-patches.mbox
3646
3646
3647 - attempt to exactly restore an exported changeset (not always
3647 - attempt to exactly restore an exported changeset (not always
3648 possible)::
3648 possible)::
3649
3649
3650 hg import --exact proposed-fix.patch
3650 hg import --exact proposed-fix.patch
3651
3651
3652 Returns 0 on success.
3652 Returns 0 on success.
3653 """
3653 """
3654
3654
3655 if not patch1:
3655 if not patch1:
3656 raise util.Abort(_('need at least one patch to import'))
3656 raise util.Abort(_('need at least one patch to import'))
3657
3657
3658 patches = (patch1,) + patches
3658 patches = (patch1,) + patches
3659
3659
3660 date = opts.get('date')
3660 date = opts.get('date')
3661 if date:
3661 if date:
3662 opts['date'] = util.parsedate(date)
3662 opts['date'] = util.parsedate(date)
3663
3663
3664 editor = cmdutil.commiteditor
3664 editor = cmdutil.commiteditor
3665 if opts.get('edit'):
3665 if opts.get('edit'):
3666 editor = cmdutil.commitforceeditor
3666 editor = cmdutil.commitforceeditor
3667
3667
3668 update = not opts.get('bypass')
3668 update = not opts.get('bypass')
3669 if not update and opts.get('no_commit'):
3669 if not update and opts.get('no_commit'):
3670 raise util.Abort(_('cannot use --no-commit with --bypass'))
3670 raise util.Abort(_('cannot use --no-commit with --bypass'))
3671 try:
3671 try:
3672 sim = float(opts.get('similarity') or 0)
3672 sim = float(opts.get('similarity') or 0)
3673 except ValueError:
3673 except ValueError:
3674 raise util.Abort(_('similarity must be a number'))
3674 raise util.Abort(_('similarity must be a number'))
3675 if sim < 0 or sim > 100:
3675 if sim < 0 or sim > 100:
3676 raise util.Abort(_('similarity must be between 0 and 100'))
3676 raise util.Abort(_('similarity must be between 0 and 100'))
3677 if sim and not update:
3677 if sim and not update:
3678 raise util.Abort(_('cannot use --similarity with --bypass'))
3678 raise util.Abort(_('cannot use --similarity with --bypass'))
3679
3679
3680 if (opts.get('exact') or not opts.get('force')) and update:
3680 if (opts.get('exact') or not opts.get('force')) and update:
3681 cmdutil.bailifchanged(repo)
3681 cmdutil.bailifchanged(repo)
3682
3682
3683 base = opts["base"]
3683 base = opts["base"]
3684 strip = opts["strip"]
3684 strip = opts["strip"]
3685 wlock = lock = tr = None
3685 wlock = lock = tr = None
3686 msgs = []
3686 msgs = []
3687
3687
3688 def checkexact(repo, n, nodeid):
3688 def checkexact(repo, n, nodeid):
3689 if opts.get('exact') and hex(n) != nodeid:
3689 if opts.get('exact') and hex(n) != nodeid:
3690 repo.rollback()
3690 repo.rollback()
3691 raise util.Abort(_('patch is damaged or loses information'))
3691 raise util.Abort(_('patch is damaged or loses information'))
3692
3692
3693 def tryone(ui, hunk, parents):
3693 def tryone(ui, hunk, parents):
3694 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3694 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3695 patch.extract(ui, hunk)
3695 patch.extract(ui, hunk)
3696
3696
3697 if not tmpname:
3697 if not tmpname:
3698 return (None, None)
3698 return (None, None)
3699 msg = _('applied to working directory')
3699 msg = _('applied to working directory')
3700
3700
3701 try:
3701 try:
3702 cmdline_message = cmdutil.logmessage(ui, opts)
3702 cmdline_message = cmdutil.logmessage(ui, opts)
3703 if cmdline_message:
3703 if cmdline_message:
3704 # pickup the cmdline msg
3704 # pickup the cmdline msg
3705 message = cmdline_message
3705 message = cmdline_message
3706 elif message:
3706 elif message:
3707 # pickup the patch msg
3707 # pickup the patch msg
3708 message = message.strip()
3708 message = message.strip()
3709 else:
3709 else:
3710 # launch the editor
3710 # launch the editor
3711 message = None
3711 message = None
3712 ui.debug('message:\n%s\n' % message)
3712 ui.debug('message:\n%s\n' % message)
3713
3713
3714 if len(parents) == 1:
3714 if len(parents) == 1:
3715 parents.append(repo[nullid])
3715 parents.append(repo[nullid])
3716 if opts.get('exact'):
3716 if opts.get('exact'):
3717 if not nodeid or not p1:
3717 if not nodeid or not p1:
3718 raise util.Abort(_('not a Mercurial patch'))
3718 raise util.Abort(_('not a Mercurial patch'))
3719 p1 = repo[p1]
3719 p1 = repo[p1]
3720 p2 = repo[p2 or nullid]
3720 p2 = repo[p2 or nullid]
3721 elif p2:
3721 elif p2:
3722 try:
3722 try:
3723 p1 = repo[p1]
3723 p1 = repo[p1]
3724 p2 = repo[p2]
3724 p2 = repo[p2]
3725 # Without any options, consider p2 only if the
3725 # Without any options, consider p2 only if the
3726 # patch is being applied on top of the recorded
3726 # patch is being applied on top of the recorded
3727 # first parent.
3727 # first parent.
3728 if p1 != parents[0]:
3728 if p1 != parents[0]:
3729 p1 = parents[0]
3729 p1 = parents[0]
3730 p2 = repo[nullid]
3730 p2 = repo[nullid]
3731 except error.RepoError:
3731 except error.RepoError:
3732 p1, p2 = parents
3732 p1, p2 = parents
3733 else:
3733 else:
3734 p1, p2 = parents
3734 p1, p2 = parents
3735
3735
3736 n = None
3736 n = None
3737 if update:
3737 if update:
3738 if p1 != parents[0]:
3738 if p1 != parents[0]:
3739 hg.clean(repo, p1.node())
3739 hg.clean(repo, p1.node())
3740 if p2 != parents[1]:
3740 if p2 != parents[1]:
3741 repo.setparents(p1.node(), p2.node())
3741 repo.setparents(p1.node(), p2.node())
3742
3742
3743 if opts.get('exact') or opts.get('import_branch'):
3743 if opts.get('exact') or opts.get('import_branch'):
3744 repo.dirstate.setbranch(branch or 'default')
3744 repo.dirstate.setbranch(branch or 'default')
3745
3745
3746 files = set()
3746 files = set()
3747 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3747 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3748 eolmode=None, similarity=sim / 100.0)
3748 eolmode=None, similarity=sim / 100.0)
3749 files = list(files)
3749 files = list(files)
3750 if opts.get('no_commit'):
3750 if opts.get('no_commit'):
3751 if message:
3751 if message:
3752 msgs.append(message)
3752 msgs.append(message)
3753 else:
3753 else:
3754 if opts.get('exact') or p2:
3754 if opts.get('exact') or p2:
3755 # If you got here, you either use --force and know what
3755 # If you got here, you either use --force and know what
3756 # you are doing or used --exact or a merge patch while
3756 # you are doing or used --exact or a merge patch while
3757 # being updated to its first parent.
3757 # being updated to its first parent.
3758 m = None
3758 m = None
3759 else:
3759 else:
3760 m = scmutil.matchfiles(repo, files or [])
3760 m = scmutil.matchfiles(repo, files or [])
3761 n = repo.commit(message, opts.get('user') or user,
3761 n = repo.commit(message, opts.get('user') or user,
3762 opts.get('date') or date, match=m,
3762 opts.get('date') or date, match=m,
3763 editor=editor)
3763 editor=editor)
3764 checkexact(repo, n, nodeid)
3764 checkexact(repo, n, nodeid)
3765 else:
3765 else:
3766 if opts.get('exact') or opts.get('import_branch'):
3766 if opts.get('exact') or opts.get('import_branch'):
3767 branch = branch or 'default'
3767 branch = branch or 'default'
3768 else:
3768 else:
3769 branch = p1.branch()
3769 branch = p1.branch()
3770 store = patch.filestore()
3770 store = patch.filestore()
3771 try:
3771 try:
3772 files = set()
3772 files = set()
3773 try:
3773 try:
3774 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3774 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3775 files, eolmode=None)
3775 files, eolmode=None)
3776 except patch.PatchError, e:
3776 except patch.PatchError, e:
3777 raise util.Abort(str(e))
3777 raise util.Abort(str(e))
3778 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3778 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3779 message,
3779 message,
3780 opts.get('user') or user,
3780 opts.get('user') or user,
3781 opts.get('date') or date,
3781 opts.get('date') or date,
3782 branch, files, store,
3782 branch, files, store,
3783 editor=cmdutil.commiteditor)
3783 editor=cmdutil.commiteditor)
3784 repo.savecommitmessage(memctx.description())
3784 repo.savecommitmessage(memctx.description())
3785 n = memctx.commit()
3785 n = memctx.commit()
3786 checkexact(repo, n, nodeid)
3786 checkexact(repo, n, nodeid)
3787 finally:
3787 finally:
3788 store.close()
3788 store.close()
3789 if n:
3789 if n:
3790 # i18n: refers to a short changeset id
3790 # i18n: refers to a short changeset id
3791 msg = _('created %s') % short(n)
3791 msg = _('created %s') % short(n)
3792 return (msg, n)
3792 return (msg, n)
3793 finally:
3793 finally:
3794 os.unlink(tmpname)
3794 os.unlink(tmpname)
3795
3795
3796 try:
3796 try:
3797 try:
3797 try:
3798 wlock = repo.wlock()
3798 wlock = repo.wlock()
3799 if not opts.get('no_commit'):
3799 if not opts.get('no_commit'):
3800 lock = repo.lock()
3800 lock = repo.lock()
3801 tr = repo.transaction('import')
3801 tr = repo.transaction('import')
3802 parents = repo.parents()
3802 parents = repo.parents()
3803 for patchurl in patches:
3803 for patchurl in patches:
3804 if patchurl == '-':
3804 if patchurl == '-':
3805 ui.status(_('applying patch from stdin\n'))
3805 ui.status(_('applying patch from stdin\n'))
3806 patchfile = ui.fin
3806 patchfile = ui.fin
3807 patchurl = 'stdin' # for error message
3807 patchurl = 'stdin' # for error message
3808 else:
3808 else:
3809 patchurl = os.path.join(base, patchurl)
3809 patchurl = os.path.join(base, patchurl)
3810 ui.status(_('applying %s\n') % patchurl)
3810 ui.status(_('applying %s\n') % patchurl)
3811 patchfile = url.open(ui, patchurl)
3811 patchfile = url.open(ui, patchurl)
3812
3812
3813 haspatch = False
3813 haspatch = False
3814 for hunk in patch.split(patchfile):
3814 for hunk in patch.split(patchfile):
3815 (msg, node) = tryone(ui, hunk, parents)
3815 (msg, node) = tryone(ui, hunk, parents)
3816 if msg:
3816 if msg:
3817 haspatch = True
3817 haspatch = True
3818 ui.note(msg + '\n')
3818 ui.note(msg + '\n')
3819 if update or opts.get('exact'):
3819 if update or opts.get('exact'):
3820 parents = repo.parents()
3820 parents = repo.parents()
3821 else:
3821 else:
3822 parents = [repo[node]]
3822 parents = [repo[node]]
3823
3823
3824 if not haspatch:
3824 if not haspatch:
3825 raise util.Abort(_('%s: no diffs found') % patchurl)
3825 raise util.Abort(_('%s: no diffs found') % patchurl)
3826
3826
3827 if tr:
3827 if tr:
3828 tr.close()
3828 tr.close()
3829 if msgs:
3829 if msgs:
3830 repo.savecommitmessage('\n* * *\n'.join(msgs))
3830 repo.savecommitmessage('\n* * *\n'.join(msgs))
3831 except: # re-raises
3831 except: # re-raises
3832 # wlock.release() indirectly calls dirstate.write(): since
3832 # wlock.release() indirectly calls dirstate.write(): since
3833 # we're crashing, we do not want to change the working dir
3833 # we're crashing, we do not want to change the working dir
3834 # parent after all, so make sure it writes nothing
3834 # parent after all, so make sure it writes nothing
3835 repo.dirstate.invalidate()
3835 repo.dirstate.invalidate()
3836 raise
3836 raise
3837 finally:
3837 finally:
3838 if tr:
3838 if tr:
3839 tr.release()
3839 tr.release()
3840 release(lock, wlock)
3840 release(lock, wlock)
3841
3841
3842 @command('incoming|in',
3842 @command('incoming|in',
3843 [('f', 'force', None,
3843 [('f', 'force', None,
3844 _('run even if remote repository is unrelated')),
3844 _('run even if remote repository is unrelated')),
3845 ('n', 'newest-first', None, _('show newest record first')),
3845 ('n', 'newest-first', None, _('show newest record first')),
3846 ('', 'bundle', '',
3846 ('', 'bundle', '',
3847 _('file to store the bundles into'), _('FILE')),
3847 _('file to store the bundles into'), _('FILE')),
3848 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3848 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3849 ('B', 'bookmarks', False, _("compare bookmarks")),
3849 ('B', 'bookmarks', False, _("compare bookmarks")),
3850 ('b', 'branch', [],
3850 ('b', 'branch', [],
3851 _('a specific branch you would like to pull'), _('BRANCH')),
3851 _('a specific branch you would like to pull'), _('BRANCH')),
3852 ] + logopts + remoteopts + subrepoopts,
3852 ] + logopts + remoteopts + subrepoopts,
3853 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3853 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3854 def incoming(ui, repo, source="default", **opts):
3854 def incoming(ui, repo, source="default", **opts):
3855 """show new changesets found in source
3855 """show new changesets found in source
3856
3856
3857 Show new changesets found in the specified path/URL or the default
3857 Show new changesets found in the specified path/URL or the default
3858 pull location. These are the changesets that would have been pulled
3858 pull location. These are the changesets that would have been pulled
3859 if a pull at the time you issued this command.
3859 if a pull at the time you issued this command.
3860
3860
3861 For remote repository, using --bundle avoids downloading the
3861 For remote repository, using --bundle avoids downloading the
3862 changesets twice if the incoming is followed by a pull.
3862 changesets twice if the incoming is followed by a pull.
3863
3863
3864 See pull for valid source format details.
3864 See pull for valid source format details.
3865
3865
3866 Returns 0 if there are incoming changes, 1 otherwise.
3866 Returns 0 if there are incoming changes, 1 otherwise.
3867 """
3867 """
3868 if opts.get('graph'):
3868 if opts.get('graph'):
3869 cmdutil.checkunsupportedgraphflags([], opts)
3869 cmdutil.checkunsupportedgraphflags([], opts)
3870 def display(other, chlist, displayer):
3870 def display(other, chlist, displayer):
3871 revdag = cmdutil.graphrevs(other, chlist, opts)
3871 revdag = cmdutil.graphrevs(other, chlist, opts)
3872 showparents = [ctx.node() for ctx in repo[None].parents()]
3872 showparents = [ctx.node() for ctx in repo[None].parents()]
3873 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3873 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3874 graphmod.asciiedges)
3874 graphmod.asciiedges)
3875
3875
3876 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3876 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3877 return 0
3877 return 0
3878
3878
3879 if opts.get('bundle') and opts.get('subrepos'):
3879 if opts.get('bundle') and opts.get('subrepos'):
3880 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3880 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3881
3881
3882 if opts.get('bookmarks'):
3882 if opts.get('bookmarks'):
3883 source, branches = hg.parseurl(ui.expandpath(source),
3883 source, branches = hg.parseurl(ui.expandpath(source),
3884 opts.get('branch'))
3884 opts.get('branch'))
3885 other = hg.peer(repo, opts, source)
3885 other = hg.peer(repo, opts, source)
3886 if 'bookmarks' not in other.listkeys('namespaces'):
3886 if 'bookmarks' not in other.listkeys('namespaces'):
3887 ui.warn(_("remote doesn't support bookmarks\n"))
3887 ui.warn(_("remote doesn't support bookmarks\n"))
3888 return 0
3888 return 0
3889 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3889 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3890 return bookmarks.diff(ui, repo, other)
3890 return bookmarks.diff(ui, repo, other)
3891
3891
3892 repo._subtoppath = ui.expandpath(source)
3892 repo._subtoppath = ui.expandpath(source)
3893 try:
3893 try:
3894 return hg.incoming(ui, repo, source, opts)
3894 return hg.incoming(ui, repo, source, opts)
3895 finally:
3895 finally:
3896 del repo._subtoppath
3896 del repo._subtoppath
3897
3897
3898
3898
3899 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3899 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3900 def init(ui, dest=".", **opts):
3900 def init(ui, dest=".", **opts):
3901 """create a new repository in the given directory
3901 """create a new repository in the given directory
3902
3902
3903 Initialize a new repository in the given directory. If the given
3903 Initialize a new repository in the given directory. If the given
3904 directory does not exist, it will be created.
3904 directory does not exist, it will be created.
3905
3905
3906 If no directory is given, the current directory is used.
3906 If no directory is given, the current directory is used.
3907
3907
3908 It is possible to specify an ``ssh://`` URL as the destination.
3908 It is possible to specify an ``ssh://`` URL as the destination.
3909 See :hg:`help urls` for more information.
3909 See :hg:`help urls` for more information.
3910
3910
3911 Returns 0 on success.
3911 Returns 0 on success.
3912 """
3912 """
3913 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3913 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3914
3914
3915 @command('locate',
3915 @command('locate',
3916 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3916 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3917 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3917 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3918 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3918 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3919 ] + walkopts,
3919 ] + walkopts,
3920 _('[OPTION]... [PATTERN]...'))
3920 _('[OPTION]... [PATTERN]...'))
3921 def locate(ui, repo, *pats, **opts):
3921 def locate(ui, repo, *pats, **opts):
3922 """locate files matching specific patterns
3922 """locate files matching specific patterns
3923
3923
3924 Print files under Mercurial control in the working directory whose
3924 Print files under Mercurial control in the working directory whose
3925 names match the given patterns.
3925 names match the given patterns.
3926
3926
3927 By default, this command searches all directories in the working
3927 By default, this command searches all directories in the working
3928 directory. To search just the current directory and its
3928 directory. To search just the current directory and its
3929 subdirectories, use "--include .".
3929 subdirectories, use "--include .".
3930
3930
3931 If no patterns are given to match, this command prints the names
3931 If no patterns are given to match, this command prints the names
3932 of all files under Mercurial control in the working directory.
3932 of all files under Mercurial control in the working directory.
3933
3933
3934 If you want to feed the output of this command into the "xargs"
3934 If you want to feed the output of this command into the "xargs"
3935 command, use the -0 option to both this command and "xargs". This
3935 command, use the -0 option to both this command and "xargs". This
3936 will avoid the problem of "xargs" treating single filenames that
3936 will avoid the problem of "xargs" treating single filenames that
3937 contain whitespace as multiple filenames.
3937 contain whitespace as multiple filenames.
3938
3938
3939 Returns 0 if a match is found, 1 otherwise.
3939 Returns 0 if a match is found, 1 otherwise.
3940 """
3940 """
3941 end = opts.get('print0') and '\0' or '\n'
3941 end = opts.get('print0') and '\0' or '\n'
3942 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3942 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3943
3943
3944 ret = 1
3944 ret = 1
3945 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3945 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3946 m.bad = lambda x, y: False
3946 m.bad = lambda x, y: False
3947 for abs in repo[rev].walk(m):
3947 for abs in repo[rev].walk(m):
3948 if not rev and abs not in repo.dirstate:
3948 if not rev and abs not in repo.dirstate:
3949 continue
3949 continue
3950 if opts.get('fullpath'):
3950 if opts.get('fullpath'):
3951 ui.write(repo.wjoin(abs), end)
3951 ui.write(repo.wjoin(abs), end)
3952 else:
3952 else:
3953 ui.write(((pats and m.rel(abs)) or abs), end)
3953 ui.write(((pats and m.rel(abs)) or abs), end)
3954 ret = 0
3954 ret = 0
3955
3955
3956 return ret
3956 return ret
3957
3957
3958 @command('^log|history',
3958 @command('^log|history',
3959 [('f', 'follow', None,
3959 [('f', 'follow', None,
3960 _('follow changeset history, or file history across copies and renames')),
3960 _('follow changeset history, or file history across copies and renames')),
3961 ('', 'follow-first', None,
3961 ('', 'follow-first', None,
3962 _('only follow the first parent of merge changesets (DEPRECATED)')),
3962 _('only follow the first parent of merge changesets (DEPRECATED)')),
3963 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3963 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3964 ('C', 'copies', None, _('show copied files')),
3964 ('C', 'copies', None, _('show copied files')),
3965 ('k', 'keyword', [],
3965 ('k', 'keyword', [],
3966 _('do case-insensitive search for a given text'), _('TEXT')),
3966 _('do case-insensitive search for a given text'), _('TEXT')),
3967 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3967 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3968 ('', 'removed', None, _('include revisions where files were removed')),
3968 ('', 'removed', None, _('include revisions where files were removed')),
3969 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3969 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3970 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3970 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3971 ('', 'only-branch', [],
3971 ('', 'only-branch', [],
3972 _('show only changesets within the given named branch (DEPRECATED)'),
3972 _('show only changesets within the given named branch (DEPRECATED)'),
3973 _('BRANCH')),
3973 _('BRANCH')),
3974 ('b', 'branch', [],
3974 ('b', 'branch', [],
3975 _('show changesets within the given named branch'), _('BRANCH')),
3975 _('show changesets within the given named branch'), _('BRANCH')),
3976 ('P', 'prune', [],
3976 ('P', 'prune', [],
3977 _('do not display revision or any of its ancestors'), _('REV')),
3977 _('do not display revision or any of its ancestors'), _('REV')),
3978 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
3978 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
3979 ] + logopts + walkopts,
3979 ] + logopts + walkopts,
3980 _('[OPTION]... [FILE]'))
3980 _('[OPTION]... [FILE]'))
3981 def log(ui, repo, *pats, **opts):
3981 def log(ui, repo, *pats, **opts):
3982 """show revision history of entire repository or files
3982 """show revision history of entire repository or files
3983
3983
3984 Print the revision history of the specified files or the entire
3984 Print the revision history of the specified files or the entire
3985 project.
3985 project.
3986
3986
3987 If no revision range is specified, the default is ``tip:0`` unless
3987 If no revision range is specified, the default is ``tip:0`` unless
3988 --follow is set, in which case the working directory parent is
3988 --follow is set, in which case the working directory parent is
3989 used as the starting revision.
3989 used as the starting revision.
3990
3990
3991 File history is shown without following rename or copy history of
3991 File history is shown without following rename or copy history of
3992 files. Use -f/--follow with a filename to follow history across
3992 files. Use -f/--follow with a filename to follow history across
3993 renames and copies. --follow without a filename will only show
3993 renames and copies. --follow without a filename will only show
3994 ancestors or descendants of the starting revision.
3994 ancestors or descendants of the starting revision.
3995
3995
3996 By default this command prints revision number and changeset id,
3996 By default this command prints revision number and changeset id,
3997 tags, non-trivial parents, user, date and time, and a summary for
3997 tags, non-trivial parents, user, date and time, and a summary for
3998 each commit. When the -v/--verbose switch is used, the list of
3998 each commit. When the -v/--verbose switch is used, the list of
3999 changed files and full commit message are shown.
3999 changed files and full commit message are shown.
4000
4000
4001 .. note::
4001 .. note::
4002 log -p/--patch may generate unexpected diff output for merge
4002 log -p/--patch may generate unexpected diff output for merge
4003 changesets, as it will only compare the merge changeset against
4003 changesets, as it will only compare the merge changeset against
4004 its first parent. Also, only files different from BOTH parents
4004 its first parent. Also, only files different from BOTH parents
4005 will appear in files:.
4005 will appear in files:.
4006
4006
4007 .. note::
4007 .. note::
4008 for performance reasons, log FILE may omit duplicate changes
4008 for performance reasons, log FILE may omit duplicate changes
4009 made on branches and will not show deletions. To see all
4009 made on branches and will not show deletions. To see all
4010 changes including duplicates and deletions, use the --removed
4010 changes including duplicates and deletions, use the --removed
4011 switch.
4011 switch.
4012
4012
4013 .. container:: verbose
4013 .. container:: verbose
4014
4014
4015 Some examples:
4015 Some examples:
4016
4016
4017 - changesets with full descriptions and file lists::
4017 - changesets with full descriptions and file lists::
4018
4018
4019 hg log -v
4019 hg log -v
4020
4020
4021 - changesets ancestral to the working directory::
4021 - changesets ancestral to the working directory::
4022
4022
4023 hg log -f
4023 hg log -f
4024
4024
4025 - last 10 commits on the current branch::
4025 - last 10 commits on the current branch::
4026
4026
4027 hg log -l 10 -b .
4027 hg log -l 10 -b .
4028
4028
4029 - changesets showing all modifications of a file, including removals::
4029 - changesets showing all modifications of a file, including removals::
4030
4030
4031 hg log --removed file.c
4031 hg log --removed file.c
4032
4032
4033 - all changesets that touch a directory, with diffs, excluding merges::
4033 - all changesets that touch a directory, with diffs, excluding merges::
4034
4034
4035 hg log -Mp lib/
4035 hg log -Mp lib/
4036
4036
4037 - all revision numbers that match a keyword::
4037 - all revision numbers that match a keyword::
4038
4038
4039 hg log -k bug --template "{rev}\\n"
4039 hg log -k bug --template "{rev}\\n"
4040
4040
4041 - check if a given changeset is included is a tagged release::
4041 - check if a given changeset is included is a tagged release::
4042
4042
4043 hg log -r "a21ccf and ancestor(1.9)"
4043 hg log -r "a21ccf and ancestor(1.9)"
4044
4044
4045 - find all changesets by some user in a date range::
4045 - find all changesets by some user in a date range::
4046
4046
4047 hg log -k alice -d "may 2008 to jul 2008"
4047 hg log -k alice -d "may 2008 to jul 2008"
4048
4048
4049 - summary of all changesets after the last tag::
4049 - summary of all changesets after the last tag::
4050
4050
4051 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4051 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4052
4052
4053 See :hg:`help dates` for a list of formats valid for -d/--date.
4053 See :hg:`help dates` for a list of formats valid for -d/--date.
4054
4054
4055 See :hg:`help revisions` and :hg:`help revsets` for more about
4055 See :hg:`help revisions` and :hg:`help revsets` for more about
4056 specifying revisions.
4056 specifying revisions.
4057
4057
4058 See :hg:`help templates` for more about pre-packaged styles and
4058 See :hg:`help templates` for more about pre-packaged styles and
4059 specifying custom templates.
4059 specifying custom templates.
4060
4060
4061 Returns 0 on success.
4061 Returns 0 on success.
4062 """
4062 """
4063 if opts.get('graph'):
4063 if opts.get('graph'):
4064 return cmdutil.graphlog(ui, repo, *pats, **opts)
4064 return cmdutil.graphlog(ui, repo, *pats, **opts)
4065
4065
4066 matchfn = scmutil.match(repo[None], pats, opts)
4066 matchfn = scmutil.match(repo[None], pats, opts)
4067 limit = cmdutil.loglimit(opts)
4067 limit = cmdutil.loglimit(opts)
4068 count = 0
4068 count = 0
4069
4069
4070 getrenamed, endrev = None, None
4070 getrenamed, endrev = None, None
4071 if opts.get('copies'):
4071 if opts.get('copies'):
4072 if opts.get('rev'):
4072 if opts.get('rev'):
4073 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4073 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4074 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4074 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4075
4075
4076 df = False
4076 df = False
4077 if opts.get("date"):
4077 if opts.get("date"):
4078 df = util.matchdate(opts["date"])
4078 df = util.matchdate(opts["date"])
4079
4079
4080 branches = opts.get('branch', []) + opts.get('only_branch', [])
4080 branches = opts.get('branch', []) + opts.get('only_branch', [])
4081 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4081 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4082
4082
4083 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4083 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4084 def prep(ctx, fns):
4084 def prep(ctx, fns):
4085 rev = ctx.rev()
4085 rev = ctx.rev()
4086 parents = [p for p in repo.changelog.parentrevs(rev)
4086 parents = [p for p in repo.changelog.parentrevs(rev)
4087 if p != nullrev]
4087 if p != nullrev]
4088 if opts.get('no_merges') and len(parents) == 2:
4088 if opts.get('no_merges') and len(parents) == 2:
4089 return
4089 return
4090 if opts.get('only_merges') and len(parents) != 2:
4090 if opts.get('only_merges') and len(parents) != 2:
4091 return
4091 return
4092 if opts.get('branch') and ctx.branch() not in opts['branch']:
4092 if opts.get('branch') and ctx.branch() not in opts['branch']:
4093 return
4093 return
4094 if not opts.get('hidden') and ctx.hidden():
4094 if not opts.get('hidden') and ctx.hidden():
4095 return
4095 return
4096 if df and not df(ctx.date()[0]):
4096 if df and not df(ctx.date()[0]):
4097 return
4097 return
4098
4098
4099 lower = encoding.lower
4099 lower = encoding.lower
4100 if opts.get('user'):
4100 if opts.get('user'):
4101 luser = lower(ctx.user())
4101 luser = lower(ctx.user())
4102 for k in [lower(x) for x in opts['user']]:
4102 for k in [lower(x) for x in opts['user']]:
4103 if (k in luser):
4103 if (k in luser):
4104 break
4104 break
4105 else:
4105 else:
4106 return
4106 return
4107 if opts.get('keyword'):
4107 if opts.get('keyword'):
4108 luser = lower(ctx.user())
4108 luser = lower(ctx.user())
4109 ldesc = lower(ctx.description())
4109 ldesc = lower(ctx.description())
4110 lfiles = lower(" ".join(ctx.files()))
4110 lfiles = lower(" ".join(ctx.files()))
4111 for k in [lower(x) for x in opts['keyword']]:
4111 for k in [lower(x) for x in opts['keyword']]:
4112 if (k in luser or k in ldesc or k in lfiles):
4112 if (k in luser or k in ldesc or k in lfiles):
4113 break
4113 break
4114 else:
4114 else:
4115 return
4115 return
4116
4116
4117 copies = None
4117 copies = None
4118 if getrenamed is not None and rev:
4118 if getrenamed is not None and rev:
4119 copies = []
4119 copies = []
4120 for fn in ctx.files():
4120 for fn in ctx.files():
4121 rename = getrenamed(fn, rev)
4121 rename = getrenamed(fn, rev)
4122 if rename:
4122 if rename:
4123 copies.append((fn, rename[0]))
4123 copies.append((fn, rename[0]))
4124
4124
4125 revmatchfn = None
4125 revmatchfn = None
4126 if opts.get('patch') or opts.get('stat'):
4126 if opts.get('patch') or opts.get('stat'):
4127 if opts.get('follow') or opts.get('follow_first'):
4127 if opts.get('follow') or opts.get('follow_first'):
4128 # note: this might be wrong when following through merges
4128 # note: this might be wrong when following through merges
4129 revmatchfn = scmutil.match(repo[None], fns, default='path')
4129 revmatchfn = scmutil.match(repo[None], fns, default='path')
4130 else:
4130 else:
4131 revmatchfn = matchfn
4131 revmatchfn = matchfn
4132
4132
4133 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4133 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4134
4134
4135 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4135 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4136 if count == limit:
4136 if count == limit:
4137 break
4137 break
4138 if displayer.flush(ctx.rev()):
4138 if displayer.flush(ctx.rev()):
4139 count += 1
4139 count += 1
4140 displayer.close()
4140 displayer.close()
4141
4141
4142 @command('manifest',
4142 @command('manifest',
4143 [('r', 'rev', '', _('revision to display'), _('REV')),
4143 [('r', 'rev', '', _('revision to display'), _('REV')),
4144 ('', 'all', False, _("list files from all revisions"))],
4144 ('', 'all', False, _("list files from all revisions"))],
4145 _('[-r REV]'))
4145 _('[-r REV]'))
4146 def manifest(ui, repo, node=None, rev=None, **opts):
4146 def manifest(ui, repo, node=None, rev=None, **opts):
4147 """output the current or given revision of the project manifest
4147 """output the current or given revision of the project manifest
4148
4148
4149 Print a list of version controlled files for the given revision.
4149 Print a list of version controlled files for the given revision.
4150 If no revision is given, the first parent of the working directory
4150 If no revision is given, the first parent of the working directory
4151 is used, or the null revision if no revision is checked out.
4151 is used, or the null revision if no revision is checked out.
4152
4152
4153 With -v, print file permissions, symlink and executable bits.
4153 With -v, print file permissions, symlink and executable bits.
4154 With --debug, print file revision hashes.
4154 With --debug, print file revision hashes.
4155
4155
4156 If option --all is specified, the list of all files from all revisions
4156 If option --all is specified, the list of all files from all revisions
4157 is printed. This includes deleted and renamed files.
4157 is printed. This includes deleted and renamed files.
4158
4158
4159 Returns 0 on success.
4159 Returns 0 on success.
4160 """
4160 """
4161 if opts.get('all'):
4161 if opts.get('all'):
4162 if rev or node:
4162 if rev or node:
4163 raise util.Abort(_("can't specify a revision with --all"))
4163 raise util.Abort(_("can't specify a revision with --all"))
4164
4164
4165 res = []
4165 res = []
4166 prefix = "data/"
4166 prefix = "data/"
4167 suffix = ".i"
4167 suffix = ".i"
4168 plen = len(prefix)
4168 plen = len(prefix)
4169 slen = len(suffix)
4169 slen = len(suffix)
4170 lock = repo.lock()
4170 lock = repo.lock()
4171 try:
4171 try:
4172 for fn, b, size in repo.store.datafiles():
4172 for fn, b, size in repo.store.datafiles():
4173 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4173 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4174 res.append(fn[plen:-slen])
4174 res.append(fn[plen:-slen])
4175 finally:
4175 finally:
4176 lock.release()
4176 lock.release()
4177 for f in sorted(res):
4177 for f in sorted(res):
4178 ui.write("%s\n" % f)
4178 ui.write("%s\n" % f)
4179 return
4179 return
4180
4180
4181 if rev and node:
4181 if rev and node:
4182 raise util.Abort(_("please specify just one revision"))
4182 raise util.Abort(_("please specify just one revision"))
4183
4183
4184 if not node:
4184 if not node:
4185 node = rev
4185 node = rev
4186
4186
4187 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
4187 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
4188 ctx = scmutil.revsingle(repo, node)
4188 ctx = scmutil.revsingle(repo, node)
4189 for f in ctx:
4189 for f in ctx:
4190 if ui.debugflag:
4190 if ui.debugflag:
4191 ui.write("%40s " % hex(ctx.manifest()[f]))
4191 ui.write("%40s " % hex(ctx.manifest()[f]))
4192 if ui.verbose:
4192 if ui.verbose:
4193 ui.write(decor[ctx.flags(f)])
4193 ui.write(decor[ctx.flags(f)])
4194 ui.write("%s\n" % f)
4194 ui.write("%s\n" % f)
4195
4195
4196 @command('^merge',
4196 @command('^merge',
4197 [('f', 'force', None, _('force a merge with outstanding changes')),
4197 [('f', 'force', None, _('force a merge with outstanding changes')),
4198 ('r', 'rev', '', _('revision to merge'), _('REV')),
4198 ('r', 'rev', '', _('revision to merge'), _('REV')),
4199 ('P', 'preview', None,
4199 ('P', 'preview', None,
4200 _('review revisions to merge (no merge is performed)'))
4200 _('review revisions to merge (no merge is performed)'))
4201 ] + mergetoolopts,
4201 ] + mergetoolopts,
4202 _('[-P] [-f] [[-r] REV]'))
4202 _('[-P] [-f] [[-r] REV]'))
4203 def merge(ui, repo, node=None, **opts):
4203 def merge(ui, repo, node=None, **opts):
4204 """merge working directory with another revision
4204 """merge working directory with another revision
4205
4205
4206 The current working directory is updated with all changes made in
4206 The current working directory is updated with all changes made in
4207 the requested revision since the last common predecessor revision.
4207 the requested revision since the last common predecessor revision.
4208
4208
4209 Files that changed between either parent are marked as changed for
4209 Files that changed between either parent are marked as changed for
4210 the next commit and a commit must be performed before any further
4210 the next commit and a commit must be performed before any further
4211 updates to the repository are allowed. The next commit will have
4211 updates to the repository are allowed. The next commit will have
4212 two parents.
4212 two parents.
4213
4213
4214 ``--tool`` can be used to specify the merge tool used for file
4214 ``--tool`` can be used to specify the merge tool used for file
4215 merges. It overrides the HGMERGE environment variable and your
4215 merges. It overrides the HGMERGE environment variable and your
4216 configuration files. See :hg:`help merge-tools` for options.
4216 configuration files. See :hg:`help merge-tools` for options.
4217
4217
4218 If no revision is specified, the working directory's parent is a
4218 If no revision is specified, the working directory's parent is a
4219 head revision, and the current branch contains exactly one other
4219 head revision, and the current branch contains exactly one other
4220 head, the other head is merged with by default. Otherwise, an
4220 head, the other head is merged with by default. Otherwise, an
4221 explicit revision with which to merge with must be provided.
4221 explicit revision with which to merge with must be provided.
4222
4222
4223 :hg:`resolve` must be used to resolve unresolved files.
4223 :hg:`resolve` must be used to resolve unresolved files.
4224
4224
4225 To undo an uncommitted merge, use :hg:`update --clean .` which
4225 To undo an uncommitted merge, use :hg:`update --clean .` which
4226 will check out a clean copy of the original merge parent, losing
4226 will check out a clean copy of the original merge parent, losing
4227 all changes.
4227 all changes.
4228
4228
4229 Returns 0 on success, 1 if there are unresolved files.
4229 Returns 0 on success, 1 if there are unresolved files.
4230 """
4230 """
4231
4231
4232 if opts.get('rev') and node:
4232 if opts.get('rev') and node:
4233 raise util.Abort(_("please specify just one revision"))
4233 raise util.Abort(_("please specify just one revision"))
4234 if not node:
4234 if not node:
4235 node = opts.get('rev')
4235 node = opts.get('rev')
4236
4236
4237 if node:
4237 if node:
4238 node = scmutil.revsingle(repo, node).node()
4238 node = scmutil.revsingle(repo, node).node()
4239
4239
4240 if not node and repo._bookmarkcurrent:
4240 if not node and repo._bookmarkcurrent:
4241 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4241 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4242 curhead = repo[repo._bookmarkcurrent]
4242 curhead = repo[repo._bookmarkcurrent]
4243 if len(bmheads) == 2:
4243 if len(bmheads) == 2:
4244 if curhead == bmheads[0]:
4244 if curhead == bmheads[0]:
4245 node = bmheads[1]
4245 node = bmheads[1]
4246 else:
4246 else:
4247 node = bmheads[0]
4247 node = bmheads[0]
4248 elif len(bmheads) > 2:
4248 elif len(bmheads) > 2:
4249 raise util.Abort(_("multiple matching bookmarks to merge - "
4249 raise util.Abort(_("multiple matching bookmarks to merge - "
4250 "please merge with an explicit rev or bookmark"),
4250 "please merge with an explicit rev or bookmark"),
4251 hint=_("run 'hg heads' to see all heads"))
4251 hint=_("run 'hg heads' to see all heads"))
4252 elif len(bmheads) <= 1:
4252 elif len(bmheads) <= 1:
4253 raise util.Abort(_("no matching bookmark to merge - "
4253 raise util.Abort(_("no matching bookmark to merge - "
4254 "please merge with an explicit rev or bookmark"),
4254 "please merge with an explicit rev or bookmark"),
4255 hint=_("run 'hg heads' to see all heads"))
4255 hint=_("run 'hg heads' to see all heads"))
4256
4256
4257 if not node and not repo._bookmarkcurrent:
4257 if not node and not repo._bookmarkcurrent:
4258 branch = repo[None].branch()
4258 branch = repo[None].branch()
4259 bheads = repo.branchheads(branch)
4259 bheads = repo.branchheads(branch)
4260 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4260 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4261
4261
4262 if len(nbhs) > 2:
4262 if len(nbhs) > 2:
4263 raise util.Abort(_("branch '%s' has %d heads - "
4263 raise util.Abort(_("branch '%s' has %d heads - "
4264 "please merge with an explicit rev")
4264 "please merge with an explicit rev")
4265 % (branch, len(bheads)),
4265 % (branch, len(bheads)),
4266 hint=_("run 'hg heads .' to see heads"))
4266 hint=_("run 'hg heads .' to see heads"))
4267
4267
4268 parent = repo.dirstate.p1()
4268 parent = repo.dirstate.p1()
4269 if len(nbhs) == 1:
4269 if len(nbhs) == 1:
4270 if len(bheads) > 1:
4270 if len(bheads) > 1:
4271 raise util.Abort(_("heads are bookmarked - "
4271 raise util.Abort(_("heads are bookmarked - "
4272 "please merge with an explicit rev"),
4272 "please merge with an explicit rev"),
4273 hint=_("run 'hg heads' to see all heads"))
4273 hint=_("run 'hg heads' to see all heads"))
4274 if len(repo.heads()) > 1:
4274 if len(repo.heads()) > 1:
4275 raise util.Abort(_("branch '%s' has one head - "
4275 raise util.Abort(_("branch '%s' has one head - "
4276 "please merge with an explicit rev")
4276 "please merge with an explicit rev")
4277 % branch,
4277 % branch,
4278 hint=_("run 'hg heads' to see all heads"))
4278 hint=_("run 'hg heads' to see all heads"))
4279 msg, hint = _('nothing to merge'), None
4279 msg, hint = _('nothing to merge'), None
4280 if parent != repo.lookup(branch):
4280 if parent != repo.lookup(branch):
4281 hint = _("use 'hg update' instead")
4281 hint = _("use 'hg update' instead")
4282 raise util.Abort(msg, hint=hint)
4282 raise util.Abort(msg, hint=hint)
4283
4283
4284 if parent not in bheads:
4284 if parent not in bheads:
4285 raise util.Abort(_('working directory not at a head revision'),
4285 raise util.Abort(_('working directory not at a head revision'),
4286 hint=_("use 'hg update' or merge with an "
4286 hint=_("use 'hg update' or merge with an "
4287 "explicit revision"))
4287 "explicit revision"))
4288 if parent == nbhs[0]:
4288 if parent == nbhs[0]:
4289 node = nbhs[-1]
4289 node = nbhs[-1]
4290 else:
4290 else:
4291 node = nbhs[0]
4291 node = nbhs[0]
4292
4292
4293 if opts.get('preview'):
4293 if opts.get('preview'):
4294 # find nodes that are ancestors of p2 but not of p1
4294 # find nodes that are ancestors of p2 but not of p1
4295 p1 = repo.lookup('.')
4295 p1 = repo.lookup('.')
4296 p2 = repo.lookup(node)
4296 p2 = repo.lookup(node)
4297 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4297 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4298
4298
4299 displayer = cmdutil.show_changeset(ui, repo, opts)
4299 displayer = cmdutil.show_changeset(ui, repo, opts)
4300 for node in nodes:
4300 for node in nodes:
4301 displayer.show(repo[node])
4301 displayer.show(repo[node])
4302 displayer.close()
4302 displayer.close()
4303 return 0
4303 return 0
4304
4304
4305 try:
4305 try:
4306 # ui.forcemerge is an internal variable, do not document
4306 # ui.forcemerge is an internal variable, do not document
4307 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4307 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4308 return hg.merge(repo, node, force=opts.get('force'))
4308 return hg.merge(repo, node, force=opts.get('force'))
4309 finally:
4309 finally:
4310 ui.setconfig('ui', 'forcemerge', '')
4310 ui.setconfig('ui', 'forcemerge', '')
4311
4311
4312 @command('outgoing|out',
4312 @command('outgoing|out',
4313 [('f', 'force', None, _('run even when the destination is unrelated')),
4313 [('f', 'force', None, _('run even when the destination is unrelated')),
4314 ('r', 'rev', [],
4314 ('r', 'rev', [],
4315 _('a changeset intended to be included in the destination'), _('REV')),
4315 _('a changeset intended to be included in the destination'), _('REV')),
4316 ('n', 'newest-first', None, _('show newest record first')),
4316 ('n', 'newest-first', None, _('show newest record first')),
4317 ('B', 'bookmarks', False, _('compare bookmarks')),
4317 ('B', 'bookmarks', False, _('compare bookmarks')),
4318 ('b', 'branch', [], _('a specific branch you would like to push'),
4318 ('b', 'branch', [], _('a specific branch you would like to push'),
4319 _('BRANCH')),
4319 _('BRANCH')),
4320 ] + logopts + remoteopts + subrepoopts,
4320 ] + logopts + remoteopts + subrepoopts,
4321 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4321 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4322 def outgoing(ui, repo, dest=None, **opts):
4322 def outgoing(ui, repo, dest=None, **opts):
4323 """show changesets not found in the destination
4323 """show changesets not found in the destination
4324
4324
4325 Show changesets not found in the specified destination repository
4325 Show changesets not found in the specified destination repository
4326 or the default push location. These are the changesets that would
4326 or the default push location. These are the changesets that would
4327 be pushed if a push was requested.
4327 be pushed if a push was requested.
4328
4328
4329 See pull for details of valid destination formats.
4329 See pull for details of valid destination formats.
4330
4330
4331 Returns 0 if there are outgoing changes, 1 otherwise.
4331 Returns 0 if there are outgoing changes, 1 otherwise.
4332 """
4332 """
4333 if opts.get('graph'):
4333 if opts.get('graph'):
4334 cmdutil.checkunsupportedgraphflags([], opts)
4334 cmdutil.checkunsupportedgraphflags([], opts)
4335 o = hg._outgoing(ui, repo, dest, opts)
4335 o = hg._outgoing(ui, repo, dest, opts)
4336 if o is None:
4336 if o is None:
4337 return
4337 return
4338
4338
4339 revdag = cmdutil.graphrevs(repo, o, opts)
4339 revdag = cmdutil.graphrevs(repo, o, opts)
4340 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4340 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4341 showparents = [ctx.node() for ctx in repo[None].parents()]
4341 showparents = [ctx.node() for ctx in repo[None].parents()]
4342 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4342 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4343 graphmod.asciiedges)
4343 graphmod.asciiedges)
4344 return 0
4344 return 0
4345
4345
4346 if opts.get('bookmarks'):
4346 if opts.get('bookmarks'):
4347 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4347 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4348 dest, branches = hg.parseurl(dest, opts.get('branch'))
4348 dest, branches = hg.parseurl(dest, opts.get('branch'))
4349 other = hg.peer(repo, opts, dest)
4349 other = hg.peer(repo, opts, dest)
4350 if 'bookmarks' not in other.listkeys('namespaces'):
4350 if 'bookmarks' not in other.listkeys('namespaces'):
4351 ui.warn(_("remote doesn't support bookmarks\n"))
4351 ui.warn(_("remote doesn't support bookmarks\n"))
4352 return 0
4352 return 0
4353 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4353 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4354 return bookmarks.diff(ui, other, repo)
4354 return bookmarks.diff(ui, other, repo)
4355
4355
4356 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4356 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4357 try:
4357 try:
4358 return hg.outgoing(ui, repo, dest, opts)
4358 return hg.outgoing(ui, repo, dest, opts)
4359 finally:
4359 finally:
4360 del repo._subtoppath
4360 del repo._subtoppath
4361
4361
4362 @command('parents',
4362 @command('parents',
4363 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4363 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4364 ] + templateopts,
4364 ] + templateopts,
4365 _('[-r REV] [FILE]'))
4365 _('[-r REV] [FILE]'))
4366 def parents(ui, repo, file_=None, **opts):
4366 def parents(ui, repo, file_=None, **opts):
4367 """show the parents of the working directory or revision
4367 """show the parents of the working directory or revision
4368
4368
4369 Print the working directory's parent revisions. If a revision is
4369 Print the working directory's parent revisions. If a revision is
4370 given via -r/--rev, the parent of that revision will be printed.
4370 given via -r/--rev, the parent of that revision will be printed.
4371 If a file argument is given, the revision in which the file was
4371 If a file argument is given, the revision in which the file was
4372 last changed (before the working directory revision or the
4372 last changed (before the working directory revision or the
4373 argument to --rev if given) is printed.
4373 argument to --rev if given) is printed.
4374
4374
4375 Returns 0 on success.
4375 Returns 0 on success.
4376 """
4376 """
4377
4377
4378 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4378 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4379
4379
4380 if file_:
4380 if file_:
4381 m = scmutil.match(ctx, (file_,), opts)
4381 m = scmutil.match(ctx, (file_,), opts)
4382 if m.anypats() or len(m.files()) != 1:
4382 if m.anypats() or len(m.files()) != 1:
4383 raise util.Abort(_('can only specify an explicit filename'))
4383 raise util.Abort(_('can only specify an explicit filename'))
4384 file_ = m.files()[0]
4384 file_ = m.files()[0]
4385 filenodes = []
4385 filenodes = []
4386 for cp in ctx.parents():
4386 for cp in ctx.parents():
4387 if not cp:
4387 if not cp:
4388 continue
4388 continue
4389 try:
4389 try:
4390 filenodes.append(cp.filenode(file_))
4390 filenodes.append(cp.filenode(file_))
4391 except error.LookupError:
4391 except error.LookupError:
4392 pass
4392 pass
4393 if not filenodes:
4393 if not filenodes:
4394 raise util.Abort(_("'%s' not found in manifest!") % file_)
4394 raise util.Abort(_("'%s' not found in manifest!") % file_)
4395 fl = repo.file(file_)
4395 fl = repo.file(file_)
4396 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4396 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4397 else:
4397 else:
4398 p = [cp.node() for cp in ctx.parents()]
4398 p = [cp.node() for cp in ctx.parents()]
4399
4399
4400 displayer = cmdutil.show_changeset(ui, repo, opts)
4400 displayer = cmdutil.show_changeset(ui, repo, opts)
4401 for n in p:
4401 for n in p:
4402 if n != nullid:
4402 if n != nullid:
4403 displayer.show(repo[n])
4403 displayer.show(repo[n])
4404 displayer.close()
4404 displayer.close()
4405
4405
4406 @command('paths', [], _('[NAME]'))
4406 @command('paths', [], _('[NAME]'))
4407 def paths(ui, repo, search=None):
4407 def paths(ui, repo, search=None):
4408 """show aliases for remote repositories
4408 """show aliases for remote repositories
4409
4409
4410 Show definition of symbolic path name NAME. If no name is given,
4410 Show definition of symbolic path name NAME. If no name is given,
4411 show definition of all available names.
4411 show definition of all available names.
4412
4412
4413 Option -q/--quiet suppresses all output when searching for NAME
4413 Option -q/--quiet suppresses all output when searching for NAME
4414 and shows only the path names when listing all definitions.
4414 and shows only the path names when listing all definitions.
4415
4415
4416 Path names are defined in the [paths] section of your
4416 Path names are defined in the [paths] section of your
4417 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4417 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4418 repository, ``.hg/hgrc`` is used, too.
4418 repository, ``.hg/hgrc`` is used, too.
4419
4419
4420 The path names ``default`` and ``default-push`` have a special
4420 The path names ``default`` and ``default-push`` have a special
4421 meaning. When performing a push or pull operation, they are used
4421 meaning. When performing a push or pull operation, they are used
4422 as fallbacks if no location is specified on the command-line.
4422 as fallbacks if no location is specified on the command-line.
4423 When ``default-push`` is set, it will be used for push and
4423 When ``default-push`` is set, it will be used for push and
4424 ``default`` will be used for pull; otherwise ``default`` is used
4424 ``default`` will be used for pull; otherwise ``default`` is used
4425 as the fallback for both. When cloning a repository, the clone
4425 as the fallback for both. When cloning a repository, the clone
4426 source is written as ``default`` in ``.hg/hgrc``. Note that
4426 source is written as ``default`` in ``.hg/hgrc``. Note that
4427 ``default`` and ``default-push`` apply to all inbound (e.g.
4427 ``default`` and ``default-push`` apply to all inbound (e.g.
4428 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4428 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4429 :hg:`bundle`) operations.
4429 :hg:`bundle`) operations.
4430
4430
4431 See :hg:`help urls` for more information.
4431 See :hg:`help urls` for more information.
4432
4432
4433 Returns 0 on success.
4433 Returns 0 on success.
4434 """
4434 """
4435 if search:
4435 if search:
4436 for name, path in ui.configitems("paths"):
4436 for name, path in ui.configitems("paths"):
4437 if name == search:
4437 if name == search:
4438 ui.status("%s\n" % util.hidepassword(path))
4438 ui.status("%s\n" % util.hidepassword(path))
4439 return
4439 return
4440 if not ui.quiet:
4440 if not ui.quiet:
4441 ui.warn(_("not found!\n"))
4441 ui.warn(_("not found!\n"))
4442 return 1
4442 return 1
4443 else:
4443 else:
4444 for name, path in ui.configitems("paths"):
4444 for name, path in ui.configitems("paths"):
4445 if ui.quiet:
4445 if ui.quiet:
4446 ui.write("%s\n" % name)
4446 ui.write("%s\n" % name)
4447 else:
4447 else:
4448 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4448 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4449
4449
4450 @command('^phase',
4450 @command('^phase',
4451 [('p', 'public', False, _('set changeset phase to public')),
4451 [('p', 'public', False, _('set changeset phase to public')),
4452 ('d', 'draft', False, _('set changeset phase to draft')),
4452 ('d', 'draft', False, _('set changeset phase to draft')),
4453 ('s', 'secret', False, _('set changeset phase to secret')),
4453 ('s', 'secret', False, _('set changeset phase to secret')),
4454 ('f', 'force', False, _('allow to move boundary backward')),
4454 ('f', 'force', False, _('allow to move boundary backward')),
4455 ('r', 'rev', [], _('target revision'), _('REV')),
4455 ('r', 'rev', [], _('target revision'), _('REV')),
4456 ],
4456 ],
4457 _('[-p|-d|-s] [-f] [-r] REV...'))
4457 _('[-p|-d|-s] [-f] [-r] REV...'))
4458 def phase(ui, repo, *revs, **opts):
4458 def phase(ui, repo, *revs, **opts):
4459 """set or show the current phase name
4459 """set or show the current phase name
4460
4460
4461 With no argument, show the phase name of specified revisions.
4461 With no argument, show the phase name of specified revisions.
4462
4462
4463 With one of -p/--public, -d/--draft or -s/--secret, change the
4463 With one of -p/--public, -d/--draft or -s/--secret, change the
4464 phase value of the specified revisions.
4464 phase value of the specified revisions.
4465
4465
4466 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4466 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4467 lower phase to an higher phase. Phases are ordered as follows::
4467 lower phase to an higher phase. Phases are ordered as follows::
4468
4468
4469 public < draft < secret
4469 public < draft < secret
4470
4470
4471 Return 0 on success, 1 if no phases were changed or some could not
4471 Return 0 on success, 1 if no phases were changed or some could not
4472 be changed.
4472 be changed.
4473 """
4473 """
4474 # search for a unique phase argument
4474 # search for a unique phase argument
4475 targetphase = None
4475 targetphase = None
4476 for idx, name in enumerate(phases.phasenames):
4476 for idx, name in enumerate(phases.phasenames):
4477 if opts[name]:
4477 if opts[name]:
4478 if targetphase is not None:
4478 if targetphase is not None:
4479 raise util.Abort(_('only one phase can be specified'))
4479 raise util.Abort(_('only one phase can be specified'))
4480 targetphase = idx
4480 targetphase = idx
4481
4481
4482 # look for specified revision
4482 # look for specified revision
4483 revs = list(revs)
4483 revs = list(revs)
4484 revs.extend(opts['rev'])
4484 revs.extend(opts['rev'])
4485 if not revs:
4485 if not revs:
4486 raise util.Abort(_('no revisions specified'))
4486 raise util.Abort(_('no revisions specified'))
4487
4487
4488 revs = scmutil.revrange(repo, revs)
4488 revs = scmutil.revrange(repo, revs)
4489
4489
4490 lock = None
4490 lock = None
4491 ret = 0
4491 ret = 0
4492 if targetphase is None:
4492 if targetphase is None:
4493 # display
4493 # display
4494 for r in revs:
4494 for r in revs:
4495 ctx = repo[r]
4495 ctx = repo[r]
4496 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4496 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4497 else:
4497 else:
4498 lock = repo.lock()
4498 lock = repo.lock()
4499 try:
4499 try:
4500 # set phase
4500 # set phase
4501 if not revs:
4501 if not revs:
4502 raise util.Abort(_('empty revision set'))
4502 raise util.Abort(_('empty revision set'))
4503 nodes = [repo[r].node() for r in revs]
4503 nodes = [repo[r].node() for r in revs]
4504 olddata = repo._phasecache.getphaserevs(repo)[:]
4504 olddata = repo._phasecache.getphaserevs(repo)[:]
4505 phases.advanceboundary(repo, targetphase, nodes)
4505 phases.advanceboundary(repo, targetphase, nodes)
4506 if opts['force']:
4506 if opts['force']:
4507 phases.retractboundary(repo, targetphase, nodes)
4507 phases.retractboundary(repo, targetphase, nodes)
4508 finally:
4508 finally:
4509 lock.release()
4509 lock.release()
4510 newdata = repo._phasecache.getphaserevs(repo)
4510 newdata = repo._phasecache.getphaserevs(repo)
4511 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4511 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4512 rejected = [n for n in nodes
4512 rejected = [n for n in nodes
4513 if newdata[repo[n].rev()] < targetphase]
4513 if newdata[repo[n].rev()] < targetphase]
4514 if rejected:
4514 if rejected:
4515 ui.warn(_('cannot move %i changesets to a more permissive '
4515 ui.warn(_('cannot move %i changesets to a more permissive '
4516 'phase, use --force\n') % len(rejected))
4516 'phase, use --force\n') % len(rejected))
4517 ret = 1
4517 ret = 1
4518 if changes:
4518 if changes:
4519 msg = _('phase changed for %i changesets\n') % changes
4519 msg = _('phase changed for %i changesets\n') % changes
4520 if ret:
4520 if ret:
4521 ui.status(msg)
4521 ui.status(msg)
4522 else:
4522 else:
4523 ui.note(msg)
4523 ui.note(msg)
4524 else:
4524 else:
4525 ui.warn(_('no phases changed\n'))
4525 ui.warn(_('no phases changed\n'))
4526 ret = 1
4526 ret = 1
4527 return ret
4527 return ret
4528
4528
4529 def postincoming(ui, repo, modheads, optupdate, checkout):
4529 def postincoming(ui, repo, modheads, optupdate, checkout):
4530 if modheads == 0:
4530 if modheads == 0:
4531 return
4531 return
4532 if optupdate:
4532 if optupdate:
4533 movemarkfrom = repo['.'].node()
4533 movemarkfrom = repo['.'].node()
4534 try:
4534 try:
4535 ret = hg.update(repo, checkout)
4535 ret = hg.update(repo, checkout)
4536 except util.Abort, inst:
4536 except util.Abort, inst:
4537 ui.warn(_("not updating: %s\n") % str(inst))
4537 ui.warn(_("not updating: %s\n") % str(inst))
4538 return 0
4538 return 0
4539 if not ret and not checkout:
4539 if not ret and not checkout:
4540 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4540 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4541 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4541 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4542 return ret
4542 return ret
4543 if modheads > 1:
4543 if modheads > 1:
4544 currentbranchheads = len(repo.branchheads())
4544 currentbranchheads = len(repo.branchheads())
4545 if currentbranchheads == modheads:
4545 if currentbranchheads == modheads:
4546 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4546 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4547 elif currentbranchheads > 1:
4547 elif currentbranchheads > 1:
4548 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4548 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4549 "merge)\n"))
4549 "merge)\n"))
4550 else:
4550 else:
4551 ui.status(_("(run 'hg heads' to see heads)\n"))
4551 ui.status(_("(run 'hg heads' to see heads)\n"))
4552 else:
4552 else:
4553 ui.status(_("(run 'hg update' to get a working copy)\n"))
4553 ui.status(_("(run 'hg update' to get a working copy)\n"))
4554
4554
4555 @command('^pull',
4555 @command('^pull',
4556 [('u', 'update', None,
4556 [('u', 'update', None,
4557 _('update to new branch head if changesets were pulled')),
4557 _('update to new branch head if changesets were pulled')),
4558 ('f', 'force', None, _('run even when remote repository is unrelated')),
4558 ('f', 'force', None, _('run even when remote repository is unrelated')),
4559 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4559 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4560 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4560 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4561 ('b', 'branch', [], _('a specific branch you would like to pull'),
4561 ('b', 'branch', [], _('a specific branch you would like to pull'),
4562 _('BRANCH')),
4562 _('BRANCH')),
4563 ] + remoteopts,
4563 ] + remoteopts,
4564 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4564 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4565 def pull(ui, repo, source="default", **opts):
4565 def pull(ui, repo, source="default", **opts):
4566 """pull changes from the specified source
4566 """pull changes from the specified source
4567
4567
4568 Pull changes from a remote repository to a local one.
4568 Pull changes from a remote repository to a local one.
4569
4569
4570 This finds all changes from the repository at the specified path
4570 This finds all changes from the repository at the specified path
4571 or URL and adds them to a local repository (the current one unless
4571 or URL and adds them to a local repository (the current one unless
4572 -R is specified). By default, this does not update the copy of the
4572 -R is specified). By default, this does not update the copy of the
4573 project in the working directory.
4573 project in the working directory.
4574
4574
4575 Use :hg:`incoming` if you want to see what would have been added
4575 Use :hg:`incoming` if you want to see what would have been added
4576 by a pull at the time you issued this command. If you then decide
4576 by a pull at the time you issued this command. If you then decide
4577 to add those changes to the repository, you should use :hg:`pull
4577 to add those changes to the repository, you should use :hg:`pull
4578 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4578 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4579
4579
4580 If SOURCE is omitted, the 'default' path will be used.
4580 If SOURCE is omitted, the 'default' path will be used.
4581 See :hg:`help urls` for more information.
4581 See :hg:`help urls` for more information.
4582
4582
4583 Returns 0 on success, 1 if an update had unresolved files.
4583 Returns 0 on success, 1 if an update had unresolved files.
4584 """
4584 """
4585 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4585 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4586 other = hg.peer(repo, opts, source)
4586 other = hg.peer(repo, opts, source)
4587 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4587 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4588 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4588 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4589
4589
4590 if opts.get('bookmark'):
4590 if opts.get('bookmark'):
4591 if not revs:
4591 if not revs:
4592 revs = []
4592 revs = []
4593 rb = other.listkeys('bookmarks')
4593 rb = other.listkeys('bookmarks')
4594 for b in opts['bookmark']:
4594 for b in opts['bookmark']:
4595 if b not in rb:
4595 if b not in rb:
4596 raise util.Abort(_('remote bookmark %s not found!') % b)
4596 raise util.Abort(_('remote bookmark %s not found!') % b)
4597 revs.append(rb[b])
4597 revs.append(rb[b])
4598
4598
4599 if revs:
4599 if revs:
4600 try:
4600 try:
4601 revs = [other.lookup(rev) for rev in revs]
4601 revs = [other.lookup(rev) for rev in revs]
4602 except error.CapabilityError:
4602 except error.CapabilityError:
4603 err = _("other repository doesn't support revision lookup, "
4603 err = _("other repository doesn't support revision lookup, "
4604 "so a rev cannot be specified.")
4604 "so a rev cannot be specified.")
4605 raise util.Abort(err)
4605 raise util.Abort(err)
4606
4606
4607 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4607 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4608 bookmarks.updatefromremote(ui, repo, other, source)
4608 bookmarks.updatefromremote(ui, repo, other, source)
4609 if checkout:
4609 if checkout:
4610 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4610 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4611 repo._subtoppath = source
4611 repo._subtoppath = source
4612 try:
4612 try:
4613 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4613 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4614
4614
4615 finally:
4615 finally:
4616 del repo._subtoppath
4616 del repo._subtoppath
4617
4617
4618 # update specified bookmarks
4618 # update specified bookmarks
4619 if opts.get('bookmark'):
4619 if opts.get('bookmark'):
4620 for b in opts['bookmark']:
4620 for b in opts['bookmark']:
4621 # explicit pull overrides local bookmark if any
4621 # explicit pull overrides local bookmark if any
4622 ui.status(_("importing bookmark %s\n") % b)
4622 ui.status(_("importing bookmark %s\n") % b)
4623 repo._bookmarks[b] = repo[rb[b]].node()
4623 repo._bookmarks[b] = repo[rb[b]].node()
4624 bookmarks.write(repo)
4624 bookmarks.write(repo)
4625
4625
4626 return ret
4626 return ret
4627
4627
4628 @command('^push',
4628 @command('^push',
4629 [('f', 'force', None, _('force push')),
4629 [('f', 'force', None, _('force push')),
4630 ('r', 'rev', [],
4630 ('r', 'rev', [],
4631 _('a changeset intended to be included in the destination'),
4631 _('a changeset intended to be included in the destination'),
4632 _('REV')),
4632 _('REV')),
4633 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4633 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4634 ('b', 'branch', [],
4634 ('b', 'branch', [],
4635 _('a specific branch you would like to push'), _('BRANCH')),
4635 _('a specific branch you would like to push'), _('BRANCH')),
4636 ('', 'new-branch', False, _('allow pushing a new branch')),
4636 ('', 'new-branch', False, _('allow pushing a new branch')),
4637 ] + remoteopts,
4637 ] + remoteopts,
4638 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4638 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4639 def push(ui, repo, dest=None, **opts):
4639 def push(ui, repo, dest=None, **opts):
4640 """push changes to the specified destination
4640 """push changes to the specified destination
4641
4641
4642 Push changesets from the local repository to the specified
4642 Push changesets from the local repository to the specified
4643 destination.
4643 destination.
4644
4644
4645 This operation is symmetrical to pull: it is identical to a pull
4645 This operation is symmetrical to pull: it is identical to a pull
4646 in the destination repository from the current one.
4646 in the destination repository from the current one.
4647
4647
4648 By default, push will not allow creation of new heads at the
4648 By default, push will not allow creation of new heads at the
4649 destination, since multiple heads would make it unclear which head
4649 destination, since multiple heads would make it unclear which head
4650 to use. In this situation, it is recommended to pull and merge
4650 to use. In this situation, it is recommended to pull and merge
4651 before pushing.
4651 before pushing.
4652
4652
4653 Use --new-branch if you want to allow push to create a new named
4653 Use --new-branch if you want to allow push to create a new named
4654 branch that is not present at the destination. This allows you to
4654 branch that is not present at the destination. This allows you to
4655 only create a new branch without forcing other changes.
4655 only create a new branch without forcing other changes.
4656
4656
4657 Use -f/--force to override the default behavior and push all
4657 Use -f/--force to override the default behavior and push all
4658 changesets on all branches.
4658 changesets on all branches.
4659
4659
4660 If -r/--rev is used, the specified revision and all its ancestors
4660 If -r/--rev is used, the specified revision and all its ancestors
4661 will be pushed to the remote repository.
4661 will be pushed to the remote repository.
4662
4662
4663 If -B/--bookmark is used, the specified bookmarked revision, its
4663 If -B/--bookmark is used, the specified bookmarked revision, its
4664 ancestors, and the bookmark will be pushed to the remote
4664 ancestors, and the bookmark will be pushed to the remote
4665 repository.
4665 repository.
4666
4666
4667 Please see :hg:`help urls` for important details about ``ssh://``
4667 Please see :hg:`help urls` for important details about ``ssh://``
4668 URLs. If DESTINATION is omitted, a default path will be used.
4668 URLs. If DESTINATION is omitted, a default path will be used.
4669
4669
4670 Returns 0 if push was successful, 1 if nothing to push.
4670 Returns 0 if push was successful, 1 if nothing to push.
4671 """
4671 """
4672
4672
4673 if opts.get('bookmark'):
4673 if opts.get('bookmark'):
4674 for b in opts['bookmark']:
4674 for b in opts['bookmark']:
4675 # translate -B options to -r so changesets get pushed
4675 # translate -B options to -r so changesets get pushed
4676 if b in repo._bookmarks:
4676 if b in repo._bookmarks:
4677 opts.setdefault('rev', []).append(b)
4677 opts.setdefault('rev', []).append(b)
4678 else:
4678 else:
4679 # if we try to push a deleted bookmark, translate it to null
4679 # if we try to push a deleted bookmark, translate it to null
4680 # this lets simultaneous -r, -b options continue working
4680 # this lets simultaneous -r, -b options continue working
4681 opts.setdefault('rev', []).append("null")
4681 opts.setdefault('rev', []).append("null")
4682
4682
4683 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4683 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4684 dest, branches = hg.parseurl(dest, opts.get('branch'))
4684 dest, branches = hg.parseurl(dest, opts.get('branch'))
4685 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4685 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4686 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4686 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4687 other = hg.peer(repo, opts, dest)
4687 other = hg.peer(repo, opts, dest)
4688 if revs:
4688 if revs:
4689 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4689 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4690
4690
4691 repo._subtoppath = dest
4691 repo._subtoppath = dest
4692 try:
4692 try:
4693 # push subrepos depth-first for coherent ordering
4693 # push subrepos depth-first for coherent ordering
4694 c = repo['']
4694 c = repo['']
4695 subs = c.substate # only repos that are committed
4695 subs = c.substate # only repos that are committed
4696 for s in sorted(subs):
4696 for s in sorted(subs):
4697 if c.sub(s).push(opts) == 0:
4697 if c.sub(s).push(opts) == 0:
4698 return False
4698 return False
4699 finally:
4699 finally:
4700 del repo._subtoppath
4700 del repo._subtoppath
4701 result = repo.push(other, opts.get('force'), revs=revs,
4701 result = repo.push(other, opts.get('force'), revs=revs,
4702 newbranch=opts.get('new_branch'))
4702 newbranch=opts.get('new_branch'))
4703
4703
4704 result = not result
4704 result = not result
4705
4705
4706 if opts.get('bookmark'):
4706 if opts.get('bookmark'):
4707 rb = other.listkeys('bookmarks')
4707 rb = other.listkeys('bookmarks')
4708 for b in opts['bookmark']:
4708 for b in opts['bookmark']:
4709 # explicit push overrides remote bookmark if any
4709 # explicit push overrides remote bookmark if any
4710 if b in repo._bookmarks:
4710 if b in repo._bookmarks:
4711 ui.status(_("exporting bookmark %s\n") % b)
4711 ui.status(_("exporting bookmark %s\n") % b)
4712 new = repo[b].hex()
4712 new = repo[b].hex()
4713 elif b in rb:
4713 elif b in rb:
4714 ui.status(_("deleting remote bookmark %s\n") % b)
4714 ui.status(_("deleting remote bookmark %s\n") % b)
4715 new = '' # delete
4715 new = '' # delete
4716 else:
4716 else:
4717 ui.warn(_('bookmark %s does not exist on the local '
4717 ui.warn(_('bookmark %s does not exist on the local '
4718 'or remote repository!\n') % b)
4718 'or remote repository!\n') % b)
4719 return 2
4719 return 2
4720 old = rb.get(b, '')
4720 old = rb.get(b, '')
4721 r = other.pushkey('bookmarks', b, old, new)
4721 r = other.pushkey('bookmarks', b, old, new)
4722 if not r:
4722 if not r:
4723 ui.warn(_('updating bookmark %s failed!\n') % b)
4723 ui.warn(_('updating bookmark %s failed!\n') % b)
4724 if not result:
4724 if not result:
4725 result = 2
4725 result = 2
4726
4726
4727 return result
4727 return result
4728
4728
4729 @command('recover', [])
4729 @command('recover', [])
4730 def recover(ui, repo):
4730 def recover(ui, repo):
4731 """roll back an interrupted transaction
4731 """roll back an interrupted transaction
4732
4732
4733 Recover from an interrupted commit or pull.
4733 Recover from an interrupted commit or pull.
4734
4734
4735 This command tries to fix the repository status after an
4735 This command tries to fix the repository status after an
4736 interrupted operation. It should only be necessary when Mercurial
4736 interrupted operation. It should only be necessary when Mercurial
4737 suggests it.
4737 suggests it.
4738
4738
4739 Returns 0 if successful, 1 if nothing to recover or verify fails.
4739 Returns 0 if successful, 1 if nothing to recover or verify fails.
4740 """
4740 """
4741 if repo.recover():
4741 if repo.recover():
4742 return hg.verify(repo)
4742 return hg.verify(repo)
4743 return 1
4743 return 1
4744
4744
4745 @command('^remove|rm',
4745 @command('^remove|rm',
4746 [('A', 'after', None, _('record delete for missing files')),
4746 [('A', 'after', None, _('record delete for missing files')),
4747 ('f', 'force', None,
4747 ('f', 'force', None,
4748 _('remove (and delete) file even if added or modified')),
4748 _('remove (and delete) file even if added or modified')),
4749 ] + walkopts,
4749 ] + walkopts,
4750 _('[OPTION]... FILE...'))
4750 _('[OPTION]... FILE...'))
4751 def remove(ui, repo, *pats, **opts):
4751 def remove(ui, repo, *pats, **opts):
4752 """remove the specified files on the next commit
4752 """remove the specified files on the next commit
4753
4753
4754 Schedule the indicated files for removal from the current branch.
4754 Schedule the indicated files for removal from the current branch.
4755
4755
4756 This command schedules the files to be removed at the next commit.
4756 This command schedules the files to be removed at the next commit.
4757 To undo a remove before that, see :hg:`revert`. To undo added
4757 To undo a remove before that, see :hg:`revert`. To undo added
4758 files, see :hg:`forget`.
4758 files, see :hg:`forget`.
4759
4759
4760 .. container:: verbose
4760 .. container:: verbose
4761
4761
4762 -A/--after can be used to remove only files that have already
4762 -A/--after can be used to remove only files that have already
4763 been deleted, -f/--force can be used to force deletion, and -Af
4763 been deleted, -f/--force can be used to force deletion, and -Af
4764 can be used to remove files from the next revision without
4764 can be used to remove files from the next revision without
4765 deleting them from the working directory.
4765 deleting them from the working directory.
4766
4766
4767 The following table details the behavior of remove for different
4767 The following table details the behavior of remove for different
4768 file states (columns) and option combinations (rows). The file
4768 file states (columns) and option combinations (rows). The file
4769 states are Added [A], Clean [C], Modified [M] and Missing [!]
4769 states are Added [A], Clean [C], Modified [M] and Missing [!]
4770 (as reported by :hg:`status`). The actions are Warn, Remove
4770 (as reported by :hg:`status`). The actions are Warn, Remove
4771 (from branch) and Delete (from disk):
4771 (from branch) and Delete (from disk):
4772
4772
4773 ======= == == == ==
4773 ======= == == == ==
4774 A C M !
4774 A C M !
4775 ======= == == == ==
4775 ======= == == == ==
4776 none W RD W R
4776 none W RD W R
4777 -f R RD RD R
4777 -f R RD RD R
4778 -A W W W R
4778 -A W W W R
4779 -Af R R R R
4779 -Af R R R R
4780 ======= == == == ==
4780 ======= == == == ==
4781
4781
4782 Note that remove never deletes files in Added [A] state from the
4782 Note that remove never deletes files in Added [A] state from the
4783 working directory, not even if option --force is specified.
4783 working directory, not even if option --force is specified.
4784
4784
4785 Returns 0 on success, 1 if any warnings encountered.
4785 Returns 0 on success, 1 if any warnings encountered.
4786 """
4786 """
4787
4787
4788 ret = 0
4788 ret = 0
4789 after, force = opts.get('after'), opts.get('force')
4789 after, force = opts.get('after'), opts.get('force')
4790 if not pats and not after:
4790 if not pats and not after:
4791 raise util.Abort(_('no files specified'))
4791 raise util.Abort(_('no files specified'))
4792
4792
4793 m = scmutil.match(repo[None], pats, opts)
4793 m = scmutil.match(repo[None], pats, opts)
4794 s = repo.status(match=m, clean=True)
4794 s = repo.status(match=m, clean=True)
4795 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4795 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4796
4796
4797 for f in m.files():
4797 for f in m.files():
4798 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4798 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4799 if os.path.exists(m.rel(f)):
4799 if os.path.exists(m.rel(f)):
4800 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4800 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4801 ret = 1
4801 ret = 1
4802
4802
4803 if force:
4803 if force:
4804 list = modified + deleted + clean + added
4804 list = modified + deleted + clean + added
4805 elif after:
4805 elif after:
4806 list = deleted
4806 list = deleted
4807 for f in modified + added + clean:
4807 for f in modified + added + clean:
4808 ui.warn(_('not removing %s: file still exists (use -f'
4808 ui.warn(_('not removing %s: file still exists (use -f'
4809 ' to force removal)\n') % m.rel(f))
4809 ' to force removal)\n') % m.rel(f))
4810 ret = 1
4810 ret = 1
4811 else:
4811 else:
4812 list = deleted + clean
4812 list = deleted + clean
4813 for f in modified:
4813 for f in modified:
4814 ui.warn(_('not removing %s: file is modified (use -f'
4814 ui.warn(_('not removing %s: file is modified (use -f'
4815 ' to force removal)\n') % m.rel(f))
4815 ' to force removal)\n') % m.rel(f))
4816 ret = 1
4816 ret = 1
4817 for f in added:
4817 for f in added:
4818 ui.warn(_('not removing %s: file has been marked for add'
4818 ui.warn(_('not removing %s: file has been marked for add'
4819 ' (use forget to undo)\n') % m.rel(f))
4819 ' (use forget to undo)\n') % m.rel(f))
4820 ret = 1
4820 ret = 1
4821
4821
4822 for f in sorted(list):
4822 for f in sorted(list):
4823 if ui.verbose or not m.exact(f):
4823 if ui.verbose or not m.exact(f):
4824 ui.status(_('removing %s\n') % m.rel(f))
4824 ui.status(_('removing %s\n') % m.rel(f))
4825
4825
4826 wlock = repo.wlock()
4826 wlock = repo.wlock()
4827 try:
4827 try:
4828 if not after:
4828 if not after:
4829 for f in list:
4829 for f in list:
4830 if f in added:
4830 if f in added:
4831 continue # we never unlink added files on remove
4831 continue # we never unlink added files on remove
4832 try:
4832 try:
4833 util.unlinkpath(repo.wjoin(f))
4833 util.unlinkpath(repo.wjoin(f))
4834 except OSError, inst:
4834 except OSError, inst:
4835 if inst.errno != errno.ENOENT:
4835 if inst.errno != errno.ENOENT:
4836 raise
4836 raise
4837 repo[None].forget(list)
4837 repo[None].forget(list)
4838 finally:
4838 finally:
4839 wlock.release()
4839 wlock.release()
4840
4840
4841 return ret
4841 return ret
4842
4842
4843 @command('rename|move|mv',
4843 @command('rename|move|mv',
4844 [('A', 'after', None, _('record a rename that has already occurred')),
4844 [('A', 'after', None, _('record a rename that has already occurred')),
4845 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4845 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4846 ] + walkopts + dryrunopts,
4846 ] + walkopts + dryrunopts,
4847 _('[OPTION]... SOURCE... DEST'))
4847 _('[OPTION]... SOURCE... DEST'))
4848 def rename(ui, repo, *pats, **opts):
4848 def rename(ui, repo, *pats, **opts):
4849 """rename files; equivalent of copy + remove
4849 """rename files; equivalent of copy + remove
4850
4850
4851 Mark dest as copies of sources; mark sources for deletion. If dest
4851 Mark dest as copies of sources; mark sources for deletion. If dest
4852 is a directory, copies are put in that directory. If dest is a
4852 is a directory, copies are put in that directory. If dest is a
4853 file, there can only be one source.
4853 file, there can only be one source.
4854
4854
4855 By default, this command copies the contents of files as they
4855 By default, this command copies the contents of files as they
4856 exist in the working directory. If invoked with -A/--after, the
4856 exist in the working directory. If invoked with -A/--after, the
4857 operation is recorded, but no copying is performed.
4857 operation is recorded, but no copying is performed.
4858
4858
4859 This command takes effect at the next commit. To undo a rename
4859 This command takes effect at the next commit. To undo a rename
4860 before that, see :hg:`revert`.
4860 before that, see :hg:`revert`.
4861
4861
4862 Returns 0 on success, 1 if errors are encountered.
4862 Returns 0 on success, 1 if errors are encountered.
4863 """
4863 """
4864 wlock = repo.wlock(False)
4864 wlock = repo.wlock(False)
4865 try:
4865 try:
4866 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4866 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4867 finally:
4867 finally:
4868 wlock.release()
4868 wlock.release()
4869
4869
4870 @command('resolve',
4870 @command('resolve',
4871 [('a', 'all', None, _('select all unresolved files')),
4871 [('a', 'all', None, _('select all unresolved files')),
4872 ('l', 'list', None, _('list state of files needing merge')),
4872 ('l', 'list', None, _('list state of files needing merge')),
4873 ('m', 'mark', None, _('mark files as resolved')),
4873 ('m', 'mark', None, _('mark files as resolved')),
4874 ('u', 'unmark', None, _('mark files as unresolved')),
4874 ('u', 'unmark', None, _('mark files as unresolved')),
4875 ('n', 'no-status', None, _('hide status prefix'))]
4875 ('n', 'no-status', None, _('hide status prefix'))]
4876 + mergetoolopts + walkopts,
4876 + mergetoolopts + walkopts,
4877 _('[OPTION]... [FILE]...'))
4877 _('[OPTION]... [FILE]...'))
4878 def resolve(ui, repo, *pats, **opts):
4878 def resolve(ui, repo, *pats, **opts):
4879 """redo merges or set/view the merge status of files
4879 """redo merges or set/view the merge status of files
4880
4880
4881 Merges with unresolved conflicts are often the result of
4881 Merges with unresolved conflicts are often the result of
4882 non-interactive merging using the ``internal:merge`` configuration
4882 non-interactive merging using the ``internal:merge`` configuration
4883 setting, or a command-line merge tool like ``diff3``. The resolve
4883 setting, or a command-line merge tool like ``diff3``. The resolve
4884 command is used to manage the files involved in a merge, after
4884 command is used to manage the files involved in a merge, after
4885 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4885 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4886 working directory must have two parents). See :hg:`help
4886 working directory must have two parents). See :hg:`help
4887 merge-tools` for information on configuring merge tools.
4887 merge-tools` for information on configuring merge tools.
4888
4888
4889 The resolve command can be used in the following ways:
4889 The resolve command can be used in the following ways:
4890
4890
4891 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4891 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4892 files, discarding any previous merge attempts. Re-merging is not
4892 files, discarding any previous merge attempts. Re-merging is not
4893 performed for files already marked as resolved. Use ``--all/-a``
4893 performed for files already marked as resolved. Use ``--all/-a``
4894 to select all unresolved files. ``--tool`` can be used to specify
4894 to select all unresolved files. ``--tool`` can be used to specify
4895 the merge tool used for the given files. It overrides the HGMERGE
4895 the merge tool used for the given files. It overrides the HGMERGE
4896 environment variable and your configuration files. Previous file
4896 environment variable and your configuration files. Previous file
4897 contents are saved with a ``.orig`` suffix.
4897 contents are saved with a ``.orig`` suffix.
4898
4898
4899 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4899 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4900 (e.g. after having manually fixed-up the files). The default is
4900 (e.g. after having manually fixed-up the files). The default is
4901 to mark all unresolved files.
4901 to mark all unresolved files.
4902
4902
4903 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4903 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4904 default is to mark all resolved files.
4904 default is to mark all resolved files.
4905
4905
4906 - :hg:`resolve -l`: list files which had or still have conflicts.
4906 - :hg:`resolve -l`: list files which had or still have conflicts.
4907 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4907 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4908
4908
4909 Note that Mercurial will not let you commit files with unresolved
4909 Note that Mercurial will not let you commit files with unresolved
4910 merge conflicts. You must use :hg:`resolve -m ...` before you can
4910 merge conflicts. You must use :hg:`resolve -m ...` before you can
4911 commit after a conflicting merge.
4911 commit after a conflicting merge.
4912
4912
4913 Returns 0 on success, 1 if any files fail a resolve attempt.
4913 Returns 0 on success, 1 if any files fail a resolve attempt.
4914 """
4914 """
4915
4915
4916 all, mark, unmark, show, nostatus = \
4916 all, mark, unmark, show, nostatus = \
4917 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4917 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4918
4918
4919 if (show and (mark or unmark)) or (mark and unmark):
4919 if (show and (mark or unmark)) or (mark and unmark):
4920 raise util.Abort(_("too many options specified"))
4920 raise util.Abort(_("too many options specified"))
4921 if pats and all:
4921 if pats and all:
4922 raise util.Abort(_("can't specify --all and patterns"))
4922 raise util.Abort(_("can't specify --all and patterns"))
4923 if not (all or pats or show or mark or unmark):
4923 if not (all or pats or show or mark or unmark):
4924 raise util.Abort(_('no files or directories specified; '
4924 raise util.Abort(_('no files or directories specified; '
4925 'use --all to remerge all files'))
4925 'use --all to remerge all files'))
4926
4926
4927 ms = mergemod.mergestate(repo)
4927 ms = mergemod.mergestate(repo)
4928 m = scmutil.match(repo[None], pats, opts)
4928 m = scmutil.match(repo[None], pats, opts)
4929 ret = 0
4929 ret = 0
4930
4930
4931 for f in ms:
4931 for f in ms:
4932 if m(f):
4932 if m(f):
4933 if show:
4933 if show:
4934 if nostatus:
4934 if nostatus:
4935 ui.write("%s\n" % f)
4935 ui.write("%s\n" % f)
4936 else:
4936 else:
4937 ui.write("%s %s\n" % (ms[f].upper(), f),
4937 ui.write("%s %s\n" % (ms[f].upper(), f),
4938 label='resolve.' +
4938 label='resolve.' +
4939 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4939 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4940 elif mark:
4940 elif mark:
4941 ms.mark(f, "r")
4941 ms.mark(f, "r")
4942 elif unmark:
4942 elif unmark:
4943 ms.mark(f, "u")
4943 ms.mark(f, "u")
4944 else:
4944 else:
4945 wctx = repo[None]
4945 wctx = repo[None]
4946 mctx = wctx.parents()[-1]
4946 mctx = wctx.parents()[-1]
4947
4947
4948 # backup pre-resolve (merge uses .orig for its own purposes)
4948 # backup pre-resolve (merge uses .orig for its own purposes)
4949 a = repo.wjoin(f)
4949 a = repo.wjoin(f)
4950 util.copyfile(a, a + ".resolve")
4950 util.copyfile(a, a + ".resolve")
4951
4951
4952 try:
4952 try:
4953 # resolve file
4953 # resolve file
4954 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4954 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4955 if ms.resolve(f, wctx, mctx):
4955 if ms.resolve(f, wctx, mctx):
4956 ret = 1
4956 ret = 1
4957 finally:
4957 finally:
4958 ui.setconfig('ui', 'forcemerge', '')
4958 ui.setconfig('ui', 'forcemerge', '')
4959
4959
4960 # replace filemerge's .orig file with our resolve file
4960 # replace filemerge's .orig file with our resolve file
4961 util.rename(a + ".resolve", a + ".orig")
4961 util.rename(a + ".resolve", a + ".orig")
4962
4962
4963 ms.commit()
4963 ms.commit()
4964 return ret
4964 return ret
4965
4965
4966 @command('revert',
4966 @command('revert',
4967 [('a', 'all', None, _('revert all changes when no arguments given')),
4967 [('a', 'all', None, _('revert all changes when no arguments given')),
4968 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4968 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4969 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4969 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4970 ('C', 'no-backup', None, _('do not save backup copies of files')),
4970 ('C', 'no-backup', None, _('do not save backup copies of files')),
4971 ] + walkopts + dryrunopts,
4971 ] + walkopts + dryrunopts,
4972 _('[OPTION]... [-r REV] [NAME]...'))
4972 _('[OPTION]... [-r REV] [NAME]...'))
4973 def revert(ui, repo, *pats, **opts):
4973 def revert(ui, repo, *pats, **opts):
4974 """restore files to their checkout state
4974 """restore files to their checkout state
4975
4975
4976 .. note::
4976 .. note::
4977
4977
4978 To check out earlier revisions, you should use :hg:`update REV`.
4978 To check out earlier revisions, you should use :hg:`update REV`.
4979 To cancel an uncommitted merge (and lose your changes), use
4979 To cancel an uncommitted merge (and lose your changes), use
4980 :hg:`update --clean .`.
4980 :hg:`update --clean .`.
4981
4981
4982 With no revision specified, revert the specified files or directories
4982 With no revision specified, revert the specified files or directories
4983 to the contents they had in the parent of the working directory.
4983 to the contents they had in the parent of the working directory.
4984 This restores the contents of files to an unmodified
4984 This restores the contents of files to an unmodified
4985 state and unschedules adds, removes, copies, and renames. If the
4985 state and unschedules adds, removes, copies, and renames. If the
4986 working directory has two parents, you must explicitly specify a
4986 working directory has two parents, you must explicitly specify a
4987 revision.
4987 revision.
4988
4988
4989 Using the -r/--rev or -d/--date options, revert the given files or
4989 Using the -r/--rev or -d/--date options, revert the given files or
4990 directories to their states as of a specific revision. Because
4990 directories to their states as of a specific revision. Because
4991 revert does not change the working directory parents, this will
4991 revert does not change the working directory parents, this will
4992 cause these files to appear modified. This can be helpful to "back
4992 cause these files to appear modified. This can be helpful to "back
4993 out" some or all of an earlier change. See :hg:`backout` for a
4993 out" some or all of an earlier change. See :hg:`backout` for a
4994 related method.
4994 related method.
4995
4995
4996 Modified files are saved with a .orig suffix before reverting.
4996 Modified files are saved with a .orig suffix before reverting.
4997 To disable these backups, use --no-backup.
4997 To disable these backups, use --no-backup.
4998
4998
4999 See :hg:`help dates` for a list of formats valid for -d/--date.
4999 See :hg:`help dates` for a list of formats valid for -d/--date.
5000
5000
5001 Returns 0 on success.
5001 Returns 0 on success.
5002 """
5002 """
5003
5003
5004 if opts.get("date"):
5004 if opts.get("date"):
5005 if opts.get("rev"):
5005 if opts.get("rev"):
5006 raise util.Abort(_("you can't specify a revision and a date"))
5006 raise util.Abort(_("you can't specify a revision and a date"))
5007 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5007 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5008
5008
5009 parent, p2 = repo.dirstate.parents()
5009 parent, p2 = repo.dirstate.parents()
5010 if not opts.get('rev') and p2 != nullid:
5010 if not opts.get('rev') and p2 != nullid:
5011 # revert after merge is a trap for new users (issue2915)
5011 # revert after merge is a trap for new users (issue2915)
5012 raise util.Abort(_('uncommitted merge with no revision specified'),
5012 raise util.Abort(_('uncommitted merge with no revision specified'),
5013 hint=_('use "hg update" or see "hg help revert"'))
5013 hint=_('use "hg update" or see "hg help revert"'))
5014
5014
5015 ctx = scmutil.revsingle(repo, opts.get('rev'))
5015 ctx = scmutil.revsingle(repo, opts.get('rev'))
5016
5016
5017 if not pats and not opts.get('all'):
5017 if not pats and not opts.get('all'):
5018 msg = _("no files or directories specified")
5018 msg = _("no files or directories specified")
5019 if p2 != nullid:
5019 if p2 != nullid:
5020 hint = _("uncommitted merge, use --all to discard all changes,"
5020 hint = _("uncommitted merge, use --all to discard all changes,"
5021 " or 'hg update -C .' to abort the merge")
5021 " or 'hg update -C .' to abort the merge")
5022 raise util.Abort(msg, hint=hint)
5022 raise util.Abort(msg, hint=hint)
5023 dirty = util.any(repo.status())
5023 dirty = util.any(repo.status())
5024 node = ctx.node()
5024 node = ctx.node()
5025 if node != parent:
5025 if node != parent:
5026 if dirty:
5026 if dirty:
5027 hint = _("uncommitted changes, use --all to discard all"
5027 hint = _("uncommitted changes, use --all to discard all"
5028 " changes, or 'hg update %s' to update") % ctx.rev()
5028 " changes, or 'hg update %s' to update") % ctx.rev()
5029 else:
5029 else:
5030 hint = _("use --all to revert all files,"
5030 hint = _("use --all to revert all files,"
5031 " or 'hg update %s' to update") % ctx.rev()
5031 " or 'hg update %s' to update") % ctx.rev()
5032 elif dirty:
5032 elif dirty:
5033 hint = _("uncommitted changes, use --all to discard all changes")
5033 hint = _("uncommitted changes, use --all to discard all changes")
5034 else:
5034 else:
5035 hint = _("use --all to revert all files")
5035 hint = _("use --all to revert all files")
5036 raise util.Abort(msg, hint=hint)
5036 raise util.Abort(msg, hint=hint)
5037
5037
5038 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5038 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5039
5039
5040 @command('rollback', dryrunopts +
5040 @command('rollback', dryrunopts +
5041 [('f', 'force', False, _('ignore safety measures'))])
5041 [('f', 'force', False, _('ignore safety measures'))])
5042 def rollback(ui, repo, **opts):
5042 def rollback(ui, repo, **opts):
5043 """roll back the last transaction (dangerous)
5043 """roll back the last transaction (dangerous)
5044
5044
5045 This command should be used with care. There is only one level of
5045 This command should be used with care. There is only one level of
5046 rollback, and there is no way to undo a rollback. It will also
5046 rollback, and there is no way to undo a rollback. It will also
5047 restore the dirstate at the time of the last transaction, losing
5047 restore the dirstate at the time of the last transaction, losing
5048 any dirstate changes since that time. This command does not alter
5048 any dirstate changes since that time. This command does not alter
5049 the working directory.
5049 the working directory.
5050
5050
5051 Transactions are used to encapsulate the effects of all commands
5051 Transactions are used to encapsulate the effects of all commands
5052 that create new changesets or propagate existing changesets into a
5052 that create new changesets or propagate existing changesets into a
5053 repository.
5053 repository.
5054
5054
5055 .. container:: verbose
5055 .. container:: verbose
5056
5056
5057 For example, the following commands are transactional, and their
5057 For example, the following commands are transactional, and their
5058 effects can be rolled back:
5058 effects can be rolled back:
5059
5059
5060 - commit
5060 - commit
5061 - import
5061 - import
5062 - pull
5062 - pull
5063 - push (with this repository as the destination)
5063 - push (with this repository as the destination)
5064 - unbundle
5064 - unbundle
5065
5065
5066 To avoid permanent data loss, rollback will refuse to rollback a
5066 To avoid permanent data loss, rollback will refuse to rollback a
5067 commit transaction if it isn't checked out. Use --force to
5067 commit transaction if it isn't checked out. Use --force to
5068 override this protection.
5068 override this protection.
5069
5069
5070 This command is not intended for use on public repositories. Once
5070 This command is not intended for use on public repositories. Once
5071 changes are visible for pull by other users, rolling a transaction
5071 changes are visible for pull by other users, rolling a transaction
5072 back locally is ineffective (someone else may already have pulled
5072 back locally is ineffective (someone else may already have pulled
5073 the changes). Furthermore, a race is possible with readers of the
5073 the changes). Furthermore, a race is possible with readers of the
5074 repository; for example an in-progress pull from the repository
5074 repository; for example an in-progress pull from the repository
5075 may fail if a rollback is performed.
5075 may fail if a rollback is performed.
5076
5076
5077 Returns 0 on success, 1 if no rollback data is available.
5077 Returns 0 on success, 1 if no rollback data is available.
5078 """
5078 """
5079 return repo.rollback(dryrun=opts.get('dry_run'),
5079 return repo.rollback(dryrun=opts.get('dry_run'),
5080 force=opts.get('force'))
5080 force=opts.get('force'))
5081
5081
5082 @command('root', [])
5082 @command('root', [])
5083 def root(ui, repo):
5083 def root(ui, repo):
5084 """print the root (top) of the current working directory
5084 """print the root (top) of the current working directory
5085
5085
5086 Print the root directory of the current repository.
5086 Print the root directory of the current repository.
5087
5087
5088 Returns 0 on success.
5088 Returns 0 on success.
5089 """
5089 """
5090 ui.write(repo.root + "\n")
5090 ui.write(repo.root + "\n")
5091
5091
5092 @command('^serve',
5092 @command('^serve',
5093 [('A', 'accesslog', '', _('name of access log file to write to'),
5093 [('A', 'accesslog', '', _('name of access log file to write to'),
5094 _('FILE')),
5094 _('FILE')),
5095 ('d', 'daemon', None, _('run server in background')),
5095 ('d', 'daemon', None, _('run server in background')),
5096 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5096 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5097 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5097 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5098 # use string type, then we can check if something was passed
5098 # use string type, then we can check if something was passed
5099 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5099 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5100 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5100 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5101 _('ADDR')),
5101 _('ADDR')),
5102 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5102 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5103 _('PREFIX')),
5103 _('PREFIX')),
5104 ('n', 'name', '',
5104 ('n', 'name', '',
5105 _('name to show in web pages (default: working directory)'), _('NAME')),
5105 _('name to show in web pages (default: working directory)'), _('NAME')),
5106 ('', 'web-conf', '',
5106 ('', 'web-conf', '',
5107 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5107 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5108 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5108 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5109 _('FILE')),
5109 _('FILE')),
5110 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5110 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5111 ('', 'stdio', None, _('for remote clients')),
5111 ('', 'stdio', None, _('for remote clients')),
5112 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5112 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5113 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5113 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5114 ('', 'style', '', _('template style to use'), _('STYLE')),
5114 ('', 'style', '', _('template style to use'), _('STYLE')),
5115 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5115 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5116 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5116 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5117 _('[OPTION]...'))
5117 _('[OPTION]...'))
5118 def serve(ui, repo, **opts):
5118 def serve(ui, repo, **opts):
5119 """start stand-alone webserver
5119 """start stand-alone webserver
5120
5120
5121 Start a local HTTP repository browser and pull server. You can use
5121 Start a local HTTP repository browser and pull server. You can use
5122 this for ad-hoc sharing and browsing of repositories. It is
5122 this for ad-hoc sharing and browsing of repositories. It is
5123 recommended to use a real web server to serve a repository for
5123 recommended to use a real web server to serve a repository for
5124 longer periods of time.
5124 longer periods of time.
5125
5125
5126 Please note that the server does not implement access control.
5126 Please note that the server does not implement access control.
5127 This means that, by default, anybody can read from the server and
5127 This means that, by default, anybody can read from the server and
5128 nobody can write to it by default. Set the ``web.allow_push``
5128 nobody can write to it by default. Set the ``web.allow_push``
5129 option to ``*`` to allow everybody to push to the server. You
5129 option to ``*`` to allow everybody to push to the server. You
5130 should use a real web server if you need to authenticate users.
5130 should use a real web server if you need to authenticate users.
5131
5131
5132 By default, the server logs accesses to stdout and errors to
5132 By default, the server logs accesses to stdout and errors to
5133 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5133 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5134 files.
5134 files.
5135
5135
5136 To have the server choose a free port number to listen on, specify
5136 To have the server choose a free port number to listen on, specify
5137 a port number of 0; in this case, the server will print the port
5137 a port number of 0; in this case, the server will print the port
5138 number it uses.
5138 number it uses.
5139
5139
5140 Returns 0 on success.
5140 Returns 0 on success.
5141 """
5141 """
5142
5142
5143 if opts["stdio"] and opts["cmdserver"]:
5143 if opts["stdio"] and opts["cmdserver"]:
5144 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5144 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5145
5145
5146 def checkrepo():
5146 def checkrepo():
5147 if repo is None:
5147 if repo is None:
5148 raise error.RepoError(_("there is no Mercurial repository here"
5148 raise error.RepoError(_("there is no Mercurial repository here"
5149 " (.hg not found)"))
5149 " (.hg not found)"))
5150
5150
5151 if opts["stdio"]:
5151 if opts["stdio"]:
5152 checkrepo()
5152 checkrepo()
5153 s = sshserver.sshserver(ui, repo)
5153 s = sshserver.sshserver(ui, repo)
5154 s.serve_forever()
5154 s.serve_forever()
5155
5155
5156 if opts["cmdserver"]:
5156 if opts["cmdserver"]:
5157 checkrepo()
5157 checkrepo()
5158 s = commandserver.server(ui, repo, opts["cmdserver"])
5158 s = commandserver.server(ui, repo, opts["cmdserver"])
5159 return s.serve()
5159 return s.serve()
5160
5160
5161 # this way we can check if something was given in the command-line
5161 # this way we can check if something was given in the command-line
5162 if opts.get('port'):
5162 if opts.get('port'):
5163 opts['port'] = util.getport(opts.get('port'))
5163 opts['port'] = util.getport(opts.get('port'))
5164
5164
5165 baseui = repo and repo.baseui or ui
5165 baseui = repo and repo.baseui or ui
5166 optlist = ("name templates style address port prefix ipv6"
5166 optlist = ("name templates style address port prefix ipv6"
5167 " accesslog errorlog certificate encoding")
5167 " accesslog errorlog certificate encoding")
5168 for o in optlist.split():
5168 for o in optlist.split():
5169 val = opts.get(o, '')
5169 val = opts.get(o, '')
5170 if val in (None, ''): # should check against default options instead
5170 if val in (None, ''): # should check against default options instead
5171 continue
5171 continue
5172 baseui.setconfig("web", o, val)
5172 baseui.setconfig("web", o, val)
5173 if repo and repo.ui != baseui:
5173 if repo and repo.ui != baseui:
5174 repo.ui.setconfig("web", o, val)
5174 repo.ui.setconfig("web", o, val)
5175
5175
5176 o = opts.get('web_conf') or opts.get('webdir_conf')
5176 o = opts.get('web_conf') or opts.get('webdir_conf')
5177 if not o:
5177 if not o:
5178 if not repo:
5178 if not repo:
5179 raise error.RepoError(_("there is no Mercurial repository"
5179 raise error.RepoError(_("there is no Mercurial repository"
5180 " here (.hg not found)"))
5180 " here (.hg not found)"))
5181 o = repo.root
5181 o = repo.root
5182
5182
5183 app = hgweb.hgweb(o, baseui=ui)
5183 app = hgweb.hgweb(o, baseui=ui)
5184
5184
5185 class service(object):
5185 class service(object):
5186 def init(self):
5186 def init(self):
5187 util.setsignalhandler()
5187 util.setsignalhandler()
5188 self.httpd = hgweb.server.create_server(ui, app)
5188 self.httpd = hgweb.server.create_server(ui, app)
5189
5189
5190 if opts['port'] and not ui.verbose:
5190 if opts['port'] and not ui.verbose:
5191 return
5191 return
5192
5192
5193 if self.httpd.prefix:
5193 if self.httpd.prefix:
5194 prefix = self.httpd.prefix.strip('/') + '/'
5194 prefix = self.httpd.prefix.strip('/') + '/'
5195 else:
5195 else:
5196 prefix = ''
5196 prefix = ''
5197
5197
5198 port = ':%d' % self.httpd.port
5198 port = ':%d' % self.httpd.port
5199 if port == ':80':
5199 if port == ':80':
5200 port = ''
5200 port = ''
5201
5201
5202 bindaddr = self.httpd.addr
5202 bindaddr = self.httpd.addr
5203 if bindaddr == '0.0.0.0':
5203 if bindaddr == '0.0.0.0':
5204 bindaddr = '*'
5204 bindaddr = '*'
5205 elif ':' in bindaddr: # IPv6
5205 elif ':' in bindaddr: # IPv6
5206 bindaddr = '[%s]' % bindaddr
5206 bindaddr = '[%s]' % bindaddr
5207
5207
5208 fqaddr = self.httpd.fqaddr
5208 fqaddr = self.httpd.fqaddr
5209 if ':' in fqaddr:
5209 if ':' in fqaddr:
5210 fqaddr = '[%s]' % fqaddr
5210 fqaddr = '[%s]' % fqaddr
5211 if opts['port']:
5211 if opts['port']:
5212 write = ui.status
5212 write = ui.status
5213 else:
5213 else:
5214 write = ui.write
5214 write = ui.write
5215 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5215 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5216 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5216 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5217
5217
5218 def run(self):
5218 def run(self):
5219 self.httpd.serve_forever()
5219 self.httpd.serve_forever()
5220
5220
5221 service = service()
5221 service = service()
5222
5222
5223 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5223 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5224
5224
5225 @command('showconfig|debugconfig',
5225 @command('showconfig|debugconfig',
5226 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5226 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5227 _('[-u] [NAME]...'))
5227 _('[-u] [NAME]...'))
5228 def showconfig(ui, repo, *values, **opts):
5228 def showconfig(ui, repo, *values, **opts):
5229 """show combined config settings from all hgrc files
5229 """show combined config settings from all hgrc files
5230
5230
5231 With no arguments, print names and values of all config items.
5231 With no arguments, print names and values of all config items.
5232
5232
5233 With one argument of the form section.name, print just the value
5233 With one argument of the form section.name, print just the value
5234 of that config item.
5234 of that config item.
5235
5235
5236 With multiple arguments, print names and values of all config
5236 With multiple arguments, print names and values of all config
5237 items with matching section names.
5237 items with matching section names.
5238
5238
5239 With --debug, the source (filename and line number) is printed
5239 With --debug, the source (filename and line number) is printed
5240 for each config item.
5240 for each config item.
5241
5241
5242 Returns 0 on success.
5242 Returns 0 on success.
5243 """
5243 """
5244
5244
5245 for f in scmutil.rcpath():
5245 for f in scmutil.rcpath():
5246 ui.debug('read config from: %s\n' % f)
5246 ui.debug('read config from: %s\n' % f)
5247 untrusted = bool(opts.get('untrusted'))
5247 untrusted = bool(opts.get('untrusted'))
5248 if values:
5248 if values:
5249 sections = [v for v in values if '.' not in v]
5249 sections = [v for v in values if '.' not in v]
5250 items = [v for v in values if '.' in v]
5250 items = [v for v in values if '.' in v]
5251 if len(items) > 1 or items and sections:
5251 if len(items) > 1 or items and sections:
5252 raise util.Abort(_('only one config item permitted'))
5252 raise util.Abort(_('only one config item permitted'))
5253 for section, name, value in ui.walkconfig(untrusted=untrusted):
5253 for section, name, value in ui.walkconfig(untrusted=untrusted):
5254 value = str(value).replace('\n', '\\n')
5254 value = str(value).replace('\n', '\\n')
5255 sectname = section + '.' + name
5255 sectname = section + '.' + name
5256 if values:
5256 if values:
5257 for v in values:
5257 for v in values:
5258 if v == section:
5258 if v == section:
5259 ui.debug('%s: ' %
5259 ui.debug('%s: ' %
5260 ui.configsource(section, name, untrusted))
5260 ui.configsource(section, name, untrusted))
5261 ui.write('%s=%s\n' % (sectname, value))
5261 ui.write('%s=%s\n' % (sectname, value))
5262 elif v == sectname:
5262 elif v == sectname:
5263 ui.debug('%s: ' %
5263 ui.debug('%s: ' %
5264 ui.configsource(section, name, untrusted))
5264 ui.configsource(section, name, untrusted))
5265 ui.write(value, '\n')
5265 ui.write(value, '\n')
5266 else:
5266 else:
5267 ui.debug('%s: ' %
5267 ui.debug('%s: ' %
5268 ui.configsource(section, name, untrusted))
5268 ui.configsource(section, name, untrusted))
5269 ui.write('%s=%s\n' % (sectname, value))
5269 ui.write('%s=%s\n' % (sectname, value))
5270
5270
5271 @command('^status|st',
5271 @command('^status|st',
5272 [('A', 'all', None, _('show status of all files')),
5272 [('A', 'all', None, _('show status of all files')),
5273 ('m', 'modified', None, _('show only modified files')),
5273 ('m', 'modified', None, _('show only modified files')),
5274 ('a', 'added', None, _('show only added files')),
5274 ('a', 'added', None, _('show only added files')),
5275 ('r', 'removed', None, _('show only removed files')),
5275 ('r', 'removed', None, _('show only removed files')),
5276 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5276 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5277 ('c', 'clean', None, _('show only files without changes')),
5277 ('c', 'clean', None, _('show only files without changes')),
5278 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5278 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5279 ('i', 'ignored', None, _('show only ignored files')),
5279 ('i', 'ignored', None, _('show only ignored files')),
5280 ('n', 'no-status', None, _('hide status prefix')),
5280 ('n', 'no-status', None, _('hide status prefix')),
5281 ('C', 'copies', None, _('show source of copied files')),
5281 ('C', 'copies', None, _('show source of copied files')),
5282 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5282 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5283 ('', 'rev', [], _('show difference from revision'), _('REV')),
5283 ('', 'rev', [], _('show difference from revision'), _('REV')),
5284 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5284 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5285 ] + walkopts + subrepoopts,
5285 ] + walkopts + subrepoopts,
5286 _('[OPTION]... [FILE]...'))
5286 _('[OPTION]... [FILE]...'))
5287 def status(ui, repo, *pats, **opts):
5287 def status(ui, repo, *pats, **opts):
5288 """show changed files in the working directory
5288 """show changed files in the working directory
5289
5289
5290 Show status of files in the repository. If names are given, only
5290 Show status of files in the repository. If names are given, only
5291 files that match are shown. Files that are clean or ignored or
5291 files that match are shown. Files that are clean or ignored or
5292 the source of a copy/move operation, are not listed unless
5292 the source of a copy/move operation, are not listed unless
5293 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5293 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5294 Unless options described with "show only ..." are given, the
5294 Unless options described with "show only ..." are given, the
5295 options -mardu are used.
5295 options -mardu are used.
5296
5296
5297 Option -q/--quiet hides untracked (unknown and ignored) files
5297 Option -q/--quiet hides untracked (unknown and ignored) files
5298 unless explicitly requested with -u/--unknown or -i/--ignored.
5298 unless explicitly requested with -u/--unknown or -i/--ignored.
5299
5299
5300 .. note::
5300 .. note::
5301 status may appear to disagree with diff if permissions have
5301 status may appear to disagree with diff if permissions have
5302 changed or a merge has occurred. The standard diff format does
5302 changed or a merge has occurred. The standard diff format does
5303 not report permission changes and diff only reports changes
5303 not report permission changes and diff only reports changes
5304 relative to one merge parent.
5304 relative to one merge parent.
5305
5305
5306 If one revision is given, it is used as the base revision.
5306 If one revision is given, it is used as the base revision.
5307 If two revisions are given, the differences between them are
5307 If two revisions are given, the differences between them are
5308 shown. The --change option can also be used as a shortcut to list
5308 shown. The --change option can also be used as a shortcut to list
5309 the changed files of a revision from its first parent.
5309 the changed files of a revision from its first parent.
5310
5310
5311 The codes used to show the status of files are::
5311 The codes used to show the status of files are::
5312
5312
5313 M = modified
5313 M = modified
5314 A = added
5314 A = added
5315 R = removed
5315 R = removed
5316 C = clean
5316 C = clean
5317 ! = missing (deleted by non-hg command, but still tracked)
5317 ! = missing (deleted by non-hg command, but still tracked)
5318 ? = not tracked
5318 ? = not tracked
5319 I = ignored
5319 I = ignored
5320 = origin of the previous file listed as A (added)
5320 = origin of the previous file listed as A (added)
5321
5321
5322 .. container:: verbose
5322 .. container:: verbose
5323
5323
5324 Examples:
5324 Examples:
5325
5325
5326 - show changes in the working directory relative to a
5326 - show changes in the working directory relative to a
5327 changeset::
5327 changeset::
5328
5328
5329 hg status --rev 9353
5329 hg status --rev 9353
5330
5330
5331 - show all changes including copies in an existing changeset::
5331 - show all changes including copies in an existing changeset::
5332
5332
5333 hg status --copies --change 9353
5333 hg status --copies --change 9353
5334
5334
5335 - get a NUL separated list of added files, suitable for xargs::
5335 - get a NUL separated list of added files, suitable for xargs::
5336
5336
5337 hg status -an0
5337 hg status -an0
5338
5338
5339 Returns 0 on success.
5339 Returns 0 on success.
5340 """
5340 """
5341
5341
5342 revs = opts.get('rev')
5342 revs = opts.get('rev')
5343 change = opts.get('change')
5343 change = opts.get('change')
5344
5344
5345 if revs and change:
5345 if revs and change:
5346 msg = _('cannot specify --rev and --change at the same time')
5346 msg = _('cannot specify --rev and --change at the same time')
5347 raise util.Abort(msg)
5347 raise util.Abort(msg)
5348 elif change:
5348 elif change:
5349 node2 = scmutil.revsingle(repo, change, None).node()
5349 node2 = scmutil.revsingle(repo, change, None).node()
5350 node1 = repo[node2].p1().node()
5350 node1 = repo[node2].p1().node()
5351 else:
5351 else:
5352 node1, node2 = scmutil.revpair(repo, revs)
5352 node1, node2 = scmutil.revpair(repo, revs)
5353
5353
5354 cwd = (pats and repo.getcwd()) or ''
5354 cwd = (pats and repo.getcwd()) or ''
5355 end = opts.get('print0') and '\0' or '\n'
5355 end = opts.get('print0') and '\0' or '\n'
5356 copy = {}
5356 copy = {}
5357 states = 'modified added removed deleted unknown ignored clean'.split()
5357 states = 'modified added removed deleted unknown ignored clean'.split()
5358 show = [k for k in states if opts.get(k)]
5358 show = [k for k in states if opts.get(k)]
5359 if opts.get('all'):
5359 if opts.get('all'):
5360 show += ui.quiet and (states[:4] + ['clean']) or states
5360 show += ui.quiet and (states[:4] + ['clean']) or states
5361 if not show:
5361 if not show:
5362 show = ui.quiet and states[:4] or states[:5]
5362 show = ui.quiet and states[:4] or states[:5]
5363
5363
5364 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5364 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5365 'ignored' in show, 'clean' in show, 'unknown' in show,
5365 'ignored' in show, 'clean' in show, 'unknown' in show,
5366 opts.get('subrepos'))
5366 opts.get('subrepos'))
5367 changestates = zip(states, 'MAR!?IC', stat)
5367 changestates = zip(states, 'MAR!?IC', stat)
5368
5368
5369 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5369 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5370 copy = copies.pathcopies(repo[node1], repo[node2])
5370 copy = copies.pathcopies(repo[node1], repo[node2])
5371
5371
5372 fm = ui.formatter('status', opts)
5372 fm = ui.formatter('status', opts)
5373 format = '%s %s' + end
5373 format = '%s %s' + end
5374 if opts.get('no_status'):
5374 if opts.get('no_status'):
5375 format = '%.0s%s' + end
5375 format = '%.0s%s' + end
5376
5376
5377 for state, char, files in changestates:
5377 for state, char, files in changestates:
5378 if state in show:
5378 if state in show:
5379 label = 'status.' + state
5379 label = 'status.' + state
5380 for f in files:
5380 for f in files:
5381 fm.startitem()
5381 fm.startitem()
5382 fm.write("status path", format, char,
5382 fm.write("status path", format, char,
5383 repo.pathto(f, cwd), label=label)
5383 repo.pathto(f, cwd), label=label)
5384 if f in copy:
5384 if f in copy:
5385 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5385 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5386 label='status.copied')
5386 label='status.copied')
5387 fm.end()
5387 fm.end()
5388
5388
5389 @command('^summary|sum',
5389 @command('^summary|sum',
5390 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5390 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5391 def summary(ui, repo, **opts):
5391 def summary(ui, repo, **opts):
5392 """summarize working directory state
5392 """summarize working directory state
5393
5393
5394 This generates a brief summary of the working directory state,
5394 This generates a brief summary of the working directory state,
5395 including parents, branch, commit status, and available updates.
5395 including parents, branch, commit status, and available updates.
5396
5396
5397 With the --remote option, this will check the default paths for
5397 With the --remote option, this will check the default paths for
5398 incoming and outgoing changes. This can be time-consuming.
5398 incoming and outgoing changes. This can be time-consuming.
5399
5399
5400 Returns 0 on success.
5400 Returns 0 on success.
5401 """
5401 """
5402
5402
5403 ctx = repo[None]
5403 ctx = repo[None]
5404 parents = ctx.parents()
5404 parents = ctx.parents()
5405 pnode = parents[0].node()
5405 pnode = parents[0].node()
5406 marks = []
5406 marks = []
5407
5407
5408 for p in parents:
5408 for p in parents:
5409 # label with log.changeset (instead of log.parent) since this
5409 # label with log.changeset (instead of log.parent) since this
5410 # shows a working directory parent *changeset*:
5410 # shows a working directory parent *changeset*:
5411 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5411 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5412 label='log.changeset')
5412 label='log.changeset')
5413 ui.write(' '.join(p.tags()), label='log.tag')
5413 ui.write(' '.join(p.tags()), label='log.tag')
5414 if p.bookmarks():
5414 if p.bookmarks():
5415 marks.extend(p.bookmarks())
5415 marks.extend(p.bookmarks())
5416 if p.rev() == -1:
5416 if p.rev() == -1:
5417 if not len(repo):
5417 if not len(repo):
5418 ui.write(_(' (empty repository)'))
5418 ui.write(_(' (empty repository)'))
5419 else:
5419 else:
5420 ui.write(_(' (no revision checked out)'))
5420 ui.write(_(' (no revision checked out)'))
5421 ui.write('\n')
5421 ui.write('\n')
5422 if p.description():
5422 if p.description():
5423 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5423 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5424 label='log.summary')
5424 label='log.summary')
5425
5425
5426 branch = ctx.branch()
5426 branch = ctx.branch()
5427 bheads = repo.branchheads(branch)
5427 bheads = repo.branchheads(branch)
5428 m = _('branch: %s\n') % branch
5428 m = _('branch: %s\n') % branch
5429 if branch != 'default':
5429 if branch != 'default':
5430 ui.write(m, label='log.branch')
5430 ui.write(m, label='log.branch')
5431 else:
5431 else:
5432 ui.status(m, label='log.branch')
5432 ui.status(m, label='log.branch')
5433
5433
5434 if marks:
5434 if marks:
5435 current = repo._bookmarkcurrent
5435 current = repo._bookmarkcurrent
5436 ui.write(_('bookmarks:'), label='log.bookmark')
5436 ui.write(_('bookmarks:'), label='log.bookmark')
5437 if current is not None:
5437 if current is not None:
5438 try:
5438 try:
5439 marks.remove(current)
5439 marks.remove(current)
5440 ui.write(' *' + current, label='bookmarks.current')
5440 ui.write(' *' + current, label='bookmarks.current')
5441 except ValueError:
5441 except ValueError:
5442 # current bookmark not in parent ctx marks
5442 # current bookmark not in parent ctx marks
5443 pass
5443 pass
5444 for m in marks:
5444 for m in marks:
5445 ui.write(' ' + m, label='log.bookmark')
5445 ui.write(' ' + m, label='log.bookmark')
5446 ui.write('\n', label='log.bookmark')
5446 ui.write('\n', label='log.bookmark')
5447
5447
5448 st = list(repo.status(unknown=True))[:6]
5448 st = list(repo.status(unknown=True))[:6]
5449
5449
5450 c = repo.dirstate.copies()
5450 c = repo.dirstate.copies()
5451 copied, renamed = [], []
5451 copied, renamed = [], []
5452 for d, s in c.iteritems():
5452 for d, s in c.iteritems():
5453 if s in st[2]:
5453 if s in st[2]:
5454 st[2].remove(s)
5454 st[2].remove(s)
5455 renamed.append(d)
5455 renamed.append(d)
5456 else:
5456 else:
5457 copied.append(d)
5457 copied.append(d)
5458 if d in st[1]:
5458 if d in st[1]:
5459 st[1].remove(d)
5459 st[1].remove(d)
5460 st.insert(3, renamed)
5460 st.insert(3, renamed)
5461 st.insert(4, copied)
5461 st.insert(4, copied)
5462
5462
5463 ms = mergemod.mergestate(repo)
5463 ms = mergemod.mergestate(repo)
5464 st.append([f for f in ms if ms[f] == 'u'])
5464 st.append([f for f in ms if ms[f] == 'u'])
5465
5465
5466 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5466 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5467 st.append(subs)
5467 st.append(subs)
5468
5468
5469 labels = [ui.label(_('%d modified'), 'status.modified'),
5469 labels = [ui.label(_('%d modified'), 'status.modified'),
5470 ui.label(_('%d added'), 'status.added'),
5470 ui.label(_('%d added'), 'status.added'),
5471 ui.label(_('%d removed'), 'status.removed'),
5471 ui.label(_('%d removed'), 'status.removed'),
5472 ui.label(_('%d renamed'), 'status.copied'),
5472 ui.label(_('%d renamed'), 'status.copied'),
5473 ui.label(_('%d copied'), 'status.copied'),
5473 ui.label(_('%d copied'), 'status.copied'),
5474 ui.label(_('%d deleted'), 'status.deleted'),
5474 ui.label(_('%d deleted'), 'status.deleted'),
5475 ui.label(_('%d unknown'), 'status.unknown'),
5475 ui.label(_('%d unknown'), 'status.unknown'),
5476 ui.label(_('%d ignored'), 'status.ignored'),
5476 ui.label(_('%d ignored'), 'status.ignored'),
5477 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5477 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5478 ui.label(_('%d subrepos'), 'status.modified')]
5478 ui.label(_('%d subrepos'), 'status.modified')]
5479 t = []
5479 t = []
5480 for s, l in zip(st, labels):
5480 for s, l in zip(st, labels):
5481 if s:
5481 if s:
5482 t.append(l % len(s))
5482 t.append(l % len(s))
5483
5483
5484 t = ', '.join(t)
5484 t = ', '.join(t)
5485 cleanworkdir = False
5485 cleanworkdir = False
5486
5486
5487 if len(parents) > 1:
5487 if len(parents) > 1:
5488 t += _(' (merge)')
5488 t += _(' (merge)')
5489 elif branch != parents[0].branch():
5489 elif branch != parents[0].branch():
5490 t += _(' (new branch)')
5490 t += _(' (new branch)')
5491 elif (parents[0].closesbranch() and
5491 elif (parents[0].closesbranch() and
5492 pnode in repo.branchheads(branch, closed=True)):
5492 pnode in repo.branchheads(branch, closed=True)):
5493 t += _(' (head closed)')
5493 t += _(' (head closed)')
5494 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5494 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5495 t += _(' (clean)')
5495 t += _(' (clean)')
5496 cleanworkdir = True
5496 cleanworkdir = True
5497 elif pnode not in bheads:
5497 elif pnode not in bheads:
5498 t += _(' (new branch head)')
5498 t += _(' (new branch head)')
5499
5499
5500 if cleanworkdir:
5500 if cleanworkdir:
5501 ui.status(_('commit: %s\n') % t.strip())
5501 ui.status(_('commit: %s\n') % t.strip())
5502 else:
5502 else:
5503 ui.write(_('commit: %s\n') % t.strip())
5503 ui.write(_('commit: %s\n') % t.strip())
5504
5504
5505 # all ancestors of branch heads - all ancestors of parent = new csets
5505 # all ancestors of branch heads - all ancestors of parent = new csets
5506 new = [0] * len(repo)
5506 new = [0] * len(repo)
5507 cl = repo.changelog
5507 cl = repo.changelog
5508 for a in [cl.rev(n) for n in bheads]:
5508 for a in [cl.rev(n) for n in bheads]:
5509 new[a] = 1
5509 new[a] = 1
5510 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5510 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5511 new[a] = 1
5511 new[a] = 1
5512 for a in [p.rev() for p in parents]:
5512 for a in [p.rev() for p in parents]:
5513 if a >= 0:
5513 if a >= 0:
5514 new[a] = 0
5514 new[a] = 0
5515 for a in cl.ancestors([p.rev() for p in parents]):
5515 for a in cl.ancestors([p.rev() for p in parents]):
5516 new[a] = 0
5516 new[a] = 0
5517 new = sum(new)
5517 new = sum(new)
5518
5518
5519 if new == 0:
5519 if new == 0:
5520 ui.status(_('update: (current)\n'))
5520 ui.status(_('update: (current)\n'))
5521 elif pnode not in bheads:
5521 elif pnode not in bheads:
5522 ui.write(_('update: %d new changesets (update)\n') % new)
5522 ui.write(_('update: %d new changesets (update)\n') % new)
5523 else:
5523 else:
5524 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5524 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5525 (new, len(bheads)))
5525 (new, len(bheads)))
5526
5526
5527 if opts.get('remote'):
5527 if opts.get('remote'):
5528 t = []
5528 t = []
5529 source, branches = hg.parseurl(ui.expandpath('default'))
5529 source, branches = hg.parseurl(ui.expandpath('default'))
5530 other = hg.peer(repo, {}, source)
5530 other = hg.peer(repo, {}, source)
5531 revs, checkout = hg.addbranchrevs(repo, other, branches,
5531 revs, checkout = hg.addbranchrevs(repo, other, branches,
5532 opts.get('rev'))
5532 opts.get('rev'))
5533 ui.debug('comparing with %s\n' % util.hidepassword(source))
5533 ui.debug('comparing with %s\n' % util.hidepassword(source))
5534 repo.ui.pushbuffer()
5534 repo.ui.pushbuffer()
5535 commoninc = discovery.findcommonincoming(repo, other)
5535 commoninc = discovery.findcommonincoming(repo, other)
5536 _common, incoming, _rheads = commoninc
5536 _common, incoming, _rheads = commoninc
5537 repo.ui.popbuffer()
5537 repo.ui.popbuffer()
5538 if incoming:
5538 if incoming:
5539 t.append(_('1 or more incoming'))
5539 t.append(_('1 or more incoming'))
5540
5540
5541 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5541 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5542 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5542 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5543 if source != dest:
5543 if source != dest:
5544 other = hg.peer(repo, {}, dest)
5544 other = hg.peer(repo, {}, dest)
5545 commoninc = None
5545 commoninc = None
5546 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5546 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5547 repo.ui.pushbuffer()
5547 repo.ui.pushbuffer()
5548 outgoing = discovery.findcommonoutgoing(repo, other,
5548 outgoing = discovery.findcommonoutgoing(repo, other,
5549 commoninc=commoninc)
5549 commoninc=commoninc)
5550 repo.ui.popbuffer()
5550 repo.ui.popbuffer()
5551 o = outgoing.missing
5551 o = outgoing.missing
5552 if o:
5552 if o:
5553 t.append(_('%d outgoing') % len(o))
5553 t.append(_('%d outgoing') % len(o))
5554 if 'bookmarks' in other.listkeys('namespaces'):
5554 if 'bookmarks' in other.listkeys('namespaces'):
5555 lmarks = repo.listkeys('bookmarks')
5555 lmarks = repo.listkeys('bookmarks')
5556 rmarks = other.listkeys('bookmarks')
5556 rmarks = other.listkeys('bookmarks')
5557 diff = set(rmarks) - set(lmarks)
5557 diff = set(rmarks) - set(lmarks)
5558 if len(diff) > 0:
5558 if len(diff) > 0:
5559 t.append(_('%d incoming bookmarks') % len(diff))
5559 t.append(_('%d incoming bookmarks') % len(diff))
5560 diff = set(lmarks) - set(rmarks)
5560 diff = set(lmarks) - set(rmarks)
5561 if len(diff) > 0:
5561 if len(diff) > 0:
5562 t.append(_('%d outgoing bookmarks') % len(diff))
5562 t.append(_('%d outgoing bookmarks') % len(diff))
5563
5563
5564 if t:
5564 if t:
5565 ui.write(_('remote: %s\n') % (', '.join(t)))
5565 ui.write(_('remote: %s\n') % (', '.join(t)))
5566 else:
5566 else:
5567 ui.status(_('remote: (synced)\n'))
5567 ui.status(_('remote: (synced)\n'))
5568
5568
5569 @command('tag',
5569 @command('tag',
5570 [('f', 'force', None, _('force tag')),
5570 [('f', 'force', None, _('force tag')),
5571 ('l', 'local', None, _('make the tag local')),
5571 ('l', 'local', None, _('make the tag local')),
5572 ('r', 'rev', '', _('revision to tag'), _('REV')),
5572 ('r', 'rev', '', _('revision to tag'), _('REV')),
5573 ('', 'remove', None, _('remove a tag')),
5573 ('', 'remove', None, _('remove a tag')),
5574 # -l/--local is already there, commitopts cannot be used
5574 # -l/--local is already there, commitopts cannot be used
5575 ('e', 'edit', None, _('edit commit message')),
5575 ('e', 'edit', None, _('edit commit message')),
5576 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5576 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5577 ] + commitopts2,
5577 ] + commitopts2,
5578 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5578 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5579 def tag(ui, repo, name1, *names, **opts):
5579 def tag(ui, repo, name1, *names, **opts):
5580 """add one or more tags for the current or given revision
5580 """add one or more tags for the current or given revision
5581
5581
5582 Name a particular revision using <name>.
5582 Name a particular revision using <name>.
5583
5583
5584 Tags are used to name particular revisions of the repository and are
5584 Tags are used to name particular revisions of the repository and are
5585 very useful to compare different revisions, to go back to significant
5585 very useful to compare different revisions, to go back to significant
5586 earlier versions or to mark branch points as releases, etc. Changing
5586 earlier versions or to mark branch points as releases, etc. Changing
5587 an existing tag is normally disallowed; use -f/--force to override.
5587 an existing tag is normally disallowed; use -f/--force to override.
5588
5588
5589 If no revision is given, the parent of the working directory is
5589 If no revision is given, the parent of the working directory is
5590 used, or tip if no revision is checked out.
5590 used, or tip if no revision is checked out.
5591
5591
5592 To facilitate version control, distribution, and merging of tags,
5592 To facilitate version control, distribution, and merging of tags,
5593 they are stored as a file named ".hgtags" which is managed similarly
5593 they are stored as a file named ".hgtags" which is managed similarly
5594 to other project files and can be hand-edited if necessary. This
5594 to other project files and can be hand-edited if necessary. This
5595 also means that tagging creates a new commit. The file
5595 also means that tagging creates a new commit. The file
5596 ".hg/localtags" is used for local tags (not shared among
5596 ".hg/localtags" is used for local tags (not shared among
5597 repositories).
5597 repositories).
5598
5598
5599 Tag commits are usually made at the head of a branch. If the parent
5599 Tag commits are usually made at the head of a branch. If the parent
5600 of the working directory is not a branch head, :hg:`tag` aborts; use
5600 of the working directory is not a branch head, :hg:`tag` aborts; use
5601 -f/--force to force the tag commit to be based on a non-head
5601 -f/--force to force the tag commit to be based on a non-head
5602 changeset.
5602 changeset.
5603
5603
5604 See :hg:`help dates` for a list of formats valid for -d/--date.
5604 See :hg:`help dates` for a list of formats valid for -d/--date.
5605
5605
5606 Since tag names have priority over branch names during revision
5606 Since tag names have priority over branch names during revision
5607 lookup, using an existing branch name as a tag name is discouraged.
5607 lookup, using an existing branch name as a tag name is discouraged.
5608
5608
5609 Returns 0 on success.
5609 Returns 0 on success.
5610 """
5610 """
5611 wlock = lock = None
5611 wlock = lock = None
5612 try:
5612 try:
5613 wlock = repo.wlock()
5613 wlock = repo.wlock()
5614 lock = repo.lock()
5614 lock = repo.lock()
5615 rev_ = "."
5615 rev_ = "."
5616 names = [t.strip() for t in (name1,) + names]
5616 names = [t.strip() for t in (name1,) + names]
5617 if len(names) != len(set(names)):
5617 if len(names) != len(set(names)):
5618 raise util.Abort(_('tag names must be unique'))
5618 raise util.Abort(_('tag names must be unique'))
5619 for n in names:
5619 for n in names:
5620 if n in ['tip', '.', 'null']:
5620 if n in ['tip', '.', 'null']:
5621 raise util.Abort(_("the name '%s' is reserved") % n)
5621 raise util.Abort(_("the name '%s' is reserved") % n)
5622 if not n:
5622 if not n:
5623 raise util.Abort(_('tag names cannot consist entirely of '
5623 raise util.Abort(_('tag names cannot consist entirely of '
5624 'whitespace'))
5624 'whitespace'))
5625 if opts.get('rev') and opts.get('remove'):
5625 if opts.get('rev') and opts.get('remove'):
5626 raise util.Abort(_("--rev and --remove are incompatible"))
5626 raise util.Abort(_("--rev and --remove are incompatible"))
5627 if opts.get('rev'):
5627 if opts.get('rev'):
5628 rev_ = opts['rev']
5628 rev_ = opts['rev']
5629 message = opts.get('message')
5629 message = opts.get('message')
5630 if opts.get('remove'):
5630 if opts.get('remove'):
5631 expectedtype = opts.get('local') and 'local' or 'global'
5631 expectedtype = opts.get('local') and 'local' or 'global'
5632 for n in names:
5632 for n in names:
5633 if not repo.tagtype(n):
5633 if not repo.tagtype(n):
5634 raise util.Abort(_("tag '%s' does not exist") % n)
5634 raise util.Abort(_("tag '%s' does not exist") % n)
5635 if repo.tagtype(n) != expectedtype:
5635 if repo.tagtype(n) != expectedtype:
5636 if expectedtype == 'global':
5636 if expectedtype == 'global':
5637 raise util.Abort(_("tag '%s' is not a global tag") % n)
5637 raise util.Abort(_("tag '%s' is not a global tag") % n)
5638 else:
5638 else:
5639 raise util.Abort(_("tag '%s' is not a local tag") % n)
5639 raise util.Abort(_("tag '%s' is not a local tag") % n)
5640 rev_ = nullid
5640 rev_ = nullid
5641 if not message:
5641 if not message:
5642 # we don't translate commit messages
5642 # we don't translate commit messages
5643 message = 'Removed tag %s' % ', '.join(names)
5643 message = 'Removed tag %s' % ', '.join(names)
5644 elif not opts.get('force'):
5644 elif not opts.get('force'):
5645 for n in names:
5645 for n in names:
5646 if n in repo.tags():
5646 if n in repo.tags():
5647 raise util.Abort(_("tag '%s' already exists "
5647 raise util.Abort(_("tag '%s' already exists "
5648 "(use -f to force)") % n)
5648 "(use -f to force)") % n)
5649 if not opts.get('local'):
5649 if not opts.get('local'):
5650 p1, p2 = repo.dirstate.parents()
5650 p1, p2 = repo.dirstate.parents()
5651 if p2 != nullid:
5651 if p2 != nullid:
5652 raise util.Abort(_('uncommitted merge'))
5652 raise util.Abort(_('uncommitted merge'))
5653 bheads = repo.branchheads()
5653 bheads = repo.branchheads()
5654 if not opts.get('force') and bheads and p1 not in bheads:
5654 if not opts.get('force') and bheads and p1 not in bheads:
5655 raise util.Abort(_('not at a branch head (use -f to force)'))
5655 raise util.Abort(_('not at a branch head (use -f to force)'))
5656 r = scmutil.revsingle(repo, rev_).node()
5656 r = scmutil.revsingle(repo, rev_).node()
5657
5657
5658 if not message:
5658 if not message:
5659 # we don't translate commit messages
5659 # we don't translate commit messages
5660 message = ('Added tag %s for changeset %s' %
5660 message = ('Added tag %s for changeset %s' %
5661 (', '.join(names), short(r)))
5661 (', '.join(names), short(r)))
5662
5662
5663 date = opts.get('date')
5663 date = opts.get('date')
5664 if date:
5664 if date:
5665 date = util.parsedate(date)
5665 date = util.parsedate(date)
5666
5666
5667 if opts.get('edit'):
5667 if opts.get('edit'):
5668 message = ui.edit(message, ui.username())
5668 message = ui.edit(message, ui.username())
5669
5669
5670 # don't allow tagging the null rev
5670 # don't allow tagging the null rev
5671 if (not opts.get('remove') and
5671 if (not opts.get('remove') and
5672 scmutil.revsingle(repo, rev_).rev() == nullrev):
5672 scmutil.revsingle(repo, rev_).rev() == nullrev):
5673 raise util.Abort(_("null revision specified"))
5673 raise util.Abort(_("null revision specified"))
5674
5674
5675 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5675 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5676 finally:
5676 finally:
5677 release(lock, wlock)
5677 release(lock, wlock)
5678
5678
5679 @command('tags', [], '')
5679 @command('tags', [], '')
5680 def tags(ui, repo):
5680 def tags(ui, repo):
5681 """list repository tags
5681 """list repository tags
5682
5682
5683 This lists both regular and local tags. When the -v/--verbose
5683 This lists both regular and local tags. When the -v/--verbose
5684 switch is used, a third column "local" is printed for local tags.
5684 switch is used, a third column "local" is printed for local tags.
5685
5685
5686 Returns 0 on success.
5686 Returns 0 on success.
5687 """
5687 """
5688
5688
5689 hexfunc = ui.debugflag and hex or short
5689 hexfunc = ui.debugflag and hex or short
5690 tagtype = ""
5690 tagtype = ""
5691
5691
5692 for t, n in reversed(repo.tagslist()):
5692 for t, n in reversed(repo.tagslist()):
5693 if ui.quiet:
5693 if ui.quiet:
5694 ui.write("%s\n" % t, label='tags.normal')
5694 ui.write("%s\n" % t, label='tags.normal')
5695 continue
5695 continue
5696
5696
5697 hn = hexfunc(n)
5697 hn = hexfunc(n)
5698 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5698 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5699 rev = ui.label(r, 'log.changeset')
5699 rev = ui.label(r, 'log.changeset')
5700 spaces = " " * (30 - encoding.colwidth(t))
5700 spaces = " " * (30 - encoding.colwidth(t))
5701
5701
5702 tag = ui.label(t, 'tags.normal')
5702 tag = ui.label(t, 'tags.normal')
5703 if ui.verbose:
5703 if ui.verbose:
5704 if repo.tagtype(t) == 'local':
5704 if repo.tagtype(t) == 'local':
5705 tagtype = " local"
5705 tagtype = " local"
5706 tag = ui.label(t, 'tags.local')
5706 tag = ui.label(t, 'tags.local')
5707 else:
5707 else:
5708 tagtype = ""
5708 tagtype = ""
5709 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5709 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5710
5710
5711 @command('tip',
5711 @command('tip',
5712 [('p', 'patch', None, _('show patch')),
5712 [('p', 'patch', None, _('show patch')),
5713 ('g', 'git', None, _('use git extended diff format')),
5713 ('g', 'git', None, _('use git extended diff format')),
5714 ] + templateopts,
5714 ] + templateopts,
5715 _('[-p] [-g]'))
5715 _('[-p] [-g]'))
5716 def tip(ui, repo, **opts):
5716 def tip(ui, repo, **opts):
5717 """show the tip revision
5717 """show the tip revision
5718
5718
5719 The tip revision (usually just called the tip) is the changeset
5719 The tip revision (usually just called the tip) is the changeset
5720 most recently added to the repository (and therefore the most
5720 most recently added to the repository (and therefore the most
5721 recently changed head).
5721 recently changed head).
5722
5722
5723 If you have just made a commit, that commit will be the tip. If
5723 If you have just made a commit, that commit will be the tip. If
5724 you have just pulled changes from another repository, the tip of
5724 you have just pulled changes from another repository, the tip of
5725 that repository becomes the current tip. The "tip" tag is special
5725 that repository becomes the current tip. The "tip" tag is special
5726 and cannot be renamed or assigned to a different changeset.
5726 and cannot be renamed or assigned to a different changeset.
5727
5727
5728 Returns 0 on success.
5728 Returns 0 on success.
5729 """
5729 """
5730 displayer = cmdutil.show_changeset(ui, repo, opts)
5730 displayer = cmdutil.show_changeset(ui, repo, opts)
5731 displayer.show(repo[len(repo) - 1])
5731 displayer.show(repo[len(repo) - 1])
5732 displayer.close()
5732 displayer.close()
5733
5733
5734 @command('unbundle',
5734 @command('unbundle',
5735 [('u', 'update', None,
5735 [('u', 'update', None,
5736 _('update to new branch head if changesets were unbundled'))],
5736 _('update to new branch head if changesets were unbundled'))],
5737 _('[-u] FILE...'))
5737 _('[-u] FILE...'))
5738 def unbundle(ui, repo, fname1, *fnames, **opts):
5738 def unbundle(ui, repo, fname1, *fnames, **opts):
5739 """apply one or more changegroup files
5739 """apply one or more changegroup files
5740
5740
5741 Apply one or more compressed changegroup files generated by the
5741 Apply one or more compressed changegroup files generated by the
5742 bundle command.
5742 bundle command.
5743
5743
5744 Returns 0 on success, 1 if an update has unresolved files.
5744 Returns 0 on success, 1 if an update has unresolved files.
5745 """
5745 """
5746 fnames = (fname1,) + fnames
5746 fnames = (fname1,) + fnames
5747
5747
5748 lock = repo.lock()
5748 lock = repo.lock()
5749 wc = repo['.']
5749 wc = repo['.']
5750 try:
5750 try:
5751 for fname in fnames:
5751 for fname in fnames:
5752 f = url.open(ui, fname)
5752 f = url.open(ui, fname)
5753 gen = changegroup.readbundle(f, fname)
5753 gen = changegroup.readbundle(f, fname)
5754 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5754 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5755 finally:
5755 finally:
5756 lock.release()
5756 lock.release()
5757 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5757 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5758 return postincoming(ui, repo, modheads, opts.get('update'), None)
5758 return postincoming(ui, repo, modheads, opts.get('update'), None)
5759
5759
5760 @command('^update|up|checkout|co',
5760 @command('^update|up|checkout|co',
5761 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5761 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5762 ('c', 'check', None,
5762 ('c', 'check', None,
5763 _('update across branches if no uncommitted changes')),
5763 _('update across branches if no uncommitted changes')),
5764 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5764 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5765 ('r', 'rev', '', _('revision'), _('REV'))],
5765 ('r', 'rev', '', _('revision'), _('REV'))],
5766 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5766 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5767 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5767 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5768 """update working directory (or switch revisions)
5768 """update working directory (or switch revisions)
5769
5769
5770 Update the repository's working directory to the specified
5770 Update the repository's working directory to the specified
5771 changeset. If no changeset is specified, update to the tip of the
5771 changeset. If no changeset is specified, update to the tip of the
5772 current named branch and move the current bookmark (see :hg:`help
5772 current named branch and move the current bookmark (see :hg:`help
5773 bookmarks`).
5773 bookmarks`).
5774
5774
5775 Update sets the working directory's parent revison to the specified
5775 Update sets the working directory's parent revison to the specified
5776 changeset (see :hg:`help parents`).
5776 changeset (see :hg:`help parents`).
5777
5777
5778 If the changeset is not a descendant or ancestor of the working
5778 If the changeset is not a descendant or ancestor of the working
5779 directory's parent, the update is aborted. With the -c/--check
5779 directory's parent, the update is aborted. With the -c/--check
5780 option, the working directory is checked for uncommitted changes; if
5780 option, the working directory is checked for uncommitted changes; if
5781 none are found, the working directory is updated to the specified
5781 none are found, the working directory is updated to the specified
5782 changeset.
5782 changeset.
5783
5783
5784 .. container:: verbose
5784 .. container:: verbose
5785
5785
5786 The following rules apply when the working directory contains
5786 The following rules apply when the working directory contains
5787 uncommitted changes:
5787 uncommitted changes:
5788
5788
5789 1. If neither -c/--check nor -C/--clean is specified, and if
5789 1. If neither -c/--check nor -C/--clean is specified, and if
5790 the requested changeset is an ancestor or descendant of
5790 the requested changeset is an ancestor or descendant of
5791 the working directory's parent, the uncommitted changes
5791 the working directory's parent, the uncommitted changes
5792 are merged into the requested changeset and the merged
5792 are merged into the requested changeset and the merged
5793 result is left uncommitted. If the requested changeset is
5793 result is left uncommitted. If the requested changeset is
5794 not an ancestor or descendant (that is, it is on another
5794 not an ancestor or descendant (that is, it is on another
5795 branch), the update is aborted and the uncommitted changes
5795 branch), the update is aborted and the uncommitted changes
5796 are preserved.
5796 are preserved.
5797
5797
5798 2. With the -c/--check option, the update is aborted and the
5798 2. With the -c/--check option, the update is aborted and the
5799 uncommitted changes are preserved.
5799 uncommitted changes are preserved.
5800
5800
5801 3. With the -C/--clean option, uncommitted changes are discarded and
5801 3. With the -C/--clean option, uncommitted changes are discarded and
5802 the working directory is updated to the requested changeset.
5802 the working directory is updated to the requested changeset.
5803
5803
5804 To cancel an uncommitted merge (and lose your changes), use
5804 To cancel an uncommitted merge (and lose your changes), use
5805 :hg:`update --clean .`.
5805 :hg:`update --clean .`.
5806
5806
5807 Use null as the changeset to remove the working directory (like
5807 Use null as the changeset to remove the working directory (like
5808 :hg:`clone -U`).
5808 :hg:`clone -U`).
5809
5809
5810 If you want to revert just one file to an older revision, use
5810 If you want to revert just one file to an older revision, use
5811 :hg:`revert [-r REV] NAME`.
5811 :hg:`revert [-r REV] NAME`.
5812
5812
5813 See :hg:`help dates` for a list of formats valid for -d/--date.
5813 See :hg:`help dates` for a list of formats valid for -d/--date.
5814
5814
5815 Returns 0 on success, 1 if there are unresolved files.
5815 Returns 0 on success, 1 if there are unresolved files.
5816 """
5816 """
5817 if rev and node:
5817 if rev and node:
5818 raise util.Abort(_("please specify just one revision"))
5818 raise util.Abort(_("please specify just one revision"))
5819
5819
5820 if rev is None or rev == '':
5820 if rev is None or rev == '':
5821 rev = node
5821 rev = node
5822
5822
5823 # with no argument, we also move the current bookmark, if any
5823 # with no argument, we also move the current bookmark, if any
5824 movemarkfrom = None
5824 movemarkfrom = None
5825 if rev is None or node == '':
5825 if rev is None or node == '':
5826 movemarkfrom = repo['.'].node()
5826 movemarkfrom = repo['.'].node()
5827
5827
5828 # if we defined a bookmark, we have to remember the original bookmark name
5828 # if we defined a bookmark, we have to remember the original bookmark name
5829 brev = rev
5829 brev = rev
5830 rev = scmutil.revsingle(repo, rev, rev).rev()
5830 rev = scmutil.revsingle(repo, rev, rev).rev()
5831
5831
5832 if check and clean:
5832 if check and clean:
5833 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5833 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5834
5834
5835 if date:
5835 if date:
5836 if rev is not None:
5836 if rev is not None:
5837 raise util.Abort(_("you can't specify a revision and a date"))
5837 raise util.Abort(_("you can't specify a revision and a date"))
5838 rev = cmdutil.finddate(ui, repo, date)
5838 rev = cmdutil.finddate(ui, repo, date)
5839
5839
5840 if check:
5840 if check:
5841 c = repo[None]
5841 c = repo[None]
5842 if c.dirty(merge=False, branch=False):
5842 if c.dirty(merge=False, branch=False):
5843 raise util.Abort(_("uncommitted local changes"))
5843 raise util.Abort(_("uncommitted local changes"))
5844 if rev is None:
5844 if rev is None:
5845 rev = repo[repo[None].branch()].rev()
5845 rev = repo[repo[None].branch()].rev()
5846 mergemod._checkunknown(repo, repo[None], repo[rev])
5846 mergemod._checkunknown(repo, repo[None], repo[rev])
5847
5847
5848 if clean:
5848 if clean:
5849 ret = hg.clean(repo, rev)
5849 ret = hg.clean(repo, rev)
5850 else:
5850 else:
5851 ret = hg.update(repo, rev)
5851 ret = hg.update(repo, rev)
5852
5852
5853 if not ret and movemarkfrom:
5853 if not ret and movemarkfrom:
5854 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5854 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5855 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5855 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5856 elif brev in repo._bookmarks:
5856 elif brev in repo._bookmarks:
5857 bookmarks.setcurrent(repo, brev)
5857 bookmarks.setcurrent(repo, brev)
5858 elif brev:
5858 elif brev:
5859 bookmarks.unsetcurrent(repo)
5859 bookmarks.unsetcurrent(repo)
5860
5860
5861 return ret
5861 return ret
5862
5862
5863 @command('verify', [])
5863 @command('verify', [])
5864 def verify(ui, repo):
5864 def verify(ui, repo):
5865 """verify the integrity of the repository
5865 """verify the integrity of the repository
5866
5866
5867 Verify the integrity of the current repository.
5867 Verify the integrity of the current repository.
5868
5868
5869 This will perform an extensive check of the repository's
5869 This will perform an extensive check of the repository's
5870 integrity, validating the hashes and checksums of each entry in
5870 integrity, validating the hashes and checksums of each entry in
5871 the changelog, manifest, and tracked files, as well as the
5871 the changelog, manifest, and tracked files, as well as the
5872 integrity of their crosslinks and indices.
5872 integrity of their crosslinks and indices.
5873
5873
5874 Returns 0 on success, 1 if errors are encountered.
5874 Returns 0 on success, 1 if errors are encountered.
5875 """
5875 """
5876 return hg.verify(repo)
5876 return hg.verify(repo)
5877
5877
5878 @command('version', [])
5878 @command('version', [])
5879 def version_(ui):
5879 def version_(ui):
5880 """output version and copyright information"""
5880 """output version and copyright information"""
5881 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5881 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5882 % util.version())
5882 % util.version())
5883 ui.status(_(
5883 ui.status(_(
5884 "(see http://mercurial.selenic.com for more information)\n"
5884 "(see http://mercurial.selenic.com for more information)\n"
5885 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5885 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5886 "This is free software; see the source for copying conditions. "
5886 "This is free software; see the source for copying conditions. "
5887 "There is NO\nwarranty; "
5887 "There is NO\nwarranty; "
5888 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5888 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5889 ))
5889 ))
5890
5890
5891 norepo = ("clone init version help debugcommands debugcomplete"
5891 norepo = ("clone init version help debugcommands debugcomplete"
5892 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5892 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5893 " debugknown debuggetbundle debugbundle")
5893 " debugknown debuggetbundle debugbundle")
5894 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5894 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5895 " debugdata debugindex debugindexdot debugrevlog")
5895 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,203 +1,203 b''
1 # help.py - help data for mercurial
1 # help.py - help data for mercurial
2 #
2 #
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006 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 i18n import gettext, _
8 from i18n import gettext, _
9 import itertools, sys, os
9 import itertools, sys, os
10 import extensions, revset, fileset, templatekw, templatefilters, filemerge
10 import extensions, revset, fileset, templatekw, templatefilters, filemerge
11 import encoding, util, minirst
11 import encoding, util, minirst
12
12
13 def listexts(header, exts, indent=1):
13 def listexts(header, exts, indent=1):
14 '''return a text listing of the given extensions'''
14 '''return a text listing of the given extensions'''
15 rst = []
15 rst = []
16 if exts:
16 if exts:
17 rst.append('\n%s\n\n' % header)
17 rst.append('\n%s\n\n' % header)
18 for name, desc in sorted(exts.iteritems()):
18 for name, desc in sorted(exts.iteritems()):
19 rst.append('%s:%s: %s\n' % (' ' * indent, name, desc))
19 rst.append('%s:%s: %s\n' % (' ' * indent, name, desc))
20 return rst
20 return rst
21
21
22 def extshelp():
22 def extshelp():
23 rst = loaddoc('extensions')().splitlines(True)
23 rst = loaddoc('extensions')().splitlines(True)
24 rst.extend(listexts(_('enabled extensions:'), extensions.enabled()))
24 rst.extend(listexts(_('enabled extensions:'), extensions.enabled()))
25 rst.extend(listexts(_('disabled extensions:'), extensions.disabled()))
25 rst.extend(listexts(_('disabled extensions:'), extensions.disabled()))
26 doc = ''.join(rst)
26 doc = ''.join(rst)
27 return doc
27 return doc
28
28
29 def optrst(options, verbose):
29 def optrst(options, verbose):
30 data = []
30 data = []
31 multioccur = False
31 multioccur = False
32 for option in options:
32 for option in options:
33 if len(option) == 5:
33 if len(option) == 5:
34 shortopt, longopt, default, desc, optlabel = option
34 shortopt, longopt, default, desc, optlabel = option
35 else:
35 else:
36 shortopt, longopt, default, desc = option
36 shortopt, longopt, default, desc = option
37 optlabel = _("VALUE") # default label
37 optlabel = _("VALUE") # default label
38
38
39 if _("DEPRECATED") in desc and not verbose:
39 if _("DEPRECATED") in desc and not verbose:
40 continue
40 continue
41
41
42 so = ''
42 so = ''
43 if shortopt:
43 if shortopt:
44 so = '-' + shortopt
44 so = '-' + shortopt
45 lo = '--' + longopt
45 lo = '--' + longopt
46 if default:
46 if default:
47 desc += _(" (default: %s)") % default
47 desc += _(" (default: %s)") % default
48
48
49 if isinstance(default, list):
49 if isinstance(default, list):
50 lo += " %s [+]" % optlabel
50 lo += " %s [+]" % optlabel
51 multioccur = True
51 multioccur = True
52 elif (default is not None) and not isinstance(default, bool):
52 elif (default is not None) and not isinstance(default, bool):
53 lo += " %s" % optlabel
53 lo += " %s" % optlabel
54
54
55 data.append((so, lo, desc))
55 data.append((so, lo, desc))
56
56
57 rst = minirst.maketable(data, 1)
57 rst = minirst.maketable(data, 1)
58
58
59 if multioccur:
59 if multioccur:
60 rst.append(_("\n[+] marked option can be specified multiple times\n"))
60 rst.append(_("\n[+] marked option can be specified multiple times\n"))
61
61
62 return ''.join(rst)
62 return ''.join(rst)
63
63
64 def topicmatch(kw):
64 def topicmatch(kw):
65 """Return help topics matching kw.
65 """Return help topics matching kw.
66
66
67 Returns {'section': [(name, summary), ...], ...} where section is
67 Returns {'section': [(name, summary), ...], ...} where section is
68 one of topics, commands, extensions, or extensioncommands.
68 one of topics, commands, extensions, or extensioncommands.
69 """
69 """
70 kw = encoding.lower(kw)
70 kw = encoding.lower(kw)
71 def lowercontains(container):
71 def lowercontains(container):
72 return kw in encoding.lower(container) # translated in helptable
72 return kw in encoding.lower(container) # translated in helptable
73 results = {'topics': [],
73 results = {'topics': [],
74 'commands': [],
74 'commands': [],
75 'extensions': [],
75 'extensions': [],
76 'extensioncommands': [],
76 'extensioncommands': [],
77 }
77 }
78 for names, header, doc in helptable:
78 for names, header, doc in helptable:
79 if (sum(map(lowercontains, names))
79 if (sum(map(lowercontains, names))
80 or lowercontains(header)
80 or lowercontains(header)
81 or lowercontains(doc())):
81 or lowercontains(doc())):
82 results['topics'].append((names[0], header))
82 results['topics'].append((names[0], header))
83 import commands # avoid cycle
83 import commands # avoid cycle
84 for cmd, entry in commands.table.iteritems():
84 for cmd, entry in commands.table.iteritems():
85 if cmd.startswith('debug'):
85 if cmd.startswith('debug'):
86 continue
86 continue
87 if len(entry) == 3:
87 if len(entry) == 3:
88 summary = entry[2]
88 summary = entry[2]
89 else:
89 else:
90 summary = ''
90 summary = ''
91 # translate docs *before* searching there
91 # translate docs *before* searching there
92 docs = _(getattr(entry[0], '__doc__', None)) or ''
92 docs = _(getattr(entry[0], '__doc__', None)) or ''
93 if kw in cmd or lowercontains(summary) or lowercontains(docs):
93 if kw in cmd or lowercontains(summary) or lowercontains(docs):
94 doclines = docs.splitlines()
94 doclines = docs.splitlines()
95 if doclines:
95 if doclines:
96 summary = doclines[0]
96 summary = doclines[0]
97 cmdname = cmd.split('|')[0].lstrip('^')
97 cmdname = cmd.split('|')[0].lstrip('^')
98 results['commands'].append((cmdname, summary))
98 results['commands'].append((cmdname, summary))
99 for name, docs in itertools.chain(
99 for name, docs in itertools.chain(
100 extensions.enabled().iteritems(),
100 extensions.enabled().iteritems(),
101 extensions.disabled().iteritems()):
101 extensions.disabled().iteritems()):
102 # extensions.load ignores the UI argument
102 # extensions.load ignores the UI argument
103 mod = extensions.load(None, name, '')
103 mod = extensions.load(None, name, '')
104 if lowercontains(name) or lowercontains(docs):
104 if lowercontains(name) or lowercontains(docs):
105 # extension docs are already translated
105 # extension docs are already translated
106 results['extensions'].append((name, docs.splitlines()[0]))
106 results['extensions'].append((name, docs.splitlines()[0]))
107 for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
107 for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
108 if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
108 if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
109 cmdname = cmd.split('|')[0].lstrip('^')
109 cmdname = cmd.split('|')[0].lstrip('^')
110 if entry[0].__doc__:
110 if entry[0].__doc__:
111 cmddoc = gettext(entry[0].__doc__).splitlines()[0]
111 cmddoc = gettext(entry[0].__doc__).splitlines()[0]
112 else:
112 else:
113 cmddoc = _('(no help text available)')
113 cmddoc = _('(no help text available)')
114 results['extensioncommands'].append((cmdname, cmddoc))
114 results['extensioncommands'].append((cmdname, cmddoc))
115 return results
115 return results
116
116
117 def loaddoc(topic):
117 def loaddoc(topic):
118 """Return a delayed loader for help/topic.txt."""
118 """Return a delayed loader for help/topic.txt."""
119
119
120 def loader():
120 def loader():
121 if util.mainfrozen():
121 if util.mainfrozen():
122 module = sys.executable
122 module = sys.executable
123 else:
123 else:
124 module = __file__
124 module = __file__
125 base = os.path.dirname(module)
125 base = os.path.dirname(module)
126
126
127 for dir in ('.', '..'):
127 for dir in ('.', '..'):
128 docdir = os.path.join(base, dir, 'help')
128 docdir = os.path.join(base, dir, 'help')
129 if os.path.isdir(docdir):
129 if os.path.isdir(docdir):
130 break
130 break
131
131
132 path = os.path.join(docdir, topic + ".txt")
132 path = os.path.join(docdir, topic + ".txt")
133 doc = gettext(util.readfile(path))
133 doc = gettext(util.readfile(path))
134 for rewriter in helphooks.get(topic, []):
134 for rewriter in helphooks.get(topic, []):
135 doc = rewriter(topic, doc)
135 doc = rewriter(topic, doc)
136 return doc
136 return doc
137
137
138 return loader
138 return loader
139
139
140 helptable = sorted([
140 helptable = sorted([
141 (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
141 (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
142 (["dates"], _("Date Formats"), loaddoc('dates')),
142 (["dates"], _("Date Formats"), loaddoc('dates')),
143 (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
143 (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
144 (['environment', 'env'], _('Environment Variables'),
144 (['environment', 'env'], _('Environment Variables'),
145 loaddoc('environment')),
145 loaddoc('environment')),
146 (['revs', 'revisions'], _('Specifying Single Revisions'),
146 (['revisions', 'revs'], _('Specifying Single Revisions'),
147 loaddoc('revisions')),
147 loaddoc('revisions')),
148 (['mrevs', 'multirevs'], _('Specifying Multiple Revisions'),
148 (['multirevs', 'mrevs'], _('Specifying Multiple Revisions'),
149 loaddoc('multirevs')),
149 loaddoc('multirevs')),
150 (['revset', 'revsets'], _("Specifying Revision Sets"), loaddoc('revsets')),
150 (['revsets', 'revset'], _("Specifying Revision Sets"), loaddoc('revsets')),
151 (['fileset', 'filesets'], _("Specifying File Sets"), loaddoc('filesets')),
151 (['filesets', 'fileset'], _("Specifying File Sets"), loaddoc('filesets')),
152 (['diffs'], _('Diff Formats'), loaddoc('diffs')),
152 (['diffs'], _('Diff Formats'), loaddoc('diffs')),
153 (['merge-tools'], _('Merge Tools'), loaddoc('merge-tools')),
153 (['merge-tools'], _('Merge Tools'), loaddoc('merge-tools')),
154 (['templating', 'templates', 'template', 'style'], _('Template Usage'),
154 (['templating', 'templates', 'template', 'style'], _('Template Usage'),
155 loaddoc('templates')),
155 loaddoc('templates')),
156 (['urls'], _('URL Paths'), loaddoc('urls')),
156 (['urls'], _('URL Paths'), loaddoc('urls')),
157 (["extensions"], _("Using Additional Features"), extshelp),
157 (["extensions"], _("Using Additional Features"), extshelp),
158 (["subrepo", "subrepos"], _("Subrepositories"), loaddoc('subrepos')),
158 (["subrepos", "subrepo"], _("Subrepositories"), loaddoc('subrepos')),
159 (["hgweb"], _("Configuring hgweb"), loaddoc('hgweb')),
159 (["hgweb"], _("Configuring hgweb"), loaddoc('hgweb')),
160 (["glossary"], _("Glossary"), loaddoc('glossary')),
160 (["glossary"], _("Glossary"), loaddoc('glossary')),
161 (["hgignore", "ignore"], _("Syntax for Mercurial Ignore Files"),
161 (["hgignore", "ignore"], _("Syntax for Mercurial Ignore Files"),
162 loaddoc('hgignore')),
162 loaddoc('hgignore')),
163 (["phases"], _("Working with Phases"), loaddoc('phases')),
163 (["phases"], _("Working with Phases"), loaddoc('phases')),
164 ])
164 ])
165
165
166 # Map topics to lists of callable taking the current topic help and
166 # Map topics to lists of callable taking the current topic help and
167 # returning the updated version
167 # returning the updated version
168 helphooks = {}
168 helphooks = {}
169
169
170 def addtopichook(topic, rewriter):
170 def addtopichook(topic, rewriter):
171 helphooks.setdefault(topic, []).append(rewriter)
171 helphooks.setdefault(topic, []).append(rewriter)
172
172
173 def makeitemsdoc(topic, doc, marker, items):
173 def makeitemsdoc(topic, doc, marker, items):
174 """Extract docstring from the items key to function mapping, build a
174 """Extract docstring from the items key to function mapping, build a
175 .single documentation block and use it to overwrite the marker in doc
175 .single documentation block and use it to overwrite the marker in doc
176 """
176 """
177 entries = []
177 entries = []
178 for name in sorted(items):
178 for name in sorted(items):
179 text = (items[name].__doc__ or '').rstrip()
179 text = (items[name].__doc__ or '').rstrip()
180 if not text:
180 if not text:
181 continue
181 continue
182 text = gettext(text)
182 text = gettext(text)
183 lines = text.splitlines()
183 lines = text.splitlines()
184 doclines = [(lines[0])]
184 doclines = [(lines[0])]
185 for l in lines[1:]:
185 for l in lines[1:]:
186 # Stop once we find some Python doctest
186 # Stop once we find some Python doctest
187 if l.strip().startswith('>>>'):
187 if l.strip().startswith('>>>'):
188 break
188 break
189 doclines.append(' ' + l.strip())
189 doclines.append(' ' + l.strip())
190 entries.append('\n'.join(doclines))
190 entries.append('\n'.join(doclines))
191 entries = '\n\n'.join(entries)
191 entries = '\n\n'.join(entries)
192 return doc.replace(marker, entries)
192 return doc.replace(marker, entries)
193
193
194 def addtopicsymbols(topic, marker, symbols):
194 def addtopicsymbols(topic, marker, symbols):
195 def add(topic, doc):
195 def add(topic, doc):
196 return makeitemsdoc(topic, doc, marker, symbols)
196 return makeitemsdoc(topic, doc, marker, symbols)
197 addtopichook(topic, add)
197 addtopichook(topic, add)
198
198
199 addtopicsymbols('filesets', '.. predicatesmarker', fileset.symbols)
199 addtopicsymbols('filesets', '.. predicatesmarker', fileset.symbols)
200 addtopicsymbols('merge-tools', '.. internaltoolsmarker', filemerge.internals)
200 addtopicsymbols('merge-tools', '.. internaltoolsmarker', filemerge.internals)
201 addtopicsymbols('revsets', '.. predicatesmarker', revset.symbols)
201 addtopicsymbols('revsets', '.. predicatesmarker', revset.symbols)
202 addtopicsymbols('templates', '.. keywordsmarker', templatekw.dockeywords)
202 addtopicsymbols('templates', '.. keywordsmarker', templatekw.dockeywords)
203 addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters)
203 addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters)
@@ -1,971 +1,970 b''
1 #
1 #
2 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
2 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
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 import os, mimetypes, re, cgi, copy
8 import os, mimetypes, re, cgi, copy
9 import webutil
9 import webutil
10 from mercurial import error, encoding, archival, templater, templatefilters
10 from mercurial import error, encoding, archival, templater, templatefilters
11 from mercurial.node import short, hex, nullid
11 from mercurial.node import short, hex, nullid
12 from mercurial.util import binary
12 from mercurial.util import binary
13 from common import paritygen, staticfile, get_contact, ErrorResponse
13 from common import paritygen, staticfile, get_contact, ErrorResponse
14 from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND
14 from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND
15 from mercurial import graphmod, patch
15 from mercurial import graphmod, patch
16 from mercurial import help as helpmod
16 from mercurial import help as helpmod
17 from mercurial.i18n import _
17 from mercurial.i18n import _
18
18
19 # __all__ is populated with the allowed commands. Be sure to add to it if
19 # __all__ is populated with the allowed commands. Be sure to add to it if
20 # you're adding a new command, or the new command won't work.
20 # you're adding a new command, or the new command won't work.
21
21
22 __all__ = [
22 __all__ = [
23 'log', 'rawfile', 'file', 'changelog', 'shortlog', 'changeset', 'rev',
23 'log', 'rawfile', 'file', 'changelog', 'shortlog', 'changeset', 'rev',
24 'manifest', 'tags', 'bookmarks', 'branches', 'summary', 'filediff', 'diff',
24 'manifest', 'tags', 'bookmarks', 'branches', 'summary', 'filediff', 'diff',
25 'comparison', 'annotate', 'filelog', 'archive', 'static', 'graph', 'help',
25 'comparison', 'annotate', 'filelog', 'archive', 'static', 'graph', 'help',
26 ]
26 ]
27
27
28 def log(web, req, tmpl):
28 def log(web, req, tmpl):
29 if 'file' in req.form and req.form['file'][0]:
29 if 'file' in req.form and req.form['file'][0]:
30 return filelog(web, req, tmpl)
30 return filelog(web, req, tmpl)
31 else:
31 else:
32 return changelog(web, req, tmpl)
32 return changelog(web, req, tmpl)
33
33
34 def rawfile(web, req, tmpl):
34 def rawfile(web, req, tmpl):
35 guessmime = web.configbool('web', 'guessmime', False)
35 guessmime = web.configbool('web', 'guessmime', False)
36
36
37 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
37 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
38 if not path:
38 if not path:
39 content = manifest(web, req, tmpl)
39 content = manifest(web, req, tmpl)
40 req.respond(HTTP_OK, web.ctype)
40 req.respond(HTTP_OK, web.ctype)
41 return content
41 return content
42
42
43 try:
43 try:
44 fctx = webutil.filectx(web.repo, req)
44 fctx = webutil.filectx(web.repo, req)
45 except error.LookupError, inst:
45 except error.LookupError, inst:
46 try:
46 try:
47 content = manifest(web, req, tmpl)
47 content = manifest(web, req, tmpl)
48 req.respond(HTTP_OK, web.ctype)
48 req.respond(HTTP_OK, web.ctype)
49 return content
49 return content
50 except ErrorResponse:
50 except ErrorResponse:
51 raise inst
51 raise inst
52
52
53 path = fctx.path()
53 path = fctx.path()
54 text = fctx.data()
54 text = fctx.data()
55 mt = 'application/binary'
55 mt = 'application/binary'
56 if guessmime:
56 if guessmime:
57 mt = mimetypes.guess_type(path)[0]
57 mt = mimetypes.guess_type(path)[0]
58 if mt is None:
58 if mt is None:
59 mt = binary(text) and 'application/binary' or 'text/plain'
59 mt = binary(text) and 'application/binary' or 'text/plain'
60 if mt.startswith('text/'):
60 if mt.startswith('text/'):
61 mt += '; charset="%s"' % encoding.encoding
61 mt += '; charset="%s"' % encoding.encoding
62
62
63 req.respond(HTTP_OK, mt, path, len(text))
63 req.respond(HTTP_OK, mt, path, len(text))
64 return [text]
64 return [text]
65
65
66 def _filerevision(web, tmpl, fctx):
66 def _filerevision(web, tmpl, fctx):
67 f = fctx.path()
67 f = fctx.path()
68 text = fctx.data()
68 text = fctx.data()
69 parity = paritygen(web.stripecount)
69 parity = paritygen(web.stripecount)
70
70
71 if binary(text):
71 if binary(text):
72 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
72 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
73 text = '(binary:%s)' % mt
73 text = '(binary:%s)' % mt
74
74
75 def lines():
75 def lines():
76 for lineno, t in enumerate(text.splitlines(True)):
76 for lineno, t in enumerate(text.splitlines(True)):
77 yield {"line": t,
77 yield {"line": t,
78 "lineid": "l%d" % (lineno + 1),
78 "lineid": "l%d" % (lineno + 1),
79 "linenumber": "% 6d" % (lineno + 1),
79 "linenumber": "% 6d" % (lineno + 1),
80 "parity": parity.next()}
80 "parity": parity.next()}
81
81
82 return tmpl("filerevision",
82 return tmpl("filerevision",
83 file=f,
83 file=f,
84 path=webutil.up(f),
84 path=webutil.up(f),
85 text=lines(),
85 text=lines(),
86 rev=fctx.rev(),
86 rev=fctx.rev(),
87 node=fctx.hex(),
87 node=fctx.hex(),
88 author=fctx.user(),
88 author=fctx.user(),
89 date=fctx.date(),
89 date=fctx.date(),
90 desc=fctx.description(),
90 desc=fctx.description(),
91 branch=webutil.nodebranchnodefault(fctx),
91 branch=webutil.nodebranchnodefault(fctx),
92 parent=webutil.parents(fctx),
92 parent=webutil.parents(fctx),
93 child=webutil.children(fctx),
93 child=webutil.children(fctx),
94 rename=webutil.renamelink(fctx),
94 rename=webutil.renamelink(fctx),
95 permissions=fctx.manifest().flags(f))
95 permissions=fctx.manifest().flags(f))
96
96
97 def file(web, req, tmpl):
97 def file(web, req, tmpl):
98 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
98 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
99 if not path:
99 if not path:
100 return manifest(web, req, tmpl)
100 return manifest(web, req, tmpl)
101 try:
101 try:
102 return _filerevision(web, tmpl, webutil.filectx(web.repo, req))
102 return _filerevision(web, tmpl, webutil.filectx(web.repo, req))
103 except error.LookupError, inst:
103 except error.LookupError, inst:
104 try:
104 try:
105 return manifest(web, req, tmpl)
105 return manifest(web, req, tmpl)
106 except ErrorResponse:
106 except ErrorResponse:
107 raise inst
107 raise inst
108
108
109 def _search(web, req, tmpl):
109 def _search(web, req, tmpl):
110
110
111 query = req.form['rev'][0]
111 query = req.form['rev'][0]
112 revcount = web.maxchanges
112 revcount = web.maxchanges
113 if 'revcount' in req.form:
113 if 'revcount' in req.form:
114 revcount = int(req.form.get('revcount', [revcount])[0])
114 revcount = int(req.form.get('revcount', [revcount])[0])
115 revcount = max(revcount, 1)
115 revcount = max(revcount, 1)
116 tmpl.defaults['sessionvars']['revcount'] = revcount
116 tmpl.defaults['sessionvars']['revcount'] = revcount
117
117
118 lessvars = copy.copy(tmpl.defaults['sessionvars'])
118 lessvars = copy.copy(tmpl.defaults['sessionvars'])
119 lessvars['revcount'] = max(revcount / 2, 1)
119 lessvars['revcount'] = max(revcount / 2, 1)
120 lessvars['rev'] = query
120 lessvars['rev'] = query
121 morevars = copy.copy(tmpl.defaults['sessionvars'])
121 morevars = copy.copy(tmpl.defaults['sessionvars'])
122 morevars['revcount'] = revcount * 2
122 morevars['revcount'] = revcount * 2
123 morevars['rev'] = query
123 morevars['rev'] = query
124
124
125 def changelist(**map):
125 def changelist(**map):
126 count = 0
126 count = 0
127 lower = encoding.lower
127 lower = encoding.lower
128 qw = lower(query).split()
128 qw = lower(query).split()
129
129
130 def revgen():
130 def revgen():
131 for i in xrange(len(web.repo) - 1, 0, -100):
131 for i in xrange(len(web.repo) - 1, 0, -100):
132 l = []
132 l = []
133 for j in xrange(max(0, i - 100), i + 1):
133 for j in xrange(max(0, i - 100), i + 1):
134 ctx = web.repo[j]
134 ctx = web.repo[j]
135 l.append(ctx)
135 l.append(ctx)
136 l.reverse()
136 l.reverse()
137 for e in l:
137 for e in l:
138 yield e
138 yield e
139
139
140 for ctx in revgen():
140 for ctx in revgen():
141 miss = 0
141 miss = 0
142 for q in qw:
142 for q in qw:
143 if not (q in lower(ctx.user()) or
143 if not (q in lower(ctx.user()) or
144 q in lower(ctx.description()) or
144 q in lower(ctx.description()) or
145 q in lower(" ".join(ctx.files()))):
145 q in lower(" ".join(ctx.files()))):
146 miss = 1
146 miss = 1
147 break
147 break
148 if miss:
148 if miss:
149 continue
149 continue
150
150
151 count += 1
151 count += 1
152 n = ctx.node()
152 n = ctx.node()
153 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
153 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
154 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
154 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
155
155
156 yield tmpl('searchentry',
156 yield tmpl('searchentry',
157 parity=parity.next(),
157 parity=parity.next(),
158 author=ctx.user(),
158 author=ctx.user(),
159 parent=webutil.parents(ctx),
159 parent=webutil.parents(ctx),
160 child=webutil.children(ctx),
160 child=webutil.children(ctx),
161 changelogtag=showtags,
161 changelogtag=showtags,
162 desc=ctx.description(),
162 desc=ctx.description(),
163 date=ctx.date(),
163 date=ctx.date(),
164 files=files,
164 files=files,
165 rev=ctx.rev(),
165 rev=ctx.rev(),
166 node=hex(n),
166 node=hex(n),
167 tags=webutil.nodetagsdict(web.repo, n),
167 tags=webutil.nodetagsdict(web.repo, n),
168 bookmarks=webutil.nodebookmarksdict(web.repo, n),
168 bookmarks=webutil.nodebookmarksdict(web.repo, n),
169 inbranch=webutil.nodeinbranch(web.repo, ctx),
169 inbranch=webutil.nodeinbranch(web.repo, ctx),
170 branches=webutil.nodebranchdict(web.repo, ctx))
170 branches=webutil.nodebranchdict(web.repo, ctx))
171
171
172 if count >= revcount:
172 if count >= revcount:
173 break
173 break
174
174
175 tip = web.repo['tip']
175 tip = web.repo['tip']
176 parity = paritygen(web.stripecount)
176 parity = paritygen(web.stripecount)
177
177
178 return tmpl('search', query=query, node=tip.hex(),
178 return tmpl('search', query=query, node=tip.hex(),
179 entries=changelist, archives=web.archivelist("tip"),
179 entries=changelist, archives=web.archivelist("tip"),
180 morevars=morevars, lessvars=lessvars)
180 morevars=morevars, lessvars=lessvars)
181
181
182 def changelog(web, req, tmpl, shortlog=False):
182 def changelog(web, req, tmpl, shortlog=False):
183
183
184 if 'node' in req.form:
184 if 'node' in req.form:
185 ctx = webutil.changectx(web.repo, req)
185 ctx = webutil.changectx(web.repo, req)
186 else:
186 else:
187 if 'rev' in req.form:
187 if 'rev' in req.form:
188 hi = req.form['rev'][0]
188 hi = req.form['rev'][0]
189 else:
189 else:
190 hi = len(web.repo) - 1
190 hi = len(web.repo) - 1
191 try:
191 try:
192 ctx = web.repo[hi]
192 ctx = web.repo[hi]
193 except error.RepoError:
193 except error.RepoError:
194 return _search(web, req, tmpl) # XXX redirect to 404 page?
194 return _search(web, req, tmpl) # XXX redirect to 404 page?
195
195
196 def changelist(limit=0, **map):
196 def changelist(limit=0, **map):
197 l = [] # build a list in forward order for efficiency
197 l = [] # build a list in forward order for efficiency
198 for i in xrange(start, end):
198 for i in xrange(start, end):
199 ctx = web.repo[i]
199 ctx = web.repo[i]
200 n = ctx.node()
200 n = ctx.node()
201 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
201 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
202 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
202 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
203
203
204 l.insert(0, {"parity": parity.next(),
204 l.insert(0, {"parity": parity.next(),
205 "author": ctx.user(),
205 "author": ctx.user(),
206 "parent": webutil.parents(ctx, i - 1),
206 "parent": webutil.parents(ctx, i - 1),
207 "child": webutil.children(ctx, i + 1),
207 "child": webutil.children(ctx, i + 1),
208 "changelogtag": showtags,
208 "changelogtag": showtags,
209 "desc": ctx.description(),
209 "desc": ctx.description(),
210 "date": ctx.date(),
210 "date": ctx.date(),
211 "files": files,
211 "files": files,
212 "rev": i,
212 "rev": i,
213 "node": hex(n),
213 "node": hex(n),
214 "tags": webutil.nodetagsdict(web.repo, n),
214 "tags": webutil.nodetagsdict(web.repo, n),
215 "bookmarks": webutil.nodebookmarksdict(web.repo, n),
215 "bookmarks": webutil.nodebookmarksdict(web.repo, n),
216 "inbranch": webutil.nodeinbranch(web.repo, ctx),
216 "inbranch": webutil.nodeinbranch(web.repo, ctx),
217 "branches": webutil.nodebranchdict(web.repo, ctx)
217 "branches": webutil.nodebranchdict(web.repo, ctx)
218 })
218 })
219
219
220 if limit > 0:
220 if limit > 0:
221 l = l[:limit]
221 l = l[:limit]
222
222
223 for e in l:
223 for e in l:
224 yield e
224 yield e
225
225
226 revcount = shortlog and web.maxshortchanges or web.maxchanges
226 revcount = shortlog and web.maxshortchanges or web.maxchanges
227 if 'revcount' in req.form:
227 if 'revcount' in req.form:
228 revcount = int(req.form.get('revcount', [revcount])[0])
228 revcount = int(req.form.get('revcount', [revcount])[0])
229 revcount = max(revcount, 1)
229 revcount = max(revcount, 1)
230 tmpl.defaults['sessionvars']['revcount'] = revcount
230 tmpl.defaults['sessionvars']['revcount'] = revcount
231
231
232 lessvars = copy.copy(tmpl.defaults['sessionvars'])
232 lessvars = copy.copy(tmpl.defaults['sessionvars'])
233 lessvars['revcount'] = max(revcount / 2, 1)
233 lessvars['revcount'] = max(revcount / 2, 1)
234 morevars = copy.copy(tmpl.defaults['sessionvars'])
234 morevars = copy.copy(tmpl.defaults['sessionvars'])
235 morevars['revcount'] = revcount * 2
235 morevars['revcount'] = revcount * 2
236
236
237 count = len(web.repo)
237 count = len(web.repo)
238 pos = ctx.rev()
238 pos = ctx.rev()
239 start = max(0, pos - revcount + 1)
239 start = max(0, pos - revcount + 1)
240 end = min(count, start + revcount)
240 end = min(count, start + revcount)
241 pos = end - 1
241 pos = end - 1
242 parity = paritygen(web.stripecount, offset=start - end)
242 parity = paritygen(web.stripecount, offset=start - end)
243
243
244 changenav = webutil.revnavgen(pos, revcount, count, web.repo.changectx)
244 changenav = webutil.revnavgen(pos, revcount, count, web.repo.changectx)
245
245
246 return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
246 return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
247 node=ctx.hex(), rev=pos, changesets=count,
247 node=ctx.hex(), rev=pos, changesets=count,
248 entries=lambda **x: changelist(limit=0,**x),
248 entries=lambda **x: changelist(limit=0,**x),
249 latestentry=lambda **x: changelist(limit=1,**x),
249 latestentry=lambda **x: changelist(limit=1,**x),
250 archives=web.archivelist("tip"), revcount=revcount,
250 archives=web.archivelist("tip"), revcount=revcount,
251 morevars=morevars, lessvars=lessvars)
251 morevars=morevars, lessvars=lessvars)
252
252
253 def shortlog(web, req, tmpl):
253 def shortlog(web, req, tmpl):
254 return changelog(web, req, tmpl, shortlog = True)
254 return changelog(web, req, tmpl, shortlog = True)
255
255
256 def changeset(web, req, tmpl):
256 def changeset(web, req, tmpl):
257 ctx = webutil.changectx(web.repo, req)
257 ctx = webutil.changectx(web.repo, req)
258 showtags = webutil.showtag(web.repo, tmpl, 'changesettag', ctx.node())
258 showtags = webutil.showtag(web.repo, tmpl, 'changesettag', ctx.node())
259 showbookmarks = webutil.showbookmark(web.repo, tmpl, 'changesetbookmark',
259 showbookmarks = webutil.showbookmark(web.repo, tmpl, 'changesetbookmark',
260 ctx.node())
260 ctx.node())
261 showbranch = webutil.nodebranchnodefault(ctx)
261 showbranch = webutil.nodebranchnodefault(ctx)
262
262
263 files = []
263 files = []
264 parity = paritygen(web.stripecount)
264 parity = paritygen(web.stripecount)
265 for blockno, f in enumerate(ctx.files()):
265 for blockno, f in enumerate(ctx.files()):
266 template = f in ctx and 'filenodelink' or 'filenolink'
266 template = f in ctx and 'filenodelink' or 'filenolink'
267 files.append(tmpl(template,
267 files.append(tmpl(template,
268 node=ctx.hex(), file=f, blockno=blockno + 1,
268 node=ctx.hex(), file=f, blockno=blockno + 1,
269 parity=parity.next()))
269 parity=parity.next()))
270
270
271 style = web.config('web', 'style', 'paper')
271 style = web.config('web', 'style', 'paper')
272 if 'style' in req.form:
272 if 'style' in req.form:
273 style = req.form['style'][0]
273 style = req.form['style'][0]
274
274
275 parity = paritygen(web.stripecount)
275 parity = paritygen(web.stripecount)
276 diffs = webutil.diffs(web.repo, tmpl, ctx, None, parity, style)
276 diffs = webutil.diffs(web.repo, tmpl, ctx, None, parity, style)
277
277
278 parity = paritygen(web.stripecount)
278 parity = paritygen(web.stripecount)
279 diffstatgen = webutil.diffstatgen(ctx)
279 diffstatgen = webutil.diffstatgen(ctx)
280 diffstat = webutil.diffstat(tmpl, ctx, diffstatgen, parity)
280 diffstat = webutil.diffstat(tmpl, ctx, diffstatgen, parity)
281
281
282 return tmpl('changeset',
282 return tmpl('changeset',
283 diff=diffs,
283 diff=diffs,
284 rev=ctx.rev(),
284 rev=ctx.rev(),
285 node=ctx.hex(),
285 node=ctx.hex(),
286 parent=webutil.parents(ctx),
286 parent=webutil.parents(ctx),
287 child=webutil.children(ctx),
287 child=webutil.children(ctx),
288 changesettag=showtags,
288 changesettag=showtags,
289 changesetbookmark=showbookmarks,
289 changesetbookmark=showbookmarks,
290 changesetbranch=showbranch,
290 changesetbranch=showbranch,
291 author=ctx.user(),
291 author=ctx.user(),
292 desc=ctx.description(),
292 desc=ctx.description(),
293 date=ctx.date(),
293 date=ctx.date(),
294 files=files,
294 files=files,
295 diffsummary=lambda **x: webutil.diffsummary(diffstatgen),
295 diffsummary=lambda **x: webutil.diffsummary(diffstatgen),
296 diffstat=diffstat,
296 diffstat=diffstat,
297 archives=web.archivelist(ctx.hex()),
297 archives=web.archivelist(ctx.hex()),
298 tags=webutil.nodetagsdict(web.repo, ctx.node()),
298 tags=webutil.nodetagsdict(web.repo, ctx.node()),
299 bookmarks=webutil.nodebookmarksdict(web.repo, ctx.node()),
299 bookmarks=webutil.nodebookmarksdict(web.repo, ctx.node()),
300 branch=webutil.nodebranchnodefault(ctx),
300 branch=webutil.nodebranchnodefault(ctx),
301 inbranch=webutil.nodeinbranch(web.repo, ctx),
301 inbranch=webutil.nodeinbranch(web.repo, ctx),
302 branches=webutil.nodebranchdict(web.repo, ctx))
302 branches=webutil.nodebranchdict(web.repo, ctx))
303
303
304 rev = changeset
304 rev = changeset
305
305
306 def decodepath(path):
306 def decodepath(path):
307 """Hook for mapping a path in the repository to a path in the
307 """Hook for mapping a path in the repository to a path in the
308 working copy.
308 working copy.
309
309
310 Extensions (e.g., largefiles) can override this to remap files in
310 Extensions (e.g., largefiles) can override this to remap files in
311 the virtual file system presented by the manifest command below."""
311 the virtual file system presented by the manifest command below."""
312 return path
312 return path
313
313
314 def manifest(web, req, tmpl):
314 def manifest(web, req, tmpl):
315 ctx = webutil.changectx(web.repo, req)
315 ctx = webutil.changectx(web.repo, req)
316 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
316 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
317 mf = ctx.manifest()
317 mf = ctx.manifest()
318 node = ctx.node()
318 node = ctx.node()
319
319
320 files = {}
320 files = {}
321 dirs = {}
321 dirs = {}
322 parity = paritygen(web.stripecount)
322 parity = paritygen(web.stripecount)
323
323
324 if path and path[-1] != "/":
324 if path and path[-1] != "/":
325 path += "/"
325 path += "/"
326 l = len(path)
326 l = len(path)
327 abspath = "/" + path
327 abspath = "/" + path
328
328
329 for full, n in mf.iteritems():
329 for full, n in mf.iteritems():
330 # the virtual path (working copy path) used for the full
330 # the virtual path (working copy path) used for the full
331 # (repository) path
331 # (repository) path
332 f = decodepath(full)
332 f = decodepath(full)
333
333
334 if f[:l] != path:
334 if f[:l] != path:
335 continue
335 continue
336 remain = f[l:]
336 remain = f[l:]
337 elements = remain.split('/')
337 elements = remain.split('/')
338 if len(elements) == 1:
338 if len(elements) == 1:
339 files[remain] = full
339 files[remain] = full
340 else:
340 else:
341 h = dirs # need to retain ref to dirs (root)
341 h = dirs # need to retain ref to dirs (root)
342 for elem in elements[0:-1]:
342 for elem in elements[0:-1]:
343 if elem not in h:
343 if elem not in h:
344 h[elem] = {}
344 h[elem] = {}
345 h = h[elem]
345 h = h[elem]
346 if len(h) > 1:
346 if len(h) > 1:
347 break
347 break
348 h[None] = None # denotes files present
348 h[None] = None # denotes files present
349
349
350 if mf and not files and not dirs:
350 if mf and not files and not dirs:
351 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
351 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
352
352
353 def filelist(**map):
353 def filelist(**map):
354 for f in sorted(files):
354 for f in sorted(files):
355 full = files[f]
355 full = files[f]
356
356
357 fctx = ctx.filectx(full)
357 fctx = ctx.filectx(full)
358 yield {"file": full,
358 yield {"file": full,
359 "parity": parity.next(),
359 "parity": parity.next(),
360 "basename": f,
360 "basename": f,
361 "date": fctx.date(),
361 "date": fctx.date(),
362 "size": fctx.size(),
362 "size": fctx.size(),
363 "permissions": mf.flags(full)}
363 "permissions": mf.flags(full)}
364
364
365 def dirlist(**map):
365 def dirlist(**map):
366 for d in sorted(dirs):
366 for d in sorted(dirs):
367
367
368 emptydirs = []
368 emptydirs = []
369 h = dirs[d]
369 h = dirs[d]
370 while isinstance(h, dict) and len(h) == 1:
370 while isinstance(h, dict) and len(h) == 1:
371 k, v = h.items()[0]
371 k, v = h.items()[0]
372 if v:
372 if v:
373 emptydirs.append(k)
373 emptydirs.append(k)
374 h = v
374 h = v
375
375
376 path = "%s%s" % (abspath, d)
376 path = "%s%s" % (abspath, d)
377 yield {"parity": parity.next(),
377 yield {"parity": parity.next(),
378 "path": path,
378 "path": path,
379 "emptydirs": "/".join(emptydirs),
379 "emptydirs": "/".join(emptydirs),
380 "basename": d}
380 "basename": d}
381
381
382 return tmpl("manifest",
382 return tmpl("manifest",
383 rev=ctx.rev(),
383 rev=ctx.rev(),
384 node=hex(node),
384 node=hex(node),
385 path=abspath,
385 path=abspath,
386 up=webutil.up(abspath),
386 up=webutil.up(abspath),
387 upparity=parity.next(),
387 upparity=parity.next(),
388 fentries=filelist,
388 fentries=filelist,
389 dentries=dirlist,
389 dentries=dirlist,
390 archives=web.archivelist(hex(node)),
390 archives=web.archivelist(hex(node)),
391 tags=webutil.nodetagsdict(web.repo, node),
391 tags=webutil.nodetagsdict(web.repo, node),
392 bookmarks=webutil.nodebookmarksdict(web.repo, node),
392 bookmarks=webutil.nodebookmarksdict(web.repo, node),
393 inbranch=webutil.nodeinbranch(web.repo, ctx),
393 inbranch=webutil.nodeinbranch(web.repo, ctx),
394 branches=webutil.nodebranchdict(web.repo, ctx))
394 branches=webutil.nodebranchdict(web.repo, ctx))
395
395
396 def tags(web, req, tmpl):
396 def tags(web, req, tmpl):
397 i = reversed(web.repo.tagslist())
397 i = reversed(web.repo.tagslist())
398 parity = paritygen(web.stripecount)
398 parity = paritygen(web.stripecount)
399
399
400 def entries(notip=False, limit=0, **map):
400 def entries(notip=False, limit=0, **map):
401 count = 0
401 count = 0
402 for k, n in i:
402 for k, n in i:
403 if notip and k == "tip":
403 if notip and k == "tip":
404 continue
404 continue
405 if limit > 0 and count >= limit:
405 if limit > 0 and count >= limit:
406 continue
406 continue
407 count = count + 1
407 count = count + 1
408 yield {"parity": parity.next(),
408 yield {"parity": parity.next(),
409 "tag": k,
409 "tag": k,
410 "date": web.repo[n].date(),
410 "date": web.repo[n].date(),
411 "node": hex(n)}
411 "node": hex(n)}
412
412
413 return tmpl("tags",
413 return tmpl("tags",
414 node=hex(web.repo.changelog.tip()),
414 node=hex(web.repo.changelog.tip()),
415 entries=lambda **x: entries(False, 0, **x),
415 entries=lambda **x: entries(False, 0, **x),
416 entriesnotip=lambda **x: entries(True, 0, **x),
416 entriesnotip=lambda **x: entries(True, 0, **x),
417 latestentry=lambda **x: entries(True, 1, **x))
417 latestentry=lambda **x: entries(True, 1, **x))
418
418
419 def bookmarks(web, req, tmpl):
419 def bookmarks(web, req, tmpl):
420 i = web.repo._bookmarks.items()
420 i = web.repo._bookmarks.items()
421 parity = paritygen(web.stripecount)
421 parity = paritygen(web.stripecount)
422
422
423 def entries(limit=0, **map):
423 def entries(limit=0, **map):
424 count = 0
424 count = 0
425 for k, n in sorted(i):
425 for k, n in sorted(i):
426 if limit > 0 and count >= limit:
426 if limit > 0 and count >= limit:
427 continue
427 continue
428 count = count + 1
428 count = count + 1
429 yield {"parity": parity.next(),
429 yield {"parity": parity.next(),
430 "bookmark": k,
430 "bookmark": k,
431 "date": web.repo[n].date(),
431 "date": web.repo[n].date(),
432 "node": hex(n)}
432 "node": hex(n)}
433
433
434 return tmpl("bookmarks",
434 return tmpl("bookmarks",
435 node=hex(web.repo.changelog.tip()),
435 node=hex(web.repo.changelog.tip()),
436 entries=lambda **x: entries(0, **x),
436 entries=lambda **x: entries(0, **x),
437 latestentry=lambda **x: entries(1, **x))
437 latestentry=lambda **x: entries(1, **x))
438
438
439 def branches(web, req, tmpl):
439 def branches(web, req, tmpl):
440 tips = (web.repo[n] for t, n in web.repo.branchtags().iteritems())
440 tips = (web.repo[n] for t, n in web.repo.branchtags().iteritems())
441 heads = web.repo.heads()
441 heads = web.repo.heads()
442 parity = paritygen(web.stripecount)
442 parity = paritygen(web.stripecount)
443 sortkey = lambda ctx: (not ctx.closesbranch(), ctx.rev())
443 sortkey = lambda ctx: (not ctx.closesbranch(), ctx.rev())
444
444
445 def entries(limit, **map):
445 def entries(limit, **map):
446 count = 0
446 count = 0
447 for ctx in sorted(tips, key=sortkey, reverse=True):
447 for ctx in sorted(tips, key=sortkey, reverse=True):
448 if limit > 0 and count >= limit:
448 if limit > 0 and count >= limit:
449 return
449 return
450 count += 1
450 count += 1
451 if not web.repo.branchheads(ctx.branch()):
451 if not web.repo.branchheads(ctx.branch()):
452 status = 'closed'
452 status = 'closed'
453 elif ctx.node() not in heads:
453 elif ctx.node() not in heads:
454 status = 'inactive'
454 status = 'inactive'
455 else:
455 else:
456 status = 'open'
456 status = 'open'
457 yield {'parity': parity.next(),
457 yield {'parity': parity.next(),
458 'branch': ctx.branch(),
458 'branch': ctx.branch(),
459 'status': status,
459 'status': status,
460 'node': ctx.hex(),
460 'node': ctx.hex(),
461 'date': ctx.date()}
461 'date': ctx.date()}
462
462
463 return tmpl('branches', node=hex(web.repo.changelog.tip()),
463 return tmpl('branches', node=hex(web.repo.changelog.tip()),
464 entries=lambda **x: entries(0, **x),
464 entries=lambda **x: entries(0, **x),
465 latestentry=lambda **x: entries(1, **x))
465 latestentry=lambda **x: entries(1, **x))
466
466
467 def summary(web, req, tmpl):
467 def summary(web, req, tmpl):
468 i = reversed(web.repo.tagslist())
468 i = reversed(web.repo.tagslist())
469
469
470 def tagentries(**map):
470 def tagentries(**map):
471 parity = paritygen(web.stripecount)
471 parity = paritygen(web.stripecount)
472 count = 0
472 count = 0
473 for k, n in i:
473 for k, n in i:
474 if k == "tip": # skip tip
474 if k == "tip": # skip tip
475 continue
475 continue
476
476
477 count += 1
477 count += 1
478 if count > 10: # limit to 10 tags
478 if count > 10: # limit to 10 tags
479 break
479 break
480
480
481 yield tmpl("tagentry",
481 yield tmpl("tagentry",
482 parity=parity.next(),
482 parity=parity.next(),
483 tag=k,
483 tag=k,
484 node=hex(n),
484 node=hex(n),
485 date=web.repo[n].date())
485 date=web.repo[n].date())
486
486
487 def bookmarks(**map):
487 def bookmarks(**map):
488 parity = paritygen(web.stripecount)
488 parity = paritygen(web.stripecount)
489 b = web.repo._bookmarks.items()
489 b = web.repo._bookmarks.items()
490 for k, n in sorted(b)[:10]: # limit to 10 bookmarks
490 for k, n in sorted(b)[:10]: # limit to 10 bookmarks
491 yield {'parity': parity.next(),
491 yield {'parity': parity.next(),
492 'bookmark': k,
492 'bookmark': k,
493 'date': web.repo[n].date(),
493 'date': web.repo[n].date(),
494 'node': hex(n)}
494 'node': hex(n)}
495
495
496 def branches(**map):
496 def branches(**map):
497 parity = paritygen(web.stripecount)
497 parity = paritygen(web.stripecount)
498
498
499 b = web.repo.branchtags()
499 b = web.repo.branchtags()
500 l = [(-web.repo.changelog.rev(n), n, t) for t, n in b.iteritems()]
500 l = [(-web.repo.changelog.rev(n), n, t) for t, n in b.iteritems()]
501 for r, n, t in sorted(l):
501 for r, n, t in sorted(l):
502 yield {'parity': parity.next(),
502 yield {'parity': parity.next(),
503 'branch': t,
503 'branch': t,
504 'node': hex(n),
504 'node': hex(n),
505 'date': web.repo[n].date()}
505 'date': web.repo[n].date()}
506
506
507 def changelist(**map):
507 def changelist(**map):
508 parity = paritygen(web.stripecount, offset=start - end)
508 parity = paritygen(web.stripecount, offset=start - end)
509 l = [] # build a list in forward order for efficiency
509 l = [] # build a list in forward order for efficiency
510 for i in xrange(start, end):
510 for i in xrange(start, end):
511 ctx = web.repo[i]
511 ctx = web.repo[i]
512 n = ctx.node()
512 n = ctx.node()
513 hn = hex(n)
513 hn = hex(n)
514
514
515 l.insert(0, tmpl(
515 l.insert(0, tmpl(
516 'shortlogentry',
516 'shortlogentry',
517 parity=parity.next(),
517 parity=parity.next(),
518 author=ctx.user(),
518 author=ctx.user(),
519 desc=ctx.description(),
519 desc=ctx.description(),
520 date=ctx.date(),
520 date=ctx.date(),
521 rev=i,
521 rev=i,
522 node=hn,
522 node=hn,
523 tags=webutil.nodetagsdict(web.repo, n),
523 tags=webutil.nodetagsdict(web.repo, n),
524 bookmarks=webutil.nodebookmarksdict(web.repo, n),
524 bookmarks=webutil.nodebookmarksdict(web.repo, n),
525 inbranch=webutil.nodeinbranch(web.repo, ctx),
525 inbranch=webutil.nodeinbranch(web.repo, ctx),
526 branches=webutil.nodebranchdict(web.repo, ctx)))
526 branches=webutil.nodebranchdict(web.repo, ctx)))
527
527
528 yield l
528 yield l
529
529
530 tip = web.repo['tip']
530 tip = web.repo['tip']
531 count = len(web.repo)
531 count = len(web.repo)
532 start = max(0, count - web.maxchanges)
532 start = max(0, count - web.maxchanges)
533 end = min(count, start + web.maxchanges)
533 end = min(count, start + web.maxchanges)
534
534
535 return tmpl("summary",
535 return tmpl("summary",
536 desc=web.config("web", "description", "unknown"),
536 desc=web.config("web", "description", "unknown"),
537 owner=get_contact(web.config) or "unknown",
537 owner=get_contact(web.config) or "unknown",
538 lastchange=tip.date(),
538 lastchange=tip.date(),
539 tags=tagentries,
539 tags=tagentries,
540 bookmarks=bookmarks,
540 bookmarks=bookmarks,
541 branches=branches,
541 branches=branches,
542 shortlog=changelist,
542 shortlog=changelist,
543 node=tip.hex(),
543 node=tip.hex(),
544 archives=web.archivelist("tip"))
544 archives=web.archivelist("tip"))
545
545
546 def filediff(web, req, tmpl):
546 def filediff(web, req, tmpl):
547 fctx, ctx = None, None
547 fctx, ctx = None, None
548 try:
548 try:
549 fctx = webutil.filectx(web.repo, req)
549 fctx = webutil.filectx(web.repo, req)
550 except LookupError:
550 except LookupError:
551 ctx = webutil.changectx(web.repo, req)
551 ctx = webutil.changectx(web.repo, req)
552 path = webutil.cleanpath(web.repo, req.form['file'][0])
552 path = webutil.cleanpath(web.repo, req.form['file'][0])
553 if path not in ctx.files():
553 if path not in ctx.files():
554 raise
554 raise
555
555
556 if fctx is not None:
556 if fctx is not None:
557 n = fctx.node()
557 n = fctx.node()
558 path = fctx.path()
558 path = fctx.path()
559 ctx = fctx.changectx()
559 ctx = fctx.changectx()
560 else:
560 else:
561 n = ctx.node()
561 n = ctx.node()
562 # path already defined in except clause
562 # path already defined in except clause
563
563
564 parity = paritygen(web.stripecount)
564 parity = paritygen(web.stripecount)
565 style = web.config('web', 'style', 'paper')
565 style = web.config('web', 'style', 'paper')
566 if 'style' in req.form:
566 if 'style' in req.form:
567 style = req.form['style'][0]
567 style = req.form['style'][0]
568
568
569 diffs = webutil.diffs(web.repo, tmpl, ctx, [path], parity, style)
569 diffs = webutil.diffs(web.repo, tmpl, ctx, [path], parity, style)
570 rename = fctx and webutil.renamelink(fctx) or []
570 rename = fctx and webutil.renamelink(fctx) or []
571 ctx = fctx and fctx or ctx
571 ctx = fctx and fctx or ctx
572 return tmpl("filediff",
572 return tmpl("filediff",
573 file=path,
573 file=path,
574 node=hex(n),
574 node=hex(n),
575 rev=ctx.rev(),
575 rev=ctx.rev(),
576 date=ctx.date(),
576 date=ctx.date(),
577 desc=ctx.description(),
577 desc=ctx.description(),
578 author=ctx.user(),
578 author=ctx.user(),
579 rename=rename,
579 rename=rename,
580 branch=webutil.nodebranchnodefault(ctx),
580 branch=webutil.nodebranchnodefault(ctx),
581 parent=webutil.parents(ctx),
581 parent=webutil.parents(ctx),
582 child=webutil.children(ctx),
582 child=webutil.children(ctx),
583 diff=diffs)
583 diff=diffs)
584
584
585 diff = filediff
585 diff = filediff
586
586
587 def comparison(web, req, tmpl):
587 def comparison(web, req, tmpl):
588 ctx = webutil.changectx(web.repo, req)
588 ctx = webutil.changectx(web.repo, req)
589 if 'file' not in req.form:
589 if 'file' not in req.form:
590 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
590 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
591 path = webutil.cleanpath(web.repo, req.form['file'][0])
591 path = webutil.cleanpath(web.repo, req.form['file'][0])
592 rename = path in ctx and webutil.renamelink(ctx[path]) or []
592 rename = path in ctx and webutil.renamelink(ctx[path]) or []
593
593
594 parsecontext = lambda v: v == 'full' and -1 or int(v)
594 parsecontext = lambda v: v == 'full' and -1 or int(v)
595 if 'context' in req.form:
595 if 'context' in req.form:
596 context = parsecontext(req.form['context'][0])
596 context = parsecontext(req.form['context'][0])
597 else:
597 else:
598 context = parsecontext(web.config('web', 'comparisoncontext', '5'))
598 context = parsecontext(web.config('web', 'comparisoncontext', '5'))
599
599
600 def filelines(f):
600 def filelines(f):
601 if binary(f.data()):
601 if binary(f.data()):
602 mt = mimetypes.guess_type(f.path())[0]
602 mt = mimetypes.guess_type(f.path())[0]
603 if not mt:
603 if not mt:
604 mt = 'application/octet-stream'
604 mt = 'application/octet-stream'
605 return [_('(binary file %s, hash: %s)') % (mt, hex(f.filenode()))]
605 return [_('(binary file %s, hash: %s)') % (mt, hex(f.filenode()))]
606 return f.data().splitlines()
606 return f.data().splitlines()
607
607
608 if path in ctx:
608 if path in ctx:
609 fctx = ctx[path]
609 fctx = ctx[path]
610 rightrev = fctx.filerev()
610 rightrev = fctx.filerev()
611 rightnode = fctx.filenode()
611 rightnode = fctx.filenode()
612 rightlines = filelines(fctx)
612 rightlines = filelines(fctx)
613 parents = fctx.parents()
613 parents = fctx.parents()
614 if not parents:
614 if not parents:
615 leftrev = -1
615 leftrev = -1
616 leftnode = nullid
616 leftnode = nullid
617 leftlines = ()
617 leftlines = ()
618 else:
618 else:
619 pfctx = parents[0]
619 pfctx = parents[0]
620 leftrev = pfctx.filerev()
620 leftrev = pfctx.filerev()
621 leftnode = pfctx.filenode()
621 leftnode = pfctx.filenode()
622 leftlines = filelines(pfctx)
622 leftlines = filelines(pfctx)
623 else:
623 else:
624 rightrev = -1
624 rightrev = -1
625 rightnode = nullid
625 rightnode = nullid
626 rightlines = ()
626 rightlines = ()
627 fctx = ctx.parents()[0][path]
627 fctx = ctx.parents()[0][path]
628 leftrev = fctx.filerev()
628 leftrev = fctx.filerev()
629 leftnode = fctx.filenode()
629 leftnode = fctx.filenode()
630 leftlines = filelines(fctx)
630 leftlines = filelines(fctx)
631
631
632 comparison = webutil.compare(tmpl, context, leftlines, rightlines)
632 comparison = webutil.compare(tmpl, context, leftlines, rightlines)
633 return tmpl('filecomparison',
633 return tmpl('filecomparison',
634 file=path,
634 file=path,
635 node=hex(ctx.node()),
635 node=hex(ctx.node()),
636 rev=ctx.rev(),
636 rev=ctx.rev(),
637 date=ctx.date(),
637 date=ctx.date(),
638 desc=ctx.description(),
638 desc=ctx.description(),
639 author=ctx.user(),
639 author=ctx.user(),
640 rename=rename,
640 rename=rename,
641 branch=webutil.nodebranchnodefault(ctx),
641 branch=webutil.nodebranchnodefault(ctx),
642 parent=webutil.parents(fctx),
642 parent=webutil.parents(fctx),
643 child=webutil.children(fctx),
643 child=webutil.children(fctx),
644 leftrev=leftrev,
644 leftrev=leftrev,
645 leftnode=hex(leftnode),
645 leftnode=hex(leftnode),
646 rightrev=rightrev,
646 rightrev=rightrev,
647 rightnode=hex(rightnode),
647 rightnode=hex(rightnode),
648 comparison=comparison)
648 comparison=comparison)
649
649
650 def annotate(web, req, tmpl):
650 def annotate(web, req, tmpl):
651 fctx = webutil.filectx(web.repo, req)
651 fctx = webutil.filectx(web.repo, req)
652 f = fctx.path()
652 f = fctx.path()
653 parity = paritygen(web.stripecount)
653 parity = paritygen(web.stripecount)
654 diffopts = patch.diffopts(web.repo.ui, untrusted=True, section='annotate')
654 diffopts = patch.diffopts(web.repo.ui, untrusted=True, section='annotate')
655
655
656 def annotate(**map):
656 def annotate(**map):
657 last = None
657 last = None
658 if binary(fctx.data()):
658 if binary(fctx.data()):
659 mt = (mimetypes.guess_type(fctx.path())[0]
659 mt = (mimetypes.guess_type(fctx.path())[0]
660 or 'application/octet-stream')
660 or 'application/octet-stream')
661 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
661 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
662 '(binary:%s)' % mt)])
662 '(binary:%s)' % mt)])
663 else:
663 else:
664 lines = enumerate(fctx.annotate(follow=True, linenumber=True,
664 lines = enumerate(fctx.annotate(follow=True, linenumber=True,
665 diffopts=diffopts))
665 diffopts=diffopts))
666 for lineno, ((f, targetline), l) in lines:
666 for lineno, ((f, targetline), l) in lines:
667 fnode = f.filenode()
667 fnode = f.filenode()
668
668
669 if last != fnode:
669 if last != fnode:
670 last = fnode
670 last = fnode
671
671
672 yield {"parity": parity.next(),
672 yield {"parity": parity.next(),
673 "node": f.hex(),
673 "node": f.hex(),
674 "rev": f.rev(),
674 "rev": f.rev(),
675 "author": f.user(),
675 "author": f.user(),
676 "desc": f.description(),
676 "desc": f.description(),
677 "file": f.path(),
677 "file": f.path(),
678 "targetline": targetline,
678 "targetline": targetline,
679 "line": l,
679 "line": l,
680 "lineid": "l%d" % (lineno + 1),
680 "lineid": "l%d" % (lineno + 1),
681 "linenumber": "% 6d" % (lineno + 1),
681 "linenumber": "% 6d" % (lineno + 1),
682 "revdate": f.date()}
682 "revdate": f.date()}
683
683
684 return tmpl("fileannotate",
684 return tmpl("fileannotate",
685 file=f,
685 file=f,
686 annotate=annotate,
686 annotate=annotate,
687 path=webutil.up(f),
687 path=webutil.up(f),
688 rev=fctx.rev(),
688 rev=fctx.rev(),
689 node=fctx.hex(),
689 node=fctx.hex(),
690 author=fctx.user(),
690 author=fctx.user(),
691 date=fctx.date(),
691 date=fctx.date(),
692 desc=fctx.description(),
692 desc=fctx.description(),
693 rename=webutil.renamelink(fctx),
693 rename=webutil.renamelink(fctx),
694 branch=webutil.nodebranchnodefault(fctx),
694 branch=webutil.nodebranchnodefault(fctx),
695 parent=webutil.parents(fctx),
695 parent=webutil.parents(fctx),
696 child=webutil.children(fctx),
696 child=webutil.children(fctx),
697 permissions=fctx.manifest().flags(f))
697 permissions=fctx.manifest().flags(f))
698
698
699 def filelog(web, req, tmpl):
699 def filelog(web, req, tmpl):
700
700
701 try:
701 try:
702 fctx = webutil.filectx(web.repo, req)
702 fctx = webutil.filectx(web.repo, req)
703 f = fctx.path()
703 f = fctx.path()
704 fl = fctx.filelog()
704 fl = fctx.filelog()
705 except error.LookupError:
705 except error.LookupError:
706 f = webutil.cleanpath(web.repo, req.form['file'][0])
706 f = webutil.cleanpath(web.repo, req.form['file'][0])
707 fl = web.repo.file(f)
707 fl = web.repo.file(f)
708 numrevs = len(fl)
708 numrevs = len(fl)
709 if not numrevs: # file doesn't exist at all
709 if not numrevs: # file doesn't exist at all
710 raise
710 raise
711 rev = webutil.changectx(web.repo, req).rev()
711 rev = webutil.changectx(web.repo, req).rev()
712 first = fl.linkrev(0)
712 first = fl.linkrev(0)
713 if rev < first: # current rev is from before file existed
713 if rev < first: # current rev is from before file existed
714 raise
714 raise
715 frev = numrevs - 1
715 frev = numrevs - 1
716 while fl.linkrev(frev) > rev:
716 while fl.linkrev(frev) > rev:
717 frev -= 1
717 frev -= 1
718 fctx = web.repo.filectx(f, fl.linkrev(frev))
718 fctx = web.repo.filectx(f, fl.linkrev(frev))
719
719
720 revcount = web.maxshortchanges
720 revcount = web.maxshortchanges
721 if 'revcount' in req.form:
721 if 'revcount' in req.form:
722 revcount = int(req.form.get('revcount', [revcount])[0])
722 revcount = int(req.form.get('revcount', [revcount])[0])
723 revcount = max(revcount, 1)
723 revcount = max(revcount, 1)
724 tmpl.defaults['sessionvars']['revcount'] = revcount
724 tmpl.defaults['sessionvars']['revcount'] = revcount
725
725
726 lessvars = copy.copy(tmpl.defaults['sessionvars'])
726 lessvars = copy.copy(tmpl.defaults['sessionvars'])
727 lessvars['revcount'] = max(revcount / 2, 1)
727 lessvars['revcount'] = max(revcount / 2, 1)
728 morevars = copy.copy(tmpl.defaults['sessionvars'])
728 morevars = copy.copy(tmpl.defaults['sessionvars'])
729 morevars['revcount'] = revcount * 2
729 morevars['revcount'] = revcount * 2
730
730
731 count = fctx.filerev() + 1
731 count = fctx.filerev() + 1
732 start = max(0, fctx.filerev() - revcount + 1) # first rev on this page
732 start = max(0, fctx.filerev() - revcount + 1) # first rev on this page
733 end = min(count, start + revcount) # last rev on this page
733 end = min(count, start + revcount) # last rev on this page
734 parity = paritygen(web.stripecount, offset=start - end)
734 parity = paritygen(web.stripecount, offset=start - end)
735
735
736 def entries(limit=0, **map):
736 def entries(limit=0, **map):
737 l = []
737 l = []
738
738
739 repo = web.repo
739 repo = web.repo
740 for i in xrange(start, end):
740 for i in xrange(start, end):
741 iterfctx = fctx.filectx(i)
741 iterfctx = fctx.filectx(i)
742
742
743 l.insert(0, {"parity": parity.next(),
743 l.insert(0, {"parity": parity.next(),
744 "filerev": i,
744 "filerev": i,
745 "file": f,
745 "file": f,
746 "node": iterfctx.hex(),
746 "node": iterfctx.hex(),
747 "author": iterfctx.user(),
747 "author": iterfctx.user(),
748 "date": iterfctx.date(),
748 "date": iterfctx.date(),
749 "rename": webutil.renamelink(iterfctx),
749 "rename": webutil.renamelink(iterfctx),
750 "parent": webutil.parents(iterfctx),
750 "parent": webutil.parents(iterfctx),
751 "child": webutil.children(iterfctx),
751 "child": webutil.children(iterfctx),
752 "desc": iterfctx.description(),
752 "desc": iterfctx.description(),
753 "tags": webutil.nodetagsdict(repo, iterfctx.node()),
753 "tags": webutil.nodetagsdict(repo, iterfctx.node()),
754 "bookmarks": webutil.nodebookmarksdict(
754 "bookmarks": webutil.nodebookmarksdict(
755 repo, iterfctx.node()),
755 repo, iterfctx.node()),
756 "branch": webutil.nodebranchnodefault(iterfctx),
756 "branch": webutil.nodebranchnodefault(iterfctx),
757 "inbranch": webutil.nodeinbranch(repo, iterfctx),
757 "inbranch": webutil.nodeinbranch(repo, iterfctx),
758 "branches": webutil.nodebranchdict(repo, iterfctx)})
758 "branches": webutil.nodebranchdict(repo, iterfctx)})
759
759
760 if limit > 0:
760 if limit > 0:
761 l = l[:limit]
761 l = l[:limit]
762
762
763 for e in l:
763 for e in l:
764 yield e
764 yield e
765
765
766 nodefunc = lambda x: fctx.filectx(fileid=x)
766 nodefunc = lambda x: fctx.filectx(fileid=x)
767 nav = webutil.revnavgen(end - 1, revcount, count, nodefunc)
767 nav = webutil.revnavgen(end - 1, revcount, count, nodefunc)
768 return tmpl("filelog", file=f, node=fctx.hex(), nav=nav,
768 return tmpl("filelog", file=f, node=fctx.hex(), nav=nav,
769 entries=lambda **x: entries(limit=0, **x),
769 entries=lambda **x: entries(limit=0, **x),
770 latestentry=lambda **x: entries(limit=1, **x),
770 latestentry=lambda **x: entries(limit=1, **x),
771 revcount=revcount, morevars=morevars, lessvars=lessvars)
771 revcount=revcount, morevars=morevars, lessvars=lessvars)
772
772
773 def archive(web, req, tmpl):
773 def archive(web, req, tmpl):
774 type_ = req.form.get('type', [None])[0]
774 type_ = req.form.get('type', [None])[0]
775 allowed = web.configlist("web", "allow_archive")
775 allowed = web.configlist("web", "allow_archive")
776 key = req.form['node'][0]
776 key = req.form['node'][0]
777
777
778 if type_ not in web.archives:
778 if type_ not in web.archives:
779 msg = 'Unsupported archive type: %s' % type_
779 msg = 'Unsupported archive type: %s' % type_
780 raise ErrorResponse(HTTP_NOT_FOUND, msg)
780 raise ErrorResponse(HTTP_NOT_FOUND, msg)
781
781
782 if not ((type_ in allowed or
782 if not ((type_ in allowed or
783 web.configbool("web", "allow" + type_, False))):
783 web.configbool("web", "allow" + type_, False))):
784 msg = 'Archive type not allowed: %s' % type_
784 msg = 'Archive type not allowed: %s' % type_
785 raise ErrorResponse(HTTP_FORBIDDEN, msg)
785 raise ErrorResponse(HTTP_FORBIDDEN, msg)
786
786
787 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
787 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
788 cnode = web.repo.lookup(key)
788 cnode = web.repo.lookup(key)
789 arch_version = key
789 arch_version = key
790 if cnode == key or key == 'tip':
790 if cnode == key or key == 'tip':
791 arch_version = short(cnode)
791 arch_version = short(cnode)
792 name = "%s-%s" % (reponame, arch_version)
792 name = "%s-%s" % (reponame, arch_version)
793 mimetype, artype, extension, encoding = web.archive_specs[type_]
793 mimetype, artype, extension, encoding = web.archive_specs[type_]
794 headers = [
794 headers = [
795 ('Content-Type', mimetype),
795 ('Content-Type', mimetype),
796 ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
796 ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
797 ]
797 ]
798 if encoding:
798 if encoding:
799 headers.append(('Content-Encoding', encoding))
799 headers.append(('Content-Encoding', encoding))
800 req.header(headers)
800 req.header(headers)
801 req.respond(HTTP_OK)
801 req.respond(HTTP_OK)
802 archival.archive(web.repo, req, cnode, artype, prefix=name)
802 archival.archive(web.repo, req, cnode, artype, prefix=name)
803 return []
803 return []
804
804
805
805
806 def static(web, req, tmpl):
806 def static(web, req, tmpl):
807 fname = req.form['file'][0]
807 fname = req.form['file'][0]
808 # a repo owner may set web.static in .hg/hgrc to get any file
808 # a repo owner may set web.static in .hg/hgrc to get any file
809 # readable by the user running the CGI script
809 # readable by the user running the CGI script
810 static = web.config("web", "static", None, untrusted=False)
810 static = web.config("web", "static", None, untrusted=False)
811 if not static:
811 if not static:
812 tp = web.templatepath or templater.templatepath()
812 tp = web.templatepath or templater.templatepath()
813 if isinstance(tp, str):
813 if isinstance(tp, str):
814 tp = [tp]
814 tp = [tp]
815 static = [os.path.join(p, 'static') for p in tp]
815 static = [os.path.join(p, 'static') for p in tp]
816 return [staticfile(static, fname, req)]
816 return [staticfile(static, fname, req)]
817
817
818 def graph(web, req, tmpl):
818 def graph(web, req, tmpl):
819
819
820 ctx = webutil.changectx(web.repo, req)
820 ctx = webutil.changectx(web.repo, req)
821 rev = ctx.rev()
821 rev = ctx.rev()
822
822
823 bg_height = 39
823 bg_height = 39
824 revcount = web.maxshortchanges
824 revcount = web.maxshortchanges
825 if 'revcount' in req.form:
825 if 'revcount' in req.form:
826 revcount = int(req.form.get('revcount', [revcount])[0])
826 revcount = int(req.form.get('revcount', [revcount])[0])
827 revcount = max(revcount, 1)
827 revcount = max(revcount, 1)
828 tmpl.defaults['sessionvars']['revcount'] = revcount
828 tmpl.defaults['sessionvars']['revcount'] = revcount
829
829
830 lessvars = copy.copy(tmpl.defaults['sessionvars'])
830 lessvars = copy.copy(tmpl.defaults['sessionvars'])
831 lessvars['revcount'] = max(revcount / 2, 1)
831 lessvars['revcount'] = max(revcount / 2, 1)
832 morevars = copy.copy(tmpl.defaults['sessionvars'])
832 morevars = copy.copy(tmpl.defaults['sessionvars'])
833 morevars['revcount'] = revcount * 2
833 morevars['revcount'] = revcount * 2
834
834
835 count = len(web.repo)
835 count = len(web.repo)
836 pos = rev
836 pos = rev
837 start = max(0, pos - revcount + 1)
837 start = max(0, pos - revcount + 1)
838 end = min(count, start + revcount)
838 end = min(count, start + revcount)
839 pos = end - 1
839 pos = end - 1
840
840
841 uprev = min(max(0, count - 1), rev + revcount)
841 uprev = min(max(0, count - 1), rev + revcount)
842 downrev = max(0, rev - revcount)
842 downrev = max(0, rev - revcount)
843 changenav = webutil.revnavgen(pos, revcount, count, web.repo.changectx)
843 changenav = webutil.revnavgen(pos, revcount, count, web.repo.changectx)
844
844
845 dag = graphmod.dagwalker(web.repo, range(start, end)[::-1])
845 dag = graphmod.dagwalker(web.repo, range(start, end)[::-1])
846 tree = list(graphmod.colored(dag, web.repo))
846 tree = list(graphmod.colored(dag, web.repo))
847
847
848 def getcolumns(tree):
848 def getcolumns(tree):
849 cols = 0
849 cols = 0
850 for (id, type, ctx, vtx, edges) in tree:
850 for (id, type, ctx, vtx, edges) in tree:
851 if type != graphmod.CHANGESET:
851 if type != graphmod.CHANGESET:
852 continue
852 continue
853 cols = max(cols, max([edge[0] for edge in edges] or [0]),
853 cols = max(cols, max([edge[0] for edge in edges] or [0]),
854 max([edge[1] for edge in edges] or [0]))
854 max([edge[1] for edge in edges] or [0]))
855 return cols
855 return cols
856
856
857 def graphdata(usetuples, **map):
857 def graphdata(usetuples, **map):
858 data = []
858 data = []
859
859
860 row = 0
860 row = 0
861 for (id, type, ctx, vtx, edges) in tree:
861 for (id, type, ctx, vtx, edges) in tree:
862 if type != graphmod.CHANGESET:
862 if type != graphmod.CHANGESET:
863 continue
863 continue
864 node = str(ctx)
864 node = str(ctx)
865 age = templatefilters.age(ctx.date())
865 age = templatefilters.age(ctx.date())
866 desc = templatefilters.firstline(ctx.description())
866 desc = templatefilters.firstline(ctx.description())
867 desc = cgi.escape(templatefilters.nonempty(desc))
867 desc = cgi.escape(templatefilters.nonempty(desc))
868 user = cgi.escape(templatefilters.person(ctx.user()))
868 user = cgi.escape(templatefilters.person(ctx.user()))
869 branch = ctx.branch()
869 branch = ctx.branch()
870 try:
870 try:
871 branchnode = web.repo.branchtip(branch)
871 branchnode = web.repo.branchtip(branch)
872 except error.RepoLookupError:
872 except error.RepoLookupError:
873 branchnode = None
873 branchnode = None
874 branch = branch, branchnode == ctx.node()
874 branch = branch, branchnode == ctx.node()
875
875
876 if usetuples:
876 if usetuples:
877 data.append((node, vtx, edges, desc, user, age, branch,
877 data.append((node, vtx, edges, desc, user, age, branch,
878 ctx.tags(), ctx.bookmarks()))
878 ctx.tags(), ctx.bookmarks()))
879 else:
879 else:
880 edgedata = [dict(col=edge[0], nextcol=edge[1],
880 edgedata = [dict(col=edge[0], nextcol=edge[1],
881 color=(edge[2] - 1) % 6 + 1,
881 color=(edge[2] - 1) % 6 + 1,
882 width=edge[3], bcolor=edge[4])
882 width=edge[3], bcolor=edge[4])
883 for edge in edges]
883 for edge in edges]
884
884
885 data.append(
885 data.append(
886 dict(node=node,
886 dict(node=node,
887 col=vtx[0],
887 col=vtx[0],
888 color=(vtx[1] - 1) % 6 + 1,
888 color=(vtx[1] - 1) % 6 + 1,
889 edges=edgedata,
889 edges=edgedata,
890 row=row,
890 row=row,
891 nextrow=row + 1,
891 nextrow=row + 1,
892 desc=desc,
892 desc=desc,
893 user=user,
893 user=user,
894 age=age,
894 age=age,
895 bookmarks=webutil.nodebookmarksdict(
895 bookmarks=webutil.nodebookmarksdict(
896 web.repo, ctx.node()),
896 web.repo, ctx.node()),
897 branches=webutil.nodebranchdict(web.repo, ctx),
897 branches=webutil.nodebranchdict(web.repo, ctx),
898 inbranch=webutil.nodeinbranch(web.repo, ctx),
898 inbranch=webutil.nodeinbranch(web.repo, ctx),
899 tags=webutil.nodetagsdict(web.repo, ctx.node())))
899 tags=webutil.nodetagsdict(web.repo, ctx.node())))
900
900
901 row += 1
901 row += 1
902
902
903 return data
903 return data
904
904
905 cols = getcolumns(tree)
905 cols = getcolumns(tree)
906 rows = len(tree)
906 rows = len(tree)
907 canvasheight = (rows + 1) * bg_height - 27
907 canvasheight = (rows + 1) * bg_height - 27
908
908
909 return tmpl('graph', rev=rev, revcount=revcount, uprev=uprev,
909 return tmpl('graph', rev=rev, revcount=revcount, uprev=uprev,
910 lessvars=lessvars, morevars=morevars, downrev=downrev,
910 lessvars=lessvars, morevars=morevars, downrev=downrev,
911 cols=cols, rows=rows,
911 cols=cols, rows=rows,
912 canvaswidth=(cols + 1) * bg_height,
912 canvaswidth=(cols + 1) * bg_height,
913 truecanvasheight=rows * bg_height,
913 truecanvasheight=rows * bg_height,
914 canvasheight=canvasheight, bg_height=bg_height,
914 canvasheight=canvasheight, bg_height=bg_height,
915 jsdata=lambda **x: graphdata(True, **x),
915 jsdata=lambda **x: graphdata(True, **x),
916 nodes=lambda **x: graphdata(False, **x),
916 nodes=lambda **x: graphdata(False, **x),
917 node=ctx.hex(), changenav=changenav)
917 node=ctx.hex(), changenav=changenav)
918
918
919 def _getdoc(e):
919 def _getdoc(e):
920 doc = e[0].__doc__
920 doc = e[0].__doc__
921 if doc:
921 if doc:
922 doc = _(doc).split('\n')[0]
922 doc = _(doc).split('\n')[0]
923 else:
923 else:
924 doc = _('(no help text available)')
924 doc = _('(no help text available)')
925 return doc
925 return doc
926
926
927 def help(web, req, tmpl):
927 def help(web, req, tmpl):
928 from mercurial import commands # avoid cycle
928 from mercurial import commands # avoid cycle
929
929
930 topicname = req.form.get('node', [None])[0]
930 topicname = req.form.get('node', [None])[0]
931 if not topicname:
931 if not topicname:
932 def topics(**map):
932 def topics(**map):
933 for entries, summary, _ in helpmod.helptable:
933 for entries, summary, _ in helpmod.helptable:
934 entries = sorted(entries, key=len)
934 yield {'topic': entries[0], 'summary': summary}
935 yield {'topic': entries[-1], 'summary': summary}
936
935
937 early, other = [], []
936 early, other = [], []
938 primary = lambda s: s.split('|')[0]
937 primary = lambda s: s.split('|')[0]
939 for c, e in commands.table.iteritems():
938 for c, e in commands.table.iteritems():
940 doc = _getdoc(e)
939 doc = _getdoc(e)
941 if 'DEPRECATED' in doc or c.startswith('debug'):
940 if 'DEPRECATED' in doc or c.startswith('debug'):
942 continue
941 continue
943 cmd = primary(c)
942 cmd = primary(c)
944 if cmd.startswith('^'):
943 if cmd.startswith('^'):
945 early.append((cmd[1:], doc))
944 early.append((cmd[1:], doc))
946 else:
945 else:
947 other.append((cmd, doc))
946 other.append((cmd, doc))
948
947
949 early.sort()
948 early.sort()
950 other.sort()
949 other.sort()
951
950
952 def earlycommands(**map):
951 def earlycommands(**map):
953 for c, doc in early:
952 for c, doc in early:
954 yield {'topic': c, 'summary': doc}
953 yield {'topic': c, 'summary': doc}
955
954
956 def othercommands(**map):
955 def othercommands(**map):
957 for c, doc in other:
956 for c, doc in other:
958 yield {'topic': c, 'summary': doc}
957 yield {'topic': c, 'summary': doc}
959
958
960 return tmpl('helptopics', topics=topics, earlycommands=earlycommands,
959 return tmpl('helptopics', topics=topics, earlycommands=earlycommands,
961 othercommands=othercommands, title='Index')
960 othercommands=othercommands, title='Index')
962
961
963 u = webutil.wsgiui()
962 u = webutil.wsgiui()
964 u.pushbuffer()
963 u.pushbuffer()
965 u.verbose = True
964 u.verbose = True
966 try:
965 try:
967 commands.help_(u, topicname)
966 commands.help_(u, topicname)
968 except error.UnknownCommand:
967 except error.UnknownCommand:
969 raise ErrorResponse(HTTP_NOT_FOUND)
968 raise ErrorResponse(HTTP_NOT_FOUND)
970 doc = u.popbuffer()
969 doc = u.popbuffer()
971 return tmpl('help', topic=topicname, doc=doc)
970 return tmpl('help', topic=topicname, doc=doc)
@@ -1,804 +1,804 b''
1 Short help:
1 Short help:
2
2
3 $ hg
3 $ hg
4 Mercurial Distributed SCM
4 Mercurial Distributed SCM
5
5
6 basic commands:
6 basic commands:
7
7
8 add add the specified files on the next commit
8 add add the specified files on the next commit
9 annotate show changeset information by line for each file
9 annotate show changeset information by line for each file
10 clone make a copy of an existing repository
10 clone make a copy of an existing repository
11 commit commit the specified files or all outstanding changes
11 commit commit the specified files or all outstanding changes
12 diff diff repository (or selected files)
12 diff diff repository (or selected files)
13 export dump the header and diffs for one or more changesets
13 export dump the header and diffs for one or more changesets
14 forget forget the specified files on the next commit
14 forget forget the specified files on the next commit
15 init create a new repository in the given directory
15 init create a new repository in the given directory
16 log show revision history of entire repository or files
16 log show revision history of entire repository or files
17 merge merge working directory with another revision
17 merge merge working directory with another revision
18 phase set or show the current phase name
18 phase set or show the current phase name
19 pull pull changes from the specified source
19 pull pull changes from the specified source
20 push push changes to the specified destination
20 push push changes to the specified destination
21 remove remove the specified files on the next commit
21 remove remove the specified files on the next commit
22 serve start stand-alone webserver
22 serve start stand-alone webserver
23 status show changed files in the working directory
23 status show changed files in the working directory
24 summary summarize working directory state
24 summary summarize working directory state
25 update update working directory (or switch revisions)
25 update update working directory (or switch revisions)
26
26
27 use "hg help" for the full list of commands or "hg -v" for details
27 use "hg help" for the full list of commands or "hg -v" for details
28
28
29 $ hg -q
29 $ hg -q
30 add add the specified files on the next commit
30 add add the specified files on the next commit
31 annotate show changeset information by line for each file
31 annotate show changeset information by line for each file
32 clone make a copy of an existing repository
32 clone make a copy of an existing repository
33 commit commit the specified files or all outstanding changes
33 commit commit the specified files or all outstanding changes
34 diff diff repository (or selected files)
34 diff diff repository (or selected files)
35 export dump the header and diffs for one or more changesets
35 export dump the header and diffs for one or more changesets
36 forget forget the specified files on the next commit
36 forget forget the specified files on the next commit
37 init create a new repository in the given directory
37 init create a new repository in the given directory
38 log show revision history of entire repository or files
38 log show revision history of entire repository or files
39 merge merge working directory with another revision
39 merge merge working directory with another revision
40 phase set or show the current phase name
40 phase set or show the current phase name
41 pull pull changes from the specified source
41 pull pull changes from the specified source
42 push push changes to the specified destination
42 push push changes to the specified destination
43 remove remove the specified files on the next commit
43 remove remove the specified files on the next commit
44 serve start stand-alone webserver
44 serve start stand-alone webserver
45 status show changed files in the working directory
45 status show changed files in the working directory
46 summary summarize working directory state
46 summary summarize working directory state
47 update update working directory (or switch revisions)
47 update update working directory (or switch revisions)
48
48
49 $ hg help
49 $ hg help
50 Mercurial Distributed SCM
50 Mercurial Distributed SCM
51
51
52 list of commands:
52 list of commands:
53
53
54 add add the specified files on the next commit
54 add add the specified files on the next commit
55 addremove add all new files, delete all missing files
55 addremove add all new files, delete all missing files
56 annotate show changeset information by line for each file
56 annotate show changeset information by line for each file
57 archive create an unversioned archive of a repository revision
57 archive create an unversioned archive of a repository revision
58 backout reverse effect of earlier changeset
58 backout reverse effect of earlier changeset
59 bisect subdivision search of changesets
59 bisect subdivision search of changesets
60 bookmarks track a line of development with movable markers
60 bookmarks track a line of development with movable markers
61 branch set or show the current branch name
61 branch set or show the current branch name
62 branches list repository named branches
62 branches list repository named branches
63 bundle create a changegroup file
63 bundle create a changegroup file
64 cat output the current or given revision of files
64 cat output the current or given revision of files
65 clone make a copy of an existing repository
65 clone make a copy of an existing repository
66 commit commit the specified files or all outstanding changes
66 commit commit the specified files or all outstanding changes
67 copy mark files as copied for the next commit
67 copy mark files as copied for the next commit
68 diff diff repository (or selected files)
68 diff diff repository (or selected files)
69 export dump the header and diffs for one or more changesets
69 export dump the header and diffs for one or more changesets
70 forget forget the specified files on the next commit
70 forget forget the specified files on the next commit
71 graft copy changes from other branches onto the current branch
71 graft copy changes from other branches onto the current branch
72 grep search for a pattern in specified files and revisions
72 grep search for a pattern in specified files and revisions
73 heads show current repository heads or show branch heads
73 heads show current repository heads or show branch heads
74 help show help for a given topic or a help overview
74 help show help for a given topic or a help overview
75 identify identify the working copy or specified revision
75 identify identify the working copy or specified revision
76 import import an ordered set of patches
76 import import an ordered set of patches
77 incoming show new changesets found in source
77 incoming show new changesets found in source
78 init create a new repository in the given directory
78 init create a new repository in the given directory
79 locate locate files matching specific patterns
79 locate locate files matching specific patterns
80 log show revision history of entire repository or files
80 log show revision history of entire repository or files
81 manifest output the current or given revision of the project manifest
81 manifest output the current or given revision of the project manifest
82 merge merge working directory with another revision
82 merge merge working directory with another revision
83 outgoing show changesets not found in the destination
83 outgoing show changesets not found in the destination
84 parents show the parents of the working directory or revision
84 parents show the parents of the working directory or revision
85 paths show aliases for remote repositories
85 paths show aliases for remote repositories
86 phase set or show the current phase name
86 phase set or show the current phase name
87 pull pull changes from the specified source
87 pull pull changes from the specified source
88 push push changes to the specified destination
88 push push changes to the specified destination
89 recover roll back an interrupted transaction
89 recover roll back an interrupted transaction
90 remove remove the specified files on the next commit
90 remove remove the specified files on the next commit
91 rename rename files; equivalent of copy + remove
91 rename rename files; equivalent of copy + remove
92 resolve redo merges or set/view the merge status of files
92 resolve redo merges or set/view the merge status of files
93 revert restore files to their checkout state
93 revert restore files to their checkout state
94 rollback roll back the last transaction (dangerous)
94 rollback roll back the last transaction (dangerous)
95 root print the root (top) of the current working directory
95 root print the root (top) of the current working directory
96 serve start stand-alone webserver
96 serve start stand-alone webserver
97 showconfig show combined config settings from all hgrc files
97 showconfig show combined config settings from all hgrc files
98 status show changed files in the working directory
98 status show changed files in the working directory
99 summary summarize working directory state
99 summary summarize working directory state
100 tag add one or more tags for the current or given revision
100 tag add one or more tags for the current or given revision
101 tags list repository tags
101 tags list repository tags
102 tip show the tip revision
102 tip show the tip revision
103 unbundle apply one or more changegroup files
103 unbundle apply one or more changegroup files
104 update update working directory (or switch revisions)
104 update update working directory (or switch revisions)
105 verify verify the integrity of the repository
105 verify verify the integrity of the repository
106 version output version and copyright information
106 version output version and copyright information
107
107
108 additional help topics:
108 additional help topics:
109
109
110 config Configuration Files
110 config Configuration Files
111 dates Date Formats
111 dates Date Formats
112 diffs Diff Formats
112 diffs Diff Formats
113 environment Environment Variables
113 environment Environment Variables
114 extensions Using Additional Features
114 extensions Using Additional Features
115 filesets Specifying File Sets
115 filesets Specifying File Sets
116 glossary Glossary
116 glossary Glossary
117 hgignore Syntax for Mercurial Ignore Files
117 hgignore Syntax for Mercurial Ignore Files
118 hgweb Configuring hgweb
118 hgweb Configuring hgweb
119 merge-tools Merge Tools
119 merge-tools Merge Tools
120 multirevs Specifying Multiple Revisions
120 multirevs Specifying Multiple Revisions
121 patterns File Name Patterns
121 patterns File Name Patterns
122 phases Working with Phases
122 phases Working with Phases
123 revisions Specifying Single Revisions
123 revisions Specifying Single Revisions
124 revsets Specifying Revision Sets
124 revsets Specifying Revision Sets
125 subrepos Subrepositories
125 subrepos Subrepositories
126 templating Template Usage
126 templating Template Usage
127 urls URL Paths
127 urls URL Paths
128
128
129 use "hg -v help" to show builtin aliases and global options
129 use "hg -v help" to show builtin aliases and global options
130
130
131 $ hg -q help
131 $ hg -q help
132 add add the specified files on the next commit
132 add add the specified files on the next commit
133 addremove add all new files, delete all missing files
133 addremove add all new files, delete all missing files
134 annotate show changeset information by line for each file
134 annotate show changeset information by line for each file
135 archive create an unversioned archive of a repository revision
135 archive create an unversioned archive of a repository revision
136 backout reverse effect of earlier changeset
136 backout reverse effect of earlier changeset
137 bisect subdivision search of changesets
137 bisect subdivision search of changesets
138 bookmarks track a line of development with movable markers
138 bookmarks track a line of development with movable markers
139 branch set or show the current branch name
139 branch set or show the current branch name
140 branches list repository named branches
140 branches list repository named branches
141 bundle create a changegroup file
141 bundle create a changegroup file
142 cat output the current or given revision of files
142 cat output the current or given revision of files
143 clone make a copy of an existing repository
143 clone make a copy of an existing repository
144 commit commit the specified files or all outstanding changes
144 commit commit the specified files or all outstanding changes
145 copy mark files as copied for the next commit
145 copy mark files as copied for the next commit
146 diff diff repository (or selected files)
146 diff diff repository (or selected files)
147 export dump the header and diffs for one or more changesets
147 export dump the header and diffs for one or more changesets
148 forget forget the specified files on the next commit
148 forget forget the specified files on the next commit
149 graft copy changes from other branches onto the current branch
149 graft copy changes from other branches onto the current branch
150 grep search for a pattern in specified files and revisions
150 grep search for a pattern in specified files and revisions
151 heads show current repository heads or show branch heads
151 heads show current repository heads or show branch heads
152 help show help for a given topic or a help overview
152 help show help for a given topic or a help overview
153 identify identify the working copy or specified revision
153 identify identify the working copy or specified revision
154 import import an ordered set of patches
154 import import an ordered set of patches
155 incoming show new changesets found in source
155 incoming show new changesets found in source
156 init create a new repository in the given directory
156 init create a new repository in the given directory
157 locate locate files matching specific patterns
157 locate locate files matching specific patterns
158 log show revision history of entire repository or files
158 log show revision history of entire repository or files
159 manifest output the current or given revision of the project manifest
159 manifest output the current or given revision of the project manifest
160 merge merge working directory with another revision
160 merge merge working directory with another revision
161 outgoing show changesets not found in the destination
161 outgoing show changesets not found in the destination
162 parents show the parents of the working directory or revision
162 parents show the parents of the working directory or revision
163 paths show aliases for remote repositories
163 paths show aliases for remote repositories
164 phase set or show the current phase name
164 phase set or show the current phase name
165 pull pull changes from the specified source
165 pull pull changes from the specified source
166 push push changes to the specified destination
166 push push changes to the specified destination
167 recover roll back an interrupted transaction
167 recover roll back an interrupted transaction
168 remove remove the specified files on the next commit
168 remove remove the specified files on the next commit
169 rename rename files; equivalent of copy + remove
169 rename rename files; equivalent of copy + remove
170 resolve redo merges or set/view the merge status of files
170 resolve redo merges or set/view the merge status of files
171 revert restore files to their checkout state
171 revert restore files to their checkout state
172 rollback roll back the last transaction (dangerous)
172 rollback roll back the last transaction (dangerous)
173 root print the root (top) of the current working directory
173 root print the root (top) of the current working directory
174 serve start stand-alone webserver
174 serve start stand-alone webserver
175 showconfig show combined config settings from all hgrc files
175 showconfig show combined config settings from all hgrc files
176 status show changed files in the working directory
176 status show changed files in the working directory
177 summary summarize working directory state
177 summary summarize working directory state
178 tag add one or more tags for the current or given revision
178 tag add one or more tags for the current or given revision
179 tags list repository tags
179 tags list repository tags
180 tip show the tip revision
180 tip show the tip revision
181 unbundle apply one or more changegroup files
181 unbundle apply one or more changegroup files
182 update update working directory (or switch revisions)
182 update update working directory (or switch revisions)
183 verify verify the integrity of the repository
183 verify verify the integrity of the repository
184 version output version and copyright information
184 version output version and copyright information
185
185
186 additional help topics:
186 additional help topics:
187
187
188 config Configuration Files
188 config Configuration Files
189 dates Date Formats
189 dates Date Formats
190 diffs Diff Formats
190 diffs Diff Formats
191 environment Environment Variables
191 environment Environment Variables
192 extensions Using Additional Features
192 extensions Using Additional Features
193 filesets Specifying File Sets
193 filesets Specifying File Sets
194 glossary Glossary
194 glossary Glossary
195 hgignore Syntax for Mercurial Ignore Files
195 hgignore Syntax for Mercurial Ignore Files
196 hgweb Configuring hgweb
196 hgweb Configuring hgweb
197 merge-tools Merge Tools
197 merge-tools Merge Tools
198 multirevs Specifying Multiple Revisions
198 multirevs Specifying Multiple Revisions
199 patterns File Name Patterns
199 patterns File Name Patterns
200 phases Working with Phases
200 phases Working with Phases
201 revisions Specifying Single Revisions
201 revisions Specifying Single Revisions
202 revsets Specifying Revision Sets
202 revsets Specifying Revision Sets
203 subrepos Subrepositories
203 subrepos Subrepositories
204 templating Template Usage
204 templating Template Usage
205 urls URL Paths
205 urls URL Paths
206
206
207 Test short command list with verbose option
207 Test short command list with verbose option
208
208
209 $ hg -v help shortlist
209 $ hg -v help shortlist
210 Mercurial Distributed SCM
210 Mercurial Distributed SCM
211
211
212 basic commands:
212 basic commands:
213
213
214 add add the specified files on the next commit
214 add add the specified files on the next commit
215 annotate, blame
215 annotate, blame
216 show changeset information by line for each file
216 show changeset information by line for each file
217 clone make a copy of an existing repository
217 clone make a copy of an existing repository
218 commit, ci commit the specified files or all outstanding changes
218 commit, ci commit the specified files or all outstanding changes
219 diff diff repository (or selected files)
219 diff diff repository (or selected files)
220 export dump the header and diffs for one or more changesets
220 export dump the header and diffs for one or more changesets
221 forget forget the specified files on the next commit
221 forget forget the specified files on the next commit
222 init create a new repository in the given directory
222 init create a new repository in the given directory
223 log, history show revision history of entire repository or files
223 log, history show revision history of entire repository or files
224 merge merge working directory with another revision
224 merge merge working directory with another revision
225 phase set or show the current phase name
225 phase set or show the current phase name
226 pull pull changes from the specified source
226 pull pull changes from the specified source
227 push push changes to the specified destination
227 push push changes to the specified destination
228 remove, rm remove the specified files on the next commit
228 remove, rm remove the specified files on the next commit
229 serve start stand-alone webserver
229 serve start stand-alone webserver
230 status, st show changed files in the working directory
230 status, st show changed files in the working directory
231 summary, sum summarize working directory state
231 summary, sum summarize working directory state
232 update, up, checkout, co
232 update, up, checkout, co
233 update working directory (or switch revisions)
233 update working directory (or switch revisions)
234
234
235 global options:
235 global options:
236
236
237 -R --repository REPO repository root directory or name of overlay bundle
237 -R --repository REPO repository root directory or name of overlay bundle
238 file
238 file
239 --cwd DIR change working directory
239 --cwd DIR change working directory
240 -y --noninteractive do not prompt, automatically pick the first choice for
240 -y --noninteractive do not prompt, automatically pick the first choice for
241 all prompts
241 all prompts
242 -q --quiet suppress output
242 -q --quiet suppress output
243 -v --verbose enable additional output
243 -v --verbose enable additional output
244 --config CONFIG [+] set/override config option (use 'section.name=value')
244 --config CONFIG [+] set/override config option (use 'section.name=value')
245 --debug enable debugging output
245 --debug enable debugging output
246 --debugger start debugger
246 --debugger start debugger
247 --encoding ENCODE set the charset encoding (default: ascii)
247 --encoding ENCODE set the charset encoding (default: ascii)
248 --encodingmode MODE set the charset encoding mode (default: strict)
248 --encodingmode MODE set the charset encoding mode (default: strict)
249 --traceback always print a traceback on exception
249 --traceback always print a traceback on exception
250 --time time how long the command takes
250 --time time how long the command takes
251 --profile print command execution profile
251 --profile print command execution profile
252 --version output version information and exit
252 --version output version information and exit
253 -h --help display help and exit
253 -h --help display help and exit
254
254
255 [+] marked option can be specified multiple times
255 [+] marked option can be specified multiple times
256
256
257 use "hg help" for the full list of commands
257 use "hg help" for the full list of commands
258
258
259 $ hg add -h
259 $ hg add -h
260 hg add [OPTION]... [FILE]...
260 hg add [OPTION]... [FILE]...
261
261
262 add the specified files on the next commit
262 add the specified files on the next commit
263
263
264 Schedule files to be version controlled and added to the repository.
264 Schedule files to be version controlled and added to the repository.
265
265
266 The files will be added to the repository at the next commit. To undo an
266 The files will be added to the repository at the next commit. To undo an
267 add before that, see "hg forget".
267 add before that, see "hg forget".
268
268
269 If no names are given, add all files to the repository.
269 If no names are given, add all files to the repository.
270
270
271 Returns 0 if all files are successfully added.
271 Returns 0 if all files are successfully added.
272
272
273 options:
273 options:
274
274
275 -I --include PATTERN [+] include names matching the given patterns
275 -I --include PATTERN [+] include names matching the given patterns
276 -X --exclude PATTERN [+] exclude names matching the given patterns
276 -X --exclude PATTERN [+] exclude names matching the given patterns
277 -S --subrepos recurse into subrepositories
277 -S --subrepos recurse into subrepositories
278 -n --dry-run do not perform actions, just print output
278 -n --dry-run do not perform actions, just print output
279
279
280 [+] marked option can be specified multiple times
280 [+] marked option can be specified multiple times
281
281
282 use "hg -v help add" to show more info
282 use "hg -v help add" to show more info
283
283
284 Verbose help for add
284 Verbose help for add
285
285
286 $ hg add -hv
286 $ hg add -hv
287 hg add [OPTION]... [FILE]...
287 hg add [OPTION]... [FILE]...
288
288
289 add the specified files on the next commit
289 add the specified files on the next commit
290
290
291 Schedule files to be version controlled and added to the repository.
291 Schedule files to be version controlled and added to the repository.
292
292
293 The files will be added to the repository at the next commit. To undo an
293 The files will be added to the repository at the next commit. To undo an
294 add before that, see "hg forget".
294 add before that, see "hg forget".
295
295
296 If no names are given, add all files to the repository.
296 If no names are given, add all files to the repository.
297
297
298 An example showing how new (unknown) files are added automatically by "hg
298 An example showing how new (unknown) files are added automatically by "hg
299 add":
299 add":
300
300
301 $ ls
301 $ ls
302 foo.c
302 foo.c
303 $ hg status
303 $ hg status
304 ? foo.c
304 ? foo.c
305 $ hg add
305 $ hg add
306 adding foo.c
306 adding foo.c
307 $ hg status
307 $ hg status
308 A foo.c
308 A foo.c
309
309
310 Returns 0 if all files are successfully added.
310 Returns 0 if all files are successfully added.
311
311
312 options:
312 options:
313
313
314 -I --include PATTERN [+] include names matching the given patterns
314 -I --include PATTERN [+] include names matching the given patterns
315 -X --exclude PATTERN [+] exclude names matching the given patterns
315 -X --exclude PATTERN [+] exclude names matching the given patterns
316 -S --subrepos recurse into subrepositories
316 -S --subrepos recurse into subrepositories
317 -n --dry-run do not perform actions, just print output
317 -n --dry-run do not perform actions, just print output
318
318
319 [+] marked option can be specified multiple times
319 [+] marked option can be specified multiple times
320
320
321 global options:
321 global options:
322
322
323 -R --repository REPO repository root directory or name of overlay bundle
323 -R --repository REPO repository root directory or name of overlay bundle
324 file
324 file
325 --cwd DIR change working directory
325 --cwd DIR change working directory
326 -y --noninteractive do not prompt, automatically pick the first choice for
326 -y --noninteractive do not prompt, automatically pick the first choice for
327 all prompts
327 all prompts
328 -q --quiet suppress output
328 -q --quiet suppress output
329 -v --verbose enable additional output
329 -v --verbose enable additional output
330 --config CONFIG [+] set/override config option (use 'section.name=value')
330 --config CONFIG [+] set/override config option (use 'section.name=value')
331 --debug enable debugging output
331 --debug enable debugging output
332 --debugger start debugger
332 --debugger start debugger
333 --encoding ENCODE set the charset encoding (default: ascii)
333 --encoding ENCODE set the charset encoding (default: ascii)
334 --encodingmode MODE set the charset encoding mode (default: strict)
334 --encodingmode MODE set the charset encoding mode (default: strict)
335 --traceback always print a traceback on exception
335 --traceback always print a traceback on exception
336 --time time how long the command takes
336 --time time how long the command takes
337 --profile print command execution profile
337 --profile print command execution profile
338 --version output version information and exit
338 --version output version information and exit
339 -h --help display help and exit
339 -h --help display help and exit
340
340
341 [+] marked option can be specified multiple times
341 [+] marked option can be specified multiple times
342
342
343 Test help option with version option
343 Test help option with version option
344
344
345 $ hg add -h --version
345 $ hg add -h --version
346 Mercurial Distributed SCM (version *) (glob)
346 Mercurial Distributed SCM (version *) (glob)
347 (see http://mercurial.selenic.com for more information)
347 (see http://mercurial.selenic.com for more information)
348
348
349 Copyright (C) 2005-2012 Matt Mackall and others
349 Copyright (C) 2005-2012 Matt Mackall and others
350 This is free software; see the source for copying conditions. There is NO
350 This is free software; see the source for copying conditions. There is NO
351 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
351 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
352
352
353 $ hg add --skjdfks
353 $ hg add --skjdfks
354 hg add: option --skjdfks not recognized
354 hg add: option --skjdfks not recognized
355 hg add [OPTION]... [FILE]...
355 hg add [OPTION]... [FILE]...
356
356
357 add the specified files on the next commit
357 add the specified files on the next commit
358
358
359 options:
359 options:
360
360
361 -I --include PATTERN [+] include names matching the given patterns
361 -I --include PATTERN [+] include names matching the given patterns
362 -X --exclude PATTERN [+] exclude names matching the given patterns
362 -X --exclude PATTERN [+] exclude names matching the given patterns
363 -S --subrepos recurse into subrepositories
363 -S --subrepos recurse into subrepositories
364 -n --dry-run do not perform actions, just print output
364 -n --dry-run do not perform actions, just print output
365
365
366 [+] marked option can be specified multiple times
366 [+] marked option can be specified multiple times
367
367
368 use "hg help add" to show the full help text
368 use "hg help add" to show the full help text
369 [255]
369 [255]
370
370
371 Test ambiguous command help
371 Test ambiguous command help
372
372
373 $ hg help ad
373 $ hg help ad
374 list of commands:
374 list of commands:
375
375
376 add add the specified files on the next commit
376 add add the specified files on the next commit
377 addremove add all new files, delete all missing files
377 addremove add all new files, delete all missing files
378
378
379 use "hg -v help ad" to show builtin aliases and global options
379 use "hg -v help ad" to show builtin aliases and global options
380
380
381 Test command without options
381 Test command without options
382
382
383 $ hg help verify
383 $ hg help verify
384 hg verify
384 hg verify
385
385
386 verify the integrity of the repository
386 verify the integrity of the repository
387
387
388 Verify the integrity of the current repository.
388 Verify the integrity of the current repository.
389
389
390 This will perform an extensive check of the repository's integrity,
390 This will perform an extensive check of the repository's integrity,
391 validating the hashes and checksums of each entry in the changelog,
391 validating the hashes and checksums of each entry in the changelog,
392 manifest, and tracked files, as well as the integrity of their crosslinks
392 manifest, and tracked files, as well as the integrity of their crosslinks
393 and indices.
393 and indices.
394
394
395 Returns 0 on success, 1 if errors are encountered.
395 Returns 0 on success, 1 if errors are encountered.
396
396
397 use "hg -v help verify" to show more info
397 use "hg -v help verify" to show more info
398
398
399 $ hg help diff
399 $ hg help diff
400 hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...
400 hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...
401
401
402 diff repository (or selected files)
402 diff repository (or selected files)
403
403
404 Show differences between revisions for the specified files.
404 Show differences between revisions for the specified files.
405
405
406 Differences between files are shown using the unified diff format.
406 Differences between files are shown using the unified diff format.
407
407
408 Note:
408 Note:
409 diff may generate unexpected results for merges, as it will default to
409 diff may generate unexpected results for merges, as it will default to
410 comparing against the working directory's first parent changeset if no
410 comparing against the working directory's first parent changeset if no
411 revisions are specified.
411 revisions are specified.
412
412
413 When two revision arguments are given, then changes are shown between
413 When two revision arguments are given, then changes are shown between
414 those revisions. If only one revision is specified then that revision is
414 those revisions. If only one revision is specified then that revision is
415 compared to the working directory, and, when no revisions are specified,
415 compared to the working directory, and, when no revisions are specified,
416 the working directory files are compared to its parent.
416 the working directory files are compared to its parent.
417
417
418 Alternatively you can specify -c/--change with a revision to see the
418 Alternatively you can specify -c/--change with a revision to see the
419 changes in that changeset relative to its first parent.
419 changes in that changeset relative to its first parent.
420
420
421 Without the -a/--text option, diff will avoid generating diffs of files it
421 Without the -a/--text option, diff will avoid generating diffs of files it
422 detects as binary. With -a, diff will generate a diff anyway, probably
422 detects as binary. With -a, diff will generate a diff anyway, probably
423 with undesirable results.
423 with undesirable results.
424
424
425 Use the -g/--git option to generate diffs in the git extended diff format.
425 Use the -g/--git option to generate diffs in the git extended diff format.
426 For more information, read "hg help diffs".
426 For more information, read "hg help diffs".
427
427
428 Returns 0 on success.
428 Returns 0 on success.
429
429
430 options:
430 options:
431
431
432 -r --rev REV [+] revision
432 -r --rev REV [+] revision
433 -c --change REV change made by revision
433 -c --change REV change made by revision
434 -a --text treat all files as text
434 -a --text treat all files as text
435 -g --git use git extended diff format
435 -g --git use git extended diff format
436 --nodates omit dates from diff headers
436 --nodates omit dates from diff headers
437 -p --show-function show which function each change is in
437 -p --show-function show which function each change is in
438 --reverse produce a diff that undoes the changes
438 --reverse produce a diff that undoes the changes
439 -w --ignore-all-space ignore white space when comparing lines
439 -w --ignore-all-space ignore white space when comparing lines
440 -b --ignore-space-change ignore changes in the amount of white space
440 -b --ignore-space-change ignore changes in the amount of white space
441 -B --ignore-blank-lines ignore changes whose lines are all blank
441 -B --ignore-blank-lines ignore changes whose lines are all blank
442 -U --unified NUM number of lines of context to show
442 -U --unified NUM number of lines of context to show
443 --stat output diffstat-style summary of changes
443 --stat output diffstat-style summary of changes
444 -I --include PATTERN [+] include names matching the given patterns
444 -I --include PATTERN [+] include names matching the given patterns
445 -X --exclude PATTERN [+] exclude names matching the given patterns
445 -X --exclude PATTERN [+] exclude names matching the given patterns
446 -S --subrepos recurse into subrepositories
446 -S --subrepos recurse into subrepositories
447
447
448 [+] marked option can be specified multiple times
448 [+] marked option can be specified multiple times
449
449
450 use "hg -v help diff" to show more info
450 use "hg -v help diff" to show more info
451
451
452 $ hg help status
452 $ hg help status
453 hg status [OPTION]... [FILE]...
453 hg status [OPTION]... [FILE]...
454
454
455 aliases: st
455 aliases: st
456
456
457 show changed files in the working directory
457 show changed files in the working directory
458
458
459 Show status of files in the repository. If names are given, only files
459 Show status of files in the repository. If names are given, only files
460 that match are shown. Files that are clean or ignored or the source of a
460 that match are shown. Files that are clean or ignored or the source of a
461 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
461 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
462 -C/--copies or -A/--all are given. Unless options described with "show
462 -C/--copies or -A/--all are given. Unless options described with "show
463 only ..." are given, the options -mardu are used.
463 only ..." are given, the options -mardu are used.
464
464
465 Option -q/--quiet hides untracked (unknown and ignored) files unless
465 Option -q/--quiet hides untracked (unknown and ignored) files unless
466 explicitly requested with -u/--unknown or -i/--ignored.
466 explicitly requested with -u/--unknown or -i/--ignored.
467
467
468 Note:
468 Note:
469 status may appear to disagree with diff if permissions have changed or
469 status may appear to disagree with diff if permissions have changed or
470 a merge has occurred. The standard diff format does not report
470 a merge has occurred. The standard diff format does not report
471 permission changes and diff only reports changes relative to one merge
471 permission changes and diff only reports changes relative to one merge
472 parent.
472 parent.
473
473
474 If one revision is given, it is used as the base revision. If two
474 If one revision is given, it is used as the base revision. If two
475 revisions are given, the differences between them are shown. The --change
475 revisions are given, the differences between them are shown. The --change
476 option can also be used as a shortcut to list the changed files of a
476 option can also be used as a shortcut to list the changed files of a
477 revision from its first parent.
477 revision from its first parent.
478
478
479 The codes used to show the status of files are:
479 The codes used to show the status of files are:
480
480
481 M = modified
481 M = modified
482 A = added
482 A = added
483 R = removed
483 R = removed
484 C = clean
484 C = clean
485 ! = missing (deleted by non-hg command, but still tracked)
485 ! = missing (deleted by non-hg command, but still tracked)
486 ? = not tracked
486 ? = not tracked
487 I = ignored
487 I = ignored
488 = origin of the previous file listed as A (added)
488 = origin of the previous file listed as A (added)
489
489
490 Returns 0 on success.
490 Returns 0 on success.
491
491
492 options:
492 options:
493
493
494 -A --all show status of all files
494 -A --all show status of all files
495 -m --modified show only modified files
495 -m --modified show only modified files
496 -a --added show only added files
496 -a --added show only added files
497 -r --removed show only removed files
497 -r --removed show only removed files
498 -d --deleted show only deleted (but tracked) files
498 -d --deleted show only deleted (but tracked) files
499 -c --clean show only files without changes
499 -c --clean show only files without changes
500 -u --unknown show only unknown (not tracked) files
500 -u --unknown show only unknown (not tracked) files
501 -i --ignored show only ignored files
501 -i --ignored show only ignored files
502 -n --no-status hide status prefix
502 -n --no-status hide status prefix
503 -C --copies show source of copied files
503 -C --copies show source of copied files
504 -0 --print0 end filenames with NUL, for use with xargs
504 -0 --print0 end filenames with NUL, for use with xargs
505 --rev REV [+] show difference from revision
505 --rev REV [+] show difference from revision
506 --change REV list the changed files of a revision
506 --change REV list the changed files of a revision
507 -I --include PATTERN [+] include names matching the given patterns
507 -I --include PATTERN [+] include names matching the given patterns
508 -X --exclude PATTERN [+] exclude names matching the given patterns
508 -X --exclude PATTERN [+] exclude names matching the given patterns
509 -S --subrepos recurse into subrepositories
509 -S --subrepos recurse into subrepositories
510
510
511 [+] marked option can be specified multiple times
511 [+] marked option can be specified multiple times
512
512
513 use "hg -v help status" to show more info
513 use "hg -v help status" to show more info
514
514
515 $ hg -q help status
515 $ hg -q help status
516 hg status [OPTION]... [FILE]...
516 hg status [OPTION]... [FILE]...
517
517
518 show changed files in the working directory
518 show changed files in the working directory
519
519
520 $ hg help foo
520 $ hg help foo
521 hg: unknown command 'foo'
521 hg: unknown command 'foo'
522 Mercurial Distributed SCM
522 Mercurial Distributed SCM
523
523
524 basic commands:
524 basic commands:
525
525
526 add add the specified files on the next commit
526 add add the specified files on the next commit
527 annotate show changeset information by line for each file
527 annotate show changeset information by line for each file
528 clone make a copy of an existing repository
528 clone make a copy of an existing repository
529 commit commit the specified files or all outstanding changes
529 commit commit the specified files or all outstanding changes
530 diff diff repository (or selected files)
530 diff diff repository (or selected files)
531 export dump the header and diffs for one or more changesets
531 export dump the header and diffs for one or more changesets
532 forget forget the specified files on the next commit
532 forget forget the specified files on the next commit
533 init create a new repository in the given directory
533 init create a new repository in the given directory
534 log show revision history of entire repository or files
534 log show revision history of entire repository or files
535 merge merge working directory with another revision
535 merge merge working directory with another revision
536 phase set or show the current phase name
536 phase set or show the current phase name
537 pull pull changes from the specified source
537 pull pull changes from the specified source
538 push push changes to the specified destination
538 push push changes to the specified destination
539 remove remove the specified files on the next commit
539 remove remove the specified files on the next commit
540 serve start stand-alone webserver
540 serve start stand-alone webserver
541 status show changed files in the working directory
541 status show changed files in the working directory
542 summary summarize working directory state
542 summary summarize working directory state
543 update update working directory (or switch revisions)
543 update update working directory (or switch revisions)
544
544
545 use "hg help" for the full list of commands or "hg -v" for details
545 use "hg help" for the full list of commands or "hg -v" for details
546 [255]
546 [255]
547
547
548 $ hg skjdfks
548 $ hg skjdfks
549 hg: unknown command 'skjdfks'
549 hg: unknown command 'skjdfks'
550 Mercurial Distributed SCM
550 Mercurial Distributed SCM
551
551
552 basic commands:
552 basic commands:
553
553
554 add add the specified files on the next commit
554 add add the specified files on the next commit
555 annotate show changeset information by line for each file
555 annotate show changeset information by line for each file
556 clone make a copy of an existing repository
556 clone make a copy of an existing repository
557 commit commit the specified files or all outstanding changes
557 commit commit the specified files or all outstanding changes
558 diff diff repository (or selected files)
558 diff diff repository (or selected files)
559 export dump the header and diffs for one or more changesets
559 export dump the header and diffs for one or more changesets
560 forget forget the specified files on the next commit
560 forget forget the specified files on the next commit
561 init create a new repository in the given directory
561 init create a new repository in the given directory
562 log show revision history of entire repository or files
562 log show revision history of entire repository or files
563 merge merge working directory with another revision
563 merge merge working directory with another revision
564 phase set or show the current phase name
564 phase set or show the current phase name
565 pull pull changes from the specified source
565 pull pull changes from the specified source
566 push push changes to the specified destination
566 push push changes to the specified destination
567 remove remove the specified files on the next commit
567 remove remove the specified files on the next commit
568 serve start stand-alone webserver
568 serve start stand-alone webserver
569 status show changed files in the working directory
569 status show changed files in the working directory
570 summary summarize working directory state
570 summary summarize working directory state
571 update update working directory (or switch revisions)
571 update update working directory (or switch revisions)
572
572
573 use "hg help" for the full list of commands or "hg -v" for details
573 use "hg help" for the full list of commands or "hg -v" for details
574 [255]
574 [255]
575
575
576 $ cat > helpext.py <<EOF
576 $ cat > helpext.py <<EOF
577 > import os
577 > import os
578 > from mercurial import commands
578 > from mercurial import commands
579 >
579 >
580 > def nohelp(ui, *args, **kwargs):
580 > def nohelp(ui, *args, **kwargs):
581 > pass
581 > pass
582 >
582 >
583 > cmdtable = {
583 > cmdtable = {
584 > "nohelp": (nohelp, [], "hg nohelp"),
584 > "nohelp": (nohelp, [], "hg nohelp"),
585 > }
585 > }
586 >
586 >
587 > commands.norepo += ' nohelp'
587 > commands.norepo += ' nohelp'
588 > EOF
588 > EOF
589 $ echo '[extensions]' >> $HGRCPATH
589 $ echo '[extensions]' >> $HGRCPATH
590 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
590 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
591
591
592 Test command with no help text
592 Test command with no help text
593
593
594 $ hg help nohelp
594 $ hg help nohelp
595 hg nohelp
595 hg nohelp
596
596
597 (no help text available)
597 (no help text available)
598
598
599 use "hg -v help nohelp" to show more info
599 use "hg -v help nohelp" to show more info
600
600
601 $ hg help -k nohelp
601 $ hg help -k nohelp
602 Commands:
602 Commands:
603
603
604 nohelp hg nohelp
604 nohelp hg nohelp
605
605
606 Extension Commands:
606 Extension Commands:
607
607
608 nohelp (no help text available)
608 nohelp (no help text available)
609
609
610 Test that default list of commands omits extension commands
610 Test that default list of commands omits extension commands
611
611
612 $ hg help
612 $ hg help
613 Mercurial Distributed SCM
613 Mercurial Distributed SCM
614
614
615 list of commands:
615 list of commands:
616
616
617 add add the specified files on the next commit
617 add add the specified files on the next commit
618 addremove add all new files, delete all missing files
618 addremove add all new files, delete all missing files
619 annotate show changeset information by line for each file
619 annotate show changeset information by line for each file
620 archive create an unversioned archive of a repository revision
620 archive create an unversioned archive of a repository revision
621 backout reverse effect of earlier changeset
621 backout reverse effect of earlier changeset
622 bisect subdivision search of changesets
622 bisect subdivision search of changesets
623 bookmarks track a line of development with movable markers
623 bookmarks track a line of development with movable markers
624 branch set or show the current branch name
624 branch set or show the current branch name
625 branches list repository named branches
625 branches list repository named branches
626 bundle create a changegroup file
626 bundle create a changegroup file
627 cat output the current or given revision of files
627 cat output the current or given revision of files
628 clone make a copy of an existing repository
628 clone make a copy of an existing repository
629 commit commit the specified files or all outstanding changes
629 commit commit the specified files or all outstanding changes
630 copy mark files as copied for the next commit
630 copy mark files as copied for the next commit
631 diff diff repository (or selected files)
631 diff diff repository (or selected files)
632 export dump the header and diffs for one or more changesets
632 export dump the header and diffs for one or more changesets
633 forget forget the specified files on the next commit
633 forget forget the specified files on the next commit
634 graft copy changes from other branches onto the current branch
634 graft copy changes from other branches onto the current branch
635 grep search for a pattern in specified files and revisions
635 grep search for a pattern in specified files and revisions
636 heads show current repository heads or show branch heads
636 heads show current repository heads or show branch heads
637 help show help for a given topic or a help overview
637 help show help for a given topic or a help overview
638 identify identify the working copy or specified revision
638 identify identify the working copy or specified revision
639 import import an ordered set of patches
639 import import an ordered set of patches
640 incoming show new changesets found in source
640 incoming show new changesets found in source
641 init create a new repository in the given directory
641 init create a new repository in the given directory
642 locate locate files matching specific patterns
642 locate locate files matching specific patterns
643 log show revision history of entire repository or files
643 log show revision history of entire repository or files
644 manifest output the current or given revision of the project manifest
644 manifest output the current or given revision of the project manifest
645 merge merge working directory with another revision
645 merge merge working directory with another revision
646 outgoing show changesets not found in the destination
646 outgoing show changesets not found in the destination
647 parents show the parents of the working directory or revision
647 parents show the parents of the working directory or revision
648 paths show aliases for remote repositories
648 paths show aliases for remote repositories
649 phase set or show the current phase name
649 phase set or show the current phase name
650 pull pull changes from the specified source
650 pull pull changes from the specified source
651 push push changes to the specified destination
651 push push changes to the specified destination
652 recover roll back an interrupted transaction
652 recover roll back an interrupted transaction
653 remove remove the specified files on the next commit
653 remove remove the specified files on the next commit
654 rename rename files; equivalent of copy + remove
654 rename rename files; equivalent of copy + remove
655 resolve redo merges or set/view the merge status of files
655 resolve redo merges or set/view the merge status of files
656 revert restore files to their checkout state
656 revert restore files to their checkout state
657 rollback roll back the last transaction (dangerous)
657 rollback roll back the last transaction (dangerous)
658 root print the root (top) of the current working directory
658 root print the root (top) of the current working directory
659 serve start stand-alone webserver
659 serve start stand-alone webserver
660 showconfig show combined config settings from all hgrc files
660 showconfig show combined config settings from all hgrc files
661 status show changed files in the working directory
661 status show changed files in the working directory
662 summary summarize working directory state
662 summary summarize working directory state
663 tag add one or more tags for the current or given revision
663 tag add one or more tags for the current or given revision
664 tags list repository tags
664 tags list repository tags
665 tip show the tip revision
665 tip show the tip revision
666 unbundle apply one or more changegroup files
666 unbundle apply one or more changegroup files
667 update update working directory (or switch revisions)
667 update update working directory (or switch revisions)
668 verify verify the integrity of the repository
668 verify verify the integrity of the repository
669 version output version and copyright information
669 version output version and copyright information
670
670
671 enabled extensions:
671 enabled extensions:
672
672
673 helpext (no help text available)
673 helpext (no help text available)
674
674
675 additional help topics:
675 additional help topics:
676
676
677 config Configuration Files
677 config Configuration Files
678 dates Date Formats
678 dates Date Formats
679 diffs Diff Formats
679 diffs Diff Formats
680 environment Environment Variables
680 environment Environment Variables
681 extensions Using Additional Features
681 extensions Using Additional Features
682 filesets Specifying File Sets
682 filesets Specifying File Sets
683 glossary Glossary
683 glossary Glossary
684 hgignore Syntax for Mercurial Ignore Files
684 hgignore Syntax for Mercurial Ignore Files
685 hgweb Configuring hgweb
685 hgweb Configuring hgweb
686 merge-tools Merge Tools
686 merge-tools Merge Tools
687 multirevs Specifying Multiple Revisions
687 multirevs Specifying Multiple Revisions
688 patterns File Name Patterns
688 patterns File Name Patterns
689 phases Working with Phases
689 phases Working with Phases
690 revisions Specifying Single Revisions
690 revisions Specifying Single Revisions
691 revsets Specifying Revision Sets
691 revsets Specifying Revision Sets
692 subrepos Subrepositories
692 subrepos Subrepositories
693 templating Template Usage
693 templating Template Usage
694 urls URL Paths
694 urls URL Paths
695
695
696 use "hg -v help" to show builtin aliases and global options
696 use "hg -v help" to show builtin aliases and global options
697
697
698
698
699
699
700 Test list of commands with command with no help text
700 Test list of commands with command with no help text
701
701
702 $ hg help helpext
702 $ hg help helpext
703 helpext extension - no help text available
703 helpext extension - no help text available
704
704
705 list of commands:
705 list of commands:
706
706
707 nohelp (no help text available)
707 nohelp (no help text available)
708
708
709 use "hg -v help helpext" to show builtin aliases and global options
709 use "hg -v help helpext" to show builtin aliases and global options
710
710
711 Test a help topic
711 Test a help topic
712
712
713 $ hg help revs
713 $ hg help revs
714 Specifying Single Revisions
714 Specifying Single Revisions
715
715
716 Mercurial supports several ways to specify individual revisions.
716 Mercurial supports several ways to specify individual revisions.
717
717
718 A plain integer is treated as a revision number. Negative integers are
718 A plain integer is treated as a revision number. Negative integers are
719 treated as sequential offsets from the tip, with -1 denoting the tip, -2
719 treated as sequential offsets from the tip, with -1 denoting the tip, -2
720 denoting the revision prior to the tip, and so forth.
720 denoting the revision prior to the tip, and so forth.
721
721
722 A 40-digit hexadecimal string is treated as a unique revision identifier.
722 A 40-digit hexadecimal string is treated as a unique revision identifier.
723
723
724 A hexadecimal string less than 40 characters long is treated as a unique
724 A hexadecimal string less than 40 characters long is treated as a unique
725 revision identifier and is referred to as a short-form identifier. A
725 revision identifier and is referred to as a short-form identifier. A
726 short-form identifier is only valid if it is the prefix of exactly one
726 short-form identifier is only valid if it is the prefix of exactly one
727 full-length identifier.
727 full-length identifier.
728
728
729 Any other string is treated as a bookmark, tag, or branch name. A bookmark
729 Any other string is treated as a bookmark, tag, or branch name. A bookmark
730 is a movable pointer to a revision. A tag is a permanent name associated
730 is a movable pointer to a revision. A tag is a permanent name associated
731 with a revision. A branch name denotes the tipmost revision of that
731 with a revision. A branch name denotes the tipmost revision of that
732 branch. Bookmark, tag, and branch names must not contain the ":"
732 branch. Bookmark, tag, and branch names must not contain the ":"
733 character.
733 character.
734
734
735 The reserved name "tip" always identifies the most recent revision.
735 The reserved name "tip" always identifies the most recent revision.
736
736
737 The reserved name "null" indicates the null revision. This is the revision
737 The reserved name "null" indicates the null revision. This is the revision
738 of an empty repository, and the parent of revision 0.
738 of an empty repository, and the parent of revision 0.
739
739
740 The reserved name "." indicates the working directory parent. If no
740 The reserved name "." indicates the working directory parent. If no
741 working directory is checked out, it is equivalent to null. If an
741 working directory is checked out, it is equivalent to null. If an
742 uncommitted merge is in progress, "." is the revision of the first parent.
742 uncommitted merge is in progress, "." is the revision of the first parent.
743
743
744 Test templating help
744 Test templating help
745
745
746 $ hg help templating | egrep '(desc|diffstat|firstline|nonempty) '
746 $ hg help templating | egrep '(desc|diffstat|firstline|nonempty) '
747 desc String. The text of the changeset description.
747 desc String. The text of the changeset description.
748 diffstat String. Statistics of changes with the following format:
748 diffstat String. Statistics of changes with the following format:
749 firstline Any text. Returns the first line of text.
749 firstline Any text. Returns the first line of text.
750 nonempty Any text. Returns '(none)' if the string is empty.
750 nonempty Any text. Returns '(none)' if the string is empty.
751
751
752 Test help hooks
752 Test help hooks
753
753
754 $ cat > helphook1.py <<EOF
754 $ cat > helphook1.py <<EOF
755 > from mercurial import help
755 > from mercurial import help
756 >
756 >
757 > def rewrite(topic, doc):
757 > def rewrite(topic, doc):
758 > return doc + '\nhelphook1\n'
758 > return doc + '\nhelphook1\n'
759 >
759 >
760 > def extsetup(ui):
760 > def extsetup(ui):
761 > help.addtopichook('revsets', rewrite)
761 > help.addtopichook('revsets', rewrite)
762 > EOF
762 > EOF
763 $ cat > helphook2.py <<EOF
763 $ cat > helphook2.py <<EOF
764 > from mercurial import help
764 > from mercurial import help
765 >
765 >
766 > def rewrite(topic, doc):
766 > def rewrite(topic, doc):
767 > return doc + '\nhelphook2\n'
767 > return doc + '\nhelphook2\n'
768 >
768 >
769 > def extsetup(ui):
769 > def extsetup(ui):
770 > help.addtopichook('revsets', rewrite)
770 > help.addtopichook('revsets', rewrite)
771 > EOF
771 > EOF
772 $ echo '[extensions]' >> $HGRCPATH
772 $ echo '[extensions]' >> $HGRCPATH
773 $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
773 $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
774 $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
774 $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
775 $ hg help revsets | grep helphook
775 $ hg help revsets | grep helphook
776 helphook1
776 helphook1
777 helphook2
777 helphook2
778
778
779 Test keyword search help
779 Test keyword search help
780
780
781 $ hg help -k clone
781 $ hg help -k clone
782 Topics:
782 Topics:
783
783
784 config Configuration Files
784 config Configuration Files
785 extensions Using Additional Features
785 extensions Using Additional Features
786 glossary Glossary
786 glossary Glossary
787 phases Working with Phases
787 phases Working with Phases
788 subrepo Subrepositories
788 subrepos Subrepositories
789 urls URL Paths
789 urls URL Paths
790
790
791 Commands:
791 Commands:
792
792
793 clone make a copy of an existing repository
793 clone make a copy of an existing repository
794 paths show aliases for remote repositories
794 paths show aliases for remote repositories
795 update update working directory (or switch revisions)
795 update update working directory (or switch revisions)
796
796
797 Extensions:
797 Extensions:
798
798
799 relink recreates hardlinks between repository clones
799 relink recreates hardlinks between repository clones
800
800
801 Extension Commands:
801 Extension Commands:
802
802
803 qclone clone main and patch repository at same time
803 qclone clone main and patch repository at same time
804
804
General Comments 0
You need to be logged in to leave comments. Login now