##// END OF EJS Templates
help: move the majority of the help command to the help module...
Dan Villiom Podlaski Christiansen -
r18746:c0087d48 default
parent child Browse files
Show More
@@ -1,6011 +1,5729
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 _
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, copies, error, bookmarks
13 import patch, help, encoding, templatekw, discovery
13 import patch, help, 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 ('', 'hidden', False, _('consider hidden changesets')),
52 ('', 'hidden', False, _('consider hidden changesets')),
53 ]
53 ]
54
54
55 dryrunopts = [('n', 'dry-run', None,
55 dryrunopts = [('n', 'dry-run', None,
56 _('do not perform actions, just print output'))]
56 _('do not perform actions, just print output'))]
57
57
58 remoteopts = [
58 remoteopts = [
59 ('e', 'ssh', '',
59 ('e', 'ssh', '',
60 _('specify ssh command to use'), _('CMD')),
60 _('specify ssh command to use'), _('CMD')),
61 ('', 'remotecmd', '',
61 ('', 'remotecmd', '',
62 _('specify hg command to run on the remote side'), _('CMD')),
62 _('specify hg command to run on the remote side'), _('CMD')),
63 ('', 'insecure', None,
63 ('', 'insecure', None,
64 _('do not verify server certificate (ignoring web.cacerts config)')),
64 _('do not verify server certificate (ignoring web.cacerts config)')),
65 ]
65 ]
66
66
67 walkopts = [
67 walkopts = [
68 ('I', 'include', [],
68 ('I', 'include', [],
69 _('include names matching the given patterns'), _('PATTERN')),
69 _('include names matching the given patterns'), _('PATTERN')),
70 ('X', 'exclude', [],
70 ('X', 'exclude', [],
71 _('exclude names matching the given patterns'), _('PATTERN')),
71 _('exclude names matching the given patterns'), _('PATTERN')),
72 ]
72 ]
73
73
74 commitopts = [
74 commitopts = [
75 ('m', 'message', '',
75 ('m', 'message', '',
76 _('use text as commit message'), _('TEXT')),
76 _('use text as commit message'), _('TEXT')),
77 ('l', 'logfile', '',
77 ('l', 'logfile', '',
78 _('read commit message from file'), _('FILE')),
78 _('read commit message from file'), _('FILE')),
79 ]
79 ]
80
80
81 commitopts2 = [
81 commitopts2 = [
82 ('d', 'date', '',
82 ('d', 'date', '',
83 _('record the specified date as commit date'), _('DATE')),
83 _('record the specified date as commit date'), _('DATE')),
84 ('u', 'user', '',
84 ('u', 'user', '',
85 _('record the specified user as committer'), _('USER')),
85 _('record the specified user as committer'), _('USER')),
86 ]
86 ]
87
87
88 templateopts = [
88 templateopts = [
89 ('', 'style', '',
89 ('', 'style', '',
90 _('display using template map file'), _('STYLE')),
90 _('display using template map file'), _('STYLE')),
91 ('', 'template', '',
91 ('', 'template', '',
92 _('display with template'), _('TEMPLATE')),
92 _('display with template'), _('TEMPLATE')),
93 ]
93 ]
94
94
95 logopts = [
95 logopts = [
96 ('p', 'patch', None, _('show patch')),
96 ('p', 'patch', None, _('show patch')),
97 ('g', 'git', None, _('use git extended diff format')),
97 ('g', 'git', None, _('use git extended diff format')),
98 ('l', 'limit', '',
98 ('l', 'limit', '',
99 _('limit number of changes displayed'), _('NUM')),
99 _('limit number of changes displayed'), _('NUM')),
100 ('M', 'no-merges', None, _('do not show merges')),
100 ('M', 'no-merges', None, _('do not show merges')),
101 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 ('', 'stat', None, _('output diffstat-style summary of changes')),
102 ('G', 'graph', None, _("show the revision DAG")),
102 ('G', 'graph', None, _("show the revision DAG")),
103 ] + templateopts
103 ] + templateopts
104
104
105 diffopts = [
105 diffopts = [
106 ('a', 'text', None, _('treat all files as text')),
106 ('a', 'text', None, _('treat all files as text')),
107 ('g', 'git', None, _('use git extended diff format')),
107 ('g', 'git', None, _('use git extended diff format')),
108 ('', 'nodates', None, _('omit dates from diff headers'))
108 ('', 'nodates', None, _('omit dates from diff headers'))
109 ]
109 ]
110
110
111 diffwsopts = [
111 diffwsopts = [
112 ('w', 'ignore-all-space', None,
112 ('w', 'ignore-all-space', None,
113 _('ignore white space when comparing lines')),
113 _('ignore white space when comparing lines')),
114 ('b', 'ignore-space-change', None,
114 ('b', 'ignore-space-change', None,
115 _('ignore changes in the amount of white space')),
115 _('ignore changes in the amount of white space')),
116 ('B', 'ignore-blank-lines', None,
116 ('B', 'ignore-blank-lines', None,
117 _('ignore changes whose lines are all blank')),
117 _('ignore changes whose lines are all blank')),
118 ]
118 ]
119
119
120 diffopts2 = [
120 diffopts2 = [
121 ('p', 'show-function', None, _('show which function each change is in')),
121 ('p', 'show-function', None, _('show which function each change is in')),
122 ('', 'reverse', None, _('produce a diff that undoes the changes')),
122 ('', 'reverse', None, _('produce a diff that undoes the changes')),
123 ] + diffwsopts + [
123 ] + diffwsopts + [
124 ('U', 'unified', '',
124 ('U', 'unified', '',
125 _('number of lines of context to show'), _('NUM')),
125 _('number of lines of context to show'), _('NUM')),
126 ('', 'stat', None, _('output diffstat-style summary of changes')),
126 ('', 'stat', None, _('output diffstat-style summary of changes')),
127 ]
127 ]
128
128
129 mergetoolopts = [
129 mergetoolopts = [
130 ('t', 'tool', '', _('specify merge tool')),
130 ('t', 'tool', '', _('specify merge tool')),
131 ]
131 ]
132
132
133 similarityopts = [
133 similarityopts = [
134 ('s', 'similarity', '',
134 ('s', 'similarity', '',
135 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
135 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
136 ]
136 ]
137
137
138 subrepoopts = [
138 subrepoopts = [
139 ('S', 'subrepos', None,
139 ('S', 'subrepos', None,
140 _('recurse into subrepositories'))
140 _('recurse into subrepositories'))
141 ]
141 ]
142
142
143 # Commands start here, listed alphabetically
143 # Commands start here, listed alphabetically
144
144
145 @command('^add',
145 @command('^add',
146 walkopts + subrepoopts + dryrunopts,
146 walkopts + subrepoopts + dryrunopts,
147 _('[OPTION]... [FILE]...'))
147 _('[OPTION]... [FILE]...'))
148 def add(ui, repo, *pats, **opts):
148 def add(ui, repo, *pats, **opts):
149 """add the specified files on the next commit
149 """add the specified files on the next commit
150
150
151 Schedule files to be version controlled and added to the
151 Schedule files to be version controlled and added to the
152 repository.
152 repository.
153
153
154 The files will be added to the repository at the next commit. To
154 The files will be added to the repository at the next commit. To
155 undo an add before that, see :hg:`forget`.
155 undo an add before that, see :hg:`forget`.
156
156
157 If no names are given, add all files to the repository.
157 If no names are given, add all files to the repository.
158
158
159 .. container:: verbose
159 .. container:: verbose
160
160
161 An example showing how new (unknown) files are added
161 An example showing how new (unknown) files are added
162 automatically by :hg:`add`::
162 automatically by :hg:`add`::
163
163
164 $ ls
164 $ ls
165 foo.c
165 foo.c
166 $ hg status
166 $ hg status
167 ? foo.c
167 ? foo.c
168 $ hg add
168 $ hg add
169 adding foo.c
169 adding foo.c
170 $ hg status
170 $ hg status
171 A foo.c
171 A foo.c
172
172
173 Returns 0 if all files are successfully added.
173 Returns 0 if all files are successfully added.
174 """
174 """
175
175
176 m = scmutil.match(repo[None], pats, opts)
176 m = scmutil.match(repo[None], pats, opts)
177 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
177 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
178 opts.get('subrepos'), prefix="", explicitonly=False)
178 opts.get('subrepos'), prefix="", explicitonly=False)
179 return rejected and 1 or 0
179 return rejected and 1 or 0
180
180
181 @command('addremove',
181 @command('addremove',
182 similarityopts + walkopts + dryrunopts,
182 similarityopts + walkopts + dryrunopts,
183 _('[OPTION]... [FILE]...'))
183 _('[OPTION]... [FILE]...'))
184 def addremove(ui, repo, *pats, **opts):
184 def addremove(ui, repo, *pats, **opts):
185 """add all new files, delete all missing files
185 """add all new files, delete all missing files
186
186
187 Add all new files and remove all missing files from the
187 Add all new files and remove all missing files from the
188 repository.
188 repository.
189
189
190 New files are ignored if they match any of the patterns in
190 New files are ignored if they match any of the patterns in
191 ``.hgignore``. As with add, these changes take effect at the next
191 ``.hgignore``. As with add, these changes take effect at the next
192 commit.
192 commit.
193
193
194 Use the -s/--similarity option to detect renamed files. This
194 Use the -s/--similarity option to detect renamed files. This
195 option takes a percentage between 0 (disabled) and 100 (files must
195 option takes a percentage between 0 (disabled) and 100 (files must
196 be identical) as its parameter. With a parameter greater than 0,
196 be identical) as its parameter. With a parameter greater than 0,
197 this compares every removed file with every added file and records
197 this compares every removed file with every added file and records
198 those similar enough as renames. Detecting renamed files this way
198 those similar enough as renames. Detecting renamed files this way
199 can be expensive. After using this option, :hg:`status -C` can be
199 can be expensive. After using this option, :hg:`status -C` can be
200 used to check which files were identified as moved or renamed. If
200 used to check which files were identified as moved or renamed. If
201 not specified, -s/--similarity defaults to 100 and only renames of
201 not specified, -s/--similarity defaults to 100 and only renames of
202 identical files are detected.
202 identical files are detected.
203
203
204 Returns 0 if all files are successfully added.
204 Returns 0 if all files are successfully added.
205 """
205 """
206 try:
206 try:
207 sim = float(opts.get('similarity') or 100)
207 sim = float(opts.get('similarity') or 100)
208 except ValueError:
208 except ValueError:
209 raise util.Abort(_('similarity must be a number'))
209 raise util.Abort(_('similarity must be a number'))
210 if sim < 0 or sim > 100:
210 if sim < 0 or sim > 100:
211 raise util.Abort(_('similarity must be between 0 and 100'))
211 raise util.Abort(_('similarity must be between 0 and 100'))
212 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
212 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
213
213
214 @command('^annotate|blame',
214 @command('^annotate|blame',
215 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
215 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
216 ('', 'follow', None,
216 ('', 'follow', None,
217 _('follow copies/renames and list the filename (DEPRECATED)')),
217 _('follow copies/renames and list the filename (DEPRECATED)')),
218 ('', 'no-follow', None, _("don't follow copies and renames")),
218 ('', 'no-follow', None, _("don't follow copies and renames")),
219 ('a', 'text', None, _('treat all files as text')),
219 ('a', 'text', None, _('treat all files as text')),
220 ('u', 'user', None, _('list the author (long with -v)')),
220 ('u', 'user', None, _('list the author (long with -v)')),
221 ('f', 'file', None, _('list the filename')),
221 ('f', 'file', None, _('list the filename')),
222 ('d', 'date', None, _('list the date (short with -q)')),
222 ('d', 'date', None, _('list the date (short with -q)')),
223 ('n', 'number', None, _('list the revision number (default)')),
223 ('n', 'number', None, _('list the revision number (default)')),
224 ('c', 'changeset', None, _('list the changeset')),
224 ('c', 'changeset', None, _('list the changeset')),
225 ('l', 'line-number', None, _('show line number at the first appearance'))
225 ('l', 'line-number', None, _('show line number at the first appearance'))
226 ] + diffwsopts + walkopts,
226 ] + diffwsopts + walkopts,
227 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
227 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
228 def annotate(ui, repo, *pats, **opts):
228 def annotate(ui, repo, *pats, **opts):
229 """show changeset information by line for each file
229 """show changeset information by line for each file
230
230
231 List changes in files, showing the revision id responsible for
231 List changes in files, showing the revision id responsible for
232 each line
232 each line
233
233
234 This command is useful for discovering when a change was made and
234 This command is useful for discovering when a change was made and
235 by whom.
235 by whom.
236
236
237 Without the -a/--text option, annotate will avoid processing files
237 Without the -a/--text option, annotate will avoid processing files
238 it detects as binary. With -a, annotate will annotate the file
238 it detects as binary. With -a, annotate will annotate the file
239 anyway, although the results will probably be neither useful
239 anyway, although the results will probably be neither useful
240 nor desirable.
240 nor desirable.
241
241
242 Returns 0 on success.
242 Returns 0 on success.
243 """
243 """
244 if opts.get('follow'):
244 if opts.get('follow'):
245 # --follow is deprecated and now just an alias for -f/--file
245 # --follow is deprecated and now just an alias for -f/--file
246 # to mimic the behavior of Mercurial before version 1.5
246 # to mimic the behavior of Mercurial before version 1.5
247 opts['file'] = True
247 opts['file'] = True
248
248
249 datefunc = ui.quiet and util.shortdate or util.datestr
249 datefunc = ui.quiet and util.shortdate or util.datestr
250 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
250 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
251
251
252 if not pats:
252 if not pats:
253 raise util.Abort(_('at least one filename or pattern is required'))
253 raise util.Abort(_('at least one filename or pattern is required'))
254
254
255 hexfn = ui.debugflag and hex or short
255 hexfn = ui.debugflag and hex or short
256
256
257 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
257 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
258 ('number', ' ', lambda x: str(x[0].rev())),
258 ('number', ' ', lambda x: str(x[0].rev())),
259 ('changeset', ' ', lambda x: hexfn(x[0].node())),
259 ('changeset', ' ', lambda x: hexfn(x[0].node())),
260 ('date', ' ', getdate),
260 ('date', ' ', getdate),
261 ('file', ' ', lambda x: x[0].path()),
261 ('file', ' ', lambda x: x[0].path()),
262 ('line_number', ':', lambda x: str(x[1])),
262 ('line_number', ':', lambda x: str(x[1])),
263 ]
263 ]
264
264
265 if (not opts.get('user') and not opts.get('changeset')
265 if (not opts.get('user') and not opts.get('changeset')
266 and not opts.get('date') and not opts.get('file')):
266 and not opts.get('date') and not opts.get('file')):
267 opts['number'] = True
267 opts['number'] = True
268
268
269 linenumber = opts.get('line_number') is not None
269 linenumber = opts.get('line_number') is not None
270 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
270 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
271 raise util.Abort(_('at least one of -n/-c is required for -l'))
271 raise util.Abort(_('at least one of -n/-c is required for -l'))
272
272
273 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
273 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
274 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
274 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
275
275
276 def bad(x, y):
276 def bad(x, y):
277 raise util.Abort("%s: %s" % (x, y))
277 raise util.Abort("%s: %s" % (x, y))
278
278
279 ctx = scmutil.revsingle(repo, opts.get('rev'))
279 ctx = scmutil.revsingle(repo, opts.get('rev'))
280 m = scmutil.match(ctx, pats, opts)
280 m = scmutil.match(ctx, pats, opts)
281 m.bad = bad
281 m.bad = bad
282 follow = not opts.get('no_follow')
282 follow = not opts.get('no_follow')
283 diffopts = patch.diffopts(ui, opts, section='annotate')
283 diffopts = patch.diffopts(ui, opts, section='annotate')
284 for abs in ctx.walk(m):
284 for abs in ctx.walk(m):
285 fctx = ctx[abs]
285 fctx = ctx[abs]
286 if not opts.get('text') and util.binary(fctx.data()):
286 if not opts.get('text') and util.binary(fctx.data()):
287 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
287 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
288 continue
288 continue
289
289
290 lines = fctx.annotate(follow=follow, linenumber=linenumber,
290 lines = fctx.annotate(follow=follow, linenumber=linenumber,
291 diffopts=diffopts)
291 diffopts=diffopts)
292 pieces = []
292 pieces = []
293
293
294 for f, sep in funcmap:
294 for f, sep in funcmap:
295 l = [f(n) for n, dummy in lines]
295 l = [f(n) for n, dummy in lines]
296 if l:
296 if l:
297 sized = [(x, encoding.colwidth(x)) for x in l]
297 sized = [(x, encoding.colwidth(x)) for x in l]
298 ml = max([w for x, w in sized])
298 ml = max([w for x, w in sized])
299 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
299 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
300 for x, w in sized])
300 for x, w in sized])
301
301
302 if pieces:
302 if pieces:
303 for p, l in zip(zip(*pieces), lines):
303 for p, l in zip(zip(*pieces), lines):
304 ui.write("%s: %s" % ("".join(p), l[1]))
304 ui.write("%s: %s" % ("".join(p), l[1]))
305
305
306 if lines and not lines[-1][1].endswith('\n'):
306 if lines and not lines[-1][1].endswith('\n'):
307 ui.write('\n')
307 ui.write('\n')
308
308
309 @command('archive',
309 @command('archive',
310 [('', 'no-decode', None, _('do not pass files through decoders')),
310 [('', 'no-decode', None, _('do not pass files through decoders')),
311 ('p', 'prefix', '', _('directory prefix for files in archive'),
311 ('p', 'prefix', '', _('directory prefix for files in archive'),
312 _('PREFIX')),
312 _('PREFIX')),
313 ('r', 'rev', '', _('revision to distribute'), _('REV')),
313 ('r', 'rev', '', _('revision to distribute'), _('REV')),
314 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
314 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
315 ] + subrepoopts + walkopts,
315 ] + subrepoopts + walkopts,
316 _('[OPTION]... DEST'))
316 _('[OPTION]... DEST'))
317 def archive(ui, repo, dest, **opts):
317 def archive(ui, repo, dest, **opts):
318 '''create an unversioned archive of a repository revision
318 '''create an unversioned archive of a repository revision
319
319
320 By default, the revision used is the parent of the working
320 By default, the revision used is the parent of the working
321 directory; use -r/--rev to specify a different revision.
321 directory; use -r/--rev to specify a different revision.
322
322
323 The archive type is automatically detected based on file
323 The archive type is automatically detected based on file
324 extension (or override using -t/--type).
324 extension (or override using -t/--type).
325
325
326 .. container:: verbose
326 .. container:: verbose
327
327
328 Examples:
328 Examples:
329
329
330 - create a zip file containing the 1.0 release::
330 - create a zip file containing the 1.0 release::
331
331
332 hg archive -r 1.0 project-1.0.zip
332 hg archive -r 1.0 project-1.0.zip
333
333
334 - create a tarball excluding .hg files::
334 - create a tarball excluding .hg files::
335
335
336 hg archive project.tar.gz -X ".hg*"
336 hg archive project.tar.gz -X ".hg*"
337
337
338 Valid types are:
338 Valid types are:
339
339
340 :``files``: a directory full of files (default)
340 :``files``: a directory full of files (default)
341 :``tar``: tar archive, uncompressed
341 :``tar``: tar archive, uncompressed
342 :``tbz2``: tar archive, compressed using bzip2
342 :``tbz2``: tar archive, compressed using bzip2
343 :``tgz``: tar archive, compressed using gzip
343 :``tgz``: tar archive, compressed using gzip
344 :``uzip``: zip archive, uncompressed
344 :``uzip``: zip archive, uncompressed
345 :``zip``: zip archive, compressed using deflate
345 :``zip``: zip archive, compressed using deflate
346
346
347 The exact name of the destination archive or directory is given
347 The exact name of the destination archive or directory is given
348 using a format string; see :hg:`help export` for details.
348 using a format string; see :hg:`help export` for details.
349
349
350 Each member added to an archive file has a directory prefix
350 Each member added to an archive file has a directory prefix
351 prepended. Use -p/--prefix to specify a format string for the
351 prepended. Use -p/--prefix to specify a format string for the
352 prefix. The default is the basename of the archive, with suffixes
352 prefix. The default is the basename of the archive, with suffixes
353 removed.
353 removed.
354
354
355 Returns 0 on success.
355 Returns 0 on success.
356 '''
356 '''
357
357
358 ctx = scmutil.revsingle(repo, opts.get('rev'))
358 ctx = scmutil.revsingle(repo, opts.get('rev'))
359 if not ctx:
359 if not ctx:
360 raise util.Abort(_('no working directory: please specify a revision'))
360 raise util.Abort(_('no working directory: please specify a revision'))
361 node = ctx.node()
361 node = ctx.node()
362 dest = cmdutil.makefilename(repo, dest, node)
362 dest = cmdutil.makefilename(repo, dest, node)
363 if os.path.realpath(dest) == repo.root:
363 if os.path.realpath(dest) == repo.root:
364 raise util.Abort(_('repository root cannot be destination'))
364 raise util.Abort(_('repository root cannot be destination'))
365
365
366 kind = opts.get('type') or archival.guesskind(dest) or 'files'
366 kind = opts.get('type') or archival.guesskind(dest) or 'files'
367 prefix = opts.get('prefix')
367 prefix = opts.get('prefix')
368
368
369 if dest == '-':
369 if dest == '-':
370 if kind == 'files':
370 if kind == 'files':
371 raise util.Abort(_('cannot archive plain files to stdout'))
371 raise util.Abort(_('cannot archive plain files to stdout'))
372 dest = cmdutil.makefileobj(repo, dest)
372 dest = cmdutil.makefileobj(repo, dest)
373 if not prefix:
373 if not prefix:
374 prefix = os.path.basename(repo.root) + '-%h'
374 prefix = os.path.basename(repo.root) + '-%h'
375
375
376 prefix = cmdutil.makefilename(repo, prefix, node)
376 prefix = cmdutil.makefilename(repo, prefix, node)
377 matchfn = scmutil.match(ctx, [], opts)
377 matchfn = scmutil.match(ctx, [], opts)
378 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
378 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
379 matchfn, prefix, subrepos=opts.get('subrepos'))
379 matchfn, prefix, subrepos=opts.get('subrepos'))
380
380
381 @command('backout',
381 @command('backout',
382 [('', 'merge', None, _('merge with old dirstate parent after backout')),
382 [('', 'merge', None, _('merge with old dirstate parent after backout')),
383 ('', 'parent', '',
383 ('', 'parent', '',
384 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
384 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
385 ('r', 'rev', '', _('revision to backout'), _('REV')),
385 ('r', 'rev', '', _('revision to backout'), _('REV')),
386 ] + mergetoolopts + walkopts + commitopts + commitopts2,
386 ] + mergetoolopts + walkopts + commitopts + commitopts2,
387 _('[OPTION]... [-r] REV'))
387 _('[OPTION]... [-r] REV'))
388 def backout(ui, repo, node=None, rev=None, **opts):
388 def backout(ui, repo, node=None, rev=None, **opts):
389 '''reverse effect of earlier changeset
389 '''reverse effect of earlier changeset
390
390
391 Prepare a new changeset with the effect of REV undone in the
391 Prepare a new changeset with the effect of REV undone in the
392 current working directory.
392 current working directory.
393
393
394 If REV is the parent of the working directory, then this new changeset
394 If REV is the parent of the working directory, then this new changeset
395 is committed automatically. Otherwise, hg needs to merge the
395 is committed automatically. Otherwise, hg needs to merge the
396 changes and the merged result is left uncommitted.
396 changes and the merged result is left uncommitted.
397
397
398 .. note::
398 .. note::
399 backout cannot be used to fix either an unwanted or
399 backout cannot be used to fix either an unwanted or
400 incorrect merge.
400 incorrect merge.
401
401
402 .. container:: verbose
402 .. container:: verbose
403
403
404 By default, the pending changeset will have one parent,
404 By default, the pending changeset will have one parent,
405 maintaining a linear history. With --merge, the pending
405 maintaining a linear history. With --merge, the pending
406 changeset will instead have two parents: the old parent of the
406 changeset will instead have two parents: the old parent of the
407 working directory and a new child of REV that simply undoes REV.
407 working directory and a new child of REV that simply undoes REV.
408
408
409 Before version 1.7, the behavior without --merge was equivalent
409 Before version 1.7, the behavior without --merge was equivalent
410 to specifying --merge followed by :hg:`update --clean .` to
410 to specifying --merge followed by :hg:`update --clean .` to
411 cancel the merge and leave the child of REV as a head to be
411 cancel the merge and leave the child of REV as a head to be
412 merged separately.
412 merged separately.
413
413
414 See :hg:`help dates` for a list of formats valid for -d/--date.
414 See :hg:`help dates` for a list of formats valid for -d/--date.
415
415
416 Returns 0 on success.
416 Returns 0 on success.
417 '''
417 '''
418 if rev and node:
418 if rev and node:
419 raise util.Abort(_("please specify just one revision"))
419 raise util.Abort(_("please specify just one revision"))
420
420
421 if not rev:
421 if not rev:
422 rev = node
422 rev = node
423
423
424 if not rev:
424 if not rev:
425 raise util.Abort(_("please specify a revision to backout"))
425 raise util.Abort(_("please specify a revision to backout"))
426
426
427 date = opts.get('date')
427 date = opts.get('date')
428 if date:
428 if date:
429 opts['date'] = util.parsedate(date)
429 opts['date'] = util.parsedate(date)
430
430
431 cmdutil.bailifchanged(repo)
431 cmdutil.bailifchanged(repo)
432 node = scmutil.revsingle(repo, rev).node()
432 node = scmutil.revsingle(repo, rev).node()
433
433
434 op1, op2 = repo.dirstate.parents()
434 op1, op2 = repo.dirstate.parents()
435 a = repo.changelog.ancestor(op1, node)
435 a = repo.changelog.ancestor(op1, node)
436 if a != node:
436 if a != node:
437 raise util.Abort(_('cannot backout change on a different branch'))
437 raise util.Abort(_('cannot backout change on a different branch'))
438
438
439 p1, p2 = repo.changelog.parents(node)
439 p1, p2 = repo.changelog.parents(node)
440 if p1 == nullid:
440 if p1 == nullid:
441 raise util.Abort(_('cannot backout a change with no parents'))
441 raise util.Abort(_('cannot backout a change with no parents'))
442 if p2 != nullid:
442 if p2 != nullid:
443 if not opts.get('parent'):
443 if not opts.get('parent'):
444 raise util.Abort(_('cannot backout a merge changeset'))
444 raise util.Abort(_('cannot backout a merge changeset'))
445 p = repo.lookup(opts['parent'])
445 p = repo.lookup(opts['parent'])
446 if p not in (p1, p2):
446 if p not in (p1, p2):
447 raise util.Abort(_('%s is not a parent of %s') %
447 raise util.Abort(_('%s is not a parent of %s') %
448 (short(p), short(node)))
448 (short(p), short(node)))
449 parent = p
449 parent = p
450 else:
450 else:
451 if opts.get('parent'):
451 if opts.get('parent'):
452 raise util.Abort(_('cannot use --parent on non-merge changeset'))
452 raise util.Abort(_('cannot use --parent on non-merge changeset'))
453 parent = p1
453 parent = p1
454
454
455 # the backout should appear on the same branch
455 # the backout should appear on the same branch
456 wlock = repo.wlock()
456 wlock = repo.wlock()
457 try:
457 try:
458 branch = repo.dirstate.branch()
458 branch = repo.dirstate.branch()
459 bheads = repo.branchheads(branch)
459 bheads = repo.branchheads(branch)
460 hg.clean(repo, node, show_stats=False)
460 hg.clean(repo, node, show_stats=False)
461 repo.dirstate.setbranch(branch)
461 repo.dirstate.setbranch(branch)
462 rctx = scmutil.revsingle(repo, hex(parent))
462 rctx = scmutil.revsingle(repo, hex(parent))
463 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
463 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
464 if not opts.get('merge') and op1 != node:
464 if not opts.get('merge') and op1 != node:
465 try:
465 try:
466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
467 return hg.update(repo, op1)
467 return hg.update(repo, op1)
468 finally:
468 finally:
469 ui.setconfig('ui', 'forcemerge', '')
469 ui.setconfig('ui', 'forcemerge', '')
470
470
471 e = cmdutil.commiteditor
471 e = cmdutil.commiteditor
472 if not opts['message'] and not opts['logfile']:
472 if not opts['message'] and not opts['logfile']:
473 # we don't translate commit messages
473 # we don't translate commit messages
474 opts['message'] = "Backed out changeset %s" % short(node)
474 opts['message'] = "Backed out changeset %s" % short(node)
475 e = cmdutil.commitforceeditor
475 e = cmdutil.commitforceeditor
476
476
477 def commitfunc(ui, repo, message, match, opts):
477 def commitfunc(ui, repo, message, match, opts):
478 return repo.commit(message, opts.get('user'), opts.get('date'),
478 return repo.commit(message, opts.get('user'), opts.get('date'),
479 match, editor=e)
479 match, editor=e)
480 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
480 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
481 cmdutil.commitstatus(repo, newnode, branch, bheads)
481 cmdutil.commitstatus(repo, newnode, branch, bheads)
482
482
483 def nice(node):
483 def nice(node):
484 return '%d:%s' % (repo.changelog.rev(node), short(node))
484 return '%d:%s' % (repo.changelog.rev(node), short(node))
485 ui.status(_('changeset %s backs out changeset %s\n') %
485 ui.status(_('changeset %s backs out changeset %s\n') %
486 (nice(repo.changelog.tip()), nice(node)))
486 (nice(repo.changelog.tip()), nice(node)))
487 if opts.get('merge') and op1 != node:
487 if opts.get('merge') and op1 != node:
488 hg.clean(repo, op1, show_stats=False)
488 hg.clean(repo, op1, show_stats=False)
489 ui.status(_('merging with changeset %s\n')
489 ui.status(_('merging with changeset %s\n')
490 % nice(repo.changelog.tip()))
490 % nice(repo.changelog.tip()))
491 try:
491 try:
492 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
492 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
493 return hg.merge(repo, hex(repo.changelog.tip()))
493 return hg.merge(repo, hex(repo.changelog.tip()))
494 finally:
494 finally:
495 ui.setconfig('ui', 'forcemerge', '')
495 ui.setconfig('ui', 'forcemerge', '')
496 finally:
496 finally:
497 wlock.release()
497 wlock.release()
498 return 0
498 return 0
499
499
500 @command('bisect',
500 @command('bisect',
501 [('r', 'reset', False, _('reset bisect state')),
501 [('r', 'reset', False, _('reset bisect state')),
502 ('g', 'good', False, _('mark changeset good')),
502 ('g', 'good', False, _('mark changeset good')),
503 ('b', 'bad', False, _('mark changeset bad')),
503 ('b', 'bad', False, _('mark changeset bad')),
504 ('s', 'skip', False, _('skip testing changeset')),
504 ('s', 'skip', False, _('skip testing changeset')),
505 ('e', 'extend', False, _('extend the bisect range')),
505 ('e', 'extend', False, _('extend the bisect range')),
506 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
506 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
507 ('U', 'noupdate', False, _('do not update to target'))],
507 ('U', 'noupdate', False, _('do not update to target'))],
508 _("[-gbsr] [-U] [-c CMD] [REV]"))
508 _("[-gbsr] [-U] [-c CMD] [REV]"))
509 def bisect(ui, repo, rev=None, extra=None, command=None,
509 def bisect(ui, repo, rev=None, extra=None, command=None,
510 reset=None, good=None, bad=None, skip=None, extend=None,
510 reset=None, good=None, bad=None, skip=None, extend=None,
511 noupdate=None):
511 noupdate=None):
512 """subdivision search of changesets
512 """subdivision search of changesets
513
513
514 This command helps to find changesets which introduce problems. To
514 This command helps to find changesets which introduce problems. To
515 use, mark the earliest changeset you know exhibits the problem as
515 use, mark the earliest changeset you know exhibits the problem as
516 bad, then mark the latest changeset which is free from the problem
516 bad, then mark the latest changeset which is free from the problem
517 as good. Bisect will update your working directory to a revision
517 as good. Bisect will update your working directory to a revision
518 for testing (unless the -U/--noupdate option is specified). Once
518 for testing (unless the -U/--noupdate option is specified). Once
519 you have performed tests, mark the working directory as good or
519 you have performed tests, mark the working directory as good or
520 bad, and bisect will either update to another candidate changeset
520 bad, and bisect will either update to another candidate changeset
521 or announce that it has found the bad revision.
521 or announce that it has found the bad revision.
522
522
523 As a shortcut, you can also use the revision argument to mark a
523 As a shortcut, you can also use the revision argument to mark a
524 revision as good or bad without checking it out first.
524 revision as good or bad without checking it out first.
525
525
526 If you supply a command, it will be used for automatic bisection.
526 If you supply a command, it will be used for automatic bisection.
527 The environment variable HG_NODE will contain the ID of the
527 The environment variable HG_NODE will contain the ID of the
528 changeset being tested. The exit status of the command will be
528 changeset being tested. The exit status of the command will be
529 used to mark revisions as good or bad: status 0 means good, 125
529 used to mark revisions as good or bad: status 0 means good, 125
530 means to skip the revision, 127 (command not found) will abort the
530 means to skip the revision, 127 (command not found) will abort the
531 bisection, and any other non-zero exit status means the revision
531 bisection, and any other non-zero exit status means the revision
532 is bad.
532 is bad.
533
533
534 .. container:: verbose
534 .. container:: verbose
535
535
536 Some examples:
536 Some examples:
537
537
538 - start a bisection with known bad revision 12, and good revision 34::
538 - start a bisection with known bad revision 12, and good revision 34::
539
539
540 hg bisect --bad 34
540 hg bisect --bad 34
541 hg bisect --good 12
541 hg bisect --good 12
542
542
543 - advance the current bisection by marking current revision as good or
543 - advance the current bisection by marking current revision as good or
544 bad::
544 bad::
545
545
546 hg bisect --good
546 hg bisect --good
547 hg bisect --bad
547 hg bisect --bad
548
548
549 - mark the current revision, or a known revision, to be skipped (e.g. if
549 - mark the current revision, or a known revision, to be skipped (e.g. if
550 that revision is not usable because of another issue)::
550 that revision is not usable because of another issue)::
551
551
552 hg bisect --skip
552 hg bisect --skip
553 hg bisect --skip 23
553 hg bisect --skip 23
554
554
555 - skip all revisions that do not touch directories ``foo`` or ``bar``
555 - skip all revisions that do not touch directories ``foo`` or ``bar``
556
556
557 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
557 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
558
558
559 - forget the current bisection::
559 - forget the current bisection::
560
560
561 hg bisect --reset
561 hg bisect --reset
562
562
563 - use 'make && make tests' to automatically find the first broken
563 - use 'make && make tests' to automatically find the first broken
564 revision::
564 revision::
565
565
566 hg bisect --reset
566 hg bisect --reset
567 hg bisect --bad 34
567 hg bisect --bad 34
568 hg bisect --good 12
568 hg bisect --good 12
569 hg bisect --command 'make && make tests'
569 hg bisect --command 'make && make tests'
570
570
571 - see all changesets whose states are already known in the current
571 - see all changesets whose states are already known in the current
572 bisection::
572 bisection::
573
573
574 hg log -r "bisect(pruned)"
574 hg log -r "bisect(pruned)"
575
575
576 - see the changeset currently being bisected (especially useful
576 - see the changeset currently being bisected (especially useful
577 if running with -U/--noupdate)::
577 if running with -U/--noupdate)::
578
578
579 hg log -r "bisect(current)"
579 hg log -r "bisect(current)"
580
580
581 - see all changesets that took part in the current bisection::
581 - see all changesets that took part in the current bisection::
582
582
583 hg log -r "bisect(range)"
583 hg log -r "bisect(range)"
584
584
585 - with the graphlog extension, you can even get a nice graph::
585 - with the graphlog extension, you can even get a nice graph::
586
586
587 hg log --graph -r "bisect(range)"
587 hg log --graph -r "bisect(range)"
588
588
589 See :hg:`help revsets` for more about the `bisect()` keyword.
589 See :hg:`help revsets` for more about the `bisect()` keyword.
590
590
591 Returns 0 on success.
591 Returns 0 on success.
592 """
592 """
593 def extendbisectrange(nodes, good):
593 def extendbisectrange(nodes, good):
594 # bisect is incomplete when it ends on a merge node and
594 # bisect is incomplete when it ends on a merge node and
595 # one of the parent was not checked.
595 # one of the parent was not checked.
596 parents = repo[nodes[0]].parents()
596 parents = repo[nodes[0]].parents()
597 if len(parents) > 1:
597 if len(parents) > 1:
598 side = good and state['bad'] or state['good']
598 side = good and state['bad'] or state['good']
599 num = len(set(i.node() for i in parents) & set(side))
599 num = len(set(i.node() for i in parents) & set(side))
600 if num == 1:
600 if num == 1:
601 return parents[0].ancestor(parents[1])
601 return parents[0].ancestor(parents[1])
602 return None
602 return None
603
603
604 def print_result(nodes, good):
604 def print_result(nodes, good):
605 displayer = cmdutil.show_changeset(ui, repo, {})
605 displayer = cmdutil.show_changeset(ui, repo, {})
606 if len(nodes) == 1:
606 if len(nodes) == 1:
607 # narrowed it down to a single revision
607 # narrowed it down to a single revision
608 if good:
608 if good:
609 ui.write(_("The first good revision is:\n"))
609 ui.write(_("The first good revision is:\n"))
610 else:
610 else:
611 ui.write(_("The first bad revision is:\n"))
611 ui.write(_("The first bad revision is:\n"))
612 displayer.show(repo[nodes[0]])
612 displayer.show(repo[nodes[0]])
613 extendnode = extendbisectrange(nodes, good)
613 extendnode = extendbisectrange(nodes, good)
614 if extendnode is not None:
614 if extendnode is not None:
615 ui.write(_('Not all ancestors of this changeset have been'
615 ui.write(_('Not all ancestors of this changeset have been'
616 ' checked.\nUse bisect --extend to continue the '
616 ' checked.\nUse bisect --extend to continue the '
617 'bisection from\nthe common ancestor, %s.\n')
617 'bisection from\nthe common ancestor, %s.\n')
618 % extendnode)
618 % extendnode)
619 else:
619 else:
620 # multiple possible revisions
620 # multiple possible revisions
621 if good:
621 if good:
622 ui.write(_("Due to skipped revisions, the first "
622 ui.write(_("Due to skipped revisions, the first "
623 "good revision could be any of:\n"))
623 "good revision could be any of:\n"))
624 else:
624 else:
625 ui.write(_("Due to skipped revisions, the first "
625 ui.write(_("Due to skipped revisions, the first "
626 "bad revision could be any of:\n"))
626 "bad revision could be any of:\n"))
627 for n in nodes:
627 for n in nodes:
628 displayer.show(repo[n])
628 displayer.show(repo[n])
629 displayer.close()
629 displayer.close()
630
630
631 def check_state(state, interactive=True):
631 def check_state(state, interactive=True):
632 if not state['good'] or not state['bad']:
632 if not state['good'] or not state['bad']:
633 if (good or bad or skip or reset) and interactive:
633 if (good or bad or skip or reset) and interactive:
634 return
634 return
635 if not state['good']:
635 if not state['good']:
636 raise util.Abort(_('cannot bisect (no known good revisions)'))
636 raise util.Abort(_('cannot bisect (no known good revisions)'))
637 else:
637 else:
638 raise util.Abort(_('cannot bisect (no known bad revisions)'))
638 raise util.Abort(_('cannot bisect (no known bad revisions)'))
639 return True
639 return True
640
640
641 # backward compatibility
641 # backward compatibility
642 if rev in "good bad reset init".split():
642 if rev in "good bad reset init".split():
643 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
643 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
644 cmd, rev, extra = rev, extra, None
644 cmd, rev, extra = rev, extra, None
645 if cmd == "good":
645 if cmd == "good":
646 good = True
646 good = True
647 elif cmd == "bad":
647 elif cmd == "bad":
648 bad = True
648 bad = True
649 else:
649 else:
650 reset = True
650 reset = True
651 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
651 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
652 raise util.Abort(_('incompatible arguments'))
652 raise util.Abort(_('incompatible arguments'))
653
653
654 if reset:
654 if reset:
655 p = repo.join("bisect.state")
655 p = repo.join("bisect.state")
656 if os.path.exists(p):
656 if os.path.exists(p):
657 os.unlink(p)
657 os.unlink(p)
658 return
658 return
659
659
660 state = hbisect.load_state(repo)
660 state = hbisect.load_state(repo)
661
661
662 if command:
662 if command:
663 changesets = 1
663 changesets = 1
664 try:
664 try:
665 node = state['current'][0]
665 node = state['current'][0]
666 except LookupError:
666 except LookupError:
667 if noupdate:
667 if noupdate:
668 raise util.Abort(_('current bisect revision is unknown - '
668 raise util.Abort(_('current bisect revision is unknown - '
669 'start a new bisect to fix'))
669 'start a new bisect to fix'))
670 node, p2 = repo.dirstate.parents()
670 node, p2 = repo.dirstate.parents()
671 if p2 != nullid:
671 if p2 != nullid:
672 raise util.Abort(_('current bisect revision is a merge'))
672 raise util.Abort(_('current bisect revision is a merge'))
673 try:
673 try:
674 while changesets:
674 while changesets:
675 # update state
675 # update state
676 state['current'] = [node]
676 state['current'] = [node]
677 hbisect.save_state(repo, state)
677 hbisect.save_state(repo, state)
678 status = util.system(command,
678 status = util.system(command,
679 environ={'HG_NODE': hex(node)},
679 environ={'HG_NODE': hex(node)},
680 out=ui.fout)
680 out=ui.fout)
681 if status == 125:
681 if status == 125:
682 transition = "skip"
682 transition = "skip"
683 elif status == 0:
683 elif status == 0:
684 transition = "good"
684 transition = "good"
685 # status < 0 means process was killed
685 # status < 0 means process was killed
686 elif status == 127:
686 elif status == 127:
687 raise util.Abort(_("failed to execute %s") % command)
687 raise util.Abort(_("failed to execute %s") % command)
688 elif status < 0:
688 elif status < 0:
689 raise util.Abort(_("%s killed") % command)
689 raise util.Abort(_("%s killed") % command)
690 else:
690 else:
691 transition = "bad"
691 transition = "bad"
692 ctx = scmutil.revsingle(repo, rev, node)
692 ctx = scmutil.revsingle(repo, rev, node)
693 rev = None # clear for future iterations
693 rev = None # clear for future iterations
694 state[transition].append(ctx.node())
694 state[transition].append(ctx.node())
695 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
695 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
696 check_state(state, interactive=False)
696 check_state(state, interactive=False)
697 # bisect
697 # bisect
698 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
698 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
699 # update to next check
699 # update to next check
700 node = nodes[0]
700 node = nodes[0]
701 if not noupdate:
701 if not noupdate:
702 cmdutil.bailifchanged(repo)
702 cmdutil.bailifchanged(repo)
703 hg.clean(repo, node, show_stats=False)
703 hg.clean(repo, node, show_stats=False)
704 finally:
704 finally:
705 state['current'] = [node]
705 state['current'] = [node]
706 hbisect.save_state(repo, state)
706 hbisect.save_state(repo, state)
707 print_result(nodes, good)
707 print_result(nodes, good)
708 return
708 return
709
709
710 # update state
710 # update state
711
711
712 if rev:
712 if rev:
713 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
713 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
714 else:
714 else:
715 nodes = [repo.lookup('.')]
715 nodes = [repo.lookup('.')]
716
716
717 if good or bad or skip:
717 if good or bad or skip:
718 if good:
718 if good:
719 state['good'] += nodes
719 state['good'] += nodes
720 elif bad:
720 elif bad:
721 state['bad'] += nodes
721 state['bad'] += nodes
722 elif skip:
722 elif skip:
723 state['skip'] += nodes
723 state['skip'] += nodes
724 hbisect.save_state(repo, state)
724 hbisect.save_state(repo, state)
725
725
726 if not check_state(state):
726 if not check_state(state):
727 return
727 return
728
728
729 # actually bisect
729 # actually bisect
730 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
730 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
731 if extend:
731 if extend:
732 if not changesets:
732 if not changesets:
733 extendnode = extendbisectrange(nodes, good)
733 extendnode = extendbisectrange(nodes, good)
734 if extendnode is not None:
734 if extendnode is not None:
735 ui.write(_("Extending search to changeset %d:%s\n"
735 ui.write(_("Extending search to changeset %d:%s\n"
736 % (extendnode.rev(), extendnode)))
736 % (extendnode.rev(), extendnode)))
737 state['current'] = [extendnode.node()]
737 state['current'] = [extendnode.node()]
738 hbisect.save_state(repo, state)
738 hbisect.save_state(repo, state)
739 if noupdate:
739 if noupdate:
740 return
740 return
741 cmdutil.bailifchanged(repo)
741 cmdutil.bailifchanged(repo)
742 return hg.clean(repo, extendnode.node())
742 return hg.clean(repo, extendnode.node())
743 raise util.Abort(_("nothing to extend"))
743 raise util.Abort(_("nothing to extend"))
744
744
745 if changesets == 0:
745 if changesets == 0:
746 print_result(nodes, good)
746 print_result(nodes, good)
747 else:
747 else:
748 assert len(nodes) == 1 # only a single node can be tested next
748 assert len(nodes) == 1 # only a single node can be tested next
749 node = nodes[0]
749 node = nodes[0]
750 # compute the approximate number of remaining tests
750 # compute the approximate number of remaining tests
751 tests, size = 0, 2
751 tests, size = 0, 2
752 while size <= changesets:
752 while size <= changesets:
753 tests, size = tests + 1, size * 2
753 tests, size = tests + 1, size * 2
754 rev = repo.changelog.rev(node)
754 rev = repo.changelog.rev(node)
755 ui.write(_("Testing changeset %d:%s "
755 ui.write(_("Testing changeset %d:%s "
756 "(%d changesets remaining, ~%d tests)\n")
756 "(%d changesets remaining, ~%d tests)\n")
757 % (rev, short(node), changesets, tests))
757 % (rev, short(node), changesets, tests))
758 state['current'] = [node]
758 state['current'] = [node]
759 hbisect.save_state(repo, state)
759 hbisect.save_state(repo, state)
760 if not noupdate:
760 if not noupdate:
761 cmdutil.bailifchanged(repo)
761 cmdutil.bailifchanged(repo)
762 return hg.clean(repo, node)
762 return hg.clean(repo, node)
763
763
764 @command('bookmarks|bookmark',
764 @command('bookmarks|bookmark',
765 [('f', 'force', False, _('force')),
765 [('f', 'force', False, _('force')),
766 ('r', 'rev', '', _('revision'), _('REV')),
766 ('r', 'rev', '', _('revision'), _('REV')),
767 ('d', 'delete', False, _('delete a given bookmark')),
767 ('d', 'delete', False, _('delete a given bookmark')),
768 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
768 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
769 ('i', 'inactive', False, _('mark a bookmark inactive'))],
769 ('i', 'inactive', False, _('mark a bookmark inactive'))],
770 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
770 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
771 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
771 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
772 rename=None, inactive=False):
772 rename=None, inactive=False):
773 '''track a line of development with movable markers
773 '''track a line of development with movable markers
774
774
775 Bookmarks are pointers to certain commits that move when committing.
775 Bookmarks are pointers to certain commits that move when committing.
776 Bookmarks are local. They can be renamed, copied and deleted. It is
776 Bookmarks are local. They can be renamed, copied and deleted. It is
777 possible to use :hg:`merge NAME` to merge from a given bookmark, and
777 possible to use :hg:`merge NAME` to merge from a given bookmark, and
778 :hg:`update NAME` to update to a given bookmark.
778 :hg:`update NAME` to update to a given bookmark.
779
779
780 You can use :hg:`bookmark NAME` to set a bookmark on the working
780 You can use :hg:`bookmark NAME` to set a bookmark on the working
781 directory's parent revision with the given name. If you specify
781 directory's parent revision with the given name. If you specify
782 a revision using -r REV (where REV may be an existing bookmark),
782 a revision using -r REV (where REV may be an existing bookmark),
783 the bookmark is assigned to that revision.
783 the bookmark is assigned to that revision.
784
784
785 Bookmarks can be pushed and pulled between repositories (see :hg:`help
785 Bookmarks can be pushed and pulled between repositories (see :hg:`help
786 push` and :hg:`help pull`). This requires both the local and remote
786 push` and :hg:`help pull`). This requires both the local and remote
787 repositories to support bookmarks. For versions prior to 1.8, this means
787 repositories to support bookmarks. For versions prior to 1.8, this means
788 the bookmarks extension must be enabled.
788 the bookmarks extension must be enabled.
789
789
790 If you set a bookmark called '@', new clones of the repository will
790 If you set a bookmark called '@', new clones of the repository will
791 have that revision checked out (and the bookmark made active) by
791 have that revision checked out (and the bookmark made active) by
792 default.
792 default.
793
793
794 With -i/--inactive, the new bookmark will not be made the active
794 With -i/--inactive, the new bookmark will not be made the active
795 bookmark. If -r/--rev is given, the new bookmark will not be made
795 bookmark. If -r/--rev is given, the new bookmark will not be made
796 active even if -i/--inactive is not given. If no NAME is given, the
796 active even if -i/--inactive is not given. If no NAME is given, the
797 current active bookmark will be marked inactive.
797 current active bookmark will be marked inactive.
798 '''
798 '''
799 hexfn = ui.debugflag and hex or short
799 hexfn = ui.debugflag and hex or short
800 marks = repo._bookmarks
800 marks = repo._bookmarks
801 cur = repo.changectx('.').node()
801 cur = repo.changectx('.').node()
802
802
803 def checkformat(mark):
803 def checkformat(mark):
804 mark = mark.strip()
804 mark = mark.strip()
805 if not mark:
805 if not mark:
806 raise util.Abort(_("bookmark names cannot consist entirely of "
806 raise util.Abort(_("bookmark names cannot consist entirely of "
807 "whitespace"))
807 "whitespace"))
808 scmutil.checknewlabel(repo, mark, 'bookmark')
808 scmutil.checknewlabel(repo, mark, 'bookmark')
809 return mark
809 return mark
810
810
811 def checkconflict(repo, mark, force=False):
811 def checkconflict(repo, mark, force=False):
812 if mark in marks and not force:
812 if mark in marks and not force:
813 raise util.Abort(_("bookmark '%s' already exists "
813 raise util.Abort(_("bookmark '%s' already exists "
814 "(use -f to force)") % mark)
814 "(use -f to force)") % mark)
815 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
815 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
816 and not force):
816 and not force):
817 raise util.Abort(
817 raise util.Abort(
818 _("a bookmark cannot have the name of an existing branch"))
818 _("a bookmark cannot have the name of an existing branch"))
819
819
820 if delete and rename:
820 if delete and rename:
821 raise util.Abort(_("--delete and --rename are incompatible"))
821 raise util.Abort(_("--delete and --rename are incompatible"))
822 if delete and rev:
822 if delete and rev:
823 raise util.Abort(_("--rev is incompatible with --delete"))
823 raise util.Abort(_("--rev is incompatible with --delete"))
824 if rename and rev:
824 if rename and rev:
825 raise util.Abort(_("--rev is incompatible with --rename"))
825 raise util.Abort(_("--rev is incompatible with --rename"))
826 if mark is None and (delete or rev):
826 if mark is None and (delete or rev):
827 raise util.Abort(_("bookmark name required"))
827 raise util.Abort(_("bookmark name required"))
828
828
829 if delete:
829 if delete:
830 if mark not in marks:
830 if mark not in marks:
831 raise util.Abort(_("bookmark '%s' does not exist") % mark)
831 raise util.Abort(_("bookmark '%s' does not exist") % mark)
832 if mark == repo._bookmarkcurrent:
832 if mark == repo._bookmarkcurrent:
833 bookmarks.setcurrent(repo, None)
833 bookmarks.setcurrent(repo, None)
834 del marks[mark]
834 del marks[mark]
835 marks.write()
835 marks.write()
836
836
837 elif rename:
837 elif rename:
838 if mark is None:
838 if mark is None:
839 raise util.Abort(_("new bookmark name required"))
839 raise util.Abort(_("new bookmark name required"))
840 mark = checkformat(mark)
840 mark = checkformat(mark)
841 if rename not in marks:
841 if rename not in marks:
842 raise util.Abort(_("bookmark '%s' does not exist") % rename)
842 raise util.Abort(_("bookmark '%s' does not exist") % rename)
843 checkconflict(repo, mark, force)
843 checkconflict(repo, mark, force)
844 marks[mark] = marks[rename]
844 marks[mark] = marks[rename]
845 if repo._bookmarkcurrent == rename and not inactive:
845 if repo._bookmarkcurrent == rename and not inactive:
846 bookmarks.setcurrent(repo, mark)
846 bookmarks.setcurrent(repo, mark)
847 del marks[rename]
847 del marks[rename]
848 marks.write()
848 marks.write()
849
849
850 elif mark is not None:
850 elif mark is not None:
851 mark = checkformat(mark)
851 mark = checkformat(mark)
852 if inactive and mark == repo._bookmarkcurrent:
852 if inactive and mark == repo._bookmarkcurrent:
853 bookmarks.setcurrent(repo, None)
853 bookmarks.setcurrent(repo, None)
854 return
854 return
855 checkconflict(repo, mark, force)
855 checkconflict(repo, mark, force)
856 if rev:
856 if rev:
857 marks[mark] = scmutil.revsingle(repo, rev).node()
857 marks[mark] = scmutil.revsingle(repo, rev).node()
858 else:
858 else:
859 marks[mark] = cur
859 marks[mark] = cur
860 if not inactive and cur == marks[mark]:
860 if not inactive and cur == marks[mark]:
861 bookmarks.setcurrent(repo, mark)
861 bookmarks.setcurrent(repo, mark)
862 marks.write()
862 marks.write()
863
863
864 # Same message whether trying to deactivate the current bookmark (-i
864 # Same message whether trying to deactivate the current bookmark (-i
865 # with no NAME) or listing bookmarks
865 # with no NAME) or listing bookmarks
866 elif len(marks) == 0:
866 elif len(marks) == 0:
867 ui.status(_("no bookmarks set\n"))
867 ui.status(_("no bookmarks set\n"))
868
868
869 elif inactive:
869 elif inactive:
870 if not repo._bookmarkcurrent:
870 if not repo._bookmarkcurrent:
871 ui.status(_("no active bookmark\n"))
871 ui.status(_("no active bookmark\n"))
872 else:
872 else:
873 bookmarks.setcurrent(repo, None)
873 bookmarks.setcurrent(repo, None)
874
874
875 else: # show bookmarks
875 else: # show bookmarks
876 for bmark, n in sorted(marks.iteritems()):
876 for bmark, n in sorted(marks.iteritems()):
877 current = repo._bookmarkcurrent
877 current = repo._bookmarkcurrent
878 if bmark == current:
878 if bmark == current:
879 prefix, label = '*', 'bookmarks.current'
879 prefix, label = '*', 'bookmarks.current'
880 else:
880 else:
881 prefix, label = ' ', ''
881 prefix, label = ' ', ''
882
882
883 if ui.quiet:
883 if ui.quiet:
884 ui.write("%s\n" % bmark, label=label)
884 ui.write("%s\n" % bmark, label=label)
885 else:
885 else:
886 ui.write(" %s %-25s %d:%s\n" % (
886 ui.write(" %s %-25s %d:%s\n" % (
887 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
887 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
888 label=label)
888 label=label)
889
889
890 @command('branch',
890 @command('branch',
891 [('f', 'force', None,
891 [('f', 'force', None,
892 _('set branch name even if it shadows an existing branch')),
892 _('set branch name even if it shadows an existing branch')),
893 ('C', 'clean', None, _('reset branch name to parent branch name'))],
893 ('C', 'clean', None, _('reset branch name to parent branch name'))],
894 _('[-fC] [NAME]'))
894 _('[-fC] [NAME]'))
895 def branch(ui, repo, label=None, **opts):
895 def branch(ui, repo, label=None, **opts):
896 """set or show the current branch name
896 """set or show the current branch name
897
897
898 .. note::
898 .. note::
899 Branch names are permanent and global. Use :hg:`bookmark` to create a
899 Branch names are permanent and global. Use :hg:`bookmark` to create a
900 light-weight bookmark instead. See :hg:`help glossary` for more
900 light-weight bookmark instead. See :hg:`help glossary` for more
901 information about named branches and bookmarks.
901 information about named branches and bookmarks.
902
902
903 With no argument, show the current branch name. With one argument,
903 With no argument, show the current branch name. With one argument,
904 set the working directory branch name (the branch will not exist
904 set the working directory branch name (the branch will not exist
905 in the repository until the next commit). Standard practice
905 in the repository until the next commit). Standard practice
906 recommends that primary development take place on the 'default'
906 recommends that primary development take place on the 'default'
907 branch.
907 branch.
908
908
909 Unless -f/--force is specified, branch will not let you set a
909 Unless -f/--force is specified, branch will not let you set a
910 branch name that already exists, even if it's inactive.
910 branch name that already exists, even if it's inactive.
911
911
912 Use -C/--clean to reset the working directory branch to that of
912 Use -C/--clean to reset the working directory branch to that of
913 the parent of the working directory, negating a previous branch
913 the parent of the working directory, negating a previous branch
914 change.
914 change.
915
915
916 Use the command :hg:`update` to switch to an existing branch. Use
916 Use the command :hg:`update` to switch to an existing branch. Use
917 :hg:`commit --close-branch` to mark this branch as closed.
917 :hg:`commit --close-branch` to mark this branch as closed.
918
918
919 Returns 0 on success.
919 Returns 0 on success.
920 """
920 """
921 if not opts.get('clean') and not label:
921 if not opts.get('clean') and not label:
922 ui.write("%s\n" % repo.dirstate.branch())
922 ui.write("%s\n" % repo.dirstate.branch())
923 return
923 return
924
924
925 wlock = repo.wlock()
925 wlock = repo.wlock()
926 try:
926 try:
927 if opts.get('clean'):
927 if opts.get('clean'):
928 label = repo[None].p1().branch()
928 label = repo[None].p1().branch()
929 repo.dirstate.setbranch(label)
929 repo.dirstate.setbranch(label)
930 ui.status(_('reset working directory to branch %s\n') % label)
930 ui.status(_('reset working directory to branch %s\n') % label)
931 elif label:
931 elif label:
932 if not opts.get('force') and label in repo.branchmap():
932 if not opts.get('force') and label in repo.branchmap():
933 if label not in [p.branch() for p in repo.parents()]:
933 if label not in [p.branch() for p in repo.parents()]:
934 raise util.Abort(_('a branch of the same name already'
934 raise util.Abort(_('a branch of the same name already'
935 ' exists'),
935 ' exists'),
936 # i18n: "it" refers to an existing branch
936 # i18n: "it" refers to an existing branch
937 hint=_("use 'hg update' to switch to it"))
937 hint=_("use 'hg update' to switch to it"))
938 scmutil.checknewlabel(repo, label, 'branch')
938 scmutil.checknewlabel(repo, label, 'branch')
939 repo.dirstate.setbranch(label)
939 repo.dirstate.setbranch(label)
940 ui.status(_('marked working directory as branch %s\n') % label)
940 ui.status(_('marked working directory as branch %s\n') % label)
941 ui.status(_('(branches are permanent and global, '
941 ui.status(_('(branches are permanent and global, '
942 'did you want a bookmark?)\n'))
942 'did you want a bookmark?)\n'))
943 finally:
943 finally:
944 wlock.release()
944 wlock.release()
945
945
946 @command('branches',
946 @command('branches',
947 [('a', 'active', False, _('show only branches that have unmerged heads')),
947 [('a', 'active', False, _('show only branches that have unmerged heads')),
948 ('c', 'closed', False, _('show normal and closed branches'))],
948 ('c', 'closed', False, _('show normal and closed branches'))],
949 _('[-ac]'))
949 _('[-ac]'))
950 def branches(ui, repo, active=False, closed=False):
950 def branches(ui, repo, active=False, closed=False):
951 """list repository named branches
951 """list repository named branches
952
952
953 List the repository's named branches, indicating which ones are
953 List the repository's named branches, indicating which ones are
954 inactive. If -c/--closed is specified, also list branches which have
954 inactive. If -c/--closed is specified, also list branches which have
955 been marked closed (see :hg:`commit --close-branch`).
955 been marked closed (see :hg:`commit --close-branch`).
956
956
957 If -a/--active is specified, only show active branches. A branch
957 If -a/--active is specified, only show active branches. A branch
958 is considered active if it contains repository heads.
958 is considered active if it contains repository heads.
959
959
960 Use the command :hg:`update` to switch to an existing branch.
960 Use the command :hg:`update` to switch to an existing branch.
961
961
962 Returns 0.
962 Returns 0.
963 """
963 """
964
964
965 hexfunc = ui.debugflag and hex or short
965 hexfunc = ui.debugflag and hex or short
966
966
967 activebranches = set([repo[n].branch() for n in repo.heads()])
967 activebranches = set([repo[n].branch() for n in repo.heads()])
968 branches = []
968 branches = []
969 for tag, heads in repo.branchmap().iteritems():
969 for tag, heads in repo.branchmap().iteritems():
970 for h in reversed(heads):
970 for h in reversed(heads):
971 ctx = repo[h]
971 ctx = repo[h]
972 isopen = not ctx.closesbranch()
972 isopen = not ctx.closesbranch()
973 if isopen:
973 if isopen:
974 tip = ctx
974 tip = ctx
975 break
975 break
976 else:
976 else:
977 tip = repo[heads[-1]]
977 tip = repo[heads[-1]]
978 isactive = tag in activebranches and isopen
978 isactive = tag in activebranches and isopen
979 branches.append((tip, isactive, isopen))
979 branches.append((tip, isactive, isopen))
980 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
980 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
981 reverse=True)
981 reverse=True)
982
982
983 for ctx, isactive, isopen in branches:
983 for ctx, isactive, isopen in branches:
984 if (not active) or isactive:
984 if (not active) or isactive:
985 if isactive:
985 if isactive:
986 label = 'branches.active'
986 label = 'branches.active'
987 notice = ''
987 notice = ''
988 elif not isopen:
988 elif not isopen:
989 if not closed:
989 if not closed:
990 continue
990 continue
991 label = 'branches.closed'
991 label = 'branches.closed'
992 notice = _(' (closed)')
992 notice = _(' (closed)')
993 else:
993 else:
994 label = 'branches.inactive'
994 label = 'branches.inactive'
995 notice = _(' (inactive)')
995 notice = _(' (inactive)')
996 if ctx.branch() == repo.dirstate.branch():
996 if ctx.branch() == repo.dirstate.branch():
997 label = 'branches.current'
997 label = 'branches.current'
998 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
998 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
999 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
999 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1000 'log.changeset changeset.%s' % ctx.phasestr())
1000 'log.changeset changeset.%s' % ctx.phasestr())
1001 tag = ui.label(ctx.branch(), label)
1001 tag = ui.label(ctx.branch(), label)
1002 if ui.quiet:
1002 if ui.quiet:
1003 ui.write("%s\n" % tag)
1003 ui.write("%s\n" % tag)
1004 else:
1004 else:
1005 ui.write("%s %s%s\n" % (tag, rev, notice))
1005 ui.write("%s %s%s\n" % (tag, rev, notice))
1006
1006
1007 @command('bundle',
1007 @command('bundle',
1008 [('f', 'force', None, _('run even when the destination is unrelated')),
1008 [('f', 'force', None, _('run even when the destination is unrelated')),
1009 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1009 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1010 _('REV')),
1010 _('REV')),
1011 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1011 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1012 _('BRANCH')),
1012 _('BRANCH')),
1013 ('', 'base', [],
1013 ('', 'base', [],
1014 _('a base changeset assumed to be available at the destination'),
1014 _('a base changeset assumed to be available at the destination'),
1015 _('REV')),
1015 _('REV')),
1016 ('a', 'all', None, _('bundle all changesets in the repository')),
1016 ('a', 'all', None, _('bundle all changesets in the repository')),
1017 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1017 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1018 ] + remoteopts,
1018 ] + remoteopts,
1019 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1019 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1020 def bundle(ui, repo, fname, dest=None, **opts):
1020 def bundle(ui, repo, fname, dest=None, **opts):
1021 """create a changegroup file
1021 """create a changegroup file
1022
1022
1023 Generate a compressed changegroup file collecting changesets not
1023 Generate a compressed changegroup file collecting changesets not
1024 known to be in another repository.
1024 known to be in another repository.
1025
1025
1026 If you omit the destination repository, then hg assumes the
1026 If you omit the destination repository, then hg assumes the
1027 destination will have all the nodes you specify with --base
1027 destination will have all the nodes you specify with --base
1028 parameters. To create a bundle containing all changesets, use
1028 parameters. To create a bundle containing all changesets, use
1029 -a/--all (or --base null).
1029 -a/--all (or --base null).
1030
1030
1031 You can change compression method with the -t/--type option.
1031 You can change compression method with the -t/--type option.
1032 The available compression methods are: none, bzip2, and
1032 The available compression methods are: none, bzip2, and
1033 gzip (by default, bundles are compressed using bzip2).
1033 gzip (by default, bundles are compressed using bzip2).
1034
1034
1035 The bundle file can then be transferred using conventional means
1035 The bundle file can then be transferred using conventional means
1036 and applied to another repository with the unbundle or pull
1036 and applied to another repository with the unbundle or pull
1037 command. This is useful when direct push and pull are not
1037 command. This is useful when direct push and pull are not
1038 available or when exporting an entire repository is undesirable.
1038 available or when exporting an entire repository is undesirable.
1039
1039
1040 Applying bundles preserves all changeset contents including
1040 Applying bundles preserves all changeset contents including
1041 permissions, copy/rename information, and revision history.
1041 permissions, copy/rename information, and revision history.
1042
1042
1043 Returns 0 on success, 1 if no changes found.
1043 Returns 0 on success, 1 if no changes found.
1044 """
1044 """
1045 revs = None
1045 revs = None
1046 if 'rev' in opts:
1046 if 'rev' in opts:
1047 revs = scmutil.revrange(repo, opts['rev'])
1047 revs = scmutil.revrange(repo, opts['rev'])
1048
1048
1049 bundletype = opts.get('type', 'bzip2').lower()
1049 bundletype = opts.get('type', 'bzip2').lower()
1050 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1050 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1051 bundletype = btypes.get(bundletype)
1051 bundletype = btypes.get(bundletype)
1052 if bundletype not in changegroup.bundletypes:
1052 if bundletype not in changegroup.bundletypes:
1053 raise util.Abort(_('unknown bundle type specified with --type'))
1053 raise util.Abort(_('unknown bundle type specified with --type'))
1054
1054
1055 if opts.get('all'):
1055 if opts.get('all'):
1056 base = ['null']
1056 base = ['null']
1057 else:
1057 else:
1058 base = scmutil.revrange(repo, opts.get('base'))
1058 base = scmutil.revrange(repo, opts.get('base'))
1059 if base:
1059 if base:
1060 if dest:
1060 if dest:
1061 raise util.Abort(_("--base is incompatible with specifying "
1061 raise util.Abort(_("--base is incompatible with specifying "
1062 "a destination"))
1062 "a destination"))
1063 common = [repo.lookup(rev) for rev in base]
1063 common = [repo.lookup(rev) for rev in base]
1064 heads = revs and map(repo.lookup, revs) or revs
1064 heads = revs and map(repo.lookup, revs) or revs
1065 cg = repo.getbundle('bundle', heads=heads, common=common)
1065 cg = repo.getbundle('bundle', heads=heads, common=common)
1066 outgoing = None
1066 outgoing = None
1067 else:
1067 else:
1068 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1068 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1069 dest, branches = hg.parseurl(dest, opts.get('branch'))
1069 dest, branches = hg.parseurl(dest, opts.get('branch'))
1070 other = hg.peer(repo, opts, dest)
1070 other = hg.peer(repo, opts, dest)
1071 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1071 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1072 heads = revs and map(repo.lookup, revs) or revs
1072 heads = revs and map(repo.lookup, revs) or revs
1073 outgoing = discovery.findcommonoutgoing(repo, other,
1073 outgoing = discovery.findcommonoutgoing(repo, other,
1074 onlyheads=heads,
1074 onlyheads=heads,
1075 force=opts.get('force'),
1075 force=opts.get('force'),
1076 portable=True)
1076 portable=True)
1077 cg = repo.getlocalbundle('bundle', outgoing)
1077 cg = repo.getlocalbundle('bundle', outgoing)
1078 if not cg:
1078 if not cg:
1079 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1079 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1080 return 1
1080 return 1
1081
1081
1082 changegroup.writebundle(cg, fname, bundletype)
1082 changegroup.writebundle(cg, fname, bundletype)
1083
1083
1084 @command('cat',
1084 @command('cat',
1085 [('o', 'output', '',
1085 [('o', 'output', '',
1086 _('print output to file with formatted name'), _('FORMAT')),
1086 _('print output to file with formatted name'), _('FORMAT')),
1087 ('r', 'rev', '', _('print the given revision'), _('REV')),
1087 ('r', 'rev', '', _('print the given revision'), _('REV')),
1088 ('', 'decode', None, _('apply any matching decode filter')),
1088 ('', 'decode', None, _('apply any matching decode filter')),
1089 ] + walkopts,
1089 ] + walkopts,
1090 _('[OPTION]... FILE...'))
1090 _('[OPTION]... FILE...'))
1091 def cat(ui, repo, file1, *pats, **opts):
1091 def cat(ui, repo, file1, *pats, **opts):
1092 """output the current or given revision of files
1092 """output the current or given revision of files
1093
1093
1094 Print the specified files as they were at the given revision. If
1094 Print the specified files as they were at the given revision. If
1095 no revision is given, the parent of the working directory is used,
1095 no revision is given, the parent of the working directory is used,
1096 or tip if no revision is checked out.
1096 or tip if no revision is checked out.
1097
1097
1098 Output may be to a file, in which case the name of the file is
1098 Output may be to a file, in which case the name of the file is
1099 given using a format string. The formatting rules are the same as
1099 given using a format string. The formatting rules are the same as
1100 for the export command, with the following additions:
1100 for the export command, with the following additions:
1101
1101
1102 :``%s``: basename of file being printed
1102 :``%s``: basename of file being printed
1103 :``%d``: dirname of file being printed, or '.' if in repository root
1103 :``%d``: dirname of file being printed, or '.' if in repository root
1104 :``%p``: root-relative path name of file being printed
1104 :``%p``: root-relative path name of file being printed
1105
1105
1106 Returns 0 on success.
1106 Returns 0 on success.
1107 """
1107 """
1108 ctx = scmutil.revsingle(repo, opts.get('rev'))
1108 ctx = scmutil.revsingle(repo, opts.get('rev'))
1109 err = 1
1109 err = 1
1110 m = scmutil.match(ctx, (file1,) + pats, opts)
1110 m = scmutil.match(ctx, (file1,) + pats, opts)
1111 for abs in ctx.walk(m):
1111 for abs in ctx.walk(m):
1112 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1112 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1113 pathname=abs)
1113 pathname=abs)
1114 data = ctx[abs].data()
1114 data = ctx[abs].data()
1115 if opts.get('decode'):
1115 if opts.get('decode'):
1116 data = repo.wwritedata(abs, data)
1116 data = repo.wwritedata(abs, data)
1117 fp.write(data)
1117 fp.write(data)
1118 fp.close()
1118 fp.close()
1119 err = 0
1119 err = 0
1120 return err
1120 return err
1121
1121
1122 @command('^clone',
1122 @command('^clone',
1123 [('U', 'noupdate', None,
1123 [('U', 'noupdate', None,
1124 _('the clone will include an empty working copy (only a repository)')),
1124 _('the clone will include an empty working copy (only a repository)')),
1125 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1125 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1126 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1126 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1127 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1127 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1128 ('', 'pull', None, _('use pull protocol to copy metadata')),
1128 ('', 'pull', None, _('use pull protocol to copy metadata')),
1129 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1129 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1130 ] + remoteopts,
1130 ] + remoteopts,
1131 _('[OPTION]... SOURCE [DEST]'))
1131 _('[OPTION]... SOURCE [DEST]'))
1132 def clone(ui, source, dest=None, **opts):
1132 def clone(ui, source, dest=None, **opts):
1133 """make a copy of an existing repository
1133 """make a copy of an existing repository
1134
1134
1135 Create a copy of an existing repository in a new directory.
1135 Create a copy of an existing repository in a new directory.
1136
1136
1137 If no destination directory name is specified, it defaults to the
1137 If no destination directory name is specified, it defaults to the
1138 basename of the source.
1138 basename of the source.
1139
1139
1140 The location of the source is added to the new repository's
1140 The location of the source is added to the new repository's
1141 ``.hg/hgrc`` file, as the default to be used for future pulls.
1141 ``.hg/hgrc`` file, as the default to be used for future pulls.
1142
1142
1143 Only local paths and ``ssh://`` URLs are supported as
1143 Only local paths and ``ssh://`` URLs are supported as
1144 destinations. For ``ssh://`` destinations, no working directory or
1144 destinations. For ``ssh://`` destinations, no working directory or
1145 ``.hg/hgrc`` will be created on the remote side.
1145 ``.hg/hgrc`` will be created on the remote side.
1146
1146
1147 To pull only a subset of changesets, specify one or more revisions
1147 To pull only a subset of changesets, specify one or more revisions
1148 identifiers with -r/--rev or branches with -b/--branch. The
1148 identifiers with -r/--rev or branches with -b/--branch. The
1149 resulting clone will contain only the specified changesets and
1149 resulting clone will contain only the specified changesets and
1150 their ancestors. These options (or 'clone src#rev dest') imply
1150 their ancestors. These options (or 'clone src#rev dest') imply
1151 --pull, even for local source repositories. Note that specifying a
1151 --pull, even for local source repositories. Note that specifying a
1152 tag will include the tagged changeset but not the changeset
1152 tag will include the tagged changeset but not the changeset
1153 containing the tag.
1153 containing the tag.
1154
1154
1155 If the source repository has a bookmark called '@' set, that
1155 If the source repository has a bookmark called '@' set, that
1156 revision will be checked out in the new repository by default.
1156 revision will be checked out in the new repository by default.
1157
1157
1158 To check out a particular version, use -u/--update, or
1158 To check out a particular version, use -u/--update, or
1159 -U/--noupdate to create a clone with no working directory.
1159 -U/--noupdate to create a clone with no working directory.
1160
1160
1161 .. container:: verbose
1161 .. container:: verbose
1162
1162
1163 For efficiency, hardlinks are used for cloning whenever the
1163 For efficiency, hardlinks are used for cloning whenever the
1164 source and destination are on the same filesystem (note this
1164 source and destination are on the same filesystem (note this
1165 applies only to the repository data, not to the working
1165 applies only to the repository data, not to the working
1166 directory). Some filesystems, such as AFS, implement hardlinking
1166 directory). Some filesystems, such as AFS, implement hardlinking
1167 incorrectly, but do not report errors. In these cases, use the
1167 incorrectly, but do not report errors. In these cases, use the
1168 --pull option to avoid hardlinking.
1168 --pull option to avoid hardlinking.
1169
1169
1170 In some cases, you can clone repositories and the working
1170 In some cases, you can clone repositories and the working
1171 directory using full hardlinks with ::
1171 directory using full hardlinks with ::
1172
1172
1173 $ cp -al REPO REPOCLONE
1173 $ cp -al REPO REPOCLONE
1174
1174
1175 This is the fastest way to clone, but it is not always safe. The
1175 This is the fastest way to clone, but it is not always safe. The
1176 operation is not atomic (making sure REPO is not modified during
1176 operation is not atomic (making sure REPO is not modified during
1177 the operation is up to you) and you have to make sure your
1177 the operation is up to you) and you have to make sure your
1178 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1178 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1179 so). Also, this is not compatible with certain extensions that
1179 so). Also, this is not compatible with certain extensions that
1180 place their metadata under the .hg directory, such as mq.
1180 place their metadata under the .hg directory, such as mq.
1181
1181
1182 Mercurial will update the working directory to the first applicable
1182 Mercurial will update the working directory to the first applicable
1183 revision from this list:
1183 revision from this list:
1184
1184
1185 a) null if -U or the source repository has no changesets
1185 a) null if -U or the source repository has no changesets
1186 b) if -u . and the source repository is local, the first parent of
1186 b) if -u . and the source repository is local, the first parent of
1187 the source repository's working directory
1187 the source repository's working directory
1188 c) the changeset specified with -u (if a branch name, this means the
1188 c) the changeset specified with -u (if a branch name, this means the
1189 latest head of that branch)
1189 latest head of that branch)
1190 d) the changeset specified with -r
1190 d) the changeset specified with -r
1191 e) the tipmost head specified with -b
1191 e) the tipmost head specified with -b
1192 f) the tipmost head specified with the url#branch source syntax
1192 f) the tipmost head specified with the url#branch source syntax
1193 g) the revision marked with the '@' bookmark, if present
1193 g) the revision marked with the '@' bookmark, if present
1194 h) the tipmost head of the default branch
1194 h) the tipmost head of the default branch
1195 i) tip
1195 i) tip
1196
1196
1197 Examples:
1197 Examples:
1198
1198
1199 - clone a remote repository to a new directory named hg/::
1199 - clone a remote repository to a new directory named hg/::
1200
1200
1201 hg clone http://selenic.com/hg
1201 hg clone http://selenic.com/hg
1202
1202
1203 - create a lightweight local clone::
1203 - create a lightweight local clone::
1204
1204
1205 hg clone project/ project-feature/
1205 hg clone project/ project-feature/
1206
1206
1207 - clone from an absolute path on an ssh server (note double-slash)::
1207 - clone from an absolute path on an ssh server (note double-slash)::
1208
1208
1209 hg clone ssh://user@server//home/projects/alpha/
1209 hg clone ssh://user@server//home/projects/alpha/
1210
1210
1211 - do a high-speed clone over a LAN while checking out a
1211 - do a high-speed clone over a LAN while checking out a
1212 specified version::
1212 specified version::
1213
1213
1214 hg clone --uncompressed http://server/repo -u 1.5
1214 hg clone --uncompressed http://server/repo -u 1.5
1215
1215
1216 - create a repository without changesets after a particular revision::
1216 - create a repository without changesets after a particular revision::
1217
1217
1218 hg clone -r 04e544 experimental/ good/
1218 hg clone -r 04e544 experimental/ good/
1219
1219
1220 - clone (and track) a particular named branch::
1220 - clone (and track) a particular named branch::
1221
1221
1222 hg clone http://selenic.com/hg#stable
1222 hg clone http://selenic.com/hg#stable
1223
1223
1224 See :hg:`help urls` for details on specifying URLs.
1224 See :hg:`help urls` for details on specifying URLs.
1225
1225
1226 Returns 0 on success.
1226 Returns 0 on success.
1227 """
1227 """
1228 if opts.get('noupdate') and opts.get('updaterev'):
1228 if opts.get('noupdate') and opts.get('updaterev'):
1229 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1229 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1230
1230
1231 r = hg.clone(ui, opts, source, dest,
1231 r = hg.clone(ui, opts, source, dest,
1232 pull=opts.get('pull'),
1232 pull=opts.get('pull'),
1233 stream=opts.get('uncompressed'),
1233 stream=opts.get('uncompressed'),
1234 rev=opts.get('rev'),
1234 rev=opts.get('rev'),
1235 update=opts.get('updaterev') or not opts.get('noupdate'),
1235 update=opts.get('updaterev') or not opts.get('noupdate'),
1236 branch=opts.get('branch'))
1236 branch=opts.get('branch'))
1237
1237
1238 return r is None
1238 return r is None
1239
1239
1240 @command('^commit|ci',
1240 @command('^commit|ci',
1241 [('A', 'addremove', None,
1241 [('A', 'addremove', None,
1242 _('mark new/missing files as added/removed before committing')),
1242 _('mark new/missing files as added/removed before committing')),
1243 ('', 'close-branch', None,
1243 ('', 'close-branch', None,
1244 _('mark a branch as closed, hiding it from the branch list')),
1244 _('mark a branch as closed, hiding it from the branch list')),
1245 ('', 'amend', None, _('amend the parent of the working dir')),
1245 ('', 'amend', None, _('amend the parent of the working dir')),
1246 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1246 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1247 _('[OPTION]... [FILE]...'))
1247 _('[OPTION]... [FILE]...'))
1248 def commit(ui, repo, *pats, **opts):
1248 def commit(ui, repo, *pats, **opts):
1249 """commit the specified files or all outstanding changes
1249 """commit the specified files or all outstanding changes
1250
1250
1251 Commit changes to the given files into the repository. Unlike a
1251 Commit changes to the given files into the repository. Unlike a
1252 centralized SCM, this operation is a local operation. See
1252 centralized SCM, this operation is a local operation. See
1253 :hg:`push` for a way to actively distribute your changes.
1253 :hg:`push` for a way to actively distribute your changes.
1254
1254
1255 If a list of files is omitted, all changes reported by :hg:`status`
1255 If a list of files is omitted, all changes reported by :hg:`status`
1256 will be committed.
1256 will be committed.
1257
1257
1258 If you are committing the result of a merge, do not provide any
1258 If you are committing the result of a merge, do not provide any
1259 filenames or -I/-X filters.
1259 filenames or -I/-X filters.
1260
1260
1261 If no commit message is specified, Mercurial starts your
1261 If no commit message is specified, Mercurial starts your
1262 configured editor where you can enter a message. In case your
1262 configured editor where you can enter a message. In case your
1263 commit fails, you will find a backup of your message in
1263 commit fails, you will find a backup of your message in
1264 ``.hg/last-message.txt``.
1264 ``.hg/last-message.txt``.
1265
1265
1266 The --amend flag can be used to amend the parent of the
1266 The --amend flag can be used to amend the parent of the
1267 working directory with a new commit that contains the changes
1267 working directory with a new commit that contains the changes
1268 in the parent in addition to those currently reported by :hg:`status`,
1268 in the parent in addition to those currently reported by :hg:`status`,
1269 if there are any. The old commit is stored in a backup bundle in
1269 if there are any. The old commit is stored in a backup bundle in
1270 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1270 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1271 on how to restore it).
1271 on how to restore it).
1272
1272
1273 Message, user and date are taken from the amended commit unless
1273 Message, user and date are taken from the amended commit unless
1274 specified. When a message isn't specified on the command line,
1274 specified. When a message isn't specified on the command line,
1275 the editor will open with the message of the amended commit.
1275 the editor will open with the message of the amended commit.
1276
1276
1277 It is not possible to amend public changesets (see :hg:`help phases`)
1277 It is not possible to amend public changesets (see :hg:`help phases`)
1278 or changesets that have children.
1278 or changesets that have children.
1279
1279
1280 See :hg:`help dates` for a list of formats valid for -d/--date.
1280 See :hg:`help dates` for a list of formats valid for -d/--date.
1281
1281
1282 Returns 0 on success, 1 if nothing changed.
1282 Returns 0 on success, 1 if nothing changed.
1283 """
1283 """
1284 if opts.get('subrepos'):
1284 if opts.get('subrepos'):
1285 # Let --subrepos on the command line override config setting.
1285 # Let --subrepos on the command line override config setting.
1286 ui.setconfig('ui', 'commitsubrepos', True)
1286 ui.setconfig('ui', 'commitsubrepos', True)
1287
1287
1288 extra = {}
1288 extra = {}
1289 if opts.get('close_branch'):
1289 if opts.get('close_branch'):
1290 if repo['.'].node() not in repo.branchheads():
1290 if repo['.'].node() not in repo.branchheads():
1291 # The topo heads set is included in the branch heads set of the
1291 # The topo heads set is included in the branch heads set of the
1292 # current branch, so it's sufficient to test branchheads
1292 # current branch, so it's sufficient to test branchheads
1293 raise util.Abort(_('can only close branch heads'))
1293 raise util.Abort(_('can only close branch heads'))
1294 extra['close'] = 1
1294 extra['close'] = 1
1295
1295
1296 branch = repo[None].branch()
1296 branch = repo[None].branch()
1297 bheads = repo.branchheads(branch)
1297 bheads = repo.branchheads(branch)
1298
1298
1299 if opts.get('amend'):
1299 if opts.get('amend'):
1300 if ui.configbool('ui', 'commitsubrepos'):
1300 if ui.configbool('ui', 'commitsubrepos'):
1301 raise util.Abort(_('cannot amend recursively'))
1301 raise util.Abort(_('cannot amend recursively'))
1302
1302
1303 old = repo['.']
1303 old = repo['.']
1304 if old.phase() == phases.public:
1304 if old.phase() == phases.public:
1305 raise util.Abort(_('cannot amend public changesets'))
1305 raise util.Abort(_('cannot amend public changesets'))
1306 if len(old.parents()) > 1:
1306 if len(old.parents()) > 1:
1307 raise util.Abort(_('cannot amend merge changesets'))
1307 raise util.Abort(_('cannot amend merge changesets'))
1308 if len(repo[None].parents()) > 1:
1308 if len(repo[None].parents()) > 1:
1309 raise util.Abort(_('cannot amend while merging'))
1309 raise util.Abort(_('cannot amend while merging'))
1310 if (not obsolete._enabled) and old.children():
1310 if (not obsolete._enabled) and old.children():
1311 raise util.Abort(_('cannot amend changeset with children'))
1311 raise util.Abort(_('cannot amend changeset with children'))
1312
1312
1313 e = cmdutil.commiteditor
1313 e = cmdutil.commiteditor
1314 if opts.get('force_editor'):
1314 if opts.get('force_editor'):
1315 e = cmdutil.commitforceeditor
1315 e = cmdutil.commitforceeditor
1316
1316
1317 def commitfunc(ui, repo, message, match, opts):
1317 def commitfunc(ui, repo, message, match, opts):
1318 editor = e
1318 editor = e
1319 # message contains text from -m or -l, if it's empty,
1319 # message contains text from -m or -l, if it's empty,
1320 # open the editor with the old message
1320 # open the editor with the old message
1321 if not message:
1321 if not message:
1322 message = old.description()
1322 message = old.description()
1323 editor = cmdutil.commitforceeditor
1323 editor = cmdutil.commitforceeditor
1324 return repo.commit(message,
1324 return repo.commit(message,
1325 opts.get('user') or old.user(),
1325 opts.get('user') or old.user(),
1326 opts.get('date') or old.date(),
1326 opts.get('date') or old.date(),
1327 match,
1327 match,
1328 editor=editor,
1328 editor=editor,
1329 extra=extra)
1329 extra=extra)
1330
1330
1331 current = repo._bookmarkcurrent
1331 current = repo._bookmarkcurrent
1332 marks = old.bookmarks()
1332 marks = old.bookmarks()
1333 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1333 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1334 if node == old.node():
1334 if node == old.node():
1335 ui.status(_("nothing changed\n"))
1335 ui.status(_("nothing changed\n"))
1336 return 1
1336 return 1
1337 elif marks:
1337 elif marks:
1338 ui.debug('moving bookmarks %r from %s to %s\n' %
1338 ui.debug('moving bookmarks %r from %s to %s\n' %
1339 (marks, old.hex(), hex(node)))
1339 (marks, old.hex(), hex(node)))
1340 newmarks = repo._bookmarks
1340 newmarks = repo._bookmarks
1341 for bm in marks:
1341 for bm in marks:
1342 newmarks[bm] = node
1342 newmarks[bm] = node
1343 if bm == current:
1343 if bm == current:
1344 bookmarks.setcurrent(repo, bm)
1344 bookmarks.setcurrent(repo, bm)
1345 newmarks.write()
1345 newmarks.write()
1346 else:
1346 else:
1347 e = cmdutil.commiteditor
1347 e = cmdutil.commiteditor
1348 if opts.get('force_editor'):
1348 if opts.get('force_editor'):
1349 e = cmdutil.commitforceeditor
1349 e = cmdutil.commitforceeditor
1350
1350
1351 def commitfunc(ui, repo, message, match, opts):
1351 def commitfunc(ui, repo, message, match, opts):
1352 return repo.commit(message, opts.get('user'), opts.get('date'),
1352 return repo.commit(message, opts.get('user'), opts.get('date'),
1353 match, editor=e, extra=extra)
1353 match, editor=e, extra=extra)
1354
1354
1355 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1355 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1356
1356
1357 if not node:
1357 if not node:
1358 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1358 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1359 if stat[3]:
1359 if stat[3]:
1360 ui.status(_("nothing changed (%d missing files, see "
1360 ui.status(_("nothing changed (%d missing files, see "
1361 "'hg status')\n") % len(stat[3]))
1361 "'hg status')\n") % len(stat[3]))
1362 else:
1362 else:
1363 ui.status(_("nothing changed\n"))
1363 ui.status(_("nothing changed\n"))
1364 return 1
1364 return 1
1365
1365
1366 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1366 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1367
1367
1368 @command('copy|cp',
1368 @command('copy|cp',
1369 [('A', 'after', None, _('record a copy that has already occurred')),
1369 [('A', 'after', None, _('record a copy that has already occurred')),
1370 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1370 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1371 ] + walkopts + dryrunopts,
1371 ] + walkopts + dryrunopts,
1372 _('[OPTION]... [SOURCE]... DEST'))
1372 _('[OPTION]... [SOURCE]... DEST'))
1373 def copy(ui, repo, *pats, **opts):
1373 def copy(ui, repo, *pats, **opts):
1374 """mark files as copied for the next commit
1374 """mark files as copied for the next commit
1375
1375
1376 Mark dest as having copies of source files. If dest is a
1376 Mark dest as having copies of source files. If dest is a
1377 directory, copies are put in that directory. If dest is a file,
1377 directory, copies are put in that directory. If dest is a file,
1378 the source must be a single file.
1378 the source must be a single file.
1379
1379
1380 By default, this command copies the contents of files as they
1380 By default, this command copies the contents of files as they
1381 exist in the working directory. If invoked with -A/--after, the
1381 exist in the working directory. If invoked with -A/--after, the
1382 operation is recorded, but no copying is performed.
1382 operation is recorded, but no copying is performed.
1383
1383
1384 This command takes effect with the next commit. To undo a copy
1384 This command takes effect with the next commit. To undo a copy
1385 before that, see :hg:`revert`.
1385 before that, see :hg:`revert`.
1386
1386
1387 Returns 0 on success, 1 if errors are encountered.
1387 Returns 0 on success, 1 if errors are encountered.
1388 """
1388 """
1389 wlock = repo.wlock(False)
1389 wlock = repo.wlock(False)
1390 try:
1390 try:
1391 return cmdutil.copy(ui, repo, pats, opts)
1391 return cmdutil.copy(ui, repo, pats, opts)
1392 finally:
1392 finally:
1393 wlock.release()
1393 wlock.release()
1394
1394
1395 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1395 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1396 def debugancestor(ui, repo, *args):
1396 def debugancestor(ui, repo, *args):
1397 """find the ancestor revision of two revisions in a given index"""
1397 """find the ancestor revision of two revisions in a given index"""
1398 if len(args) == 3:
1398 if len(args) == 3:
1399 index, rev1, rev2 = args
1399 index, rev1, rev2 = args
1400 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1400 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1401 lookup = r.lookup
1401 lookup = r.lookup
1402 elif len(args) == 2:
1402 elif len(args) == 2:
1403 if not repo:
1403 if not repo:
1404 raise util.Abort(_("there is no Mercurial repository here "
1404 raise util.Abort(_("there is no Mercurial repository here "
1405 "(.hg not found)"))
1405 "(.hg not found)"))
1406 rev1, rev2 = args
1406 rev1, rev2 = args
1407 r = repo.changelog
1407 r = repo.changelog
1408 lookup = repo.lookup
1408 lookup = repo.lookup
1409 else:
1409 else:
1410 raise util.Abort(_('either two or three arguments required'))
1410 raise util.Abort(_('either two or three arguments required'))
1411 a = r.ancestor(lookup(rev1), lookup(rev2))
1411 a = r.ancestor(lookup(rev1), lookup(rev2))
1412 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1412 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1413
1413
1414 @command('debugbuilddag',
1414 @command('debugbuilddag',
1415 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1415 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1416 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1416 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1417 ('n', 'new-file', None, _('add new file at each rev'))],
1417 ('n', 'new-file', None, _('add new file at each rev'))],
1418 _('[OPTION]... [TEXT]'))
1418 _('[OPTION]... [TEXT]'))
1419 def debugbuilddag(ui, repo, text=None,
1419 def debugbuilddag(ui, repo, text=None,
1420 mergeable_file=False,
1420 mergeable_file=False,
1421 overwritten_file=False,
1421 overwritten_file=False,
1422 new_file=False):
1422 new_file=False):
1423 """builds a repo with a given DAG from scratch in the current empty repo
1423 """builds a repo with a given DAG from scratch in the current empty repo
1424
1424
1425 The description of the DAG is read from stdin if not given on the
1425 The description of the DAG is read from stdin if not given on the
1426 command line.
1426 command line.
1427
1427
1428 Elements:
1428 Elements:
1429
1429
1430 - "+n" is a linear run of n nodes based on the current default parent
1430 - "+n" is a linear run of n nodes based on the current default parent
1431 - "." is a single node based on the current default parent
1431 - "." is a single node based on the current default parent
1432 - "$" resets the default parent to null (implied at the start);
1432 - "$" resets the default parent to null (implied at the start);
1433 otherwise the default parent is always the last node created
1433 otherwise the default parent is always the last node created
1434 - "<p" sets the default parent to the backref p
1434 - "<p" sets the default parent to the backref p
1435 - "*p" is a fork at parent p, which is a backref
1435 - "*p" is a fork at parent p, which is a backref
1436 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1436 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1437 - "/p2" is a merge of the preceding node and p2
1437 - "/p2" is a merge of the preceding node and p2
1438 - ":tag" defines a local tag for the preceding node
1438 - ":tag" defines a local tag for the preceding node
1439 - "@branch" sets the named branch for subsequent nodes
1439 - "@branch" sets the named branch for subsequent nodes
1440 - "#...\\n" is a comment up to the end of the line
1440 - "#...\\n" is a comment up to the end of the line
1441
1441
1442 Whitespace between the above elements is ignored.
1442 Whitespace between the above elements is ignored.
1443
1443
1444 A backref is either
1444 A backref is either
1445
1445
1446 - a number n, which references the node curr-n, where curr is the current
1446 - a number n, which references the node curr-n, where curr is the current
1447 node, or
1447 node, or
1448 - the name of a local tag you placed earlier using ":tag", or
1448 - the name of a local tag you placed earlier using ":tag", or
1449 - empty to denote the default parent.
1449 - empty to denote the default parent.
1450
1450
1451 All string valued-elements are either strictly alphanumeric, or must
1451 All string valued-elements are either strictly alphanumeric, or must
1452 be enclosed in double quotes ("..."), with "\\" as escape character.
1452 be enclosed in double quotes ("..."), with "\\" as escape character.
1453 """
1453 """
1454
1454
1455 if text is None:
1455 if text is None:
1456 ui.status(_("reading DAG from stdin\n"))
1456 ui.status(_("reading DAG from stdin\n"))
1457 text = ui.fin.read()
1457 text = ui.fin.read()
1458
1458
1459 cl = repo.changelog
1459 cl = repo.changelog
1460 if len(cl) > 0:
1460 if len(cl) > 0:
1461 raise util.Abort(_('repository is not empty'))
1461 raise util.Abort(_('repository is not empty'))
1462
1462
1463 # determine number of revs in DAG
1463 # determine number of revs in DAG
1464 total = 0
1464 total = 0
1465 for type, data in dagparser.parsedag(text):
1465 for type, data in dagparser.parsedag(text):
1466 if type == 'n':
1466 if type == 'n':
1467 total += 1
1467 total += 1
1468
1468
1469 if mergeable_file:
1469 if mergeable_file:
1470 linesperrev = 2
1470 linesperrev = 2
1471 # make a file with k lines per rev
1471 # make a file with k lines per rev
1472 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1472 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1473 initialmergedlines.append("")
1473 initialmergedlines.append("")
1474
1474
1475 tags = []
1475 tags = []
1476
1476
1477 lock = tr = None
1477 lock = tr = None
1478 try:
1478 try:
1479 lock = repo.lock()
1479 lock = repo.lock()
1480 tr = repo.transaction("builddag")
1480 tr = repo.transaction("builddag")
1481
1481
1482 at = -1
1482 at = -1
1483 atbranch = 'default'
1483 atbranch = 'default'
1484 nodeids = []
1484 nodeids = []
1485 id = 0
1485 id = 0
1486 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1486 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1487 for type, data in dagparser.parsedag(text):
1487 for type, data in dagparser.parsedag(text):
1488 if type == 'n':
1488 if type == 'n':
1489 ui.note(('node %s\n' % str(data)))
1489 ui.note(('node %s\n' % str(data)))
1490 id, ps = data
1490 id, ps = data
1491
1491
1492 files = []
1492 files = []
1493 fctxs = {}
1493 fctxs = {}
1494
1494
1495 p2 = None
1495 p2 = None
1496 if mergeable_file:
1496 if mergeable_file:
1497 fn = "mf"
1497 fn = "mf"
1498 p1 = repo[ps[0]]
1498 p1 = repo[ps[0]]
1499 if len(ps) > 1:
1499 if len(ps) > 1:
1500 p2 = repo[ps[1]]
1500 p2 = repo[ps[1]]
1501 pa = p1.ancestor(p2)
1501 pa = p1.ancestor(p2)
1502 base, local, other = [x[fn].data() for x in (pa, p1,
1502 base, local, other = [x[fn].data() for x in (pa, p1,
1503 p2)]
1503 p2)]
1504 m3 = simplemerge.Merge3Text(base, local, other)
1504 m3 = simplemerge.Merge3Text(base, local, other)
1505 ml = [l.strip() for l in m3.merge_lines()]
1505 ml = [l.strip() for l in m3.merge_lines()]
1506 ml.append("")
1506 ml.append("")
1507 elif at > 0:
1507 elif at > 0:
1508 ml = p1[fn].data().split("\n")
1508 ml = p1[fn].data().split("\n")
1509 else:
1509 else:
1510 ml = initialmergedlines
1510 ml = initialmergedlines
1511 ml[id * linesperrev] += " r%i" % id
1511 ml[id * linesperrev] += " r%i" % id
1512 mergedtext = "\n".join(ml)
1512 mergedtext = "\n".join(ml)
1513 files.append(fn)
1513 files.append(fn)
1514 fctxs[fn] = context.memfilectx(fn, mergedtext)
1514 fctxs[fn] = context.memfilectx(fn, mergedtext)
1515
1515
1516 if overwritten_file:
1516 if overwritten_file:
1517 fn = "of"
1517 fn = "of"
1518 files.append(fn)
1518 files.append(fn)
1519 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1519 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1520
1520
1521 if new_file:
1521 if new_file:
1522 fn = "nf%i" % id
1522 fn = "nf%i" % id
1523 files.append(fn)
1523 files.append(fn)
1524 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1524 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1525 if len(ps) > 1:
1525 if len(ps) > 1:
1526 if not p2:
1526 if not p2:
1527 p2 = repo[ps[1]]
1527 p2 = repo[ps[1]]
1528 for fn in p2:
1528 for fn in p2:
1529 if fn.startswith("nf"):
1529 if fn.startswith("nf"):
1530 files.append(fn)
1530 files.append(fn)
1531 fctxs[fn] = p2[fn]
1531 fctxs[fn] = p2[fn]
1532
1532
1533 def fctxfn(repo, cx, path):
1533 def fctxfn(repo, cx, path):
1534 return fctxs.get(path)
1534 return fctxs.get(path)
1535
1535
1536 if len(ps) == 0 or ps[0] < 0:
1536 if len(ps) == 0 or ps[0] < 0:
1537 pars = [None, None]
1537 pars = [None, None]
1538 elif len(ps) == 1:
1538 elif len(ps) == 1:
1539 pars = [nodeids[ps[0]], None]
1539 pars = [nodeids[ps[0]], None]
1540 else:
1540 else:
1541 pars = [nodeids[p] for p in ps]
1541 pars = [nodeids[p] for p in ps]
1542 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1542 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1543 date=(id, 0),
1543 date=(id, 0),
1544 user="debugbuilddag",
1544 user="debugbuilddag",
1545 extra={'branch': atbranch})
1545 extra={'branch': atbranch})
1546 nodeid = repo.commitctx(cx)
1546 nodeid = repo.commitctx(cx)
1547 nodeids.append(nodeid)
1547 nodeids.append(nodeid)
1548 at = id
1548 at = id
1549 elif type == 'l':
1549 elif type == 'l':
1550 id, name = data
1550 id, name = data
1551 ui.note(('tag %s\n' % name))
1551 ui.note(('tag %s\n' % name))
1552 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1552 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1553 elif type == 'a':
1553 elif type == 'a':
1554 ui.note(('branch %s\n' % data))
1554 ui.note(('branch %s\n' % data))
1555 atbranch = data
1555 atbranch = data
1556 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1556 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1557 tr.close()
1557 tr.close()
1558
1558
1559 if tags:
1559 if tags:
1560 repo.opener.write("localtags", "".join(tags))
1560 repo.opener.write("localtags", "".join(tags))
1561 finally:
1561 finally:
1562 ui.progress(_('building'), None)
1562 ui.progress(_('building'), None)
1563 release(tr, lock)
1563 release(tr, lock)
1564
1564
1565 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1565 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1566 def debugbundle(ui, bundlepath, all=None, **opts):
1566 def debugbundle(ui, bundlepath, all=None, **opts):
1567 """lists the contents of a bundle"""
1567 """lists the contents of a bundle"""
1568 f = hg.openpath(ui, bundlepath)
1568 f = hg.openpath(ui, bundlepath)
1569 try:
1569 try:
1570 gen = changegroup.readbundle(f, bundlepath)
1570 gen = changegroup.readbundle(f, bundlepath)
1571 if all:
1571 if all:
1572 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1572 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1573
1573
1574 def showchunks(named):
1574 def showchunks(named):
1575 ui.write("\n%s\n" % named)
1575 ui.write("\n%s\n" % named)
1576 chain = None
1576 chain = None
1577 while True:
1577 while True:
1578 chunkdata = gen.deltachunk(chain)
1578 chunkdata = gen.deltachunk(chain)
1579 if not chunkdata:
1579 if not chunkdata:
1580 break
1580 break
1581 node = chunkdata['node']
1581 node = chunkdata['node']
1582 p1 = chunkdata['p1']
1582 p1 = chunkdata['p1']
1583 p2 = chunkdata['p2']
1583 p2 = chunkdata['p2']
1584 cs = chunkdata['cs']
1584 cs = chunkdata['cs']
1585 deltabase = chunkdata['deltabase']
1585 deltabase = chunkdata['deltabase']
1586 delta = chunkdata['delta']
1586 delta = chunkdata['delta']
1587 ui.write("%s %s %s %s %s %s\n" %
1587 ui.write("%s %s %s %s %s %s\n" %
1588 (hex(node), hex(p1), hex(p2),
1588 (hex(node), hex(p1), hex(p2),
1589 hex(cs), hex(deltabase), len(delta)))
1589 hex(cs), hex(deltabase), len(delta)))
1590 chain = node
1590 chain = node
1591
1591
1592 chunkdata = gen.changelogheader()
1592 chunkdata = gen.changelogheader()
1593 showchunks("changelog")
1593 showchunks("changelog")
1594 chunkdata = gen.manifestheader()
1594 chunkdata = gen.manifestheader()
1595 showchunks("manifest")
1595 showchunks("manifest")
1596 while True:
1596 while True:
1597 chunkdata = gen.filelogheader()
1597 chunkdata = gen.filelogheader()
1598 if not chunkdata:
1598 if not chunkdata:
1599 break
1599 break
1600 fname = chunkdata['filename']
1600 fname = chunkdata['filename']
1601 showchunks(fname)
1601 showchunks(fname)
1602 else:
1602 else:
1603 chunkdata = gen.changelogheader()
1603 chunkdata = gen.changelogheader()
1604 chain = None
1604 chain = None
1605 while True:
1605 while True:
1606 chunkdata = gen.deltachunk(chain)
1606 chunkdata = gen.deltachunk(chain)
1607 if not chunkdata:
1607 if not chunkdata:
1608 break
1608 break
1609 node = chunkdata['node']
1609 node = chunkdata['node']
1610 ui.write("%s\n" % hex(node))
1610 ui.write("%s\n" % hex(node))
1611 chain = node
1611 chain = node
1612 finally:
1612 finally:
1613 f.close()
1613 f.close()
1614
1614
1615 @command('debugcheckstate', [], '')
1615 @command('debugcheckstate', [], '')
1616 def debugcheckstate(ui, repo):
1616 def debugcheckstate(ui, repo):
1617 """validate the correctness of the current dirstate"""
1617 """validate the correctness of the current dirstate"""
1618 parent1, parent2 = repo.dirstate.parents()
1618 parent1, parent2 = repo.dirstate.parents()
1619 m1 = repo[parent1].manifest()
1619 m1 = repo[parent1].manifest()
1620 m2 = repo[parent2].manifest()
1620 m2 = repo[parent2].manifest()
1621 errors = 0
1621 errors = 0
1622 for f in repo.dirstate:
1622 for f in repo.dirstate:
1623 state = repo.dirstate[f]
1623 state = repo.dirstate[f]
1624 if state in "nr" and f not in m1:
1624 if state in "nr" and f not in m1:
1625 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1625 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1626 errors += 1
1626 errors += 1
1627 if state in "a" and f in m1:
1627 if state in "a" and f in m1:
1628 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1628 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1629 errors += 1
1629 errors += 1
1630 if state in "m" and f not in m1 and f not in m2:
1630 if state in "m" and f not in m1 and f not in m2:
1631 ui.warn(_("%s in state %s, but not in either manifest\n") %
1631 ui.warn(_("%s in state %s, but not in either manifest\n") %
1632 (f, state))
1632 (f, state))
1633 errors += 1
1633 errors += 1
1634 for f in m1:
1634 for f in m1:
1635 state = repo.dirstate[f]
1635 state = repo.dirstate[f]
1636 if state not in "nrm":
1636 if state not in "nrm":
1637 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1637 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1638 errors += 1
1638 errors += 1
1639 if errors:
1639 if errors:
1640 error = _(".hg/dirstate inconsistent with current parent's manifest")
1640 error = _(".hg/dirstate inconsistent with current parent's manifest")
1641 raise util.Abort(error)
1641 raise util.Abort(error)
1642
1642
1643 @command('debugcommands', [], _('[COMMAND]'))
1643 @command('debugcommands', [], _('[COMMAND]'))
1644 def debugcommands(ui, cmd='', *args):
1644 def debugcommands(ui, cmd='', *args):
1645 """list all available commands and options"""
1645 """list all available commands and options"""
1646 for cmd, vals in sorted(table.iteritems()):
1646 for cmd, vals in sorted(table.iteritems()):
1647 cmd = cmd.split('|')[0].strip('^')
1647 cmd = cmd.split('|')[0].strip('^')
1648 opts = ', '.join([i[1] for i in vals[1]])
1648 opts = ', '.join([i[1] for i in vals[1]])
1649 ui.write('%s: %s\n' % (cmd, opts))
1649 ui.write('%s: %s\n' % (cmd, opts))
1650
1650
1651 @command('debugcomplete',
1651 @command('debugcomplete',
1652 [('o', 'options', None, _('show the command options'))],
1652 [('o', 'options', None, _('show the command options'))],
1653 _('[-o] CMD'))
1653 _('[-o] CMD'))
1654 def debugcomplete(ui, cmd='', **opts):
1654 def debugcomplete(ui, cmd='', **opts):
1655 """returns the completion list associated with the given command"""
1655 """returns the completion list associated with the given command"""
1656
1656
1657 if opts.get('options'):
1657 if opts.get('options'):
1658 options = []
1658 options = []
1659 otables = [globalopts]
1659 otables = [globalopts]
1660 if cmd:
1660 if cmd:
1661 aliases, entry = cmdutil.findcmd(cmd, table, False)
1661 aliases, entry = cmdutil.findcmd(cmd, table, False)
1662 otables.append(entry[1])
1662 otables.append(entry[1])
1663 for t in otables:
1663 for t in otables:
1664 for o in t:
1664 for o in t:
1665 if "(DEPRECATED)" in o[3]:
1665 if "(DEPRECATED)" in o[3]:
1666 continue
1666 continue
1667 if o[0]:
1667 if o[0]:
1668 options.append('-%s' % o[0])
1668 options.append('-%s' % o[0])
1669 options.append('--%s' % o[1])
1669 options.append('--%s' % o[1])
1670 ui.write("%s\n" % "\n".join(options))
1670 ui.write("%s\n" % "\n".join(options))
1671 return
1671 return
1672
1672
1673 cmdlist = cmdutil.findpossible(cmd, table)
1673 cmdlist = cmdutil.findpossible(cmd, table)
1674 if ui.verbose:
1674 if ui.verbose:
1675 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1675 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1676 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1676 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1677
1677
1678 @command('debugdag',
1678 @command('debugdag',
1679 [('t', 'tags', None, _('use tags as labels')),
1679 [('t', 'tags', None, _('use tags as labels')),
1680 ('b', 'branches', None, _('annotate with branch names')),
1680 ('b', 'branches', None, _('annotate with branch names')),
1681 ('', 'dots', None, _('use dots for runs')),
1681 ('', 'dots', None, _('use dots for runs')),
1682 ('s', 'spaces', None, _('separate elements by spaces'))],
1682 ('s', 'spaces', None, _('separate elements by spaces'))],
1683 _('[OPTION]... [FILE [REV]...]'))
1683 _('[OPTION]... [FILE [REV]...]'))
1684 def debugdag(ui, repo, file_=None, *revs, **opts):
1684 def debugdag(ui, repo, file_=None, *revs, **opts):
1685 """format the changelog or an index DAG as a concise textual description
1685 """format the changelog or an index DAG as a concise textual description
1686
1686
1687 If you pass a revlog index, the revlog's DAG is emitted. If you list
1687 If you pass a revlog index, the revlog's DAG is emitted. If you list
1688 revision numbers, they get labeled in the output as rN.
1688 revision numbers, they get labeled in the output as rN.
1689
1689
1690 Otherwise, the changelog DAG of the current repo is emitted.
1690 Otherwise, the changelog DAG of the current repo is emitted.
1691 """
1691 """
1692 spaces = opts.get('spaces')
1692 spaces = opts.get('spaces')
1693 dots = opts.get('dots')
1693 dots = opts.get('dots')
1694 if file_:
1694 if file_:
1695 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1695 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1696 revs = set((int(r) for r in revs))
1696 revs = set((int(r) for r in revs))
1697 def events():
1697 def events():
1698 for r in rlog:
1698 for r in rlog:
1699 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1699 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1700 if p != -1)))
1700 if p != -1)))
1701 if r in revs:
1701 if r in revs:
1702 yield 'l', (r, "r%i" % r)
1702 yield 'l', (r, "r%i" % r)
1703 elif repo:
1703 elif repo:
1704 cl = repo.changelog
1704 cl = repo.changelog
1705 tags = opts.get('tags')
1705 tags = opts.get('tags')
1706 branches = opts.get('branches')
1706 branches = opts.get('branches')
1707 if tags:
1707 if tags:
1708 labels = {}
1708 labels = {}
1709 for l, n in repo.tags().items():
1709 for l, n in repo.tags().items():
1710 labels.setdefault(cl.rev(n), []).append(l)
1710 labels.setdefault(cl.rev(n), []).append(l)
1711 def events():
1711 def events():
1712 b = "default"
1712 b = "default"
1713 for r in cl:
1713 for r in cl:
1714 if branches:
1714 if branches:
1715 newb = cl.read(cl.node(r))[5]['branch']
1715 newb = cl.read(cl.node(r))[5]['branch']
1716 if newb != b:
1716 if newb != b:
1717 yield 'a', newb
1717 yield 'a', newb
1718 b = newb
1718 b = newb
1719 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1719 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1720 if p != -1)))
1720 if p != -1)))
1721 if tags:
1721 if tags:
1722 ls = labels.get(r)
1722 ls = labels.get(r)
1723 if ls:
1723 if ls:
1724 for l in ls:
1724 for l in ls:
1725 yield 'l', (r, l)
1725 yield 'l', (r, l)
1726 else:
1726 else:
1727 raise util.Abort(_('need repo for changelog dag'))
1727 raise util.Abort(_('need repo for changelog dag'))
1728
1728
1729 for line in dagparser.dagtextlines(events(),
1729 for line in dagparser.dagtextlines(events(),
1730 addspaces=spaces,
1730 addspaces=spaces,
1731 wraplabels=True,
1731 wraplabels=True,
1732 wrapannotations=True,
1732 wrapannotations=True,
1733 wrapnonlinear=dots,
1733 wrapnonlinear=dots,
1734 usedots=dots,
1734 usedots=dots,
1735 maxlinewidth=70):
1735 maxlinewidth=70):
1736 ui.write(line)
1736 ui.write(line)
1737 ui.write("\n")
1737 ui.write("\n")
1738
1738
1739 @command('debugdata',
1739 @command('debugdata',
1740 [('c', 'changelog', False, _('open changelog')),
1740 [('c', 'changelog', False, _('open changelog')),
1741 ('m', 'manifest', False, _('open manifest'))],
1741 ('m', 'manifest', False, _('open manifest'))],
1742 _('-c|-m|FILE REV'))
1742 _('-c|-m|FILE REV'))
1743 def debugdata(ui, repo, file_, rev = None, **opts):
1743 def debugdata(ui, repo, file_, rev = None, **opts):
1744 """dump the contents of a data file revision"""
1744 """dump the contents of a data file revision"""
1745 if opts.get('changelog') or opts.get('manifest'):
1745 if opts.get('changelog') or opts.get('manifest'):
1746 file_, rev = None, file_
1746 file_, rev = None, file_
1747 elif rev is None:
1747 elif rev is None:
1748 raise error.CommandError('debugdata', _('invalid arguments'))
1748 raise error.CommandError('debugdata', _('invalid arguments'))
1749 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1749 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1750 try:
1750 try:
1751 ui.write(r.revision(r.lookup(rev)))
1751 ui.write(r.revision(r.lookup(rev)))
1752 except KeyError:
1752 except KeyError:
1753 raise util.Abort(_('invalid revision identifier %s') % rev)
1753 raise util.Abort(_('invalid revision identifier %s') % rev)
1754
1754
1755 @command('debugdate',
1755 @command('debugdate',
1756 [('e', 'extended', None, _('try extended date formats'))],
1756 [('e', 'extended', None, _('try extended date formats'))],
1757 _('[-e] DATE [RANGE]'))
1757 _('[-e] DATE [RANGE]'))
1758 def debugdate(ui, date, range=None, **opts):
1758 def debugdate(ui, date, range=None, **opts):
1759 """parse and display a date"""
1759 """parse and display a date"""
1760 if opts["extended"]:
1760 if opts["extended"]:
1761 d = util.parsedate(date, util.extendeddateformats)
1761 d = util.parsedate(date, util.extendeddateformats)
1762 else:
1762 else:
1763 d = util.parsedate(date)
1763 d = util.parsedate(date)
1764 ui.write(("internal: %s %s\n") % d)
1764 ui.write(("internal: %s %s\n") % d)
1765 ui.write(("standard: %s\n") % util.datestr(d))
1765 ui.write(("standard: %s\n") % util.datestr(d))
1766 if range:
1766 if range:
1767 m = util.matchdate(range)
1767 m = util.matchdate(range)
1768 ui.write(("match: %s\n") % m(d[0]))
1768 ui.write(("match: %s\n") % m(d[0]))
1769
1769
1770 @command('debugdiscovery',
1770 @command('debugdiscovery',
1771 [('', 'old', None, _('use old-style discovery')),
1771 [('', 'old', None, _('use old-style discovery')),
1772 ('', 'nonheads', None,
1772 ('', 'nonheads', None,
1773 _('use old-style discovery with non-heads included')),
1773 _('use old-style discovery with non-heads included')),
1774 ] + remoteopts,
1774 ] + remoteopts,
1775 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1775 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1776 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1776 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1777 """runs the changeset discovery protocol in isolation"""
1777 """runs the changeset discovery protocol in isolation"""
1778 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1778 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1779 opts.get('branch'))
1779 opts.get('branch'))
1780 remote = hg.peer(repo, opts, remoteurl)
1780 remote = hg.peer(repo, opts, remoteurl)
1781 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1781 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1782
1782
1783 # make sure tests are repeatable
1783 # make sure tests are repeatable
1784 random.seed(12323)
1784 random.seed(12323)
1785
1785
1786 def doit(localheads, remoteheads, remote=remote):
1786 def doit(localheads, remoteheads, remote=remote):
1787 if opts.get('old'):
1787 if opts.get('old'):
1788 if localheads:
1788 if localheads:
1789 raise util.Abort('cannot use localheads with old style '
1789 raise util.Abort('cannot use localheads with old style '
1790 'discovery')
1790 'discovery')
1791 if not util.safehasattr(remote, 'branches'):
1791 if not util.safehasattr(remote, 'branches'):
1792 # enable in-client legacy support
1792 # enable in-client legacy support
1793 remote = localrepo.locallegacypeer(remote.local())
1793 remote = localrepo.locallegacypeer(remote.local())
1794 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1794 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1795 force=True)
1795 force=True)
1796 common = set(common)
1796 common = set(common)
1797 if not opts.get('nonheads'):
1797 if not opts.get('nonheads'):
1798 ui.write(("unpruned common: %s\n") %
1798 ui.write(("unpruned common: %s\n") %
1799 " ".join(sorted(short(n) for n in common)))
1799 " ".join(sorted(short(n) for n in common)))
1800 dag = dagutil.revlogdag(repo.changelog)
1800 dag = dagutil.revlogdag(repo.changelog)
1801 all = dag.ancestorset(dag.internalizeall(common))
1801 all = dag.ancestorset(dag.internalizeall(common))
1802 common = dag.externalizeall(dag.headsetofconnecteds(all))
1802 common = dag.externalizeall(dag.headsetofconnecteds(all))
1803 else:
1803 else:
1804 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1804 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1805 common = set(common)
1805 common = set(common)
1806 rheads = set(hds)
1806 rheads = set(hds)
1807 lheads = set(repo.heads())
1807 lheads = set(repo.heads())
1808 ui.write(("common heads: %s\n") %
1808 ui.write(("common heads: %s\n") %
1809 " ".join(sorted(short(n) for n in common)))
1809 " ".join(sorted(short(n) for n in common)))
1810 if lheads <= common:
1810 if lheads <= common:
1811 ui.write(("local is subset\n"))
1811 ui.write(("local is subset\n"))
1812 elif rheads <= common:
1812 elif rheads <= common:
1813 ui.write(("remote is subset\n"))
1813 ui.write(("remote is subset\n"))
1814
1814
1815 serverlogs = opts.get('serverlog')
1815 serverlogs = opts.get('serverlog')
1816 if serverlogs:
1816 if serverlogs:
1817 for filename in serverlogs:
1817 for filename in serverlogs:
1818 logfile = open(filename, 'r')
1818 logfile = open(filename, 'r')
1819 try:
1819 try:
1820 line = logfile.readline()
1820 line = logfile.readline()
1821 while line:
1821 while line:
1822 parts = line.strip().split(';')
1822 parts = line.strip().split(';')
1823 op = parts[1]
1823 op = parts[1]
1824 if op == 'cg':
1824 if op == 'cg':
1825 pass
1825 pass
1826 elif op == 'cgss':
1826 elif op == 'cgss':
1827 doit(parts[2].split(' '), parts[3].split(' '))
1827 doit(parts[2].split(' '), parts[3].split(' '))
1828 elif op == 'unb':
1828 elif op == 'unb':
1829 doit(parts[3].split(' '), parts[2].split(' '))
1829 doit(parts[3].split(' '), parts[2].split(' '))
1830 line = logfile.readline()
1830 line = logfile.readline()
1831 finally:
1831 finally:
1832 logfile.close()
1832 logfile.close()
1833
1833
1834 else:
1834 else:
1835 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1835 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1836 opts.get('remote_head'))
1836 opts.get('remote_head'))
1837 localrevs = opts.get('local_head')
1837 localrevs = opts.get('local_head')
1838 doit(localrevs, remoterevs)
1838 doit(localrevs, remoterevs)
1839
1839
1840 @command('debugfileset',
1840 @command('debugfileset',
1841 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1841 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1842 _('[-r REV] FILESPEC'))
1842 _('[-r REV] FILESPEC'))
1843 def debugfileset(ui, repo, expr, **opts):
1843 def debugfileset(ui, repo, expr, **opts):
1844 '''parse and apply a fileset specification'''
1844 '''parse and apply a fileset specification'''
1845 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1845 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1846 if ui.verbose:
1846 if ui.verbose:
1847 tree = fileset.parse(expr)[0]
1847 tree = fileset.parse(expr)[0]
1848 ui.note(tree, "\n")
1848 ui.note(tree, "\n")
1849
1849
1850 for f in fileset.getfileset(ctx, expr):
1850 for f in fileset.getfileset(ctx, expr):
1851 ui.write("%s\n" % f)
1851 ui.write("%s\n" % f)
1852
1852
1853 @command('debugfsinfo', [], _('[PATH]'))
1853 @command('debugfsinfo', [], _('[PATH]'))
1854 def debugfsinfo(ui, path = "."):
1854 def debugfsinfo(ui, path = "."):
1855 """show information detected about current filesystem"""
1855 """show information detected about current filesystem"""
1856 util.writefile('.debugfsinfo', '')
1856 util.writefile('.debugfsinfo', '')
1857 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1857 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1858 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1858 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1859 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1859 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1860 and 'yes' or 'no'))
1860 and 'yes' or 'no'))
1861 os.unlink('.debugfsinfo')
1861 os.unlink('.debugfsinfo')
1862
1862
1863 @command('debuggetbundle',
1863 @command('debuggetbundle',
1864 [('H', 'head', [], _('id of head node'), _('ID')),
1864 [('H', 'head', [], _('id of head node'), _('ID')),
1865 ('C', 'common', [], _('id of common node'), _('ID')),
1865 ('C', 'common', [], _('id of common node'), _('ID')),
1866 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1866 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1867 _('REPO FILE [-H|-C ID]...'))
1867 _('REPO FILE [-H|-C ID]...'))
1868 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1868 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1869 """retrieves a bundle from a repo
1869 """retrieves a bundle from a repo
1870
1870
1871 Every ID must be a full-length hex node id string. Saves the bundle to the
1871 Every ID must be a full-length hex node id string. Saves the bundle to the
1872 given file.
1872 given file.
1873 """
1873 """
1874 repo = hg.peer(ui, opts, repopath)
1874 repo = hg.peer(ui, opts, repopath)
1875 if not repo.capable('getbundle'):
1875 if not repo.capable('getbundle'):
1876 raise util.Abort("getbundle() not supported by target repository")
1876 raise util.Abort("getbundle() not supported by target repository")
1877 args = {}
1877 args = {}
1878 if common:
1878 if common:
1879 args['common'] = [bin(s) for s in common]
1879 args['common'] = [bin(s) for s in common]
1880 if head:
1880 if head:
1881 args['heads'] = [bin(s) for s in head]
1881 args['heads'] = [bin(s) for s in head]
1882 bundle = repo.getbundle('debug', **args)
1882 bundle = repo.getbundle('debug', **args)
1883
1883
1884 bundletype = opts.get('type', 'bzip2').lower()
1884 bundletype = opts.get('type', 'bzip2').lower()
1885 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1885 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1886 bundletype = btypes.get(bundletype)
1886 bundletype = btypes.get(bundletype)
1887 if bundletype not in changegroup.bundletypes:
1887 if bundletype not in changegroup.bundletypes:
1888 raise util.Abort(_('unknown bundle type specified with --type'))
1888 raise util.Abort(_('unknown bundle type specified with --type'))
1889 changegroup.writebundle(bundle, bundlepath, bundletype)
1889 changegroup.writebundle(bundle, bundlepath, bundletype)
1890
1890
1891 @command('debugignore', [], '')
1891 @command('debugignore', [], '')
1892 def debugignore(ui, repo, *values, **opts):
1892 def debugignore(ui, repo, *values, **opts):
1893 """display the combined ignore pattern"""
1893 """display the combined ignore pattern"""
1894 ignore = repo.dirstate._ignore
1894 ignore = repo.dirstate._ignore
1895 includepat = getattr(ignore, 'includepat', None)
1895 includepat = getattr(ignore, 'includepat', None)
1896 if includepat is not None:
1896 if includepat is not None:
1897 ui.write("%s\n" % includepat)
1897 ui.write("%s\n" % includepat)
1898 else:
1898 else:
1899 raise util.Abort(_("no ignore patterns found"))
1899 raise util.Abort(_("no ignore patterns found"))
1900
1900
1901 @command('debugindex',
1901 @command('debugindex',
1902 [('c', 'changelog', False, _('open changelog')),
1902 [('c', 'changelog', False, _('open changelog')),
1903 ('m', 'manifest', False, _('open manifest')),
1903 ('m', 'manifest', False, _('open manifest')),
1904 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1904 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1905 _('[-f FORMAT] -c|-m|FILE'))
1905 _('[-f FORMAT] -c|-m|FILE'))
1906 def debugindex(ui, repo, file_ = None, **opts):
1906 def debugindex(ui, repo, file_ = None, **opts):
1907 """dump the contents of an index file"""
1907 """dump the contents of an index file"""
1908 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1908 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1909 format = opts.get('format', 0)
1909 format = opts.get('format', 0)
1910 if format not in (0, 1):
1910 if format not in (0, 1):
1911 raise util.Abort(_("unknown format %d") % format)
1911 raise util.Abort(_("unknown format %d") % format)
1912
1912
1913 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1913 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1914 if generaldelta:
1914 if generaldelta:
1915 basehdr = ' delta'
1915 basehdr = ' delta'
1916 else:
1916 else:
1917 basehdr = ' base'
1917 basehdr = ' base'
1918
1918
1919 if format == 0:
1919 if format == 0:
1920 ui.write(" rev offset length " + basehdr + " linkrev"
1920 ui.write(" rev offset length " + basehdr + " linkrev"
1921 " nodeid p1 p2\n")
1921 " nodeid p1 p2\n")
1922 elif format == 1:
1922 elif format == 1:
1923 ui.write(" rev flag offset length"
1923 ui.write(" rev flag offset length"
1924 " size " + basehdr + " link p1 p2"
1924 " size " + basehdr + " link p1 p2"
1925 " nodeid\n")
1925 " nodeid\n")
1926
1926
1927 for i in r:
1927 for i in r:
1928 node = r.node(i)
1928 node = r.node(i)
1929 if generaldelta:
1929 if generaldelta:
1930 base = r.deltaparent(i)
1930 base = r.deltaparent(i)
1931 else:
1931 else:
1932 base = r.chainbase(i)
1932 base = r.chainbase(i)
1933 if format == 0:
1933 if format == 0:
1934 try:
1934 try:
1935 pp = r.parents(node)
1935 pp = r.parents(node)
1936 except Exception:
1936 except Exception:
1937 pp = [nullid, nullid]
1937 pp = [nullid, nullid]
1938 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1938 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1939 i, r.start(i), r.length(i), base, r.linkrev(i),
1939 i, r.start(i), r.length(i), base, r.linkrev(i),
1940 short(node), short(pp[0]), short(pp[1])))
1940 short(node), short(pp[0]), short(pp[1])))
1941 elif format == 1:
1941 elif format == 1:
1942 pr = r.parentrevs(i)
1942 pr = r.parentrevs(i)
1943 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1943 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1944 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1944 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1945 base, r.linkrev(i), pr[0], pr[1], short(node)))
1945 base, r.linkrev(i), pr[0], pr[1], short(node)))
1946
1946
1947 @command('debugindexdot', [], _('FILE'))
1947 @command('debugindexdot', [], _('FILE'))
1948 def debugindexdot(ui, repo, file_):
1948 def debugindexdot(ui, repo, file_):
1949 """dump an index DAG as a graphviz dot file"""
1949 """dump an index DAG as a graphviz dot file"""
1950 r = None
1950 r = None
1951 if repo:
1951 if repo:
1952 filelog = repo.file(file_)
1952 filelog = repo.file(file_)
1953 if len(filelog):
1953 if len(filelog):
1954 r = filelog
1954 r = filelog
1955 if not r:
1955 if not r:
1956 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1956 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1957 ui.write(("digraph G {\n"))
1957 ui.write(("digraph G {\n"))
1958 for i in r:
1958 for i in r:
1959 node = r.node(i)
1959 node = r.node(i)
1960 pp = r.parents(node)
1960 pp = r.parents(node)
1961 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1961 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1962 if pp[1] != nullid:
1962 if pp[1] != nullid:
1963 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1963 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1964 ui.write("}\n")
1964 ui.write("}\n")
1965
1965
1966 @command('debuginstall', [], '')
1966 @command('debuginstall', [], '')
1967 def debuginstall(ui):
1967 def debuginstall(ui):
1968 '''test Mercurial installation
1968 '''test Mercurial installation
1969
1969
1970 Returns 0 on success.
1970 Returns 0 on success.
1971 '''
1971 '''
1972
1972
1973 def writetemp(contents):
1973 def writetemp(contents):
1974 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1974 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1975 f = os.fdopen(fd, "wb")
1975 f = os.fdopen(fd, "wb")
1976 f.write(contents)
1976 f.write(contents)
1977 f.close()
1977 f.close()
1978 return name
1978 return name
1979
1979
1980 problems = 0
1980 problems = 0
1981
1981
1982 # encoding
1982 # encoding
1983 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
1983 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
1984 try:
1984 try:
1985 encoding.fromlocal("test")
1985 encoding.fromlocal("test")
1986 except util.Abort, inst:
1986 except util.Abort, inst:
1987 ui.write(" %s\n" % inst)
1987 ui.write(" %s\n" % inst)
1988 ui.write(_(" (check that your locale is properly set)\n"))
1988 ui.write(_(" (check that your locale is properly set)\n"))
1989 problems += 1
1989 problems += 1
1990
1990
1991 # Python lib
1991 # Python lib
1992 ui.status(_("checking Python lib (%s)...\n")
1992 ui.status(_("checking Python lib (%s)...\n")
1993 % os.path.dirname(os.__file__))
1993 % os.path.dirname(os.__file__))
1994
1994
1995 # compiled modules
1995 # compiled modules
1996 ui.status(_("checking installed modules (%s)...\n")
1996 ui.status(_("checking installed modules (%s)...\n")
1997 % os.path.dirname(__file__))
1997 % os.path.dirname(__file__))
1998 try:
1998 try:
1999 import bdiff, mpatch, base85, osutil
1999 import bdiff, mpatch, base85, osutil
2000 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2000 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2001 except Exception, inst:
2001 except Exception, inst:
2002 ui.write(" %s\n" % inst)
2002 ui.write(" %s\n" % inst)
2003 ui.write(_(" One or more extensions could not be found"))
2003 ui.write(_(" One or more extensions could not be found"))
2004 ui.write(_(" (check that you compiled the extensions)\n"))
2004 ui.write(_(" (check that you compiled the extensions)\n"))
2005 problems += 1
2005 problems += 1
2006
2006
2007 # templates
2007 # templates
2008 import templater
2008 import templater
2009 p = templater.templatepath()
2009 p = templater.templatepath()
2010 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2010 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2011 try:
2011 try:
2012 templater.templater(templater.templatepath("map-cmdline.default"))
2012 templater.templater(templater.templatepath("map-cmdline.default"))
2013 except Exception, inst:
2013 except Exception, inst:
2014 ui.write(" %s\n" % inst)
2014 ui.write(" %s\n" % inst)
2015 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2015 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2016 problems += 1
2016 problems += 1
2017
2017
2018 # editor
2018 # editor
2019 ui.status(_("checking commit editor...\n"))
2019 ui.status(_("checking commit editor...\n"))
2020 editor = ui.geteditor()
2020 editor = ui.geteditor()
2021 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2021 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2022 if not cmdpath:
2022 if not cmdpath:
2023 if editor == 'vi':
2023 if editor == 'vi':
2024 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2024 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2025 ui.write(_(" (specify a commit editor in your configuration"
2025 ui.write(_(" (specify a commit editor in your configuration"
2026 " file)\n"))
2026 " file)\n"))
2027 else:
2027 else:
2028 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2028 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2029 ui.write(_(" (specify a commit editor in your configuration"
2029 ui.write(_(" (specify a commit editor in your configuration"
2030 " file)\n"))
2030 " file)\n"))
2031 problems += 1
2031 problems += 1
2032
2032
2033 # check username
2033 # check username
2034 ui.status(_("checking username...\n"))
2034 ui.status(_("checking username...\n"))
2035 try:
2035 try:
2036 ui.username()
2036 ui.username()
2037 except util.Abort, e:
2037 except util.Abort, e:
2038 ui.write(" %s\n" % e)
2038 ui.write(" %s\n" % e)
2039 ui.write(_(" (specify a username in your configuration file)\n"))
2039 ui.write(_(" (specify a username in your configuration file)\n"))
2040 problems += 1
2040 problems += 1
2041
2041
2042 if not problems:
2042 if not problems:
2043 ui.status(_("no problems detected\n"))
2043 ui.status(_("no problems detected\n"))
2044 else:
2044 else:
2045 ui.write(_("%s problems detected,"
2045 ui.write(_("%s problems detected,"
2046 " please check your install!\n") % problems)
2046 " please check your install!\n") % problems)
2047
2047
2048 return problems
2048 return problems
2049
2049
2050 @command('debugknown', [], _('REPO ID...'))
2050 @command('debugknown', [], _('REPO ID...'))
2051 def debugknown(ui, repopath, *ids, **opts):
2051 def debugknown(ui, repopath, *ids, **opts):
2052 """test whether node ids are known to a repo
2052 """test whether node ids are known to a repo
2053
2053
2054 Every ID must be a full-length hex node id string. Returns a list of 0s
2054 Every ID must be a full-length hex node id string. Returns a list of 0s
2055 and 1s indicating unknown/known.
2055 and 1s indicating unknown/known.
2056 """
2056 """
2057 repo = hg.peer(ui, opts, repopath)
2057 repo = hg.peer(ui, opts, repopath)
2058 if not repo.capable('known'):
2058 if not repo.capable('known'):
2059 raise util.Abort("known() not supported by target repository")
2059 raise util.Abort("known() not supported by target repository")
2060 flags = repo.known([bin(s) for s in ids])
2060 flags = repo.known([bin(s) for s in ids])
2061 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2061 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2062
2062
2063 @command('debugobsolete',
2063 @command('debugobsolete',
2064 [('', 'flags', 0, _('markers flag')),
2064 [('', 'flags', 0, _('markers flag')),
2065 ] + commitopts2,
2065 ] + commitopts2,
2066 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2066 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2067 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2067 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2068 """create arbitrary obsolete marker
2068 """create arbitrary obsolete marker
2069
2069
2070 With no arguments it it display the list obsolescence marker."""
2070 With no arguments it it display the list obsolescence marker."""
2071 def parsenodeid(s):
2071 def parsenodeid(s):
2072 try:
2072 try:
2073 # We do not use revsingle/revrange functions here to accept
2073 # We do not use revsingle/revrange functions here to accept
2074 # arbitrary node identifiers, possibly not present in the
2074 # arbitrary node identifiers, possibly not present in the
2075 # local repository.
2075 # local repository.
2076 n = bin(s)
2076 n = bin(s)
2077 if len(n) != len(nullid):
2077 if len(n) != len(nullid):
2078 raise TypeError()
2078 raise TypeError()
2079 return n
2079 return n
2080 except TypeError:
2080 except TypeError:
2081 raise util.Abort('changeset references must be full hexadecimal '
2081 raise util.Abort('changeset references must be full hexadecimal '
2082 'node identifiers')
2082 'node identifiers')
2083
2083
2084 if precursor is not None:
2084 if precursor is not None:
2085 metadata = {}
2085 metadata = {}
2086 if 'date' in opts:
2086 if 'date' in opts:
2087 metadata['date'] = opts['date']
2087 metadata['date'] = opts['date']
2088 metadata['user'] = opts['user'] or ui.username()
2088 metadata['user'] = opts['user'] or ui.username()
2089 succs = tuple(parsenodeid(succ) for succ in successors)
2089 succs = tuple(parsenodeid(succ) for succ in successors)
2090 l = repo.lock()
2090 l = repo.lock()
2091 try:
2091 try:
2092 tr = repo.transaction('debugobsolete')
2092 tr = repo.transaction('debugobsolete')
2093 try:
2093 try:
2094 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2094 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2095 opts['flags'], metadata)
2095 opts['flags'], metadata)
2096 tr.close()
2096 tr.close()
2097 finally:
2097 finally:
2098 tr.release()
2098 tr.release()
2099 finally:
2099 finally:
2100 l.release()
2100 l.release()
2101 else:
2101 else:
2102 for m in obsolete.allmarkers(repo):
2102 for m in obsolete.allmarkers(repo):
2103 ui.write(hex(m.precnode()))
2103 ui.write(hex(m.precnode()))
2104 for repl in m.succnodes():
2104 for repl in m.succnodes():
2105 ui.write(' ')
2105 ui.write(' ')
2106 ui.write(hex(repl))
2106 ui.write(hex(repl))
2107 ui.write(' %X ' % m._data[2])
2107 ui.write(' %X ' % m._data[2])
2108 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2108 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2109 sorted(m.metadata().items()))))
2109 sorted(m.metadata().items()))))
2110 ui.write('\n')
2110 ui.write('\n')
2111
2111
2112 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2112 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2113 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2113 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2114 '''access the pushkey key/value protocol
2114 '''access the pushkey key/value protocol
2115
2115
2116 With two args, list the keys in the given namespace.
2116 With two args, list the keys in the given namespace.
2117
2117
2118 With five args, set a key to new if it currently is set to old.
2118 With five args, set a key to new if it currently is set to old.
2119 Reports success or failure.
2119 Reports success or failure.
2120 '''
2120 '''
2121
2121
2122 target = hg.peer(ui, {}, repopath)
2122 target = hg.peer(ui, {}, repopath)
2123 if keyinfo:
2123 if keyinfo:
2124 key, old, new = keyinfo
2124 key, old, new = keyinfo
2125 r = target.pushkey(namespace, key, old, new)
2125 r = target.pushkey(namespace, key, old, new)
2126 ui.status(str(r) + '\n')
2126 ui.status(str(r) + '\n')
2127 return not r
2127 return not r
2128 else:
2128 else:
2129 for k, v in sorted(target.listkeys(namespace).iteritems()):
2129 for k, v in sorted(target.listkeys(namespace).iteritems()):
2130 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2130 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2131 v.encode('string-escape')))
2131 v.encode('string-escape')))
2132
2132
2133 @command('debugpvec', [], _('A B'))
2133 @command('debugpvec', [], _('A B'))
2134 def debugpvec(ui, repo, a, b=None):
2134 def debugpvec(ui, repo, a, b=None):
2135 ca = scmutil.revsingle(repo, a)
2135 ca = scmutil.revsingle(repo, a)
2136 cb = scmutil.revsingle(repo, b)
2136 cb = scmutil.revsingle(repo, b)
2137 pa = pvec.ctxpvec(ca)
2137 pa = pvec.ctxpvec(ca)
2138 pb = pvec.ctxpvec(cb)
2138 pb = pvec.ctxpvec(cb)
2139 if pa == pb:
2139 if 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 elif pa | pb:
2145 elif pa | pb:
2146 rel = "|"
2146 rel = "|"
2147 ui.write(_("a: %s\n") % pa)
2147 ui.write(_("a: %s\n") % pa)
2148 ui.write(_("b: %s\n") % pb)
2148 ui.write(_("b: %s\n") % pb)
2149 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2149 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2150 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2150 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2151 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2151 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2152 pa.distance(pb), rel))
2152 pa.distance(pb), rel))
2153
2153
2154 @command('debugrebuildstate',
2154 @command('debugrebuildstate',
2155 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2155 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2156 _('[-r REV] [REV]'))
2156 _('[-r REV] [REV]'))
2157 def debugrebuildstate(ui, repo, rev="tip"):
2157 def debugrebuildstate(ui, repo, rev="tip"):
2158 """rebuild the dirstate as it would look like for the given revision"""
2158 """rebuild the dirstate as it would look like for the given revision"""
2159 ctx = scmutil.revsingle(repo, rev)
2159 ctx = scmutil.revsingle(repo, rev)
2160 wlock = repo.wlock()
2160 wlock = repo.wlock()
2161 try:
2161 try:
2162 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2162 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2163 finally:
2163 finally:
2164 wlock.release()
2164 wlock.release()
2165
2165
2166 @command('debugrename',
2166 @command('debugrename',
2167 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2167 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2168 _('[-r REV] FILE'))
2168 _('[-r REV] FILE'))
2169 def debugrename(ui, repo, file1, *pats, **opts):
2169 def debugrename(ui, repo, file1, *pats, **opts):
2170 """dump rename information"""
2170 """dump rename information"""
2171
2171
2172 ctx = scmutil.revsingle(repo, opts.get('rev'))
2172 ctx = scmutil.revsingle(repo, opts.get('rev'))
2173 m = scmutil.match(ctx, (file1,) + pats, opts)
2173 m = scmutil.match(ctx, (file1,) + pats, opts)
2174 for abs in ctx.walk(m):
2174 for abs in ctx.walk(m):
2175 fctx = ctx[abs]
2175 fctx = ctx[abs]
2176 o = fctx.filelog().renamed(fctx.filenode())
2176 o = fctx.filelog().renamed(fctx.filenode())
2177 rel = m.rel(abs)
2177 rel = m.rel(abs)
2178 if o:
2178 if o:
2179 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2179 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2180 else:
2180 else:
2181 ui.write(_("%s not renamed\n") % rel)
2181 ui.write(_("%s not renamed\n") % rel)
2182
2182
2183 @command('debugrevlog',
2183 @command('debugrevlog',
2184 [('c', 'changelog', False, _('open changelog')),
2184 [('c', 'changelog', False, _('open changelog')),
2185 ('m', 'manifest', False, _('open manifest')),
2185 ('m', 'manifest', False, _('open manifest')),
2186 ('d', 'dump', False, _('dump index data'))],
2186 ('d', 'dump', False, _('dump index data'))],
2187 _('-c|-m|FILE'))
2187 _('-c|-m|FILE'))
2188 def debugrevlog(ui, repo, file_ = None, **opts):
2188 def debugrevlog(ui, repo, file_ = None, **opts):
2189 """show data and statistics about a revlog"""
2189 """show data and statistics about a revlog"""
2190 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2190 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2191
2191
2192 if opts.get("dump"):
2192 if opts.get("dump"):
2193 numrevs = len(r)
2193 numrevs = len(r)
2194 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2194 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2195 " rawsize totalsize compression heads\n")
2195 " rawsize totalsize compression heads\n")
2196 ts = 0
2196 ts = 0
2197 heads = set()
2197 heads = set()
2198 for rev in xrange(numrevs):
2198 for rev in xrange(numrevs):
2199 dbase = r.deltaparent(rev)
2199 dbase = r.deltaparent(rev)
2200 if dbase == -1:
2200 if dbase == -1:
2201 dbase = rev
2201 dbase = rev
2202 cbase = r.chainbase(rev)
2202 cbase = r.chainbase(rev)
2203 p1, p2 = r.parentrevs(rev)
2203 p1, p2 = r.parentrevs(rev)
2204 rs = r.rawsize(rev)
2204 rs = r.rawsize(rev)
2205 ts = ts + rs
2205 ts = ts + rs
2206 heads -= set(r.parentrevs(rev))
2206 heads -= set(r.parentrevs(rev))
2207 heads.add(rev)
2207 heads.add(rev)
2208 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2208 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2209 (rev, p1, p2, r.start(rev), r.end(rev),
2209 (rev, p1, p2, r.start(rev), r.end(rev),
2210 r.start(dbase), r.start(cbase),
2210 r.start(dbase), r.start(cbase),
2211 r.start(p1), r.start(p2),
2211 r.start(p1), r.start(p2),
2212 rs, ts, ts / r.end(rev), len(heads)))
2212 rs, ts, ts / r.end(rev), len(heads)))
2213 return 0
2213 return 0
2214
2214
2215 v = r.version
2215 v = r.version
2216 format = v & 0xFFFF
2216 format = v & 0xFFFF
2217 flags = []
2217 flags = []
2218 gdelta = False
2218 gdelta = False
2219 if v & revlog.REVLOGNGINLINEDATA:
2219 if v & revlog.REVLOGNGINLINEDATA:
2220 flags.append('inline')
2220 flags.append('inline')
2221 if v & revlog.REVLOGGENERALDELTA:
2221 if v & revlog.REVLOGGENERALDELTA:
2222 gdelta = True
2222 gdelta = True
2223 flags.append('generaldelta')
2223 flags.append('generaldelta')
2224 if not flags:
2224 if not flags:
2225 flags = ['(none)']
2225 flags = ['(none)']
2226
2226
2227 nummerges = 0
2227 nummerges = 0
2228 numfull = 0
2228 numfull = 0
2229 numprev = 0
2229 numprev = 0
2230 nump1 = 0
2230 nump1 = 0
2231 nump2 = 0
2231 nump2 = 0
2232 numother = 0
2232 numother = 0
2233 nump1prev = 0
2233 nump1prev = 0
2234 nump2prev = 0
2234 nump2prev = 0
2235 chainlengths = []
2235 chainlengths = []
2236
2236
2237 datasize = [None, 0, 0L]
2237 datasize = [None, 0, 0L]
2238 fullsize = [None, 0, 0L]
2238 fullsize = [None, 0, 0L]
2239 deltasize = [None, 0, 0L]
2239 deltasize = [None, 0, 0L]
2240
2240
2241 def addsize(size, l):
2241 def addsize(size, l):
2242 if l[0] is None or size < l[0]:
2242 if l[0] is None or size < l[0]:
2243 l[0] = size
2243 l[0] = size
2244 if size > l[1]:
2244 if size > l[1]:
2245 l[1] = size
2245 l[1] = size
2246 l[2] += size
2246 l[2] += size
2247
2247
2248 numrevs = len(r)
2248 numrevs = len(r)
2249 for rev in xrange(numrevs):
2249 for rev in xrange(numrevs):
2250 p1, p2 = r.parentrevs(rev)
2250 p1, p2 = r.parentrevs(rev)
2251 delta = r.deltaparent(rev)
2251 delta = r.deltaparent(rev)
2252 if format > 0:
2252 if format > 0:
2253 addsize(r.rawsize(rev), datasize)
2253 addsize(r.rawsize(rev), datasize)
2254 if p2 != nullrev:
2254 if p2 != nullrev:
2255 nummerges += 1
2255 nummerges += 1
2256 size = r.length(rev)
2256 size = r.length(rev)
2257 if delta == nullrev:
2257 if delta == nullrev:
2258 chainlengths.append(0)
2258 chainlengths.append(0)
2259 numfull += 1
2259 numfull += 1
2260 addsize(size, fullsize)
2260 addsize(size, fullsize)
2261 else:
2261 else:
2262 chainlengths.append(chainlengths[delta] + 1)
2262 chainlengths.append(chainlengths[delta] + 1)
2263 addsize(size, deltasize)
2263 addsize(size, deltasize)
2264 if delta == rev - 1:
2264 if delta == rev - 1:
2265 numprev += 1
2265 numprev += 1
2266 if delta == p1:
2266 if delta == p1:
2267 nump1prev += 1
2267 nump1prev += 1
2268 elif delta == p2:
2268 elif delta == p2:
2269 nump2prev += 1
2269 nump2prev += 1
2270 elif delta == p1:
2270 elif delta == p1:
2271 nump1 += 1
2271 nump1 += 1
2272 elif delta == p2:
2272 elif delta == p2:
2273 nump2 += 1
2273 nump2 += 1
2274 elif delta != nullrev:
2274 elif delta != nullrev:
2275 numother += 1
2275 numother += 1
2276
2276
2277 # Adjust size min value for empty cases
2277 # Adjust size min value for empty cases
2278 for size in (datasize, fullsize, deltasize):
2278 for size in (datasize, fullsize, deltasize):
2279 if size[0] is None:
2279 if size[0] is None:
2280 size[0] = 0
2280 size[0] = 0
2281
2281
2282 numdeltas = numrevs - numfull
2282 numdeltas = numrevs - numfull
2283 numoprev = numprev - nump1prev - nump2prev
2283 numoprev = numprev - nump1prev - nump2prev
2284 totalrawsize = datasize[2]
2284 totalrawsize = datasize[2]
2285 datasize[2] /= numrevs
2285 datasize[2] /= numrevs
2286 fulltotal = fullsize[2]
2286 fulltotal = fullsize[2]
2287 fullsize[2] /= numfull
2287 fullsize[2] /= numfull
2288 deltatotal = deltasize[2]
2288 deltatotal = deltasize[2]
2289 if numrevs - numfull > 0:
2289 if numrevs - numfull > 0:
2290 deltasize[2] /= numrevs - numfull
2290 deltasize[2] /= numrevs - numfull
2291 totalsize = fulltotal + deltatotal
2291 totalsize = fulltotal + deltatotal
2292 avgchainlen = sum(chainlengths) / numrevs
2292 avgchainlen = sum(chainlengths) / numrevs
2293 compratio = totalrawsize / totalsize
2293 compratio = totalrawsize / totalsize
2294
2294
2295 basedfmtstr = '%%%dd\n'
2295 basedfmtstr = '%%%dd\n'
2296 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2296 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2297
2297
2298 def dfmtstr(max):
2298 def dfmtstr(max):
2299 return basedfmtstr % len(str(max))
2299 return basedfmtstr % len(str(max))
2300 def pcfmtstr(max, padding=0):
2300 def pcfmtstr(max, padding=0):
2301 return basepcfmtstr % (len(str(max)), ' ' * padding)
2301 return basepcfmtstr % (len(str(max)), ' ' * padding)
2302
2302
2303 def pcfmt(value, total):
2303 def pcfmt(value, total):
2304 return (value, 100 * float(value) / total)
2304 return (value, 100 * float(value) / total)
2305
2305
2306 ui.write(('format : %d\n') % format)
2306 ui.write(('format : %d\n') % format)
2307 ui.write(('flags : %s\n') % ', '.join(flags))
2307 ui.write(('flags : %s\n') % ', '.join(flags))
2308
2308
2309 ui.write('\n')
2309 ui.write('\n')
2310 fmt = pcfmtstr(totalsize)
2310 fmt = pcfmtstr(totalsize)
2311 fmt2 = dfmtstr(totalsize)
2311 fmt2 = dfmtstr(totalsize)
2312 ui.write(('revisions : ') + fmt2 % numrevs)
2312 ui.write(('revisions : ') + fmt2 % numrevs)
2313 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2313 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2314 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2314 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2315 ui.write(('revisions : ') + fmt2 % numrevs)
2315 ui.write(('revisions : ') + fmt2 % numrevs)
2316 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2316 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2317 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2317 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2318 ui.write(('revision size : ') + fmt2 % totalsize)
2318 ui.write(('revision size : ') + fmt2 % totalsize)
2319 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2319 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2320 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2320 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2321
2321
2322 ui.write('\n')
2322 ui.write('\n')
2323 fmt = dfmtstr(max(avgchainlen, compratio))
2323 fmt = dfmtstr(max(avgchainlen, compratio))
2324 ui.write(('avg chain length : ') + fmt % avgchainlen)
2324 ui.write(('avg chain length : ') + fmt % avgchainlen)
2325 ui.write(('compression ratio : ') + fmt % compratio)
2325 ui.write(('compression ratio : ') + fmt % compratio)
2326
2326
2327 if format > 0:
2327 if format > 0:
2328 ui.write('\n')
2328 ui.write('\n')
2329 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2329 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2330 % tuple(datasize))
2330 % tuple(datasize))
2331 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2331 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2332 % tuple(fullsize))
2332 % tuple(fullsize))
2333 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2333 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2334 % tuple(deltasize))
2334 % tuple(deltasize))
2335
2335
2336 if numdeltas > 0:
2336 if numdeltas > 0:
2337 ui.write('\n')
2337 ui.write('\n')
2338 fmt = pcfmtstr(numdeltas)
2338 fmt = pcfmtstr(numdeltas)
2339 fmt2 = pcfmtstr(numdeltas, 4)
2339 fmt2 = pcfmtstr(numdeltas, 4)
2340 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2340 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2341 if numprev > 0:
2341 if numprev > 0:
2342 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2342 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2343 numprev))
2343 numprev))
2344 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2344 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2345 numprev))
2345 numprev))
2346 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2346 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2347 numprev))
2347 numprev))
2348 if gdelta:
2348 if gdelta:
2349 ui.write(('deltas against p1 : ')
2349 ui.write(('deltas against p1 : ')
2350 + fmt % pcfmt(nump1, numdeltas))
2350 + fmt % pcfmt(nump1, numdeltas))
2351 ui.write(('deltas against p2 : ')
2351 ui.write(('deltas against p2 : ')
2352 + fmt % pcfmt(nump2, numdeltas))
2352 + fmt % pcfmt(nump2, numdeltas))
2353 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2353 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2354 numdeltas))
2354 numdeltas))
2355
2355
2356 @command('debugrevspec', [], ('REVSPEC'))
2356 @command('debugrevspec', [], ('REVSPEC'))
2357 def debugrevspec(ui, repo, expr):
2357 def debugrevspec(ui, repo, expr):
2358 """parse and apply a revision specification
2358 """parse and apply a revision specification
2359
2359
2360 Use --verbose to print the parsed tree before and after aliases
2360 Use --verbose to print the parsed tree before and after aliases
2361 expansion.
2361 expansion.
2362 """
2362 """
2363 if ui.verbose:
2363 if ui.verbose:
2364 tree = revset.parse(expr)[0]
2364 tree = revset.parse(expr)[0]
2365 ui.note(revset.prettyformat(tree), "\n")
2365 ui.note(revset.prettyformat(tree), "\n")
2366 newtree = revset.findaliases(ui, tree)
2366 newtree = revset.findaliases(ui, tree)
2367 if newtree != tree:
2367 if newtree != tree:
2368 ui.note(revset.prettyformat(newtree), "\n")
2368 ui.note(revset.prettyformat(newtree), "\n")
2369 func = revset.match(ui, expr)
2369 func = revset.match(ui, expr)
2370 for c in func(repo, range(len(repo))):
2370 for c in func(repo, range(len(repo))):
2371 ui.write("%s\n" % c)
2371 ui.write("%s\n" % c)
2372
2372
2373 @command('debugsetparents', [], _('REV1 [REV2]'))
2373 @command('debugsetparents', [], _('REV1 [REV2]'))
2374 def debugsetparents(ui, repo, rev1, rev2=None):
2374 def debugsetparents(ui, repo, rev1, rev2=None):
2375 """manually set the parents of the current working directory
2375 """manually set the parents of the current working directory
2376
2376
2377 This is useful for writing repository conversion tools, but should
2377 This is useful for writing repository conversion tools, but should
2378 be used with care.
2378 be used with care.
2379
2379
2380 Returns 0 on success.
2380 Returns 0 on success.
2381 """
2381 """
2382
2382
2383 r1 = scmutil.revsingle(repo, rev1).node()
2383 r1 = scmutil.revsingle(repo, rev1).node()
2384 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2384 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2385
2385
2386 wlock = repo.wlock()
2386 wlock = repo.wlock()
2387 try:
2387 try:
2388 repo.setparents(r1, r2)
2388 repo.setparents(r1, r2)
2389 finally:
2389 finally:
2390 wlock.release()
2390 wlock.release()
2391
2391
2392 @command('debugstate',
2392 @command('debugstate',
2393 [('', 'nodates', None, _('do not display the saved mtime')),
2393 [('', 'nodates', None, _('do not display the saved mtime')),
2394 ('', 'datesort', None, _('sort by saved mtime'))],
2394 ('', 'datesort', None, _('sort by saved mtime'))],
2395 _('[OPTION]...'))
2395 _('[OPTION]...'))
2396 def debugstate(ui, repo, nodates=None, datesort=None):
2396 def debugstate(ui, repo, nodates=None, datesort=None):
2397 """show the contents of the current dirstate"""
2397 """show the contents of the current dirstate"""
2398 timestr = ""
2398 timestr = ""
2399 showdate = not nodates
2399 showdate = not nodates
2400 if datesort:
2400 if datesort:
2401 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2401 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2402 else:
2402 else:
2403 keyfunc = None # sort by filename
2403 keyfunc = None # sort by filename
2404 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2404 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2405 if showdate:
2405 if showdate:
2406 if ent[3] == -1:
2406 if ent[3] == -1:
2407 # Pad or slice to locale representation
2407 # Pad or slice to locale representation
2408 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2408 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2409 time.localtime(0)))
2409 time.localtime(0)))
2410 timestr = 'unset'
2410 timestr = 'unset'
2411 timestr = (timestr[:locale_len] +
2411 timestr = (timestr[:locale_len] +
2412 ' ' * (locale_len - len(timestr)))
2412 ' ' * (locale_len - len(timestr)))
2413 else:
2413 else:
2414 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2414 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2415 time.localtime(ent[3]))
2415 time.localtime(ent[3]))
2416 if ent[1] & 020000:
2416 if ent[1] & 020000:
2417 mode = 'lnk'
2417 mode = 'lnk'
2418 else:
2418 else:
2419 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2419 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2420 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2420 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2421 for f in repo.dirstate.copies():
2421 for f in repo.dirstate.copies():
2422 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2422 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2423
2423
2424 @command('debugsub',
2424 @command('debugsub',
2425 [('r', 'rev', '',
2425 [('r', 'rev', '',
2426 _('revision to check'), _('REV'))],
2426 _('revision to check'), _('REV'))],
2427 _('[-r REV] [REV]'))
2427 _('[-r REV] [REV]'))
2428 def debugsub(ui, repo, rev=None):
2428 def debugsub(ui, repo, rev=None):
2429 ctx = scmutil.revsingle(repo, rev, None)
2429 ctx = scmutil.revsingle(repo, rev, None)
2430 for k, v in sorted(ctx.substate.items()):
2430 for k, v in sorted(ctx.substate.items()):
2431 ui.write(('path %s\n') % k)
2431 ui.write(('path %s\n') % k)
2432 ui.write((' source %s\n') % v[0])
2432 ui.write((' source %s\n') % v[0])
2433 ui.write((' revision %s\n') % v[1])
2433 ui.write((' revision %s\n') % v[1])
2434
2434
2435 @command('debugsuccessorssets',
2435 @command('debugsuccessorssets',
2436 [],
2436 [],
2437 _('[REV]'))
2437 _('[REV]'))
2438 def debugsuccessorssets(ui, repo, *revs):
2438 def debugsuccessorssets(ui, repo, *revs):
2439 """show set of successors for revision
2439 """show set of successors for revision
2440
2440
2441 A successors set of changeset A is a consistent group of revisions that
2441 A successors set of changeset A is a consistent group of revisions that
2442 succeed A. It contains non-obsolete changesets only.
2442 succeed A. It contains non-obsolete changesets only.
2443
2443
2444 In most cases a changeset A has a single successors set containing a single
2444 In most cases a changeset A has a single successors set containing a single
2445 successor (changeset A replaced by A').
2445 successor (changeset A replaced by A').
2446
2446
2447 A changeset that is made obsolete with no successors are called "pruned".
2447 A changeset that is made obsolete with no successors are called "pruned".
2448 Such changesets have no successors sets at all.
2448 Such changesets have no successors sets at all.
2449
2449
2450 A changeset that has been "split" will have a successors set containing
2450 A changeset that has been "split" will have a successors set containing
2451 more than one successor.
2451 more than one successor.
2452
2452
2453 A changeset that has been rewritten in multiple different ways is called
2453 A changeset that has been rewritten in multiple different ways is called
2454 "divergent". Such changesets have multiple successor sets (each of which
2454 "divergent". Such changesets have multiple successor sets (each of which
2455 may also be split, i.e. have multiple successors).
2455 may also be split, i.e. have multiple successors).
2456
2456
2457 Results are displayed as follows::
2457 Results are displayed as follows::
2458
2458
2459 <rev1>
2459 <rev1>
2460 <successors-1A>
2460 <successors-1A>
2461 <rev2>
2461 <rev2>
2462 <successors-2A>
2462 <successors-2A>
2463 <successors-2B1> <successors-2B2> <successors-2B3>
2463 <successors-2B1> <successors-2B2> <successors-2B3>
2464
2464
2465 Here rev2 has two possible (i.e. divergent) successors sets. The first
2465 Here rev2 has two possible (i.e. divergent) successors sets. The first
2466 holds one element, whereas the second holds three (i.e. the changeset has
2466 holds one element, whereas the second holds three (i.e. the changeset has
2467 been split).
2467 been split).
2468 """
2468 """
2469 # passed to successorssets caching computation from one call to another
2469 # passed to successorssets caching computation from one call to another
2470 cache = {}
2470 cache = {}
2471 ctx2str = str
2471 ctx2str = str
2472 node2str = short
2472 node2str = short
2473 if ui.debug():
2473 if ui.debug():
2474 def ctx2str(ctx):
2474 def ctx2str(ctx):
2475 return ctx.hex()
2475 return ctx.hex()
2476 node2str = hex
2476 node2str = hex
2477 for rev in scmutil.revrange(repo, revs):
2477 for rev in scmutil.revrange(repo, revs):
2478 ctx = repo[rev]
2478 ctx = repo[rev]
2479 ui.write('%s\n'% ctx2str(ctx))
2479 ui.write('%s\n'% ctx2str(ctx))
2480 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2480 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2481 if succsset:
2481 if succsset:
2482 ui.write(' ')
2482 ui.write(' ')
2483 ui.write(node2str(succsset[0]))
2483 ui.write(node2str(succsset[0]))
2484 for node in succsset[1:]:
2484 for node in succsset[1:]:
2485 ui.write(' ')
2485 ui.write(' ')
2486 ui.write(node2str(node))
2486 ui.write(node2str(node))
2487 ui.write('\n')
2487 ui.write('\n')
2488
2488
2489 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2489 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2490 def debugwalk(ui, repo, *pats, **opts):
2490 def debugwalk(ui, repo, *pats, **opts):
2491 """show how files match on given patterns"""
2491 """show how files match on given patterns"""
2492 m = scmutil.match(repo[None], pats, opts)
2492 m = scmutil.match(repo[None], pats, opts)
2493 items = list(repo.walk(m))
2493 items = list(repo.walk(m))
2494 if not items:
2494 if not items:
2495 return
2495 return
2496 f = lambda fn: fn
2496 f = lambda fn: fn
2497 if ui.configbool('ui', 'slash') and os.sep != '/':
2497 if ui.configbool('ui', 'slash') and os.sep != '/':
2498 f = lambda fn: util.normpath(fn)
2498 f = lambda fn: util.normpath(fn)
2499 fmt = 'f %%-%ds %%-%ds %%s' % (
2499 fmt = 'f %%-%ds %%-%ds %%s' % (
2500 max([len(abs) for abs in items]),
2500 max([len(abs) for abs in items]),
2501 max([len(m.rel(abs)) for abs in items]))
2501 max([len(m.rel(abs)) for abs in items]))
2502 for abs in items:
2502 for abs in items:
2503 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2503 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2504 ui.write("%s\n" % line.rstrip())
2504 ui.write("%s\n" % line.rstrip())
2505
2505
2506 @command('debugwireargs',
2506 @command('debugwireargs',
2507 [('', 'three', '', 'three'),
2507 [('', 'three', '', 'three'),
2508 ('', 'four', '', 'four'),
2508 ('', 'four', '', 'four'),
2509 ('', 'five', '', 'five'),
2509 ('', 'five', '', 'five'),
2510 ] + remoteopts,
2510 ] + remoteopts,
2511 _('REPO [OPTIONS]... [ONE [TWO]]'))
2511 _('REPO [OPTIONS]... [ONE [TWO]]'))
2512 def debugwireargs(ui, repopath, *vals, **opts):
2512 def debugwireargs(ui, repopath, *vals, **opts):
2513 repo = hg.peer(ui, opts, repopath)
2513 repo = hg.peer(ui, opts, repopath)
2514 for opt in remoteopts:
2514 for opt in remoteopts:
2515 del opts[opt[1]]
2515 del opts[opt[1]]
2516 args = {}
2516 args = {}
2517 for k, v in opts.iteritems():
2517 for k, v in opts.iteritems():
2518 if v:
2518 if v:
2519 args[k] = v
2519 args[k] = v
2520 # run twice to check that we don't mess up the stream for the next command
2520 # run twice to check that we don't mess up the stream for the next command
2521 res1 = repo.debugwireargs(*vals, **args)
2521 res1 = repo.debugwireargs(*vals, **args)
2522 res2 = repo.debugwireargs(*vals, **args)
2522 res2 = repo.debugwireargs(*vals, **args)
2523 ui.write("%s\n" % res1)
2523 ui.write("%s\n" % res1)
2524 if res1 != res2:
2524 if res1 != res2:
2525 ui.warn("%s\n" % res2)
2525 ui.warn("%s\n" % res2)
2526
2526
2527 @command('^diff',
2527 @command('^diff',
2528 [('r', 'rev', [], _('revision'), _('REV')),
2528 [('r', 'rev', [], _('revision'), _('REV')),
2529 ('c', 'change', '', _('change made by revision'), _('REV'))
2529 ('c', 'change', '', _('change made by revision'), _('REV'))
2530 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2530 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2531 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2531 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2532 def diff(ui, repo, *pats, **opts):
2532 def diff(ui, repo, *pats, **opts):
2533 """diff repository (or selected files)
2533 """diff repository (or selected files)
2534
2534
2535 Show differences between revisions for the specified files.
2535 Show differences between revisions for the specified files.
2536
2536
2537 Differences between files are shown using the unified diff format.
2537 Differences between files are shown using the unified diff format.
2538
2538
2539 .. note::
2539 .. note::
2540 diff may generate unexpected results for merges, as it will
2540 diff may generate unexpected results for merges, as it will
2541 default to comparing against the working directory's first
2541 default to comparing against the working directory's first
2542 parent changeset if no revisions are specified.
2542 parent changeset if no revisions are specified.
2543
2543
2544 When two revision arguments are given, then changes are shown
2544 When two revision arguments are given, then changes are shown
2545 between those revisions. If only one revision is specified then
2545 between those revisions. If only one revision is specified then
2546 that revision is compared to the working directory, and, when no
2546 that revision is compared to the working directory, and, when no
2547 revisions are specified, the working directory files are compared
2547 revisions are specified, the working directory files are compared
2548 to its parent.
2548 to its parent.
2549
2549
2550 Alternatively you can specify -c/--change with a revision to see
2550 Alternatively you can specify -c/--change with a revision to see
2551 the changes in that changeset relative to its first parent.
2551 the changes in that changeset relative to its first parent.
2552
2552
2553 Without the -a/--text option, diff will avoid generating diffs of
2553 Without the -a/--text option, diff will avoid generating diffs of
2554 files it detects as binary. With -a, diff will generate a diff
2554 files it detects as binary. With -a, diff will generate a diff
2555 anyway, probably with undesirable results.
2555 anyway, probably with undesirable results.
2556
2556
2557 Use the -g/--git option to generate diffs in the git extended diff
2557 Use the -g/--git option to generate diffs in the git extended diff
2558 format. For more information, read :hg:`help diffs`.
2558 format. For more information, read :hg:`help diffs`.
2559
2559
2560 .. container:: verbose
2560 .. container:: verbose
2561
2561
2562 Examples:
2562 Examples:
2563
2563
2564 - compare a file in the current working directory to its parent::
2564 - compare a file in the current working directory to its parent::
2565
2565
2566 hg diff foo.c
2566 hg diff foo.c
2567
2567
2568 - compare two historical versions of a directory, with rename info::
2568 - compare two historical versions of a directory, with rename info::
2569
2569
2570 hg diff --git -r 1.0:1.2 lib/
2570 hg diff --git -r 1.0:1.2 lib/
2571
2571
2572 - get change stats relative to the last change on some date::
2572 - get change stats relative to the last change on some date::
2573
2573
2574 hg diff --stat -r "date('may 2')"
2574 hg diff --stat -r "date('may 2')"
2575
2575
2576 - diff all newly-added files that contain a keyword::
2576 - diff all newly-added files that contain a keyword::
2577
2577
2578 hg diff "set:added() and grep(GNU)"
2578 hg diff "set:added() and grep(GNU)"
2579
2579
2580 - compare a revision and its parents::
2580 - compare a revision and its parents::
2581
2581
2582 hg diff -c 9353 # compare against first parent
2582 hg diff -c 9353 # compare against first parent
2583 hg diff -r 9353^:9353 # same using revset syntax
2583 hg diff -r 9353^:9353 # same using revset syntax
2584 hg diff -r 9353^2:9353 # compare against the second parent
2584 hg diff -r 9353^2:9353 # compare against the second parent
2585
2585
2586 Returns 0 on success.
2586 Returns 0 on success.
2587 """
2587 """
2588
2588
2589 revs = opts.get('rev')
2589 revs = opts.get('rev')
2590 change = opts.get('change')
2590 change = opts.get('change')
2591 stat = opts.get('stat')
2591 stat = opts.get('stat')
2592 reverse = opts.get('reverse')
2592 reverse = opts.get('reverse')
2593
2593
2594 if revs and change:
2594 if revs and change:
2595 msg = _('cannot specify --rev and --change at the same time')
2595 msg = _('cannot specify --rev and --change at the same time')
2596 raise util.Abort(msg)
2596 raise util.Abort(msg)
2597 elif change:
2597 elif change:
2598 node2 = scmutil.revsingle(repo, change, None).node()
2598 node2 = scmutil.revsingle(repo, change, None).node()
2599 node1 = repo[node2].p1().node()
2599 node1 = repo[node2].p1().node()
2600 else:
2600 else:
2601 node1, node2 = scmutil.revpair(repo, revs)
2601 node1, node2 = scmutil.revpair(repo, revs)
2602
2602
2603 if reverse:
2603 if reverse:
2604 node1, node2 = node2, node1
2604 node1, node2 = node2, node1
2605
2605
2606 diffopts = patch.diffopts(ui, opts)
2606 diffopts = patch.diffopts(ui, opts)
2607 m = scmutil.match(repo[node2], pats, opts)
2607 m = scmutil.match(repo[node2], pats, opts)
2608 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2608 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2609 listsubrepos=opts.get('subrepos'))
2609 listsubrepos=opts.get('subrepos'))
2610
2610
2611 @command('^export',
2611 @command('^export',
2612 [('o', 'output', '',
2612 [('o', 'output', '',
2613 _('print output to file with formatted name'), _('FORMAT')),
2613 _('print output to file with formatted name'), _('FORMAT')),
2614 ('', 'switch-parent', None, _('diff against the second parent')),
2614 ('', 'switch-parent', None, _('diff against the second parent')),
2615 ('r', 'rev', [], _('revisions to export'), _('REV')),
2615 ('r', 'rev', [], _('revisions to export'), _('REV')),
2616 ] + diffopts,
2616 ] + diffopts,
2617 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2617 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2618 def export(ui, repo, *changesets, **opts):
2618 def export(ui, repo, *changesets, **opts):
2619 """dump the header and diffs for one or more changesets
2619 """dump the header and diffs for one or more changesets
2620
2620
2621 Print the changeset header and diffs for one or more revisions.
2621 Print the changeset header and diffs for one or more revisions.
2622
2622
2623 The information shown in the changeset header is: author, date,
2623 The information shown in the changeset header is: author, date,
2624 branch name (if non-default), changeset hash, parent(s) and commit
2624 branch name (if non-default), changeset hash, parent(s) and commit
2625 comment.
2625 comment.
2626
2626
2627 .. note::
2627 .. note::
2628 export may generate unexpected diff output for merge
2628 export may generate unexpected diff output for merge
2629 changesets, as it will compare the merge changeset against its
2629 changesets, as it will compare the merge changeset against its
2630 first parent only.
2630 first parent only.
2631
2631
2632 Output may be to a file, in which case the name of the file is
2632 Output may be to a file, in which case the name of the file is
2633 given using a format string. The formatting rules are as follows:
2633 given using a format string. The formatting rules are as follows:
2634
2634
2635 :``%%``: literal "%" character
2635 :``%%``: literal "%" character
2636 :``%H``: changeset hash (40 hexadecimal digits)
2636 :``%H``: changeset hash (40 hexadecimal digits)
2637 :``%N``: number of patches being generated
2637 :``%N``: number of patches being generated
2638 :``%R``: changeset revision number
2638 :``%R``: changeset revision number
2639 :``%b``: basename of the exporting repository
2639 :``%b``: basename of the exporting repository
2640 :``%h``: short-form changeset hash (12 hexadecimal digits)
2640 :``%h``: short-form changeset hash (12 hexadecimal digits)
2641 :``%m``: first line of the commit message (only alphanumeric characters)
2641 :``%m``: first line of the commit message (only alphanumeric characters)
2642 :``%n``: zero-padded sequence number, starting at 1
2642 :``%n``: zero-padded sequence number, starting at 1
2643 :``%r``: zero-padded changeset revision number
2643 :``%r``: zero-padded changeset revision number
2644
2644
2645 Without the -a/--text option, export will avoid generating diffs
2645 Without the -a/--text option, export will avoid generating diffs
2646 of files it detects as binary. With -a, export will generate a
2646 of files it detects as binary. With -a, export will generate a
2647 diff anyway, probably with undesirable results.
2647 diff anyway, probably with undesirable results.
2648
2648
2649 Use the -g/--git option to generate diffs in the git extended diff
2649 Use the -g/--git option to generate diffs in the git extended diff
2650 format. See :hg:`help diffs` for more information.
2650 format. See :hg:`help diffs` for more information.
2651
2651
2652 With the --switch-parent option, the diff will be against the
2652 With the --switch-parent option, the diff will be against the
2653 second parent. It can be useful to review a merge.
2653 second parent. It can be useful to review a merge.
2654
2654
2655 .. container:: verbose
2655 .. container:: verbose
2656
2656
2657 Examples:
2657 Examples:
2658
2658
2659 - use export and import to transplant a bugfix to the current
2659 - use export and import to transplant a bugfix to the current
2660 branch::
2660 branch::
2661
2661
2662 hg export -r 9353 | hg import -
2662 hg export -r 9353 | hg import -
2663
2663
2664 - export all the changesets between two revisions to a file with
2664 - export all the changesets between two revisions to a file with
2665 rename information::
2665 rename information::
2666
2666
2667 hg export --git -r 123:150 > changes.txt
2667 hg export --git -r 123:150 > changes.txt
2668
2668
2669 - split outgoing changes into a series of patches with
2669 - split outgoing changes into a series of patches with
2670 descriptive names::
2670 descriptive names::
2671
2671
2672 hg export -r "outgoing()" -o "%n-%m.patch"
2672 hg export -r "outgoing()" -o "%n-%m.patch"
2673
2673
2674 Returns 0 on success.
2674 Returns 0 on success.
2675 """
2675 """
2676 changesets += tuple(opts.get('rev', []))
2676 changesets += tuple(opts.get('rev', []))
2677 revs = scmutil.revrange(repo, changesets)
2677 revs = scmutil.revrange(repo, changesets)
2678 if not revs:
2678 if not revs:
2679 raise util.Abort(_("export requires at least one changeset"))
2679 raise util.Abort(_("export requires at least one changeset"))
2680 if len(revs) > 1:
2680 if len(revs) > 1:
2681 ui.note(_('exporting patches:\n'))
2681 ui.note(_('exporting patches:\n'))
2682 else:
2682 else:
2683 ui.note(_('exporting patch:\n'))
2683 ui.note(_('exporting patch:\n'))
2684 cmdutil.export(repo, revs, template=opts.get('output'),
2684 cmdutil.export(repo, revs, template=opts.get('output'),
2685 switch_parent=opts.get('switch_parent'),
2685 switch_parent=opts.get('switch_parent'),
2686 opts=patch.diffopts(ui, opts))
2686 opts=patch.diffopts(ui, opts))
2687
2687
2688 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2688 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2689 def forget(ui, repo, *pats, **opts):
2689 def forget(ui, repo, *pats, **opts):
2690 """forget the specified files on the next commit
2690 """forget the specified files on the next commit
2691
2691
2692 Mark the specified files so they will no longer be tracked
2692 Mark the specified files so they will no longer be tracked
2693 after the next commit.
2693 after the next commit.
2694
2694
2695 This only removes files from the current branch, not from the
2695 This only removes files from the current branch, not from the
2696 entire project history, and it does not delete them from the
2696 entire project history, and it does not delete them from the
2697 working directory.
2697 working directory.
2698
2698
2699 To undo a forget before the next commit, see :hg:`add`.
2699 To undo a forget before the next commit, see :hg:`add`.
2700
2700
2701 .. container:: verbose
2701 .. container:: verbose
2702
2702
2703 Examples:
2703 Examples:
2704
2704
2705 - forget newly-added binary files::
2705 - forget newly-added binary files::
2706
2706
2707 hg forget "set:added() and binary()"
2707 hg forget "set:added() and binary()"
2708
2708
2709 - forget files that would be excluded by .hgignore::
2709 - forget files that would be excluded by .hgignore::
2710
2710
2711 hg forget "set:hgignore()"
2711 hg forget "set:hgignore()"
2712
2712
2713 Returns 0 on success.
2713 Returns 0 on success.
2714 """
2714 """
2715
2715
2716 if not pats:
2716 if not pats:
2717 raise util.Abort(_('no files specified'))
2717 raise util.Abort(_('no files specified'))
2718
2718
2719 m = scmutil.match(repo[None], pats, opts)
2719 m = scmutil.match(repo[None], pats, opts)
2720 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2720 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2721 return rejected and 1 or 0
2721 return rejected and 1 or 0
2722
2722
2723 @command(
2723 @command(
2724 'graft',
2724 'graft',
2725 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2725 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2726 ('c', 'continue', False, _('resume interrupted graft')),
2726 ('c', 'continue', False, _('resume interrupted graft')),
2727 ('e', 'edit', False, _('invoke editor on commit messages')),
2727 ('e', 'edit', False, _('invoke editor on commit messages')),
2728 ('', 'log', None, _('append graft info to log message')),
2728 ('', 'log', None, _('append graft info to log message')),
2729 ('D', 'currentdate', False,
2729 ('D', 'currentdate', False,
2730 _('record the current date as commit date')),
2730 _('record the current date as commit date')),
2731 ('U', 'currentuser', False,
2731 ('U', 'currentuser', False,
2732 _('record the current user as committer'), _('DATE'))]
2732 _('record the current user as committer'), _('DATE'))]
2733 + commitopts2 + mergetoolopts + dryrunopts,
2733 + commitopts2 + mergetoolopts + dryrunopts,
2734 _('[OPTION]... [-r] REV...'))
2734 _('[OPTION]... [-r] REV...'))
2735 def graft(ui, repo, *revs, **opts):
2735 def graft(ui, repo, *revs, **opts):
2736 '''copy changes from other branches onto the current branch
2736 '''copy changes from other branches onto the current branch
2737
2737
2738 This command uses Mercurial's merge logic to copy individual
2738 This command uses Mercurial's merge logic to copy individual
2739 changes from other branches without merging branches in the
2739 changes from other branches without merging branches in the
2740 history graph. This is sometimes known as 'backporting' or
2740 history graph. This is sometimes known as 'backporting' or
2741 'cherry-picking'. By default, graft will copy user, date, and
2741 'cherry-picking'. By default, graft will copy user, date, and
2742 description from the source changesets.
2742 description from the source changesets.
2743
2743
2744 Changesets that are ancestors of the current revision, that have
2744 Changesets that are ancestors of the current revision, that have
2745 already been grafted, or that are merges will be skipped.
2745 already been grafted, or that are merges will be skipped.
2746
2746
2747 If --log is specified, log messages will have a comment appended
2747 If --log is specified, log messages will have a comment appended
2748 of the form::
2748 of the form::
2749
2749
2750 (grafted from CHANGESETHASH)
2750 (grafted from CHANGESETHASH)
2751
2751
2752 If a graft merge results in conflicts, the graft process is
2752 If a graft merge results in conflicts, the graft process is
2753 interrupted so that the current merge can be manually resolved.
2753 interrupted so that the current merge can be manually resolved.
2754 Once all conflicts are addressed, the graft process can be
2754 Once all conflicts are addressed, the graft process can be
2755 continued with the -c/--continue option.
2755 continued with the -c/--continue option.
2756
2756
2757 .. note::
2757 .. note::
2758 The -c/--continue option does not reapply earlier options.
2758 The -c/--continue option does not reapply earlier options.
2759
2759
2760 .. container:: verbose
2760 .. container:: verbose
2761
2761
2762 Examples:
2762 Examples:
2763
2763
2764 - copy a single change to the stable branch and edit its description::
2764 - copy a single change to the stable branch and edit its description::
2765
2765
2766 hg update stable
2766 hg update stable
2767 hg graft --edit 9393
2767 hg graft --edit 9393
2768
2768
2769 - graft a range of changesets with one exception, updating dates::
2769 - graft a range of changesets with one exception, updating dates::
2770
2770
2771 hg graft -D "2085::2093 and not 2091"
2771 hg graft -D "2085::2093 and not 2091"
2772
2772
2773 - continue a graft after resolving conflicts::
2773 - continue a graft after resolving conflicts::
2774
2774
2775 hg graft -c
2775 hg graft -c
2776
2776
2777 - show the source of a grafted changeset::
2777 - show the source of a grafted changeset::
2778
2778
2779 hg log --debug -r tip
2779 hg log --debug -r tip
2780
2780
2781 Returns 0 on successful completion.
2781 Returns 0 on successful completion.
2782 '''
2782 '''
2783
2783
2784 revs = list(revs)
2784 revs = list(revs)
2785 revs.extend(opts['rev'])
2785 revs.extend(opts['rev'])
2786
2786
2787 if not opts.get('user') and opts.get('currentuser'):
2787 if not opts.get('user') and opts.get('currentuser'):
2788 opts['user'] = ui.username()
2788 opts['user'] = ui.username()
2789 if not opts.get('date') and opts.get('currentdate'):
2789 if not opts.get('date') and opts.get('currentdate'):
2790 opts['date'] = "%d %d" % util.makedate()
2790 opts['date'] = "%d %d" % util.makedate()
2791
2791
2792 editor = None
2792 editor = None
2793 if opts.get('edit'):
2793 if opts.get('edit'):
2794 editor = cmdutil.commitforceeditor
2794 editor = cmdutil.commitforceeditor
2795
2795
2796 cont = False
2796 cont = False
2797 if opts['continue']:
2797 if opts['continue']:
2798 cont = True
2798 cont = True
2799 if revs:
2799 if revs:
2800 raise util.Abort(_("can't specify --continue and revisions"))
2800 raise util.Abort(_("can't specify --continue and revisions"))
2801 # read in unfinished revisions
2801 # read in unfinished revisions
2802 try:
2802 try:
2803 nodes = repo.opener.read('graftstate').splitlines()
2803 nodes = repo.opener.read('graftstate').splitlines()
2804 revs = [repo[node].rev() for node in nodes]
2804 revs = [repo[node].rev() for node in nodes]
2805 except IOError, inst:
2805 except IOError, inst:
2806 if inst.errno != errno.ENOENT:
2806 if inst.errno != errno.ENOENT:
2807 raise
2807 raise
2808 raise util.Abort(_("no graft state found, can't continue"))
2808 raise util.Abort(_("no graft state found, can't continue"))
2809 else:
2809 else:
2810 cmdutil.bailifchanged(repo)
2810 cmdutil.bailifchanged(repo)
2811 if not revs:
2811 if not revs:
2812 raise util.Abort(_('no revisions specified'))
2812 raise util.Abort(_('no revisions specified'))
2813 revs = scmutil.revrange(repo, revs)
2813 revs = scmutil.revrange(repo, revs)
2814
2814
2815 # check for merges
2815 # check for merges
2816 for rev in repo.revs('%ld and merge()', revs):
2816 for rev in repo.revs('%ld and merge()', revs):
2817 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2817 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2818 revs.remove(rev)
2818 revs.remove(rev)
2819 if not revs:
2819 if not revs:
2820 return -1
2820 return -1
2821
2821
2822 # check for ancestors of dest branch
2822 # check for ancestors of dest branch
2823 for rev in repo.revs('::. and %ld', revs):
2823 for rev in repo.revs('::. and %ld', revs):
2824 ui.warn(_('skipping ancestor revision %s\n') % rev)
2824 ui.warn(_('skipping ancestor revision %s\n') % rev)
2825 revs.remove(rev)
2825 revs.remove(rev)
2826 if not revs:
2826 if not revs:
2827 return -1
2827 return -1
2828
2828
2829 # analyze revs for earlier grafts
2829 # analyze revs for earlier grafts
2830 ids = {}
2830 ids = {}
2831 for ctx in repo.set("%ld", revs):
2831 for ctx in repo.set("%ld", revs):
2832 ids[ctx.hex()] = ctx.rev()
2832 ids[ctx.hex()] = ctx.rev()
2833 n = ctx.extra().get('source')
2833 n = ctx.extra().get('source')
2834 if n:
2834 if n:
2835 ids[n] = ctx.rev()
2835 ids[n] = ctx.rev()
2836
2836
2837 # check ancestors for earlier grafts
2837 # check ancestors for earlier grafts
2838 ui.debug('scanning for duplicate grafts\n')
2838 ui.debug('scanning for duplicate grafts\n')
2839 for ctx in repo.set("::. - ::%ld", revs):
2839 for ctx in repo.set("::. - ::%ld", revs):
2840 n = ctx.extra().get('source')
2840 n = ctx.extra().get('source')
2841 if n in ids:
2841 if n in ids:
2842 r = repo[n].rev()
2842 r = repo[n].rev()
2843 if r in revs:
2843 if r in revs:
2844 ui.warn(_('skipping already grafted revision %s\n') % r)
2844 ui.warn(_('skipping already grafted revision %s\n') % r)
2845 revs.remove(r)
2845 revs.remove(r)
2846 elif ids[n] in revs:
2846 elif ids[n] in revs:
2847 ui.warn(_('skipping already grafted revision %s '
2847 ui.warn(_('skipping already grafted revision %s '
2848 '(same origin %d)\n') % (ids[n], r))
2848 '(same origin %d)\n') % (ids[n], r))
2849 revs.remove(ids[n])
2849 revs.remove(ids[n])
2850 elif ctx.hex() in ids:
2850 elif ctx.hex() in ids:
2851 r = ids[ctx.hex()]
2851 r = ids[ctx.hex()]
2852 ui.warn(_('skipping already grafted revision %s '
2852 ui.warn(_('skipping already grafted revision %s '
2853 '(was grafted from %d)\n') % (r, ctx.rev()))
2853 '(was grafted from %d)\n') % (r, ctx.rev()))
2854 revs.remove(r)
2854 revs.remove(r)
2855 if not revs:
2855 if not revs:
2856 return -1
2856 return -1
2857
2857
2858 wlock = repo.wlock()
2858 wlock = repo.wlock()
2859 try:
2859 try:
2860 current = repo['.']
2860 current = repo['.']
2861 for pos, ctx in enumerate(repo.set("%ld", revs)):
2861 for pos, ctx in enumerate(repo.set("%ld", revs)):
2862
2862
2863 ui.status(_('grafting revision %s\n') % ctx.rev())
2863 ui.status(_('grafting revision %s\n') % ctx.rev())
2864 if opts.get('dry_run'):
2864 if opts.get('dry_run'):
2865 continue
2865 continue
2866
2866
2867 source = ctx.extra().get('source')
2867 source = ctx.extra().get('source')
2868 if not source:
2868 if not source:
2869 source = ctx.hex()
2869 source = ctx.hex()
2870 extra = {'source': source}
2870 extra = {'source': source}
2871 user = ctx.user()
2871 user = ctx.user()
2872 if opts.get('user'):
2872 if opts.get('user'):
2873 user = opts['user']
2873 user = opts['user']
2874 date = ctx.date()
2874 date = ctx.date()
2875 if opts.get('date'):
2875 if opts.get('date'):
2876 date = opts['date']
2876 date = opts['date']
2877 message = ctx.description()
2877 message = ctx.description()
2878 if opts.get('log'):
2878 if opts.get('log'):
2879 message += '\n(grafted from %s)' % ctx.hex()
2879 message += '\n(grafted from %s)' % ctx.hex()
2880
2880
2881 # we don't merge the first commit when continuing
2881 # we don't merge the first commit when continuing
2882 if not cont:
2882 if not cont:
2883 # perform the graft merge with p1(rev) as 'ancestor'
2883 # perform the graft merge with p1(rev) as 'ancestor'
2884 try:
2884 try:
2885 # ui.forcemerge is an internal variable, do not document
2885 # ui.forcemerge is an internal variable, do not document
2886 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2886 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2887 stats = mergemod.update(repo, ctx.node(), True, True, False,
2887 stats = mergemod.update(repo, ctx.node(), True, True, False,
2888 ctx.p1().node())
2888 ctx.p1().node())
2889 finally:
2889 finally:
2890 repo.ui.setconfig('ui', 'forcemerge', '')
2890 repo.ui.setconfig('ui', 'forcemerge', '')
2891 # report any conflicts
2891 # report any conflicts
2892 if stats and stats[3] > 0:
2892 if stats and stats[3] > 0:
2893 # write out state for --continue
2893 # write out state for --continue
2894 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2894 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2895 repo.opener.write('graftstate', ''.join(nodelines))
2895 repo.opener.write('graftstate', ''.join(nodelines))
2896 raise util.Abort(
2896 raise util.Abort(
2897 _("unresolved conflicts, can't continue"),
2897 _("unresolved conflicts, can't continue"),
2898 hint=_('use hg resolve and hg graft --continue'))
2898 hint=_('use hg resolve and hg graft --continue'))
2899 else:
2899 else:
2900 cont = False
2900 cont = False
2901
2901
2902 # drop the second merge parent
2902 # drop the second merge parent
2903 repo.setparents(current.node(), nullid)
2903 repo.setparents(current.node(), nullid)
2904 repo.dirstate.write()
2904 repo.dirstate.write()
2905 # fix up dirstate for copies and renames
2905 # fix up dirstate for copies and renames
2906 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2906 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2907
2907
2908 # commit
2908 # commit
2909 node = repo.commit(text=message, user=user,
2909 node = repo.commit(text=message, user=user,
2910 date=date, extra=extra, editor=editor)
2910 date=date, extra=extra, editor=editor)
2911 if node is None:
2911 if node is None:
2912 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2912 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2913 else:
2913 else:
2914 current = repo[node]
2914 current = repo[node]
2915 finally:
2915 finally:
2916 wlock.release()
2916 wlock.release()
2917
2917
2918 # remove state when we complete successfully
2918 # remove state when we complete successfully
2919 if not opts.get('dry_run'):
2919 if not opts.get('dry_run'):
2920 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2920 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2921
2921
2922 return 0
2922 return 0
2923
2923
2924 @command('grep',
2924 @command('grep',
2925 [('0', 'print0', None, _('end fields with NUL')),
2925 [('0', 'print0', None, _('end fields with NUL')),
2926 ('', 'all', None, _('print all revisions that match')),
2926 ('', 'all', None, _('print all revisions that match')),
2927 ('a', 'text', None, _('treat all files as text')),
2927 ('a', 'text', None, _('treat all files as text')),
2928 ('f', 'follow', None,
2928 ('f', 'follow', None,
2929 _('follow changeset history,'
2929 _('follow changeset history,'
2930 ' or file history across copies and renames')),
2930 ' or file history across copies and renames')),
2931 ('i', 'ignore-case', None, _('ignore case when matching')),
2931 ('i', 'ignore-case', None, _('ignore case when matching')),
2932 ('l', 'files-with-matches', None,
2932 ('l', 'files-with-matches', None,
2933 _('print only filenames and revisions that match')),
2933 _('print only filenames and revisions that match')),
2934 ('n', 'line-number', None, _('print matching line numbers')),
2934 ('n', 'line-number', None, _('print matching line numbers')),
2935 ('r', 'rev', [],
2935 ('r', 'rev', [],
2936 _('only search files changed within revision range'), _('REV')),
2936 _('only search files changed within revision range'), _('REV')),
2937 ('u', 'user', None, _('list the author (long with -v)')),
2937 ('u', 'user', None, _('list the author (long with -v)')),
2938 ('d', 'date', None, _('list the date (short with -q)')),
2938 ('d', 'date', None, _('list the date (short with -q)')),
2939 ] + walkopts,
2939 ] + walkopts,
2940 _('[OPTION]... PATTERN [FILE]...'))
2940 _('[OPTION]... PATTERN [FILE]...'))
2941 def grep(ui, repo, pattern, *pats, **opts):
2941 def grep(ui, repo, pattern, *pats, **opts):
2942 """search for a pattern in specified files and revisions
2942 """search for a pattern in specified files and revisions
2943
2943
2944 Search revisions of files for a regular expression.
2944 Search revisions of files for a regular expression.
2945
2945
2946 This command behaves differently than Unix grep. It only accepts
2946 This command behaves differently than Unix grep. It only accepts
2947 Python/Perl regexps. It searches repository history, not the
2947 Python/Perl regexps. It searches repository history, not the
2948 working directory. It always prints the revision number in which a
2948 working directory. It always prints the revision number in which a
2949 match appears.
2949 match appears.
2950
2950
2951 By default, grep only prints output for the first revision of a
2951 By default, grep only prints output for the first revision of a
2952 file in which it finds a match. To get it to print every revision
2952 file in which it finds a match. To get it to print every revision
2953 that contains a change in match status ("-" for a match that
2953 that contains a change in match status ("-" for a match that
2954 becomes a non-match, or "+" for a non-match that becomes a match),
2954 becomes a non-match, or "+" for a non-match that becomes a match),
2955 use the --all flag.
2955 use the --all flag.
2956
2956
2957 Returns 0 if a match is found, 1 otherwise.
2957 Returns 0 if a match is found, 1 otherwise.
2958 """
2958 """
2959 reflags = re.M
2959 reflags = re.M
2960 if opts.get('ignore_case'):
2960 if opts.get('ignore_case'):
2961 reflags |= re.I
2961 reflags |= re.I
2962 try:
2962 try:
2963 regexp = re.compile(pattern, reflags)
2963 regexp = re.compile(pattern, reflags)
2964 except re.error, inst:
2964 except re.error, inst:
2965 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2965 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2966 return 1
2966 return 1
2967 sep, eol = ':', '\n'
2967 sep, eol = ':', '\n'
2968 if opts.get('print0'):
2968 if opts.get('print0'):
2969 sep = eol = '\0'
2969 sep = eol = '\0'
2970
2970
2971 getfile = util.lrucachefunc(repo.file)
2971 getfile = util.lrucachefunc(repo.file)
2972
2972
2973 def matchlines(body):
2973 def matchlines(body):
2974 begin = 0
2974 begin = 0
2975 linenum = 0
2975 linenum = 0
2976 while begin < len(body):
2976 while begin < len(body):
2977 match = regexp.search(body, begin)
2977 match = regexp.search(body, begin)
2978 if not match:
2978 if not match:
2979 break
2979 break
2980 mstart, mend = match.span()
2980 mstart, mend = match.span()
2981 linenum += body.count('\n', begin, mstart) + 1
2981 linenum += body.count('\n', begin, mstart) + 1
2982 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2982 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2983 begin = body.find('\n', mend) + 1 or len(body) + 1
2983 begin = body.find('\n', mend) + 1 or len(body) + 1
2984 lend = begin - 1
2984 lend = begin - 1
2985 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2985 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2986
2986
2987 class linestate(object):
2987 class linestate(object):
2988 def __init__(self, line, linenum, colstart, colend):
2988 def __init__(self, line, linenum, colstart, colend):
2989 self.line = line
2989 self.line = line
2990 self.linenum = linenum
2990 self.linenum = linenum
2991 self.colstart = colstart
2991 self.colstart = colstart
2992 self.colend = colend
2992 self.colend = colend
2993
2993
2994 def __hash__(self):
2994 def __hash__(self):
2995 return hash((self.linenum, self.line))
2995 return hash((self.linenum, self.line))
2996
2996
2997 def __eq__(self, other):
2997 def __eq__(self, other):
2998 return self.line == other.line
2998 return self.line == other.line
2999
2999
3000 matches = {}
3000 matches = {}
3001 copies = {}
3001 copies = {}
3002 def grepbody(fn, rev, body):
3002 def grepbody(fn, rev, body):
3003 matches[rev].setdefault(fn, [])
3003 matches[rev].setdefault(fn, [])
3004 m = matches[rev][fn]
3004 m = matches[rev][fn]
3005 for lnum, cstart, cend, line in matchlines(body):
3005 for lnum, cstart, cend, line in matchlines(body):
3006 s = linestate(line, lnum, cstart, cend)
3006 s = linestate(line, lnum, cstart, cend)
3007 m.append(s)
3007 m.append(s)
3008
3008
3009 def difflinestates(a, b):
3009 def difflinestates(a, b):
3010 sm = difflib.SequenceMatcher(None, a, b)
3010 sm = difflib.SequenceMatcher(None, a, b)
3011 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3011 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3012 if tag == 'insert':
3012 if tag == 'insert':
3013 for i in xrange(blo, bhi):
3013 for i in xrange(blo, bhi):
3014 yield ('+', b[i])
3014 yield ('+', b[i])
3015 elif tag == 'delete':
3015 elif tag == 'delete':
3016 for i in xrange(alo, ahi):
3016 for i in xrange(alo, ahi):
3017 yield ('-', a[i])
3017 yield ('-', a[i])
3018 elif tag == 'replace':
3018 elif tag == 'replace':
3019 for i in xrange(alo, ahi):
3019 for i in xrange(alo, ahi):
3020 yield ('-', a[i])
3020 yield ('-', a[i])
3021 for i in xrange(blo, bhi):
3021 for i in xrange(blo, bhi):
3022 yield ('+', b[i])
3022 yield ('+', b[i])
3023
3023
3024 def display(fn, ctx, pstates, states):
3024 def display(fn, ctx, pstates, states):
3025 rev = ctx.rev()
3025 rev = ctx.rev()
3026 datefunc = ui.quiet and util.shortdate or util.datestr
3026 datefunc = ui.quiet and util.shortdate or util.datestr
3027 found = False
3027 found = False
3028 filerevmatches = {}
3028 filerevmatches = {}
3029 def binary():
3029 def binary():
3030 flog = getfile(fn)
3030 flog = getfile(fn)
3031 return util.binary(flog.read(ctx.filenode(fn)))
3031 return util.binary(flog.read(ctx.filenode(fn)))
3032
3032
3033 if opts.get('all'):
3033 if opts.get('all'):
3034 iter = difflinestates(pstates, states)
3034 iter = difflinestates(pstates, states)
3035 else:
3035 else:
3036 iter = [('', l) for l in states]
3036 iter = [('', l) for l in states]
3037 for change, l in iter:
3037 for change, l in iter:
3038 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3038 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3039 before, match, after = None, None, None
3039 before, match, after = None, None, None
3040
3040
3041 if opts.get('line_number'):
3041 if opts.get('line_number'):
3042 cols.append((str(l.linenum), 'grep.linenumber'))
3042 cols.append((str(l.linenum), 'grep.linenumber'))
3043 if opts.get('all'):
3043 if opts.get('all'):
3044 cols.append((change, 'grep.change'))
3044 cols.append((change, 'grep.change'))
3045 if opts.get('user'):
3045 if opts.get('user'):
3046 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3046 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3047 if opts.get('date'):
3047 if opts.get('date'):
3048 cols.append((datefunc(ctx.date()), 'grep.date'))
3048 cols.append((datefunc(ctx.date()), 'grep.date'))
3049 if opts.get('files_with_matches'):
3049 if opts.get('files_with_matches'):
3050 c = (fn, rev)
3050 c = (fn, rev)
3051 if c in filerevmatches:
3051 if c in filerevmatches:
3052 continue
3052 continue
3053 filerevmatches[c] = 1
3053 filerevmatches[c] = 1
3054 else:
3054 else:
3055 before = l.line[:l.colstart]
3055 before = l.line[:l.colstart]
3056 match = l.line[l.colstart:l.colend]
3056 match = l.line[l.colstart:l.colend]
3057 after = l.line[l.colend:]
3057 after = l.line[l.colend:]
3058 for col, label in cols[:-1]:
3058 for col, label in cols[:-1]:
3059 ui.write(col, label=label)
3059 ui.write(col, label=label)
3060 ui.write(sep, label='grep.sep')
3060 ui.write(sep, label='grep.sep')
3061 ui.write(cols[-1][0], label=cols[-1][1])
3061 ui.write(cols[-1][0], label=cols[-1][1])
3062 if before is not None:
3062 if before is not None:
3063 ui.write(sep, label='grep.sep')
3063 ui.write(sep, label='grep.sep')
3064 if not opts.get('text') and binary():
3064 if not opts.get('text') and binary():
3065 ui.write(" Binary file matches")
3065 ui.write(" Binary file matches")
3066 else:
3066 else:
3067 ui.write(before)
3067 ui.write(before)
3068 ui.write(match, label='grep.match')
3068 ui.write(match, label='grep.match')
3069 ui.write(after)
3069 ui.write(after)
3070 ui.write(eol)
3070 ui.write(eol)
3071 found = True
3071 found = True
3072 return found
3072 return found
3073
3073
3074 skip = {}
3074 skip = {}
3075 revfiles = {}
3075 revfiles = {}
3076 matchfn = scmutil.match(repo[None], pats, opts)
3076 matchfn = scmutil.match(repo[None], pats, opts)
3077 found = False
3077 found = False
3078 follow = opts.get('follow')
3078 follow = opts.get('follow')
3079
3079
3080 def prep(ctx, fns):
3080 def prep(ctx, fns):
3081 rev = ctx.rev()
3081 rev = ctx.rev()
3082 pctx = ctx.p1()
3082 pctx = ctx.p1()
3083 parent = pctx.rev()
3083 parent = pctx.rev()
3084 matches.setdefault(rev, {})
3084 matches.setdefault(rev, {})
3085 matches.setdefault(parent, {})
3085 matches.setdefault(parent, {})
3086 files = revfiles.setdefault(rev, [])
3086 files = revfiles.setdefault(rev, [])
3087 for fn in fns:
3087 for fn in fns:
3088 flog = getfile(fn)
3088 flog = getfile(fn)
3089 try:
3089 try:
3090 fnode = ctx.filenode(fn)
3090 fnode = ctx.filenode(fn)
3091 except error.LookupError:
3091 except error.LookupError:
3092 continue
3092 continue
3093
3093
3094 copied = flog.renamed(fnode)
3094 copied = flog.renamed(fnode)
3095 copy = follow and copied and copied[0]
3095 copy = follow and copied and copied[0]
3096 if copy:
3096 if copy:
3097 copies.setdefault(rev, {})[fn] = copy
3097 copies.setdefault(rev, {})[fn] = copy
3098 if fn in skip:
3098 if fn in skip:
3099 if copy:
3099 if copy:
3100 skip[copy] = True
3100 skip[copy] = True
3101 continue
3101 continue
3102 files.append(fn)
3102 files.append(fn)
3103
3103
3104 if fn not in matches[rev]:
3104 if fn not in matches[rev]:
3105 grepbody(fn, rev, flog.read(fnode))
3105 grepbody(fn, rev, flog.read(fnode))
3106
3106
3107 pfn = copy or fn
3107 pfn = copy or fn
3108 if pfn not in matches[parent]:
3108 if pfn not in matches[parent]:
3109 try:
3109 try:
3110 fnode = pctx.filenode(pfn)
3110 fnode = pctx.filenode(pfn)
3111 grepbody(pfn, parent, flog.read(fnode))
3111 grepbody(pfn, parent, flog.read(fnode))
3112 except error.LookupError:
3112 except error.LookupError:
3113 pass
3113 pass
3114
3114
3115 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3115 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3116 rev = ctx.rev()
3116 rev = ctx.rev()
3117 parent = ctx.p1().rev()
3117 parent = ctx.p1().rev()
3118 for fn in sorted(revfiles.get(rev, [])):
3118 for fn in sorted(revfiles.get(rev, [])):
3119 states = matches[rev][fn]
3119 states = matches[rev][fn]
3120 copy = copies.get(rev, {}).get(fn)
3120 copy = copies.get(rev, {}).get(fn)
3121 if fn in skip:
3121 if fn in skip:
3122 if copy:
3122 if copy:
3123 skip[copy] = True
3123 skip[copy] = True
3124 continue
3124 continue
3125 pstates = matches.get(parent, {}).get(copy or fn, [])
3125 pstates = matches.get(parent, {}).get(copy or fn, [])
3126 if pstates or states:
3126 if pstates or states:
3127 r = display(fn, ctx, pstates, states)
3127 r = display(fn, ctx, pstates, states)
3128 found = found or r
3128 found = found or r
3129 if r and not opts.get('all'):
3129 if r and not opts.get('all'):
3130 skip[fn] = True
3130 skip[fn] = True
3131 if copy:
3131 if copy:
3132 skip[copy] = True
3132 skip[copy] = True
3133 del matches[rev]
3133 del matches[rev]
3134 del revfiles[rev]
3134 del revfiles[rev]
3135
3135
3136 return not found
3136 return not found
3137
3137
3138 @command('heads',
3138 @command('heads',
3139 [('r', 'rev', '',
3139 [('r', 'rev', '',
3140 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3140 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3141 ('t', 'topo', False, _('show topological heads only')),
3141 ('t', 'topo', False, _('show topological heads only')),
3142 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3142 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3143 ('c', 'closed', False, _('show normal and closed branch heads')),
3143 ('c', 'closed', False, _('show normal and closed branch heads')),
3144 ] + templateopts,
3144 ] + templateopts,
3145 _('[-ct] [-r STARTREV] [REV]...'))
3145 _('[-ct] [-r STARTREV] [REV]...'))
3146 def heads(ui, repo, *branchrevs, **opts):
3146 def heads(ui, repo, *branchrevs, **opts):
3147 """show current repository heads or show branch heads
3147 """show current repository heads or show branch heads
3148
3148
3149 With no arguments, show all repository branch heads.
3149 With no arguments, show all repository branch heads.
3150
3150
3151 Repository "heads" are changesets with no child changesets. They are
3151 Repository "heads" are changesets with no child changesets. They are
3152 where development generally takes place and are the usual targets
3152 where development generally takes place and are the usual targets
3153 for update and merge operations. Branch heads are changesets that have
3153 for update and merge operations. Branch heads are changesets that have
3154 no child changeset on the same branch.
3154 no child changeset on the same branch.
3155
3155
3156 If one or more REVs are given, only branch heads on the branches
3156 If one or more REVs are given, only branch heads on the branches
3157 associated with the specified changesets are shown. This means
3157 associated with the specified changesets are shown. This means
3158 that you can use :hg:`heads foo` to see the heads on a branch
3158 that you can use :hg:`heads foo` to see the heads on a branch
3159 named ``foo``.
3159 named ``foo``.
3160
3160
3161 If -c/--closed is specified, also show branch heads marked closed
3161 If -c/--closed is specified, also show branch heads marked closed
3162 (see :hg:`commit --close-branch`).
3162 (see :hg:`commit --close-branch`).
3163
3163
3164 If STARTREV is specified, only those heads that are descendants of
3164 If STARTREV is specified, only those heads that are descendants of
3165 STARTREV will be displayed.
3165 STARTREV will be displayed.
3166
3166
3167 If -t/--topo is specified, named branch mechanics will be ignored and only
3167 If -t/--topo is specified, named branch mechanics will be ignored and only
3168 changesets without children will be shown.
3168 changesets without children will be shown.
3169
3169
3170 Returns 0 if matching heads are found, 1 if not.
3170 Returns 0 if matching heads are found, 1 if not.
3171 """
3171 """
3172
3172
3173 start = None
3173 start = None
3174 if 'rev' in opts:
3174 if 'rev' in opts:
3175 start = scmutil.revsingle(repo, opts['rev'], None).node()
3175 start = scmutil.revsingle(repo, opts['rev'], None).node()
3176
3176
3177 if opts.get('topo'):
3177 if opts.get('topo'):
3178 heads = [repo[h] for h in repo.heads(start)]
3178 heads = [repo[h] for h in repo.heads(start)]
3179 else:
3179 else:
3180 heads = []
3180 heads = []
3181 for branch in repo.branchmap():
3181 for branch in repo.branchmap():
3182 heads += repo.branchheads(branch, start, opts.get('closed'))
3182 heads += repo.branchheads(branch, start, opts.get('closed'))
3183 heads = [repo[h] for h in heads]
3183 heads = [repo[h] for h in heads]
3184
3184
3185 if branchrevs:
3185 if branchrevs:
3186 branches = set(repo[br].branch() for br in branchrevs)
3186 branches = set(repo[br].branch() for br in branchrevs)
3187 heads = [h for h in heads if h.branch() in branches]
3187 heads = [h for h in heads if h.branch() in branches]
3188
3188
3189 if opts.get('active') and branchrevs:
3189 if opts.get('active') and branchrevs:
3190 dagheads = repo.heads(start)
3190 dagheads = repo.heads(start)
3191 heads = [h for h in heads if h.node() in dagheads]
3191 heads = [h for h in heads if h.node() in dagheads]
3192
3192
3193 if branchrevs:
3193 if branchrevs:
3194 haveheads = set(h.branch() for h in heads)
3194 haveheads = set(h.branch() for h in heads)
3195 if branches - haveheads:
3195 if branches - haveheads:
3196 headless = ', '.join(b for b in branches - haveheads)
3196 headless = ', '.join(b for b in branches - haveheads)
3197 msg = _('no open branch heads found on branches %s')
3197 msg = _('no open branch heads found on branches %s')
3198 if opts.get('rev'):
3198 if opts.get('rev'):
3199 msg += _(' (started at %s)') % opts['rev']
3199 msg += _(' (started at %s)') % opts['rev']
3200 ui.warn((msg + '\n') % headless)
3200 ui.warn((msg + '\n') % headless)
3201
3201
3202 if not heads:
3202 if not heads:
3203 return 1
3203 return 1
3204
3204
3205 heads = sorted(heads, key=lambda x: -x.rev())
3205 heads = sorted(heads, key=lambda x: -x.rev())
3206 displayer = cmdutil.show_changeset(ui, repo, opts)
3206 displayer = cmdutil.show_changeset(ui, repo, opts)
3207 for ctx in heads:
3207 for ctx in heads:
3208 displayer.show(ctx)
3208 displayer.show(ctx)
3209 displayer.close()
3209 displayer.close()
3210
3210
3211 @command('help',
3211 @command('help',
3212 [('e', 'extension', None, _('show only help for extensions')),
3212 [('e', 'extension', None, _('show only help for extensions')),
3213 ('c', 'command', None, _('show only help for commands')),
3213 ('c', 'command', None, _('show only help for commands')),
3214 ('k', 'keyword', '', _('show topics matching keyword')),
3214 ('k', 'keyword', '', _('show topics matching keyword')),
3215 ],
3215 ],
3216 _('[-ec] [TOPIC]'))
3216 _('[-ec] [TOPIC]'))
3217 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3217 def help_(ui, name=None, **opts):
3218 """show help for a given topic or a help overview
3218 """show help for a given topic or a help overview
3219
3219
3220 With no arguments, print a list of commands with short help messages.
3220 With no arguments, print a list of commands with short help messages.
3221
3221
3222 Given a topic, extension, or command name, print help for that
3222 Given a topic, extension, or command name, print help for that
3223 topic.
3223 topic.
3224
3224
3225 Returns 0 if successful.
3225 Returns 0 if successful.
3226 """
3226 """
3227
3227
3228 textwidth = min(ui.termwidth(), 80) - 2
3228 textwidth = min(ui.termwidth(), 80) - 2
3229
3229
3230 def helpcmd(name):
3231 try:
3232 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3233 except error.AmbiguousCommand, inst:
3234 # py3k fix: except vars can't be used outside the scope of the
3235 # except block, nor can be used inside a lambda. python issue4617
3236 prefix = inst.args[0]
3237 select = lambda c: c.lstrip('^').startswith(prefix)
3238 rst = helplist(select)
3239 return rst
3240
3241 rst = []
3242
3243 # check if it's an invalid alias and display its error if it is
3244 if getattr(entry[0], 'badalias', False):
3245 if not unknowncmd:
3246 ui.pushbuffer()
3247 entry[0](ui)
3248 rst.append(ui.popbuffer())
3249 return rst
3250
3251 # synopsis
3252 if len(entry) > 2:
3253 if entry[2].startswith('hg'):
3254 rst.append("%s\n" % entry[2])
3255 else:
3256 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3257 else:
3258 rst.append('hg %s\n' % aliases[0])
3259 # aliases
3260 if full and not ui.quiet and len(aliases) > 1:
3261 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3262 rst.append('\n')
3263
3264 # description
3265 doc = gettext(entry[0].__doc__)
3266 if not doc:
3267 doc = _("(no help text available)")
3268 if util.safehasattr(entry[0], 'definition'): # aliased command
3269 if entry[0].definition.startswith('!'): # shell alias
3270 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3271 else:
3272 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3273 doc = doc.splitlines(True)
3274 if ui.quiet or not full:
3275 rst.append(doc[0])
3276 else:
3277 rst.extend(doc)
3278 rst.append('\n')
3279
3280 # check if this command shadows a non-trivial (multi-line)
3281 # extension help text
3282 try:
3283 mod = extensions.find(name)
3284 doc = gettext(mod.__doc__) or ''
3285 if '\n' in doc.strip():
3286 msg = _('use "hg help -e %s" to show help for '
3287 'the %s extension') % (name, name)
3288 rst.append('\n%s\n' % msg)
3289 except KeyError:
3290 pass
3291
3292 # options
3293 if not ui.quiet and entry[1]:
3294 rst.append('\n%s\n\n' % _("options:"))
3295 rst.append(help.optrst(entry[1], ui.verbose))
3296
3297 if ui.verbose:
3298 rst.append('\n%s\n\n' % _("global options:"))
3299 rst.append(help.optrst(globalopts, ui.verbose))
3300
3301 if not ui.verbose:
3302 if not full:
3303 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3304 % name)
3305 elif not ui.quiet:
3306 omitted = _('use "hg -v help %s" to show more complete'
3307 ' help and the global options') % name
3308 notomitted = _('use "hg -v help %s" to show'
3309 ' the global options') % name
3310 help.indicateomitted(rst, omitted, notomitted)
3311
3312 return rst
3313
3314
3315 def helplist(select=None):
3316 # list of commands
3317 if name == "shortlist":
3318 header = _('basic commands:\n\n')
3319 else:
3320 header = _('list of commands:\n\n')
3321
3322 h = {}
3323 cmds = {}
3324 for c, e in table.iteritems():
3325 f = c.split("|", 1)[0]
3326 if select and not select(f):
3327 continue
3328 if (not select and name != 'shortlist' and
3329 e[0].__module__ != __name__):
3330 continue
3331 if name == "shortlist" and not f.startswith("^"):
3332 continue
3333 f = f.lstrip("^")
3334 if not ui.debugflag and f.startswith("debug"):
3335 continue
3336 doc = e[0].__doc__
3337 if doc and 'DEPRECATED' in doc and not ui.verbose:
3338 continue
3339 doc = gettext(doc)
3340 if not doc:
3341 doc = _("(no help text available)")
3342 h[f] = doc.splitlines()[0].rstrip()
3343 cmds[f] = c.lstrip("^")
3344
3345 rst = []
3346 if not h:
3347 if not ui.quiet:
3348 rst.append(_('no commands defined\n'))
3349 return rst
3350
3351 if not ui.quiet:
3352 rst.append(header)
3353 fns = sorted(h)
3354 for f in fns:
3355 if ui.verbose:
3356 commands = cmds[f].replace("|",", ")
3357 rst.append(" :%s: %s\n" % (commands, h[f]))
3358 else:
3359 rst.append(' :%s: %s\n' % (f, h[f]))
3360
3361 if not name:
3362 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3363 if exts:
3364 rst.append('\n')
3365 rst.extend(exts)
3366
3367 rst.append(_("\nadditional help topics:\n\n"))
3368 topics = []
3369 for names, header, doc in help.helptable:
3370 topics.append((names[0], header))
3371 for t, desc in topics:
3372 rst.append(" :%s: %s\n" % (t, desc))
3373
3374 optlist = []
3375 if not ui.quiet:
3376 if ui.verbose:
3377 optlist.append((_("global options:"), globalopts))
3378 if name == 'shortlist':
3379 optlist.append((_('use "hg help" for the full list '
3380 'of commands'), ()))
3381 else:
3382 if name == 'shortlist':
3383 msg = _('use "hg help" for the full list of commands '
3384 'or "hg -v" for details')
3385 elif name and not full:
3386 msg = _('use "hg help %s" to show the full help '
3387 'text') % name
3388 else:
3389 msg = _('use "hg -v help%s" to show builtin aliases and '
3390 'global options') % (name and " " + name or "")
3391 optlist.append((msg, ()))
3392
3393 if optlist:
3394 for title, options in optlist:
3395 rst.append('\n%s\n' % title)
3396 if options:
3397 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3398 return rst
3399
3400 def helptopic(name):
3401 for names, header, doc in help.helptable:
3402 if name in names:
3403 break
3404 else:
3405 raise error.UnknownCommand(name)
3406
3407 rst = ["%s\n\n" % header]
3408 # description
3409 if not doc:
3410 rst.append(" %s\n" % _("(no help text available)"))
3411 if util.safehasattr(doc, '__call__'):
3412 rst += [" %s\n" % l for l in doc().splitlines()]
3413
3414 if not ui.verbose:
3415 omitted = (_('use "hg help -v %s" to show more complete help') %
3416 name)
3417 help.indicateomitted(rst, omitted)
3418
3419 try:
3420 cmdutil.findcmd(name, table)
3421 rst.append(_('\nuse "hg help -c %s" to see help for '
3422 'the %s command\n') % (name, name))
3423 except error.UnknownCommand:
3424 pass
3425 return rst
3426
3427 def helpext(name):
3428 try:
3429 mod = extensions.find(name)
3430 doc = gettext(mod.__doc__) or _('no help text available')
3431 except KeyError:
3432 mod = None
3433 doc = extensions.disabledext(name)
3434 if not doc:
3435 raise error.UnknownCommand(name)
3436
3437 if '\n' not in doc:
3438 head, tail = doc, ""
3439 else:
3440 head, tail = doc.split('\n', 1)
3441 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3442 if tail:
3443 rst.extend(tail.splitlines(True))
3444 rst.append('\n')
3445
3446 if not ui.verbose:
3447 omitted = (_('use "hg help -v %s" to show more complete help') %
3448 name)
3449 help.indicateomitted(rst, omitted)
3450
3451 if mod:
3452 try:
3453 ct = mod.cmdtable
3454 except AttributeError:
3455 ct = {}
3456 modcmds = set([c.split('|', 1)[0] for c in ct])
3457 rst.extend(helplist(modcmds.__contains__))
3458 else:
3459 rst.append(_('use "hg help extensions" for information on enabling '
3460 'extensions\n'))
3461 return rst
3462
3463 def helpextcmd(name):
3464 cmd, ext, mod = extensions.disabledcmd(ui, name,
3465 ui.configbool('ui', 'strict'))
3466 doc = gettext(mod.__doc__).splitlines()[0]
3467
3468 rst = help.listexts(_("'%s' is provided by the following "
3469 "extension:") % cmd, {ext: doc}, indent=4)
3470 rst.append('\n')
3471 rst.append(_('use "hg help extensions" for information on enabling '
3472 'extensions\n'))
3473 return rst
3474
3475
3476 rst = []
3477 kw = opts.get('keyword')
3478 if kw:
3479 matches = help.topicmatch(kw)
3480 for t, title in (('topics', _('Topics')),
3481 ('commands', _('Commands')),
3482 ('extensions', _('Extensions')),
3483 ('extensioncommands', _('Extension Commands'))):
3484 if matches[t]:
3485 rst.append('%s:\n\n' % title)
3486 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3487 rst.append('\n')
3488 elif name and name != 'shortlist':
3489 i = None
3490 if unknowncmd:
3491 queries = (helpextcmd,)
3492 elif opts.get('extension'):
3493 queries = (helpext,)
3494 elif opts.get('command'):
3495 queries = (helpcmd,)
3496 else:
3497 queries = (helptopic, helpcmd, helpext, helpextcmd)
3498 for f in queries:
3499 try:
3500 rst = f(name)
3501 i = None
3502 break
3503 except error.UnknownCommand, inst:
3504 i = inst
3505 if i:
3506 raise i
3507 else:
3508 # program name
3509 if not ui.quiet:
3510 rst = [_("Mercurial Distributed SCM\n"), '\n']
3511 rst.extend(helplist())
3512
3513 keep = ui.verbose and ['verbose'] or []
3230 keep = ui.verbose and ['verbose'] or []
3514 text = ''.join(rst)
3231 text = help.help_(ui, name, **opts)
3232
3515 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3233 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3516 if 'verbose' in pruned:
3234 if 'verbose' in pruned:
3517 keep.append('omitted')
3235 keep.append('omitted')
3518 else:
3236 else:
3519 keep.append('notomitted')
3237 keep.append('notomitted')
3520 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3238 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3521 ui.write(formatted)
3239 ui.write(formatted)
3522
3240
3523
3241
3524 @command('identify|id',
3242 @command('identify|id',
3525 [('r', 'rev', '',
3243 [('r', 'rev', '',
3526 _('identify the specified revision'), _('REV')),
3244 _('identify the specified revision'), _('REV')),
3527 ('n', 'num', None, _('show local revision number')),
3245 ('n', 'num', None, _('show local revision number')),
3528 ('i', 'id', None, _('show global revision id')),
3246 ('i', 'id', None, _('show global revision id')),
3529 ('b', 'branch', None, _('show branch')),
3247 ('b', 'branch', None, _('show branch')),
3530 ('t', 'tags', None, _('show tags')),
3248 ('t', 'tags', None, _('show tags')),
3531 ('B', 'bookmarks', None, _('show bookmarks')),
3249 ('B', 'bookmarks', None, _('show bookmarks')),
3532 ] + remoteopts,
3250 ] + remoteopts,
3533 _('[-nibtB] [-r REV] [SOURCE]'))
3251 _('[-nibtB] [-r REV] [SOURCE]'))
3534 def identify(ui, repo, source=None, rev=None,
3252 def identify(ui, repo, source=None, rev=None,
3535 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3253 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3536 """identify the working copy or specified revision
3254 """identify the working copy or specified revision
3537
3255
3538 Print a summary identifying the repository state at REV using one or
3256 Print a summary identifying the repository state at REV using one or
3539 two parent hash identifiers, followed by a "+" if the working
3257 two parent hash identifiers, followed by a "+" if the working
3540 directory has uncommitted changes, the branch name (if not default),
3258 directory has uncommitted changes, the branch name (if not default),
3541 a list of tags, and a list of bookmarks.
3259 a list of tags, and a list of bookmarks.
3542
3260
3543 When REV is not given, print a summary of the current state of the
3261 When REV is not given, print a summary of the current state of the
3544 repository.
3262 repository.
3545
3263
3546 Specifying a path to a repository root or Mercurial bundle will
3264 Specifying a path to a repository root or Mercurial bundle will
3547 cause lookup to operate on that repository/bundle.
3265 cause lookup to operate on that repository/bundle.
3548
3266
3549 .. container:: verbose
3267 .. container:: verbose
3550
3268
3551 Examples:
3269 Examples:
3552
3270
3553 - generate a build identifier for the working directory::
3271 - generate a build identifier for the working directory::
3554
3272
3555 hg id --id > build-id.dat
3273 hg id --id > build-id.dat
3556
3274
3557 - find the revision corresponding to a tag::
3275 - find the revision corresponding to a tag::
3558
3276
3559 hg id -n -r 1.3
3277 hg id -n -r 1.3
3560
3278
3561 - check the most recent revision of a remote repository::
3279 - check the most recent revision of a remote repository::
3562
3280
3563 hg id -r tip http://selenic.com/hg/
3281 hg id -r tip http://selenic.com/hg/
3564
3282
3565 Returns 0 if successful.
3283 Returns 0 if successful.
3566 """
3284 """
3567
3285
3568 if not repo and not source:
3286 if not repo and not source:
3569 raise util.Abort(_("there is no Mercurial repository here "
3287 raise util.Abort(_("there is no Mercurial repository here "
3570 "(.hg not found)"))
3288 "(.hg not found)"))
3571
3289
3572 hexfunc = ui.debugflag and hex or short
3290 hexfunc = ui.debugflag and hex or short
3573 default = not (num or id or branch or tags or bookmarks)
3291 default = not (num or id or branch or tags or bookmarks)
3574 output = []
3292 output = []
3575 revs = []
3293 revs = []
3576
3294
3577 if source:
3295 if source:
3578 source, branches = hg.parseurl(ui.expandpath(source))
3296 source, branches = hg.parseurl(ui.expandpath(source))
3579 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3297 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3580 repo = peer.local()
3298 repo = peer.local()
3581 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3299 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3582
3300
3583 if not repo:
3301 if not repo:
3584 if num or branch or tags:
3302 if num or branch or tags:
3585 raise util.Abort(
3303 raise util.Abort(
3586 _("can't query remote revision number, branch, or tags"))
3304 _("can't query remote revision number, branch, or tags"))
3587 if not rev and revs:
3305 if not rev and revs:
3588 rev = revs[0]
3306 rev = revs[0]
3589 if not rev:
3307 if not rev:
3590 rev = "tip"
3308 rev = "tip"
3591
3309
3592 remoterev = peer.lookup(rev)
3310 remoterev = peer.lookup(rev)
3593 if default or id:
3311 if default or id:
3594 output = [hexfunc(remoterev)]
3312 output = [hexfunc(remoterev)]
3595
3313
3596 def getbms():
3314 def getbms():
3597 bms = []
3315 bms = []
3598
3316
3599 if 'bookmarks' in peer.listkeys('namespaces'):
3317 if 'bookmarks' in peer.listkeys('namespaces'):
3600 hexremoterev = hex(remoterev)
3318 hexremoterev = hex(remoterev)
3601 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3319 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3602 if bmr == hexremoterev]
3320 if bmr == hexremoterev]
3603
3321
3604 return sorted(bms)
3322 return sorted(bms)
3605
3323
3606 if bookmarks:
3324 if bookmarks:
3607 output.extend(getbms())
3325 output.extend(getbms())
3608 elif default and not ui.quiet:
3326 elif default and not ui.quiet:
3609 # multiple bookmarks for a single parent separated by '/'
3327 # multiple bookmarks for a single parent separated by '/'
3610 bm = '/'.join(getbms())
3328 bm = '/'.join(getbms())
3611 if bm:
3329 if bm:
3612 output.append(bm)
3330 output.append(bm)
3613 else:
3331 else:
3614 if not rev:
3332 if not rev:
3615 ctx = repo[None]
3333 ctx = repo[None]
3616 parents = ctx.parents()
3334 parents = ctx.parents()
3617 changed = ""
3335 changed = ""
3618 if default or id or num:
3336 if default or id or num:
3619 if (util.any(repo.status())
3337 if (util.any(repo.status())
3620 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3338 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3621 changed = '+'
3339 changed = '+'
3622 if default or id:
3340 if default or id:
3623 output = ["%s%s" %
3341 output = ["%s%s" %
3624 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3342 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3625 if num:
3343 if num:
3626 output.append("%s%s" %
3344 output.append("%s%s" %
3627 ('+'.join([str(p.rev()) for p in parents]), changed))
3345 ('+'.join([str(p.rev()) for p in parents]), changed))
3628 else:
3346 else:
3629 ctx = scmutil.revsingle(repo, rev)
3347 ctx = scmutil.revsingle(repo, rev)
3630 if default or id:
3348 if default or id:
3631 output = [hexfunc(ctx.node())]
3349 output = [hexfunc(ctx.node())]
3632 if num:
3350 if num:
3633 output.append(str(ctx.rev()))
3351 output.append(str(ctx.rev()))
3634
3352
3635 if default and not ui.quiet:
3353 if default and not ui.quiet:
3636 b = ctx.branch()
3354 b = ctx.branch()
3637 if b != 'default':
3355 if b != 'default':
3638 output.append("(%s)" % b)
3356 output.append("(%s)" % b)
3639
3357
3640 # multiple tags for a single parent separated by '/'
3358 # multiple tags for a single parent separated by '/'
3641 t = '/'.join(ctx.tags())
3359 t = '/'.join(ctx.tags())
3642 if t:
3360 if t:
3643 output.append(t)
3361 output.append(t)
3644
3362
3645 # multiple bookmarks for a single parent separated by '/'
3363 # multiple bookmarks for a single parent separated by '/'
3646 bm = '/'.join(ctx.bookmarks())
3364 bm = '/'.join(ctx.bookmarks())
3647 if bm:
3365 if bm:
3648 output.append(bm)
3366 output.append(bm)
3649 else:
3367 else:
3650 if branch:
3368 if branch:
3651 output.append(ctx.branch())
3369 output.append(ctx.branch())
3652
3370
3653 if tags:
3371 if tags:
3654 output.extend(ctx.tags())
3372 output.extend(ctx.tags())
3655
3373
3656 if bookmarks:
3374 if bookmarks:
3657 output.extend(ctx.bookmarks())
3375 output.extend(ctx.bookmarks())
3658
3376
3659 ui.write("%s\n" % ' '.join(output))
3377 ui.write("%s\n" % ' '.join(output))
3660
3378
3661 @command('import|patch',
3379 @command('import|patch',
3662 [('p', 'strip', 1,
3380 [('p', 'strip', 1,
3663 _('directory strip option for patch. This has the same '
3381 _('directory strip option for patch. This has the same '
3664 'meaning as the corresponding patch option'), _('NUM')),
3382 'meaning as the corresponding patch option'), _('NUM')),
3665 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3383 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3666 ('e', 'edit', False, _('invoke editor on commit messages')),
3384 ('e', 'edit', False, _('invoke editor on commit messages')),
3667 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3385 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3668 ('', 'no-commit', None,
3386 ('', 'no-commit', None,
3669 _("don't commit, just update the working directory")),
3387 _("don't commit, just update the working directory")),
3670 ('', 'bypass', None,
3388 ('', 'bypass', None,
3671 _("apply patch without touching the working directory")),
3389 _("apply patch without touching the working directory")),
3672 ('', 'exact', None,
3390 ('', 'exact', None,
3673 _('apply patch to the nodes from which it was generated')),
3391 _('apply patch to the nodes from which it was generated')),
3674 ('', 'import-branch', None,
3392 ('', 'import-branch', None,
3675 _('use any branch information in patch (implied by --exact)'))] +
3393 _('use any branch information in patch (implied by --exact)'))] +
3676 commitopts + commitopts2 + similarityopts,
3394 commitopts + commitopts2 + similarityopts,
3677 _('[OPTION]... PATCH...'))
3395 _('[OPTION]... PATCH...'))
3678 def import_(ui, repo, patch1=None, *patches, **opts):
3396 def import_(ui, repo, patch1=None, *patches, **opts):
3679 """import an ordered set of patches
3397 """import an ordered set of patches
3680
3398
3681 Import a list of patches and commit them individually (unless
3399 Import a list of patches and commit them individually (unless
3682 --no-commit is specified).
3400 --no-commit is specified).
3683
3401
3684 If there are outstanding changes in the working directory, import
3402 If there are outstanding changes in the working directory, import
3685 will abort unless given the -f/--force flag.
3403 will abort unless given the -f/--force flag.
3686
3404
3687 You can import a patch straight from a mail message. Even patches
3405 You can import a patch straight from a mail message. Even patches
3688 as attachments work (to use the body part, it must have type
3406 as attachments work (to use the body part, it must have type
3689 text/plain or text/x-patch). From and Subject headers of email
3407 text/plain or text/x-patch). From and Subject headers of email
3690 message are used as default committer and commit message. All
3408 message are used as default committer and commit message. All
3691 text/plain body parts before first diff are added to commit
3409 text/plain body parts before first diff are added to commit
3692 message.
3410 message.
3693
3411
3694 If the imported patch was generated by :hg:`export`, user and
3412 If the imported patch was generated by :hg:`export`, user and
3695 description from patch override values from message headers and
3413 description from patch override values from message headers and
3696 body. Values given on command line with -m/--message and -u/--user
3414 body. Values given on command line with -m/--message and -u/--user
3697 override these.
3415 override these.
3698
3416
3699 If --exact is specified, import will set the working directory to
3417 If --exact is specified, import will set the working directory to
3700 the parent of each patch before applying it, and will abort if the
3418 the parent of each patch before applying it, and will abort if the
3701 resulting changeset has a different ID than the one recorded in
3419 resulting changeset has a different ID than the one recorded in
3702 the patch. This may happen due to character set problems or other
3420 the patch. This may happen due to character set problems or other
3703 deficiencies in the text patch format.
3421 deficiencies in the text patch format.
3704
3422
3705 Use --bypass to apply and commit patches directly to the
3423 Use --bypass to apply and commit patches directly to the
3706 repository, not touching the working directory. Without --exact,
3424 repository, not touching the working directory. Without --exact,
3707 patches will be applied on top of the working directory parent
3425 patches will be applied on top of the working directory parent
3708 revision.
3426 revision.
3709
3427
3710 With -s/--similarity, hg will attempt to discover renames and
3428 With -s/--similarity, hg will attempt to discover renames and
3711 copies in the patch in the same way as :hg:`addremove`.
3429 copies in the patch in the same way as :hg:`addremove`.
3712
3430
3713 To read a patch from standard input, use "-" as the patch name. If
3431 To read a patch from standard input, use "-" as the patch name. If
3714 a URL is specified, the patch will be downloaded from it.
3432 a URL is specified, the patch will be downloaded from it.
3715 See :hg:`help dates` for a list of formats valid for -d/--date.
3433 See :hg:`help dates` for a list of formats valid for -d/--date.
3716
3434
3717 .. container:: verbose
3435 .. container:: verbose
3718
3436
3719 Examples:
3437 Examples:
3720
3438
3721 - import a traditional patch from a website and detect renames::
3439 - import a traditional patch from a website and detect renames::
3722
3440
3723 hg import -s 80 http://example.com/bugfix.patch
3441 hg import -s 80 http://example.com/bugfix.patch
3724
3442
3725 - import a changeset from an hgweb server::
3443 - import a changeset from an hgweb server::
3726
3444
3727 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3445 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3728
3446
3729 - import all the patches in an Unix-style mbox::
3447 - import all the patches in an Unix-style mbox::
3730
3448
3731 hg import incoming-patches.mbox
3449 hg import incoming-patches.mbox
3732
3450
3733 - attempt to exactly restore an exported changeset (not always
3451 - attempt to exactly restore an exported changeset (not always
3734 possible)::
3452 possible)::
3735
3453
3736 hg import --exact proposed-fix.patch
3454 hg import --exact proposed-fix.patch
3737
3455
3738 Returns 0 on success.
3456 Returns 0 on success.
3739 """
3457 """
3740
3458
3741 if not patch1:
3459 if not patch1:
3742 raise util.Abort(_('need at least one patch to import'))
3460 raise util.Abort(_('need at least one patch to import'))
3743
3461
3744 patches = (patch1,) + patches
3462 patches = (patch1,) + patches
3745
3463
3746 date = opts.get('date')
3464 date = opts.get('date')
3747 if date:
3465 if date:
3748 opts['date'] = util.parsedate(date)
3466 opts['date'] = util.parsedate(date)
3749
3467
3750 editor = cmdutil.commiteditor
3468 editor = cmdutil.commiteditor
3751 if opts.get('edit'):
3469 if opts.get('edit'):
3752 editor = cmdutil.commitforceeditor
3470 editor = cmdutil.commitforceeditor
3753
3471
3754 update = not opts.get('bypass')
3472 update = not opts.get('bypass')
3755 if not update and opts.get('no_commit'):
3473 if not update and opts.get('no_commit'):
3756 raise util.Abort(_('cannot use --no-commit with --bypass'))
3474 raise util.Abort(_('cannot use --no-commit with --bypass'))
3757 try:
3475 try:
3758 sim = float(opts.get('similarity') or 0)
3476 sim = float(opts.get('similarity') or 0)
3759 except ValueError:
3477 except ValueError:
3760 raise util.Abort(_('similarity must be a number'))
3478 raise util.Abort(_('similarity must be a number'))
3761 if sim < 0 or sim > 100:
3479 if sim < 0 or sim > 100:
3762 raise util.Abort(_('similarity must be between 0 and 100'))
3480 raise util.Abort(_('similarity must be between 0 and 100'))
3763 if sim and not update:
3481 if sim and not update:
3764 raise util.Abort(_('cannot use --similarity with --bypass'))
3482 raise util.Abort(_('cannot use --similarity with --bypass'))
3765
3483
3766 if (opts.get('exact') or not opts.get('force')) and update:
3484 if (opts.get('exact') or not opts.get('force')) and update:
3767 cmdutil.bailifchanged(repo)
3485 cmdutil.bailifchanged(repo)
3768
3486
3769 base = opts["base"]
3487 base = opts["base"]
3770 strip = opts["strip"]
3488 strip = opts["strip"]
3771 wlock = lock = tr = None
3489 wlock = lock = tr = None
3772 msgs = []
3490 msgs = []
3773
3491
3774 def checkexact(repo, n, nodeid):
3492 def checkexact(repo, n, nodeid):
3775 if opts.get('exact') and hex(n) != nodeid:
3493 if opts.get('exact') and hex(n) != nodeid:
3776 raise util.Abort(_('patch is damaged or loses information'))
3494 raise util.Abort(_('patch is damaged or loses information'))
3777
3495
3778 def tryone(ui, hunk, parents):
3496 def tryone(ui, hunk, parents):
3779 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3497 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3780 patch.extract(ui, hunk)
3498 patch.extract(ui, hunk)
3781
3499
3782 if not tmpname:
3500 if not tmpname:
3783 return (None, None)
3501 return (None, None)
3784 msg = _('applied to working directory')
3502 msg = _('applied to working directory')
3785
3503
3786 try:
3504 try:
3787 cmdline_message = cmdutil.logmessage(ui, opts)
3505 cmdline_message = cmdutil.logmessage(ui, opts)
3788 if cmdline_message:
3506 if cmdline_message:
3789 # pickup the cmdline msg
3507 # pickup the cmdline msg
3790 message = cmdline_message
3508 message = cmdline_message
3791 elif message:
3509 elif message:
3792 # pickup the patch msg
3510 # pickup the patch msg
3793 message = message.strip()
3511 message = message.strip()
3794 else:
3512 else:
3795 # launch the editor
3513 # launch the editor
3796 message = None
3514 message = None
3797 ui.debug('message:\n%s\n' % message)
3515 ui.debug('message:\n%s\n' % message)
3798
3516
3799 if len(parents) == 1:
3517 if len(parents) == 1:
3800 parents.append(repo[nullid])
3518 parents.append(repo[nullid])
3801 if opts.get('exact'):
3519 if opts.get('exact'):
3802 if not nodeid or not p1:
3520 if not nodeid or not p1:
3803 raise util.Abort(_('not a Mercurial patch'))
3521 raise util.Abort(_('not a Mercurial patch'))
3804 p1 = repo[p1]
3522 p1 = repo[p1]
3805 p2 = repo[p2 or nullid]
3523 p2 = repo[p2 or nullid]
3806 elif p2:
3524 elif p2:
3807 try:
3525 try:
3808 p1 = repo[p1]
3526 p1 = repo[p1]
3809 p2 = repo[p2]
3527 p2 = repo[p2]
3810 # Without any options, consider p2 only if the
3528 # Without any options, consider p2 only if the
3811 # patch is being applied on top of the recorded
3529 # patch is being applied on top of the recorded
3812 # first parent.
3530 # first parent.
3813 if p1 != parents[0]:
3531 if p1 != parents[0]:
3814 p1 = parents[0]
3532 p1 = parents[0]
3815 p2 = repo[nullid]
3533 p2 = repo[nullid]
3816 except error.RepoError:
3534 except error.RepoError:
3817 p1, p2 = parents
3535 p1, p2 = parents
3818 else:
3536 else:
3819 p1, p2 = parents
3537 p1, p2 = parents
3820
3538
3821 n = None
3539 n = None
3822 if update:
3540 if update:
3823 if p1 != parents[0]:
3541 if p1 != parents[0]:
3824 hg.clean(repo, p1.node())
3542 hg.clean(repo, p1.node())
3825 if p2 != parents[1]:
3543 if p2 != parents[1]:
3826 repo.setparents(p1.node(), p2.node())
3544 repo.setparents(p1.node(), p2.node())
3827
3545
3828 if opts.get('exact') or opts.get('import_branch'):
3546 if opts.get('exact') or opts.get('import_branch'):
3829 repo.dirstate.setbranch(branch or 'default')
3547 repo.dirstate.setbranch(branch or 'default')
3830
3548
3831 files = set()
3549 files = set()
3832 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3550 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3833 eolmode=None, similarity=sim / 100.0)
3551 eolmode=None, similarity=sim / 100.0)
3834 files = list(files)
3552 files = list(files)
3835 if opts.get('no_commit'):
3553 if opts.get('no_commit'):
3836 if message:
3554 if message:
3837 msgs.append(message)
3555 msgs.append(message)
3838 else:
3556 else:
3839 if opts.get('exact') or p2:
3557 if opts.get('exact') or p2:
3840 # If you got here, you either use --force and know what
3558 # If you got here, you either use --force and know what
3841 # you are doing or used --exact or a merge patch while
3559 # you are doing or used --exact or a merge patch while
3842 # being updated to its first parent.
3560 # being updated to its first parent.
3843 m = None
3561 m = None
3844 else:
3562 else:
3845 m = scmutil.matchfiles(repo, files or [])
3563 m = scmutil.matchfiles(repo, files or [])
3846 n = repo.commit(message, opts.get('user') or user,
3564 n = repo.commit(message, opts.get('user') or user,
3847 opts.get('date') or date, match=m,
3565 opts.get('date') or date, match=m,
3848 editor=editor)
3566 editor=editor)
3849 checkexact(repo, n, nodeid)
3567 checkexact(repo, n, nodeid)
3850 else:
3568 else:
3851 if opts.get('exact') or opts.get('import_branch'):
3569 if opts.get('exact') or opts.get('import_branch'):
3852 branch = branch or 'default'
3570 branch = branch or 'default'
3853 else:
3571 else:
3854 branch = p1.branch()
3572 branch = p1.branch()
3855 store = patch.filestore()
3573 store = patch.filestore()
3856 try:
3574 try:
3857 files = set()
3575 files = set()
3858 try:
3576 try:
3859 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3577 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3860 files, eolmode=None)
3578 files, eolmode=None)
3861 except patch.PatchError, e:
3579 except patch.PatchError, e:
3862 raise util.Abort(str(e))
3580 raise util.Abort(str(e))
3863 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3581 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3864 message,
3582 message,
3865 opts.get('user') or user,
3583 opts.get('user') or user,
3866 opts.get('date') or date,
3584 opts.get('date') or date,
3867 branch, files, store,
3585 branch, files, store,
3868 editor=cmdutil.commiteditor)
3586 editor=cmdutil.commiteditor)
3869 repo.savecommitmessage(memctx.description())
3587 repo.savecommitmessage(memctx.description())
3870 n = memctx.commit()
3588 n = memctx.commit()
3871 checkexact(repo, n, nodeid)
3589 checkexact(repo, n, nodeid)
3872 finally:
3590 finally:
3873 store.close()
3591 store.close()
3874 if n:
3592 if n:
3875 # i18n: refers to a short changeset id
3593 # i18n: refers to a short changeset id
3876 msg = _('created %s') % short(n)
3594 msg = _('created %s') % short(n)
3877 return (msg, n)
3595 return (msg, n)
3878 finally:
3596 finally:
3879 os.unlink(tmpname)
3597 os.unlink(tmpname)
3880
3598
3881 try:
3599 try:
3882 try:
3600 try:
3883 wlock = repo.wlock()
3601 wlock = repo.wlock()
3884 if not opts.get('no_commit'):
3602 if not opts.get('no_commit'):
3885 lock = repo.lock()
3603 lock = repo.lock()
3886 tr = repo.transaction('import')
3604 tr = repo.transaction('import')
3887 parents = repo.parents()
3605 parents = repo.parents()
3888 for patchurl in patches:
3606 for patchurl in patches:
3889 if patchurl == '-':
3607 if patchurl == '-':
3890 ui.status(_('applying patch from stdin\n'))
3608 ui.status(_('applying patch from stdin\n'))
3891 patchfile = ui.fin
3609 patchfile = ui.fin
3892 patchurl = 'stdin' # for error message
3610 patchurl = 'stdin' # for error message
3893 else:
3611 else:
3894 patchurl = os.path.join(base, patchurl)
3612 patchurl = os.path.join(base, patchurl)
3895 ui.status(_('applying %s\n') % patchurl)
3613 ui.status(_('applying %s\n') % patchurl)
3896 patchfile = hg.openpath(ui, patchurl)
3614 patchfile = hg.openpath(ui, patchurl)
3897
3615
3898 haspatch = False
3616 haspatch = False
3899 for hunk in patch.split(patchfile):
3617 for hunk in patch.split(patchfile):
3900 (msg, node) = tryone(ui, hunk, parents)
3618 (msg, node) = tryone(ui, hunk, parents)
3901 if msg:
3619 if msg:
3902 haspatch = True
3620 haspatch = True
3903 ui.note(msg + '\n')
3621 ui.note(msg + '\n')
3904 if update or opts.get('exact'):
3622 if update or opts.get('exact'):
3905 parents = repo.parents()
3623 parents = repo.parents()
3906 else:
3624 else:
3907 parents = [repo[node]]
3625 parents = [repo[node]]
3908
3626
3909 if not haspatch:
3627 if not haspatch:
3910 raise util.Abort(_('%s: no diffs found') % patchurl)
3628 raise util.Abort(_('%s: no diffs found') % patchurl)
3911
3629
3912 if tr:
3630 if tr:
3913 tr.close()
3631 tr.close()
3914 if msgs:
3632 if msgs:
3915 repo.savecommitmessage('\n* * *\n'.join(msgs))
3633 repo.savecommitmessage('\n* * *\n'.join(msgs))
3916 except: # re-raises
3634 except: # re-raises
3917 # wlock.release() indirectly calls dirstate.write(): since
3635 # wlock.release() indirectly calls dirstate.write(): since
3918 # we're crashing, we do not want to change the working dir
3636 # we're crashing, we do not want to change the working dir
3919 # parent after all, so make sure it writes nothing
3637 # parent after all, so make sure it writes nothing
3920 repo.dirstate.invalidate()
3638 repo.dirstate.invalidate()
3921 raise
3639 raise
3922 finally:
3640 finally:
3923 if tr:
3641 if tr:
3924 tr.release()
3642 tr.release()
3925 release(lock, wlock)
3643 release(lock, wlock)
3926
3644
3927 @command('incoming|in',
3645 @command('incoming|in',
3928 [('f', 'force', None,
3646 [('f', 'force', None,
3929 _('run even if remote repository is unrelated')),
3647 _('run even if remote repository is unrelated')),
3930 ('n', 'newest-first', None, _('show newest record first')),
3648 ('n', 'newest-first', None, _('show newest record first')),
3931 ('', 'bundle', '',
3649 ('', 'bundle', '',
3932 _('file to store the bundles into'), _('FILE')),
3650 _('file to store the bundles into'), _('FILE')),
3933 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3651 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3934 ('B', 'bookmarks', False, _("compare bookmarks")),
3652 ('B', 'bookmarks', False, _("compare bookmarks")),
3935 ('b', 'branch', [],
3653 ('b', 'branch', [],
3936 _('a specific branch you would like to pull'), _('BRANCH')),
3654 _('a specific branch you would like to pull'), _('BRANCH')),
3937 ] + logopts + remoteopts + subrepoopts,
3655 ] + logopts + remoteopts + subrepoopts,
3938 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3656 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3939 def incoming(ui, repo, source="default", **opts):
3657 def incoming(ui, repo, source="default", **opts):
3940 """show new changesets found in source
3658 """show new changesets found in source
3941
3659
3942 Show new changesets found in the specified path/URL or the default
3660 Show new changesets found in the specified path/URL or the default
3943 pull location. These are the changesets that would have been pulled
3661 pull location. These are the changesets that would have been pulled
3944 if a pull at the time you issued this command.
3662 if a pull at the time you issued this command.
3945
3663
3946 For remote repository, using --bundle avoids downloading the
3664 For remote repository, using --bundle avoids downloading the
3947 changesets twice if the incoming is followed by a pull.
3665 changesets twice if the incoming is followed by a pull.
3948
3666
3949 See pull for valid source format details.
3667 See pull for valid source format details.
3950
3668
3951 Returns 0 if there are incoming changes, 1 otherwise.
3669 Returns 0 if there are incoming changes, 1 otherwise.
3952 """
3670 """
3953 if opts.get('graph'):
3671 if opts.get('graph'):
3954 cmdutil.checkunsupportedgraphflags([], opts)
3672 cmdutil.checkunsupportedgraphflags([], opts)
3955 def display(other, chlist, displayer):
3673 def display(other, chlist, displayer):
3956 revdag = cmdutil.graphrevs(other, chlist, opts)
3674 revdag = cmdutil.graphrevs(other, chlist, opts)
3957 showparents = [ctx.node() for ctx in repo[None].parents()]
3675 showparents = [ctx.node() for ctx in repo[None].parents()]
3958 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3676 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3959 graphmod.asciiedges)
3677 graphmod.asciiedges)
3960
3678
3961 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3679 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3962 return 0
3680 return 0
3963
3681
3964 if opts.get('bundle') and opts.get('subrepos'):
3682 if opts.get('bundle') and opts.get('subrepos'):
3965 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3683 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3966
3684
3967 if opts.get('bookmarks'):
3685 if opts.get('bookmarks'):
3968 source, branches = hg.parseurl(ui.expandpath(source),
3686 source, branches = hg.parseurl(ui.expandpath(source),
3969 opts.get('branch'))
3687 opts.get('branch'))
3970 other = hg.peer(repo, opts, source)
3688 other = hg.peer(repo, opts, source)
3971 if 'bookmarks' not in other.listkeys('namespaces'):
3689 if 'bookmarks' not in other.listkeys('namespaces'):
3972 ui.warn(_("remote doesn't support bookmarks\n"))
3690 ui.warn(_("remote doesn't support bookmarks\n"))
3973 return 0
3691 return 0
3974 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3692 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3975 return bookmarks.diff(ui, repo, other)
3693 return bookmarks.diff(ui, repo, other)
3976
3694
3977 repo._subtoppath = ui.expandpath(source)
3695 repo._subtoppath = ui.expandpath(source)
3978 try:
3696 try:
3979 return hg.incoming(ui, repo, source, opts)
3697 return hg.incoming(ui, repo, source, opts)
3980 finally:
3698 finally:
3981 del repo._subtoppath
3699 del repo._subtoppath
3982
3700
3983
3701
3984 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3702 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3985 def init(ui, dest=".", **opts):
3703 def init(ui, dest=".", **opts):
3986 """create a new repository in the given directory
3704 """create a new repository in the given directory
3987
3705
3988 Initialize a new repository in the given directory. If the given
3706 Initialize a new repository in the given directory. If the given
3989 directory does not exist, it will be created.
3707 directory does not exist, it will be created.
3990
3708
3991 If no directory is given, the current directory is used.
3709 If no directory is given, the current directory is used.
3992
3710
3993 It is possible to specify an ``ssh://`` URL as the destination.
3711 It is possible to specify an ``ssh://`` URL as the destination.
3994 See :hg:`help urls` for more information.
3712 See :hg:`help urls` for more information.
3995
3713
3996 Returns 0 on success.
3714 Returns 0 on success.
3997 """
3715 """
3998 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3716 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3999
3717
4000 @command('locate',
3718 @command('locate',
4001 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3719 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4002 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3720 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4003 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3721 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4004 ] + walkopts,
3722 ] + walkopts,
4005 _('[OPTION]... [PATTERN]...'))
3723 _('[OPTION]... [PATTERN]...'))
4006 def locate(ui, repo, *pats, **opts):
3724 def locate(ui, repo, *pats, **opts):
4007 """locate files matching specific patterns
3725 """locate files matching specific patterns
4008
3726
4009 Print files under Mercurial control in the working directory whose
3727 Print files under Mercurial control in the working directory whose
4010 names match the given patterns.
3728 names match the given patterns.
4011
3729
4012 By default, this command searches all directories in the working
3730 By default, this command searches all directories in the working
4013 directory. To search just the current directory and its
3731 directory. To search just the current directory and its
4014 subdirectories, use "--include .".
3732 subdirectories, use "--include .".
4015
3733
4016 If no patterns are given to match, this command prints the names
3734 If no patterns are given to match, this command prints the names
4017 of all files under Mercurial control in the working directory.
3735 of all files under Mercurial control in the working directory.
4018
3736
4019 If you want to feed the output of this command into the "xargs"
3737 If you want to feed the output of this command into the "xargs"
4020 command, use the -0 option to both this command and "xargs". This
3738 command, use the -0 option to both this command and "xargs". This
4021 will avoid the problem of "xargs" treating single filenames that
3739 will avoid the problem of "xargs" treating single filenames that
4022 contain whitespace as multiple filenames.
3740 contain whitespace as multiple filenames.
4023
3741
4024 Returns 0 if a match is found, 1 otherwise.
3742 Returns 0 if a match is found, 1 otherwise.
4025 """
3743 """
4026 end = opts.get('print0') and '\0' or '\n'
3744 end = opts.get('print0') and '\0' or '\n'
4027 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3745 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4028
3746
4029 ret = 1
3747 ret = 1
4030 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3748 m = scmutil.match(repo[rev], pats, opts, default='relglob')
4031 m.bad = lambda x, y: False
3749 m.bad = lambda x, y: False
4032 for abs in repo[rev].walk(m):
3750 for abs in repo[rev].walk(m):
4033 if not rev and abs not in repo.dirstate:
3751 if not rev and abs not in repo.dirstate:
4034 continue
3752 continue
4035 if opts.get('fullpath'):
3753 if opts.get('fullpath'):
4036 ui.write(repo.wjoin(abs), end)
3754 ui.write(repo.wjoin(abs), end)
4037 else:
3755 else:
4038 ui.write(((pats and m.rel(abs)) or abs), end)
3756 ui.write(((pats and m.rel(abs)) or abs), end)
4039 ret = 0
3757 ret = 0
4040
3758
4041 return ret
3759 return ret
4042
3760
4043 @command('^log|history',
3761 @command('^log|history',
4044 [('f', 'follow', None,
3762 [('f', 'follow', None,
4045 _('follow changeset history, or file history across copies and renames')),
3763 _('follow changeset history, or file history across copies and renames')),
4046 ('', 'follow-first', None,
3764 ('', 'follow-first', None,
4047 _('only follow the first parent of merge changesets (DEPRECATED)')),
3765 _('only follow the first parent of merge changesets (DEPRECATED)')),
4048 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3766 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4049 ('C', 'copies', None, _('show copied files')),
3767 ('C', 'copies', None, _('show copied files')),
4050 ('k', 'keyword', [],
3768 ('k', 'keyword', [],
4051 _('do case-insensitive search for a given text'), _('TEXT')),
3769 _('do case-insensitive search for a given text'), _('TEXT')),
4052 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3770 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4053 ('', 'removed', None, _('include revisions where files were removed')),
3771 ('', 'removed', None, _('include revisions where files were removed')),
4054 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3772 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4055 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3773 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4056 ('', 'only-branch', [],
3774 ('', 'only-branch', [],
4057 _('show only changesets within the given named branch (DEPRECATED)'),
3775 _('show only changesets within the given named branch (DEPRECATED)'),
4058 _('BRANCH')),
3776 _('BRANCH')),
4059 ('b', 'branch', [],
3777 ('b', 'branch', [],
4060 _('show changesets within the given named branch'), _('BRANCH')),
3778 _('show changesets within the given named branch'), _('BRANCH')),
4061 ('P', 'prune', [],
3779 ('P', 'prune', [],
4062 _('do not display revision or any of its ancestors'), _('REV')),
3780 _('do not display revision or any of its ancestors'), _('REV')),
4063 ] + logopts + walkopts,
3781 ] + logopts + walkopts,
4064 _('[OPTION]... [FILE]'))
3782 _('[OPTION]... [FILE]'))
4065 def log(ui, repo, *pats, **opts):
3783 def log(ui, repo, *pats, **opts):
4066 """show revision history of entire repository or files
3784 """show revision history of entire repository or files
4067
3785
4068 Print the revision history of the specified files or the entire
3786 Print the revision history of the specified files or the entire
4069 project.
3787 project.
4070
3788
4071 If no revision range is specified, the default is ``tip:0`` unless
3789 If no revision range is specified, the default is ``tip:0`` unless
4072 --follow is set, in which case the working directory parent is
3790 --follow is set, in which case the working directory parent is
4073 used as the starting revision.
3791 used as the starting revision.
4074
3792
4075 File history is shown without following rename or copy history of
3793 File history is shown without following rename or copy history of
4076 files. Use -f/--follow with a filename to follow history across
3794 files. Use -f/--follow with a filename to follow history across
4077 renames and copies. --follow without a filename will only show
3795 renames and copies. --follow without a filename will only show
4078 ancestors or descendants of the starting revision.
3796 ancestors or descendants of the starting revision.
4079
3797
4080 By default this command prints revision number and changeset id,
3798 By default this command prints revision number and changeset id,
4081 tags, non-trivial parents, user, date and time, and a summary for
3799 tags, non-trivial parents, user, date and time, and a summary for
4082 each commit. When the -v/--verbose switch is used, the list of
3800 each commit. When the -v/--verbose switch is used, the list of
4083 changed files and full commit message are shown.
3801 changed files and full commit message are shown.
4084
3802
4085 .. note::
3803 .. note::
4086 log -p/--patch may generate unexpected diff output for merge
3804 log -p/--patch may generate unexpected diff output for merge
4087 changesets, as it will only compare the merge changeset against
3805 changesets, as it will only compare the merge changeset against
4088 its first parent. Also, only files different from BOTH parents
3806 its first parent. Also, only files different from BOTH parents
4089 will appear in files:.
3807 will appear in files:.
4090
3808
4091 .. note::
3809 .. note::
4092 for performance reasons, log FILE may omit duplicate changes
3810 for performance reasons, log FILE may omit duplicate changes
4093 made on branches and will not show deletions. To see all
3811 made on branches and will not show deletions. To see all
4094 changes including duplicates and deletions, use the --removed
3812 changes including duplicates and deletions, use the --removed
4095 switch.
3813 switch.
4096
3814
4097 .. container:: verbose
3815 .. container:: verbose
4098
3816
4099 Some examples:
3817 Some examples:
4100
3818
4101 - changesets with full descriptions and file lists::
3819 - changesets with full descriptions and file lists::
4102
3820
4103 hg log -v
3821 hg log -v
4104
3822
4105 - changesets ancestral to the working directory::
3823 - changesets ancestral to the working directory::
4106
3824
4107 hg log -f
3825 hg log -f
4108
3826
4109 - last 10 commits on the current branch::
3827 - last 10 commits on the current branch::
4110
3828
4111 hg log -l 10 -b .
3829 hg log -l 10 -b .
4112
3830
4113 - changesets showing all modifications of a file, including removals::
3831 - changesets showing all modifications of a file, including removals::
4114
3832
4115 hg log --removed file.c
3833 hg log --removed file.c
4116
3834
4117 - all changesets that touch a directory, with diffs, excluding merges::
3835 - all changesets that touch a directory, with diffs, excluding merges::
4118
3836
4119 hg log -Mp lib/
3837 hg log -Mp lib/
4120
3838
4121 - all revision numbers that match a keyword::
3839 - all revision numbers that match a keyword::
4122
3840
4123 hg log -k bug --template "{rev}\\n"
3841 hg log -k bug --template "{rev}\\n"
4124
3842
4125 - check if a given changeset is included is a tagged release::
3843 - check if a given changeset is included is a tagged release::
4126
3844
4127 hg log -r "a21ccf and ancestor(1.9)"
3845 hg log -r "a21ccf and ancestor(1.9)"
4128
3846
4129 - find all changesets by some user in a date range::
3847 - find all changesets by some user in a date range::
4130
3848
4131 hg log -k alice -d "may 2008 to jul 2008"
3849 hg log -k alice -d "may 2008 to jul 2008"
4132
3850
4133 - summary of all changesets after the last tag::
3851 - summary of all changesets after the last tag::
4134
3852
4135 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3853 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4136
3854
4137 See :hg:`help dates` for a list of formats valid for -d/--date.
3855 See :hg:`help dates` for a list of formats valid for -d/--date.
4138
3856
4139 See :hg:`help revisions` and :hg:`help revsets` for more about
3857 See :hg:`help revisions` and :hg:`help revsets` for more about
4140 specifying revisions.
3858 specifying revisions.
4141
3859
4142 See :hg:`help templates` for more about pre-packaged styles and
3860 See :hg:`help templates` for more about pre-packaged styles and
4143 specifying custom templates.
3861 specifying custom templates.
4144
3862
4145 Returns 0 on success.
3863 Returns 0 on success.
4146 """
3864 """
4147 if opts.get('graph'):
3865 if opts.get('graph'):
4148 return cmdutil.graphlog(ui, repo, *pats, **opts)
3866 return cmdutil.graphlog(ui, repo, *pats, **opts)
4149
3867
4150 matchfn = scmutil.match(repo[None], pats, opts)
3868 matchfn = scmutil.match(repo[None], pats, opts)
4151 limit = cmdutil.loglimit(opts)
3869 limit = cmdutil.loglimit(opts)
4152 count = 0
3870 count = 0
4153
3871
4154 getrenamed, endrev = None, None
3872 getrenamed, endrev = None, None
4155 if opts.get('copies'):
3873 if opts.get('copies'):
4156 if opts.get('rev'):
3874 if opts.get('rev'):
4157 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3875 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4158 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3876 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4159
3877
4160 df = False
3878 df = False
4161 if opts.get("date"):
3879 if opts.get("date"):
4162 df = util.matchdate(opts["date"])
3880 df = util.matchdate(opts["date"])
4163
3881
4164 branches = opts.get('branch', []) + opts.get('only_branch', [])
3882 branches = opts.get('branch', []) + opts.get('only_branch', [])
4165 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3883 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4166
3884
4167 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3885 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4168 def prep(ctx, fns):
3886 def prep(ctx, fns):
4169 rev = ctx.rev()
3887 rev = ctx.rev()
4170 parents = [p for p in repo.changelog.parentrevs(rev)
3888 parents = [p for p in repo.changelog.parentrevs(rev)
4171 if p != nullrev]
3889 if p != nullrev]
4172 if opts.get('no_merges') and len(parents) == 2:
3890 if opts.get('no_merges') and len(parents) == 2:
4173 return
3891 return
4174 if opts.get('only_merges') and len(parents) != 2:
3892 if opts.get('only_merges') and len(parents) != 2:
4175 return
3893 return
4176 if opts.get('branch') and ctx.branch() not in opts['branch']:
3894 if opts.get('branch') and ctx.branch() not in opts['branch']:
4177 return
3895 return
4178 if df and not df(ctx.date()[0]):
3896 if df and not df(ctx.date()[0]):
4179 return
3897 return
4180
3898
4181 lower = encoding.lower
3899 lower = encoding.lower
4182 if opts.get('user'):
3900 if opts.get('user'):
4183 luser = lower(ctx.user())
3901 luser = lower(ctx.user())
4184 for k in [lower(x) for x in opts['user']]:
3902 for k in [lower(x) for x in opts['user']]:
4185 if (k in luser):
3903 if (k in luser):
4186 break
3904 break
4187 else:
3905 else:
4188 return
3906 return
4189 if opts.get('keyword'):
3907 if opts.get('keyword'):
4190 luser = lower(ctx.user())
3908 luser = lower(ctx.user())
4191 ldesc = lower(ctx.description())
3909 ldesc = lower(ctx.description())
4192 lfiles = lower(" ".join(ctx.files()))
3910 lfiles = lower(" ".join(ctx.files()))
4193 for k in [lower(x) for x in opts['keyword']]:
3911 for k in [lower(x) for x in opts['keyword']]:
4194 if (k in luser or k in ldesc or k in lfiles):
3912 if (k in luser or k in ldesc or k in lfiles):
4195 break
3913 break
4196 else:
3914 else:
4197 return
3915 return
4198
3916
4199 copies = None
3917 copies = None
4200 if getrenamed is not None and rev:
3918 if getrenamed is not None and rev:
4201 copies = []
3919 copies = []
4202 for fn in ctx.files():
3920 for fn in ctx.files():
4203 rename = getrenamed(fn, rev)
3921 rename = getrenamed(fn, rev)
4204 if rename:
3922 if rename:
4205 copies.append((fn, rename[0]))
3923 copies.append((fn, rename[0]))
4206
3924
4207 revmatchfn = None
3925 revmatchfn = None
4208 if opts.get('patch') or opts.get('stat'):
3926 if opts.get('patch') or opts.get('stat'):
4209 if opts.get('follow') or opts.get('follow_first'):
3927 if opts.get('follow') or opts.get('follow_first'):
4210 # note: this might be wrong when following through merges
3928 # note: this might be wrong when following through merges
4211 revmatchfn = scmutil.match(repo[None], fns, default='path')
3929 revmatchfn = scmutil.match(repo[None], fns, default='path')
4212 else:
3930 else:
4213 revmatchfn = matchfn
3931 revmatchfn = matchfn
4214
3932
4215 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3933 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4216
3934
4217 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3935 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4218 if displayer.flush(ctx.rev()):
3936 if displayer.flush(ctx.rev()):
4219 count += 1
3937 count += 1
4220 if count == limit:
3938 if count == limit:
4221 break
3939 break
4222 displayer.close()
3940 displayer.close()
4223
3941
4224 @command('manifest',
3942 @command('manifest',
4225 [('r', 'rev', '', _('revision to display'), _('REV')),
3943 [('r', 'rev', '', _('revision to display'), _('REV')),
4226 ('', 'all', False, _("list files from all revisions"))],
3944 ('', 'all', False, _("list files from all revisions"))],
4227 _('[-r REV]'))
3945 _('[-r REV]'))
4228 def manifest(ui, repo, node=None, rev=None, **opts):
3946 def manifest(ui, repo, node=None, rev=None, **opts):
4229 """output the current or given revision of the project manifest
3947 """output the current or given revision of the project manifest
4230
3948
4231 Print a list of version controlled files for the given revision.
3949 Print a list of version controlled files for the given revision.
4232 If no revision is given, the first parent of the working directory
3950 If no revision is given, the first parent of the working directory
4233 is used, or the null revision if no revision is checked out.
3951 is used, or the null revision if no revision is checked out.
4234
3952
4235 With -v, print file permissions, symlink and executable bits.
3953 With -v, print file permissions, symlink and executable bits.
4236 With --debug, print file revision hashes.
3954 With --debug, print file revision hashes.
4237
3955
4238 If option --all is specified, the list of all files from all revisions
3956 If option --all is specified, the list of all files from all revisions
4239 is printed. This includes deleted and renamed files.
3957 is printed. This includes deleted and renamed files.
4240
3958
4241 Returns 0 on success.
3959 Returns 0 on success.
4242 """
3960 """
4243
3961
4244 fm = ui.formatter('manifest', opts)
3962 fm = ui.formatter('manifest', opts)
4245
3963
4246 if opts.get('all'):
3964 if opts.get('all'):
4247 if rev or node:
3965 if rev or node:
4248 raise util.Abort(_("can't specify a revision with --all"))
3966 raise util.Abort(_("can't specify a revision with --all"))
4249
3967
4250 res = []
3968 res = []
4251 prefix = "data/"
3969 prefix = "data/"
4252 suffix = ".i"
3970 suffix = ".i"
4253 plen = len(prefix)
3971 plen = len(prefix)
4254 slen = len(suffix)
3972 slen = len(suffix)
4255 lock = repo.lock()
3973 lock = repo.lock()
4256 try:
3974 try:
4257 for fn, b, size in repo.store.datafiles():
3975 for fn, b, size in repo.store.datafiles():
4258 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3976 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4259 res.append(fn[plen:-slen])
3977 res.append(fn[plen:-slen])
4260 finally:
3978 finally:
4261 lock.release()
3979 lock.release()
4262 for f in res:
3980 for f in res:
4263 fm.startitem()
3981 fm.startitem()
4264 fm.write("path", '%s\n', f)
3982 fm.write("path", '%s\n', f)
4265 fm.end()
3983 fm.end()
4266 return
3984 return
4267
3985
4268 if rev and node:
3986 if rev and node:
4269 raise util.Abort(_("please specify just one revision"))
3987 raise util.Abort(_("please specify just one revision"))
4270
3988
4271 if not node:
3989 if not node:
4272 node = rev
3990 node = rev
4273
3991
4274 char = {'l': '@', 'x': '*', '': ''}
3992 char = {'l': '@', 'x': '*', '': ''}
4275 mode = {'l': '644', 'x': '755', '': '644'}
3993 mode = {'l': '644', 'x': '755', '': '644'}
4276 ctx = scmutil.revsingle(repo, node)
3994 ctx = scmutil.revsingle(repo, node)
4277 mf = ctx.manifest()
3995 mf = ctx.manifest()
4278 for f in ctx:
3996 for f in ctx:
4279 fm.startitem()
3997 fm.startitem()
4280 fl = ctx[f].flags()
3998 fl = ctx[f].flags()
4281 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3999 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4282 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4000 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4283 fm.write('path', '%s\n', f)
4001 fm.write('path', '%s\n', f)
4284 fm.end()
4002 fm.end()
4285
4003
4286 @command('^merge',
4004 @command('^merge',
4287 [('f', 'force', None, _('force a merge with outstanding changes')),
4005 [('f', 'force', None, _('force a merge with outstanding changes')),
4288 ('r', 'rev', '', _('revision to merge'), _('REV')),
4006 ('r', 'rev', '', _('revision to merge'), _('REV')),
4289 ('P', 'preview', None,
4007 ('P', 'preview', None,
4290 _('review revisions to merge (no merge is performed)'))
4008 _('review revisions to merge (no merge is performed)'))
4291 ] + mergetoolopts,
4009 ] + mergetoolopts,
4292 _('[-P] [-f] [[-r] REV]'))
4010 _('[-P] [-f] [[-r] REV]'))
4293 def merge(ui, repo, node=None, **opts):
4011 def merge(ui, repo, node=None, **opts):
4294 """merge working directory with another revision
4012 """merge working directory with another revision
4295
4013
4296 The current working directory is updated with all changes made in
4014 The current working directory is updated with all changes made in
4297 the requested revision since the last common predecessor revision.
4015 the requested revision since the last common predecessor revision.
4298
4016
4299 Files that changed between either parent are marked as changed for
4017 Files that changed between either parent are marked as changed for
4300 the next commit and a commit must be performed before any further
4018 the next commit and a commit must be performed before any further
4301 updates to the repository are allowed. The next commit will have
4019 updates to the repository are allowed. The next commit will have
4302 two parents.
4020 two parents.
4303
4021
4304 ``--tool`` can be used to specify the merge tool used for file
4022 ``--tool`` can be used to specify the merge tool used for file
4305 merges. It overrides the HGMERGE environment variable and your
4023 merges. It overrides the HGMERGE environment variable and your
4306 configuration files. See :hg:`help merge-tools` for options.
4024 configuration files. See :hg:`help merge-tools` for options.
4307
4025
4308 If no revision is specified, the working directory's parent is a
4026 If no revision is specified, the working directory's parent is a
4309 head revision, and the current branch contains exactly one other
4027 head revision, and the current branch contains exactly one other
4310 head, the other head is merged with by default. Otherwise, an
4028 head, the other head is merged with by default. Otherwise, an
4311 explicit revision with which to merge with must be provided.
4029 explicit revision with which to merge with must be provided.
4312
4030
4313 :hg:`resolve` must be used to resolve unresolved files.
4031 :hg:`resolve` must be used to resolve unresolved files.
4314
4032
4315 To undo an uncommitted merge, use :hg:`update --clean .` which
4033 To undo an uncommitted merge, use :hg:`update --clean .` which
4316 will check out a clean copy of the original merge parent, losing
4034 will check out a clean copy of the original merge parent, losing
4317 all changes.
4035 all changes.
4318
4036
4319 Returns 0 on success, 1 if there are unresolved files.
4037 Returns 0 on success, 1 if there are unresolved files.
4320 """
4038 """
4321
4039
4322 if opts.get('rev') and node:
4040 if opts.get('rev') and node:
4323 raise util.Abort(_("please specify just one revision"))
4041 raise util.Abort(_("please specify just one revision"))
4324 if not node:
4042 if not node:
4325 node = opts.get('rev')
4043 node = opts.get('rev')
4326
4044
4327 if node:
4045 if node:
4328 node = scmutil.revsingle(repo, node).node()
4046 node = scmutil.revsingle(repo, node).node()
4329
4047
4330 if not node and repo._bookmarkcurrent:
4048 if not node and repo._bookmarkcurrent:
4331 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4049 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4332 curhead = repo[repo._bookmarkcurrent].node()
4050 curhead = repo[repo._bookmarkcurrent].node()
4333 if len(bmheads) == 2:
4051 if len(bmheads) == 2:
4334 if curhead == bmheads[0]:
4052 if curhead == bmheads[0]:
4335 node = bmheads[1]
4053 node = bmheads[1]
4336 else:
4054 else:
4337 node = bmheads[0]
4055 node = bmheads[0]
4338 elif len(bmheads) > 2:
4056 elif len(bmheads) > 2:
4339 raise util.Abort(_("multiple matching bookmarks to merge - "
4057 raise util.Abort(_("multiple matching bookmarks to merge - "
4340 "please merge with an explicit rev or bookmark"),
4058 "please merge with an explicit rev or bookmark"),
4341 hint=_("run 'hg heads' to see all heads"))
4059 hint=_("run 'hg heads' to see all heads"))
4342 elif len(bmheads) <= 1:
4060 elif len(bmheads) <= 1:
4343 raise util.Abort(_("no matching bookmark to merge - "
4061 raise util.Abort(_("no matching bookmark to merge - "
4344 "please merge with an explicit rev or bookmark"),
4062 "please merge with an explicit rev or bookmark"),
4345 hint=_("run 'hg heads' to see all heads"))
4063 hint=_("run 'hg heads' to see all heads"))
4346
4064
4347 if not node and not repo._bookmarkcurrent:
4065 if not node and not repo._bookmarkcurrent:
4348 branch = repo[None].branch()
4066 branch = repo[None].branch()
4349 bheads = repo.branchheads(branch)
4067 bheads = repo.branchheads(branch)
4350 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4068 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4351
4069
4352 if len(nbhs) > 2:
4070 if len(nbhs) > 2:
4353 raise util.Abort(_("branch '%s' has %d heads - "
4071 raise util.Abort(_("branch '%s' has %d heads - "
4354 "please merge with an explicit rev")
4072 "please merge with an explicit rev")
4355 % (branch, len(bheads)),
4073 % (branch, len(bheads)),
4356 hint=_("run 'hg heads .' to see heads"))
4074 hint=_("run 'hg heads .' to see heads"))
4357
4075
4358 parent = repo.dirstate.p1()
4076 parent = repo.dirstate.p1()
4359 if len(nbhs) <= 1:
4077 if len(nbhs) <= 1:
4360 if len(bheads) > 1:
4078 if len(bheads) > 1:
4361 raise util.Abort(_("heads are bookmarked - "
4079 raise util.Abort(_("heads are bookmarked - "
4362 "please merge with an explicit rev"),
4080 "please merge with an explicit rev"),
4363 hint=_("run 'hg heads' to see all heads"))
4081 hint=_("run 'hg heads' to see all heads"))
4364 if len(repo.heads()) > 1:
4082 if len(repo.heads()) > 1:
4365 raise util.Abort(_("branch '%s' has one head - "
4083 raise util.Abort(_("branch '%s' has one head - "
4366 "please merge with an explicit rev")
4084 "please merge with an explicit rev")
4367 % branch,
4085 % branch,
4368 hint=_("run 'hg heads' to see all heads"))
4086 hint=_("run 'hg heads' to see all heads"))
4369 msg, hint = _('nothing to merge'), None
4087 msg, hint = _('nothing to merge'), None
4370 if parent != repo.lookup(branch):
4088 if parent != repo.lookup(branch):
4371 hint = _("use 'hg update' instead")
4089 hint = _("use 'hg update' instead")
4372 raise util.Abort(msg, hint=hint)
4090 raise util.Abort(msg, hint=hint)
4373
4091
4374 if parent not in bheads:
4092 if parent not in bheads:
4375 raise util.Abort(_('working directory not at a head revision'),
4093 raise util.Abort(_('working directory not at a head revision'),
4376 hint=_("use 'hg update' or merge with an "
4094 hint=_("use 'hg update' or merge with an "
4377 "explicit revision"))
4095 "explicit revision"))
4378 if parent == nbhs[0]:
4096 if parent == nbhs[0]:
4379 node = nbhs[-1]
4097 node = nbhs[-1]
4380 else:
4098 else:
4381 node = nbhs[0]
4099 node = nbhs[0]
4382
4100
4383 if opts.get('preview'):
4101 if opts.get('preview'):
4384 # find nodes that are ancestors of p2 but not of p1
4102 # find nodes that are ancestors of p2 but not of p1
4385 p1 = repo.lookup('.')
4103 p1 = repo.lookup('.')
4386 p2 = repo.lookup(node)
4104 p2 = repo.lookup(node)
4387 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4105 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4388
4106
4389 displayer = cmdutil.show_changeset(ui, repo, opts)
4107 displayer = cmdutil.show_changeset(ui, repo, opts)
4390 for node in nodes:
4108 for node in nodes:
4391 displayer.show(repo[node])
4109 displayer.show(repo[node])
4392 displayer.close()
4110 displayer.close()
4393 return 0
4111 return 0
4394
4112
4395 try:
4113 try:
4396 # ui.forcemerge is an internal variable, do not document
4114 # ui.forcemerge is an internal variable, do not document
4397 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4115 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4398 return hg.merge(repo, node, force=opts.get('force'))
4116 return hg.merge(repo, node, force=opts.get('force'))
4399 finally:
4117 finally:
4400 ui.setconfig('ui', 'forcemerge', '')
4118 ui.setconfig('ui', 'forcemerge', '')
4401
4119
4402 @command('outgoing|out',
4120 @command('outgoing|out',
4403 [('f', 'force', None, _('run even when the destination is unrelated')),
4121 [('f', 'force', None, _('run even when the destination is unrelated')),
4404 ('r', 'rev', [],
4122 ('r', 'rev', [],
4405 _('a changeset intended to be included in the destination'), _('REV')),
4123 _('a changeset intended to be included in the destination'), _('REV')),
4406 ('n', 'newest-first', None, _('show newest record first')),
4124 ('n', 'newest-first', None, _('show newest record first')),
4407 ('B', 'bookmarks', False, _('compare bookmarks')),
4125 ('B', 'bookmarks', False, _('compare bookmarks')),
4408 ('b', 'branch', [], _('a specific branch you would like to push'),
4126 ('b', 'branch', [], _('a specific branch you would like to push'),
4409 _('BRANCH')),
4127 _('BRANCH')),
4410 ] + logopts + remoteopts + subrepoopts,
4128 ] + logopts + remoteopts + subrepoopts,
4411 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4129 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4412 def outgoing(ui, repo, dest=None, **opts):
4130 def outgoing(ui, repo, dest=None, **opts):
4413 """show changesets not found in the destination
4131 """show changesets not found in the destination
4414
4132
4415 Show changesets not found in the specified destination repository
4133 Show changesets not found in the specified destination repository
4416 or the default push location. These are the changesets that would
4134 or the default push location. These are the changesets that would
4417 be pushed if a push was requested.
4135 be pushed if a push was requested.
4418
4136
4419 See pull for details of valid destination formats.
4137 See pull for details of valid destination formats.
4420
4138
4421 Returns 0 if there are outgoing changes, 1 otherwise.
4139 Returns 0 if there are outgoing changes, 1 otherwise.
4422 """
4140 """
4423 if opts.get('graph'):
4141 if opts.get('graph'):
4424 cmdutil.checkunsupportedgraphflags([], opts)
4142 cmdutil.checkunsupportedgraphflags([], opts)
4425 o = hg._outgoing(ui, repo, dest, opts)
4143 o = hg._outgoing(ui, repo, dest, opts)
4426 if o is None:
4144 if o is None:
4427 return
4145 return
4428
4146
4429 revdag = cmdutil.graphrevs(repo, o, opts)
4147 revdag = cmdutil.graphrevs(repo, o, opts)
4430 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4148 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4431 showparents = [ctx.node() for ctx in repo[None].parents()]
4149 showparents = [ctx.node() for ctx in repo[None].parents()]
4432 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4150 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4433 graphmod.asciiedges)
4151 graphmod.asciiedges)
4434 return 0
4152 return 0
4435
4153
4436 if opts.get('bookmarks'):
4154 if opts.get('bookmarks'):
4437 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4155 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4438 dest, branches = hg.parseurl(dest, opts.get('branch'))
4156 dest, branches = hg.parseurl(dest, opts.get('branch'))
4439 other = hg.peer(repo, opts, dest)
4157 other = hg.peer(repo, opts, dest)
4440 if 'bookmarks' not in other.listkeys('namespaces'):
4158 if 'bookmarks' not in other.listkeys('namespaces'):
4441 ui.warn(_("remote doesn't support bookmarks\n"))
4159 ui.warn(_("remote doesn't support bookmarks\n"))
4442 return 0
4160 return 0
4443 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4161 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4444 return bookmarks.diff(ui, other, repo)
4162 return bookmarks.diff(ui, other, repo)
4445
4163
4446 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4164 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4447 try:
4165 try:
4448 return hg.outgoing(ui, repo, dest, opts)
4166 return hg.outgoing(ui, repo, dest, opts)
4449 finally:
4167 finally:
4450 del repo._subtoppath
4168 del repo._subtoppath
4451
4169
4452 @command('parents',
4170 @command('parents',
4453 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4171 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4454 ] + templateopts,
4172 ] + templateopts,
4455 _('[-r REV] [FILE]'))
4173 _('[-r REV] [FILE]'))
4456 def parents(ui, repo, file_=None, **opts):
4174 def parents(ui, repo, file_=None, **opts):
4457 """show the parents of the working directory or revision
4175 """show the parents of the working directory or revision
4458
4176
4459 Print the working directory's parent revisions. If a revision is
4177 Print the working directory's parent revisions. If a revision is
4460 given via -r/--rev, the parent of that revision will be printed.
4178 given via -r/--rev, the parent of that revision will be printed.
4461 If a file argument is given, the revision in which the file was
4179 If a file argument is given, the revision in which the file was
4462 last changed (before the working directory revision or the
4180 last changed (before the working directory revision or the
4463 argument to --rev if given) is printed.
4181 argument to --rev if given) is printed.
4464
4182
4465 Returns 0 on success.
4183 Returns 0 on success.
4466 """
4184 """
4467
4185
4468 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4186 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4469
4187
4470 if file_:
4188 if file_:
4471 m = scmutil.match(ctx, (file_,), opts)
4189 m = scmutil.match(ctx, (file_,), opts)
4472 if m.anypats() or len(m.files()) != 1:
4190 if m.anypats() or len(m.files()) != 1:
4473 raise util.Abort(_('can only specify an explicit filename'))
4191 raise util.Abort(_('can only specify an explicit filename'))
4474 file_ = m.files()[0]
4192 file_ = m.files()[0]
4475 filenodes = []
4193 filenodes = []
4476 for cp in ctx.parents():
4194 for cp in ctx.parents():
4477 if not cp:
4195 if not cp:
4478 continue
4196 continue
4479 try:
4197 try:
4480 filenodes.append(cp.filenode(file_))
4198 filenodes.append(cp.filenode(file_))
4481 except error.LookupError:
4199 except error.LookupError:
4482 pass
4200 pass
4483 if not filenodes:
4201 if not filenodes:
4484 raise util.Abort(_("'%s' not found in manifest!") % file_)
4202 raise util.Abort(_("'%s' not found in manifest!") % file_)
4485 fl = repo.file(file_)
4203 fl = repo.file(file_)
4486 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4204 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4487 else:
4205 else:
4488 p = [cp.node() for cp in ctx.parents()]
4206 p = [cp.node() for cp in ctx.parents()]
4489
4207
4490 displayer = cmdutil.show_changeset(ui, repo, opts)
4208 displayer = cmdutil.show_changeset(ui, repo, opts)
4491 for n in p:
4209 for n in p:
4492 if n != nullid:
4210 if n != nullid:
4493 displayer.show(repo[n])
4211 displayer.show(repo[n])
4494 displayer.close()
4212 displayer.close()
4495
4213
4496 @command('paths', [], _('[NAME]'))
4214 @command('paths', [], _('[NAME]'))
4497 def paths(ui, repo, search=None):
4215 def paths(ui, repo, search=None):
4498 """show aliases for remote repositories
4216 """show aliases for remote repositories
4499
4217
4500 Show definition of symbolic path name NAME. If no name is given,
4218 Show definition of symbolic path name NAME. If no name is given,
4501 show definition of all available names.
4219 show definition of all available names.
4502
4220
4503 Option -q/--quiet suppresses all output when searching for NAME
4221 Option -q/--quiet suppresses all output when searching for NAME
4504 and shows only the path names when listing all definitions.
4222 and shows only the path names when listing all definitions.
4505
4223
4506 Path names are defined in the [paths] section of your
4224 Path names are defined in the [paths] section of your
4507 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4225 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4508 repository, ``.hg/hgrc`` is used, too.
4226 repository, ``.hg/hgrc`` is used, too.
4509
4227
4510 The path names ``default`` and ``default-push`` have a special
4228 The path names ``default`` and ``default-push`` have a special
4511 meaning. When performing a push or pull operation, they are used
4229 meaning. When performing a push or pull operation, they are used
4512 as fallbacks if no location is specified on the command-line.
4230 as fallbacks if no location is specified on the command-line.
4513 When ``default-push`` is set, it will be used for push and
4231 When ``default-push`` is set, it will be used for push and
4514 ``default`` will be used for pull; otherwise ``default`` is used
4232 ``default`` will be used for pull; otherwise ``default`` is used
4515 as the fallback for both. When cloning a repository, the clone
4233 as the fallback for both. When cloning a repository, the clone
4516 source is written as ``default`` in ``.hg/hgrc``. Note that
4234 source is written as ``default`` in ``.hg/hgrc``. Note that
4517 ``default`` and ``default-push`` apply to all inbound (e.g.
4235 ``default`` and ``default-push`` apply to all inbound (e.g.
4518 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4236 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4519 :hg:`bundle`) operations.
4237 :hg:`bundle`) operations.
4520
4238
4521 See :hg:`help urls` for more information.
4239 See :hg:`help urls` for more information.
4522
4240
4523 Returns 0 on success.
4241 Returns 0 on success.
4524 """
4242 """
4525 if search:
4243 if search:
4526 for name, path in ui.configitems("paths"):
4244 for name, path in ui.configitems("paths"):
4527 if name == search:
4245 if name == search:
4528 ui.status("%s\n" % util.hidepassword(path))
4246 ui.status("%s\n" % util.hidepassword(path))
4529 return
4247 return
4530 if not ui.quiet:
4248 if not ui.quiet:
4531 ui.warn(_("not found!\n"))
4249 ui.warn(_("not found!\n"))
4532 return 1
4250 return 1
4533 else:
4251 else:
4534 for name, path in ui.configitems("paths"):
4252 for name, path in ui.configitems("paths"):
4535 if ui.quiet:
4253 if ui.quiet:
4536 ui.write("%s\n" % name)
4254 ui.write("%s\n" % name)
4537 else:
4255 else:
4538 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4256 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4539
4257
4540 @command('phase',
4258 @command('phase',
4541 [('p', 'public', False, _('set changeset phase to public')),
4259 [('p', 'public', False, _('set changeset phase to public')),
4542 ('d', 'draft', False, _('set changeset phase to draft')),
4260 ('d', 'draft', False, _('set changeset phase to draft')),
4543 ('s', 'secret', False, _('set changeset phase to secret')),
4261 ('s', 'secret', False, _('set changeset phase to secret')),
4544 ('f', 'force', False, _('allow to move boundary backward')),
4262 ('f', 'force', False, _('allow to move boundary backward')),
4545 ('r', 'rev', [], _('target revision'), _('REV')),
4263 ('r', 'rev', [], _('target revision'), _('REV')),
4546 ],
4264 ],
4547 _('[-p|-d|-s] [-f] [-r] REV...'))
4265 _('[-p|-d|-s] [-f] [-r] REV...'))
4548 def phase(ui, repo, *revs, **opts):
4266 def phase(ui, repo, *revs, **opts):
4549 """set or show the current phase name
4267 """set or show the current phase name
4550
4268
4551 With no argument, show the phase name of specified revisions.
4269 With no argument, show the phase name of specified revisions.
4552
4270
4553 With one of -p/--public, -d/--draft or -s/--secret, change the
4271 With one of -p/--public, -d/--draft or -s/--secret, change the
4554 phase value of the specified revisions.
4272 phase value of the specified revisions.
4555
4273
4556 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4274 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4557 lower phase to an higher phase. Phases are ordered as follows::
4275 lower phase to an higher phase. Phases are ordered as follows::
4558
4276
4559 public < draft < secret
4277 public < draft < secret
4560
4278
4561 Return 0 on success, 1 if no phases were changed or some could not
4279 Return 0 on success, 1 if no phases were changed or some could not
4562 be changed.
4280 be changed.
4563 """
4281 """
4564 # search for a unique phase argument
4282 # search for a unique phase argument
4565 targetphase = None
4283 targetphase = None
4566 for idx, name in enumerate(phases.phasenames):
4284 for idx, name in enumerate(phases.phasenames):
4567 if opts[name]:
4285 if opts[name]:
4568 if targetphase is not None:
4286 if targetphase is not None:
4569 raise util.Abort(_('only one phase can be specified'))
4287 raise util.Abort(_('only one phase can be specified'))
4570 targetphase = idx
4288 targetphase = idx
4571
4289
4572 # look for specified revision
4290 # look for specified revision
4573 revs = list(revs)
4291 revs = list(revs)
4574 revs.extend(opts['rev'])
4292 revs.extend(opts['rev'])
4575 if not revs:
4293 if not revs:
4576 raise util.Abort(_('no revisions specified'))
4294 raise util.Abort(_('no revisions specified'))
4577
4295
4578 revs = scmutil.revrange(repo, revs)
4296 revs = scmutil.revrange(repo, revs)
4579
4297
4580 lock = None
4298 lock = None
4581 ret = 0
4299 ret = 0
4582 if targetphase is None:
4300 if targetphase is None:
4583 # display
4301 # display
4584 for r in revs:
4302 for r in revs:
4585 ctx = repo[r]
4303 ctx = repo[r]
4586 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4304 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4587 else:
4305 else:
4588 lock = repo.lock()
4306 lock = repo.lock()
4589 try:
4307 try:
4590 # set phase
4308 # set phase
4591 if not revs:
4309 if not revs:
4592 raise util.Abort(_('empty revision set'))
4310 raise util.Abort(_('empty revision set'))
4593 nodes = [repo[r].node() for r in revs]
4311 nodes = [repo[r].node() for r in revs]
4594 olddata = repo._phasecache.getphaserevs(repo)[:]
4312 olddata = repo._phasecache.getphaserevs(repo)[:]
4595 phases.advanceboundary(repo, targetphase, nodes)
4313 phases.advanceboundary(repo, targetphase, nodes)
4596 if opts['force']:
4314 if opts['force']:
4597 phases.retractboundary(repo, targetphase, nodes)
4315 phases.retractboundary(repo, targetphase, nodes)
4598 finally:
4316 finally:
4599 lock.release()
4317 lock.release()
4600 # moving revision from public to draft may hide them
4318 # moving revision from public to draft may hide them
4601 # We have to check result on an unfiltered repository
4319 # We have to check result on an unfiltered repository
4602 unfi = repo.unfiltered()
4320 unfi = repo.unfiltered()
4603 newdata = repo._phasecache.getphaserevs(unfi)
4321 newdata = repo._phasecache.getphaserevs(unfi)
4604 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4322 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4605 cl = unfi.changelog
4323 cl = unfi.changelog
4606 rejected = [n for n in nodes
4324 rejected = [n for n in nodes
4607 if newdata[cl.rev(n)] < targetphase]
4325 if newdata[cl.rev(n)] < targetphase]
4608 if rejected:
4326 if rejected:
4609 ui.warn(_('cannot move %i changesets to a more permissive '
4327 ui.warn(_('cannot move %i changesets to a more permissive '
4610 'phase, use --force\n') % len(rejected))
4328 'phase, use --force\n') % len(rejected))
4611 ret = 1
4329 ret = 1
4612 if changes:
4330 if changes:
4613 msg = _('phase changed for %i changesets\n') % changes
4331 msg = _('phase changed for %i changesets\n') % changes
4614 if ret:
4332 if ret:
4615 ui.status(msg)
4333 ui.status(msg)
4616 else:
4334 else:
4617 ui.note(msg)
4335 ui.note(msg)
4618 else:
4336 else:
4619 ui.warn(_('no phases changed\n'))
4337 ui.warn(_('no phases changed\n'))
4620 ret = 1
4338 ret = 1
4621 return ret
4339 return ret
4622
4340
4623 def postincoming(ui, repo, modheads, optupdate, checkout):
4341 def postincoming(ui, repo, modheads, optupdate, checkout):
4624 if modheads == 0:
4342 if modheads == 0:
4625 return
4343 return
4626 if optupdate:
4344 if optupdate:
4627 movemarkfrom = repo['.'].node()
4345 movemarkfrom = repo['.'].node()
4628 try:
4346 try:
4629 ret = hg.update(repo, checkout)
4347 ret = hg.update(repo, checkout)
4630 except util.Abort, inst:
4348 except util.Abort, inst:
4631 ui.warn(_("not updating: %s\n") % str(inst))
4349 ui.warn(_("not updating: %s\n") % str(inst))
4632 return 0
4350 return 0
4633 if not ret and not checkout:
4351 if not ret and not checkout:
4634 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4352 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4635 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4353 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4636 return ret
4354 return ret
4637 if modheads > 1:
4355 if modheads > 1:
4638 currentbranchheads = len(repo.branchheads())
4356 currentbranchheads = len(repo.branchheads())
4639 if currentbranchheads == modheads:
4357 if currentbranchheads == modheads:
4640 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4358 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4641 elif currentbranchheads > 1:
4359 elif currentbranchheads > 1:
4642 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4360 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4643 "merge)\n"))
4361 "merge)\n"))
4644 else:
4362 else:
4645 ui.status(_("(run 'hg heads' to see heads)\n"))
4363 ui.status(_("(run 'hg heads' to see heads)\n"))
4646 else:
4364 else:
4647 ui.status(_("(run 'hg update' to get a working copy)\n"))
4365 ui.status(_("(run 'hg update' to get a working copy)\n"))
4648
4366
4649 @command('^pull',
4367 @command('^pull',
4650 [('u', 'update', None,
4368 [('u', 'update', None,
4651 _('update to new branch head if changesets were pulled')),
4369 _('update to new branch head if changesets were pulled')),
4652 ('f', 'force', None, _('run even when remote repository is unrelated')),
4370 ('f', 'force', None, _('run even when remote repository is unrelated')),
4653 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4371 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4654 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4372 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4655 ('b', 'branch', [], _('a specific branch you would like to pull'),
4373 ('b', 'branch', [], _('a specific branch you would like to pull'),
4656 _('BRANCH')),
4374 _('BRANCH')),
4657 ] + remoteopts,
4375 ] + remoteopts,
4658 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4376 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4659 def pull(ui, repo, source="default", **opts):
4377 def pull(ui, repo, source="default", **opts):
4660 """pull changes from the specified source
4378 """pull changes from the specified source
4661
4379
4662 Pull changes from a remote repository to a local one.
4380 Pull changes from a remote repository to a local one.
4663
4381
4664 This finds all changes from the repository at the specified path
4382 This finds all changes from the repository at the specified path
4665 or URL and adds them to a local repository (the current one unless
4383 or URL and adds them to a local repository (the current one unless
4666 -R is specified). By default, this does not update the copy of the
4384 -R is specified). By default, this does not update the copy of the
4667 project in the working directory.
4385 project in the working directory.
4668
4386
4669 Use :hg:`incoming` if you want to see what would have been added
4387 Use :hg:`incoming` if you want to see what would have been added
4670 by a pull at the time you issued this command. If you then decide
4388 by a pull at the time you issued this command. If you then decide
4671 to add those changes to the repository, you should use :hg:`pull
4389 to add those changes to the repository, you should use :hg:`pull
4672 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4390 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4673
4391
4674 If SOURCE is omitted, the 'default' path will be used.
4392 If SOURCE is omitted, the 'default' path will be used.
4675 See :hg:`help urls` for more information.
4393 See :hg:`help urls` for more information.
4676
4394
4677 Returns 0 on success, 1 if an update had unresolved files.
4395 Returns 0 on success, 1 if an update had unresolved files.
4678 """
4396 """
4679 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4397 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4680 other = hg.peer(repo, opts, source)
4398 other = hg.peer(repo, opts, source)
4681 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4399 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4682 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4400 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4683
4401
4684 if opts.get('bookmark'):
4402 if opts.get('bookmark'):
4685 if not revs:
4403 if not revs:
4686 revs = []
4404 revs = []
4687 rb = other.listkeys('bookmarks')
4405 rb = other.listkeys('bookmarks')
4688 for b in opts['bookmark']:
4406 for b in opts['bookmark']:
4689 if b not in rb:
4407 if b not in rb:
4690 raise util.Abort(_('remote bookmark %s not found!') % b)
4408 raise util.Abort(_('remote bookmark %s not found!') % b)
4691 revs.append(rb[b])
4409 revs.append(rb[b])
4692
4410
4693 if revs:
4411 if revs:
4694 try:
4412 try:
4695 revs = [other.lookup(rev) for rev in revs]
4413 revs = [other.lookup(rev) for rev in revs]
4696 except error.CapabilityError:
4414 except error.CapabilityError:
4697 err = _("other repository doesn't support revision lookup, "
4415 err = _("other repository doesn't support revision lookup, "
4698 "so a rev cannot be specified.")
4416 "so a rev cannot be specified.")
4699 raise util.Abort(err)
4417 raise util.Abort(err)
4700
4418
4701 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4419 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4702 bookmarks.updatefromremote(ui, repo, other, source)
4420 bookmarks.updatefromremote(ui, repo, other, source)
4703 if checkout:
4421 if checkout:
4704 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4422 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4705 repo._subtoppath = source
4423 repo._subtoppath = source
4706 try:
4424 try:
4707 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4425 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4708
4426
4709 finally:
4427 finally:
4710 del repo._subtoppath
4428 del repo._subtoppath
4711
4429
4712 # update specified bookmarks
4430 # update specified bookmarks
4713 if opts.get('bookmark'):
4431 if opts.get('bookmark'):
4714 marks = repo._bookmarks
4432 marks = repo._bookmarks
4715 for b in opts['bookmark']:
4433 for b in opts['bookmark']:
4716 # explicit pull overrides local bookmark if any
4434 # explicit pull overrides local bookmark if any
4717 ui.status(_("importing bookmark %s\n") % b)
4435 ui.status(_("importing bookmark %s\n") % b)
4718 marks[b] = repo[rb[b]].node()
4436 marks[b] = repo[rb[b]].node()
4719 marks.write()
4437 marks.write()
4720
4438
4721 return ret
4439 return ret
4722
4440
4723 @command('^push',
4441 @command('^push',
4724 [('f', 'force', None, _('force push')),
4442 [('f', 'force', None, _('force push')),
4725 ('r', 'rev', [],
4443 ('r', 'rev', [],
4726 _('a changeset intended to be included in the destination'),
4444 _('a changeset intended to be included in the destination'),
4727 _('REV')),
4445 _('REV')),
4728 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4446 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4729 ('b', 'branch', [],
4447 ('b', 'branch', [],
4730 _('a specific branch you would like to push'), _('BRANCH')),
4448 _('a specific branch you would like to push'), _('BRANCH')),
4731 ('', 'new-branch', False, _('allow pushing a new branch')),
4449 ('', 'new-branch', False, _('allow pushing a new branch')),
4732 ] + remoteopts,
4450 ] + remoteopts,
4733 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4451 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4734 def push(ui, repo, dest=None, **opts):
4452 def push(ui, repo, dest=None, **opts):
4735 """push changes to the specified destination
4453 """push changes to the specified destination
4736
4454
4737 Push changesets from the local repository to the specified
4455 Push changesets from the local repository to the specified
4738 destination.
4456 destination.
4739
4457
4740 This operation is symmetrical to pull: it is identical to a pull
4458 This operation is symmetrical to pull: it is identical to a pull
4741 in the destination repository from the current one.
4459 in the destination repository from the current one.
4742
4460
4743 By default, push will not allow creation of new heads at the
4461 By default, push will not allow creation of new heads at the
4744 destination, since multiple heads would make it unclear which head
4462 destination, since multiple heads would make it unclear which head
4745 to use. In this situation, it is recommended to pull and merge
4463 to use. In this situation, it is recommended to pull and merge
4746 before pushing.
4464 before pushing.
4747
4465
4748 Use --new-branch if you want to allow push to create a new named
4466 Use --new-branch if you want to allow push to create a new named
4749 branch that is not present at the destination. This allows you to
4467 branch that is not present at the destination. This allows you to
4750 only create a new branch without forcing other changes.
4468 only create a new branch without forcing other changes.
4751
4469
4752 Use -f/--force to override the default behavior and push all
4470 Use -f/--force to override the default behavior and push all
4753 changesets on all branches.
4471 changesets on all branches.
4754
4472
4755 If -r/--rev is used, the specified revision and all its ancestors
4473 If -r/--rev is used, the specified revision and all its ancestors
4756 will be pushed to the remote repository.
4474 will be pushed to the remote repository.
4757
4475
4758 If -B/--bookmark is used, the specified bookmarked revision, its
4476 If -B/--bookmark is used, the specified bookmarked revision, its
4759 ancestors, and the bookmark will be pushed to the remote
4477 ancestors, and the bookmark will be pushed to the remote
4760 repository.
4478 repository.
4761
4479
4762 Please see :hg:`help urls` for important details about ``ssh://``
4480 Please see :hg:`help urls` for important details about ``ssh://``
4763 URLs. If DESTINATION is omitted, a default path will be used.
4481 URLs. If DESTINATION is omitted, a default path will be used.
4764
4482
4765 Returns 0 if push was successful, 1 if nothing to push.
4483 Returns 0 if push was successful, 1 if nothing to push.
4766 """
4484 """
4767
4485
4768 if opts.get('bookmark'):
4486 if opts.get('bookmark'):
4769 for b in opts['bookmark']:
4487 for b in opts['bookmark']:
4770 # translate -B options to -r so changesets get pushed
4488 # translate -B options to -r so changesets get pushed
4771 if b in repo._bookmarks:
4489 if b in repo._bookmarks:
4772 opts.setdefault('rev', []).append(b)
4490 opts.setdefault('rev', []).append(b)
4773 else:
4491 else:
4774 # if we try to push a deleted bookmark, translate it to null
4492 # if we try to push a deleted bookmark, translate it to null
4775 # this lets simultaneous -r, -b options continue working
4493 # this lets simultaneous -r, -b options continue working
4776 opts.setdefault('rev', []).append("null")
4494 opts.setdefault('rev', []).append("null")
4777
4495
4778 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4496 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4779 dest, branches = hg.parseurl(dest, opts.get('branch'))
4497 dest, branches = hg.parseurl(dest, opts.get('branch'))
4780 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4498 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4781 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4499 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4782 other = hg.peer(repo, opts, dest)
4500 other = hg.peer(repo, opts, dest)
4783 if revs:
4501 if revs:
4784 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4502 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4785
4503
4786 repo._subtoppath = dest
4504 repo._subtoppath = dest
4787 try:
4505 try:
4788 # push subrepos depth-first for coherent ordering
4506 # push subrepos depth-first for coherent ordering
4789 c = repo['']
4507 c = repo['']
4790 subs = c.substate # only repos that are committed
4508 subs = c.substate # only repos that are committed
4791 for s in sorted(subs):
4509 for s in sorted(subs):
4792 if c.sub(s).push(opts) == 0:
4510 if c.sub(s).push(opts) == 0:
4793 return False
4511 return False
4794 finally:
4512 finally:
4795 del repo._subtoppath
4513 del repo._subtoppath
4796 result = repo.push(other, opts.get('force'), revs=revs,
4514 result = repo.push(other, opts.get('force'), revs=revs,
4797 newbranch=opts.get('new_branch'))
4515 newbranch=opts.get('new_branch'))
4798
4516
4799 result = not result
4517 result = not result
4800
4518
4801 if opts.get('bookmark'):
4519 if opts.get('bookmark'):
4802 rb = other.listkeys('bookmarks')
4520 rb = other.listkeys('bookmarks')
4803 for b in opts['bookmark']:
4521 for b in opts['bookmark']:
4804 # explicit push overrides remote bookmark if any
4522 # explicit push overrides remote bookmark if any
4805 if b in repo._bookmarks:
4523 if b in repo._bookmarks:
4806 ui.status(_("exporting bookmark %s\n") % b)
4524 ui.status(_("exporting bookmark %s\n") % b)
4807 new = repo[b].hex()
4525 new = repo[b].hex()
4808 elif b in rb:
4526 elif b in rb:
4809 ui.status(_("deleting remote bookmark %s\n") % b)
4527 ui.status(_("deleting remote bookmark %s\n") % b)
4810 new = '' # delete
4528 new = '' # delete
4811 else:
4529 else:
4812 ui.warn(_('bookmark %s does not exist on the local '
4530 ui.warn(_('bookmark %s does not exist on the local '
4813 'or remote repository!\n') % b)
4531 'or remote repository!\n') % b)
4814 return 2
4532 return 2
4815 old = rb.get(b, '')
4533 old = rb.get(b, '')
4816 r = other.pushkey('bookmarks', b, old, new)
4534 r = other.pushkey('bookmarks', b, old, new)
4817 if not r:
4535 if not r:
4818 ui.warn(_('updating bookmark %s failed!\n') % b)
4536 ui.warn(_('updating bookmark %s failed!\n') % b)
4819 if not result:
4537 if not result:
4820 result = 2
4538 result = 2
4821
4539
4822 return result
4540 return result
4823
4541
4824 @command('recover', [])
4542 @command('recover', [])
4825 def recover(ui, repo):
4543 def recover(ui, repo):
4826 """roll back an interrupted transaction
4544 """roll back an interrupted transaction
4827
4545
4828 Recover from an interrupted commit or pull.
4546 Recover from an interrupted commit or pull.
4829
4547
4830 This command tries to fix the repository status after an
4548 This command tries to fix the repository status after an
4831 interrupted operation. It should only be necessary when Mercurial
4549 interrupted operation. It should only be necessary when Mercurial
4832 suggests it.
4550 suggests it.
4833
4551
4834 Returns 0 if successful, 1 if nothing to recover or verify fails.
4552 Returns 0 if successful, 1 if nothing to recover or verify fails.
4835 """
4553 """
4836 if repo.recover():
4554 if repo.recover():
4837 return hg.verify(repo)
4555 return hg.verify(repo)
4838 return 1
4556 return 1
4839
4557
4840 @command('^remove|rm',
4558 @command('^remove|rm',
4841 [('A', 'after', None, _('record delete for missing files')),
4559 [('A', 'after', None, _('record delete for missing files')),
4842 ('f', 'force', None,
4560 ('f', 'force', None,
4843 _('remove (and delete) file even if added or modified')),
4561 _('remove (and delete) file even if added or modified')),
4844 ] + walkopts,
4562 ] + walkopts,
4845 _('[OPTION]... FILE...'))
4563 _('[OPTION]... FILE...'))
4846 def remove(ui, repo, *pats, **opts):
4564 def remove(ui, repo, *pats, **opts):
4847 """remove the specified files on the next commit
4565 """remove the specified files on the next commit
4848
4566
4849 Schedule the indicated files for removal from the current branch.
4567 Schedule the indicated files for removal from the current branch.
4850
4568
4851 This command schedules the files to be removed at the next commit.
4569 This command schedules the files to be removed at the next commit.
4852 To undo a remove before that, see :hg:`revert`. To undo added
4570 To undo a remove before that, see :hg:`revert`. To undo added
4853 files, see :hg:`forget`.
4571 files, see :hg:`forget`.
4854
4572
4855 .. container:: verbose
4573 .. container:: verbose
4856
4574
4857 -A/--after can be used to remove only files that have already
4575 -A/--after can be used to remove only files that have already
4858 been deleted, -f/--force can be used to force deletion, and -Af
4576 been deleted, -f/--force can be used to force deletion, and -Af
4859 can be used to remove files from the next revision without
4577 can be used to remove files from the next revision without
4860 deleting them from the working directory.
4578 deleting them from the working directory.
4861
4579
4862 The following table details the behavior of remove for different
4580 The following table details the behavior of remove for different
4863 file states (columns) and option combinations (rows). The file
4581 file states (columns) and option combinations (rows). The file
4864 states are Added [A], Clean [C], Modified [M] and Missing [!]
4582 states are Added [A], Clean [C], Modified [M] and Missing [!]
4865 (as reported by :hg:`status`). The actions are Warn, Remove
4583 (as reported by :hg:`status`). The actions are Warn, Remove
4866 (from branch) and Delete (from disk):
4584 (from branch) and Delete (from disk):
4867
4585
4868 ======= == == == ==
4586 ======= == == == ==
4869 A C M !
4587 A C M !
4870 ======= == == == ==
4588 ======= == == == ==
4871 none W RD W R
4589 none W RD W R
4872 -f R RD RD R
4590 -f R RD RD R
4873 -A W W W R
4591 -A W W W R
4874 -Af R R R R
4592 -Af R R R R
4875 ======= == == == ==
4593 ======= == == == ==
4876
4594
4877 Note that remove never deletes files in Added [A] state from the
4595 Note that remove never deletes files in Added [A] state from the
4878 working directory, not even if option --force is specified.
4596 working directory, not even if option --force is specified.
4879
4597
4880 Returns 0 on success, 1 if any warnings encountered.
4598 Returns 0 on success, 1 if any warnings encountered.
4881 """
4599 """
4882
4600
4883 ret = 0
4601 ret = 0
4884 after, force = opts.get('after'), opts.get('force')
4602 after, force = opts.get('after'), opts.get('force')
4885 if not pats and not after:
4603 if not pats and not after:
4886 raise util.Abort(_('no files specified'))
4604 raise util.Abort(_('no files specified'))
4887
4605
4888 m = scmutil.match(repo[None], pats, opts)
4606 m = scmutil.match(repo[None], pats, opts)
4889 s = repo.status(match=m, clean=True)
4607 s = repo.status(match=m, clean=True)
4890 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4608 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4891
4609
4892 # warn about failure to delete explicit files/dirs
4610 # warn about failure to delete explicit files/dirs
4893 wctx = repo[None]
4611 wctx = repo[None]
4894 for f in m.files():
4612 for f in m.files():
4895 if f in repo.dirstate or f in wctx.dirs():
4613 if f in repo.dirstate or f in wctx.dirs():
4896 continue
4614 continue
4897 if os.path.exists(m.rel(f)):
4615 if os.path.exists(m.rel(f)):
4898 if os.path.isdir(m.rel(f)):
4616 if os.path.isdir(m.rel(f)):
4899 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4617 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4900 else:
4618 else:
4901 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4619 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4902 # missing files will generate a warning elsewhere
4620 # missing files will generate a warning elsewhere
4903 ret = 1
4621 ret = 1
4904
4622
4905 if force:
4623 if force:
4906 list = modified + deleted + clean + added
4624 list = modified + deleted + clean + added
4907 elif after:
4625 elif after:
4908 list = deleted
4626 list = deleted
4909 for f in modified + added + clean:
4627 for f in modified + added + clean:
4910 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4628 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4911 ret = 1
4629 ret = 1
4912 else:
4630 else:
4913 list = deleted + clean
4631 list = deleted + clean
4914 for f in modified:
4632 for f in modified:
4915 ui.warn(_('not removing %s: file is modified (use -f'
4633 ui.warn(_('not removing %s: file is modified (use -f'
4916 ' to force removal)\n') % m.rel(f))
4634 ' to force removal)\n') % m.rel(f))
4917 ret = 1
4635 ret = 1
4918 for f in added:
4636 for f in added:
4919 ui.warn(_('not removing %s: file has been marked for add'
4637 ui.warn(_('not removing %s: file has been marked for add'
4920 ' (use forget to undo)\n') % m.rel(f))
4638 ' (use forget to undo)\n') % m.rel(f))
4921 ret = 1
4639 ret = 1
4922
4640
4923 for f in sorted(list):
4641 for f in sorted(list):
4924 if ui.verbose or not m.exact(f):
4642 if ui.verbose or not m.exact(f):
4925 ui.status(_('removing %s\n') % m.rel(f))
4643 ui.status(_('removing %s\n') % m.rel(f))
4926
4644
4927 wlock = repo.wlock()
4645 wlock = repo.wlock()
4928 try:
4646 try:
4929 if not after:
4647 if not after:
4930 for f in list:
4648 for f in list:
4931 if f in added:
4649 if f in added:
4932 continue # we never unlink added files on remove
4650 continue # we never unlink added files on remove
4933 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4651 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4934 repo[None].forget(list)
4652 repo[None].forget(list)
4935 finally:
4653 finally:
4936 wlock.release()
4654 wlock.release()
4937
4655
4938 return ret
4656 return ret
4939
4657
4940 @command('rename|move|mv',
4658 @command('rename|move|mv',
4941 [('A', 'after', None, _('record a rename that has already occurred')),
4659 [('A', 'after', None, _('record a rename that has already occurred')),
4942 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4660 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4943 ] + walkopts + dryrunopts,
4661 ] + walkopts + dryrunopts,
4944 _('[OPTION]... SOURCE... DEST'))
4662 _('[OPTION]... SOURCE... DEST'))
4945 def rename(ui, repo, *pats, **opts):
4663 def rename(ui, repo, *pats, **opts):
4946 """rename files; equivalent of copy + remove
4664 """rename files; equivalent of copy + remove
4947
4665
4948 Mark dest as copies of sources; mark sources for deletion. If dest
4666 Mark dest as copies of sources; mark sources for deletion. If dest
4949 is a directory, copies are put in that directory. If dest is a
4667 is a directory, copies are put in that directory. If dest is a
4950 file, there can only be one source.
4668 file, there can only be one source.
4951
4669
4952 By default, this command copies the contents of files as they
4670 By default, this command copies the contents of files as they
4953 exist in the working directory. If invoked with -A/--after, the
4671 exist in the working directory. If invoked with -A/--after, the
4954 operation is recorded, but no copying is performed.
4672 operation is recorded, but no copying is performed.
4955
4673
4956 This command takes effect at the next commit. To undo a rename
4674 This command takes effect at the next commit. To undo a rename
4957 before that, see :hg:`revert`.
4675 before that, see :hg:`revert`.
4958
4676
4959 Returns 0 on success, 1 if errors are encountered.
4677 Returns 0 on success, 1 if errors are encountered.
4960 """
4678 """
4961 wlock = repo.wlock(False)
4679 wlock = repo.wlock(False)
4962 try:
4680 try:
4963 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4681 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4964 finally:
4682 finally:
4965 wlock.release()
4683 wlock.release()
4966
4684
4967 @command('resolve',
4685 @command('resolve',
4968 [('a', 'all', None, _('select all unresolved files')),
4686 [('a', 'all', None, _('select all unresolved files')),
4969 ('l', 'list', None, _('list state of files needing merge')),
4687 ('l', 'list', None, _('list state of files needing merge')),
4970 ('m', 'mark', None, _('mark files as resolved')),
4688 ('m', 'mark', None, _('mark files as resolved')),
4971 ('u', 'unmark', None, _('mark files as unresolved')),
4689 ('u', 'unmark', None, _('mark files as unresolved')),
4972 ('n', 'no-status', None, _('hide status prefix'))]
4690 ('n', 'no-status', None, _('hide status prefix'))]
4973 + mergetoolopts + walkopts,
4691 + mergetoolopts + walkopts,
4974 _('[OPTION]... [FILE]...'))
4692 _('[OPTION]... [FILE]...'))
4975 def resolve(ui, repo, *pats, **opts):
4693 def resolve(ui, repo, *pats, **opts):
4976 """redo merges or set/view the merge status of files
4694 """redo merges or set/view the merge status of files
4977
4695
4978 Merges with unresolved conflicts are often the result of
4696 Merges with unresolved conflicts are often the result of
4979 non-interactive merging using the ``internal:merge`` configuration
4697 non-interactive merging using the ``internal:merge`` configuration
4980 setting, or a command-line merge tool like ``diff3``. The resolve
4698 setting, or a command-line merge tool like ``diff3``. The resolve
4981 command is used to manage the files involved in a merge, after
4699 command is used to manage the files involved in a merge, after
4982 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4700 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4983 working directory must have two parents). See :hg:`help
4701 working directory must have two parents). See :hg:`help
4984 merge-tools` for information on configuring merge tools.
4702 merge-tools` for information on configuring merge tools.
4985
4703
4986 The resolve command can be used in the following ways:
4704 The resolve command can be used in the following ways:
4987
4705
4988 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4706 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4989 files, discarding any previous merge attempts. Re-merging is not
4707 files, discarding any previous merge attempts. Re-merging is not
4990 performed for files already marked as resolved. Use ``--all/-a``
4708 performed for files already marked as resolved. Use ``--all/-a``
4991 to select all unresolved files. ``--tool`` can be used to specify
4709 to select all unresolved files. ``--tool`` can be used to specify
4992 the merge tool used for the given files. It overrides the HGMERGE
4710 the merge tool used for the given files. It overrides the HGMERGE
4993 environment variable and your configuration files. Previous file
4711 environment variable and your configuration files. Previous file
4994 contents are saved with a ``.orig`` suffix.
4712 contents are saved with a ``.orig`` suffix.
4995
4713
4996 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4714 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4997 (e.g. after having manually fixed-up the files). The default is
4715 (e.g. after having manually fixed-up the files). The default is
4998 to mark all unresolved files.
4716 to mark all unresolved files.
4999
4717
5000 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4718 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5001 default is to mark all resolved files.
4719 default is to mark all resolved files.
5002
4720
5003 - :hg:`resolve -l`: list files which had or still have conflicts.
4721 - :hg:`resolve -l`: list files which had or still have conflicts.
5004 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4722 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5005
4723
5006 Note that Mercurial will not let you commit files with unresolved
4724 Note that Mercurial will not let you commit files with unresolved
5007 merge conflicts. You must use :hg:`resolve -m ...` before you can
4725 merge conflicts. You must use :hg:`resolve -m ...` before you can
5008 commit after a conflicting merge.
4726 commit after a conflicting merge.
5009
4727
5010 Returns 0 on success, 1 if any files fail a resolve attempt.
4728 Returns 0 on success, 1 if any files fail a resolve attempt.
5011 """
4729 """
5012
4730
5013 all, mark, unmark, show, nostatus = \
4731 all, mark, unmark, show, nostatus = \
5014 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4732 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5015
4733
5016 if (show and (mark or unmark)) or (mark and unmark):
4734 if (show and (mark or unmark)) or (mark and unmark):
5017 raise util.Abort(_("too many options specified"))
4735 raise util.Abort(_("too many options specified"))
5018 if pats and all:
4736 if pats and all:
5019 raise util.Abort(_("can't specify --all and patterns"))
4737 raise util.Abort(_("can't specify --all and patterns"))
5020 if not (all or pats or show or mark or unmark):
4738 if not (all or pats or show or mark or unmark):
5021 raise util.Abort(_('no files or directories specified; '
4739 raise util.Abort(_('no files or directories specified; '
5022 'use --all to remerge all files'))
4740 'use --all to remerge all files'))
5023
4741
5024 ms = mergemod.mergestate(repo)
4742 ms = mergemod.mergestate(repo)
5025 m = scmutil.match(repo[None], pats, opts)
4743 m = scmutil.match(repo[None], pats, opts)
5026 ret = 0
4744 ret = 0
5027
4745
5028 for f in ms:
4746 for f in ms:
5029 if m(f):
4747 if m(f):
5030 if show:
4748 if show:
5031 if nostatus:
4749 if nostatus:
5032 ui.write("%s\n" % f)
4750 ui.write("%s\n" % f)
5033 else:
4751 else:
5034 ui.write("%s %s\n" % (ms[f].upper(), f),
4752 ui.write("%s %s\n" % (ms[f].upper(), f),
5035 label='resolve.' +
4753 label='resolve.' +
5036 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4754 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5037 elif mark:
4755 elif mark:
5038 ms.mark(f, "r")
4756 ms.mark(f, "r")
5039 elif unmark:
4757 elif unmark:
5040 ms.mark(f, "u")
4758 ms.mark(f, "u")
5041 else:
4759 else:
5042 wctx = repo[None]
4760 wctx = repo[None]
5043 mctx = wctx.parents()[-1]
4761 mctx = wctx.parents()[-1]
5044
4762
5045 # backup pre-resolve (merge uses .orig for its own purposes)
4763 # backup pre-resolve (merge uses .orig for its own purposes)
5046 a = repo.wjoin(f)
4764 a = repo.wjoin(f)
5047 util.copyfile(a, a + ".resolve")
4765 util.copyfile(a, a + ".resolve")
5048
4766
5049 try:
4767 try:
5050 # resolve file
4768 # resolve file
5051 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4769 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
5052 if ms.resolve(f, wctx, mctx):
4770 if ms.resolve(f, wctx, mctx):
5053 ret = 1
4771 ret = 1
5054 finally:
4772 finally:
5055 ui.setconfig('ui', 'forcemerge', '')
4773 ui.setconfig('ui', 'forcemerge', '')
5056 ms.commit()
4774 ms.commit()
5057
4775
5058 # replace filemerge's .orig file with our resolve file
4776 # replace filemerge's .orig file with our resolve file
5059 util.rename(a + ".resolve", a + ".orig")
4777 util.rename(a + ".resolve", a + ".orig")
5060
4778
5061 ms.commit()
4779 ms.commit()
5062 return ret
4780 return ret
5063
4781
5064 @command('revert',
4782 @command('revert',
5065 [('a', 'all', None, _('revert all changes when no arguments given')),
4783 [('a', 'all', None, _('revert all changes when no arguments given')),
5066 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4784 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5067 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4785 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5068 ('C', 'no-backup', None, _('do not save backup copies of files')),
4786 ('C', 'no-backup', None, _('do not save backup copies of files')),
5069 ] + walkopts + dryrunopts,
4787 ] + walkopts + dryrunopts,
5070 _('[OPTION]... [-r REV] [NAME]...'))
4788 _('[OPTION]... [-r REV] [NAME]...'))
5071 def revert(ui, repo, *pats, **opts):
4789 def revert(ui, repo, *pats, **opts):
5072 """restore files to their checkout state
4790 """restore files to their checkout state
5073
4791
5074 .. note::
4792 .. note::
5075
4793
5076 To check out earlier revisions, you should use :hg:`update REV`.
4794 To check out earlier revisions, you should use :hg:`update REV`.
5077 To cancel an uncommitted merge (and lose your changes), use
4795 To cancel an uncommitted merge (and lose your changes), use
5078 :hg:`update --clean .`.
4796 :hg:`update --clean .`.
5079
4797
5080 With no revision specified, revert the specified files or directories
4798 With no revision specified, revert the specified files or directories
5081 to the contents they had in the parent of the working directory.
4799 to the contents they had in the parent of the working directory.
5082 This restores the contents of files to an unmodified
4800 This restores the contents of files to an unmodified
5083 state and unschedules adds, removes, copies, and renames. If the
4801 state and unschedules adds, removes, copies, and renames. If the
5084 working directory has two parents, you must explicitly specify a
4802 working directory has two parents, you must explicitly specify a
5085 revision.
4803 revision.
5086
4804
5087 Using the -r/--rev or -d/--date options, revert the given files or
4805 Using the -r/--rev or -d/--date options, revert the given files or
5088 directories to their states as of a specific revision. Because
4806 directories to their states as of a specific revision. Because
5089 revert does not change the working directory parents, this will
4807 revert does not change the working directory parents, this will
5090 cause these files to appear modified. This can be helpful to "back
4808 cause these files to appear modified. This can be helpful to "back
5091 out" some or all of an earlier change. See :hg:`backout` for a
4809 out" some or all of an earlier change. See :hg:`backout` for a
5092 related method.
4810 related method.
5093
4811
5094 Modified files are saved with a .orig suffix before reverting.
4812 Modified files are saved with a .orig suffix before reverting.
5095 To disable these backups, use --no-backup.
4813 To disable these backups, use --no-backup.
5096
4814
5097 See :hg:`help dates` for a list of formats valid for -d/--date.
4815 See :hg:`help dates` for a list of formats valid for -d/--date.
5098
4816
5099 Returns 0 on success.
4817 Returns 0 on success.
5100 """
4818 """
5101
4819
5102 if opts.get("date"):
4820 if opts.get("date"):
5103 if opts.get("rev"):
4821 if opts.get("rev"):
5104 raise util.Abort(_("you can't specify a revision and a date"))
4822 raise util.Abort(_("you can't specify a revision and a date"))
5105 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4823 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5106
4824
5107 parent, p2 = repo.dirstate.parents()
4825 parent, p2 = repo.dirstate.parents()
5108 if not opts.get('rev') and p2 != nullid:
4826 if not opts.get('rev') and p2 != nullid:
5109 # revert after merge is a trap for new users (issue2915)
4827 # revert after merge is a trap for new users (issue2915)
5110 raise util.Abort(_('uncommitted merge with no revision specified'),
4828 raise util.Abort(_('uncommitted merge with no revision specified'),
5111 hint=_('use "hg update" or see "hg help revert"'))
4829 hint=_('use "hg update" or see "hg help revert"'))
5112
4830
5113 ctx = scmutil.revsingle(repo, opts.get('rev'))
4831 ctx = scmutil.revsingle(repo, opts.get('rev'))
5114
4832
5115 if not pats and not opts.get('all'):
4833 if not pats and not opts.get('all'):
5116 msg = _("no files or directories specified")
4834 msg = _("no files or directories specified")
5117 if p2 != nullid:
4835 if p2 != nullid:
5118 hint = _("uncommitted merge, use --all to discard all changes,"
4836 hint = _("uncommitted merge, use --all to discard all changes,"
5119 " or 'hg update -C .' to abort the merge")
4837 " or 'hg update -C .' to abort the merge")
5120 raise util.Abort(msg, hint=hint)
4838 raise util.Abort(msg, hint=hint)
5121 dirty = util.any(repo.status())
4839 dirty = util.any(repo.status())
5122 node = ctx.node()
4840 node = ctx.node()
5123 if node != parent:
4841 if node != parent:
5124 if dirty:
4842 if dirty:
5125 hint = _("uncommitted changes, use --all to discard all"
4843 hint = _("uncommitted changes, use --all to discard all"
5126 " changes, or 'hg update %s' to update") % ctx.rev()
4844 " changes, or 'hg update %s' to update") % ctx.rev()
5127 else:
4845 else:
5128 hint = _("use --all to revert all files,"
4846 hint = _("use --all to revert all files,"
5129 " or 'hg update %s' to update") % ctx.rev()
4847 " or 'hg update %s' to update") % ctx.rev()
5130 elif dirty:
4848 elif dirty:
5131 hint = _("uncommitted changes, use --all to discard all changes")
4849 hint = _("uncommitted changes, use --all to discard all changes")
5132 else:
4850 else:
5133 hint = _("use --all to revert all files")
4851 hint = _("use --all to revert all files")
5134 raise util.Abort(msg, hint=hint)
4852 raise util.Abort(msg, hint=hint)
5135
4853
5136 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4854 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5137
4855
5138 @command('rollback', dryrunopts +
4856 @command('rollback', dryrunopts +
5139 [('f', 'force', False, _('ignore safety measures'))])
4857 [('f', 'force', False, _('ignore safety measures'))])
5140 def rollback(ui, repo, **opts):
4858 def rollback(ui, repo, **opts):
5141 """roll back the last transaction (dangerous)
4859 """roll back the last transaction (dangerous)
5142
4860
5143 This command should be used with care. There is only one level of
4861 This command should be used with care. There is only one level of
5144 rollback, and there is no way to undo a rollback. It will also
4862 rollback, and there is no way to undo a rollback. It will also
5145 restore the dirstate at the time of the last transaction, losing
4863 restore the dirstate at the time of the last transaction, losing
5146 any dirstate changes since that time. This command does not alter
4864 any dirstate changes since that time. This command does not alter
5147 the working directory.
4865 the working directory.
5148
4866
5149 Transactions are used to encapsulate the effects of all commands
4867 Transactions are used to encapsulate the effects of all commands
5150 that create new changesets or propagate existing changesets into a
4868 that create new changesets or propagate existing changesets into a
5151 repository.
4869 repository.
5152
4870
5153 .. container:: verbose
4871 .. container:: verbose
5154
4872
5155 For example, the following commands are transactional, and their
4873 For example, the following commands are transactional, and their
5156 effects can be rolled back:
4874 effects can be rolled back:
5157
4875
5158 - commit
4876 - commit
5159 - import
4877 - import
5160 - pull
4878 - pull
5161 - push (with this repository as the destination)
4879 - push (with this repository as the destination)
5162 - unbundle
4880 - unbundle
5163
4881
5164 To avoid permanent data loss, rollback will refuse to rollback a
4882 To avoid permanent data loss, rollback will refuse to rollback a
5165 commit transaction if it isn't checked out. Use --force to
4883 commit transaction if it isn't checked out. Use --force to
5166 override this protection.
4884 override this protection.
5167
4885
5168 This command is not intended for use on public repositories. Once
4886 This command is not intended for use on public repositories. Once
5169 changes are visible for pull by other users, rolling a transaction
4887 changes are visible for pull by other users, rolling a transaction
5170 back locally is ineffective (someone else may already have pulled
4888 back locally is ineffective (someone else may already have pulled
5171 the changes). Furthermore, a race is possible with readers of the
4889 the changes). Furthermore, a race is possible with readers of the
5172 repository; for example an in-progress pull from the repository
4890 repository; for example an in-progress pull from the repository
5173 may fail if a rollback is performed.
4891 may fail if a rollback is performed.
5174
4892
5175 Returns 0 on success, 1 if no rollback data is available.
4893 Returns 0 on success, 1 if no rollback data is available.
5176 """
4894 """
5177 return repo.rollback(dryrun=opts.get('dry_run'),
4895 return repo.rollback(dryrun=opts.get('dry_run'),
5178 force=opts.get('force'))
4896 force=opts.get('force'))
5179
4897
5180 @command('root', [])
4898 @command('root', [])
5181 def root(ui, repo):
4899 def root(ui, repo):
5182 """print the root (top) of the current working directory
4900 """print the root (top) of the current working directory
5183
4901
5184 Print the root directory of the current repository.
4902 Print the root directory of the current repository.
5185
4903
5186 Returns 0 on success.
4904 Returns 0 on success.
5187 """
4905 """
5188 ui.write(repo.root + "\n")
4906 ui.write(repo.root + "\n")
5189
4907
5190 @command('^serve',
4908 @command('^serve',
5191 [('A', 'accesslog', '', _('name of access log file to write to'),
4909 [('A', 'accesslog', '', _('name of access log file to write to'),
5192 _('FILE')),
4910 _('FILE')),
5193 ('d', 'daemon', None, _('run server in background')),
4911 ('d', 'daemon', None, _('run server in background')),
5194 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4912 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5195 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4913 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5196 # use string type, then we can check if something was passed
4914 # use string type, then we can check if something was passed
5197 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4915 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5198 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4916 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5199 _('ADDR')),
4917 _('ADDR')),
5200 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4918 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5201 _('PREFIX')),
4919 _('PREFIX')),
5202 ('n', 'name', '',
4920 ('n', 'name', '',
5203 _('name to show in web pages (default: working directory)'), _('NAME')),
4921 _('name to show in web pages (default: working directory)'), _('NAME')),
5204 ('', 'web-conf', '',
4922 ('', 'web-conf', '',
5205 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4923 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5206 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4924 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5207 _('FILE')),
4925 _('FILE')),
5208 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4926 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5209 ('', 'stdio', None, _('for remote clients')),
4927 ('', 'stdio', None, _('for remote clients')),
5210 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4928 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5211 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4929 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5212 ('', 'style', '', _('template style to use'), _('STYLE')),
4930 ('', 'style', '', _('template style to use'), _('STYLE')),
5213 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4931 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5214 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4932 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5215 _('[OPTION]...'))
4933 _('[OPTION]...'))
5216 def serve(ui, repo, **opts):
4934 def serve(ui, repo, **opts):
5217 """start stand-alone webserver
4935 """start stand-alone webserver
5218
4936
5219 Start a local HTTP repository browser and pull server. You can use
4937 Start a local HTTP repository browser and pull server. You can use
5220 this for ad-hoc sharing and browsing of repositories. It is
4938 this for ad-hoc sharing and browsing of repositories. It is
5221 recommended to use a real web server to serve a repository for
4939 recommended to use a real web server to serve a repository for
5222 longer periods of time.
4940 longer periods of time.
5223
4941
5224 Please note that the server does not implement access control.
4942 Please note that the server does not implement access control.
5225 This means that, by default, anybody can read from the server and
4943 This means that, by default, anybody can read from the server and
5226 nobody can write to it by default. Set the ``web.allow_push``
4944 nobody can write to it by default. Set the ``web.allow_push``
5227 option to ``*`` to allow everybody to push to the server. You
4945 option to ``*`` to allow everybody to push to the server. You
5228 should use a real web server if you need to authenticate users.
4946 should use a real web server if you need to authenticate users.
5229
4947
5230 By default, the server logs accesses to stdout and errors to
4948 By default, the server logs accesses to stdout and errors to
5231 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4949 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5232 files.
4950 files.
5233
4951
5234 To have the server choose a free port number to listen on, specify
4952 To have the server choose a free port number to listen on, specify
5235 a port number of 0; in this case, the server will print the port
4953 a port number of 0; in this case, the server will print the port
5236 number it uses.
4954 number it uses.
5237
4955
5238 Returns 0 on success.
4956 Returns 0 on success.
5239 """
4957 """
5240
4958
5241 if opts["stdio"] and opts["cmdserver"]:
4959 if opts["stdio"] and opts["cmdserver"]:
5242 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4960 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5243
4961
5244 def checkrepo():
4962 def checkrepo():
5245 if repo is None:
4963 if repo is None:
5246 raise error.RepoError(_("there is no Mercurial repository here"
4964 raise error.RepoError(_("there is no Mercurial repository here"
5247 " (.hg not found)"))
4965 " (.hg not found)"))
5248
4966
5249 if opts["stdio"]:
4967 if opts["stdio"]:
5250 checkrepo()
4968 checkrepo()
5251 s = sshserver.sshserver(ui, repo)
4969 s = sshserver.sshserver(ui, repo)
5252 s.serve_forever()
4970 s.serve_forever()
5253
4971
5254 if opts["cmdserver"]:
4972 if opts["cmdserver"]:
5255 checkrepo()
4973 checkrepo()
5256 s = commandserver.server(ui, repo, opts["cmdserver"])
4974 s = commandserver.server(ui, repo, opts["cmdserver"])
5257 return s.serve()
4975 return s.serve()
5258
4976
5259 # this way we can check if something was given in the command-line
4977 # this way we can check if something was given in the command-line
5260 if opts.get('port'):
4978 if opts.get('port'):
5261 opts['port'] = util.getport(opts.get('port'))
4979 opts['port'] = util.getport(opts.get('port'))
5262
4980
5263 baseui = repo and repo.baseui or ui
4981 baseui = repo and repo.baseui or ui
5264 optlist = ("name templates style address port prefix ipv6"
4982 optlist = ("name templates style address port prefix ipv6"
5265 " accesslog errorlog certificate encoding")
4983 " accesslog errorlog certificate encoding")
5266 for o in optlist.split():
4984 for o in optlist.split():
5267 val = opts.get(o, '')
4985 val = opts.get(o, '')
5268 if val in (None, ''): # should check against default options instead
4986 if val in (None, ''): # should check against default options instead
5269 continue
4987 continue
5270 baseui.setconfig("web", o, val)
4988 baseui.setconfig("web", o, val)
5271 if repo and repo.ui != baseui:
4989 if repo and repo.ui != baseui:
5272 repo.ui.setconfig("web", o, val)
4990 repo.ui.setconfig("web", o, val)
5273
4991
5274 o = opts.get('web_conf') or opts.get('webdir_conf')
4992 o = opts.get('web_conf') or opts.get('webdir_conf')
5275 if not o:
4993 if not o:
5276 if not repo:
4994 if not repo:
5277 raise error.RepoError(_("there is no Mercurial repository"
4995 raise error.RepoError(_("there is no Mercurial repository"
5278 " here (.hg not found)"))
4996 " here (.hg not found)"))
5279 o = repo.root
4997 o = repo.root
5280
4998
5281 app = hgweb.hgweb(o, baseui=ui)
4999 app = hgweb.hgweb(o, baseui=ui)
5282
5000
5283 class service(object):
5001 class service(object):
5284 def init(self):
5002 def init(self):
5285 util.setsignalhandler()
5003 util.setsignalhandler()
5286 self.httpd = hgweb.server.create_server(ui, app)
5004 self.httpd = hgweb.server.create_server(ui, app)
5287
5005
5288 if opts['port'] and not ui.verbose:
5006 if opts['port'] and not ui.verbose:
5289 return
5007 return
5290
5008
5291 if self.httpd.prefix:
5009 if self.httpd.prefix:
5292 prefix = self.httpd.prefix.strip('/') + '/'
5010 prefix = self.httpd.prefix.strip('/') + '/'
5293 else:
5011 else:
5294 prefix = ''
5012 prefix = ''
5295
5013
5296 port = ':%d' % self.httpd.port
5014 port = ':%d' % self.httpd.port
5297 if port == ':80':
5015 if port == ':80':
5298 port = ''
5016 port = ''
5299
5017
5300 bindaddr = self.httpd.addr
5018 bindaddr = self.httpd.addr
5301 if bindaddr == '0.0.0.0':
5019 if bindaddr == '0.0.0.0':
5302 bindaddr = '*'
5020 bindaddr = '*'
5303 elif ':' in bindaddr: # IPv6
5021 elif ':' in bindaddr: # IPv6
5304 bindaddr = '[%s]' % bindaddr
5022 bindaddr = '[%s]' % bindaddr
5305
5023
5306 fqaddr = self.httpd.fqaddr
5024 fqaddr = self.httpd.fqaddr
5307 if ':' in fqaddr:
5025 if ':' in fqaddr:
5308 fqaddr = '[%s]' % fqaddr
5026 fqaddr = '[%s]' % fqaddr
5309 if opts['port']:
5027 if opts['port']:
5310 write = ui.status
5028 write = ui.status
5311 else:
5029 else:
5312 write = ui.write
5030 write = ui.write
5313 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5031 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5314 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5032 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5315
5033
5316 def run(self):
5034 def run(self):
5317 self.httpd.serve_forever()
5035 self.httpd.serve_forever()
5318
5036
5319 service = service()
5037 service = service()
5320
5038
5321 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5039 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5322
5040
5323 @command('showconfig|debugconfig',
5041 @command('showconfig|debugconfig',
5324 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5042 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5325 _('[-u] [NAME]...'))
5043 _('[-u] [NAME]...'))
5326 def showconfig(ui, repo, *values, **opts):
5044 def showconfig(ui, repo, *values, **opts):
5327 """show combined config settings from all hgrc files
5045 """show combined config settings from all hgrc files
5328
5046
5329 With no arguments, print names and values of all config items.
5047 With no arguments, print names and values of all config items.
5330
5048
5331 With one argument of the form section.name, print just the value
5049 With one argument of the form section.name, print just the value
5332 of that config item.
5050 of that config item.
5333
5051
5334 With multiple arguments, print names and values of all config
5052 With multiple arguments, print names and values of all config
5335 items with matching section names.
5053 items with matching section names.
5336
5054
5337 With --debug, the source (filename and line number) is printed
5055 With --debug, the source (filename and line number) is printed
5338 for each config item.
5056 for each config item.
5339
5057
5340 Returns 0 on success.
5058 Returns 0 on success.
5341 """
5059 """
5342
5060
5343 for f in scmutil.rcpath():
5061 for f in scmutil.rcpath():
5344 ui.debug('read config from: %s\n' % f)
5062 ui.debug('read config from: %s\n' % f)
5345 untrusted = bool(opts.get('untrusted'))
5063 untrusted = bool(opts.get('untrusted'))
5346 if values:
5064 if values:
5347 sections = [v for v in values if '.' not in v]
5065 sections = [v for v in values if '.' not in v]
5348 items = [v for v in values if '.' in v]
5066 items = [v for v in values if '.' in v]
5349 if len(items) > 1 or items and sections:
5067 if len(items) > 1 or items and sections:
5350 raise util.Abort(_('only one config item permitted'))
5068 raise util.Abort(_('only one config item permitted'))
5351 for section, name, value in ui.walkconfig(untrusted=untrusted):
5069 for section, name, value in ui.walkconfig(untrusted=untrusted):
5352 value = str(value).replace('\n', '\\n')
5070 value = str(value).replace('\n', '\\n')
5353 sectname = section + '.' + name
5071 sectname = section + '.' + name
5354 if values:
5072 if values:
5355 for v in values:
5073 for v in values:
5356 if v == section:
5074 if v == section:
5357 ui.debug('%s: ' %
5075 ui.debug('%s: ' %
5358 ui.configsource(section, name, untrusted))
5076 ui.configsource(section, name, untrusted))
5359 ui.write('%s=%s\n' % (sectname, value))
5077 ui.write('%s=%s\n' % (sectname, value))
5360 elif v == sectname:
5078 elif v == sectname:
5361 ui.debug('%s: ' %
5079 ui.debug('%s: ' %
5362 ui.configsource(section, name, untrusted))
5080 ui.configsource(section, name, untrusted))
5363 ui.write(value, '\n')
5081 ui.write(value, '\n')
5364 else:
5082 else:
5365 ui.debug('%s: ' %
5083 ui.debug('%s: ' %
5366 ui.configsource(section, name, untrusted))
5084 ui.configsource(section, name, untrusted))
5367 ui.write('%s=%s\n' % (sectname, value))
5085 ui.write('%s=%s\n' % (sectname, value))
5368
5086
5369 @command('^status|st',
5087 @command('^status|st',
5370 [('A', 'all', None, _('show status of all files')),
5088 [('A', 'all', None, _('show status of all files')),
5371 ('m', 'modified', None, _('show only modified files')),
5089 ('m', 'modified', None, _('show only modified files')),
5372 ('a', 'added', None, _('show only added files')),
5090 ('a', 'added', None, _('show only added files')),
5373 ('r', 'removed', None, _('show only removed files')),
5091 ('r', 'removed', None, _('show only removed files')),
5374 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5092 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5375 ('c', 'clean', None, _('show only files without changes')),
5093 ('c', 'clean', None, _('show only files without changes')),
5376 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5094 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5377 ('i', 'ignored', None, _('show only ignored files')),
5095 ('i', 'ignored', None, _('show only ignored files')),
5378 ('n', 'no-status', None, _('hide status prefix')),
5096 ('n', 'no-status', None, _('hide status prefix')),
5379 ('C', 'copies', None, _('show source of copied files')),
5097 ('C', 'copies', None, _('show source of copied files')),
5380 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5098 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5381 ('', 'rev', [], _('show difference from revision'), _('REV')),
5099 ('', 'rev', [], _('show difference from revision'), _('REV')),
5382 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5100 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5383 ] + walkopts + subrepoopts,
5101 ] + walkopts + subrepoopts,
5384 _('[OPTION]... [FILE]...'))
5102 _('[OPTION]... [FILE]...'))
5385 def status(ui, repo, *pats, **opts):
5103 def status(ui, repo, *pats, **opts):
5386 """show changed files in the working directory
5104 """show changed files in the working directory
5387
5105
5388 Show status of files in the repository. If names are given, only
5106 Show status of files in the repository. If names are given, only
5389 files that match are shown. Files that are clean or ignored or
5107 files that match are shown. Files that are clean or ignored or
5390 the source of a copy/move operation, are not listed unless
5108 the source of a copy/move operation, are not listed unless
5391 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5109 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5392 Unless options described with "show only ..." are given, the
5110 Unless options described with "show only ..." are given, the
5393 options -mardu are used.
5111 options -mardu are used.
5394
5112
5395 Option -q/--quiet hides untracked (unknown and ignored) files
5113 Option -q/--quiet hides untracked (unknown and ignored) files
5396 unless explicitly requested with -u/--unknown or -i/--ignored.
5114 unless explicitly requested with -u/--unknown or -i/--ignored.
5397
5115
5398 .. note::
5116 .. note::
5399 status may appear to disagree with diff if permissions have
5117 status may appear to disagree with diff if permissions have
5400 changed or a merge has occurred. The standard diff format does
5118 changed or a merge has occurred. The standard diff format does
5401 not report permission changes and diff only reports changes
5119 not report permission changes and diff only reports changes
5402 relative to one merge parent.
5120 relative to one merge parent.
5403
5121
5404 If one revision is given, it is used as the base revision.
5122 If one revision is given, it is used as the base revision.
5405 If two revisions are given, the differences between them are
5123 If two revisions are given, the differences between them are
5406 shown. The --change option can also be used as a shortcut to list
5124 shown. The --change option can also be used as a shortcut to list
5407 the changed files of a revision from its first parent.
5125 the changed files of a revision from its first parent.
5408
5126
5409 The codes used to show the status of files are::
5127 The codes used to show the status of files are::
5410
5128
5411 M = modified
5129 M = modified
5412 A = added
5130 A = added
5413 R = removed
5131 R = removed
5414 C = clean
5132 C = clean
5415 ! = missing (deleted by non-hg command, but still tracked)
5133 ! = missing (deleted by non-hg command, but still tracked)
5416 ? = not tracked
5134 ? = not tracked
5417 I = ignored
5135 I = ignored
5418 = origin of the previous file listed as A (added)
5136 = origin of the previous file listed as A (added)
5419
5137
5420 .. container:: verbose
5138 .. container:: verbose
5421
5139
5422 Examples:
5140 Examples:
5423
5141
5424 - show changes in the working directory relative to a
5142 - show changes in the working directory relative to a
5425 changeset::
5143 changeset::
5426
5144
5427 hg status --rev 9353
5145 hg status --rev 9353
5428
5146
5429 - show all changes including copies in an existing changeset::
5147 - show all changes including copies in an existing changeset::
5430
5148
5431 hg status --copies --change 9353
5149 hg status --copies --change 9353
5432
5150
5433 - get a NUL separated list of added files, suitable for xargs::
5151 - get a NUL separated list of added files, suitable for xargs::
5434
5152
5435 hg status -an0
5153 hg status -an0
5436
5154
5437 Returns 0 on success.
5155 Returns 0 on success.
5438 """
5156 """
5439
5157
5440 revs = opts.get('rev')
5158 revs = opts.get('rev')
5441 change = opts.get('change')
5159 change = opts.get('change')
5442
5160
5443 if revs and change:
5161 if revs and change:
5444 msg = _('cannot specify --rev and --change at the same time')
5162 msg = _('cannot specify --rev and --change at the same time')
5445 raise util.Abort(msg)
5163 raise util.Abort(msg)
5446 elif change:
5164 elif change:
5447 node2 = scmutil.revsingle(repo, change, None).node()
5165 node2 = scmutil.revsingle(repo, change, None).node()
5448 node1 = repo[node2].p1().node()
5166 node1 = repo[node2].p1().node()
5449 else:
5167 else:
5450 node1, node2 = scmutil.revpair(repo, revs)
5168 node1, node2 = scmutil.revpair(repo, revs)
5451
5169
5452 cwd = (pats and repo.getcwd()) or ''
5170 cwd = (pats and repo.getcwd()) or ''
5453 end = opts.get('print0') and '\0' or '\n'
5171 end = opts.get('print0') and '\0' or '\n'
5454 copy = {}
5172 copy = {}
5455 states = 'modified added removed deleted unknown ignored clean'.split()
5173 states = 'modified added removed deleted unknown ignored clean'.split()
5456 show = [k for k in states if opts.get(k)]
5174 show = [k for k in states if opts.get(k)]
5457 if opts.get('all'):
5175 if opts.get('all'):
5458 show += ui.quiet and (states[:4] + ['clean']) or states
5176 show += ui.quiet and (states[:4] + ['clean']) or states
5459 if not show:
5177 if not show:
5460 show = ui.quiet and states[:4] or states[:5]
5178 show = ui.quiet and states[:4] or states[:5]
5461
5179
5462 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5180 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5463 'ignored' in show, 'clean' in show, 'unknown' in show,
5181 'ignored' in show, 'clean' in show, 'unknown' in show,
5464 opts.get('subrepos'))
5182 opts.get('subrepos'))
5465 changestates = zip(states, 'MAR!?IC', stat)
5183 changestates = zip(states, 'MAR!?IC', stat)
5466
5184
5467 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5185 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5468 copy = copies.pathcopies(repo[node1], repo[node2])
5186 copy = copies.pathcopies(repo[node1], repo[node2])
5469
5187
5470 fm = ui.formatter('status', opts)
5188 fm = ui.formatter('status', opts)
5471 fmt = '%s' + end
5189 fmt = '%s' + end
5472 showchar = not opts.get('no_status')
5190 showchar = not opts.get('no_status')
5473
5191
5474 for state, char, files in changestates:
5192 for state, char, files in changestates:
5475 if state in show:
5193 if state in show:
5476 label = 'status.' + state
5194 label = 'status.' + state
5477 for f in files:
5195 for f in files:
5478 fm.startitem()
5196 fm.startitem()
5479 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5197 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5480 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5198 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5481 if f in copy:
5199 if f in copy:
5482 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5200 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5483 label='status.copied')
5201 label='status.copied')
5484 fm.end()
5202 fm.end()
5485
5203
5486 @command('^summary|sum',
5204 @command('^summary|sum',
5487 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5205 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5488 def summary(ui, repo, **opts):
5206 def summary(ui, repo, **opts):
5489 """summarize working directory state
5207 """summarize working directory state
5490
5208
5491 This generates a brief summary of the working directory state,
5209 This generates a brief summary of the working directory state,
5492 including parents, branch, commit status, and available updates.
5210 including parents, branch, commit status, and available updates.
5493
5211
5494 With the --remote option, this will check the default paths for
5212 With the --remote option, this will check the default paths for
5495 incoming and outgoing changes. This can be time-consuming.
5213 incoming and outgoing changes. This can be time-consuming.
5496
5214
5497 Returns 0 on success.
5215 Returns 0 on success.
5498 """
5216 """
5499
5217
5500 ctx = repo[None]
5218 ctx = repo[None]
5501 parents = ctx.parents()
5219 parents = ctx.parents()
5502 pnode = parents[0].node()
5220 pnode = parents[0].node()
5503 marks = []
5221 marks = []
5504
5222
5505 for p in parents:
5223 for p in parents:
5506 # label with log.changeset (instead of log.parent) since this
5224 # label with log.changeset (instead of log.parent) since this
5507 # shows a working directory parent *changeset*:
5225 # shows a working directory parent *changeset*:
5508 # i18n: column positioning for "hg summary"
5226 # i18n: column positioning for "hg summary"
5509 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5227 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5510 label='log.changeset changeset.%s' % p.phasestr())
5228 label='log.changeset changeset.%s' % p.phasestr())
5511 ui.write(' '.join(p.tags()), label='log.tag')
5229 ui.write(' '.join(p.tags()), label='log.tag')
5512 if p.bookmarks():
5230 if p.bookmarks():
5513 marks.extend(p.bookmarks())
5231 marks.extend(p.bookmarks())
5514 if p.rev() == -1:
5232 if p.rev() == -1:
5515 if not len(repo):
5233 if not len(repo):
5516 ui.write(_(' (empty repository)'))
5234 ui.write(_(' (empty repository)'))
5517 else:
5235 else:
5518 ui.write(_(' (no revision checked out)'))
5236 ui.write(_(' (no revision checked out)'))
5519 ui.write('\n')
5237 ui.write('\n')
5520 if p.description():
5238 if p.description():
5521 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5239 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5522 label='log.summary')
5240 label='log.summary')
5523
5241
5524 branch = ctx.branch()
5242 branch = ctx.branch()
5525 bheads = repo.branchheads(branch)
5243 bheads = repo.branchheads(branch)
5526 # i18n: column positioning for "hg summary"
5244 # i18n: column positioning for "hg summary"
5527 m = _('branch: %s\n') % branch
5245 m = _('branch: %s\n') % branch
5528 if branch != 'default':
5246 if branch != 'default':
5529 ui.write(m, label='log.branch')
5247 ui.write(m, label='log.branch')
5530 else:
5248 else:
5531 ui.status(m, label='log.branch')
5249 ui.status(m, label='log.branch')
5532
5250
5533 if marks:
5251 if marks:
5534 current = repo._bookmarkcurrent
5252 current = repo._bookmarkcurrent
5535 # i18n: column positioning for "hg summary"
5253 # i18n: column positioning for "hg summary"
5536 ui.write(_('bookmarks:'), label='log.bookmark')
5254 ui.write(_('bookmarks:'), label='log.bookmark')
5537 if current is not None:
5255 if current is not None:
5538 if current in marks:
5256 if current in marks:
5539 ui.write(' *' + current, label='bookmarks.current')
5257 ui.write(' *' + current, label='bookmarks.current')
5540 marks.remove(current)
5258 marks.remove(current)
5541 else:
5259 else:
5542 ui.write(' [%s]' % current, label='bookmarks.current')
5260 ui.write(' [%s]' % current, label='bookmarks.current')
5543 for m in marks:
5261 for m in marks:
5544 ui.write(' ' + m, label='log.bookmark')
5262 ui.write(' ' + m, label='log.bookmark')
5545 ui.write('\n', label='log.bookmark')
5263 ui.write('\n', label='log.bookmark')
5546
5264
5547 st = list(repo.status(unknown=True))[:6]
5265 st = list(repo.status(unknown=True))[:6]
5548
5266
5549 c = repo.dirstate.copies()
5267 c = repo.dirstate.copies()
5550 copied, renamed = [], []
5268 copied, renamed = [], []
5551 for d, s in c.iteritems():
5269 for d, s in c.iteritems():
5552 if s in st[2]:
5270 if s in st[2]:
5553 st[2].remove(s)
5271 st[2].remove(s)
5554 renamed.append(d)
5272 renamed.append(d)
5555 else:
5273 else:
5556 copied.append(d)
5274 copied.append(d)
5557 if d in st[1]:
5275 if d in st[1]:
5558 st[1].remove(d)
5276 st[1].remove(d)
5559 st.insert(3, renamed)
5277 st.insert(3, renamed)
5560 st.insert(4, copied)
5278 st.insert(4, copied)
5561
5279
5562 ms = mergemod.mergestate(repo)
5280 ms = mergemod.mergestate(repo)
5563 st.append([f for f in ms if ms[f] == 'u'])
5281 st.append([f for f in ms if ms[f] == 'u'])
5564
5282
5565 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5283 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5566 st.append(subs)
5284 st.append(subs)
5567
5285
5568 labels = [ui.label(_('%d modified'), 'status.modified'),
5286 labels = [ui.label(_('%d modified'), 'status.modified'),
5569 ui.label(_('%d added'), 'status.added'),
5287 ui.label(_('%d added'), 'status.added'),
5570 ui.label(_('%d removed'), 'status.removed'),
5288 ui.label(_('%d removed'), 'status.removed'),
5571 ui.label(_('%d renamed'), 'status.copied'),
5289 ui.label(_('%d renamed'), 'status.copied'),
5572 ui.label(_('%d copied'), 'status.copied'),
5290 ui.label(_('%d copied'), 'status.copied'),
5573 ui.label(_('%d deleted'), 'status.deleted'),
5291 ui.label(_('%d deleted'), 'status.deleted'),
5574 ui.label(_('%d unknown'), 'status.unknown'),
5292 ui.label(_('%d unknown'), 'status.unknown'),
5575 ui.label(_('%d ignored'), 'status.ignored'),
5293 ui.label(_('%d ignored'), 'status.ignored'),
5576 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5294 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5577 ui.label(_('%d subrepos'), 'status.modified')]
5295 ui.label(_('%d subrepos'), 'status.modified')]
5578 t = []
5296 t = []
5579 for s, l in zip(st, labels):
5297 for s, l in zip(st, labels):
5580 if s:
5298 if s:
5581 t.append(l % len(s))
5299 t.append(l % len(s))
5582
5300
5583 t = ', '.join(t)
5301 t = ', '.join(t)
5584 cleanworkdir = False
5302 cleanworkdir = False
5585
5303
5586 if len(parents) > 1:
5304 if len(parents) > 1:
5587 t += _(' (merge)')
5305 t += _(' (merge)')
5588 elif branch != parents[0].branch():
5306 elif branch != parents[0].branch():
5589 t += _(' (new branch)')
5307 t += _(' (new branch)')
5590 elif (parents[0].closesbranch() and
5308 elif (parents[0].closesbranch() and
5591 pnode in repo.branchheads(branch, closed=True)):
5309 pnode in repo.branchheads(branch, closed=True)):
5592 t += _(' (head closed)')
5310 t += _(' (head closed)')
5593 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5311 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5594 t += _(' (clean)')
5312 t += _(' (clean)')
5595 cleanworkdir = True
5313 cleanworkdir = True
5596 elif pnode not in bheads:
5314 elif pnode not in bheads:
5597 t += _(' (new branch head)')
5315 t += _(' (new branch head)')
5598
5316
5599 if cleanworkdir:
5317 if cleanworkdir:
5600 # i18n: column positioning for "hg summary"
5318 # i18n: column positioning for "hg summary"
5601 ui.status(_('commit: %s\n') % t.strip())
5319 ui.status(_('commit: %s\n') % t.strip())
5602 else:
5320 else:
5603 # i18n: column positioning for "hg summary"
5321 # i18n: column positioning for "hg summary"
5604 ui.write(_('commit: %s\n') % t.strip())
5322 ui.write(_('commit: %s\n') % t.strip())
5605
5323
5606 # all ancestors of branch heads - all ancestors of parent = new csets
5324 # all ancestors of branch heads - all ancestors of parent = new csets
5607 new = [0] * len(repo)
5325 new = [0] * len(repo)
5608 cl = repo.changelog
5326 cl = repo.changelog
5609 for a in [cl.rev(n) for n in bheads]:
5327 for a in [cl.rev(n) for n in bheads]:
5610 new[a] = 1
5328 new[a] = 1
5611 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5329 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5612 new[a] = 1
5330 new[a] = 1
5613 for a in [p.rev() for p in parents]:
5331 for a in [p.rev() for p in parents]:
5614 if a >= 0:
5332 if a >= 0:
5615 new[a] = 0
5333 new[a] = 0
5616 for a in cl.ancestors([p.rev() for p in parents]):
5334 for a in cl.ancestors([p.rev() for p in parents]):
5617 new[a] = 0
5335 new[a] = 0
5618 new = sum(new)
5336 new = sum(new)
5619
5337
5620 if new == 0:
5338 if new == 0:
5621 # i18n: column positioning for "hg summary"
5339 # i18n: column positioning for "hg summary"
5622 ui.status(_('update: (current)\n'))
5340 ui.status(_('update: (current)\n'))
5623 elif pnode not in bheads:
5341 elif pnode not in bheads:
5624 # i18n: column positioning for "hg summary"
5342 # i18n: column positioning for "hg summary"
5625 ui.write(_('update: %d new changesets (update)\n') % new)
5343 ui.write(_('update: %d new changesets (update)\n') % new)
5626 else:
5344 else:
5627 # i18n: column positioning for "hg summary"
5345 # i18n: column positioning for "hg summary"
5628 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5346 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5629 (new, len(bheads)))
5347 (new, len(bheads)))
5630
5348
5631 if opts.get('remote'):
5349 if opts.get('remote'):
5632 t = []
5350 t = []
5633 source, branches = hg.parseurl(ui.expandpath('default'))
5351 source, branches = hg.parseurl(ui.expandpath('default'))
5634 other = hg.peer(repo, {}, source)
5352 other = hg.peer(repo, {}, source)
5635 revs, checkout = hg.addbranchrevs(repo, other, branches,
5353 revs, checkout = hg.addbranchrevs(repo, other, branches,
5636 opts.get('rev'))
5354 opts.get('rev'))
5637 ui.debug('comparing with %s\n' % util.hidepassword(source))
5355 ui.debug('comparing with %s\n' % util.hidepassword(source))
5638 repo.ui.pushbuffer()
5356 repo.ui.pushbuffer()
5639 commoninc = discovery.findcommonincoming(repo, other)
5357 commoninc = discovery.findcommonincoming(repo, other)
5640 _common, incoming, _rheads = commoninc
5358 _common, incoming, _rheads = commoninc
5641 repo.ui.popbuffer()
5359 repo.ui.popbuffer()
5642 if incoming:
5360 if incoming:
5643 t.append(_('1 or more incoming'))
5361 t.append(_('1 or more incoming'))
5644
5362
5645 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5363 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5646 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5364 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5647 if source != dest:
5365 if source != dest:
5648 other = hg.peer(repo, {}, dest)
5366 other = hg.peer(repo, {}, dest)
5649 commoninc = None
5367 commoninc = None
5650 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5368 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5651 repo.ui.pushbuffer()
5369 repo.ui.pushbuffer()
5652 outgoing = discovery.findcommonoutgoing(repo, other,
5370 outgoing = discovery.findcommonoutgoing(repo, other,
5653 commoninc=commoninc)
5371 commoninc=commoninc)
5654 repo.ui.popbuffer()
5372 repo.ui.popbuffer()
5655 o = outgoing.missing
5373 o = outgoing.missing
5656 if o:
5374 if o:
5657 t.append(_('%d outgoing') % len(o))
5375 t.append(_('%d outgoing') % len(o))
5658 if 'bookmarks' in other.listkeys('namespaces'):
5376 if 'bookmarks' in other.listkeys('namespaces'):
5659 lmarks = repo.listkeys('bookmarks')
5377 lmarks = repo.listkeys('bookmarks')
5660 rmarks = other.listkeys('bookmarks')
5378 rmarks = other.listkeys('bookmarks')
5661 diff = set(rmarks) - set(lmarks)
5379 diff = set(rmarks) - set(lmarks)
5662 if len(diff) > 0:
5380 if len(diff) > 0:
5663 t.append(_('%d incoming bookmarks') % len(diff))
5381 t.append(_('%d incoming bookmarks') % len(diff))
5664 diff = set(lmarks) - set(rmarks)
5382 diff = set(lmarks) - set(rmarks)
5665 if len(diff) > 0:
5383 if len(diff) > 0:
5666 t.append(_('%d outgoing bookmarks') % len(diff))
5384 t.append(_('%d outgoing bookmarks') % len(diff))
5667
5385
5668 if t:
5386 if t:
5669 # i18n: column positioning for "hg summary"
5387 # i18n: column positioning for "hg summary"
5670 ui.write(_('remote: %s\n') % (', '.join(t)))
5388 ui.write(_('remote: %s\n') % (', '.join(t)))
5671 else:
5389 else:
5672 # i18n: column positioning for "hg summary"
5390 # i18n: column positioning for "hg summary"
5673 ui.status(_('remote: (synced)\n'))
5391 ui.status(_('remote: (synced)\n'))
5674
5392
5675 @command('tag',
5393 @command('tag',
5676 [('f', 'force', None, _('force tag')),
5394 [('f', 'force', None, _('force tag')),
5677 ('l', 'local', None, _('make the tag local')),
5395 ('l', 'local', None, _('make the tag local')),
5678 ('r', 'rev', '', _('revision to tag'), _('REV')),
5396 ('r', 'rev', '', _('revision to tag'), _('REV')),
5679 ('', 'remove', None, _('remove a tag')),
5397 ('', 'remove', None, _('remove a tag')),
5680 # -l/--local is already there, commitopts cannot be used
5398 # -l/--local is already there, commitopts cannot be used
5681 ('e', 'edit', None, _('edit commit message')),
5399 ('e', 'edit', None, _('edit commit message')),
5682 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5400 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5683 ] + commitopts2,
5401 ] + commitopts2,
5684 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5402 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5685 def tag(ui, repo, name1, *names, **opts):
5403 def tag(ui, repo, name1, *names, **opts):
5686 """add one or more tags for the current or given revision
5404 """add one or more tags for the current or given revision
5687
5405
5688 Name a particular revision using <name>.
5406 Name a particular revision using <name>.
5689
5407
5690 Tags are used to name particular revisions of the repository and are
5408 Tags are used to name particular revisions of the repository and are
5691 very useful to compare different revisions, to go back to significant
5409 very useful to compare different revisions, to go back to significant
5692 earlier versions or to mark branch points as releases, etc. Changing
5410 earlier versions or to mark branch points as releases, etc. Changing
5693 an existing tag is normally disallowed; use -f/--force to override.
5411 an existing tag is normally disallowed; use -f/--force to override.
5694
5412
5695 If no revision is given, the parent of the working directory is
5413 If no revision is given, the parent of the working directory is
5696 used, or tip if no revision is checked out.
5414 used, or tip if no revision is checked out.
5697
5415
5698 To facilitate version control, distribution, and merging of tags,
5416 To facilitate version control, distribution, and merging of tags,
5699 they are stored as a file named ".hgtags" which is managed similarly
5417 they are stored as a file named ".hgtags" which is managed similarly
5700 to other project files and can be hand-edited if necessary. This
5418 to other project files and can be hand-edited if necessary. This
5701 also means that tagging creates a new commit. The file
5419 also means that tagging creates a new commit. The file
5702 ".hg/localtags" is used for local tags (not shared among
5420 ".hg/localtags" is used for local tags (not shared among
5703 repositories).
5421 repositories).
5704
5422
5705 Tag commits are usually made at the head of a branch. If the parent
5423 Tag commits are usually made at the head of a branch. If the parent
5706 of the working directory is not a branch head, :hg:`tag` aborts; use
5424 of the working directory is not a branch head, :hg:`tag` aborts; use
5707 -f/--force to force the tag commit to be based on a non-head
5425 -f/--force to force the tag commit to be based on a non-head
5708 changeset.
5426 changeset.
5709
5427
5710 See :hg:`help dates` for a list of formats valid for -d/--date.
5428 See :hg:`help dates` for a list of formats valid for -d/--date.
5711
5429
5712 Since tag names have priority over branch names during revision
5430 Since tag names have priority over branch names during revision
5713 lookup, using an existing branch name as a tag name is discouraged.
5431 lookup, using an existing branch name as a tag name is discouraged.
5714
5432
5715 Returns 0 on success.
5433 Returns 0 on success.
5716 """
5434 """
5717 wlock = lock = None
5435 wlock = lock = None
5718 try:
5436 try:
5719 wlock = repo.wlock()
5437 wlock = repo.wlock()
5720 lock = repo.lock()
5438 lock = repo.lock()
5721 rev_ = "."
5439 rev_ = "."
5722 names = [t.strip() for t in (name1,) + names]
5440 names = [t.strip() for t in (name1,) + names]
5723 if len(names) != len(set(names)):
5441 if len(names) != len(set(names)):
5724 raise util.Abort(_('tag names must be unique'))
5442 raise util.Abort(_('tag names must be unique'))
5725 for n in names:
5443 for n in names:
5726 scmutil.checknewlabel(repo, n, 'tag')
5444 scmutil.checknewlabel(repo, n, 'tag')
5727 if not n:
5445 if not n:
5728 raise util.Abort(_('tag names cannot consist entirely of '
5446 raise util.Abort(_('tag names cannot consist entirely of '
5729 'whitespace'))
5447 'whitespace'))
5730 if opts.get('rev') and opts.get('remove'):
5448 if opts.get('rev') and opts.get('remove'):
5731 raise util.Abort(_("--rev and --remove are incompatible"))
5449 raise util.Abort(_("--rev and --remove are incompatible"))
5732 if opts.get('rev'):
5450 if opts.get('rev'):
5733 rev_ = opts['rev']
5451 rev_ = opts['rev']
5734 message = opts.get('message')
5452 message = opts.get('message')
5735 if opts.get('remove'):
5453 if opts.get('remove'):
5736 expectedtype = opts.get('local') and 'local' or 'global'
5454 expectedtype = opts.get('local') and 'local' or 'global'
5737 for n in names:
5455 for n in names:
5738 if not repo.tagtype(n):
5456 if not repo.tagtype(n):
5739 raise util.Abort(_("tag '%s' does not exist") % n)
5457 raise util.Abort(_("tag '%s' does not exist") % n)
5740 if repo.tagtype(n) != expectedtype:
5458 if repo.tagtype(n) != expectedtype:
5741 if expectedtype == 'global':
5459 if expectedtype == 'global':
5742 raise util.Abort(_("tag '%s' is not a global tag") % n)
5460 raise util.Abort(_("tag '%s' is not a global tag") % n)
5743 else:
5461 else:
5744 raise util.Abort(_("tag '%s' is not a local tag") % n)
5462 raise util.Abort(_("tag '%s' is not a local tag") % n)
5745 rev_ = nullid
5463 rev_ = nullid
5746 if not message:
5464 if not message:
5747 # we don't translate commit messages
5465 # we don't translate commit messages
5748 message = 'Removed tag %s' % ', '.join(names)
5466 message = 'Removed tag %s' % ', '.join(names)
5749 elif not opts.get('force'):
5467 elif not opts.get('force'):
5750 for n in names:
5468 for n in names:
5751 if n in repo.tags():
5469 if n in repo.tags():
5752 raise util.Abort(_("tag '%s' already exists "
5470 raise util.Abort(_("tag '%s' already exists "
5753 "(use -f to force)") % n)
5471 "(use -f to force)") % n)
5754 if not opts.get('local'):
5472 if not opts.get('local'):
5755 p1, p2 = repo.dirstate.parents()
5473 p1, p2 = repo.dirstate.parents()
5756 if p2 != nullid:
5474 if p2 != nullid:
5757 raise util.Abort(_('uncommitted merge'))
5475 raise util.Abort(_('uncommitted merge'))
5758 bheads = repo.branchheads()
5476 bheads = repo.branchheads()
5759 if not opts.get('force') and bheads and p1 not in bheads:
5477 if not opts.get('force') and bheads and p1 not in bheads:
5760 raise util.Abort(_('not at a branch head (use -f to force)'))
5478 raise util.Abort(_('not at a branch head (use -f to force)'))
5761 r = scmutil.revsingle(repo, rev_).node()
5479 r = scmutil.revsingle(repo, rev_).node()
5762
5480
5763 if not message:
5481 if not message:
5764 # we don't translate commit messages
5482 # we don't translate commit messages
5765 message = ('Added tag %s for changeset %s' %
5483 message = ('Added tag %s for changeset %s' %
5766 (', '.join(names), short(r)))
5484 (', '.join(names), short(r)))
5767
5485
5768 date = opts.get('date')
5486 date = opts.get('date')
5769 if date:
5487 if date:
5770 date = util.parsedate(date)
5488 date = util.parsedate(date)
5771
5489
5772 if opts.get('edit'):
5490 if opts.get('edit'):
5773 message = ui.edit(message, ui.username())
5491 message = ui.edit(message, ui.username())
5774
5492
5775 # don't allow tagging the null rev
5493 # don't allow tagging the null rev
5776 if (not opts.get('remove') and
5494 if (not opts.get('remove') and
5777 scmutil.revsingle(repo, rev_).rev() == nullrev):
5495 scmutil.revsingle(repo, rev_).rev() == nullrev):
5778 raise util.Abort(_("null revision specified"))
5496 raise util.Abort(_("null revision specified"))
5779
5497
5780 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5498 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5781 finally:
5499 finally:
5782 release(lock, wlock)
5500 release(lock, wlock)
5783
5501
5784 @command('tags', [], '')
5502 @command('tags', [], '')
5785 def tags(ui, repo, **opts):
5503 def tags(ui, repo, **opts):
5786 """list repository tags
5504 """list repository tags
5787
5505
5788 This lists both regular and local tags. When the -v/--verbose
5506 This lists both regular and local tags. When the -v/--verbose
5789 switch is used, a third column "local" is printed for local tags.
5507 switch is used, a third column "local" is printed for local tags.
5790
5508
5791 Returns 0 on success.
5509 Returns 0 on success.
5792 """
5510 """
5793
5511
5794 fm = ui.formatter('tags', opts)
5512 fm = ui.formatter('tags', opts)
5795 hexfunc = ui.debugflag and hex or short
5513 hexfunc = ui.debugflag and hex or short
5796 tagtype = ""
5514 tagtype = ""
5797
5515
5798 for t, n in reversed(repo.tagslist()):
5516 for t, n in reversed(repo.tagslist()):
5799 hn = hexfunc(n)
5517 hn = hexfunc(n)
5800 label = 'tags.normal'
5518 label = 'tags.normal'
5801 tagtype = ''
5519 tagtype = ''
5802 if repo.tagtype(t) == 'local':
5520 if repo.tagtype(t) == 'local':
5803 label = 'tags.local'
5521 label = 'tags.local'
5804 tagtype = 'local'
5522 tagtype = 'local'
5805
5523
5806 fm.startitem()
5524 fm.startitem()
5807 fm.write('tag', '%s', t, label=label)
5525 fm.write('tag', '%s', t, label=label)
5808 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5526 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5809 fm.condwrite(not ui.quiet, 'rev id', fmt,
5527 fm.condwrite(not ui.quiet, 'rev id', fmt,
5810 repo.changelog.rev(n), hn, label=label)
5528 repo.changelog.rev(n), hn, label=label)
5811 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5529 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5812 tagtype, label=label)
5530 tagtype, label=label)
5813 fm.plain('\n')
5531 fm.plain('\n')
5814 fm.end()
5532 fm.end()
5815
5533
5816 @command('tip',
5534 @command('tip',
5817 [('p', 'patch', None, _('show patch')),
5535 [('p', 'patch', None, _('show patch')),
5818 ('g', 'git', None, _('use git extended diff format')),
5536 ('g', 'git', None, _('use git extended diff format')),
5819 ] + templateopts,
5537 ] + templateopts,
5820 _('[-p] [-g]'))
5538 _('[-p] [-g]'))
5821 def tip(ui, repo, **opts):
5539 def tip(ui, repo, **opts):
5822 """show the tip revision
5540 """show the tip revision
5823
5541
5824 The tip revision (usually just called the tip) is the changeset
5542 The tip revision (usually just called the tip) is the changeset
5825 most recently added to the repository (and therefore the most
5543 most recently added to the repository (and therefore the most
5826 recently changed head).
5544 recently changed head).
5827
5545
5828 If you have just made a commit, that commit will be the tip. If
5546 If you have just made a commit, that commit will be the tip. If
5829 you have just pulled changes from another repository, the tip of
5547 you have just pulled changes from another repository, the tip of
5830 that repository becomes the current tip. The "tip" tag is special
5548 that repository becomes the current tip. The "tip" tag is special
5831 and cannot be renamed or assigned to a different changeset.
5549 and cannot be renamed or assigned to a different changeset.
5832
5550
5833 Returns 0 on success.
5551 Returns 0 on success.
5834 """
5552 """
5835 displayer = cmdutil.show_changeset(ui, repo, opts)
5553 displayer = cmdutil.show_changeset(ui, repo, opts)
5836 displayer.show(repo['tip'])
5554 displayer.show(repo['tip'])
5837 displayer.close()
5555 displayer.close()
5838
5556
5839 @command('unbundle',
5557 @command('unbundle',
5840 [('u', 'update', None,
5558 [('u', 'update', None,
5841 _('update to new branch head if changesets were unbundled'))],
5559 _('update to new branch head if changesets were unbundled'))],
5842 _('[-u] FILE...'))
5560 _('[-u] FILE...'))
5843 def unbundle(ui, repo, fname1, *fnames, **opts):
5561 def unbundle(ui, repo, fname1, *fnames, **opts):
5844 """apply one or more changegroup files
5562 """apply one or more changegroup files
5845
5563
5846 Apply one or more compressed changegroup files generated by the
5564 Apply one or more compressed changegroup files generated by the
5847 bundle command.
5565 bundle command.
5848
5566
5849 Returns 0 on success, 1 if an update has unresolved files.
5567 Returns 0 on success, 1 if an update has unresolved files.
5850 """
5568 """
5851 fnames = (fname1,) + fnames
5569 fnames = (fname1,) + fnames
5852
5570
5853 lock = repo.lock()
5571 lock = repo.lock()
5854 wc = repo['.']
5572 wc = repo['.']
5855 try:
5573 try:
5856 for fname in fnames:
5574 for fname in fnames:
5857 f = hg.openpath(ui, fname)
5575 f = hg.openpath(ui, fname)
5858 gen = changegroup.readbundle(f, fname)
5576 gen = changegroup.readbundle(f, fname)
5859 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5577 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5860 finally:
5578 finally:
5861 lock.release()
5579 lock.release()
5862 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5580 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5863 return postincoming(ui, repo, modheads, opts.get('update'), None)
5581 return postincoming(ui, repo, modheads, opts.get('update'), None)
5864
5582
5865 @command('^update|up|checkout|co',
5583 @command('^update|up|checkout|co',
5866 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5584 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5867 ('c', 'check', None,
5585 ('c', 'check', None,
5868 _('update across branches if no uncommitted changes')),
5586 _('update across branches if no uncommitted changes')),
5869 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5587 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5870 ('r', 'rev', '', _('revision'), _('REV'))],
5588 ('r', 'rev', '', _('revision'), _('REV'))],
5871 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5589 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5872 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5590 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5873 """update working directory (or switch revisions)
5591 """update working directory (or switch revisions)
5874
5592
5875 Update the repository's working directory to the specified
5593 Update the repository's working directory to the specified
5876 changeset. If no changeset is specified, update to the tip of the
5594 changeset. If no changeset is specified, update to the tip of the
5877 current named branch and move the current bookmark (see :hg:`help
5595 current named branch and move the current bookmark (see :hg:`help
5878 bookmarks`).
5596 bookmarks`).
5879
5597
5880 Update sets the working directory's parent revision to the specified
5598 Update sets the working directory's parent revision to the specified
5881 changeset (see :hg:`help parents`).
5599 changeset (see :hg:`help parents`).
5882
5600
5883 If the changeset is not a descendant or ancestor of the working
5601 If the changeset is not a descendant or ancestor of the working
5884 directory's parent, the update is aborted. With the -c/--check
5602 directory's parent, the update is aborted. With the -c/--check
5885 option, the working directory is checked for uncommitted changes; if
5603 option, the working directory is checked for uncommitted changes; if
5886 none are found, the working directory is updated to the specified
5604 none are found, the working directory is updated to the specified
5887 changeset.
5605 changeset.
5888
5606
5889 .. container:: verbose
5607 .. container:: verbose
5890
5608
5891 The following rules apply when the working directory contains
5609 The following rules apply when the working directory contains
5892 uncommitted changes:
5610 uncommitted changes:
5893
5611
5894 1. If neither -c/--check nor -C/--clean is specified, and if
5612 1. If neither -c/--check nor -C/--clean is specified, and if
5895 the requested changeset is an ancestor or descendant of
5613 the requested changeset is an ancestor or descendant of
5896 the working directory's parent, the uncommitted changes
5614 the working directory's parent, the uncommitted changes
5897 are merged into the requested changeset and the merged
5615 are merged into the requested changeset and the merged
5898 result is left uncommitted. If the requested changeset is
5616 result is left uncommitted. If the requested changeset is
5899 not an ancestor or descendant (that is, it is on another
5617 not an ancestor or descendant (that is, it is on another
5900 branch), the update is aborted and the uncommitted changes
5618 branch), the update is aborted and the uncommitted changes
5901 are preserved.
5619 are preserved.
5902
5620
5903 2. With the -c/--check option, the update is aborted and the
5621 2. With the -c/--check option, the update is aborted and the
5904 uncommitted changes are preserved.
5622 uncommitted changes are preserved.
5905
5623
5906 3. With the -C/--clean option, uncommitted changes are discarded and
5624 3. With the -C/--clean option, uncommitted changes are discarded and
5907 the working directory is updated to the requested changeset.
5625 the working directory is updated to the requested changeset.
5908
5626
5909 To cancel an uncommitted merge (and lose your changes), use
5627 To cancel an uncommitted merge (and lose your changes), use
5910 :hg:`update --clean .`.
5628 :hg:`update --clean .`.
5911
5629
5912 Use null as the changeset to remove the working directory (like
5630 Use null as the changeset to remove the working directory (like
5913 :hg:`clone -U`).
5631 :hg:`clone -U`).
5914
5632
5915 If you want to revert just one file to an older revision, use
5633 If you want to revert just one file to an older revision, use
5916 :hg:`revert [-r REV] NAME`.
5634 :hg:`revert [-r REV] NAME`.
5917
5635
5918 See :hg:`help dates` for a list of formats valid for -d/--date.
5636 See :hg:`help dates` for a list of formats valid for -d/--date.
5919
5637
5920 Returns 0 on success, 1 if there are unresolved files.
5638 Returns 0 on success, 1 if there are unresolved files.
5921 """
5639 """
5922 if rev and node:
5640 if rev and node:
5923 raise util.Abort(_("please specify just one revision"))
5641 raise util.Abort(_("please specify just one revision"))
5924
5642
5925 if rev is None or rev == '':
5643 if rev is None or rev == '':
5926 rev = node
5644 rev = node
5927
5645
5928 # with no argument, we also move the current bookmark, if any
5646 # with no argument, we also move the current bookmark, if any
5929 movemarkfrom = None
5647 movemarkfrom = None
5930 if rev is None:
5648 if rev is None:
5931 curmark = repo._bookmarkcurrent
5649 curmark = repo._bookmarkcurrent
5932 if bookmarks.iscurrent(repo):
5650 if bookmarks.iscurrent(repo):
5933 movemarkfrom = repo['.'].node()
5651 movemarkfrom = repo['.'].node()
5934 elif curmark:
5652 elif curmark:
5935 ui.status(_("updating to active bookmark %s\n") % curmark)
5653 ui.status(_("updating to active bookmark %s\n") % curmark)
5936 rev = curmark
5654 rev = curmark
5937
5655
5938 # if we defined a bookmark, we have to remember the original bookmark name
5656 # if we defined a bookmark, we have to remember the original bookmark name
5939 brev = rev
5657 brev = rev
5940 rev = scmutil.revsingle(repo, rev, rev).rev()
5658 rev = scmutil.revsingle(repo, rev, rev).rev()
5941
5659
5942 if check and clean:
5660 if check and clean:
5943 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5661 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5944
5662
5945 if date:
5663 if date:
5946 if rev is not None:
5664 if rev is not None:
5947 raise util.Abort(_("you can't specify a revision and a date"))
5665 raise util.Abort(_("you can't specify a revision and a date"))
5948 rev = cmdutil.finddate(ui, repo, date)
5666 rev = cmdutil.finddate(ui, repo, date)
5949
5667
5950 if check:
5668 if check:
5951 c = repo[None]
5669 c = repo[None]
5952 if c.dirty(merge=False, branch=False, missing=True):
5670 if c.dirty(merge=False, branch=False, missing=True):
5953 raise util.Abort(_("uncommitted local changes"))
5671 raise util.Abort(_("uncommitted local changes"))
5954 if rev is None:
5672 if rev is None:
5955 rev = repo[repo[None].branch()].rev()
5673 rev = repo[repo[None].branch()].rev()
5956 mergemod._checkunknown(repo, repo[None], repo[rev])
5674 mergemod._checkunknown(repo, repo[None], repo[rev])
5957
5675
5958 if clean:
5676 if clean:
5959 ret = hg.clean(repo, rev)
5677 ret = hg.clean(repo, rev)
5960 else:
5678 else:
5961 ret = hg.update(repo, rev)
5679 ret = hg.update(repo, rev)
5962
5680
5963 if not ret and movemarkfrom:
5681 if not ret and movemarkfrom:
5964 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5682 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5965 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5683 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5966 elif brev in repo._bookmarks:
5684 elif brev in repo._bookmarks:
5967 bookmarks.setcurrent(repo, brev)
5685 bookmarks.setcurrent(repo, brev)
5968 elif brev:
5686 elif brev:
5969 bookmarks.unsetcurrent(repo)
5687 bookmarks.unsetcurrent(repo)
5970
5688
5971 return ret
5689 return ret
5972
5690
5973 @command('verify', [])
5691 @command('verify', [])
5974 def verify(ui, repo):
5692 def verify(ui, repo):
5975 """verify the integrity of the repository
5693 """verify the integrity of the repository
5976
5694
5977 Verify the integrity of the current repository.
5695 Verify the integrity of the current repository.
5978
5696
5979 This will perform an extensive check of the repository's
5697 This will perform an extensive check of the repository's
5980 integrity, validating the hashes and checksums of each entry in
5698 integrity, validating the hashes and checksums of each entry in
5981 the changelog, manifest, and tracked files, as well as the
5699 the changelog, manifest, and tracked files, as well as the
5982 integrity of their crosslinks and indices.
5700 integrity of their crosslinks and indices.
5983
5701
5984 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5702 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5985 for more information about recovery from corruption of the
5703 for more information about recovery from corruption of the
5986 repository.
5704 repository.
5987
5705
5988 Returns 0 on success, 1 if errors are encountered.
5706 Returns 0 on success, 1 if errors are encountered.
5989 """
5707 """
5990 return hg.verify(repo)
5708 return hg.verify(repo)
5991
5709
5992 @command('version', [])
5710 @command('version', [])
5993 def version_(ui):
5711 def version_(ui):
5994 """output version and copyright information"""
5712 """output version and copyright information"""
5995 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5713 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5996 % util.version())
5714 % util.version())
5997 ui.status(_(
5715 ui.status(_(
5998 "(see http://mercurial.selenic.com for more information)\n"
5716 "(see http://mercurial.selenic.com for more information)\n"
5999 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5717 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
6000 "This is free software; see the source for copying conditions. "
5718 "This is free software; see the source for copying conditions. "
6001 "There is NO\nwarranty; "
5719 "There is NO\nwarranty; "
6002 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5720 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6003 ))
5721 ))
6004
5722
6005 norepo = ("clone init version help debugcommands debugcomplete"
5723 norepo = ("clone init version help debugcommands debugcomplete"
6006 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5724 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
6007 " debugknown debuggetbundle debugbundle")
5725 " debugknown debuggetbundle debugbundle")
6008 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5726 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
6009 " debugdata debugindex debugindexdot debugrevlog")
5727 " debugdata debugindex debugindexdot debugrevlog")
6010 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5728 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
6011 " remove resolve status debugwalk")
5729 " remove resolve status debugwalk")
@@ -1,208 +1,503
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, error
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 import cmdutil
12
13
13 def listexts(header, exts, indent=1):
14 def listexts(header, exts, indent=1):
14 '''return a text listing of the given extensions'''
15 '''return a text listing of the given extensions'''
15 rst = []
16 rst = []
16 if exts:
17 if exts:
17 rst.append('\n%s\n\n' % header)
18 rst.append('\n%s\n\n' % header)
18 for name, desc in sorted(exts.iteritems()):
19 for name, desc in sorted(exts.iteritems()):
19 rst.append('%s:%s: %s\n' % (' ' * indent, name, desc))
20 rst.append('%s:%s: %s\n' % (' ' * indent, name, desc))
20 return rst
21 return rst
21
22
22 def extshelp():
23 def extshelp():
23 rst = loaddoc('extensions')().splitlines(True)
24 rst = loaddoc('extensions')().splitlines(True)
24 rst.extend(listexts(_('enabled extensions:'), extensions.enabled()))
25 rst.extend(listexts(_('enabled extensions:'), extensions.enabled()))
25 rst.extend(listexts(_('disabled extensions:'), extensions.disabled()))
26 rst.extend(listexts(_('disabled extensions:'), extensions.disabled()))
26 doc = ''.join(rst)
27 doc = ''.join(rst)
27 return doc
28 return doc
28
29
29 def optrst(options, verbose):
30 def optrst(options, verbose):
30 data = []
31 data = []
31 multioccur = False
32 multioccur = False
32 for option in options:
33 for option in options:
33 if len(option) == 5:
34 if len(option) == 5:
34 shortopt, longopt, default, desc, optlabel = option
35 shortopt, longopt, default, desc, optlabel = option
35 else:
36 else:
36 shortopt, longopt, default, desc = option
37 shortopt, longopt, default, desc = option
37 optlabel = _("VALUE") # default label
38 optlabel = _("VALUE") # default label
38
39
39 if _("DEPRECATED") in desc and not verbose:
40 if _("DEPRECATED") in desc and not verbose:
40 continue
41 continue
41
42
42 so = ''
43 so = ''
43 if shortopt:
44 if shortopt:
44 so = '-' + shortopt
45 so = '-' + shortopt
45 lo = '--' + longopt
46 lo = '--' + longopt
46 if default:
47 if default:
47 desc += _(" (default: %s)") % default
48 desc += _(" (default: %s)") % default
48
49
49 if isinstance(default, list):
50 if isinstance(default, list):
50 lo += " %s [+]" % optlabel
51 lo += " %s [+]" % optlabel
51 multioccur = True
52 multioccur = True
52 elif (default is not None) and not isinstance(default, bool):
53 elif (default is not None) and not isinstance(default, bool):
53 lo += " %s" % optlabel
54 lo += " %s" % optlabel
54
55
55 data.append((so, lo, desc))
56 data.append((so, lo, desc))
56
57
57 rst = minirst.maketable(data, 1)
58 rst = minirst.maketable(data, 1)
58
59
59 if multioccur:
60 if multioccur:
60 rst.append(_("\n[+] marked option can be specified multiple times\n"))
61 rst.append(_("\n[+] marked option can be specified multiple times\n"))
61
62
62 return ''.join(rst)
63 return ''.join(rst)
63
64
64 def indicateomitted(rst, omitted, notomitted=None):
65 def indicateomitted(rst, omitted, notomitted=None):
65 rst.append('\n\n.. container:: omitted\n\n %s\n\n' % omitted)
66 rst.append('\n\n.. container:: omitted\n\n %s\n\n' % omitted)
66 if notomitted:
67 if notomitted:
67 rst.append('\n\n.. container:: notomitted\n\n %s\n\n' % notomitted)
68 rst.append('\n\n.. container:: notomitted\n\n %s\n\n' % notomitted)
68
69
69 def topicmatch(kw):
70 def topicmatch(kw):
70 """Return help topics matching kw.
71 """Return help topics matching kw.
71
72
72 Returns {'section': [(name, summary), ...], ...} where section is
73 Returns {'section': [(name, summary), ...], ...} where section is
73 one of topics, commands, extensions, or extensioncommands.
74 one of topics, commands, extensions, or extensioncommands.
74 """
75 """
75 kw = encoding.lower(kw)
76 kw = encoding.lower(kw)
76 def lowercontains(container):
77 def lowercontains(container):
77 return kw in encoding.lower(container) # translated in helptable
78 return kw in encoding.lower(container) # translated in helptable
78 results = {'topics': [],
79 results = {'topics': [],
79 'commands': [],
80 'commands': [],
80 'extensions': [],
81 'extensions': [],
81 'extensioncommands': [],
82 'extensioncommands': [],
82 }
83 }
83 for names, header, doc in helptable:
84 for names, header, doc in helptable:
84 if (sum(map(lowercontains, names))
85 if (sum(map(lowercontains, names))
85 or lowercontains(header)
86 or lowercontains(header)
86 or lowercontains(doc())):
87 or lowercontains(doc())):
87 results['topics'].append((names[0], header))
88 results['topics'].append((names[0], header))
88 import commands # avoid cycle
89 import commands # avoid cycle
89 for cmd, entry in commands.table.iteritems():
90 for cmd, entry in commands.table.iteritems():
90 if cmd.startswith('debug'):
91 if cmd.startswith('debug'):
91 continue
92 continue
92 if len(entry) == 3:
93 if len(entry) == 3:
93 summary = entry[2]
94 summary = entry[2]
94 else:
95 else:
95 summary = ''
96 summary = ''
96 # translate docs *before* searching there
97 # translate docs *before* searching there
97 docs = _(getattr(entry[0], '__doc__', None)) or ''
98 docs = _(getattr(entry[0], '__doc__', None)) or ''
98 if kw in cmd or lowercontains(summary) or lowercontains(docs):
99 if kw in cmd or lowercontains(summary) or lowercontains(docs):
99 doclines = docs.splitlines()
100 doclines = docs.splitlines()
100 if doclines:
101 if doclines:
101 summary = doclines[0]
102 summary = doclines[0]
102 cmdname = cmd.split('|')[0].lstrip('^')
103 cmdname = cmd.split('|')[0].lstrip('^')
103 results['commands'].append((cmdname, summary))
104 results['commands'].append((cmdname, summary))
104 for name, docs in itertools.chain(
105 for name, docs in itertools.chain(
105 extensions.enabled().iteritems(),
106 extensions.enabled().iteritems(),
106 extensions.disabled().iteritems()):
107 extensions.disabled().iteritems()):
107 # extensions.load ignores the UI argument
108 # extensions.load ignores the UI argument
108 mod = extensions.load(None, name, '')
109 mod = extensions.load(None, name, '')
109 if lowercontains(name) or lowercontains(docs):
110 if lowercontains(name) or lowercontains(docs):
110 # extension docs are already translated
111 # extension docs are already translated
111 results['extensions'].append((name, docs.splitlines()[0]))
112 results['extensions'].append((name, docs.splitlines()[0]))
112 for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
113 for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
113 if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
114 if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
114 cmdname = cmd.split('|')[0].lstrip('^')
115 cmdname = cmd.split('|')[0].lstrip('^')
115 if entry[0].__doc__:
116 if entry[0].__doc__:
116 cmddoc = gettext(entry[0].__doc__).splitlines()[0]
117 cmddoc = gettext(entry[0].__doc__).splitlines()[0]
117 else:
118 else:
118 cmddoc = _('(no help text available)')
119 cmddoc = _('(no help text available)')
119 results['extensioncommands'].append((cmdname, cmddoc))
120 results['extensioncommands'].append((cmdname, cmddoc))
120 return results
121 return results
121
122
122 def loaddoc(topic):
123 def loaddoc(topic):
123 """Return a delayed loader for help/topic.txt."""
124 """Return a delayed loader for help/topic.txt."""
124
125
125 def loader():
126 def loader():
126 if util.mainfrozen():
127 if util.mainfrozen():
127 module = sys.executable
128 module = sys.executable
128 else:
129 else:
129 module = __file__
130 module = __file__
130 base = os.path.dirname(module)
131 base = os.path.dirname(module)
131
132
132 for dir in ('.', '..'):
133 for dir in ('.', '..'):
133 docdir = os.path.join(base, dir, 'help')
134 docdir = os.path.join(base, dir, 'help')
134 if os.path.isdir(docdir):
135 if os.path.isdir(docdir):
135 break
136 break
136
137
137 path = os.path.join(docdir, topic + ".txt")
138 path = os.path.join(docdir, topic + ".txt")
138 doc = gettext(util.readfile(path))
139 doc = gettext(util.readfile(path))
139 for rewriter in helphooks.get(topic, []):
140 for rewriter in helphooks.get(topic, []):
140 doc = rewriter(topic, doc)
141 doc = rewriter(topic, doc)
141 return doc
142 return doc
142
143
143 return loader
144 return loader
144
145
145 helptable = sorted([
146 helptable = sorted([
146 (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
147 (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
147 (["dates"], _("Date Formats"), loaddoc('dates')),
148 (["dates"], _("Date Formats"), loaddoc('dates')),
148 (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
149 (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
149 (['environment', 'env'], _('Environment Variables'),
150 (['environment', 'env'], _('Environment Variables'),
150 loaddoc('environment')),
151 loaddoc('environment')),
151 (['revisions', 'revs'], _('Specifying Single Revisions'),
152 (['revisions', 'revs'], _('Specifying Single Revisions'),
152 loaddoc('revisions')),
153 loaddoc('revisions')),
153 (['multirevs', 'mrevs'], _('Specifying Multiple Revisions'),
154 (['multirevs', 'mrevs'], _('Specifying Multiple Revisions'),
154 loaddoc('multirevs')),
155 loaddoc('multirevs')),
155 (['revsets', 'revset'], _("Specifying Revision Sets"), loaddoc('revsets')),
156 (['revsets', 'revset'], _("Specifying Revision Sets"), loaddoc('revsets')),
156 (['filesets', 'fileset'], _("Specifying File Sets"), loaddoc('filesets')),
157 (['filesets', 'fileset'], _("Specifying File Sets"), loaddoc('filesets')),
157 (['diffs'], _('Diff Formats'), loaddoc('diffs')),
158 (['diffs'], _('Diff Formats'), loaddoc('diffs')),
158 (['merge-tools', 'mergetools'], _('Merge Tools'), loaddoc('merge-tools')),
159 (['merge-tools', 'mergetools'], _('Merge Tools'), loaddoc('merge-tools')),
159 (['templating', 'templates', 'template', 'style'], _('Template Usage'),
160 (['templating', 'templates', 'template', 'style'], _('Template Usage'),
160 loaddoc('templates')),
161 loaddoc('templates')),
161 (['urls'], _('URL Paths'), loaddoc('urls')),
162 (['urls'], _('URL Paths'), loaddoc('urls')),
162 (["extensions"], _("Using Additional Features"), extshelp),
163 (["extensions"], _("Using Additional Features"), extshelp),
163 (["subrepos", "subrepo"], _("Subrepositories"), loaddoc('subrepos')),
164 (["subrepos", "subrepo"], _("Subrepositories"), loaddoc('subrepos')),
164 (["hgweb"], _("Configuring hgweb"), loaddoc('hgweb')),
165 (["hgweb"], _("Configuring hgweb"), loaddoc('hgweb')),
165 (["glossary"], _("Glossary"), loaddoc('glossary')),
166 (["glossary"], _("Glossary"), loaddoc('glossary')),
166 (["hgignore", "ignore"], _("Syntax for Mercurial Ignore Files"),
167 (["hgignore", "ignore"], _("Syntax for Mercurial Ignore Files"),
167 loaddoc('hgignore')),
168 loaddoc('hgignore')),
168 (["phases"], _("Working with Phases"), loaddoc('phases')),
169 (["phases"], _("Working with Phases"), loaddoc('phases')),
169 ])
170 ])
170
171
171 # Map topics to lists of callable taking the current topic help and
172 # Map topics to lists of callable taking the current topic help and
172 # returning the updated version
173 # returning the updated version
173 helphooks = {}
174 helphooks = {}
174
175
175 def addtopichook(topic, rewriter):
176 def addtopichook(topic, rewriter):
176 helphooks.setdefault(topic, []).append(rewriter)
177 helphooks.setdefault(topic, []).append(rewriter)
177
178
178 def makeitemsdoc(topic, doc, marker, items):
179 def makeitemsdoc(topic, doc, marker, items):
179 """Extract docstring from the items key to function mapping, build a
180 """Extract docstring from the items key to function mapping, build a
180 .single documentation block and use it to overwrite the marker in doc
181 .single documentation block and use it to overwrite the marker in doc
181 """
182 """
182 entries = []
183 entries = []
183 for name in sorted(items):
184 for name in sorted(items):
184 text = (items[name].__doc__ or '').rstrip()
185 text = (items[name].__doc__ or '').rstrip()
185 if not text:
186 if not text:
186 continue
187 continue
187 text = gettext(text)
188 text = gettext(text)
188 lines = text.splitlines()
189 lines = text.splitlines()
189 doclines = [(lines[0])]
190 doclines = [(lines[0])]
190 for l in lines[1:]:
191 for l in lines[1:]:
191 # Stop once we find some Python doctest
192 # Stop once we find some Python doctest
192 if l.strip().startswith('>>>'):
193 if l.strip().startswith('>>>'):
193 break
194 break
194 doclines.append(' ' + l.strip())
195 doclines.append(' ' + l.strip())
195 entries.append('\n'.join(doclines))
196 entries.append('\n'.join(doclines))
196 entries = '\n\n'.join(entries)
197 entries = '\n\n'.join(entries)
197 return doc.replace(marker, entries)
198 return doc.replace(marker, entries)
198
199
199 def addtopicsymbols(topic, marker, symbols):
200 def addtopicsymbols(topic, marker, symbols):
200 def add(topic, doc):
201 def add(topic, doc):
201 return makeitemsdoc(topic, doc, marker, symbols)
202 return makeitemsdoc(topic, doc, marker, symbols)
202 addtopichook(topic, add)
203 addtopichook(topic, add)
203
204
204 addtopicsymbols('filesets', '.. predicatesmarker', fileset.symbols)
205 addtopicsymbols('filesets', '.. predicatesmarker', fileset.symbols)
205 addtopicsymbols('merge-tools', '.. internaltoolsmarker', filemerge.internals)
206 addtopicsymbols('merge-tools', '.. internaltoolsmarker', filemerge.internals)
206 addtopicsymbols('revsets', '.. predicatesmarker', revset.symbols)
207 addtopicsymbols('revsets', '.. predicatesmarker', revset.symbols)
207 addtopicsymbols('templates', '.. keywordsmarker', templatekw.dockeywords)
208 addtopicsymbols('templates', '.. keywordsmarker', templatekw.dockeywords)
208 addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters)
209 addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters)
210
211 def help_(ui, name, unknowncmd=False, full=True, **opts):
212 '''
213 Generate the help for 'name' as unformatted restructured text. If
214 'name' is None, describe the commands available.
215 '''
216
217 import commands # avoid cycle
218
219 def helpcmd(name):
220 try:
221 aliases, entry = cmdutil.findcmd(name, commands.table,
222 strict=unknowncmd)
223 except error.AmbiguousCommand, inst:
224 # py3k fix: except vars can't be used outside the scope of the
225 # except block, nor can be used inside a lambda. python issue4617
226 prefix = inst.args[0]
227 select = lambda c: c.lstrip('^').startswith(prefix)
228 rst = helplist(select)
229 return rst
230
231 rst = []
232
233 # check if it's an invalid alias and display its error if it is
234 if getattr(entry[0], 'badalias', False):
235 if not unknowncmd:
236 ui.pushbuffer()
237 entry[0](ui)
238 rst.append(ui.popbuffer())
239 return rst
240
241 # synopsis
242 if len(entry) > 2:
243 if entry[2].startswith('hg'):
244 rst.append("%s\n" % entry[2])
245 else:
246 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
247 else:
248 rst.append('hg %s\n' % aliases[0])
249 # aliases
250 if full and not ui.quiet and len(aliases) > 1:
251 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
252 rst.append('\n')
253
254 # description
255 doc = gettext(entry[0].__doc__)
256 if not doc:
257 doc = _("(no help text available)")
258 if util.safehasattr(entry[0], 'definition'): # aliased command
259 if entry[0].definition.startswith('!'): # shell alias
260 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
261 else:
262 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
263 doc = doc.splitlines(True)
264 if ui.quiet or not full:
265 rst.append(doc[0])
266 else:
267 rst.extend(doc)
268 rst.append('\n')
269
270 # check if this command shadows a non-trivial (multi-line)
271 # extension help text
272 try:
273 mod = extensions.find(name)
274 doc = gettext(mod.__doc__) or ''
275 if '\n' in doc.strip():
276 msg = _('use "hg help -e %s" to show help for '
277 'the %s extension') % (name, name)
278 rst.append('\n%s\n' % msg)
279 except KeyError:
280 pass
281
282 # options
283 if not ui.quiet and entry[1]:
284 rst.append('\n%s\n\n' % _("options:"))
285 rst.append(optrst(entry[1], ui.verbose))
286
287 if ui.verbose:
288 rst.append('\n%s\n\n' % _("global options:"))
289 rst.append(optrst(commands.globalopts, ui.verbose))
290
291 if not ui.verbose:
292 if not full:
293 rst.append(_('\nuse "hg help %s" to show the full help text\n')
294 % name)
295 elif not ui.quiet:
296 omitted = _('use "hg -v help %s" to show more complete'
297 ' help and the global options') % name
298 notomitted = _('use "hg -v help %s" to show'
299 ' the global options') % name
300 indicateomitted(rst, omitted, notomitted)
301
302 return rst
303
304
305 def helplist(select=None):
306 # list of commands
307 if name == "shortlist":
308 header = _('basic commands:\n\n')
309 else:
310 header = _('list of commands:\n\n')
311
312 h = {}
313 cmds = {}
314 for c, e in commands.table.iteritems():
315 f = c.split("|", 1)[0]
316 if select and not select(f):
317 continue
318 if (not select and name != 'shortlist' and
319 e[0].__module__ != commands.__name__):
320 continue
321 if name == "shortlist" and not f.startswith("^"):
322 continue
323 f = f.lstrip("^")
324 if not ui.debugflag and f.startswith("debug"):
325 continue
326 doc = e[0].__doc__
327 if doc and 'DEPRECATED' in doc and not ui.verbose:
328 continue
329 doc = gettext(doc)
330 if not doc:
331 doc = _("(no help text available)")
332 h[f] = doc.splitlines()[0].rstrip()
333 cmds[f] = c.lstrip("^")
334
335 rst = []
336 if not h:
337 if not ui.quiet:
338 rst.append(_('no commands defined\n'))
339 return rst
340
341 if not ui.quiet:
342 rst.append(header)
343 fns = sorted(h)
344 for f in fns:
345 if ui.verbose:
346 commacmds = cmds[f].replace("|",", ")
347 rst.append(" :%s: %s\n" % (commacmds, h[f]))
348 else:
349 rst.append(' :%s: %s\n' % (f, h[f]))
350
351 if not name:
352 exts = listexts(_('enabled extensions:'), extensions.enabled())
353 if exts:
354 rst.append('\n')
355 rst.extend(exts)
356
357 rst.append(_("\nadditional help topics:\n\n"))
358 topics = []
359 for names, header, doc in helptable:
360 topics.append((names[0], header))
361 for t, desc in topics:
362 rst.append(" :%s: %s\n" % (t, desc))
363
364 optlist = []
365 if not ui.quiet:
366 if ui.verbose:
367 optlist.append((_("global options:"), commands.globalopts))
368 if name == 'shortlist':
369 optlist.append((_('use "hg help" for the full list '
370 'of commands'), ()))
371 else:
372 if name == 'shortlist':
373 msg = _('use "hg help" for the full list of commands '
374 'or "hg -v" for details')
375 elif name and not full:
376 msg = _('use "hg help %s" to show the full help '
377 'text') % name
378 else:
379 msg = _('use "hg -v help%s" to show builtin aliases and '
380 'global options') % (name and " " + name or "")
381 optlist.append((msg, ()))
382
383 if optlist:
384 for title, options in optlist:
385 rst.append('\n%s\n' % title)
386 if options:
387 rst.append('\n%s\n' % optrst(options, ui.verbose))
388 return rst
389
390 def helptopic(name):
391 for names, header, doc in helptable:
392 if name in names:
393 break
394 else:
395 raise error.UnknownCommand(name)
396
397 rst = ["%s\n\n" % header]
398 # description
399 if not doc:
400 rst.append(" %s\n" % _("(no help text available)"))
401 if util.safehasattr(doc, '__call__'):
402 rst += [" %s\n" % l for l in doc().splitlines()]
403
404 if not ui.verbose:
405 omitted = (_('use "hg help -v %s" to show more complete help') %
406 name)
407 indicateomitted(rst, omitted)
408
409 try:
410 cmdutil.findcmd(name, commands.table)
411 rst.append(_('\nuse "hg help -c %s" to see help for '
412 'the %s command\n') % (name, name))
413 except error.UnknownCommand:
414 pass
415 return rst
416
417 def helpext(name):
418 try:
419 mod = extensions.find(name)
420 doc = gettext(mod.__doc__) or _('no help text available')
421 except KeyError:
422 mod = None
423 doc = extensions.disabledext(name)
424 if not doc:
425 raise error.UnknownCommand(name)
426
427 if '\n' not in doc:
428 head, tail = doc, ""
429 else:
430 head, tail = doc.split('\n', 1)
431 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
432 if tail:
433 rst.extend(tail.splitlines(True))
434 rst.append('\n')
435
436 if not ui.verbose:
437 omitted = (_('use "hg help -v %s" to show more complete help') %
438 name)
439 indicateomitted(rst, omitted)
440
441 if mod:
442 try:
443 ct = mod.cmdtable
444 except AttributeError:
445 ct = {}
446 modcmds = set([c.split('|', 1)[0] for c in ct])
447 rst.extend(helplist(modcmds.__contains__))
448 else:
449 rst.append(_('use "hg help extensions" for information on enabling '
450 'extensions\n'))
451 return rst
452
453 def helpextcmd(name):
454 cmd, ext, mod = extensions.disabledcmd(ui, name,
455 ui.configbool('ui', 'strict'))
456 doc = gettext(mod.__doc__).splitlines()[0]
457
458 rst = listexts(_("'%s' is provided by the following "
459 "extension:") % cmd, {ext: doc}, indent=4)
460 rst.append('\n')
461 rst.append(_('use "hg help extensions" for information on enabling '
462 'extensions\n'))
463 return rst
464
465
466 rst = []
467 kw = opts.get('keyword')
468 if kw:
469 matches = topicmatch(kw)
470 for t, title in (('topics', _('Topics')),
471 ('commands', _('Commands')),
472 ('extensions', _('Extensions')),
473 ('extensioncommands', _('Extension Commands'))):
474 if matches[t]:
475 rst.append('%s:\n\n' % title)
476 rst.extend(minirst.maketable(sorted(matches[t]), 1))
477 rst.append('\n')
478 elif name and name != 'shortlist':
479 i = None
480 if unknowncmd:
481 queries = (helpextcmd,)
482 elif opts.get('extension'):
483 queries = (helpext,)
484 elif opts.get('command'):
485 queries = (helpcmd,)
486 else:
487 queries = (helptopic, helpcmd, helpext, helpextcmd)
488 for f in queries:
489 try:
490 rst = f(name)
491 i = None
492 break
493 except error.UnknownCommand, inst:
494 i = inst
495 if i:
496 raise i
497 else:
498 # program name
499 if not ui.quiet:
500 rst = [_("Mercurial Distributed SCM\n"), '\n']
501 rst.extend(helplist())
502
503 return ''.join(rst)
General Comments 0
You need to be logged in to leave comments. Login now